Allow 32-bit float formats in ES2 CopyTexSubImage.
These corner case formats can come about from using floating
point textures and trying to copy between them. There currently
isn't a good alternative in WebGL 1 for copies.
BUG=angle:850
Change-Id: I3dc29e42b5ec7dcf071185bc09c6b3e9e3cb3207
Reviewed-on: https://chromium-review.googlesource.com/241048
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index e5c3da5..9eece1b 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -411,7 +411,8 @@
gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
- GLenum textureFormat = gl::GetInternalFormatInfo(textureInternalFormat).format;
+ const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat);
+ GLenum textureFormat = internalFormatInfo.format;
// [OpenGL ES 2.0.24] table 3.9
if (isSubImage)
@@ -448,7 +449,11 @@
colorbufferFormat != GL_RGB8_OES &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
- colorbufferFormat != GL_RGBA8_OES)
+ colorbufferFormat != GL_RGBA8_OES &&
+ colorbufferFormat != GL_R32F &&
+ colorbufferFormat != GL_RG32F &&
+ colorbufferFormat != GL_RGB32F &&
+ colorbufferFormat != GL_RGBA32F)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -460,7 +465,10 @@
colorbufferFormat != GL_RGB8_OES &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
- colorbufferFormat != GL_RGBA8_OES)
+ colorbufferFormat != GL_RGBA8_OES &&
+ colorbufferFormat != GL_RG32F &&
+ colorbufferFormat != GL_RGB32F &&
+ colorbufferFormat != GL_RGBA32F)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -471,7 +479,9 @@
colorbufferFormat != GL_RGB8_OES &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
- colorbufferFormat != GL_RGBA8_OES)
+ colorbufferFormat != GL_RGBA8_OES &&
+ colorbufferFormat != GL_RGB32F &&
+ colorbufferFormat != GL_RGBA32F)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -481,7 +491,8 @@
case GL_RGBA:
if (colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
- colorbufferFormat != GL_RGBA8_OES)
+ colorbufferFormat != GL_RGBA8_OES &&
+ colorbufferFormat != GL_RGBA32F)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
@@ -501,6 +512,13 @@
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
+
+ if (internalFormatInfo.type == GL_FLOAT &&
+ !context->getExtensions().textureFloat)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
}
else
{
diff --git a/tests/angle_tests/TextureTest.cpp b/tests/angle_tests/TextureTest.cpp
index 1a496d3..468e4a2 100644
--- a/tests/angle_tests/TextureTest.cpp
+++ b/tests/angle_tests/TextureTest.cpp
@@ -6,7 +6,7 @@
template<typename T>
class TextureTest : public ANGLETest
{
-protected:
+ protected:
TextureTest() : ANGLETest(T::GetGlesMajorVersion(), T::GetPlatform())
{
setWindowWidth(128);
@@ -103,6 +103,114 @@
ANGLETest::TearDown();
}
+ // Tests CopyTexSubImage with floating point textures of various formats.
+ void testFloatCopySubImage(int sourceImageChannels, int destImageChannels)
+ {
+ GLfloat sourceImageData[4][16] =
+ {
+ { // R
+ 1.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f
+ },
+ { // RG
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 0.0f, 0.0f,
+ 1.0f, 1.0f
+ },
+ { // RGB
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f
+ },
+ { // RGBA
+ 1.0f, 0.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f
+ },
+ };
+
+ GLenum imageFormats[] =
+ {
+ GL_R32F,
+ GL_RG32F,
+ GL_RGB32F,
+ GL_RGBA32F,
+ };
+
+ GLenum sourceUnsizedFormats[] =
+ {
+ GL_RED,
+ GL_RG,
+ GL_RGB,
+ GL_RGBA,
+ };
+
+ GLuint textures[2];
+
+ glGenTextures(2, textures);
+
+ GLfloat *imageData = sourceImageData[sourceImageChannels - 1];
+ GLenum sourceImageFormat = imageFormats[sourceImageChannels - 1];
+ GLenum sourceUnsizedFormat = sourceUnsizedFormats[sourceImageChannels - 1];
+ GLenum destImageFormat = imageFormats[destImageChannels - 1];
+
+ glBindTexture(GL_TEXTURE_2D, textures[0]);
+ glTexStorage2DEXT(GL_TEXTURE_2D, 1, sourceImageFormat, 2, 2);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, sourceUnsizedFormat, GL_FLOAT, imageData);
+
+ if (sourceImageChannels < 4 && !extensionEnabled("GL_EXT_texture_rg"))
+ {
+ // This is not supported
+ ASSERT_GL_ERROR(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ ASSERT_GL_NO_ERROR();
+ }
+
+ GLuint fbo;
+ glGenFramebuffers(1, &fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
+
+ glBindTexture(GL_TEXTURE_2D, textures[1]);
+ glTexStorage2DEXT(GL_TEXTURE_2D, 1, destImageFormat, 2, 2);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2, 2);
+ ASSERT_GL_NO_ERROR();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ drawQuad(m2DProgram, "position", 0.5f);
+ swapBuffers();
+
+ int testImageChannels = std::min(sourceImageChannels, destImageChannels);
+
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+ if (testImageChannels > 1)
+ {
+ EXPECT_PIXEL_EQ(getWindowHeight() - 1, 0, 0, 255, 0, 255);
+ EXPECT_PIXEL_EQ(getWindowHeight() - 1, getWindowWidth() - 1, 255, 255, 0, 255);
+ if (testImageChannels > 2)
+ {
+ EXPECT_PIXEL_EQ(0, getWindowWidth() - 1, 0, 0, 255, 255);
+ }
+ }
+
+ glDeleteFramebuffers(1, &fbo);
+ glDeleteTextures(2, textures);
+
+ ASSERT_GL_NO_ERROR();
+ }
+
GLuint mTexture2D;
GLuint mTextureCube;
@@ -334,3 +442,61 @@
EXPECT_PIXEL_EQ(width / 4, height / 4, 255, 0, 0, 255);
}
}
+
+// See description on testFloatCopySubImage
+// TODO(jmadill): Fix sampling from unused channels on D3D9
+TYPED_TEST(TextureTest, DISABLED_CopySubImageFloat_R_R)
+{
+ testFloatCopySubImage(1, 1);
+}
+
+// TODO(jmadill): Fix sampling from unused channels on D3D9
+TYPED_TEST(TextureTest, DISABLED_CopySubImageFloat_RG_R)
+{
+ testFloatCopySubImage(2, 1);
+}
+
+// TODO(jmadill): Fix sampling from unused channels on D3D9
+TYPED_TEST(TextureTest, DISABLED_CopySubImageFloat_RG_RG)
+{
+ testFloatCopySubImage(2, 2);
+}
+
+// TODO(jmadill): Fix sampling from unused channels on D3D9
+TYPED_TEST(TextureTest, DISABLED_CopySubImageFloat_RGB_R)
+{
+ testFloatCopySubImage(3, 1);
+}
+
+// TODO(jmadill): Fix sampling from unused channels on D3D9
+TYPED_TEST(TextureTest, DISABLED_CopySubImageFloat_RGB_RG)
+{
+ testFloatCopySubImage(3, 2);
+}
+
+TYPED_TEST(TextureTest, CopySubImageFloat_RGB_RGB)
+{
+ testFloatCopySubImage(3, 3);
+}
+
+// TODO(jmadill): Fix sampling from unused channels on D3D9
+TYPED_TEST(TextureTest, DISABLED_CopySubImageFloat_RGBA_R)
+{
+ testFloatCopySubImage(4, 1);
+}
+
+// TODO(jmadill): Fix sampling from unused channels on D3D9
+TYPED_TEST(TextureTest, DISABLED_CopySubImageFloat_RGBA_RG)
+{
+ testFloatCopySubImage(4, 2);
+}
+
+TYPED_TEST(TextureTest, CopySubImageFloat_RGBA_RGB)
+{
+ testFloatCopySubImage(4, 3);
+}
+
+TYPED_TEST(TextureTest, CopySubImageFloat_RGBA_RGBA)
+{
+ testFloatCopySubImage(4, 4);
+}