Commit 9c262ad0 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Cleanup texture image respecify

Prior to this change, respecifying a texture image due to usage, base or max level changes incurred a copy of every level and layer to a temporary buffer which was then staged as an update to the new image. This code was somewhat messy (for example with respect to depth/stencil images), error prone (e.g. previously had bugs with compressed textures) and disallowed further optimizations such as in anglebug.com/4835. This change does the following: - ImageHelper::SubresourceUpdate now takes ref-counted images, instead of image pointers. This allows the same image to be staged for multiple updates. - Respecifying an image is still done through a copy, but to an identical (temp) image instead of buffer, and each level of the image is staged as an update. * Further optimization is to stage the old image itself directly as updates to the new image Bug: angleproject:4835 Change-Id: I4a3ef2d616c9ab459ff65f918b0fb6d9a2161b73 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2897537 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCharlie Lao <cclao@google.com>
parent 9e8fea5b
...@@ -1512,6 +1512,19 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1512,6 +1512,19 @@ class ImageHelper final : public Resource, public angle::Subject
const Format &format, const Format &format,
VkImageUsageFlags usage, VkImageUsageFlags usage,
uint32_t layerCount); uint32_t layerCount);
// Create an image for staging purposes. Used by:
//
// - TextureVk::copyAndStageImageData
//
angle::Result initStaging(Context *context,
const MemoryProperties &memoryProperties,
VkImageType imageType,
const VkExtent3D &extents,
const Format &format,
GLint samples,
VkImageUsageFlags usage,
uint32_t mipLevels,
uint32_t layerCount);
// Create a multisampled image for use as the implicit image in multisampled render to texture // Create a multisampled image for use as the implicit image in multisampled render to texture
// rendering. If LAZILY_ALLOCATED memory is available, it will prefer that. // rendering. If LAZILY_ALLOCATED memory is available, it will prefer that.
angle::Result initImplicitMultisampledRenderToTexture(Context *context, angle::Result initImplicitMultisampledRenderToTexture(Context *context,
...@@ -1665,18 +1678,6 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1665,18 +1678,6 @@ class ImageHelper final : public Resource, public angle::Subject
uint8_t **destData, uint8_t **destData,
DynamicBuffer *stagingBufferOverride); DynamicBuffer *stagingBufferOverride);
angle::Result stageSubresourceUpdateFromBuffer(ContextVk *contextVk,
size_t allocationSize,
gl::LevelIndex mipLevelGL,
uint32_t baseArrayLayer,
uint32_t layerCount,
uint32_t bufferRowLength,
uint32_t bufferImageHeight,
const VkExtent3D &extent,
const VkOffset3D &offset,
BufferHelper *stagingBuffer,
StagingBufferOffsetArray stagingOffsets);
angle::Result stageSubresourceUpdateFromFramebuffer(const gl::Context *context, angle::Result stageSubresourceUpdateFromFramebuffer(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
const gl::Rectangle &sourceArea, const gl::Rectangle &sourceArea,
...@@ -1686,12 +1687,20 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1686,12 +1687,20 @@ class ImageHelper final : public Resource, public angle::Subject
FramebufferVk *framebufferVk, FramebufferVk *framebufferVk,
DynamicBuffer *stagingBufferOverride); DynamicBuffer *stagingBufferOverride);
void stageSubresourceUpdateFromImage(ImageHelper *image, void stageSubresourceUpdateFromImage(RefCounted<ImageHelper> *image,
const gl::ImageIndex &index, const gl::ImageIndex &index,
LevelIndex srcMipLevel,
const gl::Offset &destOffset, const gl::Offset &destOffset,
const gl::Extents &glExtents, const gl::Extents &glExtents,
const VkImageType imageType); const VkImageType imageType);
// Takes an image and stages a subresource update for each level of it, including its full
// extent and all its layers, at the specified GL level.
void stageSubresourceUpdatesFromAllImageLevels(RendererVk *renderer,
RefCounted<ImageHelper> *image,
gl::LevelIndex baseLevel,
gl::TexLevelMask skipLevelsMask);
// Stage a clear to an arbitrary value. // Stage a clear to an arbitrary value.
void stageClear(const gl::ImageIndex &index, void stageClear(const gl::ImageIndex &index,
VkImageAspectFlags aspectFlags, VkImageAspectFlags aspectFlags,
...@@ -1908,7 +1917,6 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1908,7 +1917,6 @@ class ImageHelper final : public Resource, public angle::Subject
}; };
struct ImageUpdate struct ImageUpdate
{ {
ImageHelper *image;
VkImageCopy copyRegion; VkImageCopy copyRegion;
}; };
...@@ -1917,7 +1925,7 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1917,7 +1925,7 @@ class ImageHelper final : public Resource, public angle::Subject
SubresourceUpdate(); SubresourceUpdate();
~SubresourceUpdate(); ~SubresourceUpdate();
SubresourceUpdate(BufferHelper *bufferHelperIn, const VkBufferImageCopy &copyRegion); SubresourceUpdate(BufferHelper *bufferHelperIn, const VkBufferImageCopy &copyRegion);
SubresourceUpdate(ImageHelper *image, const VkImageCopy &copyRegion); SubresourceUpdate(RefCounted<ImageHelper> *imageIn, const VkImageCopy &copyRegion);
SubresourceUpdate(VkImageAspectFlags aspectFlags, SubresourceUpdate(VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue, const VkClearValue &clearValue,
const gl::ImageIndex &imageIndex); const gl::ImageIndex &imageIndex);
...@@ -1939,7 +1947,8 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1939,7 +1947,8 @@ class ImageHelper final : public Resource, public angle::Subject
ClearUpdate clear; ClearUpdate clear;
BufferUpdate buffer; BufferUpdate buffer;
ImageUpdate image; ImageUpdate image;
}; } data;
RefCounted<ImageHelper> *image;
}; };
// Called from flushStagedUpdates, removes updates that are later superseded by another. This // Called from flushStagedUpdates, removes updates that are later superseded by another. This
...@@ -1989,6 +1998,11 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1989,6 +1998,11 @@ class ImageHelper final : public Resource, public angle::Subject
// Whether there are any updates in [start, end). // Whether there are any updates in [start, end).
bool hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const; bool hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const;
// Used only for assertions, these functions verify that SubresourceUpdate::image references
// have the correct ref count. This is to prevent accidental leaks.
bool validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> *image) const;
bool validateSubresourceUpdateImageRefsConsistent() const;
void resetCachedProperties(); void resetCachedProperties();
void setEntireContentDefined(); void setEntireContentDefined();
void setEntireContentUndefined(); void setEntireContentUndefined();
......
...@@ -531,6 +531,9 @@ class RefCounted : angle::NonCopyable ...@@ -531,6 +531,9 @@ class RefCounted : angle::NonCopyable
T &get() { return mObject; } T &get() { return mObject; }
const T &get() const { return mObject; } const T &get() const { return mObject; }
// A debug function to validate that the reference count is as expected used for assertions.
bool isRefCountAsExpected(uint32_t expectedRefCount) { return mRefCount == expectedRefCount; }
private: private:
uint32_t mRefCount; uint32_t mRefCount;
T mObject; T mObject;
......
...@@ -3955,7 +3955,7 @@ TEST_P(Texture2DBaseMaxTestES3, GenerateMipmapAfterRedefineAndRebase) ...@@ -3955,7 +3955,7 @@ TEST_P(Texture2DBaseMaxTestES3, GenerateMipmapAfterRedefineAndRebase)
{ {
setLodUniform(lod); setLodUniform(lod);
drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f); drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, kMipColors[lod]); EXPECT_PIXEL_COLOR_EQ(0, 0, kMipColors[lod]) << lod;
} }
// Redefine level 2 to an incompatible size, say the same size as level 0. // Redefine level 2 to an incompatible size, say the same size as level 0.
...@@ -3978,10 +3978,10 @@ TEST_P(Texture2DBaseMaxTestES3, GenerateMipmapAfterRedefineAndRebase) ...@@ -3978,10 +3978,10 @@ TEST_P(Texture2DBaseMaxTestES3, GenerateMipmapAfterRedefineAndRebase)
{ {
setLodUniform(lod); setLodUniform(lod);
drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f); drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, kMipColors[1]); EXPECT_PIXEL_COLOR_EQ(0, 0, kMipColors[1]) << lod;
EXPECT_PIXEL_COLOR_EQ(w, 0, kMipColors[1]); EXPECT_PIXEL_COLOR_EQ(w, 0, kMipColors[1]) << lod;
EXPECT_PIXEL_COLOR_EQ(0, h, kMipColors[1]); EXPECT_PIXEL_COLOR_EQ(0, h, kMipColors[1]) << lod;
EXPECT_PIXEL_COLOR_EQ(w, h, kMipColors[1]); EXPECT_PIXEL_COLOR_EQ(w, h, kMipColors[1]) << lod;
} }
// Redefine level 1 (current base level) to an incompatible size. // Redefine level 1 (current base level) to an incompatible size.
...@@ -3998,10 +3998,10 @@ TEST_P(Texture2DBaseMaxTestES3, GenerateMipmapAfterRedefineAndRebase) ...@@ -3998,10 +3998,10 @@ TEST_P(Texture2DBaseMaxTestES3, GenerateMipmapAfterRedefineAndRebase)
{ {
setLodUniform(lod); setLodUniform(lod);
drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f); drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, kMipColors[0]); EXPECT_PIXEL_COLOR_EQ(0, 0, kMipColors[0]) << lod;
EXPECT_PIXEL_COLOR_EQ(w, 0, kMipColors[0]); EXPECT_PIXEL_COLOR_EQ(w, 0, kMipColors[0]) << lod;
EXPECT_PIXEL_COLOR_EQ(0, h, kMipColors[0]); EXPECT_PIXEL_COLOR_EQ(0, h, kMipColors[0]) << lod;
EXPECT_PIXEL_COLOR_EQ(w, h, kMipColors[0]); EXPECT_PIXEL_COLOR_EQ(w, h, kMipColors[0]) << lod;
} }
} }
......
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