Commit f607c60a by Geoff Lang Committed by Commit Bot

Fix validation of ReadPixels format and type.

The validation for ReadPixels allows for two combations of format/type: 1. Based on the current framebuffer's component type. * GL_RGBA/GL_UNSIGNED_BYTE if the framebuffer is a normalized (signed or unsigned). * GL_RGBA_INTEGER/GL_INTEGER if the framebuffer is an integer format. * GL_RGBA_INTEGER/GL_UNSIGNED_INTEGER if the framebuffer is an unsigned integer format. * GL_RGBA/GL_FLOAT if the framebuffer is any type of float framebuffer (added in EXT_color_buffer_float). * These combations are detailed in the ES2 spec on pg 105 or ES3 on pg 193. 2. The implementation read format/type returned from glGetIntegerv. * These formats are added by specs, OES_texture_float, EXT_texture_rg, EXT_read_format_bgra, etc. Update the GL and D3D backends to perform the conversion from GL_HALF_FLOAT to GL_HALF_FLOAT_OES. Continue allowing reading as BGRA_EXT to support Skia. Should be removed in the future. BUG=607283 BUG=angleproject:1478 Change-Id: I0312cad4d5f138ab036f383d221f8ccd19a77f6d Reviewed-on: https://chromium-review.googlesource.com/346232 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 1ce09ace
...@@ -352,6 +352,26 @@ bool InternalFormat::isLUMA() const ...@@ -352,6 +352,26 @@ bool InternalFormat::isLUMA() const
(luminanceBits + alphaBits) > 0); (luminanceBits + alphaBits) > 0);
} }
GLenum InternalFormat::getReadPixelsFormat() const
{
return format;
}
GLenum InternalFormat::getReadPixelsType() const
{
switch (type)
{
case GL_HALF_FLOAT:
// The internal format may have a type of GL_HALF_FLOAT but when exposing this type as
// the IMPLEMENTATION_READ_TYPE, only HALF_FLOAT_OES is allowed by
// OES_texture_half_float
return GL_HALF_FLOAT_OES;
default:
return type;
}
}
Format::Format(GLenum internalFormat) : Format(GetInternalFormatInfo(internalFormat)) Format::Format(GLenum internalFormat) : Format(GetInternalFormatInfo(internalFormat))
{ {
} }
......
...@@ -76,6 +76,8 @@ struct InternalFormat ...@@ -76,6 +76,8 @@ struct InternalFormat
const gl::PixelUnpackState &unpack, const gl::PixelUnpackState &unpack,
bool applySkipImages) const; bool applySkipImages) const;
bool isLUMA() const; bool isLUMA() const;
GLenum getReadPixelsFormat() const;
GLenum getReadPixelsType() const;
bool operator==(const InternalFormat &other) const; bool operator==(const InternalFormat &other) const;
bool operator!=(const InternalFormat &other) const; bool operator!=(const InternalFormat &other) const;
......
...@@ -207,7 +207,7 @@ GLenum FramebufferD3D::getImplementationColorReadFormat() const ...@@ -207,7 +207,7 @@ GLenum FramebufferD3D::getImplementationColorReadFormat() const
GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget); GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget);
const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat); const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat);
return implementationFormatInfo.format; return implementationFormatInfo.getReadPixelsFormat();
} }
GLenum FramebufferD3D::getImplementationColorReadType() const GLenum FramebufferD3D::getImplementationColorReadType() const
...@@ -229,7 +229,7 @@ GLenum FramebufferD3D::getImplementationColorReadType() const ...@@ -229,7 +229,7 @@ GLenum FramebufferD3D::getImplementationColorReadType() const
GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget); GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget);
const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat); const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat);
return implementationFormatInfo.type; return implementationFormatInfo.getReadPixelsType();
} }
gl::Error FramebufferD3D::readPixels(ContextImpl *context, gl::Error FramebufferD3D::readPixels(ContextImpl *context,
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "libANGLE/renderer/gl/StateManagerGL.h" #include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/TextureGL.h" #include "libANGLE/renderer/gl/TextureGL.h"
#include "libANGLE/renderer/gl/WorkaroundsGL.h" #include "libANGLE/renderer/gl/WorkaroundsGL.h"
#include "libANGLE/renderer/gl/formatutilsgl.h"
#include "platform/Platform.h" #include "platform/Platform.h"
using namespace gl; using namespace gl;
...@@ -212,14 +213,14 @@ GLenum FramebufferGL::getImplementationColorReadFormat() const ...@@ -212,14 +213,14 @@ GLenum FramebufferGL::getImplementationColorReadFormat() const
{ {
const auto *readAttachment = mState.getReadAttachment(); const auto *readAttachment = mState.getReadAttachment();
const Format &format = readAttachment->getFormat(); const Format &format = readAttachment->getFormat();
return format.info->format; return format.info->getReadPixelsFormat();
} }
GLenum FramebufferGL::getImplementationColorReadType() const GLenum FramebufferGL::getImplementationColorReadType() const
{ {
const auto *readAttachment = mState.getReadAttachment(); const auto *readAttachment = mState.getReadAttachment();
const Format &format = readAttachment->getFormat(); const Format &format = readAttachment->getFormat();
return format.info->type; return format.info->getReadPixelsType();
} }
Error FramebufferGL::readPixels(ContextImpl *context, Error FramebufferGL::readPixels(ContextImpl *context,
...@@ -234,7 +235,11 @@ Error FramebufferGL::readPixels(ContextImpl *context, ...@@ -234,7 +235,11 @@ Error FramebufferGL::readPixels(ContextImpl *context,
mStateManager->setPixelPackState(packState); mStateManager->setPixelPackState(packState);
mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferID); mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferID);
mFunctions->readPixels(area.x, area.y, area.width, area.height, format, type, pixels);
nativegl::ReadPixelsFormat readPixelsFormat =
nativegl::GetReadPixelsFormat(mFunctions, mWorkarounds, format, type);
mFunctions->readPixels(area.x, area.y, area.width, area.height, readPixelsFormat.format,
readPixelsFormat.type, pixels);
return Error(GL_NO_ERROR); return Error(GL_NO_ERROR);
} }
......
...@@ -438,6 +438,32 @@ static GLenum GetNativeType(const FunctionsGL *functions, ...@@ -438,6 +438,32 @@ static GLenum GetNativeType(const FunctionsGL *functions,
return result; return result;
} }
static GLenum GetNativeReadType(const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
GLenum type)
{
GLenum result = type;
if (functions->standard == STANDARD_GL_DESKTOP)
{
if (type == GL_HALF_FLOAT_OES)
{
// The enums differ for the OES half float extensions and desktop GL spec. Update it.
result = GL_HALF_FLOAT;
}
}
return result;
}
static GLenum GetNativeReadFormat(const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
GLenum format)
{
GLenum result = format;
return result;
}
TexImageFormat GetTexImageFormat(const FunctionsGL *functions, TexImageFormat GetTexImageFormat(const FunctionsGL *functions,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
GLenum internalFormat, GLenum internalFormat,
...@@ -512,6 +538,16 @@ RenderbufferFormat GetRenderbufferFormat(const FunctionsGL *functions, ...@@ -512,6 +538,16 @@ RenderbufferFormat GetRenderbufferFormat(const FunctionsGL *functions,
GetNativeInternalFormat(functions, workarounds, internalFormat, internalFormat); GetNativeInternalFormat(functions, workarounds, internalFormat, internalFormat);
return result; return result;
} }
ReadPixelsFormat GetReadPixelsFormat(const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
GLenum format,
GLenum type)
{
ReadPixelsFormat result;
result.format = GetNativeReadFormat(functions, workarounds, format);
result.type = GetNativeReadType(functions, workarounds, type);
return result;
}
} }
} }
...@@ -112,6 +112,16 @@ struct RenderbufferFormat ...@@ -112,6 +112,16 @@ struct RenderbufferFormat
RenderbufferFormat GetRenderbufferFormat(const FunctionsGL *functions, RenderbufferFormat GetRenderbufferFormat(const FunctionsGL *functions,
const WorkaroundsGL &workarounds, const WorkaroundsGL &workarounds,
GLenum internalFormat); GLenum internalFormat);
struct ReadPixelsFormat
{
GLenum format;
GLenum type;
};
ReadPixelsFormat GetReadPixelsFormat(const FunctionsGL *functions,
const WorkaroundsGL &workarounds,
GLenum format,
GLenum type);
} }
} }
......
...@@ -99,6 +99,38 @@ bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxV ...@@ -99,6 +99,38 @@ bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxV
return true; return true;
} }
bool ValidReadPixelsFormatType(ValidationContext *context,
GLenum framebufferComponentType,
GLenum format,
GLenum type)
{
switch (framebufferComponentType)
{
case GL_UNSIGNED_NORMALIZED:
// TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use
// ReadPixels with BGRA even if the extension is not present
return (format == GL_RGBA && type == GL_UNSIGNED_BYTE) ||
(context->getExtensions().readFormatBGRA && format == GL_BGRA_EXT &&
type == GL_UNSIGNED_BYTE);
case GL_SIGNED_NORMALIZED:
return (format == GL_RGBA && type == GL_UNSIGNED_BYTE);
case GL_INT:
return (format == GL_RGBA_INTEGER && type == GL_INT);
case GL_UNSIGNED_INT:
return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT);
case GL_FLOAT:
return (format == GL_RGBA && type == GL_FLOAT);
default:
UNREACHABLE();
return false;
}
}
} // anonymous namespace } // anonymous namespace
bool ValidCap(const Context *context, GLenum cap) bool ValidCap(const Context *context, GLenum cap)
...@@ -1122,12 +1154,12 @@ bool ValidateReadPixels(ValidationContext *context, ...@@ -1122,12 +1154,12 @@ bool ValidateReadPixels(ValidationContext *context,
GLenum currentFormat = framebuffer->getImplementationColorReadFormat(); GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
GLenum currentType = framebuffer->getImplementationColorReadType(); GLenum currentType = framebuffer->getImplementationColorReadType();
GLenum currentInternalFormat = readBuffer->getFormat().asSized(); GLenum currentInternalFormat = readBuffer->getFormat().asSized();
GLuint clientVersion = context->getClientMajorVersion();
bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) : const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(currentInternalFormat);
ValidES3ReadFormatType(context, currentInternalFormat, format, type); bool validFormatTypeCombination =
ValidReadPixelsFormatType(context, internalFormatInfo.componentType, format, type);
if (!(currentFormat == format && currentType == type) && !validReadFormat) if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
{ {
context->handleError(Error(GL_INVALID_OPERATION)); context->handleError(Error(GL_INVALID_OPERATION));
return false; return false;
......
...@@ -1187,52 +1187,6 @@ bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei le ...@@ -1187,52 +1187,6 @@ bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei le
return true; return true;
} }
// check for combinations of format and type that are valid for ReadPixels
bool ValidES2ReadFormatType(ValidationContext *context, GLenum format, GLenum type)
{
switch (format)
{
case GL_RGBA:
switch (type)
{
case GL_UNSIGNED_BYTE:
break;
default:
return false;
}
break;
case GL_BGRA_EXT:
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
break;
default:
return false;
}
break;
case GL_RG_EXT:
case GL_RED_EXT:
if (!context->getExtensions().textureRG)
{
return false;
}
switch (type)
{
case GL_UNSIGNED_BYTE:
break;
default:
return false;
}
break;
default:
return false;
}
return true;
}
bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments, bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments,
const GLenum *attachments) const GLenum *attachments)
{ {
......
...@@ -38,8 +38,6 @@ bool ValidateES2CopyTexImageParameters(ValidationContext *context, ...@@ -38,8 +38,6 @@ bool ValidateES2CopyTexImageParameters(ValidationContext *context,
bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height); GLsizei width, GLsizei height);
bool ValidES2ReadFormatType(ValidationContext *context, GLenum format, GLenum type);
bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments, bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments,
const GLenum *attachments); const GLenum *attachments);
......
...@@ -204,6 +204,7 @@ ES3FormatCombinationSet BuildES3FormatSet() ...@@ -204,6 +204,7 @@ ES3FormatCombinationSet BuildES3FormatSet()
InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES ); InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES );
InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT ); InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT );
InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT ); InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT );
// clang-format on
// From GL_EXT_texture_norm16 // From GL_EXT_texture_norm16
InsertES3FormatCombo(&set, GL_R16_EXT, GL_RED, GL_UNSIGNED_SHORT); InsertES3FormatCombo(&set, GL_R16_EXT, GL_RED, GL_UNSIGNED_SHORT);
...@@ -214,7 +215,6 @@ ES3FormatCombinationSet BuildES3FormatSet() ...@@ -214,7 +215,6 @@ ES3FormatCombinationSet BuildES3FormatSet()
InsertES3FormatCombo(&set, GL_RG16_SNORM_EXT, GL_RG, GL_SHORT); InsertES3FormatCombo(&set, GL_RG16_SNORM_EXT, GL_RG, GL_SHORT);
InsertES3FormatCombo(&set, GL_RGB16_SNORM_EXT, GL_RGB, GL_SHORT); InsertES3FormatCombo(&set, GL_RGB16_SNORM_EXT, GL_RGB, GL_SHORT);
InsertES3FormatCombo(&set, GL_RGBA16_SNORM_EXT, GL_RGBA, GL_SHORT); InsertES3FormatCombo(&set, GL_RGBA16_SNORM_EXT, GL_RGBA, GL_SHORT);
// clang-format on
return set; return set;
} }
...@@ -1271,100 +1271,6 @@ bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum att ...@@ -1271,100 +1271,6 @@ bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum att
return true; return true;
} }
bool ValidES3ReadFormatType(ValidationContext *context,
GLenum internalFormat,
GLenum format,
GLenum type)
{
const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
switch (format)
{
case GL_RGBA:
switch (type)
{
case GL_UNSIGNED_BYTE:
break;
case GL_UNSIGNED_SHORT:
if (internalFormatInfo.componentType != GL_UNSIGNED_NORMALIZED &&
internalFormatInfo.type != GL_UNSIGNED_SHORT)
{
return false;
}
break;
case GL_UNSIGNED_INT_2_10_10_10_REV:
if (internalFormat != GL_RGB10_A2)
{
return false;
}
break;
case GL_FLOAT:
if (internalFormatInfo.componentType != GL_FLOAT)
{
return false;
}
break;
default:
return false;
}
break;
case GL_RGBA_INTEGER:
switch (type)
{
case GL_INT:
if (internalFormatInfo.componentType != GL_INT)
{
return false;
}
break;
case GL_UNSIGNED_INT:
if (internalFormatInfo.componentType != GL_UNSIGNED_INT)
{
return false;
}
break;
default:
return false;
}
break;
case GL_BGRA_EXT:
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
break;
default:
return false;
}
break;
case GL_RG_EXT:
case GL_RED_EXT:
if (!context->getExtensions().textureRG)
{
return false;
}
switch (type)
{
case GL_UNSIGNED_BYTE:
break;
case GL_UNSIGNED_SHORT:
if (internalFormatInfo.componentType != GL_UNSIGNED_NORMALIZED &&
internalFormatInfo.type != GL_UNSIGNED_SHORT)
{
return false;
}
break;
default:
return false;
}
break;
default:
return false;
}
return true;
}
bool ValidateES3RenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples, bool ValidateES3RenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples,
GLenum internalformat, GLsizei width, GLsizei height) GLenum internalformat, GLsizei width, GLsizei height)
{ {
......
...@@ -153,11 +153,6 @@ bool ValidateGetQueryObjectuiv(Context *context, GLuint id, GLenum pname, GLuint ...@@ -153,11 +153,6 @@ bool ValidateGetQueryObjectuiv(Context *context, GLuint id, GLenum pname, GLuint
bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment, bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment,
GLuint texture, GLint level, GLint layer); GLuint texture, GLint level, GLint layer);
bool ValidES3ReadFormatType(ValidationContext *context,
GLenum internalFormat,
GLenum format,
GLenum type);
bool ValidateES3RenderbufferStorageParameters(Context *context, GLenum target, GLsizei samples, bool ValidateES3RenderbufferStorageParameters(Context *context, GLenum target, GLsizei samples,
GLenum internalformat, GLsizei width, GLsizei height); GLenum internalformat, GLsizei width, GLsizei height);
......
...@@ -32,13 +32,12 @@ class BlendMinMaxTest : public ANGLETest ...@@ -32,13 +32,12 @@ class BlendMinMaxTest : public ANGLETest
float values[4]; float values[4];
}; };
static GLubyte getExpected(bool blendMin, float curColor, GLubyte prevColor) static float getExpected(bool blendMin, float curColor, float prevColor)
{ {
GLubyte curAsUbyte = static_cast<GLubyte>((curColor * std::numeric_limits<GLubyte>::max()) + 0.5f); return blendMin ? std::min(curColor, prevColor) : std::max(curColor, prevColor);
return blendMin ? std::min<GLubyte>(curAsUbyte, prevColor) : std::max<GLubyte>(curAsUbyte, prevColor);
} }
void runTest(GLenum colorFormat) void runTest(GLenum colorFormat, GLenum type)
{ {
if (getClientMajorVersion() < 3 && !extensionEnabled("GL_EXT_blend_minmax")) if (getClientMajorVersion() < 3 && !extensionEnabled("GL_EXT_blend_minmax"))
{ {
...@@ -55,17 +54,26 @@ class BlendMinMaxTest : public ANGLETest ...@@ -55,17 +54,26 @@ class BlendMinMaxTest : public ANGLETest
SetUpFramebuffer(colorFormat); SetUpFramebuffer(colorFormat);
const size_t colorCount = 1024; int minValue = 0;
int maxValue = 1;
if (type == GL_FLOAT)
{
minValue = -1024;
maxValue = 1024;
}
const size_t colorCount = 128;
Color colors[colorCount]; Color colors[colorCount];
for (size_t i = 0; i < colorCount; i++) for (size_t i = 0; i < colorCount; i++)
{ {
for (size_t j = 0; j < 4; j++) for (size_t j = 0; j < 4; j++)
{ {
colors[i].values[j] = (rand() % 255) / 255.0f; colors[i].values[j] =
static_cast<float>(minValue + (rand() % (maxValue - minValue)));
} }
} }
GLubyte prevColor[4]; float prevColor[4];
for (size_t i = 0; i < colorCount; i++) for (size_t i = 0; i < colorCount; i++)
{ {
const Color &color = colors[i]; const Color &color = colors[i];
...@@ -77,16 +85,37 @@ class BlendMinMaxTest : public ANGLETest ...@@ -77,16 +85,37 @@ class BlendMinMaxTest : public ANGLETest
drawQuad(mProgram, "aPosition", 0.5f); drawQuad(mProgram, "aPosition", 0.5f);
float pixel[4];
if (type == GL_UNSIGNED_BYTE)
{
GLubyte ubytePixel[4];
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, ubytePixel);
for (size_t componentIdx = 0; componentIdx < ArraySize(pixel); componentIdx++)
{
pixel[componentIdx] = ubytePixel[componentIdx] / 255.0f;
}
}
else if (type == GL_FLOAT)
{
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, pixel);
}
else
{
FAIL() << "Unexpected pixel type";
}
if (i > 0) if (i > 0)
{ {
EXPECT_PIXEL_EQ(0, 0, const float errorRange = 1.0f / 255.0f;
getExpected(blendMin, color.values[0], prevColor[0]), for (size_t componentIdx = 0; componentIdx < ArraySize(pixel); componentIdx++)
getExpected(blendMin, color.values[1], prevColor[1]), {
getExpected(blendMin, color.values[2], prevColor[2]), EXPECT_NEAR(
getExpected(blendMin, color.values[3], prevColor[3])); getExpected(blendMin, color.values[componentIdx], prevColor[componentIdx]),
pixel[componentIdx], errorRange);
}
} }
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, prevColor); memcpy(prevColor, pixel, sizeof(pixel));
} }
} }
...@@ -142,6 +171,9 @@ class BlendMinMaxTest : public ANGLETest ...@@ -142,6 +171,9 @@ class BlendMinMaxTest : public ANGLETest
glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, getWindowWidth(), getWindowHeight()); glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, getWindowWidth(), getWindowHeight());
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mColorRenderbuffer); glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mColorRenderbuffer);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
...@@ -163,10 +195,10 @@ class BlendMinMaxTest : public ANGLETest ...@@ -163,10 +195,10 @@ class BlendMinMaxTest : public ANGLETest
TEST_P(BlendMinMaxTest, RGBA8) TEST_P(BlendMinMaxTest, RGBA8)
{ {
runTest(GL_RGBA8); runTest(GL_RGBA8, GL_UNSIGNED_BYTE);
} }
TEST_P(BlendMinMaxTest, RGBA32f) TEST_P(BlendMinMaxTest, RGBA32F)
{ {
if (getClientMajorVersion() < 3 || !extensionEnabled("GL_EXT_color_buffer_float")) if (getClientMajorVersion() < 3 || !extensionEnabled("GL_EXT_color_buffer_float"))
{ {
...@@ -189,7 +221,7 @@ TEST_P(BlendMinMaxTest, RGBA32f) ...@@ -189,7 +221,7 @@ TEST_P(BlendMinMaxTest, RGBA32f)
return; return;
} }
runTest(GL_RGBA32F); runTest(GL_RGBA32F, GL_FLOAT);
} }
TEST_P(BlendMinMaxTest, RGBA16F) TEST_P(BlendMinMaxTest, RGBA16F)
...@@ -208,21 +240,16 @@ TEST_P(BlendMinMaxTest, RGBA16F) ...@@ -208,21 +240,16 @@ TEST_P(BlendMinMaxTest, RGBA16F)
return; return;
} }
// TODO(geofflang): This fails because readpixels with UNSIGNED_BYTE/RGBA does not work with runTest(GL_RGBA16F, GL_FLOAT);
// half float buffers (http://anglebug.com/1288)
if (GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)
{
std::cout << "Test skipped on OpenGL ES targets." << std::endl;
return;
}
runTest(GL_RGBA16F);
} }
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(BlendMinMaxTest, ANGLE_INSTANTIATE_TEST(BlendMinMaxTest,
ES2_D3D9(), ES2_D3D9(),
ES2_D3D11(), ES2_D3D11(),
ES3_D3D11(),
ES2_D3D11_FL9_3(), ES2_D3D11_FL9_3(),
ES2_OPENGL(), ES2_OPENGL(),
ES2_OPENGLES()); ES3_OPENGL(),
ES2_OPENGLES(),
ES3_OPENGLES());
...@@ -14,24 +14,24 @@ namespace ...@@ -14,24 +14,24 @@ namespace
{ {
// Take a pixel, and reset the components not covered by the format to default // Take a pixel, and reset the components not covered by the format to default
// values. In particular, the default value for the alpha component is 65535 // values. In particular, the default value for the alpha component is 255
// (1.0 as unsigned normalized fixed point value). // (1.0 as unsigned normalized fixed point value).
GLColor16 SliceFormatColor16(GLenum format, GLColor16 full) GLColor SliceFormatColor(GLenum format, GLColor full)
{ {
switch (format) switch (format)
{ {
case GL_RED: case GL_RED:
return GLColor16(full.R, 0, 0, 65535u); return GLColor(full.R, 0, 0, 255u);
case GL_RG: case GL_RG:
return GLColor16(full.R, full.G, 0, 65535u); return GLColor(full.R, full.G, 0, 255u);
case GL_RGB: case GL_RGB:
return GLColor16(full.R, full.G, full.B, 65535u); return GLColor(full.R, full.G, full.B, 255u);
case GL_RGBA: case GL_RGBA:
return full; return full;
default: default:
UNREACHABLE(); UNREACHABLE();
return GLColor::white;
} }
return GLColor16::white;
} }
class TexCoordDrawTest : public ANGLETest class TexCoordDrawTest : public ANGLETest
...@@ -3248,8 +3248,8 @@ class Texture2DNorm16TestES3 : public Texture2DTestES3 ...@@ -3248,8 +3248,8 @@ class Texture2DNorm16TestES3 : public Texture2DTestES3
void testNorm16Texture(GLint internalformat, GLenum format, GLenum type) void testNorm16Texture(GLint internalformat, GLenum format, GLenum type)
{ {
GLushort pixelValue = type == GL_SHORT ? 0x7FFF : 0x6A35; GLushort pixelValue = (type == GL_SHORT) ? 0x7FFF : 0x6A35;
GLColor16 imageData(pixelValue, pixelValue, pixelValue, pixelValue); GLushort imageData[] = {pixelValue, pixelValue, pixelValue, pixelValue};
setUpProgram(); setUpProgram();
...@@ -3261,20 +3261,17 @@ class Texture2DNorm16TestES3 : public Texture2DTestES3 ...@@ -3261,20 +3261,17 @@ class Texture2DNorm16TestES3 : public Texture2DTestES3
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16_EXT, 1, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16_EXT, 1, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT, nullptr);
glBindTexture(GL_TEXTURE_2D, mTextures[1]); glBindTexture(GL_TEXTURE_2D, mTextures[1]);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, 1, 1, 0, format, type, &imageData.R); glTexImage2D(GL_TEXTURE_2D, 0, internalformat, 1, 1, 0, format, type, imageData);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f); drawQuad(mProgram, "position", 0.5f);
GLColor16 expectedValue = imageData; GLubyte expectedValue = (type == GL_SHORT) ? 0xFF : static_cast<GLubyte>(pixelValue >> 8);
if (type == GL_SHORT)
{
// sampled as signed value; then stored as unsigned value
expectedValue = GLColor16::white;
}
EXPECT_PIXEL_COLOR16_EQ(0, 0, SliceFormatColor16(format, expectedValue)); EXPECT_PIXEL_COLOR_EQ(
0, 0, SliceFormatColor(
format, GLColor(expectedValue, expectedValue, expectedValue, expectedValue)));
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
...@@ -3284,7 +3281,7 @@ class Texture2DNorm16TestES3 : public Texture2DTestES3 ...@@ -3284,7 +3281,7 @@ class Texture2DNorm16TestES3 : public Texture2DTestES3
void testNorm16Render(GLint internalformat, GLenum format, GLenum type) void testNorm16Render(GLint internalformat, GLenum format, GLenum type)
{ {
GLushort pixelValue = 0x6A35; GLushort pixelValue = 0x6A35;
GLColor16 imageData(pixelValue, pixelValue, pixelValue, pixelValue); GLushort imageData[] = {pixelValue, pixelValue, pixelValue, pixelValue};
setUpProgram(); setUpProgram();
...@@ -3296,13 +3293,16 @@ class Texture2DNorm16TestES3 : public Texture2DTestES3 ...@@ -3296,13 +3293,16 @@ class Texture2DNorm16TestES3 : public Texture2DTestES3
0); 0);
glBindTexture(GL_TEXTURE_2D, mTextures[2]); glBindTexture(GL_TEXTURE_2D, mTextures[2]);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, 1, 1, 0, format, type, &imageData.R); glTexImage2D(GL_TEXTURE_2D, 0, internalformat, 1, 1, 0, format, type, imageData);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f); drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR16_EQ(0, 0, SliceFormatColor16(format, imageData)); GLubyte expectedValue = static_cast<GLubyte>(pixelValue >> 8);
EXPECT_PIXEL_COLOR_EQ(
0, 0, SliceFormatColor(
format, GLColor(expectedValue, expectedValue, expectedValue, expectedValue)));
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, internalformat, 1, 1); glRenderbufferStorage(GL_RENDERBUFFER, internalformat, 1, 1);
...@@ -3316,8 +3316,7 @@ class Texture2DNorm16TestES3 : public Texture2DTestES3 ...@@ -3316,8 +3316,7 @@ class Texture2DNorm16TestES3 : public Texture2DTestES3
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
GLColor16 expectedValue = GLColor16::white; EXPECT_PIXEL_COLOR_EQ(0, 0, SliceFormatColor(format, GLColor::white));
EXPECT_PIXEL_COLOR16_EQ(0, 0, SliceFormatColor16(format, expectedValue));
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
......
...@@ -30,8 +30,6 @@ const GLColor GLColor::transparentBlack = GLColor(0u, 0u, 0u, 0u); ...@@ -30,8 +30,6 @@ const GLColor GLColor::transparentBlack = GLColor(0u, 0u, 0u, 0u);
const GLColor GLColor::white = GLColor(255u, 255u, 255u, 255u); const GLColor GLColor::white = GLColor(255u, 255u, 255u, 255u);
const GLColor GLColor::yellow = GLColor(255u, 255u, 0, 255u); const GLColor GLColor::yellow = GLColor(255u, 255u, 0, 255u);
const GLColor16 GLColor16::white = GLColor16(65535u, 65535u, 65535u, 65535u);
namespace namespace
{ {
float ColorNorm(GLubyte channelValue) float ColorNorm(GLubyte channelValue)
...@@ -138,14 +136,6 @@ GLColor::GLColor(const Vector4 &floatColor) ...@@ -138,14 +136,6 @@ GLColor::GLColor(const Vector4 &floatColor)
{ {
} }
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) GLColor::GLColor(GLuint colorValue) : R(0), G(0), B(0), A(0)
{ {
memcpy(&R, &colorValue, sizeof(GLuint)); memcpy(&R, &colorValue, sizeof(GLuint));
...@@ -177,35 +167,6 @@ std::ostream &operator<<(std::ostream &ostream, const GLColor &color) ...@@ -177,35 +167,6 @@ std::ostream &operator<<(std::ostream &ostream, const GLColor &color)
return ostream; return ostream;
} }
GLColor16::GLColor16() : R(0), G(0), B(0), A(0)
{
}
GLColor16::GLColor16(GLushort r, GLushort g, GLushort b, GLushort a) : R(r), G(g), B(b), A(a)
{
}
GLColor16 ReadColor16(GLint x, GLint y)
{
GLColor16 actual;
glReadPixels((x), (y), 1, 1, GL_RGBA, GL_UNSIGNED_SHORT, &actual.R);
EXPECT_GL_NO_ERROR();
return actual;
}
bool operator==(const GLColor16 &a, const GLColor16 &b)
{
return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A;
}
std::ostream &operator<<(std::ostream &ostream, const GLColor16 &color)
{
ostream << "(" << static_cast<unsigned int>(color.R) << ", "
<< static_cast<unsigned int>(color.G) << ", " << static_cast<unsigned int>(color.B)
<< ", " << static_cast<unsigned int>(color.A) << ")";
return ostream;
}
} // namespace angle } // namespace angle
// static // static
......
...@@ -59,14 +59,11 @@ struct GLColorRGB ...@@ -59,14 +59,11 @@ struct GLColorRGB
static const GLColorRGB yellow; static const GLColorRGB yellow;
}; };
struct GLColor16;
struct GLColor struct GLColor
{ {
GLColor(); GLColor();
GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a); GLColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a);
GLColor(const Vector4 &floatColor); GLColor(const Vector4 &floatColor);
GLColor(const GLColor16 &color16);
GLColor(GLuint colorValue); GLColor(GLuint colorValue);
Vector4 toNormalizedVector() const; Vector4 toNormalizedVector() const;
...@@ -95,28 +92,6 @@ bool operator==(const GLColor &a, const GLColor &b); ...@@ -95,28 +92,6 @@ bool operator==(const GLColor &a, const GLColor &b);
std::ostream &operator<<(std::ostream &ostream, const GLColor &color); std::ostream &operator<<(std::ostream &ostream, const GLColor &color);
GLColor ReadColor(GLint x, GLint y); GLColor ReadColor(GLint x, GLint y);
struct GLColor16
{
GLColor16();
GLColor16(GLushort r, GLushort g, GLushort b, GLushort a);
GLushort R, G, B, A;
static const GLColor16 white;
};
// Useful to cast any type to GLushort.
template <typename TR, typename TG, typename TB, typename TA>
GLColor16 MakeGLColor16(TR r, TG g, TB b, TA a)
{
return GLColor16(static_cast<GLushort>(r), static_cast<GLushort>(g), static_cast<GLushort>(b),
static_cast<GLushort>(a));
}
bool operator==(const GLColor16 &a, const GLColor16 &b);
std::ostream &operator<<(std::ostream &ostream, const GLColor16 &color);
GLColor16 ReadColor16(GLint x, GLint y);
} // namespace angle } // namespace angle
#define EXPECT_PIXEL_EQ(x, y, r, g, b, a) \ #define EXPECT_PIXEL_EQ(x, y, r, g, b, a) \
...@@ -141,8 +116,6 @@ GLColor16 ReadColor16(GLint x, GLint y); ...@@ -141,8 +116,6 @@ GLColor16 ReadColor16(GLint x, GLint y);
#define EXPECT_PIXEL_COLOR_NEAR(x, y, angleColor, abs_error) \ #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) 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) \ #define EXPECT_COLOR_NEAR(expected, actual, 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