D3D: Fix not notifying RenderTarget release in TextureD3D
This could lead to use-after-free for the RenderTarget object.
Bug: chromium:1234829
Change-Id: I73d4547b8f09f2f2cf3f7f8394f7f573fe5a4ef5
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3063858
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index d28bbc8..207e683 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -2076,6 +2076,14 @@
return;
}
+ // This can be triggered by freeing TextureStorage in D3D back-end.
+ if (message == angle::SubjectMessage::StorageReleased)
+ {
+ mDirtyBits.set(index);
+ invalidateCompletenessCache();
+ return;
+ }
+
// This can be triggered by the GL back-end TextureGL class.
ASSERT(message == angle::SubjectMessage::DirtyBitsFlagged);
return;
diff --git a/src/libANGLE/Observer.h b/src/libANGLE/Observer.h
index 35b462a..69b34ab 100644
--- a/src/libANGLE/Observer.h
+++ b/src/libANGLE/Observer.h
@@ -61,6 +61,9 @@
ProgramRelinked,
// Indicates a separable program's sampler uniforms were updated.
SamplerUniformsUpdated,
+
+ // Indicates a Storage of back-end in gl::Texture has been released.
+ StorageReleased,
};
// The observing class inherits from this interface class.
diff --git a/src/libANGLE/Texture.cpp b/src/libANGLE/Texture.cpp
index 7843abb..5d60201 100644
--- a/src/libANGLE/Texture.cpp
+++ b/src/libANGLE/Texture.cpp
@@ -2269,6 +2269,15 @@
mState.setImageDesc(TextureTarget::Buffer, 0, desc);
}
break;
+ case angle::SubjectMessage::StorageReleased:
+ // When the TextureStorage is released, it needs to update the
+ // RenderTargetCache of the Framebuffer attaching this Texture.
+ // This is currently only for D3D back-end. See http://crbug.com/1234829
+ if (index == rx::kTextureImageImplObserverMessageIndex)
+ {
+ onStateChange(angle::SubjectMessage::StorageReleased);
+ }
+ break;
case angle::SubjectMessage::SubjectMapped:
case angle::SubjectMessage::SubjectUnmapped:
case angle::SubjectMessage::BindingChanged:
diff --git a/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/libANGLE/renderer/d3d/TextureD3D.cpp
index b23e511..b63bc0c 100644
--- a/src/libANGLE/renderer/d3d/TextureD3D.cpp
+++ b/src/libANGLE/renderer/d3d/TextureD3D.cpp
@@ -714,6 +714,8 @@
return angle::Result::Continue;
}
+ onStateChange(angle::SubjectMessage::StorageReleased);
+
auto err = mTexStorage->onDestroy(context);
SafeDelete(mTexStorage);
return err;
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index c90777c..e79bc70 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -8986,6 +8986,26 @@
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
}
+// Test if the RenderTargetCache is updated when the TextureStorage object is freed
+TEST_P(Texture2DTestES3, UpdateRenderTargetCacheOnDestroyTexStorage)
+{
+ ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
+ const GLenum attachments[] = {GL_COLOR_ATTACHMENT0};
+
+ GLTexture tex;
+ GLFramebuffer fb;
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexStorage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 100, 1);
+ glBindFramebuffer(GL_FRAMEBUFFER, fb);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
+ glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+ drawQuad(drawRed, essl3_shaders::PositionAttrib(), 1.0f);
+ EXPECT_GL_NO_ERROR();
+
+ EXPECT_PIXEL_RECT_EQ(0, 0, 100, 1, GLColor::red);
+}
+
// Draw a quad with an integer texture with a non-zero base level, and test that the color of the
// texture is output.
TEST_P(Texture2DIntegerTestES3, IntegerTextureNonZeroBaseLevel)