Commit 76e6565e by Geoff Lang Committed by Commit Bot

Validate clear attachment formats match color clear types.

TEST=conformance2/rendering/clear-func-buffer-type-match.html BUG=angleproject:1954 Change-Id: Iefeb38041608f11781f87aadb8611737ba2ee96f Reviewed-on: https://chromium-review.googlesource.com/461270 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 005a7016
...@@ -5883,4 +5883,31 @@ bool ValidateVertexFormatBase(ValidationContext *context, ...@@ -5883,4 +5883,31 @@ bool ValidateVertexFormatBase(ValidationContext *context,
return true; return true;
} }
// Perform validation from WebGL 2 section 5.10 "Invalid Clears":
// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
// specified clear value and the type of a buffer that is being cleared generates an
// INVALID_OPERATION error instead of producing undefined results
bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
GLint drawbuffer,
const GLenum *validComponentTypes,
size_t validComponentTypeCount)
{
const FramebufferAttachment *attachment =
context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
if (attachment)
{
GLenum componentType = attachment->getFormat().info->componentType;
const GLenum *end = validComponentTypes + validComponentTypeCount;
if (std::find(validComponentTypes, end, componentType) == end)
{
context->handleError(
Error(GL_INVALID_OPERATION,
"No defined conversion between clear value and attachment format."));
return false;
}
}
return true;
}
} // namespace gl } // namespace gl
...@@ -624,6 +624,11 @@ bool ValidateVertexFormatBase(ValidationContext *context, ...@@ -624,6 +624,11 @@ bool ValidateVertexFormatBase(ValidationContext *context,
GLenum type, GLenum type,
GLboolean pureInteger); GLboolean pureInteger);
bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
GLint drawbuffer,
const GLenum *validComponentTypes,
size_t validComponentTypeCount);
// Error messages shared here for use in testing. // Error messages shared here for use in testing.
extern const char *g_ExceedsMaxElementErrorMessage; extern const char *g_ExceedsMaxElementErrorMessage;
} // namespace gl } // namespace gl
......
...@@ -1965,6 +1965,22 @@ bool ValidateClear(ValidationContext *context, GLbitfield mask) ...@@ -1965,6 +1965,22 @@ bool ValidateClear(ValidationContext *context, GLbitfield mask)
return false; return false;
} }
if (context->getExtensions().webglCompatibility && (mask & GL_COLOR_BUFFER_BIT) != 0)
{
constexpr GLenum validComponentTypes[] = {GL_FLOAT, GL_UNSIGNED_NORMALIZED,
GL_SIGNED_NORMALIZED};
for (GLuint drawBufferIdx = 0; drawBufferIdx < context->getCaps().maxDrawBuffers;
drawBufferIdx++)
{
if (!ValidateWebGLFramebufferAttachmentClearType(
context, drawBufferIdx, validComponentTypes, ArraySize(validComponentTypes)))
{
return false;
}
}
}
return true; return true;
} }
......
...@@ -1481,6 +1481,15 @@ bool ValidateClearBufferiv(ValidationContext *context, ...@@ -1481,6 +1481,15 @@ bool ValidateClearBufferiv(ValidationContext *context,
context->handleError(Error(GL_INVALID_VALUE)); context->handleError(Error(GL_INVALID_VALUE));
return false; return false;
} }
if (context->getExtensions().webglCompatibility)
{
constexpr GLenum validComponentTypes[] = {GL_INT};
if (ValidateWebGLFramebufferAttachmentClearType(
context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes)))
{
return false;
}
}
break; break;
case GL_STENCIL: case GL_STENCIL:
...@@ -1513,6 +1522,15 @@ bool ValidateClearBufferuiv(ValidationContext *context, ...@@ -1513,6 +1522,15 @@ bool ValidateClearBufferuiv(ValidationContext *context,
context->handleError(Error(GL_INVALID_VALUE)); context->handleError(Error(GL_INVALID_VALUE));
return false; return false;
} }
if (context->getExtensions().webglCompatibility)
{
constexpr GLenum validComponentTypes[] = {GL_UNSIGNED_INT};
if (ValidateWebGLFramebufferAttachmentClearType(
context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes)))
{
return false;
}
}
break; break;
default: default:
...@@ -1537,6 +1555,16 @@ bool ValidateClearBufferfv(ValidationContext *context, ...@@ -1537,6 +1555,16 @@ bool ValidateClearBufferfv(ValidationContext *context,
context->handleError(Error(GL_INVALID_VALUE)); context->handleError(Error(GL_INVALID_VALUE));
return false; return false;
} }
if (context->getExtensions().webglCompatibility)
{
constexpr GLenum validComponentTypes[] = {GL_FLOAT, GL_UNSIGNED_NORMALIZED,
GL_SIGNED_NORMALIZED};
if (ValidateWebGLFramebufferAttachmentClearType(
context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes)))
{
return false;
}
}
break; break;
case GL_DEPTH: case GL_DEPTH:
......
...@@ -1288,6 +1288,94 @@ TEST_P(WebGL2CompatibilityTest, TextureCopyingFeedbackLoop3D) ...@@ -1288,6 +1288,94 @@ TEST_P(WebGL2CompatibilityTest, TextureCopyingFeedbackLoop3D)
EXPECT_GL_ERROR(GL_INVALID_OPERATION); EXPECT_GL_ERROR(GL_INVALID_OPERATION);
} }
// Verify that errors are generated when there isn not a defined conversion between the clear type
// and the buffer type.
TEST_P(WebGL2CompatibilityTest, ClearBufferTypeCompatibity)
{
if (IsD3D11())
{
std::cout << "Test skipped because it generates D3D11 runtime warnings." << std::endl;
return;
}
constexpr float clearFloat[] = {0.0f, 0.0f, 0.0f, 0.0f};
constexpr int clearInt[] = {0, 0, 0, 0};
constexpr unsigned int clearUint[] = {0, 0, 0, 0};
GLTexture texture;
GLFramebuffer framebuffer;
glBindTexture(GL_TEXTURE_2D, texture.get());
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
ASSERT_GL_NO_ERROR();
// Unsigned integer buffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32UI, 1, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, nullptr);
ASSERT_GL_NO_ERROR();
glClearBufferfv(GL_COLOR, 0, clearFloat);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glClearBufferiv(GL_COLOR, 0, clearInt);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glClearBufferuiv(GL_COLOR, 0, clearUint);
EXPECT_GL_NO_ERROR();
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
// Integer buffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, 1, 1, 0, GL_RGBA_INTEGER, GL_INT, nullptr);
ASSERT_GL_NO_ERROR();
glClearBufferfv(GL_COLOR, 0, clearFloat);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glClearBufferiv(GL_COLOR, 0, clearInt);
EXPECT_GL_NO_ERROR();
glClearBufferuiv(GL_COLOR, 0, clearUint);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
// Float buffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
ASSERT_GL_NO_ERROR();
glClearBufferfv(GL_COLOR, 0, clearFloat);
EXPECT_GL_NO_ERROR();
glClearBufferiv(GL_COLOR, 0, clearInt);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glClearBufferuiv(GL_COLOR, 0, clearUint);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_NO_ERROR();
// Normalized uint buffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
ASSERT_GL_NO_ERROR();
glClearBufferfv(GL_COLOR, 0, clearFloat);
EXPECT_GL_NO_ERROR();
glClearBufferiv(GL_COLOR, 0, clearInt);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glClearBufferuiv(GL_COLOR, 0, clearUint);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest, ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
......
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