Commit 7828506a by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Cleanup buffer format fallbacks

- Fallbacks for formats that have required vertex attribute support are removed. - Fallbacks are changed to ones with smaller sizes - A bug is fixed where CopyNativeVertexData wasn't initializing the alpha channel appropriately, which was not exercised due to fallback to 32-bit float formats. Bug: b/184163871 Change-Id: Icd9afa49d94c65545d1f3fcf521881726d64529d Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2809441Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 730bbcbb
......@@ -4,7 +4,7 @@
"src/libANGLE/renderer/Format_table_autogen.cpp":
"b28fd3a6ed2ff60197dbb40c4b122d31",
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4",
"74d6c9842128293118ccf128aeae896a",
"src/libANGLE/renderer/angle_format_data.json":
"10e2ee1ed8ee54226edb644de30f512d",
"src/libANGLE/renderer/angle_format_map.json":
......
{
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4",
"74d6c9842128293118ccf128aeae896a",
"src/libANGLE/renderer/gen_load_functions_table.py":
"c131c494e7e0b35b65a8a097b4b8e5ce",
"src/libANGLE/renderer/load_functions_data.json":
......
{
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4",
"74d6c9842128293118ccf128aeae896a",
"src/libANGLE/renderer/d3d/d3d11/gen_texture_format_table.py":
"bbb56f0a35bb2506524654444c8210d3",
"src/libANGLE/renderer/d3d/d3d11/texture_format_data.json":
......
{
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4",
"74d6c9842128293118ccf128aeae896a",
"src/libANGLE/renderer/angle_format_map.json":
"5cfbdcad0391a5d70dca1466c5361ee4",
"src/libANGLE/renderer/dxgi_format_data.json":
......
......@@ -6,5 +6,5 @@
"src/libANGLE/gen_copy_conversion_table.py":
"0a73b7580342b9e27d4c71ade3af55e5",
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4"
"74d6c9842128293118ccf128aeae896a"
}
\ No newline at end of file
......@@ -8,5 +8,5 @@
"src/libANGLE/gen_format_map.py":
"2421e2cfb4e074ae3fa6baa031c6394e",
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4"
"74d6c9842128293118ccf128aeae896a"
}
\ No newline at end of file
{
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4",
"74d6c9842128293118ccf128aeae896a",
"src/libANGLE/renderer/angle_format_map.json":
"5cfbdcad0391a5d70dca1466c5361ee4",
"src/libANGLE/renderer/gen_angle_format_table.py":
......@@ -24,7 +24,7 @@
"src/libANGLE/renderer/metal/shaders/gen_mtl_internal_shaders.py":
"ba74ebbfa2ceb825f36e84f2985b3d3d",
"src/libANGLE/renderer/metal/shaders/mtl_default_shaders_src_autogen.inc":
"12c9d71bde88dd305c2b1088ecd2d1c4",
"c9dbe9e35cd7e84104687bb04730a3c4",
"src/libANGLE/renderer/metal/shaders/visibility.metal":
"b82aa740cf4b0aed606aacef1024beea"
}
\ No newline at end of file
{
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4",
"74d6c9842128293118ccf128aeae896a",
"src/libANGLE/renderer/angle_format_map.json":
"5cfbdcad0391a5d70dca1466c5361ee4",
"src/libANGLE/renderer/metal/gen_mtl_format_table.py":
......
......@@ -2,7 +2,7 @@
"scripts/gl.xml":
"2a73a58a7e26d8676a2c0af6d528cae6",
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4",
"74d6c9842128293118ccf128aeae896a",
"src/libANGLE/renderer/gl/DispatchTableGL_autogen.cpp":
"54a5c8b87d54114ee61a4c535931ea48",
"src/libANGLE/renderer/gl/DispatchTableGL_autogen.h":
......
{
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4",
"74d6c9842128293118ccf128aeae896a",
"src/libANGLE/renderer/angle_format_map.json":
"5cfbdcad0391a5d70dca1466c5361ee4",
"src/libANGLE/renderer/vulkan/gen_vk_format_table.py":
"ffeebc0e8ec8db860e472c7cf04cd880",
"src/libANGLE/renderer/vulkan/vk_format_map.json":
"62dfb5531d601d774ce4729c0daac896",
"e95cc5c7cdeec22369acb5dfb811303e",
"src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp":
"043dfad0df3e00e759ba8959f4178714"
"559bf794dcccf632481864189b1469ab"
}
\ No newline at end of file
{
"src/libANGLE/renderer/angle_format.py":
"35b819b32d3259961da75f5c971baba4",
"74d6c9842128293118ccf128aeae896a",
"src/libANGLE/renderer/vulkan/gen_vk_mandatory_format_support_table.py":
"3e2b8cd80373275e862bb7c8ba20a745",
"src/libANGLE/renderer/vulkan/vk_format_map.json":
"62dfb5531d601d774ce4729c0daac896",
"e95cc5c7cdeec22369acb5dfb811303e",
"src/libANGLE/renderer/vulkan/vk_mandatory_format_support_data.json":
"fa2bd54c1bb0ab2cf1d386061a4bc5c5",
"src/libANGLE/renderer/vulkan/vk_mandatory_format_support_table_autogen.cpp":
......
......@@ -242,8 +242,9 @@ def get_vertex_copy_function(src_format, dst_format):
if dst_format == "NONE":
return "nullptr"
num_channel = len(get_channel_tokens(src_format))
if num_channel < 1 or num_channel > 4:
src_num_channel = len(get_channel_tokens(src_format))
dst_num_channel = len(get_channel_tokens(dst_format))
if src_num_channel < 1 or src_num_channel > 4:
return "nullptr"
if src_format.endswith('_VERTEX'):
......@@ -259,7 +260,7 @@ def get_vertex_copy_function(src_format, dst_format):
if 'FIXED' in src_format:
assert 'FLOAT' in dst_format, (
'get_vertex_copy_function: can only convert fixed to float,' + ' not to ' + dst_format)
return 'Copy32FixedTo32FVertexData<%d, %d>' % (num_channel, num_channel)
return 'Copy32FixedTo32FVertexData<%d, %d>' % (src_num_channel, dst_num_channel)
src_gl_type = get_format_gl_type(src_format)
dst_gl_type = get_format_gl_type(dst_format)
......@@ -268,13 +269,24 @@ def get_vertex_copy_function(src_format, dst_format):
return "nullptr"
if src_gl_type == dst_gl_type:
dst_num_channel = len(get_channel_tokens(dst_format))
return 'CopyNativeVertexData<%s, %d, %d, 0>' % (src_gl_type, num_channel, dst_num_channel)
default_alpha = '1'
if src_num_channel == dst_num_channel or dst_num_channel < 4:
default_alpha = '0'
elif 'A16_FLOAT' in dst_format:
default_alpha = 'gl::Float16One'
elif 'A32_FLOAT' in dst_format:
default_alpha = 'gl::Float32One'
elif 'NORM' in dst_format:
default_alpha = 'std::numeric_limits<%s>::max()' % (src_gl_type)
return 'CopyNativeVertexData<%s, %d, %d, %s>' % (src_gl_type, src_num_channel,
dst_num_channel, default_alpha)
assert 'FLOAT' in dst_format, (
'get_vertex_copy_function: can only convert to float,' + ' not to ' + dst_format)
normalized = 'true' if 'NORM' in src_format else 'false'
dst_is_half = 'true' if dst_gl_type == 'GLhalf' else 'false'
return "CopyToFloatVertexData<%s, %d, %d, %s, %s>" % (src_gl_type, num_channel, num_channel,
normalized, dst_is_half)
return "CopyToFloatVertexData<%s, %d, %d, %s, %s>" % (src_gl_type, src_num_channel,
dst_num_channel, normalized, dst_is_half)
......@@ -227,15 +227,22 @@ inline void CopyToFloatVertexData(const uint8_t *input,
}
}
// This would require special padding.
static_assert(!(inputComponentCount < 4 && outputComponentCount == 4),
"An inputComponentCount less than 4 and an outputComponentCount equal to 4 "
"is not supported.");
for (size_t j = inputComponentCount; j < outputComponentCount; j++)
{
offsetOutput[j] = 0;
}
if (inputComponentCount < 4 && outputComponentCount == 4)
{
if (toHalf)
{
offsetOutput[3] = gl::Float16One;
}
else
{
offsetOutput[3] = static_cast<outputType>(gl::Float32One);
}
}
}
}
......
......@@ -14,7 +14,7 @@ static char gDefaultMetallibSrc[] = R"(
# 1 "temp_master_source.metal"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 369 "<built-in>" 3
# 386 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "temp_master_source.metal" 2
......
......@@ -63,8 +63,6 @@ constexpr uint32_t kOverlayDrawFontBinding = 4;
constexpr uint32_t kGenerateMipmapDestinationBinding = 0;
constexpr uint32_t kGenerateMipmapSourceBinding = 1;
constexpr uint32_t kFloatOneAsUint = 0x3F80'0000u;
bool ValidateFloatOneAsUint()
{
union
......@@ -72,7 +70,7 @@ bool ValidateFloatOneAsUint()
uint32_t asUint;
float asFloat;
} one;
one.asUint = kFloatOneAsUint;
one.asUint = gl::Float32One;
return one.asFloat == 1.0f;
}
......@@ -88,6 +86,8 @@ uint32_t GetConvertVertexFlags(const UtilsVk::ConvertVertexParameters &params)
bool destIsSint = params.destFormat->isSint();
bool destIsUint = params.destFormat->isUint();
bool destIsSnorm = params.destFormat->isSnorm();
bool destIsUnorm = params.destFormat->isUnorm();
bool destIsFloat = params.destFormat->isFloat();
bool destIsHalfFloat = params.destFormat->isVertexTypeHalfFloat();
......@@ -99,7 +99,8 @@ uint32_t GetConvertVertexFlags(const UtilsVk::ConvertVertexParameters &params)
// One of each bool set must be true
ASSERT(srcIsSint || srcIsUint || srcIsSnorm || srcIsUnorm || srcIsFixed || srcIsFloat);
ASSERT(destIsSint || destIsUint || destIsFloat || destIsHalfFloat);
ASSERT(destIsSint || destIsUint || destIsSnorm || destIsUnorm || destIsFloat ||
destIsHalfFloat);
// We currently don't have any big-endian devices in the list of supported platforms. The
// shader is capable of supporting big-endian architectures, but the relevant flag (IsBigEndian)
......@@ -115,6 +116,13 @@ uint32_t GetConvertVertexFlags(const UtilsVk::ConvertVertexParameters &params)
// Note that HalfFloat conversion uses the same shader as Uint.
flags = ConvertVertex_comp::kUintToUint;
}
else if ((srcIsSnorm && destIsSnorm) || (srcIsUnorm && destIsUnorm))
{
// Do snorm->snorm and unorm->unorm copies using the uint->uint shader. Currently only
// supported for same-width formats, so it's only used when adding channels.
ASSERT(params.srcFormat->redBits == params.destFormat->redBits);
flags = ConvertVertex_comp::kUintToUint;
}
else if (srcIsSint && destIsSint)
{
flags = ConvertVertex_comp::kSintToSint;
......@@ -1793,7 +1801,7 @@ angle::Result UtilsVk::convertVertexBuffer(ContextVk *contextVk,
shaderParams.componentCount = static_cast<uint32_t>(params.vertexCount * shaderParams.Nd);
// Total number of 4-byte outputs is the number of components divided by how many components can
// fit in a 4-byte value. Note that this value is also the invocation size of the shader.
shaderParams.outputCount = shaderParams.componentCount / shaderParams.Ed;
shaderParams.outputCount = UnsignedCeilDivide(shaderParams.componentCount, shaderParams.Ed);
shaderParams.srcOffset = static_cast<uint32_t>(params.srcOffset);
shaderParams.destOffset = static_cast<uint32_t>(params.destOffset);
......@@ -1816,13 +1824,35 @@ angle::Result UtilsVk::convertVertexBuffer(ContextVk *contextVk,
switch (flags)
{
case ConvertVertex_comp::kSintToSint:
case ConvertVertex_comp::kUintToUint:
case ConvertVertex_comp::kSintToFloat:
case ConvertVertex_comp::kUintToFloat:
// For integers, alpha should take a value of 1.
shaderParams.srcEmulatedAlpha = 1;
break;
case ConvertVertex_comp::kUintToUint:
// For integers, alpha should take a value of 1. However, uint->uint is also used to
// add channels to RGB snorm, unorm and half formats.
if (params.destFormat->isSnorm())
{
// See case ConvertVertex_comp::kSnormToFloat below.
shaderParams.srcEmulatedAlpha = srcValueMask >> 1;
}
else if (params.destFormat->isUnorm())
{
// See case ConvertVertex_comp::kUnormToFloat below.
shaderParams.srcEmulatedAlpha = srcValueMask;
}
else if (params.destFormat->isVertexTypeHalfFloat())
{
shaderParams.srcEmulatedAlpha = gl::Float16One;
}
else
{
shaderParams.srcEmulatedAlpha = 1;
}
break;
case ConvertVertex_comp::kSnormToFloat:
// The largest signed number with as many bits as the alpha channel of the source is
// 0b011...1 which is srcValueMask >> 1
......@@ -1842,7 +1872,7 @@ angle::Result UtilsVk::convertVertexBuffer(ContextVk *contextVk,
case ConvertVertex_comp::kFloatToFloat:
ASSERT(ValidateFloatOneAsUint());
shaderParams.srcEmulatedAlpha = kFloatOneAsUint;
shaderParams.srcEmulatedAlpha = gl::Float32One;
break;
default:
......@@ -2942,14 +2972,13 @@ angle::Result UtilsVk::copyImageBits(ContextVk *contextVk,
else if (shaderParams.Bd == 2)
{
ASSERT(dstImageFormat.isFloat());
// 1.0 in half-float is represented with 0 01111 0000000000
shaderParams.srcEmulatedAlpha = 0x3C00;
shaderParams.srcEmulatedAlpha = gl::Float16One;
}
else if (shaderParams.Bd == 4)
{
ASSERT(dstImageFormat.isFloat());
ASSERT(ValidateFloatOneAsUint());
shaderParams.srcEmulatedAlpha = kFloatOneAsUint;
shaderParams.srcEmulatedAlpha = gl::Float32One;
}
else
{
......
......@@ -202,10 +202,6 @@
"R5G5B5A1_UNORM": {
"image": "A1R5G5B5_UNORM"
},
"R8G8B8_UNORM": {
"image": "R8G8B8A8_UNORM",
"buffer": "R32G32B32_FLOAT"
},
"R8G8B8_UNORM_SRGB": {
"image": "R8G8B8A8_UNORM_SRGB"
},
......@@ -355,45 +351,31 @@
"image": ["D24_UNORM_S8_UINT", "D32_FLOAT_S8X24_UINT", "S8_UINT"]
},
"R8_UNORM": {
"buffer": "R32_FLOAT"
},
"R8_SNORM": {
"buffer": "R32_FLOAT"
},
"R8_USCALED": {
"buffer": "R32_FLOAT"
"buffer": "R16_FLOAT"
},
"R8_SSCALED": {
"buffer": "R32_FLOAT"
},
"R8G8_UNORM": {
"buffer": "R32G32_FLOAT"
},
"R8G8_SNORM": {
"buffer": "R32G32_FLOAT"
"buffer": "R16_FLOAT"
},
"R8G8_USCALED": {
"buffer": "R32G32_FLOAT"
"buffer": "R16G16_FLOAT"
},
"R8G8_SSCALED": {
"buffer": "R32G32_FLOAT"
"buffer": "R16G16_FLOAT"
},
"R8G8B8_UNORM": {
"image": "R8G8B8A8_UNORM",
"buffer": "R8G8B8A8_UNORM"
},
"R8G8B8_SNORM": {
"image": "R8G8B8A8_SNORM",
"buffer": "R32G32B32_FLOAT"
"buffer": "R8G8B8A8_SNORM"
},
"R8G8B8_USCALED": {
"buffer": "R32G32B32_FLOAT"
"buffer": ["R16G16B16_FLOAT", "R16G16B16A16_FLOAT"]
},
"R8G8B8_SSCALED": {
"buffer": "R32G32B32_FLOAT"
},
"R8G8B8A8_UNORM": {
"buffer": "R16G16B16A16_FLOAT"
},
"R8G8B8A8_SNORM": {
"buffer": "R16G16B16A16_FLOAT"
"buffer": ["R16G16B16_FLOAT", "R16G16B16A16_FLOAT"]
},
"R8G8B8A8_USCALED": {
"buffer": "R16G16B16A16_FLOAT"
......@@ -402,47 +384,37 @@
"buffer": "R16G16B16A16_FLOAT"
},
"R16_UNORM": {
"buffer": "R32_FLOAT"
},
"R16_SNORM": {
"buffer": "R32_FLOAT"
},
"R16_USCALED": {
"buffer": "R32_FLOAT"
"buffer": "R32_FLOAT",
"buffer_compressed": "R16_FLOAT"
},
"R16_SSCALED": {
"buffer": "R32_FLOAT"
},
"R16G16_UNORM": {
"buffer": "R32G32_FLOAT"
},
"R16G16_SNORM": {
"buffer": "R32G32_FLOAT"
"buffer": "R32_FLOAT",
"buffer_compressed": "R16_FLOAT"
},
"R16G16_USCALED": {
"buffer": "R32G32_FLOAT"
"buffer": "R32G32_FLOAT",
"buffer_compressed": "R16G16_FLOAT"
},
"R16G16_SSCALED": {
"buffer": "R32G32_FLOAT"
"buffer": "R32G32_FLOAT",
"buffer_compressed": "R16G16_FLOAT"
},
"R16G16B16_UNORM": {
"buffer": "R32G32B32_FLOAT"
"buffer": "R32G32B32_FLOAT",
"buffer_compressed": ["R16G16B16_FLOAT", "R16G16B16A16_FLOAT"]
},
"R16G16B16_SNORM": {
"buffer": "R32G32B32_FLOAT"
"buffer": "R32G32B32_FLOAT",
"buffer_compressed": ["R16G16B16_FLOAT", "R16G16B16A16_FLOAT"]
},
"R16G16B16_USCALED": {
"buffer": "R32G32B32_FLOAT"
"buffer": "R32G32B32_FLOAT",
"buffer_compressed": ["R16G16B16_FLOAT", "R16G16B16A16_FLOAT"]
},
"R16G16B16_SSCALED": {
"buffer": "R32G32B32_FLOAT"
},
"R16G16B16A16_UNORM": {
"buffer": "R32G32B32A32_FLOAT"
},
"R16G16B16A16_SNORM": {
"buffer": "R32G32B32A32_FLOAT"
"buffer": "R32G32B32_FLOAT",
"buffer_compressed": ["R16G16B16_FLOAT", "R16G16B16A16_FLOAT"]
},
"R16G16B16A16_USCALED": {
"buffer": "R32G32B32A32_FLOAT",
......@@ -480,7 +452,7 @@
},
"R32G32B32_FLOAT": {
"image": "R32G32B32A32_FLOAT",
"buffer_compressed": "R16G16B16A16_FLOAT"
"buffer_compressed": ["R16G16B16_FLOAT", "R16G16B16A16_FLOAT"]
},
"ETC2_R8G8B8_UNORM_BLOCK": {
"image": "R8G8B8A8_UNORM"
......
......@@ -214,9 +214,7 @@ class VertexAttributeTest : public ANGLETest
glEnableVertexAttribArray(mExpectedAttrib);
}
void checkPixels() { checkRGBPixels(true); }
void checkRGBPixels(bool checkAlpha)
void checkPixels()
{
GLint viewportSize[4];
glGetIntegerv(GL_VIEWPORT, viewportSize);
......@@ -227,20 +225,10 @@ class VertexAttributeTest : public ANGLETest
// We need to offset our checks from triangle edges to ensure we don't fall on a single tri
// Avoid making assumptions of drawQuad with four checks to check the four possible tri
// regions
if (checkAlpha)
{
EXPECT_PIXEL_EQ((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255, 255);
EXPECT_PIXEL_EQ((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255, 255);
EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255, 255);
EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255, 255);
}
else
{
EXPECT_PIXEL_RGB_EQUAL((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255);
EXPECT_PIXEL_RGB_EQUAL((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255);
EXPECT_PIXEL_RGB_EQUAL(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255);
EXPECT_PIXEL_RGB_EQUAL(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255);
}
EXPECT_PIXEL_EQ((midPixelX + viewportSize[0]) / 2, midPixelY, 255, 255, 255, 255);
EXPECT_PIXEL_EQ((midPixelX + viewportSize[2]) / 2, midPixelY, 255, 255, 255, 255);
EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[1]) / 2, 255, 255, 255, 255);
EXPECT_PIXEL_EQ(midPixelX, (midPixelY + viewportSize[3]) / 2, 255, 255, 255, 255);
}
void checkPixelsUnEqual()
......@@ -284,16 +272,7 @@ class VertexAttributeTest : public ANGLETest
if (checkPixelEqual)
{
if ((test.type == GL_HALF_FLOAT || test.type == GL_HALF_FLOAT_OES) && IsVulkan() &&
typeSize == 3)
{ // We need a special case for RGB16F format on a Vulkan backend due to the fact
// that in such a usecase, we need to ignore the alpha channel.
checkRGBPixels(false);
}
else
{
checkPixels();
}
checkPixels();
}
else
{
......
......@@ -268,17 +268,6 @@ void LoadEntryPointsWithUtilLoader(angle::GLESDriverType driver);
EXPECT_EQ((a), pixel[3]); \
} while (0)
#define EXPECT_PIXEL_RGB_EQ_HELPER(x, y, r, g, b, ctype, format, type) \
do \
{ \
ctype pixel[4]; \
glReadPixels((x), (y), 1, 1, format, type, pixel); \
EXPECT_GL_NO_ERROR(); \
EXPECT_EQ((r), pixel[0]); \
EXPECT_EQ((g), pixel[1]); \
EXPECT_EQ((b), pixel[2]); \
} while (0)
#define EXPECT_PIXEL_NEAR(x, y, r, g, b, a, abs_error) \
EXPECT_PIXEL_NEAR_HELPER(x, y, r, g, b, a, abs_error, GLubyte, GL_RGBA, GL_UNSIGNED_BYTE)
......@@ -297,9 +286,6 @@ void LoadEntryPointsWithUtilLoader(angle::GLESDriverType driver);
#define EXPECT_PIXEL_16UI_COLOR(x, y, color) \
EXPECT_PIXEL_16UI(x, y, color.R, color.G, color.B, color.A)
#define EXPECT_PIXEL_RGB_EQUAL(x, y, r, g, b) \
EXPECT_PIXEL_RGB_EQ_HELPER(x, y, r, g, b, GLubyte, GL_RGBA, GL_UNSIGNED_BYTE)
// 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)
......
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