Commit d77e85a8 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Store image updates per level

This optimization allows iterating only over updates of a certain level or range of levels, instead of having to iterate over every update and filter out the ones matching the desired level(s). Bug: angleproject:4891 Change-Id: Ied04f4b28f05d37b9add61c7f4d54cc328c0be86 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2519095Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent d30f0114
...@@ -253,11 +253,12 @@ angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk, ...@@ -253,11 +253,12 @@ angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
// below will either flush all staged updates to the resolve image, or if the only staged update // below will either flush all staged updates to the resolve image, or if the only staged update
// is a clear, it will accumulate it in the |deferredClears| array. Later, when the render pass // is a clear, it will accumulate it in the |deferredClears| array. Later, when the render pass
// is started, the deferred clears are applied to the transient multisampled image. // is started, the deferred clears are applied to the transient multisampled image.
ASSERT(!isResolveImageOwnerOfData() || !mImage->isUpdateStaged(mLevelIndexGL, layerIndex)); ASSERT(!isResolveImageOwnerOfData() ||
!mImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex));
ASSERT(isResolveImageOwnerOfData() || mResolveImage == nullptr || ASSERT(isResolveImageOwnerOfData() || mResolveImage == nullptr ||
!mResolveImage->isUpdateStaged(mLevelIndexGL, layerIndex)); !mResolveImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex));
if (!image->isUpdateStaged(mLevelIndexGL, layerIndex)) if (!image->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex))
{ {
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -140,7 +140,8 @@ angle::Result SemaphoreVk::wait(gl::Context *context, ...@@ -140,7 +140,8 @@ angle::Result SemaphoreVk::wait(gl::Context *context,
// Image should not be accessed while unowned. Emulated formats may have staged updates // Image should not be accessed while unowned. Emulated formats may have staged updates
// to clear the image after initialization. // to clear the image after initialization.
ASSERT(!image.hasStagedUpdates() || image.getFormat().hasEmulatedImageChannels()); ASSERT(!image.hasStagedUpdatesInAllocatedLevels() ||
image.getFormat().hasEmulatedImageChannels());
// Queue ownership transfer and layout transition. // Queue ownership transfer and layout transition.
image.acquireFromExternal(contextVk, VK_QUEUE_FAMILY_EXTERNAL, rendererQueueFamilyIndex, image.acquireFromExternal(contextVk, VK_QUEUE_FAMILY_EXTERNAL, rendererQueueFamilyIndex,
......
...@@ -1550,7 +1550,7 @@ VkResult WindowSurfaceVk::acquireNextSwapchainImage(vk::Context *context) ...@@ -1550,7 +1550,7 @@ VkResult WindowSurfaceVk::acquireNextSwapchainImage(vk::Context *context)
} }
// Notify the owning framebuffer there may be staged updates. // Notify the owning framebuffer there may be staged updates.
if (image.image.hasStagedUpdates()) if (image.image.hasStagedUpdatesInAllocatedLevels())
{ {
onStateChange(angle::SubjectMessage::SubjectChanged); onStateChange(angle::SubjectMessage::SubjectChanged);
} }
......
...@@ -1841,7 +1841,7 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk, ...@@ -1841,7 +1841,7 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk,
{ {
// Recreate the image to reflect new base or max levels. // Recreate the image to reflect new base or max levels.
// First, flush any pending updates so we have good data in the existing vkImage // First, flush any pending updates so we have good data in the existing vkImage
if (mImage->valid() && mImage->hasStagedUpdates()) if (mImage->valid() && mImage->hasStagedUpdatesInAllocatedLevels())
{ {
ANGLE_TRY(flushImageStagedUpdates(contextVk)); ANGLE_TRY(flushImageStagedUpdates(contextVk));
} }
...@@ -1873,11 +1873,11 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk, ...@@ -1873,11 +1873,11 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk,
{ {
// Note: if this level is incompatibly redefined, there will necessarily be a staged // Note: if this level is incompatibly redefined, there will necessarily be a staged
// update, and the contents of the image are to be thrown away. // update, and the contents of the image are to be thrown away.
ASSERT(mImage->isUpdateStaged(levelGL, layer)); ASSERT(mImage->hasStagedUpdatesForSubresource(levelGL, layer));
continue; continue;
} }
ASSERT(!mImage->isUpdateStaged(levelGL, layer)); ASSERT(!mImage->hasStagedUpdatesForSubresource(levelGL, layer));
// Pull data from the current image and stage it as an update for the new image // Pull data from the current image and stage it as an update for the new image
...@@ -1987,7 +1987,7 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context, ...@@ -1987,7 +1987,7 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels) angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels)
{ {
if (mImage->valid() && !mImage->hasStagedUpdates()) if (mImage->valid() && !mImage->hasStagedUpdatesInAllocatedLevels())
{ {
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -3460,9 +3460,12 @@ void ImageHelper::releaseImageFromShareContexts(RendererVk *renderer, ContextVk ...@@ -3460,9 +3460,12 @@ void ImageHelper::releaseImageFromShareContexts(RendererVk *renderer, ContextVk
void ImageHelper::releaseStagingBuffer(RendererVk *renderer) void ImageHelper::releaseStagingBuffer(RendererVk *renderer)
{ {
// Remove updates that never made it to the texture. // Remove updates that never made it to the texture.
for (SubresourceUpdate &update : mSubresourceUpdates) for (std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
{ {
update.release(renderer); for (SubresourceUpdate &update : levelUpdates)
{
update.release(renderer);
}
} }
mStagingBuffer.release(renderer); mStagingBuffer.release(renderer);
mSubresourceUpdates.clear(); mSubresourceUpdates.clear();
...@@ -4401,21 +4404,28 @@ void ImageHelper::removeSingleSubresourceStagedUpdates(ContextVk *contextVk, ...@@ -4401,21 +4404,28 @@ void ImageHelper::removeSingleSubresourceStagedUpdates(ContextVk *contextVk,
gl::LevelIndex levelIndexGL, gl::LevelIndex levelIndexGL,
uint32_t layerIndex) uint32_t layerIndex)
{ {
mCurrentSingleClearValue.reset();
// Find any staged updates for this index and removes them from the pending list. // Find any staged updates for this index and removes them from the pending list.
for (size_t index = 0; index < mSubresourceUpdates.size();) std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelIndexGL);
if (levelUpdates == nullptr)
{ {
auto update = mSubresourceUpdates.begin() + index; return;
if (update->isUpdateToLayerLevel(layerIndex, levelIndexGL)) }
for (size_t index = 0; index < levelUpdates->size();)
{
auto update = levelUpdates->begin() + index;
if (update->isUpdateToLayer(layerIndex))
{ {
update->release(contextVk->getRenderer()); update->release(contextVk->getRenderer());
mSubresourceUpdates.erase(update); levelUpdates->erase(update);
} }
else else
{ {
index++; index++;
} }
} }
mCurrentSingleClearValue.reset();
} }
void ImageHelper::removeStagedUpdates(Context *context, void ImageHelper::removeStagedUpdates(Context *context,
...@@ -4423,23 +4433,21 @@ void ImageHelper::removeStagedUpdates(Context *context, ...@@ -4423,23 +4433,21 @@ void ImageHelper::removeStagedUpdates(Context *context,
gl::LevelIndex levelGLEnd) gl::LevelIndex levelGLEnd)
{ {
// Remove all updates to levels [start, end]. // Remove all updates to levels [start, end].
for (size_t index = 0; index < mSubresourceUpdates.size();) for (gl::LevelIndex level = levelGLStart; level <= levelGLEnd; ++level)
{ {
auto update = mSubresourceUpdates.begin() + index; std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
gl::LevelIndex updateMipLevelGL; if (levelUpdates == nullptr)
uint32_t updateBaseLayer, updateLayerCount;
update->getDestSubresource(mLayerCount, &updateMipLevelGL, &updateBaseLayer,
&updateLayerCount);
if (updateMipLevelGL >= levelGLStart && updateMipLevelGL <= levelGLEnd)
{ {
update->release(context->getRenderer()); ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
mSubresourceUpdates.erase(update); return;
} }
else
for (SubresourceUpdate &update : *levelUpdates)
{ {
index++; update.release(context->getRenderer());
} }
levelUpdates->clear();
} }
} }
...@@ -4576,7 +4584,8 @@ angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk, ...@@ -4576,7 +4584,8 @@ angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
copy.bufferRowLength = bufferRowLength; copy.bufferRowLength = bufferRowLength;
copy.bufferImageHeight = bufferImageHeight; copy.bufferImageHeight = bufferImageHeight;
copy.imageSubresource.mipLevel = index.getLevelIndex(); gl::LevelIndex updateLevelGL(index.getLevelIndex());
copy.imageSubresource.mipLevel = updateLevelGL.get();
copy.imageSubresource.layerCount = index.getLayerCount(); copy.imageSubresource.layerCount = index.getLayerCount();
gl_vk::GetOffset(offset, &copy.imageOffset); gl_vk::GetOffset(offset, &copy.imageOffset);
...@@ -4622,7 +4631,7 @@ angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk, ...@@ -4622,7 +4631,7 @@ angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
stencilCopy.imageOffset = copy.imageOffset; stencilCopy.imageOffset = copy.imageOffset;
stencilCopy.imageExtent = copy.imageExtent; stencilCopy.imageExtent = copy.imageExtent;
stencilCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; stencilCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
appendSubresourceUpdate(SubresourceUpdate(currentBuffer, stencilCopy)); appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(currentBuffer, stencilCopy));
aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT; aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
} }
...@@ -4645,7 +4654,7 @@ angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk, ...@@ -4645,7 +4654,7 @@ angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
if (aspectFlags) if (aspectFlags)
{ {
copy.imageSubresource.aspectMask = aspectFlags; copy.imageSubresource.aspectMask = aspectFlags;
appendSubresourceUpdate(SubresourceUpdate(currentBuffer, copy)); appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(currentBuffer, copy));
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -4791,12 +4800,14 @@ angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk ...@@ -4791,12 +4800,14 @@ angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk
ANGLE_TRY(stagingBuffer->allocateWithAlignment(contextVk, allocationSize, alignment, destData, ANGLE_TRY(stagingBuffer->allocateWithAlignment(contextVk, allocationSize, alignment, destData,
&bufferHandle, &stagingOffset, nullptr)); &bufferHandle, &stagingOffset, nullptr));
gl::LevelIndex updateLevelGL(imageIndex.getLevelIndex());
VkBufferImageCopy copy = {}; VkBufferImageCopy copy = {};
copy.bufferOffset = stagingOffset; copy.bufferOffset = stagingOffset;
copy.bufferRowLength = glExtents.width; copy.bufferRowLength = glExtents.width;
copy.bufferImageHeight = glExtents.height; copy.bufferImageHeight = glExtents.height;
copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy.imageSubresource.mipLevel = imageIndex.getLevelIndex(); copy.imageSubresource.mipLevel = updateLevelGL.get();
copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0; copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
copy.imageSubresource.layerCount = imageIndex.getLayerCount(); copy.imageSubresource.layerCount = imageIndex.getLayerCount();
...@@ -4806,7 +4817,8 @@ angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk ...@@ -4806,7 +4817,8 @@ angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk
gl_vk::GetOffset(offset, &copy.imageOffset); gl_vk::GetOffset(offset, &copy.imageOffset);
gl_vk::GetExtent(glExtents, &copy.imageExtent); gl_vk::GetExtent(glExtents, &copy.imageExtent);
appendSubresourceUpdate(SubresourceUpdate(stagingBuffer->getCurrentBuffer(), copy)); appendSubresourceUpdate(updateLevelGL,
SubresourceUpdate(stagingBuffer->getCurrentBuffer(), copy));
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -4848,10 +4860,10 @@ angle::Result ImageHelper::stageSubresourceUpdateFromBuffer(ContextVk *contextVk ...@@ -4848,10 +4860,10 @@ angle::Result ImageHelper::stageSubresourceUpdateFromBuffer(ContextVk *contextVk
copy[1] = copy[0]; copy[1] = copy[0];
copy[1].bufferOffset = stagingOffsets[1]; copy[1].bufferOffset = stagingOffsets[1];
copy[1].imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; copy[1].imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
appendSubresourceUpdate(SubresourceUpdate(bufferHelper, copy[1])); appendSubresourceUpdate(mipLevelGL, SubresourceUpdate(bufferHelper, copy[1]));
} }
appendSubresourceUpdate(SubresourceUpdate(bufferHelper, copy[0])); appendSubresourceUpdate(mipLevelGL, SubresourceUpdate(bufferHelper, copy[0]));
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -4943,20 +4955,22 @@ angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer( ...@@ -4943,20 +4955,22 @@ angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer(
stagingPointer)); stagingPointer));
} }
gl::LevelIndex updateLevelGL(index.getLevelIndex());
// 3- enqueue the destination image subresource update // 3- enqueue the destination image subresource update
VkBufferImageCopy copyToImage = {}; VkBufferImageCopy copyToImage = {};
copyToImage.bufferOffset = static_cast<VkDeviceSize>(stagingOffset); copyToImage.bufferOffset = static_cast<VkDeviceSize>(stagingOffset);
copyToImage.bufferRowLength = 0; // Tightly packed data can be specified as 0. copyToImage.bufferRowLength = 0; // Tightly packed data can be specified as 0.
copyToImage.bufferImageHeight = clippedRectangle.height; copyToImage.bufferImageHeight = clippedRectangle.height;
copyToImage.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyToImage.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyToImage.imageSubresource.mipLevel = index.getLevelIndex(); copyToImage.imageSubresource.mipLevel = updateLevelGL.get();
copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0; copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
copyToImage.imageSubresource.layerCount = index.getLayerCount(); copyToImage.imageSubresource.layerCount = index.getLayerCount();
gl_vk::GetOffset(dstOffset, &copyToImage.imageOffset); gl_vk::GetOffset(dstOffset, &copyToImage.imageOffset);
gl_vk::GetExtent(dstExtent, &copyToImage.imageExtent); gl_vk::GetExtent(dstExtent, &copyToImage.imageExtent);
// 3- enqueue the destination image subresource update // 3- enqueue the destination image subresource update
appendSubresourceUpdate(SubresourceUpdate(currentBuffer, copyToImage)); appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(currentBuffer, copyToImage));
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -4966,11 +4980,13 @@ void ImageHelper::stageSubresourceUpdateFromImage(ImageHelper *image, ...@@ -4966,11 +4980,13 @@ void ImageHelper::stageSubresourceUpdateFromImage(ImageHelper *image,
const gl::Extents &glExtents, const gl::Extents &glExtents,
const VkImageType imageType) const VkImageType imageType)
{ {
gl::LevelIndex updateLevelGL(index.getLevelIndex());
VkImageCopy copyToImage = {}; VkImageCopy copyToImage = {};
copyToImage.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyToImage.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyToImage.srcSubresource.layerCount = index.getLayerCount(); copyToImage.srcSubresource.layerCount = index.getLayerCount();
copyToImage.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyToImage.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyToImage.dstSubresource.mipLevel = index.getLevelIndex(); copyToImage.dstSubresource.mipLevel = updateLevelGL.get();
if (imageType == VK_IMAGE_TYPE_3D) if (imageType == VK_IMAGE_TYPE_3D)
{ {
...@@ -4993,14 +5009,15 @@ void ImageHelper::stageSubresourceUpdateFromImage(ImageHelper *image, ...@@ -4993,14 +5009,15 @@ void ImageHelper::stageSubresourceUpdateFromImage(ImageHelper *image,
gl_vk::GetOffset(destOffset, &copyToImage.dstOffset); gl_vk::GetOffset(destOffset, &copyToImage.dstOffset);
gl_vk::GetExtent(glExtents, &copyToImage.extent); gl_vk::GetExtent(glExtents, &copyToImage.extent);
appendSubresourceUpdate(SubresourceUpdate(image, copyToImage)); appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(image, copyToImage));
} }
void ImageHelper::stageClear(const gl::ImageIndex &index, void ImageHelper::stageClear(const gl::ImageIndex &index,
VkImageAspectFlags aspectFlags, VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue) const VkClearValue &clearValue)
{ {
appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index)); gl::LevelIndex updateLevelGL(index.getLevelIndex());
appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
} }
void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index) void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index)
...@@ -5009,7 +5026,9 @@ void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index) ...@@ -5009,7 +5026,9 @@ void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index)
ASSERT(mFormat); ASSERT(mFormat);
VkClearValue clearValue = GetRobustResourceClearValue(*mFormat); VkClearValue clearValue = GetRobustResourceClearValue(*mFormat);
appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
gl::LevelIndex updateLevelGL(index.getLevelIndex());
appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
} }
angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *contextVk, angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *contextVk,
...@@ -5021,10 +5040,13 @@ angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *context ...@@ -5021,10 +5040,13 @@ angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *context
const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat); const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat);
// Robust clears must only be staged if we do not have any prior data for this subresource. // Robust clears must only be staged if we do not have any prior data for this subresource.
ASSERT(!isUpdateStaged(gl::LevelIndex(index.getLevelIndex()), index.getLayerIndex())); ASSERT(!hasStagedUpdatesForSubresource(gl::LevelIndex(index.getLevelIndex()),
index.getLayerIndex()));
VkClearValue clearValue = GetRobustResourceClearValue(format); VkClearValue clearValue = GetRobustResourceClearValue(format);
gl::LevelIndex updateLevelGL(index.getLevelIndex());
if (imageFormat.isBlock) if (imageFormat.isBlock)
{ {
// This only supports doing an initial clear to 0, not clearing to a specific encoded RGBA // This only supports doing an initial clear to 0, not clearing to a specific encoded RGBA
...@@ -5049,16 +5071,17 @@ angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *context ...@@ -5049,16 +5071,17 @@ angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *context
copyRegion.imageExtent.width = glExtents.width; copyRegion.imageExtent.width = glExtents.width;
copyRegion.imageExtent.height = glExtents.height; copyRegion.imageExtent.height = glExtents.height;
copyRegion.imageExtent.depth = glExtents.depth; copyRegion.imageExtent.depth = glExtents.depth;
copyRegion.imageSubresource.mipLevel = index.getLevelIndex(); copyRegion.imageSubresource.mipLevel = updateLevelGL.get();
copyRegion.imageSubresource.aspectMask = aspectFlags; copyRegion.imageSubresource.aspectMask = aspectFlags;
copyRegion.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0; copyRegion.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
copyRegion.imageSubresource.layerCount = index.getLayerCount(); copyRegion.imageSubresource.layerCount = index.getLayerCount();
appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), copyRegion)); appendSubresourceUpdate(updateLevelGL,
SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), copyRegion));
} }
else else
{ {
appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index)); appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -5089,9 +5112,10 @@ void ImageHelper::stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled) ...@@ -5089,9 +5112,10 @@ void ImageHelper::stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled)
// values. // values.
for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level) for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
{ {
gl::LevelIndex updateLevelGL = toGLLevel(level);
gl::ImageIndex index = gl::ImageIndex index =
gl::ImageIndex::Make2DArrayRange(toGLLevel(level).get(), 0, mLayerCount); gl::ImageIndex::Make2DArrayRange(updateLevelGL.get(), 0, mLayerCount);
prependSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index)); prependSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
} }
} }
...@@ -5139,16 +5163,22 @@ angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contex ...@@ -5139,16 +5163,22 @@ angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contex
ClearValuesArray *deferredClears, ClearValuesArray *deferredClears,
uint32_t deferredClearIndex) uint32_t deferredClearIndex)
{ {
std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
if (levelUpdates == nullptr || levelUpdates->empty())
{
return angle::Result::Continue;
}
// Handle deferred clears. Search the updates list for a matching clear index. // Handle deferred clears. Search the updates list for a matching clear index.
if (deferredClears) if (deferredClears)
{ {
Optional<size_t> foundClear; Optional<size_t> foundClear;
for (size_t updateIndex = 0; updateIndex < mSubresourceUpdates.size(); ++updateIndex) for (size_t updateIndex = 0; updateIndex < levelUpdates->size(); ++updateIndex)
{ {
SubresourceUpdate &update = mSubresourceUpdates[updateIndex]; SubresourceUpdate &update = (*levelUpdates)[updateIndex];
if (update.isUpdateToLayerLevel(layer, levelGL)) if (update.isUpdateToLayer(layer))
{ {
// On any data update, exit out. We'll need to do a full upload. // On any data update, exit out. We'll need to do a full upload.
if (update.updateSource != UpdateSource::Clear || if (update.updateSource != UpdateSource::Clear ||
...@@ -5168,7 +5198,7 @@ angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contex ...@@ -5168,7 +5198,7 @@ angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contex
if (foundClear.valid()) if (foundClear.valid())
{ {
size_t foundIndex = foundClear.value(); size_t foundIndex = foundClear.value();
const ClearUpdate &update = mSubresourceUpdates[foundIndex].clear; const ClearUpdate &update = (*levelUpdates)[foundIndex].clear;
// Note that this set command handles combined or separate depth/stencil clears. // Note that this set command handles combined or separate depth/stencil clears.
deferredClears->store(deferredClearIndex, update.aspectFlags, update.value); deferredClears->store(deferredClearIndex, update.aspectFlags, update.value);
...@@ -5195,40 +5225,47 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk, ...@@ -5195,40 +5225,47 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
uint32_t layerEnd, uint32_t layerEnd,
gl::TexLevelMask skipLevelsMask) gl::TexLevelMask skipLevelsMask)
{ {
if (mSubresourceUpdates.empty()) if (!hasStagedUpdatesInLevels(levelGLStart, levelGLEnd))
{ {
return angle::Result::Continue; return angle::Result::Continue;
} }
removeSupersededUpdates(skipLevelsMask); removeSupersededUpdates(skipLevelsMask);
// If a clear is requested and we know it has just been cleared with the same value, we drop the // If a clear is requested and we know it was previously cleared with the same value, we drop
// clear. // the clear.
if (mSubresourceUpdates.size() == 1) if (mCurrentSingleClearValue.valid())
{ {
SubresourceUpdate &update = mSubresourceUpdates[0]; std::vector<SubresourceUpdate> *levelUpdates =
if (update.updateSource == UpdateSource::Clear && mCurrentSingleClearValue.valid() && getLevelUpdates(gl::LevelIndex(mCurrentSingleClearValue.value().levelIndex));
mCurrentSingleClearValue.value() == update.clear) if (levelUpdates && levelUpdates->size() == 1)
{ {
ANGLE_PERF_WARNING(contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW, SubresourceUpdate &update = (*levelUpdates)[0];
"Repeated Clear on framebuffer attachment dropped"); if (update.updateSource == UpdateSource::Clear &&
update.release(contextVk->getRenderer()); mCurrentSingleClearValue.value() == update.clear)
mSubresourceUpdates.clear(); {
return angle::Result::Continue; ANGLE_PERF_WARNING(contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW,
"Repeated Clear on framebuffer attachment dropped");
update.release(contextVk->getRenderer());
levelUpdates->clear();
return angle::Result::Continue;
}
} }
} }
ANGLE_TRY(mStagingBuffer.flush(contextVk)); ANGLE_TRY(mStagingBuffer.flush(contextVk));
std::vector<SubresourceUpdate> updatesToKeep;
const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(mFormat->actualImageFormat()); const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(mFormat->actualImageFormat());
// Upload levels and layers that don't conflict in parallel. The (level, layer) pair is hashed // For each level, upload layers that don't conflict in parallel. The layer is hashed to
// to `(level * mLayerCount + layer) % 64` and used to track whether that subresource is // `layer % 64` and used to track whether that subresource is currently in transfer. If so, a
// currently in transfer. If so, a barrier is inserted. If mLayerCount * mLevelCount > 64, // barrier is inserted. If mLayerCount > 64, there will be a few unnecessary barriers.
// there will be a few unnecessary barriers. //
// Note: when a barrier is necessary when uploading updates to a level, we could instead move to
// the next level and continue uploads in parallel. Once all levels need a barrier, a single
// barrier can be issued and we could continue with the rest of the updates from the first
// level.
constexpr uint32_t kMaxParallelSubresourceUpload = 64; constexpr uint32_t kMaxParallelSubresourceUpload = 64;
uint64_t subresourceUploadsInProgress = 0;
// Start in TransferDst. Don't yet mark any subresource as having defined contents; that is // Start in TransferDst. Don't yet mark any subresource as having defined contents; that is
// done with fine granularity as updates are applied. This is achieved by specifying a layer // done with fine granularity as updates are applied. This is achieved by specifying a layer
...@@ -5237,126 +5274,149 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk, ...@@ -5237,126 +5274,149 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
aspectFlags, this)); aspectFlags, this));
CommandBuffer *commandBuffer = &contextVk->getOutsideRenderPassCommandBuffer(); CommandBuffer *commandBuffer = &contextVk->getOutsideRenderPassCommandBuffer();
for (SubresourceUpdate &update : mSubresourceUpdates) for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLEnd;
++updateMipLevelGL)
{ {
ASSERT(update.updateSource == UpdateSource::Clear || std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(updateMipLevelGL);
(update.updateSource == UpdateSource::Buffer && if (levelUpdates == nullptr)
update.buffer.bufferHelper != nullptr) ||
(update.updateSource == UpdateSource::Image && update.image.image != nullptr &&
update.image.image->valid()));
gl::LevelIndex updateMipLevelGL;
uint32_t updateBaseLayer, updateLayerCount;
update.getDestSubresource(mLayerCount, &updateMipLevelGL, &updateBaseLayer,
&updateLayerCount);
// If the update level is not within the requested range, skip the update.
const bool isUpdateLevelOutsideRange = updateMipLevelGL < levelGLStart ||
updateMipLevelGL >= levelGLEnd ||
updateMipLevelGL > mMaxLevel;
// If the update layers don't intersect the requested layers, skip the update.
const bool areUpdateLayersOutsideRange =
updateBaseLayer + updateLayerCount <= layerStart || updateBaseLayer >= layerEnd;
LevelIndex updateMipLevelVk =
isUpdateLevelOutsideRange ? LevelIndex(0) : toVkLevel(updateMipLevelGL);
// Additionally, if updates to this level are specifically asked to be skipped, skip them.
// This can happen when recreating an image that has been partially incompatibly redefined,
// in which case only updates to the levels that haven't been redefined should be flushed.
if (isUpdateLevelOutsideRange || areUpdateLayersOutsideRange ||
skipLevelsMask.test(updateMipLevelVk.get()))
{ {
updatesToKeep.emplace_back(update); ASSERT(static_cast<size_t>(updateMipLevelGL.get()) >= mSubresourceUpdates.size());
continue; break;
} }
// The updates were holding gl::LevelIndex values so that they would not need modification std::vector<SubresourceUpdate> updatesToKeep;
// when the base level of the texture changes. Now that the update is about to take effect,
// we need to change miplevel to vk::LevelIndex.
if (update.updateSource == UpdateSource::Clear)
{
update.clear.levelIndex = updateMipLevelVk.get();
}
else if (update.updateSource == UpdateSource::Buffer)
{
update.buffer.copyRegion.imageSubresource.mipLevel = updateMipLevelVk.get();
}
else if (update.updateSource == UpdateSource::Image)
{
update.image.copyRegion.dstSubresource.mipLevel = updateMipLevelVk.get();
}
if (updateLayerCount >= kMaxParallelSubresourceUpload) // Hash map of uploads in progress. See comment on kMaxParallelSubresourceUpload.
{ uint64_t subresourceUploadsInProgress = 0;
// If there are more subresources than bits we can track, always insert a barrier.
recordWriteBarrier(aspectFlags, ImageLayout::TransferDst, commandBuffer); for (SubresourceUpdate &update : *levelUpdates)
subresourceUploadsInProgress = std::numeric_limits<uint64_t>::max();
}
else
{ {
const uint64_t subresourceHashRange = angle::Bit<uint64_t>(updateLayerCount) - 1; ASSERT(update.updateSource == UpdateSource::Clear ||
const uint32_t subresourceHashOffset = (update.updateSource == UpdateSource::Buffer &&
(updateMipLevelVk.get() * mLayerCount + updateBaseLayer) % update.buffer.bufferHelper != nullptr) ||
kMaxParallelSubresourceUpload; (update.updateSource == UpdateSource::Image && update.image.image != nullptr &&
const uint64_t subresourceHash = update.image.image->valid()));
ANGLE_ROTL64(subresourceHashRange, subresourceHashOffset);
uint32_t updateBaseLayer, updateLayerCount;
if ((subresourceUploadsInProgress & subresourceHash) != 0) update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
// If the update level is not within the requested range, skip the update.
const bool isUpdateLevelOutsideRange = updateMipLevelGL > mMaxLevel;
// If the update layers don't intersect the requested layers, skip the update.
const bool areUpdateLayersOutsideRange =
updateBaseLayer + updateLayerCount <= layerStart || updateBaseLayer >= layerEnd;
const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
// Additionally, if updates to this level are specifically asked to be skipped, skip
// them. This can happen when recreating an image that has been partially incompatibly
// redefined, in which case only updates to the levels that haven't been redefined
// should be flushed.
if (isUpdateLevelOutsideRange || areUpdateLayersOutsideRange ||
skipLevelsMask.test(updateMipLevelVk.get()))
{
updatesToKeep.emplace_back(update);
continue;
}
// The updates were holding gl::LevelIndex values so that they would not need
// modification when the base level of the texture changes. Now that the update is
// about to take effect, we need to change miplevel to vk::LevelIndex.
if (update.updateSource == UpdateSource::Clear)
{
update.clear.levelIndex = updateMipLevelVk.get();
}
else if (update.updateSource == UpdateSource::Buffer)
{
update.buffer.copyRegion.imageSubresource.mipLevel = updateMipLevelVk.get();
}
else if (update.updateSource == UpdateSource::Image)
{
update.image.copyRegion.dstSubresource.mipLevel = updateMipLevelVk.get();
}
if (updateLayerCount >= kMaxParallelSubresourceUpload)
{ {
// If there's overlap in subresource upload, issue a barrier. // If there are more subresources than bits we can track, always insert a barrier.
recordWriteBarrier(aspectFlags, ImageLayout::TransferDst, commandBuffer); recordWriteBarrier(aspectFlags, ImageLayout::TransferDst, commandBuffer);
subresourceUploadsInProgress = 0; subresourceUploadsInProgress = std::numeric_limits<uint64_t>::max();
} }
subresourceUploadsInProgress |= subresourceHash; else
} {
const uint64_t subresourceHashRange = angle::Bit<uint64_t>(updateLayerCount) - 1;
const uint32_t subresourceHashOffset =
updateBaseLayer % kMaxParallelSubresourceUpload;
const uint64_t subresourceHash =
ANGLE_ROTL64(subresourceHashRange, subresourceHashOffset);
if (update.updateSource == UpdateSource::Clear) if ((subresourceUploadsInProgress & subresourceHash) != 0)
{ {
clear(update.clear.aspectFlags, update.clear.value, updateMipLevelVk, updateBaseLayer, // If there's overlap in subresource upload, issue a barrier.
updateLayerCount, commandBuffer); recordWriteBarrier(aspectFlags, ImageLayout::TransferDst, commandBuffer);
// Remember the latest operation is a clear call subresourceUploadsInProgress = 0;
mCurrentSingleClearValue = update.clear; }
subresourceUploadsInProgress |= subresourceHash;
}
// Do not call onWrite as it removes mCurrentSingleClearValue, but instead call if (update.updateSource == UpdateSource::Clear)
// setContentDefined directly. {
setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount, clear(update.clear.aspectFlags, update.clear.value, updateMipLevelVk,
update.clear.aspectFlags); updateBaseLayer, updateLayerCount, commandBuffer);
} // Remember the latest operation is a clear call
else if (update.updateSource == UpdateSource::Buffer) mCurrentSingleClearValue = update.clear;
{
BufferUpdate &bufferUpdate = update.buffer; // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
// setContentDefined directly.
setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
update.clear.aspectFlags);
}
else if (update.updateSource == UpdateSource::Buffer)
{
BufferUpdate &bufferUpdate = update.buffer;
BufferHelper *currentBuffer = bufferUpdate.bufferHelper; BufferHelper *currentBuffer = bufferUpdate.bufferHelper;
ASSERT(currentBuffer && currentBuffer->valid()); ASSERT(currentBuffer && currentBuffer->valid());
ANGLE_TRY(contextVk->onBufferTransferRead(currentBuffer)); ANGLE_TRY(contextVk->onBufferTransferRead(currentBuffer));
commandBuffer = &contextVk->getOutsideRenderPassCommandBuffer(); commandBuffer = &contextVk->getOutsideRenderPassCommandBuffer();
commandBuffer->copyBufferToImage(currentBuffer->getBuffer().getHandle(), mImage, commandBuffer->copyBufferToImage(currentBuffer->getBuffer().getHandle(), mImage,
getCurrentLayout(), 1, &update.buffer.copyRegion); getCurrentLayout(), 1, &update.buffer.copyRegion);
onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount, onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
update.buffer.copyRegion.imageSubresource.aspectMask); update.buffer.copyRegion.imageSubresource.aspectMask);
} }
else else
{ {
ANGLE_TRY(contextVk->onImageTransferRead(aspectFlags, update.image.image)); ANGLE_TRY(contextVk->onImageTransferRead(aspectFlags, update.image.image));
commandBuffer = &contextVk->getOutsideRenderPassCommandBuffer(); commandBuffer = &contextVk->getOutsideRenderPassCommandBuffer();
commandBuffer->copyImage(update.image.image->getImage(), commandBuffer->copyImage(update.image.image->getImage(),
update.image.image->getCurrentLayout(), mImage, update.image.image->getCurrentLayout(), mImage,
getCurrentLayout(), 1, &update.image.copyRegion); getCurrentLayout(), 1, &update.image.copyRegion);
onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount, onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
update.image.copyRegion.dstSubresource.aspectMask); update.image.copyRegion.dstSubresource.aspectMask);
}
update.release(contextVk->getRenderer());
} }
update.release(contextVk->getRenderer()); // Only remove the updates that were actually applied to the image.
*levelUpdates = std::move(updatesToKeep);
} }
// Only remove the updates that were actually applied to the image. // Compact mSubresourceUpdates, then check if there are any updates left.
mSubresourceUpdates = std::move(updatesToKeep); size_t compactSize;
for (compactSize = mSubresourceUpdates.size(); compactSize > 0; --compactSize)
{
if (!mSubresourceUpdates[compactSize - 1].empty())
{
break;
}
}
mSubresourceUpdates.resize(compactSize);
// If no updates left, release the staging buffers to save memory.
if (mSubresourceUpdates.empty()) if (mSubresourceUpdates.empty())
{ {
mStagingBuffer.releaseInFlightBuffers(contextVk); mStagingBuffer.releaseInFlightBuffers(contextVk);
...@@ -5371,35 +5431,55 @@ angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk) ...@@ -5371,35 +5431,55 @@ angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk)
return flushStagedUpdates(contextVk, mBaseLevel, mBaseLevel + mLevelCount, 0, mLayerCount, {}); return flushStagedUpdates(contextVk, mBaseLevel, mBaseLevel + mLevelCount, 0, mLayerCount, {});
} }
bool ImageHelper::isUpdateStaged(gl::LevelIndex levelGL, uint32_t layer) bool ImageHelper::hasStagedUpdatesForSubresource(gl::LevelIndex levelGL, uint32_t layer) const
{ {
// Check to see if any updates are staged for the given level and layer // Check to see if any updates are staged for the given level and layer
if (mSubresourceUpdates.empty()) const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
if (levelUpdates == nullptr || levelUpdates->empty())
{ {
return false; return false;
} }
for (SubresourceUpdate &update : mSubresourceUpdates) for (const SubresourceUpdate &update : *levelUpdates)
{ {
gl::LevelIndex updateMipLevelGL;
uint32_t updateBaseLayer, updateLayerCount; uint32_t updateBaseLayer, updateLayerCount;
update.getDestSubresource(mLayerCount, &updateMipLevelGL, &updateBaseLayer, update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
&updateLayerCount);
if (updateMipLevelGL == levelGL) if (layer >= updateBaseLayer && layer < (updateBaseLayer + updateLayerCount))
{ {
if (layer >= updateBaseLayer && layer < (updateBaseLayer + updateLayerCount)) // The layer is within the range
{ return true;
// The level matches, and the layer is within the range
return true;
}
} }
} }
return false; return false;
} }
bool ImageHelper::hasStagedUpdatesInAllocatedLevels() const
{
return hasStagedUpdatesInLevels(mBaseLevel, mMaxLevel + 1);
}
bool ImageHelper::hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const
{
for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
{
const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
if (levelUpdates == nullptr)
{
ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
return false;
}
if (!levelUpdates->empty())
{
return true;
}
}
return false;
}
void ImageHelper::removeSupersededUpdates(gl::TexLevelMask skipLevelsMask) void ImageHelper::removeSupersededUpdates(gl::TexLevelMask skipLevelsMask)
{ {
if (mLayerCount > 64) if (mLayerCount > 64)
...@@ -5409,41 +5489,24 @@ void ImageHelper::removeSupersededUpdates(gl::TexLevelMask skipLevelsMask) ...@@ -5409,41 +5489,24 @@ void ImageHelper::removeSupersededUpdates(gl::TexLevelMask skipLevelsMask)
return; return;
} }
// Cache extents for each mip level.
gl::TexLevelArray<gl::Extents> levelExtents;
for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
{
levelExtents[level.get()] = getLevelExtents(level);
}
// Go over updates in reverse order, and mark the layers they completely overwrite. If an // Go over updates in reverse order, and mark the layers they completely overwrite. If an
// update is encountered whose layers are all already marked, that update is superseded by // update is encountered whose layers are all already marked, that update is superseded by
// future updates, so it can be dropped. This tracking is done per level. If the aspect being // future updates, so it can be dropped. This tracking is done per level. If the aspect being
// written to is color/depth or stencil, index 0 or 1 is used respectively. This is so // written to is color/depth or stencil, index 0 or 1 is used respectively. This is so
// that if a depth write for example covers the whole subresource, a stencil write to that same // that if a depth write for example covers the whole subresource, a stencil write to that same
// subresource is not dropped. // subresource is not dropped.
constexpr size_t kIndexColorOrDepth = 0; constexpr size_t kIndexColorOrDepth = 0;
constexpr size_t kIndexStencil = 1; constexpr size_t kIndexStencil = 1;
gl::TexLevelArray<uint64_t> levelSupersededLayers[2] = {}; uint64_t supersededLayers[2] = {};
auto markLayersAndDropSuperseded = [&, skipLevelsMask](const SubresourceUpdate &update) { gl::Extents levelExtents = {};
gl::LevelIndex updateMipLevelGL;
uint32_t updateBaseLayer, updateLayerCount;
update.getDestSubresource(mLayerCount, &updateMipLevelGL, &updateBaseLayer,
&updateLayerCount);
// If the update level is not within the image range, keep the update.
if (updateMipLevelGL < mBaseLevel || updateMipLevelGL > mMaxLevel)
{
return false;
}
// If level is skipped (because incompatibly redefined), don't remove any of its updates. // Note: this lambda only needs |this|, but = is specified because clang warns about kIndex* not
const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL); // needing capture, while MSVC fails to compile without capturing them.
if (skipLevelsMask.test(updateMipLevelVk.get())) auto markLayersAndDropSuperseded = [=, &supersededLayers,
{ &levelExtents](const SubresourceUpdate &update) {
return false; uint32_t updateBaseLayer, updateLayerCount;
} update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
const VkImageAspectFlags aspectMask = update.getDestAspectFlags(); const VkImageAspectFlags aspectMask = update.getDestAspectFlags();
const bool hasColorOrDepth = const bool hasColorOrDepth =
...@@ -5458,11 +5521,10 @@ void ImageHelper::removeSupersededUpdates(gl::TexLevelMask skipLevelsMask) ...@@ -5458,11 +5521,10 @@ void ImageHelper::removeSupersededUpdates(gl::TexLevelMask skipLevelsMask)
updateLayersMask <<= updateBaseLayer; updateLayersMask <<= updateBaseLayer;
const bool isColorOrDepthSuperseded = const bool isColorOrDepthSuperseded =
!hasColorOrDepth || (levelSupersededLayers[kIndexColorOrDepth][updateMipLevelVk.get()] & !hasColorOrDepth ||
updateLayersMask) == updateLayersMask; (supersededLayers[kIndexColorOrDepth] & updateLayersMask) == updateLayersMask;
const bool isStencilSuperseded = const bool isStencilSuperseded =
!hasStencil || (levelSupersededLayers[kIndexStencil][updateMipLevelVk.get()] & !hasStencil || (supersededLayers[kIndexStencil] & updateLayersMask) == updateLayersMask;
updateLayersMask) == updateLayersMask;
if (isColorOrDepthSuperseded && isStencilSuperseded) if (isColorOrDepthSuperseded && isStencilSuperseded)
{ {
...@@ -5471,8 +5533,7 @@ void ImageHelper::removeSupersededUpdates(gl::TexLevelMask skipLevelsMask) ...@@ -5471,8 +5533,7 @@ void ImageHelper::removeSupersededUpdates(gl::TexLevelMask skipLevelsMask)
// Get the area this update affects. Note that clear updates always clear the whole // Get the area this update affects. Note that clear updates always clear the whole
// subresource. // subresource.
const gl::Extents &levelExtent = levelExtents[updateMipLevelVk.get()]; gl::Box updateBox(gl::kOffsetZero, levelExtents);
gl::Box updateBox(gl::kOffsetZero, levelExtent);
if (update.updateSource == UpdateSource::Buffer) if (update.updateSource == UpdateSource::Buffer)
{ {
...@@ -5485,27 +5546,47 @@ void ImageHelper::removeSupersededUpdates(gl::TexLevelMask skipLevelsMask) ...@@ -5485,27 +5546,47 @@ void ImageHelper::removeSupersededUpdates(gl::TexLevelMask skipLevelsMask)
} }
// Only if the update is to the whole subresource, mark its layers. // Only if the update is to the whole subresource, mark its layers.
if (updateBox.coversSameExtent(levelExtent)) if (updateBox.coversSameExtent(levelExtents))
{ {
if (hasColorOrDepth) if (hasColorOrDepth)
{ {
levelSupersededLayers[kIndexColorOrDepth][updateMipLevelVk.get()] |= supersededLayers[kIndexColorOrDepth] |= updateLayersMask;
updateLayersMask;
} }
if (hasStencil) if (hasStencil)
{ {
levelSupersededLayers[kIndexStencil][updateMipLevelVk.get()] |= updateLayersMask; supersededLayers[kIndexStencil] |= updateLayersMask;
} }
} }
return false; return false;
}; };
mSubresourceUpdates.erase( for (gl::LevelIndex level = mBaseLevel; level <= mMaxLevel; ++level)
mSubresourceUpdates.rend().base(), {
std::remove_if(mSubresourceUpdates.rbegin(), mSubresourceUpdates.rend(), std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
markLayersAndDropSuperseded) if (levelUpdates == nullptr)
.base()); {
ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
break;
}
LevelIndex levelVk = toVkLevel(level);
// If level is skipped (because incompatibly redefined), don't remove any of its updates.
if (skipLevelsMask.test(levelVk.get()))
{
continue;
}
levelExtents = getLevelExtents(levelVk);
supersededLayers[kIndexColorOrDepth] = 0;
supersededLayers[kIndexStencil] = 0;
levelUpdates->erase(levelUpdates->rend().base(),
std::remove_if(levelUpdates->rbegin(), levelUpdates->rend(),
markLayersAndDropSuperseded)
.base());
}
} }
angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk, angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
...@@ -5724,7 +5805,7 @@ angle::Result ImageHelper::readPixels(ContextVk *contextVk, ...@@ -5724,7 +5805,7 @@ angle::Result ImageHelper::readPixels(ContextVk *contextVk,
ImageHelper *src = this; ImageHelper *src = this;
ASSERT(!isUpdateStaged(levelGL, layer)); ASSERT(!hasStagedUpdatesForSubresource(levelGL, layer));
if (isMultisampled) if (isMultisampled)
{ {
...@@ -5922,27 +6003,22 @@ void ImageHelper::SubresourceUpdate::release(RendererVk *renderer) ...@@ -5922,27 +6003,22 @@ void ImageHelper::SubresourceUpdate::release(RendererVk *renderer)
} }
} }
bool ImageHelper::SubresourceUpdate::isUpdateToLayerLevel(uint32_t layerIndex, bool ImageHelper::SubresourceUpdate::isUpdateToLayer(uint32_t layerIndex) const
gl::LevelIndex levelIndexGL) const
{ {
gl::LevelIndex updateMipLevelGL;
uint32_t updateBaseLayer, updateLayerCount; uint32_t updateBaseLayer, updateLayerCount;
getDestSubresource(gl::ImageIndex::kEntireLevel, &updateMipLevelGL, &updateBaseLayer, getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
&updateLayerCount);
return updateMipLevelGL == levelIndexGL && updateBaseLayer == layerIndex; return updateBaseLayer == layerIndex;
} }
void ImageHelper::SubresourceUpdate::getDestSubresource(uint32_t imageLayerCount, void ImageHelper::SubresourceUpdate::getDestSubresource(uint32_t imageLayerCount,
gl::LevelIndex *levelIndexGLOut,
uint32_t *baseLayerOut, uint32_t *baseLayerOut,
uint32_t *layerCountOut) const uint32_t *layerCountOut) const
{ {
if (updateSource == UpdateSource::Clear) if (updateSource == UpdateSource::Clear)
{ {
*levelIndexGLOut = gl::LevelIndex(clear.levelIndex); *baseLayerOut = clear.layerIndex;
*baseLayerOut = clear.layerIndex; *layerCountOut = clear.layerCount;
*layerCountOut = clear.layerCount;
if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel)) if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
{ {
...@@ -5954,10 +6030,8 @@ void ImageHelper::SubresourceUpdate::getDestSubresource(uint32_t imageLayerCount ...@@ -5954,10 +6030,8 @@ void ImageHelper::SubresourceUpdate::getDestSubresource(uint32_t imageLayerCount
const VkImageSubresourceLayers &dstSubresource = updateSource == UpdateSource::Buffer const VkImageSubresourceLayers &dstSubresource = updateSource == UpdateSource::Buffer
? buffer.copyRegion.imageSubresource ? buffer.copyRegion.imageSubresource
: image.copyRegion.dstSubresource; : image.copyRegion.dstSubresource;
// Note that the updates store a gl::LevelIndex until they are flushed. *baseLayerOut = dstSubresource.baseArrayLayer;
*levelIndexGLOut = gl::LevelIndex(dstSubresource.mipLevel); *layerCountOut = dstSubresource.layerCount;
*baseLayerOut = dstSubresource.baseArrayLayer;
*layerCountOut = dstSubresource.layerCount;
ASSERT(*layerCountOut != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel)); ASSERT(*layerCountOut != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel));
} }
...@@ -5980,15 +6054,41 @@ VkImageAspectFlags ImageHelper::SubresourceUpdate::getDestAspectFlags() const ...@@ -5980,15 +6054,41 @@ VkImageAspectFlags ImageHelper::SubresourceUpdate::getDestAspectFlags() const
} }
} }
void ImageHelper::appendSubresourceUpdate(SubresourceUpdate &&update) std::vector<ImageHelper::SubresourceUpdate> *ImageHelper::getLevelUpdates(gl::LevelIndex level)
{ {
mSubresourceUpdates.emplace_back(std::move(update)); return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
? &mSubresourceUpdates[level.get()]
: nullptr;
}
const std::vector<ImageHelper::SubresourceUpdate> *ImageHelper::getLevelUpdates(
gl::LevelIndex level) const
{
return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
? &mSubresourceUpdates[level.get()]
: nullptr;
}
void ImageHelper::appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
{
if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
{
mSubresourceUpdates.resize(level.get() + 1);
}
mSubresourceUpdates[level.get()].emplace_back(std::move(update));
onStateChange(angle::SubjectMessage::SubjectChanged); onStateChange(angle::SubjectMessage::SubjectChanged);
} }
void ImageHelper::prependSubresourceUpdate(SubresourceUpdate &&update) void ImageHelper::prependSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
{ {
mSubresourceUpdates.insert(mSubresourceUpdates.begin(), std::move(update)); if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
{
mSubresourceUpdates.resize(level.get() + 1);
}
mSubresourceUpdates[level.get()].insert(mSubresourceUpdates[level.get()].begin(),
std::move(update));
onStateChange(angle::SubjectMessage::SubjectChanged); onStateChange(angle::SubjectMessage::SubjectChanged);
} }
......
...@@ -1537,8 +1537,8 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1537,8 +1537,8 @@ class ImageHelper final : public Resource, public angle::Subject
// as with renderbuffers or surface images. // as with renderbuffers or surface images.
angle::Result flushAllStagedUpdates(ContextVk *contextVk); angle::Result flushAllStagedUpdates(ContextVk *contextVk);
bool isUpdateStaged(gl::LevelIndex levelGL, uint32_t layer); bool hasStagedUpdatesForSubresource(gl::LevelIndex levelGL, uint32_t layer) const;
bool hasStagedUpdates() const { return !mSubresourceUpdates.empty(); } bool hasStagedUpdatesInAllocatedLevels() const;
void recordWriteBarrier(VkImageAspectFlags aspectMask, void recordWriteBarrier(VkImageAspectFlags aspectMask,
ImageLayout newLayout, ImageLayout newLayout,
...@@ -1717,9 +1717,8 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1717,9 +1717,8 @@ class ImageHelper final : public Resource, public angle::Subject
void release(RendererVk *renderer); void release(RendererVk *renderer);
bool isUpdateToLayerLevel(uint32_t layerIndex, gl::LevelIndex levelIndexGL) const; bool isUpdateToLayer(uint32_t layerIndex) const;
void getDestSubresource(uint32_t imageLayerCount, void getDestSubresource(uint32_t imageLayerCount,
gl::LevelIndex *levelIndexGLOut,
uint32_t *baseLayerOut, uint32_t *baseLayerOut,
uint32_t *layerCountOut) const; uint32_t *layerCountOut) const;
VkImageAspectFlags getDestAspectFlags() const; VkImageAspectFlags getDestAspectFlags() const;
...@@ -1771,8 +1770,14 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1771,8 +1770,14 @@ class ImageHelper final : public Resource, public angle::Subject
angle::Result initializeNonZeroMemory(Context *context, VkDeviceSize size); angle::Result initializeNonZeroMemory(Context *context, VkDeviceSize size);
void appendSubresourceUpdate(SubresourceUpdate &&update); std::vector<SubresourceUpdate> *getLevelUpdates(gl::LevelIndex level);
void prependSubresourceUpdate(SubresourceUpdate &&update); const std::vector<SubresourceUpdate> *getLevelUpdates(gl::LevelIndex level) const;
void appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update);
void prependSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update);
// Whether there are any updates in [start, end).
bool hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const;
void resetCachedProperties(); void resetCachedProperties();
void setEntireContentDefined(); void setEntireContentDefined();
void setEntireContentUndefined(); void setEntireContentUndefined();
...@@ -1846,7 +1851,7 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1846,7 +1851,7 @@ class ImageHelper final : public Resource, public angle::Subject
// Staging buffer // Staging buffer
DynamicBuffer mStagingBuffer; DynamicBuffer mStagingBuffer;
std::vector<SubresourceUpdate> mSubresourceUpdates; std::vector<std::vector<SubresourceUpdate>> mSubresourceUpdates;
// Optimization for repeated clear with the same value. If this pointer is not null, the entire // Optimization for repeated clear with the same value. If this pointer is not null, the entire
// image it has been cleared to the specified clear value. If another clear call is made with // image it has been cleared to the specified clear value. If another clear call is made with
......
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