Avoid blitting malformed rectangles
If glBlitFramebuffer tries to blit massive rectangles, it can result in
NaNs. This change ignores those rectangles instead of trying to blit
them.
Added a unittest for blitting a framebuffer.
Also fixed a typo in a debug message.
Bug chromium:979986
Change-Id: Ifd8e379f27b6882044bb93c6a68647b8474e7afc
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/34428
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Presubmit-Ready: Sean Risser <srisser@google.com>
Tested-by: Sean Risser <srisser@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/libGLESv2/Device.cpp b/src/OpenGL/libGLESv2/Device.cpp
index 0c5c63e..da76467 100644
--- a/src/OpenGL/libGLESv2/Device.cpp
+++ b/src/OpenGL/libGLESv2/Device.cpp
@@ -452,6 +452,14 @@
int dWidth = dest->getWidth();
int dHeight = dest->getHeight();
+ if(sourceRect && destRect &&
+ (sourceRect->width() == 0.0f || std::isnan(sourceRect->width()) ||
+ sourceRect->height() == 0.0f || std::isnan(sourceRect->height()) ||
+ destRect->width() == 0.0f || destRect->height() == 0.0f))
+ {
+ return true; // No work to do.
+ }
+
bool flipX = false;
bool flipY = false;
if(sourceRect && destRect)
@@ -528,7 +536,8 @@
ClipDstRect(sRect, dRect, dstClipRect, flipX, flipY);
if((sRect.width() == 0) || (sRect.height() == 0) ||
- (dRect.width() == 0) || (dRect.height() == 0))
+ (dRect.width() == 0) || (dRect.height() == 0) ||
+ (std::isnan(sRect.width()) || std::isnan(sRect.height())))
{
return true; // no work to do
}
@@ -876,6 +885,11 @@
return false;
}
+ if (std::isnan(rect->x0) || std::isnan(rect->x1) || std::isnan(rect->y0) || std::isnan(rect->y1))
+ {
+ return false;
+ }
+
return true;
}
diff --git a/src/OpenGL/libGLESv2/libGLESv3.cpp b/src/OpenGL/libGLESv2/libGLESv3.cpp
index e513a50..e12ea4d 100644
--- a/src/OpenGL/libGLESv2/libGLESv3.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv3.cpp
@@ -1175,7 +1175,7 @@
TRACE("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
"GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "
"GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
- srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
switch(filter)
{
diff --git a/tests/GLESUnitTests/unittests.cpp b/tests/GLESUnitTests/unittests.cpp
index 7951e27..56a377e 100644
--- a/tests/GLESUnitTests/unittests.cpp
+++ b/tests/GLESUnitTests/unittests.cpp
@@ -1717,6 +1717,84 @@
Uninitialize();
}
+TEST_F(SwiftShaderTest, BlitTest)
+{
+ Initialize(3, false);
+
+ GLuint fbos[] = {0, 0};
+ glGenFramebuffers(2, fbos);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
+
+ GLuint textures[] = {0, 0};
+ glGenTextures(2, textures);
+
+ glBindTexture(GL_TEXTURE_2D, textures[0]);
+ unsigned char red[4][4] = {
+ {255, 0, 0, 255},
+ {255, 0, 0, 255},
+ {255, 0, 0, 255},
+ {255, 0, 0, 255}
+ };
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, red);
+ EXPECT_NO_GL_ERROR();
+
+ glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
+ EXPECT_NO_GL_ERROR();
+
+ glBindTexture(GL_TEXTURE_2D, textures[1]);
+ unsigned char black[4][4] = {
+ {0, 0, 0, 255},
+ {0, 0, 0, 255},
+ {0, 0, 0, 255},
+ {0, 0, 0, 255}
+ };
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
+ EXPECT_NO_GL_ERROR();
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], 0);
+
+ // Test that glBlitFramebuffer works as expected for the normal case.
+ glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ EXPECT_NO_GL_ERROR();
+ EXPECT_EQ(red[0][1], black[0][1]);
+
+ // Check that glBlitFramebuffer doesn't crash with ugly input.
+ glBlitFramebuffer(-2, -2, 127, 2147483470, 10, 10, 200, 200, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ EXPECT_NO_GL_ERROR();
+
+ const int big = (int) 2e9;
+ const int small = 200;
+ const int neg_small = -small;
+ const int neg_big = -big;
+ int data[][8] = {
+ // sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1
+ {0, 0, 0, 0, 0, 0, 0, 0},
+ {-1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 1, 1, 1, 1, 1, 1, 1},
+ {-1, -1, 1, 1, -1, -1, 1, 1},
+ {0, 0, 127, (int) 2e9, 10, 10, 200, 200},
+ {big, small, small, big, big, big, small, small},
+ {neg_small, small, neg_small, neg_small, neg_small, big, small},
+ {big, big-1, big-2, big-3, big-4, big-5, big-6, big-7},
+ {big, neg_big, neg_big, big, small, big, 0, neg_small},
+ {323479648, 21931, 1769809195, 32733, 0, 0, -161640504, 32766}
+ };
+
+ for (int i = 0; i < (int) (sizeof(data)/sizeof(data[0])); i++)
+ {
+ glBlitFramebuffer(
+ data[i][0], data[i][1], data[i][2], data[i][3],
+ data[i][4], data[i][5], data[i][6], data[i][7],
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ EXPECT_NO_GL_ERROR();
+ }
+
+ glDeleteFramebuffers(2, fbos);
+ glDeleteTextures(2, textures);
+ Uninitialize();
+}
+
TEST_F(SwiftShaderTest, InvalidEnum_TexImage2D)
{
Initialize(3, false);