Commit e7d27705 by Jiajie Hu Committed by Commit Bot

Fix corruption when changing the base level of a framebuffer texture attachment

In the D3D renderer, changing the base level may trigger re-allocation of the texture storage, for example if the new base level has a different aspect ratio. During the process, image contents in the texture storage should be backed up properly. The D3D11 backend does this if an image has been associated with the texture storage, but it may happen such an association has never been established, and corruption will be observed then. The proposed patch mitigates the problem by introducing a new method named findRenderTarget(), with which one can tell if a mip level has been used as the render target. This works based on the fact that render targets are cached in the texture storage object. Hence all mip levels of interest can be found, without relying on the association between images and texture storage. Bug: angleproject:2291 Change-Id: Ic73af7b603be25c65760928f276bec16df003baf Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2158830 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 101da757
...@@ -653,6 +653,27 @@ angle::Result TextureD3D::setBaseLevel(const gl::Context *context, GLuint baseLe ...@@ -653,6 +653,27 @@ angle::Result TextureD3D::setBaseLevel(const gl::Context *context, GLuint baseLe
newStorageDepth != oldStorageDepth || newStorageFormat != oldStorageFormat)) newStorageDepth != oldStorageDepth || newStorageFormat != oldStorageFormat))
{ {
markAllImagesDirty(); markAllImagesDirty();
// Iterate over all images, and backup the content if it's been used as a render target. The
// D3D11 backend can automatically restore images on storage destroy, but it only works for
// images that have been associated with the texture storage before, which is insufficient
// here.
if (mTexStorage->isRenderTarget())
{
gl::ImageIndexIterator iterator = imageIterator();
while (iterator.hasNext())
{
const gl::ImageIndex index = iterator.next();
const GLsizei samples = getRenderToTextureSamples();
RenderTargetD3D *renderTarget = nullptr;
ANGLE_TRY(mTexStorage->findRenderTarget(context, index, samples, &renderTarget));
if (renderTarget)
{
ANGLE_TRY(getImage(index)->copyFromTexStorage(context, index, mTexStorage));
}
}
}
ANGLE_TRY(releaseTexStorage(context)); ANGLE_TRY(releaseTexStorage(context));
} }
......
...@@ -51,6 +51,10 @@ class TextureStorage : public angle::Subject ...@@ -51,6 +51,10 @@ class TextureStorage : public angle::Subject
virtual bool supportsNativeMipmapFunction() const = 0; virtual bool supportsNativeMipmapFunction() const = 0;
virtual int getLevelCount() const = 0; virtual int getLevelCount() const = 0;
virtual angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const = 0;
virtual angle::Result getRenderTarget(const gl::Context *context, virtual angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
......
...@@ -199,6 +199,10 @@ class TextureStorage11 : public TextureStorage ...@@ -199,6 +199,10 @@ class TextureStorage11 : public TextureStorage
// Helper for resolving MS shadowed texture // Helper for resolving MS shadowed texture
angle::Result resolveTextureHelper(const gl::Context *context, const TextureHelper11 &texture); angle::Result resolveTextureHelper(const gl::Context *context, const TextureHelper11 &texture);
angle::Result releaseMultisampledTexStorageForLevel(size_t level) override; angle::Result releaseMultisampledTexStorageForLevel(size_t level) override;
angle::Result findMultisampledRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const;
angle::Result getMultisampledRenderTarget(const gl::Context *context, angle::Result getMultisampledRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -289,6 +293,10 @@ class TextureStorage11_2D : public TextureStorage11 ...@@ -289,6 +293,10 @@ class TextureStorage11_2D : public TextureStorage11
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
angle::Result getMippedResource(const gl::Context *context, angle::Result getMippedResource(const gl::Context *context,
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -378,6 +386,10 @@ class TextureStorage11_External : public TextureStorage11 ...@@ -378,6 +386,10 @@ class TextureStorage11_External : public TextureStorage11
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
angle::Result getMippedResource(const gl::Context *context, angle::Result getMippedResource(const gl::Context *context,
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -472,6 +484,10 @@ class TextureStorage11_EGLImage final : public TextureStorage11ImmutableBase ...@@ -472,6 +484,10 @@ class TextureStorage11_EGLImage final : public TextureStorage11ImmutableBase
const d3d11::SharedSRV **outSRV) override; const d3d11::SharedSRV **outSRV) override;
angle::Result getMippedResource(const gl::Context *context, angle::Result getMippedResource(const gl::Context *context,
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -532,6 +548,10 @@ class TextureStorage11_Cube : public TextureStorage11 ...@@ -532,6 +548,10 @@ class TextureStorage11_Cube : public TextureStorage11
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
angle::Result getMippedResource(const gl::Context *context, angle::Result getMippedResource(const gl::Context *context,
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -619,6 +639,10 @@ class TextureStorage11_3D : public TextureStorage11 ...@@ -619,6 +639,10 @@ class TextureStorage11_3D : public TextureStorage11
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
// Handles both layer and non-layer RTs // Handles both layer and non-layer RTs
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -684,6 +708,10 @@ class TextureStorage11_2DArray : public TextureStorage11 ...@@ -684,6 +708,10 @@ class TextureStorage11_2DArray : public TextureStorage11
angle::Result getResource(const gl::Context *context, angle::Result getResource(const gl::Context *context,
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -778,6 +806,10 @@ class TextureStorage11_2DMultisample final : public TextureStorage11ImmutableBas ...@@ -778,6 +806,10 @@ class TextureStorage11_2DMultisample final : public TextureStorage11ImmutableBas
angle::Result getResource(const gl::Context *context, angle::Result getResource(const gl::Context *context,
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -829,6 +861,10 @@ class TextureStorage11_2DMultisampleArray final : public TextureStorage11Immutab ...@@ -829,6 +861,10 @@ class TextureStorage11_2DMultisampleArray final : public TextureStorage11Immutab
angle::Result getResource(const gl::Context *context, angle::Result getResource(const gl::Context *context,
const TextureHelper11 **outResource) override; const TextureHelper11 **outResource) override;
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
......
...@@ -180,6 +180,18 @@ angle::Result TextureStorage9_2D::getSurfaceLevel(const gl::Context *context, ...@@ -180,6 +180,18 @@ angle::Result TextureStorage9_2D::getSurfaceLevel(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result TextureStorage9_2D::findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const
{
ASSERT(index.getLevelIndex() < getLevelCount());
ASSERT(outRT);
*outRT = mRenderTargets[index.getLevelIndex()];
return angle::Result::Continue;
}
angle::Result TextureStorage9_2D::getRenderTarget(const gl::Context *context, angle::Result TextureStorage9_2D::getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -304,6 +316,17 @@ angle::Result TextureStorage9_EGLImage::getSurfaceLevel(const gl::Context *conte ...@@ -304,6 +316,17 @@ angle::Result TextureStorage9_EGLImage::getSurfaceLevel(const gl::Context *conte
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result TextureStorage9_EGLImage::findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const
{
// Since the render target of a EGL image will be updated when orphaning, trying to find a cache
// of it can be rarely useful.
ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
return angle::Result::Stop;
}
angle::Result TextureStorage9_EGLImage::getRenderTarget(const gl::Context *context, angle::Result TextureStorage9_EGLImage::getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -431,6 +454,23 @@ angle::Result TextureStorage9_Cube::getSurfaceLevel(const gl::Context *context, ...@@ -431,6 +454,23 @@ angle::Result TextureStorage9_Cube::getSurfaceLevel(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result TextureStorage9_Cube::findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const
{
ASSERT(outRT);
ASSERT(index.getLevelIndex() == 0);
ASSERT(samples == 0);
ASSERT(index.getType() == gl::TextureType::CubeMap &&
gl::IsCubeMapFaceTarget(index.getTarget()));
const size_t renderTargetIndex = index.cubeMapFaceIndex();
*outRT = mRenderTarget[renderTargetIndex];
return angle::Result::Continue;
}
angle::Result TextureStorage9_Cube::getRenderTarget(const gl::Context *context, angle::Result TextureStorage9_Cube::getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
......
...@@ -88,6 +88,10 @@ class TextureStorage9_2D : public TextureStorage9 ...@@ -88,6 +88,10 @@ class TextureStorage9_2D : public TextureStorage9
int level, int level,
bool dirty, bool dirty,
IDirect3DSurface9 **outSurface) override; IDirect3DSurface9 **outSurface) override;
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -115,6 +119,10 @@ class TextureStorage9_EGLImage final : public TextureStorage9 ...@@ -115,6 +119,10 @@ class TextureStorage9_EGLImage final : public TextureStorage9
int level, int level,
bool dirty, bool dirty,
IDirect3DSurface9 **outSurface) override; IDirect3DSurface9 **outSurface) override;
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
...@@ -146,6 +154,10 @@ class TextureStorage9_Cube : public TextureStorage9 ...@@ -146,6 +154,10 @@ class TextureStorage9_Cube : public TextureStorage9
int level, int level,
bool dirty, bool dirty,
IDirect3DSurface9 **outSurface) override; IDirect3DSurface9 **outSurface) override;
angle::Result findRenderTarget(const gl::Context *context,
const gl::ImageIndex &index,
GLsizei samples,
RenderTargetD3D **outRT) const override;
angle::Result getRenderTarget(const gl::Context *context, angle::Result getRenderTarget(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
GLsizei samples, GLsizei samples,
......
...@@ -2208,9 +2208,6 @@ TEST_P(Texture2DTestES3, TextureImplPropogatesDirtyBits) ...@@ -2208,9 +2208,6 @@ TEST_P(Texture2DTestES3, TextureImplPropogatesDirtyBits)
// https://www.khronos.org/registry/webgl/sdk/tests/conformance2/rendering/framebuffer-texture-changing-base-level.html // https://www.khronos.org/registry/webgl/sdk/tests/conformance2/rendering/framebuffer-texture-changing-base-level.html
TEST_P(Texture2DTestES3, FramebufferTextureChangingBaselevel) TEST_P(Texture2DTestES3, FramebufferTextureChangingBaselevel)
{ {
// TODO(geofflang): Investigate on D3D11. http://anglebug.com/2291
ANGLE_SKIP_TEST_IF(IsD3D11());
// TODO(cnorthrop): Failing on Vulkan/Windows/AMD. http://anglebug.com/3996 // TODO(cnorthrop): Failing on Vulkan/Windows/AMD. http://anglebug.com/3996
ANGLE_SKIP_TEST_IF(IsVulkan() && IsWindows() && IsAMD()); ANGLE_SKIP_TEST_IF(IsVulkan() && IsWindows() && IsAMD());
......
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