Commit cc846039 by Cody Northrop Committed by Commit Bot

Capture/Replay: Fix GetTexImage on Luminance

GetTexImageANGLE and GetRenderbufferImageANGLE use ReadPixels to pull texture data. Luminance is not a renderable format, so it is not supported by ReadPixels. To support this, override Luminance formats to their underlying internal format. Test: angle_end2end_test --gtest_filter="*GetTexImage*" Bug: b/160014453 Bug: angleproject:4058 Change-Id: Id19344c2e2c06386a871338833e35b7747cb966b Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2321740Reviewed-by: 's avatarManh Nguyen <nguyenmh@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Cody Northrop <cnorthrop@google.com>
parent d019af80
...@@ -1468,6 +1468,22 @@ bool CompressedFormatRequiresWholeImage(GLenum internalFormat) ...@@ -1468,6 +1468,22 @@ bool CompressedFormatRequiresWholeImage(GLenum internalFormat)
} }
} }
void MaybeOverrideLuminance(GLenum &format, GLenum &type, GLenum actualFormat, GLenum actualType)
{
gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(format, type);
if (internalFormat.isLUMA())
{
// Ensure the format and type are compatible
ASSERT(internalFormat.pixelBytes ==
gl::GetInternalFormatInfo(actualFormat, actualType).pixelBytes);
// For Luminance formats, override with the internal format. Since this is not
// renderable, our pixel pack routines don't handle it correctly.
format = actualFormat;
type = actualType;
}
}
const FormatSet &GetAllSizedInternalFormats() const FormatSet &GetAllSizedInternalFormats()
{ {
static angle::base::NoDestructor<FormatSet> formatSet(BuildAllSizedInternalFormatSet()); static angle::base::NoDestructor<FormatSet> formatSet(BuildAllSizedInternalFormatSet());
......
...@@ -267,6 +267,9 @@ GLenum GetUnsizedFormat(GLenum internalFormat); ...@@ -267,6 +267,9 @@ GLenum GetUnsizedFormat(GLenum internalFormat);
// Return whether the compressed format requires whole image/mip level to be uploaded to texture. // Return whether the compressed format requires whole image/mip level to be uploaded to texture.
bool CompressedFormatRequiresWholeImage(GLenum internalFormat); bool CompressedFormatRequiresWholeImage(GLenum internalFormat);
// In support of GetImage, check for LUMA formats and override with real format
void MaybeOverrideLuminance(GLenum &format, GLenum &type, GLenum actualFormat, GLenum actualType);
typedef std::set<GLenum> FormatSet; typedef std::set<GLenum> FormatSet;
const FormatSet &GetAllSizedInternalFormats(); const FormatSet &GetAllSizedInternalFormats();
......
...@@ -234,6 +234,10 @@ angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context, ...@@ -234,6 +234,10 @@ angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context,
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
ANGLE_TRY(mImage->flushAllStagedUpdates(contextVk)); ANGLE_TRY(mImage->flushAllStagedUpdates(contextVk));
gl::MaybeOverrideLuminance(format, type, getColorReadFormat(context),
getColorReadType(context));
return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, 0, 0, format, type, return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, 0, 0, format, type,
pixels); pixels);
} }
......
...@@ -2423,6 +2423,10 @@ angle::Result TextureVk::getTexImage(const gl::Context *context, ...@@ -2423,6 +2423,10 @@ angle::Result TextureVk::getTexImage(const gl::Context *context,
size_t layer = size_t layer =
gl::IsCubeMapFaceTarget(target) ? gl::CubeMapTextureTargetToFaceIndex(target) : 0; gl::IsCubeMapFaceTarget(target) ? gl::CubeMapTextureTargetToFaceIndex(target) : 0;
gl::MaybeOverrideLuminance(format, type, getColorReadFormat(context),
getColorReadType(context));
return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, level, return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, level,
static_cast<uint32_t>(layer), format, type, pixels); static_cast<uint32_t>(layer), format, type, pixels);
} }
......
...@@ -4578,7 +4578,7 @@ angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk, ...@@ -4578,7 +4578,7 @@ angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk,
VkImageAspectFlagBits aspectFlags = {}; VkImageAspectFlagBits aspectFlags = {};
if (angleFormat.redBits > 0 || angleFormat.blueBits > 0 || angleFormat.greenBits > 0 || if (angleFormat.redBits > 0 || angleFormat.blueBits > 0 || angleFormat.greenBits > 0 ||
angleFormat.alphaBits > 0) angleFormat.alphaBits > 0 || angleFormat.luminanceBits > 0)
{ {
aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
} }
......
...@@ -17,6 +17,9 @@ namespace ...@@ -17,6 +17,9 @@ namespace
constexpr uint32_t kSize = 32; constexpr uint32_t kSize = 32;
constexpr char kExtensionName[] = "GL_ANGLE_get_image"; constexpr char kExtensionName[] = "GL_ANGLE_get_image";
constexpr uint32_t kSmallSize = 2; constexpr uint32_t kSmallSize = 2;
constexpr uint8_t kUNormZero = 0x00;
constexpr uint8_t kUNormHalf = 0x7F;
constexpr uint8_t kUNormFull = 0xFF;
class GetImageTest : public ANGLETest class GetImageTest : public ANGLETest
{ {
...@@ -38,6 +41,16 @@ class GetImageTestNoExtensions : public ANGLETest ...@@ -38,6 +41,16 @@ class GetImageTestNoExtensions : public ANGLETest
GetImageTestNoExtensions() { setExtensionsEnabled(false); } GetImageTestNoExtensions() { setExtensionsEnabled(false); }
}; };
GLTexture InitTextureWithFormatAndSize(GLenum format, uint32_t size, void *pixelData)
{
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, format, size, size, 0, format, GL_UNSIGNED_BYTE, pixelData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return tex;
}
GLTexture InitTextureWithSize(uint32_t size, void *pixelData) GLTexture InitTextureWithSize(uint32_t size, void *pixelData)
{ {
// Create a simple texture. // Create a simple texture.
...@@ -292,6 +305,111 @@ TEST_P(GetImageTestNoExtensions, EntryPointsInactive) ...@@ -292,6 +305,111 @@ TEST_P(GetImageTestNoExtensions, EntryPointsInactive)
EXPECT_GL_ERROR(GL_INVALID_OPERATION); EXPECT_GL_ERROR(GL_INVALID_OPERATION);
} }
// Test LUMINANCE_ALPHA (non-renderable) format with GetTexImage
TEST_P(GetImageTest, GetTexImageLuminanceAlpha)
{
// Verify the extension is enabled.
ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
constexpr GLColorRG kMediumLumAlpha = GLColorRG(kUNormHalf, kUNormHalf);
std::vector<GLColorRG> expectedData = {kMediumLumAlpha, kMediumLumAlpha, kMediumLumAlpha,
kMediumLumAlpha};
glViewport(0, 0, kSmallSize, kSmallSize);
// Set up a simple LUMINANCE_ALPHA texture
GLTexture tex =
InitTextureWithFormatAndSize(GL_LUMINANCE_ALPHA, kSmallSize, expectedData.data());
// Draw once with simple texture.
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(kUNormHalf, kUNormHalf, kUNormHalf, kUNormHalf));
ASSERT_GL_NO_ERROR();
// Pack pixels tightly.
glPixelStorei(GL_PACK_ALIGNMENT, 1);
// Verify GetImage.
std::vector<GLColorRG> actualData(kSmallSize * kSmallSize);
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, actualData.data());
EXPECT_GL_NO_ERROR();
for (uint32_t i = 0; i < kSmallSize * kSmallSize; ++i)
{
EXPECT_EQ(expectedData[i].R, actualData[i].R);
EXPECT_EQ(expectedData[i].G, actualData[i].G);
}
}
// Test LUMINANCE (non-renderable) format with GetTexImage
TEST_P(GetImageTest, GetTexImageLuminance)
{
// Verify the extension is enabled.
ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
constexpr GLColorR kMediumLuminance = GLColorR(kUNormHalf);
std::vector<GLColorR> expectedData = {kMediumLuminance, kMediumLuminance, kMediumLuminance,
kMediumLuminance};
glViewport(0, 0, kSmallSize, kSmallSize);
// Set up a simple LUMINANCE texture
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLTexture tex = InitTextureWithFormatAndSize(GL_LUMINANCE, kSmallSize, expectedData.data());
// Draw once with simple texture.
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(kUNormHalf, kUNormHalf, kUNormHalf, kUNormFull));
ASSERT_GL_NO_ERROR();
// Pack pixels tightly.
glPixelStorei(GL_PACK_ALIGNMENT, 1);
// Verify GetImage.
std::vector<GLColorR> actualData(kSmallSize * kSmallSize);
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, actualData.data());
EXPECT_GL_NO_ERROR();
for (uint32_t i = 0; i < kSmallSize * kSmallSize; ++i)
{
EXPECT_EQ(expectedData[i].R, actualData[i].R);
}
}
// Test ALPHA (non-renderable) format with GetTexImage
TEST_P(GetImageTest, GetTexImageAlpha)
{
// Verify the extension is enabled.
ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
constexpr GLColorR kMediumAlpha = GLColorR(kUNormHalf);
std::vector<GLColorR> expectedData = {kMediumAlpha, kMediumAlpha, kMediumAlpha, kMediumAlpha};
glViewport(0, 0, kSmallSize, kSmallSize);
// Set up a simple ALPHA texture
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLTexture tex = InitTextureWithFormatAndSize(GL_ALPHA, kSmallSize, expectedData.data());
// Draw once with simple texture
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(kUNormZero, kUNormZero, kUNormZero, kUNormHalf));
ASSERT_GL_NO_ERROR();
// Pack pixels tightly.
glPixelStorei(GL_PACK_ALIGNMENT, 1);
// Verify we get back the correct pixels from GetTexImage
std::vector<GLColorR> actualData(kSmallSize * kSmallSize);
glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_ALPHA, GL_UNSIGNED_BYTE, actualData.data());
EXPECT_GL_NO_ERROR();
for (uint32_t i = 0; i < kSmallSize * kSmallSize; ++i)
{
EXPECT_EQ(expectedData[i].R, actualData[i].R);
}
}
ANGLE_INSTANTIATE_TEST(GetImageTest, ES2_VULKAN(), ES3_VULKAN()); ANGLE_INSTANTIATE_TEST(GetImageTest, ES2_VULKAN(), ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(GetImageTestNoExtensions, ES2_VULKAN(), ES3_VULKAN()); ANGLE_INSTANTIATE_TEST(GetImageTestNoExtensions, ES2_VULKAN(), ES3_VULKAN());
} // namespace } // namespace
\ No newline at end of file
...@@ -94,6 +94,30 @@ struct GLColorRGB ...@@ -94,6 +94,30 @@ struct GLColorRGB
static const GLColorRGB yellow; static const GLColorRGB yellow;
}; };
struct GLColorRG
{
constexpr GLColorRG() : R(0), G(0) {}
constexpr GLColorRG(GLubyte r, GLubyte g) : R(r), G(g) {}
GLColorRG(const angle::Vector2 &floatColor);
const GLubyte *data() const { return &R; }
GLubyte *data() { return &R; }
GLubyte R, G;
};
struct GLColorR
{
constexpr GLColorR() : R(0) {}
constexpr GLColorR(GLubyte r) : R(r) {}
GLColorR(const float floatColor);
const GLubyte *data() const { return &R; }
GLubyte *data() { return &R; }
GLubyte R;
};
struct GLColor struct GLColor
{ {
constexpr GLColor() : R(0), G(0), B(0), A(0) {} constexpr GLColor() : R(0), G(0), B(0), A(0) {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment