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: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 8f93a05..ab47a90 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -5883,4 +5883,31 @@
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
diff --git a/src/libANGLE/validationES.h b/src/libANGLE/validationES.h
index cc4bd43..56ccfe6 100644
--- a/src/libANGLE/validationES.h
+++ b/src/libANGLE/validationES.h
@@ -624,6 +624,11 @@
GLenum type,
GLboolean pureInteger);
+bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
+ GLint drawbuffer,
+ const GLenum *validComponentTypes,
+ size_t validComponentTypeCount);
+
// Error messages shared here for use in testing.
extern const char *g_ExceedsMaxElementErrorMessage;
} // namespace gl
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index c17e0f8..3b084d4 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -1965,6 +1965,22 @@
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;
}
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
index 9c7d03d..2197ddd 100644
--- a/src/libANGLE/validationES3.cpp
+++ b/src/libANGLE/validationES3.cpp
@@ -1481,6 +1481,15 @@
context->handleError(Error(GL_INVALID_VALUE));
return false;
}
+ if (context->getExtensions().webglCompatibility)
+ {
+ constexpr GLenum validComponentTypes[] = {GL_INT};
+ if (ValidateWebGLFramebufferAttachmentClearType(
+ context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes)))
+ {
+ return false;
+ }
+ }
break;
case GL_STENCIL:
@@ -1513,6 +1522,15 @@
context->handleError(Error(GL_INVALID_VALUE));
return false;
}
+ if (context->getExtensions().webglCompatibility)
+ {
+ constexpr GLenum validComponentTypes[] = {GL_UNSIGNED_INT};
+ if (ValidateWebGLFramebufferAttachmentClearType(
+ context, drawbuffer, validComponentTypes, ArraySize(validComponentTypes)))
+ {
+ return false;
+ }
+ }
break;
default:
@@ -1537,6 +1555,16 @@
context->handleError(Error(GL_INVALID_VALUE));
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;
case GL_DEPTH:
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
index d99c51d..ca56989 100644
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
@@ -1288,6 +1288,94 @@
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
// tests should be run against.
ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,