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);