Commit 230d9561 by Jamie Madill

D3D11: Fix readback of BGRA-backed formats.

For some BGRA-backed formats (RGBA4, R5G6B5, RGB5A1), our ReadPixels implementation wasn't aware the BGRA format didn't exactly match the RGBA format. For these it would do the 'fast path' memcpy method, when it should stop and do the slow pixel-by-pixel packing method. BUG=angleproject:1407 BUG=chromium:616176 Change-Id: Ie24758513af6f9ef87f0aa503135456c96493701 Reviewed-on: https://chromium-review.googlesource.com/352252Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent cd1b1226
......@@ -161,6 +161,7 @@ std::string FormatString(const char *fmt, ...);
#define snprintf _snprintf
#endif
#define GL_BGR565_ANGLEX 0x6ABB
#define GL_BGRA4_ANGLEX 0x6ABC
#define GL_BGR5_A1_ANGLEX 0x6ABD
#define GL_INT_64_ANGLEX 0x6ABE
......
......@@ -459,7 +459,8 @@ gl::Error Framebuffer11::blitImpl(const gl::Rectangle &sourceArea,
GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const
{
RenderTarget11 *renderTarget11 = GetAs<RenderTarget11>(renderTarget);
return d3d11::GetANGLEFormatSet(renderTarget11->getANGLEFormat()).glInternalFormat;
return d3d11::GetANGLEFormatSet(renderTarget11->getANGLEFormat())
.fboImplementationInternalFormat;
}
void Framebuffer11::updateColorRenderTarget(size_t colorIndex)
......
......@@ -141,6 +141,7 @@ bool SupportsFormat(const Renderer11DeviceCaps &deviceCaps)
ANGLEFormatSet::ANGLEFormatSet()
: format(ANGLE_FORMAT_NONE),
glInternalFormat(GL_NONE),
fboImplementationInternalFormat(GL_NONE),
texFormat(DXGI_FORMAT_UNKNOWN),
srvFormat(DXGI_FORMAT_UNKNOWN),
rtvFormat(DXGI_FORMAT_UNKNOWN),
......@@ -172,6 +173,7 @@ TextureFormat::TextureFormat(GLenum internalFormat,
ANGLEFormatSet::ANGLEFormatSet(ANGLEFormat format,
GLenum glInternalFormat,
GLenum fboImplementationInternalFormat,
DXGI_FORMAT texFormat,
DXGI_FORMAT srvFormat,
DXGI_FORMAT rtvFormat,
......@@ -182,6 +184,7 @@ ANGLEFormatSet::ANGLEFormatSet(ANGLEFormat format,
ColorReadFunction colorReadFunction)
: format(format),
glInternalFormat(glInternalFormat),
fboImplementationInternalFormat(fboImplementationInternalFormat),
texFormat(texFormat),
srvFormat(srvFormat),
rtvFormat(rtvFormat),
......@@ -463,6 +466,7 @@ def parse_json_into_switch_angle_format_string(json_data):
table_data += ' case ' + angle_format_item[0] + ':\n'
angle_format = angle_format_item[1]
gl_internal_format = angle_format["glInternalFormat"] if "glInternalFormat" in angle_format else "GL_NONE"
fbo_internal_format = angle_format["fboImplementationInternalFormat"] if "fboImplementationInternalFormat" in angle_format else gl_internal_format
tex_format = angle_format["texFormat"] if "texFormat" in angle_format else "DXGI_FORMAT_UNKNOWN"
srv_format = angle_format["srvFormat"] if "srvFormat" in angle_format else "DXGI_FORMAT_UNKNOWN"
rtv_format = angle_format["rtvFormat"] if "rtvFormat" in angle_format else "DXGI_FORMAT_UNKNOWN"
......@@ -474,6 +478,7 @@ def parse_json_into_switch_angle_format_string(json_data):
table_data += ' {\n'
table_data += ' static const ANGLEFormatSet formatInfo(' + angle_format_item[0] + ',\n'
table_data += ' ' + gl_internal_format + ',\n'
table_data += ' ' + fbo_internal_format + ',\n'
table_data += ' ' + tex_format + ',\n'
table_data += ' ' + srv_format + ',\n'
table_data += ' ' + rtv_format + ',\n'
......
......@@ -424,7 +424,8 @@
"channels": "bgr",
"componentType": "unorm",
"bits": { "red": 5, "green": 6, "blue": 5 },
"glInternalFormat": "GL_RGB565",
"glInternalFormat": "GL_BGR565_ANGLEX",
"fboImplementationInternalFormat": "GL_RGB565",
"channelStruct": "R5G6B5"
},
"ANGLE_FORMAT_B5G5R5A1_UNORM": {
......@@ -434,7 +435,8 @@
"channels": "bgra",
"componentType": "unorm",
"bits": { "red": 5, "green": 5, "blue": 5, "alpha": 1 },
"glInternalFormat": "GL_RGB5_A1",
"glInternalFormat": "GL_BGR5_A1_ANGLEX",
"fboImplementationInternalFormat": "GL_RGB5_A1",
"channelStruct": "A1R5G5B5"
},
"ANGLE_FORMAT_R8G8B8A8_SINT": {
......@@ -479,7 +481,8 @@
"channels": "bgra",
"componentType": "unorm",
"bits": { "red": 4, "green": 4, "blue": 4, "alpha": 4 },
"glInternalFormat": "GL_RGBA4",
"glInternalFormat": "GL_BGRA4_ANGLEX",
"fboImplementationInternalFormat": "GL_RGBA4",
"channelStruct": "A4R4G4B4"
},
"ANGLE_FORMAT_R8G8B8A8_UNORM_SRGB": {
......
......@@ -43,6 +43,7 @@ struct ANGLEFormatSet
ANGLEFormatSet();
ANGLEFormatSet(ANGLEFormat format,
GLenum glInternalFormat,
GLenum fboImplementationInternalFormat,
DXGI_FORMAT texFormat,
DXGI_FORMAT srvFormat,
DXGI_FORMAT rtvFormat,
......@@ -60,6 +61,11 @@ struct ANGLEFormatSet
// may be a different internal format than the one this ANGLE format is used for.
GLenum glInternalFormat;
// The format we should report to the GL layer when querying implementation formats from a FBO.
// This might not be the same as the glInternalFormat, since some DXGI formats don't have
// matching GL format enums, like BGRA4, BGR5A1 and B5G6R6.
GLenum fboImplementationInternalFormat;
DXGI_FORMAT texFormat;
DXGI_FORMAT srvFormat;
DXGI_FORMAT rtvFormat;
......
......@@ -621,7 +621,7 @@ struct R4G4B4A4
struct A4R4G4B4
{
unsigned short ARGB;
uint16_t ARGB;
static void readColor(gl::ColorF *dst, const A4R4G4B4 *src)
{
......@@ -633,10 +633,10 @@ struct A4R4G4B4
static void writeColor(A4R4G4B4 *dst, const gl::ColorF *src)
{
dst->ARGB = gl::shiftData<4, 12>(gl::floatToNormalized<4, unsigned short>(src->alpha)) |
gl::shiftData<4, 8>(gl::floatToNormalized<4, unsigned short>(src->red)) |
gl::shiftData<4, 4>(gl::floatToNormalized<4, unsigned short>(src->green)) |
gl::shiftData<4, 0>(gl::floatToNormalized<4, unsigned short>(src->blue));
dst->ARGB = gl::shiftData<4, 12>(gl::floatToNormalized<4, uint16_t>(src->alpha)) |
gl::shiftData<4, 8>(gl::floatToNormalized<4, uint16_t>(src->red)) |
gl::shiftData<4, 4>(gl::floatToNormalized<4, uint16_t>(src->green)) |
gl::shiftData<4, 0>(gl::floatToNormalized<4, uint16_t>(src->blue));
}
static void average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2)
......
......@@ -379,6 +379,64 @@ TEST_P(SixteenBppTextureTestES3, RGB5A1UploadRGB10A2)
simpleValidationBase(tex.get());
}
// Test reading from RGBA4 textures attached to FBO.
TEST_P(SixteenBppTextureTestES3, RGBA4FramebufferReadback)
{
// TODO(jmadill): Fix bug with GLES
if (isGLES())
{
std::cout << "Test skipped on GLES." << std::endl;
return;
}
Vector4 rawColor(0.5f, 0.7f, 1.0f, 0.0f);
GLColor expectedColor(rawColor);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex.get());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.get(), 0);
glClearColor(rawColor.x, rawColor.y, rawColor.z, rawColor.w);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
GLenum colorReadFormat = GL_NONE;
GLenum colorReadType = GL_NONE;
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, reinterpret_cast<GLint *>(&colorReadFormat));
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, reinterpret_cast<GLint *>(&colorReadType));
if (colorReadFormat == GL_RGBA && colorReadType == GL_UNSIGNED_BYTE)
{
GLColor actualColor = GLColor::black;
glReadPixels(0, 0, 1, 1, colorReadFormat, colorReadType, &actualColor);
EXPECT_COLOR_NEAR(expectedColor, actualColor, 20);
}
else
{
ASSERT_GLENUM_EQ(GL_RGBA, colorReadFormat);
ASSERT_TRUE(colorReadType == GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT ||
colorReadType == GL_UNSIGNED_SHORT_4_4_4_4);
uint16_t rgba = 0;
glReadPixels(0, 0, 1, 1, colorReadFormat, colorReadType, &rgba);
GLubyte r8 = static_cast<GLubyte>((rgba & 0xF000) >> 12);
GLubyte g8 = static_cast<GLubyte>((rgba & 0x0F00) >> 8);
GLubyte b8 = static_cast<GLubyte>((rgba & 0x00F0) >> 4);
GLubyte a8 = static_cast<GLubyte>((rgba & 0x000F));
GLColor actualColor(r8 << 4, g8 << 4, b8 << 4, a8 << 4);
EXPECT_COLOR_NEAR(expectedColor, actualColor, 20);
}
ASSERT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(SixteenBppTextureTest,
ES2_D3D9(),
......
......@@ -37,6 +37,11 @@ float ColorNorm(GLubyte channelValue)
return static_cast<float>(channelValue) / 255.0f;
}
GLubyte ColorDenorm(float colorValue)
{
return static_cast<GLubyte>(colorValue * 255.0f);
}
// Use a custom ANGLE platform class to capture and report internal errors.
class TestPlatform : public angle::Platform
{
......@@ -107,6 +112,22 @@ GLColor::GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) : R(r), G(g), B(b),
{
}
GLColor::GLColor(const Vector4 &floatColor)
: R(ColorDenorm(floatColor.x)),
G(ColorDenorm(floatColor.y)),
B(ColorDenorm(floatColor.z)),
A(ColorDenorm(floatColor.w))
{
}
GLColor::GLColor(const GLColor16 &color16)
: R(static_cast<GLubyte>(color16.R)),
G(static_cast<GLubyte>(color16.G)),
B(static_cast<GLubyte>(color16.B)),
A(static_cast<GLubyte>(color16.A))
{
}
GLColor::GLColor(GLuint colorValue) : R(0), G(0), B(0), A(0)
{
memcpy(&R, &colorValue, sizeof(GLuint));
......
......@@ -57,10 +57,14 @@ struct GLColorRGB
static const GLColorRGB yellow;
};
struct GLColor16;
struct GLColor
{
GLColor();
GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a);
GLColor(const Vector4 &floatColor);
GLColor(const GLColor16 &color16);
GLColor(GLuint colorValue);
Vector4 toNormalizedVector() const;
......@@ -119,7 +123,6 @@ GLColor16 ReadColor16(GLint x, GLint y);
#define EXPECT_PIXEL_COLOR_EQ(x, y, angleColor) EXPECT_EQ(angleColor, angle::ReadColor(x, y))
// TODO(jmadill): Figure out how we can use GLColor's nice printing with EXPECT_NEAR.
#define EXPECT_PIXEL_NEAR(x, y, r, g, b, a, abs_error) \
{ \
GLubyte pixel[4]; \
......@@ -131,8 +134,22 @@ GLColor16 ReadColor16(GLint x, GLint y);
EXPECT_NEAR((a), pixel[3], abs_error); \
}
// TODO(jmadill): Figure out how we can use GLColor's nice printing with EXPECT_NEAR.
#define EXPECT_PIXEL_COLOR_NEAR(x, y, angleColor, abs_error) \
EXPECT_PIXEL_NEAR(x, y, angleColor.R, angleColor.G, angleColor.B, angleColor.A, abs_error)
#define EXPECT_PIXEL_COLOR16_EQ(x, y, angleColor) EXPECT_EQ(angleColor, angle::ReadColor16(x, y))
#define EXPECT_COLOR_NEAR(expected, actual, abs_error) \
\
{ \
EXPECT_NEAR(expected.R, actual.R, abs_error); \
EXPECT_NEAR(expected.G, actual.G, abs_error); \
EXPECT_NEAR(expected.B, actual.B, abs_error); \
EXPECT_NEAR(expected.A, actual.A, abs_error); \
\
}
class EGLWindow;
class OSWindow;
......
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