diff --git a/src/libANGLE/renderer/gl/TextureGL.cpp b/src/libANGLE/renderer/gl/TextureGL.cpp index 10e31d2992..8850d1a96f 100644 --- a/src/libANGLE/renderer/gl/TextureGL.cpp +++ b/src/libANGLE/renderer/gl/TextureGL.cpp @@ -2427,9 +2427,13 @@ angle::Result TextureGL::initializeContents(const gl::Context *context, const gl::ImageDesc &desc = mState.getImageDesc(imageIndex); const gl::InternalFormat &internalFormatInfo = *desc.format.info; + // The robust init value for depth is 1.0; the zero-filled paths below would clear it to 0.0. + // Prefer the FBO clear path for renderable depth formats so depth is initialized correctly. + bool hasDepthBits = internalFormatInfo.depthBits > 0; + // Clearing cube maps with EXT_clear_texture has inconsistent results. The drivers often clear // the entire level when only one face is specified. - if (functions->clearTexImage && !internalFormatInfo.compressed && + if (functions->clearTexImage && !internalFormatInfo.compressed && !hasDepthBits && getType() != gl::TextureType::CubeMap && !features.disableClearTexImageForRobustInit.enabled) { @@ -2463,7 +2467,7 @@ angle::Result TextureGL::initializeContents(const gl::Context *context, GLenum nativeInternalFormat = getLevelInfo(imageIndex.getTarget(), imageIndex.getLevelIndex()).nativeInternalFormat; - if ((features.allowClearForRobustResourceInit.enabled || + if ((features.allowClearForRobustResourceInit.enabled || hasDepthBits || !nativegl::SupportsTexImage(getType())) && nativegl::SupportsNativeRendering(functions, mState.getType(), nativeInternalFormat)) { diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp index b3cbd5eec0..95465b8a83 100644 --- a/src/libANGLE/renderer/gl/renderergl_utils.cpp +++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp @@ -2817,6 +2817,8 @@ void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFea ANGLE_FEATURE_CONDITION(features, clipCullDistanceBrokenWithPassthroughShaders, isQualcomm); ANGLE_FEATURE_CONDITION(features, noperspectiveInterpolationBrokenWithPassthroughShaders, isQualcomm); + + ANGLE_FEATURE_CONDITION(features, setNeedInitOnInvalidation, true); } void ReInitializeFeaturesAtGPUSwitch(const FunctionsGL *functions, angle::FeaturesGL *features) diff --git a/src/tests/gl_tests/RobustResourceInitTest.cpp b/src/tests/gl_tests/RobustResourceInitTest.cpp index 5c54ef1888..4958d9de01 100644 --- a/src/tests/gl_tests/RobustResourceInitTest.cpp +++ b/src/tests/gl_tests/RobustResourceInitTest.cpp @@ -953,6 +953,63 @@ TEST_P(RobustResourceInitTestES3, ClearThenInvalidateThenReadBack) } } +// Clearing, invalidating, then partially drawing should leave the area outside the draw with +// either the clear color (invalidate was a no-op) or transparent black (the init color). +TEST_P(RobustResourceInitTestES3, ClearThenInvalidateThenPartialDrawThenReadBack) +{ + ANGLE_SKIP_TEST_IF(!hasGLExtension()); + + ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); + + for (int i = 0; i < 10; ++i) + { + GLTexture tex; + GLRenderbuffer rb; + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + if (i % 2 == 0) + { + glBindTexture(GL_TEXTURE_2D, tex); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kWidth, kHeight); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); + } + else + { + glBindRenderbuffer(GL_RENDERBUFFER, rb); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kWidth, kHeight); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb); + } + ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); + + // Clear to red + glClearColor(1.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // Invalidate + std::array attachments = {GL_COLOR_ATTACHMENT0}; + glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments.data()); + + // Draw to a sub-region + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, kWidth / 2, kHeight / 2); + drawQuad(program, essl1_shaders::PositionAttrib(), 1.0f); + glDisable(GL_SCISSOR_TEST); + + // Read back: the drawn region must be green, the rest must be either red or transparent + // black + EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kHeight / 2, GLColor::green); + + GLColor invalidated(100, 100, 100, 100); + glReadPixels(kWidth - 1, kHeight - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &invalidated); + EXPECT_TRUE(invalidated == GLColor::red || invalidated == GLColor::transparentBlack) + << "At iteration " << i << ", color is " << invalidated; + EXPECT_GL_NO_ERROR(); + } +} + // Calling invalidate after draw should either read back the result of the draw call (invalidate // didn't happen) or the init depth/stencil values. TEST_P(RobustResourceInitTestES3, DrawThenInvalidateThenReadBackDepthStencil)