Commit 0716ce0a by Jonah Ryan-Davis Committed by Commit Bot

Re-add case to blitframebuffer workaround where src is outside of bounds.

On Mac, blitFramebuffer calls fail if the source region is not enclosed by the framebuffer. In this case, we must naively clip the source region and adjust the dest region accordingly. This is slightly different behavior and may cause issues with scaling so we use a separate workaround. Also, Windows NVIDIA has a driver bug that affects Vulkan device creation after blitting large textures, so it should be included in the original workaround. This CL cleans up the workaround to use more helpers from ANGLE and to generally improve readability. Bug: chromium:830046 Change-Id: I50bd97449725b738036e6bd3af82362020d7eda8 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1713090 Commit-Queue: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent f002a637
...@@ -331,6 +331,13 @@ struct FeaturesGL : FeatureSetBase ...@@ -331,6 +331,13 @@ struct FeaturesGL : FeatureSetBase
"adjust_src_dst_region_for_blitframebuffer", FeatureCategory::OpenGLWorkarounds, "adjust_src_dst_region_for_blitframebuffer", FeatureCategory::OpenGLWorkarounds,
"Many platforms have issues with blitFramebuffer when the parameters are large.", &members, "Many platforms have issues with blitFramebuffer when the parameters are large.", &members,
"http://crbug.com/830046"}; "http://crbug.com/830046"};
// BlitFramebuffer has issues on Mac when the source bounds aren't enclosed by the framebuffer.
// This workaround clips the source region and adjust the dest region proportionally.
Feature clipSrcRegionBlitFramebuffer = {
"clip_src_region_for_blitframebuffer", FeatureCategory::OpenGLWorkarounds,
"Mac has issues with blitFramebuffer when the parameters don't match the framebuffer size.",
&members, "http://crbug.com/830046"};
}; };
inline FeaturesGL::FeaturesGL() = default; inline FeaturesGL::FeaturesGL() = default;
......
...@@ -121,6 +121,12 @@ class FramebufferGL : public FramebufferImpl ...@@ -121,6 +121,12 @@ class FramebufferGL : public FramebufferImpl
gl::Rectangle *newSourceArea, gl::Rectangle *newSourceArea,
gl::Rectangle *newDestArea); gl::Rectangle *newDestArea);
angle::Result clipSrcRegion(const gl::Context *context,
const gl::Rectangle &sourceArea,
const gl::Rectangle &destArea,
gl::Rectangle *newSourceArea,
gl::Rectangle *newDestArea);
GLuint mFramebufferID; GLuint mFramebufferID;
bool mIsDefault; bool mIsDefault;
......
...@@ -1533,7 +1533,9 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature ...@@ -1533,7 +1533,9 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature
IsApple() && IsIntel(vendor) && GetMacOSVersion() < OSVersion(10, 12, 6); IsApple() && IsIntel(vendor) && GetMacOSVersion() < OSVersion(10, 12, 6);
features->adjustSrcDstRegionBlitFramebuffer.enabled = features->adjustSrcDstRegionBlitFramebuffer.enabled =
IsApple() || IsLinux() || (IsAndroid() && IsNvidia(vendor)); IsLinux() || (IsAndroid() && IsNvidia(vendor)) || (IsWindows() && IsNvidia(vendor));
features->clipSrcRegionBlitFramebuffer.enabled = IsApple();
} }
void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features) void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features)
......
...@@ -1750,6 +1750,105 @@ TEST_P(BlitFramebufferTest, BlitSRGBToRGBOversizedSourceArea) ...@@ -1750,6 +1750,105 @@ TEST_P(BlitFramebufferTest, BlitSRGBToRGBOversizedSourceArea)
EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::blue);
} }
// Blit an SRGB framebuffer with an oversized dest area (even though the result is clipped, it
// should be scaled as if the whole dest area was used).
TEST_P(BlitFramebufferTest, BlitSRGBToRGBOversizedDestArea)
{
constexpr const GLsizei kWidth = 256;
constexpr const GLsizei kHeight = 256;
GLRenderbuffer sourceRBO, targetRBO;
GLFramebuffer sourceFBO, targetFBO;
initColorFBOWithCheckerPattern(&sourceFBO, &sourceRBO, GL_SRGB8_ALPHA8, kWidth, kHeight);
initColorFBO(&targetFBO, &targetRBO, GL_RGBA8, kWidth, kHeight);
EXPECT_GL_NO_ERROR();
glViewport(0, 0, kWidth, kHeight);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Dest is oversized but centered the same as source
glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO);
glBlitFramebuffer(0, 0, kWidth, kHeight, -kWidth / 2, -kHeight / 2, 3 * kWidth / 2,
3 * kHeight / 2, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, targetFBO);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth / 4, kHeight / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 - 1, kHeight / 2 - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(1, kWidth - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 - 1, kHeight / 2 + 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, kHeight / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, kHeight / 2 - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, kHeight / 2 + 1, GLColor::red);
// Dest is oversized in the negative direction
glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO);
glBlitFramebuffer(0, 0, kWidth, kHeight, -kWidth / 2, -kHeight / 2, kWidth, kHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, targetFBO);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 - 1, kHeight / 2 - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(1, kWidth - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 - 1, kHeight / 2 + 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, kHeight / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, kHeight / 2 - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, kHeight / 2 + 1, GLColor::red);
// Dest is oversized in the positive direction
glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFBO);
glBlitFramebuffer(0, 0, kWidth, kHeight, 0, 0, 3 * kWidth / 2, 3 * kHeight / 2,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, targetFBO);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth / 4, kHeight / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 - 1, kHeight / 2 - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(1, kWidth - 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kWidth / 4, 3 * kHeight / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 - 1, kHeight / 2 + 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, kHeight / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, kHeight / 2 - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(kWidth / 2 + 1, kHeight / 2 + 1, GLColor::red);
}
// Test blitFramebuffer size overflow checks. WebGL 2.0 spec section 5.41. We do validation for // Test blitFramebuffer size overflow checks. WebGL 2.0 spec section 5.41. We do validation for
// overflows also in non-WebGL mode to avoid triggering driver bugs. // overflows also in non-WebGL mode to avoid triggering driver bugs.
TEST_P(BlitFramebufferTest, BlitFramebufferSizeOverflow) TEST_P(BlitFramebufferTest, BlitFramebufferSizeOverflow)
...@@ -1805,6 +1904,91 @@ TEST_P(BlitFramebufferTest, BlitFramebufferSizeOverflow) ...@@ -1805,6 +1904,91 @@ TEST_P(BlitFramebufferTest, BlitFramebufferSizeOverflow)
EXPECT_GL_ERROR(GL_INVALID_VALUE); EXPECT_GL_ERROR(GL_INVALID_VALUE);
} }
// Test blitFramebuffer size overflow checks. WebGL 2.0 spec section 5.41. Similar to above test,
// but this test more accurately duplicates the behavior of the WebGL test
// conformance2/rendering/blitframebuffer-size-overflow.html, which covers a few more edge cases.
TEST_P(BlitFramebufferTest, BlitFramebufferSizeOverflow2)
{
GLTexture textures[2];
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
GLFramebuffer framebuffers[2];
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]);
ASSERT_GL_NO_ERROR();
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1],
0);
ASSERT_GL_NO_ERROR();
GLint width = 8;
GLint height = 8;
GLTexture tex0;
glBindTexture(GL_TEXTURE_2D, tex0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
GLFramebuffer fb0;
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb0);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0, 0);
GLTexture tex1;
glBindTexture(GL_TEXTURE_2D, tex1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
GLFramebuffer fb1;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb1);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex1, 0);
GLint max = std::numeric_limits<GLint>::max();
// Using max 32-bit integer as blitFramebuffer parameter should succeed.
glBlitFramebuffer(0, 0, max, max, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBlitFramebuffer(0, 0, width, height, 0, 0, max, max, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBlitFramebuffer(0, 0, max, max, 0, 0, max, max, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_NO_ERROR();
// Using blitFramebuffer parameters where calculated width/height matches max 32-bit integer
// should succeed
glBlitFramebuffer(-1, -1, max - 1, max - 1, 0, 0, width, height, GL_COLOR_BUFFER_BIT,
GL_NEAREST);
glBlitFramebuffer(0, 0, width, height, -1, -1, max - 1, max - 1, GL_COLOR_BUFFER_BIT,
GL_NEAREST);
glBlitFramebuffer(-1, -1, max - 1, max - 1, -1, -1, max - 1, max - 1, GL_COLOR_BUFFER_BIT,
GL_NEAREST);
EXPECT_GL_NO_ERROR();
// Using source width/height greater than max 32-bit integer should fail.
glBlitFramebuffer(-1, -1, max, max, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
// Using source width/height greater than max 32-bit integer should fail.
glBlitFramebuffer(max, max, -1, -1, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
// Using destination width/height greater than max 32-bit integer should fail.
glBlitFramebuffer(0, 0, width, height, -1, -1, max, max, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
// Using destination width/height greater than max 32-bit integer should fail.
glBlitFramebuffer(0, 0, width, height, max, max, -1, -1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
// Using both source and destination width/height greater than max 32-bit integer should fail.
glBlitFramebuffer(-1, -1, max, max, -1, -1, max, max, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
// Using minimum and maximum integers for all boundaries should fail.
glBlitFramebuffer(-max - 1, -max - 1, max, max, -max - 1, -max - 1, max, max,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
}
// 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(BlitFramebufferANGLETest, ANGLE_INSTANTIATE_TEST(BlitFramebufferANGLETest,
......
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