Commit ec0b580d by Jamie Madill Committed by Commit Bot

Re-land "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. Fixes conformance2/reading/read-pixels-from-fbo-test.html. Reland: fix empty format info that was causing us to only see the first pixel in the FBO in a ReadPixels call. Also fix bugs in the unorm 16-bit format readback code, and add ASSERTs to catch bugs in subsequent new formats. BUG=angleproject:1407 BUG=chromium:616176 Change-Id: I9fd55b9e1dd6a306eb4db195d775c02a1eb1f93f Reviewed-on: https://chromium-review.googlesource.com/357132Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 563e45aa
......@@ -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
......
......@@ -462,6 +462,9 @@ static InternalFormatInfoMap BuildInternalFormatInfoMap()
map.insert(InternalFormatInfoPair(GL_BGRA4_ANGLEX, RGBAFormat( 4, 4, 4, 4, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported)));
map.insert(InternalFormatInfoPair(GL_BGR5_A1_ANGLEX, RGBAFormat( 5, 5, 5, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported)));
// Special format which is not really supported, so always false for all supports.
map.insert(InternalFormatInfoPair(GL_BGR565_ANGLEX, RGBAFormat( 5, 6, 5, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, NeverSupported, NeverSupported, NeverSupported)));
// Floating point renderability and filtering is provided by OES_texture_float and OES_texture_half_float
// | Internal format | | D |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable |
// | | | | | | | type | | | | |
......@@ -610,12 +613,15 @@ static FormatSet BuildAllSizedInternalFormatSet()
{
FormatSet result;
const InternalFormatInfoMap &formats = GetInternalFormatMap();
for (InternalFormatInfoMap::const_iterator i = formats.begin(); i != formats.end(); i++)
for (auto iter : GetInternalFormatMap())
{
if (i->second.pixelBytes > 0)
if (iter.second.pixelBytes > 0)
{
result.insert(i->first);
// TODO(jmadill): Fix this hack.
if (iter.first == GL_BGR565_ANGLEX)
continue;
result.insert(iter.first);
}
}
......@@ -681,7 +687,7 @@ const Type &GetTypeInfo(GLenum type)
const InternalFormat &GetInternalFormatInfo(GLenum internalFormat)
{
const InternalFormatInfoMap &formatMap = GetInternalFormatMap();
InternalFormatInfoMap::const_iterator iter = formatMap.find(internalFormat);
auto iter = formatMap.find(internalFormat);
if (iter != formatMap.end())
{
return iter->second;
......@@ -689,6 +695,7 @@ const InternalFormat &GetInternalFormatInfo(GLenum internalFormat)
else
{
static const InternalFormat defaultInternalFormat;
UNREACHABLE();
return defaultInternalFormat;
}
}
......
......@@ -365,7 +365,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)
......
......@@ -3729,6 +3729,7 @@ gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper,
int inputPitch = static_cast<int>(mapping.RowPitch);
const auto &angleFormatInfo = d3d11::GetANGLEFormatSet(textureHelper.getANGLEFormat());
ASSERT(angleFormatInfo.glInternalFormat != GL_NONE);
const gl::InternalFormat &sourceFormatInfo =
gl::GetInternalFormatInfo(angleFormatInfo.glInternalFormat);
const auto &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(textureHelper.getFormat());
......
......@@ -12,6 +12,7 @@ import json
import math
import pprint
import re
import sys
template_texture_format_table_autogen_h = """// GENERATED FILE - DO NOT EDIT.
// Generated by gen_texture_format_table.py using data from texture_format_data.json
......@@ -141,6 +142,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),
......@@ -167,11 +169,12 @@ TextureFormat::TextureFormat(GLenum internalFormat,
// Gather all the load functions for this internal format
loadFunctions = GetLoadFunctionsMap(internalFormat, formatSet->texFormat);
ASSERT(loadFunctions.size() != 0 || internalFormat == GL_NONE);
ASSERT(loadFunctions.size() != 0 || angleFormat == ANGLE_FORMAT_NONE);
}}
ANGLEFormatSet::ANGLEFormatSet(ANGLEFormat format,
GLenum glInternalFormat,
GLenum fboImplementationInternalFormat,
DXGI_FORMAT texFormat,
DXGI_FORMAT srvFormat,
DXGI_FORMAT rtvFormat,
......@@ -182,6 +185,7 @@ ANGLEFormatSet::ANGLEFormatSet(ANGLEFormat format,
ColorReadFunction colorReadFunction)
: format(format),
glInternalFormat(glInternalFormat),
fboImplementationInternalFormat(fboImplementationInternalFormat),
texFormat(texFormat),
srvFormat(srvFormat),
rtvFormat(rtvFormat),
......@@ -217,6 +221,7 @@ const TextureFormat &GetTextureFormatInfo(GLenum internalFormat,
{{
{texture_format_info_cases}
default:
UNREACHABLE();
break;
}}
// clang-format on
......@@ -461,19 +466,25 @@ def parse_json_into_switch_angle_format_string(json_data):
table_data = ''
for angle_format_item in sorted(json_data.iteritems()):
table_data += ' case ' + angle_format_item[0] + ':\n'
format_name = angle_format_item[0]
angle_format = angle_format_item[1]
gl_internal_format = angle_format["glInternalFormat"] if "glInternalFormat" in angle_format else "GL_NONE"
if (format_name != "ANGLE_FORMAT_NONE") and ("glInternalFormat" not in angle_format):
print("Missing 'glInternalFormat' from " + format_name)
sys.exit(1)
gl_internal_format = "GL_NONE" if format_name == "ANGLE_FORMAT_NONE" else angle_format["glInternalFormat"]
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"
dsv_format = angle_format["dsvFormat"] if "dsvFormat" in angle_format else "DXGI_FORMAT_UNKNOWN"
blit_srv_format = get_blit_srv_format(angle_format)
swizzle_format = get_swizzle_format_id(angle_format_item[0], angle_format)
swizzle_format = get_swizzle_format_id(format_name, angle_format)
mip_generation_function = get_mip_generation_function(angle_format)
color_read_function = get_color_read_function(angle_format)
table_data += ' {\n'
table_data += ' static const ANGLEFormatSet formatInfo(' + angle_format_item[0] + ',\n'
table_data += ' static const ANGLEFormatSet formatInfo(' + format_name + ',\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'
......
......@@ -680,6 +680,22 @@
}
]
},
"GL_BGR565_ANGLEX": {
"GL_UNSIGNED_SHORT_5_6_5": [
{
"loadFunction": "LoadRGB565ToBGR565",
"dxgiFormat": "DXGI_FORMAT_B5G6R5_UNORM",
"requiresConversion": "true"
}
],
"GL_UNSIGNED_BYTE": [
{
"loadFunction": "LoadToNative<GLushort,1>",
"dxgiFormat": "DXGI_FORMAT_B5G6R5_UNORM",
"requiresConversion": "false"
}
]
},
"GL_COMPRESSED_RG11_EAC": {
"GL_UNSIGNED_BYTE": [
{
......
......@@ -177,6 +177,23 @@ const std::map<GLenum, LoadImageFunctionInfo> &GetLoadFunctionsMap(GLenum intern
break;
}
}
case GL_BGR565_ANGLEX:
{
switch (dxgiFormat)
{
case DXGI_FORMAT_B5G6R5_UNORM:
{
static const std::map<GLenum, LoadImageFunctionInfo> loadFunctionsMap = {
{ GL_UNSIGNED_SHORT_5_6_5, LoadImageFunctionInfo(LoadRGB565ToBGR565, true) },
{ GL_UNSIGNED_BYTE, LoadImageFunctionInfo(LoadToNative<GLushort,1>, false) },
};
return loadFunctionsMap;
}
default:
break;
}
}
case GL_BGR5_A1_ANGLEX:
{
switch (dxgiFormat)
......
......@@ -26,7 +26,8 @@
"rtvFormat": "DXGI_FORMAT_R16G16B16A16_UNORM",
"channels": "rgba",
"componentType": "unorm",
"bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 }
"bits": { "red": 16, "green": 16, "blue": 16, "alpha": 16 },
"glInternalFormat": "GL_RGBA16_EXT"
},
"ANGLE_FORMAT_R16G16B16A16_FLOAT": {
"texFormat": "DXGI_FORMAT_R16G16B16A16_FLOAT",
......@@ -424,8 +425,9 @@
"channels": "bgr",
"componentType": "unorm",
"bits": { "red": 5, "green": 6, "blue": 5 },
"glInternalFormat": "GL_RGB565",
"channelStruct": "R5G6B5"
"glInternalFormat": "GL_BGR565_ANGLEX",
"fboImplementationInternalFormat": "GL_RGB565",
"channelStruct": "B5G6R5"
},
"ANGLE_FORMAT_B5G5R5A1_UNORM": {
"texFormat": "DXGI_FORMAT_B5G5R5A1_UNORM",
......@@ -434,7 +436,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 +482,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": {
......@@ -505,7 +509,8 @@
"rtvFormat": "DXGI_FORMAT_R16_UNORM",
"channels": "r",
"componentType": "unorm",
"bits": { "red": 16 }
"bits": { "red": 16 },
"glInternalFormat": "GL_R16_EXT"
},
"ANGLE_FORMAT_R16G16_UNORM": {
"texFormat": "DXGI_FORMAT_R16G16_UNORM",
......@@ -513,7 +518,8 @@
"rtvFormat": "DXGI_FORMAT_R16G16_UNORM",
"channels": "rg",
"componentType": "unorm",
"bits": { "red": 16, "green": 16 }
"bits": { "red": 16, "green": 16 },
"glInternalFormat": "GL_RG16_EXT"
},
"ANGLE_FORMAT_R16_SNORM": {
"texFormat": "DXGI_FORMAT_R16_SNORM",
......
......@@ -9,6 +9,7 @@
"OnlyFL10Plus": "ANGLE_FORMAT_A8_UNORM",
"OnlyFL9_3": "ANGLE_FORMAT_R8G8B8A8_UNORM"
},
"GL_BGR565_ANGLEX": "ANGLE_FORMAT_B5G6R5_UNORM",
"GL_BGR5_A1_ANGLEX": "ANGLE_FORMAT_B8G8R8A8_UNORM",
"GL_BGRA4_ANGLEX": "ANGLE_FORMAT_B8G8R8A8_UNORM",
"GL_BGRA8_EXT": "ANGLE_FORMAT_B8G8R8A8_UNORM",
......@@ -31,6 +32,20 @@
"GL_COMPRESSED_RGBA_S3TC_DXT1_EXT": "ANGLE_FORMAT_BC1_UNORM",
"GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE": "ANGLE_FORMAT_BC2_UNORM",
"GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE": "ANGLE_FORMAT_BC3_UNORM",
"GL_COMPRESSED_RGBA_ASTC_4x4_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_5x4_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_5x5_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_6x5_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_6x6_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_8x5_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_8x6_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_8x8_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_10x5_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_10x6_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_10x8_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_10x10_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_12x10_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGBA_ASTC_12x12_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_RGB_S3TC_DXT1_EXT": "ANGLE_FORMAT_BC1_UNORM",
"GL_COMPRESSED_SIGNED_R11_EAC": {
"OnlyFL10Plus": "ANGLE_FORMAT_R8_SNORM_NONRENDERABLE"
......@@ -38,6 +53,20 @@
"GL_COMPRESSED_SIGNED_RG11_EAC": {
"OnlyFL10Plus": "ANGLE_FORMAT_R8G8_SNORM_NONRENDERABLE"
},
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR": "ANGLE_FORMAT_NONE",
"GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC": {
"OnlyFL10Plus": "ANGLE_FORMAT_R8G8B8A8_UNORM_SRGB_NONRENDERABLE"
},
......
......@@ -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;
......
......@@ -256,6 +256,38 @@ void LoadRGB8ToBGR565(size_t width,
}
}
void LoadRGB565ToBGR565(size_t width,
size_t height,
size_t depth,
const uint8_t *input,
size_t inputRowPitch,
size_t inputDepthPitch,
uint8_t *output,
size_t outputRowPitch,
size_t outputDepthPitch)
{
for (size_t z = 0; z < depth; z++)
{
for (size_t y = 0; y < height; y++)
{
const uint16_t *source =
OffsetDataPointer<uint16_t>(input, y, z, inputRowPitch, inputDepthPitch);
uint16_t *dest =
OffsetDataPointer<uint16_t>(output, y, z, outputRowPitch, outputDepthPitch);
for (size_t x = 0; x < width; x++)
{
// The GL type RGB is packed with with red in the MSB, while the D3D11 type BGR
// is packed with red in the LSB
auto rgb = source[x];
uint16_t r5 = gl::getShiftedData<5, 11>(rgb);
uint16_t g6 = gl::getShiftedData<6, 5>(rgb);
uint16_t b5 = gl::getShiftedData<5, 0>(rgb);
dest[x] = (r5 << 11) | (g6 << 5) | b5;
}
}
}
}
void LoadRGB8ToBGRX8(size_t width, size_t height, size_t depth,
const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch)
......
......@@ -90,6 +90,16 @@ void LoadRGB8ToBGR565(size_t width,
size_t outputRowPitch,
size_t outputDepthPitch);
void LoadRGB565ToBGR565(size_t width,
size_t height,
size_t depth,
const uint8_t *input,
size_t inputRowPitch,
size_t inputDepthPitch,
uint8_t *output,
size_t outputRowPitch,
size_t outputDepthPitch);
void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth,
const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch,
uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch);
......
......@@ -295,7 +295,7 @@ struct R5G6B5
// most significant
// bits of the bitfield, and successive component occupying progressively less significant
// locations"
unsigned short RGB;
uint16_t RGB;
static void readColor(gl::ColorF *dst, const R5G6B5 *src)
{
......@@ -307,9 +307,9 @@ struct R5G6B5
static void writeColor(R5G6B5 *dst, const gl::ColorF *src)
{
dst->RGB = gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red)) |
gl::shiftData<6, 5>(gl::floatToNormalized<6, unsigned short>(src->green)) |
gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue));
dst->RGB = gl::shiftData<5, 11>(gl::floatToNormalized<5, uint16_t>(src->red)) |
gl::shiftData<6, 5>(gl::floatToNormalized<6, uint16_t>(src->green)) |
gl::shiftData<5, 0>(gl::floatToNormalized<5, uint16_t>(src->blue));
}
static void average(R5G6B5 *dst, const R5G6B5 *src1, const R5G6B5 *src2)
......@@ -323,6 +323,36 @@ struct R5G6B5
}
};
struct B5G6R5
{
uint16_t BGR;
static void readColor(gl::ColorF *dst, const B5G6R5 *src)
{
dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->BGR));
dst->green = gl::normalizedToFloat<6>(gl::getShiftedData<6, 5>(src->BGR));
dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->BGR));
dst->alpha = 1.0f;
}
static void writeColor(B5G6R5 *dst, const gl::ColorF *src)
{
dst->BGR = gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)) |
gl::shiftData<6, 5>(gl::floatToNormalized<6, unsigned short>(src->green)) |
gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red));
}
static void average(B5G6R5 *dst, const B5G6R5 *src1, const B5G6R5 *src2)
{
dst->BGR = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->BGR),
gl::getShiftedData<5, 11>(src2->BGR))) |
gl::shiftData<6, 5>(gl::average(gl::getShiftedData<6, 5>(src1->BGR),
gl::getShiftedData<6, 5>(src2->BGR))) |
gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->BGR),
gl::getShiftedData<5, 0>(src2->BGR)));
}
};
struct A8R8G8B8
{
unsigned char A;
......@@ -621,7 +651,7 @@ struct R4G4B4A4
struct A4R4G4B4
{
unsigned short ARGB;
uint16_t ARGB;
static void readColor(gl::ColorF *dst, const A4R4G4B4 *src)
{
......@@ -633,10 +663,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)
......
......@@ -194,6 +194,8 @@ void PackPixels(const PackPixelsParams &params,
return;
}
ASSERT(sourceFormatInfo.pixelBytes > 0);
gl::FormatType formatType(params.format, params.type);
ColorCopyFunction fastCopyFunc = GetFastCopyFunction(fastCopyFunctionsMap, formatType);
GLenum sizedDestInternalFormat = gl::GetSizedInternalFormat(formatType.format, formatType.type);
......
......@@ -9,11 +9,30 @@
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
#include "libANGLE/renderer/imageformats.h"
using namespace angle;
namespace
{
GLColor Convert565(const rx::R5G6B5 &rgb565)
{
gl::ColorF colorf;
rx::R5G6B5::readColor(&colorf, &rgb565);
Vector4 vecColor(colorf.red, colorf.green, colorf.blue, colorf.alpha);
return GLColor(vecColor);
}
rx::R5G6B5 Convert565(const GLColor &glColor)
{
const Vector4 &vecColor = glColor.toNormalizedVector();
gl::ColorF colorf(vecColor.x, vecColor.y, vecColor.z, vecColor.w);
rx::R5G6B5 rgb565;
rx::R5G6B5::writeColor(&rgb565, &colorf);
return rgb565;
}
class SixteenBppTextureTest : public ANGLETest
{
protected:
......@@ -143,13 +162,11 @@ TEST_P(SixteenBppTextureTest, RGB565Validation)
return;
}
GLushort pixels[4] =
{
0xF800, // Red
0x07E0, // Green
0x001F, // Blue
0xFFE0 // Red + Green
};
GLuint test;
memcpy(&test, &GLColor::black, 4);
rx::R5G6B5 pixels[4] = {Convert565(GLColor::red), Convert565(GLColor::green),
Convert565(GLColor::blue), Convert565(GLColor::yellow)};
glClearColor(0, 0, 0, 0);
......@@ -379,6 +396,148 @@ 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 (IsOpenGLES())
{
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();
}
// Test reading from RGB565 textures attached to FBO.
TEST_P(SixteenBppTextureTestES3, RGB565FramebufferReadback)
{
// TODO(jmadill): Fix bug with GLES
if (IsOpenGLES())
{
std::cout << "Test skipped on GLES." << std::endl;
return;
}
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
std::vector<GLColor> fourColors;
fourColors.push_back(GLColor::red);
fourColors.push_back(GLColor::green);
fourColors.push_back(GLColor::blue);
fourColors.push_back(GLColor::white);
const std::string &vertexShader =
"#version 300 es\n"
"in vec4 color;\n"
"in vec2 position;\n"
"out vec4 fcolor;\n"
"void main() {\n"
" fcolor = color;\n"
" gl_Position = vec4(position, 0.5, 1.0);\n"
"}";
const std::string &fragmentShader =
"#version 300 es\n"
"in mediump vec4 fcolor;\n"
"out mediump vec4 color;\n"
"void main() {\n"
" color = fcolor;\n"
"}";
GLuint program = CompileProgram(vertexShader, fragmentShader);
glUseProgram(program);
GLint colorLocation = glGetAttribLocation(program, "color");
ASSERT_NE(-1, colorLocation);
glEnableVertexAttribArray(colorLocation);
glVertexAttribPointer(colorLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, fourColors.data());
int w = getWindowWidth();
int h = getWindowHeight();
glViewport(0, 0, w, h);
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex.get());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.get(), 0);
drawIndexedQuad(program, "position", 0.5f);
ASSERT_GL_NO_ERROR();
int t = 12;
EXPECT_PIXEL_COLOR_NEAR(0, h - 1, GLColor::red, t);
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::green, t);
EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, GLColor::blue, t);
EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, GLColor::white, t);
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_RGB && colorReadType == GL_UNSIGNED_SHORT_5_6_5)
{
std::vector<rx::R5G6B5> readColors(w * h);
glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, readColors.data());
int hoffset = (h - 1) * w;
EXPECT_COLOR_NEAR(GLColor::red, Convert565(readColors[hoffset]), t);
EXPECT_COLOR_NEAR(GLColor::green, Convert565(readColors[0]), t);
EXPECT_COLOR_NEAR(GLColor::blue, Convert565(readColors[w - 1]), t);
EXPECT_COLOR_NEAR(GLColor::white, Convert565(readColors[w - 1 + hoffset]), t);
}
glDeleteProgram(program);
}
// 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(),
......
......@@ -15,6 +15,7 @@
namespace angle
{
const GLColorRGB GLColorRGB::black(0u, 0u, 0u);
const GLColorRGB GLColorRGB::blue(0u, 0u, 255u);
const GLColorRGB GLColorRGB::green(0u, 255u, 0u);
const GLColorRGB GLColorRGB::red(255u, 0u, 0u);
......@@ -37,6 +38,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
{
......@@ -89,6 +95,17 @@ void TestPlatform::enableMessages()
}
TestPlatform g_testPlatformInstance;
std::array<Vector3, 4> GetIndexedQuadVertices()
{
std::array<Vector3, 4> vertices;
vertices[0] = Vector3(-1.0f, 1.0f, 0.5f);
vertices[1] = Vector3(-1.0f, -1.0f, 0.5f);
vertices[2] = Vector3(1.0f, -1.0f, 0.5f);
vertices[3] = Vector3(1.0f, 1.0f, 0.5f);
return vertices;
}
} // anonymous namespace
GLColorRGB::GLColorRGB() : R(0), G(0), B(0)
......@@ -99,6 +116,11 @@ GLColorRGB::GLColorRGB(GLubyte r, GLubyte g, GLubyte b) : R(r), G(g), B(b)
{
}
GLColorRGB::GLColorRGB(const Vector3 &floatColor)
: R(ColorDenorm(floatColor.x)), G(ColorDenorm(floatColor.y)), B(ColorDenorm(floatColor.z))
{
}
GLColor::GLColor() : R(0), G(0), B(0), A(0)
{
}
......@@ -107,6 +129,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));
......@@ -169,6 +207,19 @@ std::ostream &operator<<(std::ostream &ostream, const GLColor16 &color)
} // namespace angle
// static
std::array<Vector3, 6> ANGLETest::GetQuadVertices()
{
std::array<Vector3, 6> vertices;
vertices[0] = Vector3(-1.0f, 1.0f, 0.5f);
vertices[1] = Vector3(-1.0f, -1.0f, 0.5f);
vertices[2] = Vector3(1.0f, -1.0f, 0.5f);
vertices[3] = Vector3(-1.0f, 1.0f, 0.5f);
vertices[4] = Vector3(1.0f, -1.0f, 0.5f);
vertices[5] = Vector3(1.0f, 1.0f, 0.5f);
return vertices;
}
ANGLETest::ANGLETest()
: mEGLWindow(nullptr),
mWidth(16),
......@@ -261,19 +312,6 @@ void ANGLETest::swapBuffers()
}
}
// static
std::array<Vector3, 6> ANGLETest::GetQuadVertices()
{
std::array<Vector3, 6> vertices;
vertices[0] = Vector3(-1.0f, 1.0f, 0.5f);
vertices[1] = Vector3(-1.0f, -1.0f, 0.5f);
vertices[2] = Vector3(1.0f, -1.0f, 0.5f);
vertices[3] = Vector3(-1.0f, 1.0f, 0.5f);
vertices[4] = Vector3(1.0f, -1.0f, 0.5f);
vertices[5] = Vector3(1.0f, 1.0f, 0.5f);
return vertices;
}
void ANGLETest::setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale)
{
if (mQuadVertexBuffer == 0)
......@@ -293,6 +331,25 @@ void ANGLETest::setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionA
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 6, quadVertices.data(), GL_STATIC_DRAW);
}
void ANGLETest::setupIndexedQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale)
{
if (mQuadVertexBuffer == 0)
{
glGenBuffers(1, &mQuadVertexBuffer);
}
auto quadVertices = angle::GetIndexedQuadVertices();
for (Vector3 &vertex : quadVertices)
{
vertex.x *= positionAttribXYScale;
vertex.y *= positionAttribXYScale;
vertex.z = positionAttribZ;
}
glBindBuffer(GL_ARRAY_BUFFER, mQuadVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 4, quadVertices.data(), GL_STATIC_DRAW);
}
// static
void ANGLETest::drawQuad(GLuint program,
const std::string &positionAttribName,
......@@ -380,7 +437,7 @@ void ANGLETest::drawIndexedQuad(GLuint program,
GLuint prevBinding = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, reinterpret_cast<GLint *>(&prevBinding));
setupQuadVertexBuffer(positionAttribZ, positionAttribXYScale);
setupIndexedQuadVertexBuffer(positionAttribZ, positionAttribXYScale);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(positionLocation);
......
......@@ -48,19 +48,25 @@ struct GLColorRGB
{
GLColorRGB();
GLColorRGB(GLubyte r, GLubyte g, GLubyte b);
GLColorRGB(const Vector3 &floatColor);
GLubyte R, G, B;
static const GLColorRGB black;
static const GLColorRGB blue;
static const GLColorRGB green;
static const GLColorRGB red;
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 +125,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 +136,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;
......@@ -155,6 +174,7 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters>
virtual void swapBuffers();
void setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale);
void setupIndexedQuadVertexBuffer(GLfloat positionAttribZ, GLfloat positionAttribXYScale);
void drawQuad(GLuint program, const std::string &positionAttribName, GLfloat positionAttribZ);
void drawQuad(GLuint program,
......
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