Commit 2392e6b3 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Move content-defined tracking to ImageHelper

Content-defined tracking was done in render targets prior to this change. This had multiple drawbacks: - When a framebuffer attachment is changed (including the first time it's set), it's unknown whether the contents of the attachment is defined. - Invalidate takes effect at the end of render pass, at which point the render target objects may be gone. Attachment ImageHelpers are however correctly tracked. This change moves content-defined tracking to the ImageHelper itself, and tracks it per subresource. ImageHelper::onWrite() now receives the subresource that is being written, and marks it as having defined content. A future optimization can make use of this change to ImageHelper::onWrite to track "dirty" subresources. This can lead to the removal of unnecessary barriers when same-kind writes are done on different subresources of the image. See http://anglebug.com/3347#c15 Bug: b/167275320 Bug: angleproject:4836 Change-Id: Iabd1dace4eae9eb379453a9eb7ec6eafc9db1aef Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2462036 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarIan Elliott <ianelliott@google.com>
parent b2ff69f8
......@@ -2567,7 +2567,7 @@ void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle)
mRenderPassCommands->invalidateRenderPassStencilAttachment(dsState);
mRenderPassCommands->invalidateRenderPassDepthAttachment(dsState);
// Mark content as invalid so that we will not load them in next renderpass
depthStencilRenderTarget->invalidateEntireContent();
depthStencilRenderTarget->invalidateEntireContent(this);
}
// Use finalLayout instead of extra barrier for layout change to present
......@@ -4202,8 +4202,17 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context,
}
VkImageAspectFlags aspectFlags = image->getAspectFlags();
commandBufferHelper->imageWrite(&mResourceUseList, aspectFlags, imageLayout,
vk::AliasingMode::Allowed, image);
uint32_t layerStart = 0;
uint32_t layerCount = image->getLayerCount();
if (imageUnit.layered)
{
layerStart = imageUnit.layered;
layerCount = 1;
}
commandBufferHelper->imageWrite(
&mResourceUseList, gl::LevelIndex(static_cast<uint32_t>(imageUnit.level)), layerStart,
layerCount, aspectFlags, imageLayout, vk::AliasingMode::Allowed, image);
}
return angle::Result::Continue;
......@@ -4635,7 +4644,11 @@ angle::Result ContextVk::onImageRead(VkImageAspectFlags aspectFlags,
return angle::Result::Continue;
}
angle::Result ContextVk::onImageWrite(VkImageAspectFlags aspectFlags,
angle::Result ContextVk::onImageWrite(gl::LevelIndex levelStart,
uint32_t levelCount,
uint32_t layerStart,
uint32_t layerCount,
VkImageAspectFlags aspectFlags,
vk::ImageLayout imageLayout,
vk::ImageHelper *image)
{
......@@ -4647,7 +4660,7 @@ angle::Result ContextVk::onImageWrite(VkImageAspectFlags aspectFlags,
image->recordWriteBarrier(aspectFlags, imageLayout,
&mOutsideRenderPassCommands->getCommandBuffer());
image->retain(&mResourceUseList);
image->onWrite();
image->onWrite(levelStart, levelCount, layerStart, layerCount, aspectFlags);
return angle::Result::Continue;
}
......
......@@ -511,17 +511,29 @@ class ContextVk : public ContextImpl, public vk::Context
{
return onImageRead(aspectFlags, vk::ImageLayout::TransferSrc, image);
}
angle::Result onImageTransferWrite(VkImageAspectFlags aspectFlags, vk::ImageHelper *image)
angle::Result onImageTransferWrite(gl::LevelIndex levelStart,
uint32_t levelCount,
uint32_t layerStart,
uint32_t layerCount,
VkImageAspectFlags aspectFlags,
vk::ImageHelper *image)
{
return onImageWrite(aspectFlags, vk::ImageLayout::TransferDst, image);
return onImageWrite(levelStart, levelCount, layerStart, layerCount, aspectFlags,
vk::ImageLayout::TransferDst, image);
}
angle::Result onImageComputeShaderRead(VkImageAspectFlags aspectFlags, vk::ImageHelper *image)
{
return onImageRead(aspectFlags, vk::ImageLayout::ComputeShaderReadOnly, image);
}
angle::Result onImageComputeShaderWrite(VkImageAspectFlags aspectFlags, vk::ImageHelper *image)
angle::Result onImageComputeShaderWrite(gl::LevelIndex levelStart,
uint32_t levelCount,
uint32_t layerStart,
uint32_t layerCount,
VkImageAspectFlags aspectFlags,
vk::ImageHelper *image)
{
return onImageWrite(aspectFlags, vk::ImageLayout::ComputeShaderWrite, image);
return onImageWrite(levelStart, levelCount, layerStart, layerCount, aspectFlags,
vk::ImageLayout::ComputeShaderWrite, image);
}
void onImageRenderPassRead(VkImageAspectFlags aspectFlags,
......@@ -532,19 +544,26 @@ class ContextVk : public ContextImpl, public vk::Context
mRenderPassCommands->imageRead(&mResourceUseList, aspectFlags, imageLayout, image);
}
void onImageRenderPassWrite(VkImageAspectFlags aspectFlags,
void onImageRenderPassWrite(gl::LevelIndex level,
uint32_t layerStart,
uint32_t layerCount,
VkImageAspectFlags aspectFlags,
vk::ImageLayout imageLayout,
vk::ImageHelper *image)
{
ASSERT(mRenderPassCommands->started());
mRenderPassCommands->imageWrite(&mResourceUseList, aspectFlags, imageLayout,
vk::AliasingMode::Allowed, image);
mRenderPassCommands->imageWrite(&mResourceUseList, level, layerStart, layerCount,
aspectFlags, imageLayout, vk::AliasingMode::Allowed, image);
}
void onDepthStencilDraw(vk::ImageHelper *image, vk::ImageHelper *resolveImage)
void onDepthStencilDraw(gl::LevelIndex level,
uint32_t layer,
vk::ImageHelper *image,
vk::ImageHelper *resolveImage)
{
ASSERT(mRenderPassCommands->started());
mRenderPassCommands->depthStencilImagesDraw(&mResourceUseList, image, resolveImage);
mRenderPassCommands->depthStencilImagesDraw(&mResourceUseList, level, layer, image,
resolveImage);
}
void onImageHelperRelease(const vk::ImageHelper *image)
......@@ -930,7 +949,11 @@ class ContextVk : public ContextImpl, public vk::Context
angle::Result onImageRead(VkImageAspectFlags aspectFlags,
vk::ImageLayout imageLayout,
vk::ImageHelper *image);
angle::Result onImageWrite(VkImageAspectFlags aspectFlags,
angle::Result onImageWrite(gl::LevelIndex levelStart,
uint32_t levelCount,
uint32_t layerStart,
uint32_t layerCount,
VkImageAspectFlags aspectFlags,
vk::ImageLayout imageLayout,
vk::ImageHelper *image);
......
......@@ -824,7 +824,9 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
}
ANGLE_TRY(contextVk->onImageTransferRead(imageAspectMask, srcImage));
ANGLE_TRY(contextVk->onImageTransferWrite(imageAspectMask, dstImage));
ANGLE_TRY(contextVk->onImageTransferWrite(drawRenderTarget->getLevelIndex(), 1,
drawRenderTarget->getLayerIndex(), 1, imageAspectMask,
dstImage));
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
VkImageBlit blit = {};
......@@ -1325,7 +1327,9 @@ angle::Result FramebufferVk::resolveColorWithSubpass(ContextVk *contextVk,
// End the render pass now since we don't (yet) support subpass dependencies.
RenderTargetVk *readRenderTarget = getColorReadRenderTarget();
contextVk->onImageRenderPassWrite(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
contextVk->onImageRenderPassWrite(readRenderTarget->getLevelIndex(),
readRenderTarget->getLayerIndex(), 1,
VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
&readRenderTarget->getImageForRenderPass());
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
......@@ -1362,8 +1366,9 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
{
RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
ANGLE_TRY(contextVk->onImageTransferWrite(VK_IMAGE_ASPECT_COLOR_BIT,
&drawRenderTarget->getImageForWrite()));
ANGLE_TRY(contextVk->onImageTransferWrite(
drawRenderTarget->getLevelIndex(), 1, drawRenderTarget->getLayerIndex(), 1,
VK_IMAGE_ASPECT_COLOR_BIT, &drawRenderTarget->getImageForWrite()));
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
......@@ -1517,7 +1522,7 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
{
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget);
colorRenderTarget->invalidateEntireContent();
colorRenderTarget->invalidateEntireContent(contextVk);
}
}
......@@ -1525,7 +1530,7 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
// invalid. Maybe in the future add separate depth & stencil invalid flags.
if (depthStencilRenderTarget && invalidateDepthBuffer && invalidateStencilBuffer)
{
depthStencilRenderTarget->invalidateEntireContent();
depthStencilRenderTarget->invalidateEntireContent(contextVk);
}
}
......
......@@ -120,7 +120,8 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk)
// Copy font data from staging buffer.
ANGLE_TRY(contextVk->onBufferTransferRead(&fontDataBuffer.get()));
ANGLE_TRY(contextVk->onImageTransferWrite(VK_IMAGE_ASPECT_COLOR_BIT, &mFontImage));
ANGLE_TRY(contextVk->onImageTransferWrite(gl::LevelIndex(0), 1, 0, gl::overlay::kFontCount,
VK_IMAGE_ASPECT_COLOR_BIT, &mFontImage));
vk::CommandBuffer &fontDataUpload = contextVk->getOutsideRenderPassCommandBuffer();
VkBufferImageCopy copy = {};
......
......@@ -1221,9 +1221,6 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
// Note: binding.access is unused because it is implied by the shader.
// TODO(syoussefi): Support image data reinterpretation by using binding.format.
// http://anglebug.com/3563
// Lazily allocate the descriptor set, since we may not need one if all of the image
// uniforms are inactive.
if (descriptorSet == VK_NULL_HANDLE)
......
......@@ -31,8 +31,7 @@ RenderTargetVk::RenderTargetVk(RenderTargetVk &&other)
mResolveImage(other.mResolveImage),
mResolveImageViews(other.mResolveImageViews),
mLevelIndexGL(other.mLevelIndexGL),
mLayerIndex(other.mLayerIndex),
mContentDefined(other.mContentDefined)
mLayerIndex(other.mLayerIndex)
{
other.reset();
}
......@@ -52,9 +51,6 @@ void RenderTargetVk::init(vk::ImageHelper *image,
mLevelIndexGL = levelIndexGL;
mLayerIndex = layerIndex;
// Conservatively assume the content is defined.
mContentDefined = true;
mTransience = transience;
}
......@@ -66,7 +62,6 @@ void RenderTargetVk::reset()
mResolveImageViews = nullptr;
mLevelIndexGL = gl::LevelIndex(0);
mLayerIndex = 0;
mContentDefined = false;
}
vk::ImageViewSubresourceSerial RenderTargetVk::getSubresourceSerialImpl(
......@@ -95,16 +90,14 @@ void RenderTargetVk::onColorDraw(ContextVk *contextVk)
{
ASSERT(!mImage->getFormat().actualImageFormat().hasDepthOrStencilBits());
contextVk->onImageRenderPassWrite(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
mImage);
contextVk->onImageRenderPassWrite(mLevelIndexGL, mLayerIndex, 1, VK_IMAGE_ASPECT_COLOR_BIT,
vk::ImageLayout::ColorAttachment, mImage);
if (mResolveImage)
{
contextVk->onImageRenderPassWrite(VK_IMAGE_ASPECT_COLOR_BIT,
contextVk->onImageRenderPassWrite(mLevelIndexGL, mLayerIndex, 1, VK_IMAGE_ASPECT_COLOR_BIT,
vk::ImageLayout::ColorAttachment, mResolveImage);
}
retainImageViews(contextVk);
mContentDefined = true;
}
void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk)
......@@ -112,10 +105,8 @@ void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk)
const angle::Format &format = mImage->getFormat().actualImageFormat();
ASSERT(format.hasDepthOrStencilBits());
contextVk->onDepthStencilDraw(mImage, mResolveImage);
contextVk->onDepthStencilDraw(mLevelIndexGL, mLayerIndex, mImage, mResolveImage);
retainImageViews(contextVk);
mContentDefined = true;
}
vk::ImageHelper &RenderTargetVk::getImageForRenderPass()
......@@ -175,6 +166,11 @@ bool RenderTargetVk::isResolveImageOwnerOfData() const
return isImageTransient();
}
vk::ImageHelper *RenderTargetVk::getOwnerOfData() const
{
return isResolveImageOwnerOfData() ? mResolveImage : mImage;
}
angle::Result RenderTargetVk::getAndRetainCopyImageView(ContextVk *contextVk,
const vk::ImageView **imageViewOut) const
{
......@@ -226,23 +222,19 @@ void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image,
vk::ImageHelper &RenderTargetVk::getImageForCopy() const
{
ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
return isResolveImageOwnerOfData() ? *mResolveImage : *mImage;
return *getOwnerOfData();
}
vk::ImageHelper &RenderTargetVk::getImageForWrite() const
{
ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
return isResolveImageOwnerOfData() ? *mResolveImage : *mImage;
return *getOwnerOfData();
}
angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
vk::ClearValuesArray *deferredClears,
uint32_t deferredClearIndex)
{
// This function is called when the framebuffer is notified of an update to the attachment's
// contents. Therefore, set mContentDefined so that the next render pass will have loadOp=LOAD.
mContentDefined = true;
ASSERT(mImage->valid() && (!isResolveImageOwnerOfData() || mResolveImage->valid()));
// Note that the layer index for 3D textures is always zero according to Vulkan.
......@@ -252,7 +244,7 @@ angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
layerIndex = 0;
}
vk::ImageHelper *image = isResolveImageOwnerOfData() ? mResolveImage : mImage;
vk::ImageHelper *image = getOwnerOfData();
// All updates should be staged on the image that owns the data as the source of truth. With
// multisampled-render-to-texture framebuffers, that is the resolve image. In that case, even
......@@ -283,6 +275,36 @@ void RenderTargetVk::retainImageViews(ContextVk *contextVk) const
}
}
bool RenderTargetVk::hasDefinedContent() const
{
vk::ImageHelper *image = getOwnerOfData();
// TODO: separate depth and stencil defined content. https://issuetracker.google.com/167275320
return image->hasSubresourceDefinedContent(mLevelIndexGL, mLayerIndex) ||
image->hasSubresourceDefinedStencilContent(mLevelIndexGL, mLayerIndex);
}
void RenderTargetVk::invalidateEntireContent(ContextVk *contextVk)
{
vk::ImageHelper *image = getOwnerOfData();
// TODO: separate depth and stencil defined content. https://issuetracker.google.com/167275320
image->invalidateSubresourceContent(contextVk, mLevelIndexGL, mLayerIndex);
if ((image->getAspectFlags() & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
{
image->invalidateSubresourceStencilContent(contextVk, mLevelIndexGL, mLayerIndex);
}
}
void RenderTargetVk::restoreEntireContent()
{
vk::ImageHelper *image = getOwnerOfData();
// TODO: separate depth and stencil defined content. https://issuetracker.google.com/167275320
image->restoreSubresourceContent(mLevelIndexGL, mLayerIndex);
if ((image->getAspectFlags() & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
{
image->restoreSubresourceStencilContent(mLevelIndexGL, mLayerIndex);
}
}
gl::ImageIndex RenderTargetVk::getImageIndex() const
{
// Determine the GL type from the Vk Image properties.
......
......@@ -108,11 +108,11 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
void retainImageViews(ContextVk *contextVk) const;
bool hasDefinedContent() const { return mContentDefined; }
bool hasDefinedContent() const;
// Mark content as undefined so that certain optimizations are possible such as using DONT_CARE
// as loadOp of the render target in the next renderpass.
void invalidateEntireContent() { mContentDefined = false; }
void restoreEntireContent() { mContentDefined = true; }
void invalidateEntireContent(ContextVk *contextVk);
void restoreEntireContent();
// See the description of mTransience for details of how the following two can interact.
bool hasResolveAttachment() const { return mResolveImage != nullptr && !isEntirelyTransient(); }
......@@ -131,6 +131,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
vk::ImageViewSubresourceSerial getSubresourceSerialImpl(vk::ImageViewHelper *imageViews) const;
bool isResolveImageOwnerOfData() const;
vk::ImageHelper *getOwnerOfData() const;
// The color or depth/stencil attachment of the framebuffer and its view.
vk::ImageHelper *mImage;
......@@ -150,10 +151,6 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
gl::LevelIndex mLevelIndexGL;
uint32_t mLayerIndex;
// Whether the render target has been invalidated. If so, DONT_CARE is used instead of LOAD for
// loadOp of this attachment.
bool mContentDefined;
// If resolve attachment exists, |mTransience| could be *Transient if the multisampled results
// need to be discarded.
//
......
......@@ -1197,7 +1197,8 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
{
// Transition the multisampled image to TRANSFER_SRC for resolve.
ANGLE_TRY(contextVk->onImageTransferRead(VK_IMAGE_ASPECT_COLOR_BIT, &mColorImageMS));
ANGLE_TRY(contextVk->onImageTransferWrite(VK_IMAGE_ASPECT_COLOR_BIT, &image.image));
ANGLE_TRY(contextVk->onImageTransferWrite(gl::LevelIndex(0), 1, 0, 1,
VK_IMAGE_ASPECT_COLOR_BIT, &image.image));
commandBuffer = &contextVk->getOutsideRenderPassCommandBuffer();
VkImageResolve resolveRegion = {};
......
......@@ -842,7 +842,8 @@ angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk,
// Make sure any updates to the image are already flushed.
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
ANGLE_TRY(contextVk->onImageTransferWrite(VK_IMAGE_ASPECT_COLOR_BIT, mImage));
ANGLE_TRY(contextVk->onImageTransferWrite(level, 1, baseLayer, layerCount,
VK_IMAGE_ASPECT_COLOR_BIT, mImage));
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
VkImageSubresourceLayers destSubresource = srcSubresource;
......@@ -875,7 +876,8 @@ angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk,
gl::Extents(sourceBox.width, sourceBox.height, 1),
destFormat, kTransferStagingImageFlags, layerCount));
ANGLE_TRY(contextVk->onImageTransferWrite(VK_IMAGE_ASPECT_COLOR_BIT, stagingImage.get()));
ANGLE_TRY(contextVk->onImageTransferWrite(gl::LevelIndex(0), 1, 0, layerCount,
VK_IMAGE_ASPECT_COLOR_BIT, stagingImage.get()));
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
VkImageSubresourceLayers destSubresource = srcSubresource;
......@@ -961,6 +963,8 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
break;
}
gl::LevelIndex level(index.getLevelIndex());
UtilsVk::CopyImageParameters params;
params.srcOffset[0] = rotatedSourceBox.x;
params.srcOffset[1] = rotatedSourceBox.y;
......@@ -970,13 +974,13 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
params.destOffset[1] = destOffset.y;
params.srcMip = srcImage->toVkLevel(sourceLevelGL).get();
params.srcHeight = srcExtents.height;
params.dstMip = level;
params.srcPremultiplyAlpha = unpackPremultiplyAlpha && !unpackUnmultiplyAlpha;
params.srcUnmultiplyAlpha = unpackUnmultiplyAlpha && !unpackPremultiplyAlpha;
params.srcFlipY = isSrcFlipY;
params.destFlipY = unpackFlipY;
params.srcRotation = srcFramebufferRotation;
gl::LevelIndex level(index.getLevelIndex());
uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : destOffset.z;
uint32_t layerCount = sourceBox.depth;
......@@ -1001,6 +1005,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
{
params.srcLayer = layerIndex + sourceBox.z;
params.dstLayer = baseLayer + layerIndex;
const vk::ImageView *destView;
ANGLE_TRY(getLevelLayerImageView(contextVk, level, baseLayer + layerIndex, &destView));
......@@ -1028,6 +1033,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
{
params.srcLayer = layerIndex + sourceBox.z;
params.dstLayer = layerIndex;
// Create a temporary view for this layer.
vk::ImageView stagingView;
......@@ -1447,15 +1453,24 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk,
// Vulkan Spec requires the bufferOffset to be a multiple of 4 for vkCmdCopyBufferToImage.
ASSERT((offset & (kBufferOffsetMultiple - 1)) == 0);
GLuint layerCount = 0;
GLuint layerIndex = 0;
gl::LevelIndex level = gl::LevelIndex(index.getLevelIndex());
GLuint layerCount = 0;
GLuint layerIndex = 0;
GetRenderTargetLayerCountAndIndex(mImage, index, &layerCount, &layerIndex);
GLuint depth = sourceArea.depth;
if (index.getType() == gl::TextureType::_2DArray)
{
layerCount = depth;
depth = 1;
}
// Make sure the source is initialized and its images are flushed.
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
ANGLE_TRY(contextVk->onBufferTransferRead(srcBuffer));
ANGLE_TRY(contextVk->onImageTransferWrite(VK_IMAGE_ASPECT_COLOR_BIT, mImage));
ANGLE_TRY(contextVk->onImageTransferWrite(level, 1, layerIndex, layerCount,
VK_IMAGE_ASPECT_COLOR_BIT, mImage));
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
......@@ -1465,21 +1480,14 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk,
region.bufferImageHeight = imageHeight;
region.imageExtent.width = sourceArea.width;
region.imageExtent.height = sourceArea.height;
region.imageExtent.depth = sourceArea.depth;
region.imageExtent.depth = depth;
region.imageOffset.x = sourceArea.x;
region.imageOffset.y = sourceArea.y;
region.imageOffset.z = sourceArea.z;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.baseArrayLayer = layerIndex;
region.imageSubresource.layerCount = 1;
region.imageSubresource.mipLevel =
mImage->toVkLevel(gl::LevelIndex(index.getLevelIndex())).get();
if (index.getType() == gl::TextureType::_2DArray)
{
region.imageExtent.depth = 1;
region.imageSubresource.layerCount = sourceArea.depth;
}
region.imageSubresource.layerCount = layerCount;
region.imageSubresource.mipLevel = mImage->toVkLevel(level).get();
commandBuffer.copyBufferToImage(srcBuffer->getBuffer().getHandle(), mImage->getImage(),
mImage->getCurrentLayout(), 1, &region);
......@@ -1529,7 +1537,11 @@ angle::Result TextureVk::generateMipmapsWithCompute(ContextVk *contextVk)
destBaseLevelVk < vk::LevelIndex(mImage->getLevelCount());
destBaseLevelVk = destBaseLevelVk + maxGenerateLevels.get())
{
ANGLE_TRY(contextVk->onImageComputeShaderWrite(VK_IMAGE_ASPECT_COLOR_BIT, mImage));
uint32_t writeLevelCount =
std::min(maxGenerateLevels.get(), mImage->getLevelCount() - destBaseLevelVk.get());
ANGLE_TRY(contextVk->onImageComputeShaderWrite(mImage->toGLLevel(destBaseLevelVk),
writeLevelCount, 0, mImage->getLayerCount(),
VK_IMAGE_ASPECT_COLOR_BIT, mImage));
// Generate mipmaps for every layer separately.
for (uint32_t layer = 0; layer < mImage->getLayerCount(); ++layer)
......
......@@ -1859,8 +1859,9 @@ angle::Result UtilsVk::stencilBlitResolveNoShaderExport(ContextVk *contextVk,
// Change source layout prior to computation.
ANGLE_TRY(contextVk->onImageComputeShaderRead(src->getAspectFlags(), src));
ANGLE_TRY(
contextVk->onImageTransferWrite(depthStencilImage->getAspectFlags(), depthStencilImage));
ANGLE_TRY(contextVk->onImageTransferWrite(
depthStencilRenderTarget->getLevelIndex(), 1, depthStencilRenderTarget->getLayerIndex(), 1,
depthStencilImage->getAspectFlags(), depthStencilImage));
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
......@@ -2091,8 +2092,8 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk,
// Change source layout inside render pass.
contextVk->onImageRenderPassRead(VK_IMAGE_ASPECT_COLOR_BIT,
vk::ImageLayout::FragmentShaderReadOnly, src);
contextVk->onImageRenderPassWrite(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
dest);
contextVk->onImageRenderPassWrite(params.dstMip, params.dstLayer, 1, VK_IMAGE_ASPECT_COLOR_BIT,
vk::ImageLayout::ColorAttachment, dest);
VkDescriptorImageInfo imageInfo = {};
imageInfo.imageView = srcView->getHandle();
......@@ -2404,8 +2405,11 @@ angle::Result UtilsVk::cullOverlayWidgets(ContextVk *contextVk,
ANGLE_TRY(allocateDescriptorSet(contextVk, Function::OverlayCull, &descriptorPoolBinding,
&descriptorSet));
ASSERT(dest->getLevelCount() == 1 && dest->getLayerCount() == 1 &&
dest->getBaseLevel() == gl::LevelIndex(0));
ANGLE_TRY(contextVk->onBufferComputeShaderRead(enabledWidgetsBuffer));
ANGLE_TRY(contextVk->onImageComputeShaderWrite(VK_IMAGE_ASPECT_COLOR_BIT, dest));
ANGLE_TRY(contextVk->onImageComputeShaderWrite(gl::LevelIndex(0), 1, 0, 1,
VK_IMAGE_ASPECT_COLOR_BIT, dest));
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
......@@ -2474,7 +2478,10 @@ angle::Result UtilsVk::drawOverlay(ContextVk *contextVk,
ANGLE_TRY(allocateDescriptorSet(contextVk, Function::OverlayDraw, &descriptorPoolBinding,
&descriptorSet));
ANGLE_TRY(contextVk->onImageComputeShaderWrite(VK_IMAGE_ASPECT_COLOR_BIT, dest));
ASSERT(dest->getLevelCount() == 1 && dest->getLayerCount() == 1 &&
dest->getBaseLevel() == gl::LevelIndex(0));
ANGLE_TRY(contextVk->onImageComputeShaderWrite(gl::LevelIndex(0), 1, 0, 1,
VK_IMAGE_ASPECT_COLOR_BIT, dest));
ANGLE_TRY(contextVk->onImageComputeShaderRead(VK_IMAGE_ASPECT_COLOR_BIT, culledWidgets));
ANGLE_TRY(contextVk->onImageComputeShaderRead(VK_IMAGE_ASPECT_COLOR_BIT, font));
ANGLE_TRY(contextVk->onBufferComputeShaderRead(textWidgetsBuffer));
......
......@@ -139,6 +139,8 @@ class UtilsVk : angle::NonCopyable
int srcMip;
int srcLayer;
int srcHeight;
gl::LevelIndex dstMip;
int dstLayer;
bool srcPremultiplyAlpha;
bool srcUnmultiplyAlpha;
bool srcFlipY;
......
......@@ -945,12 +945,17 @@ class CommandBufferHelper : angle::NonCopyable
ImageLayout imageLayout,
ImageHelper *image);
void imageWrite(ResourceUseList *resourceUseList,
gl::LevelIndex level,
uint32_t layerStart,
uint32_t layerCount,
VkImageAspectFlags aspectFlags,
ImageLayout imageLayout,
AliasingMode aliasingMode,
ImageHelper *image);
void depthStencilImagesDraw(ResourceUseList *resourceUseList,
gl::LevelIndex level,
uint32_t layer,
ImageHelper *image,
ImageHelper *resolveImage);
......@@ -1629,10 +1634,29 @@ class ImageHelper final : public Resource, public angle::Subject
GLuint *inputDepthPitch,
GLuint *inputSkipBytes);
void onWrite() { mCurrentSingleClearValue.reset(); }
// Mark a given subresource as written to. The subresource is identified by [levelStart,
// levelStart + levelCount) and [layerStart, layerStart + layerCount).
void onWrite(gl::LevelIndex levelStart,
uint32_t levelCount,
uint32_t layerStart,
uint32_t layerCount,
VkImageAspectFlags aspectFlags);
bool hasImmutableSampler() { return mExternalFormat != 0; }
uint64_t getExternalFormat() const { return mExternalFormat; }
// Used by framebuffer and render pass functions to decide loadOps and invalidate/un-invalidate
// render target contents.
bool hasSubresourceDefinedContent(gl::LevelIndex level, uint32_t layerIndex) const;
bool hasSubresourceDefinedStencilContent(gl::LevelIndex level, uint32_t layerIndex) const;
void invalidateSubresourceContent(ContextVk *contextVk,
gl::LevelIndex level,
uint32_t layerIndex);
void invalidateSubresourceStencilContent(ContextVk *contextVk,
gl::LevelIndex level,
uint32_t layerIndex);
void restoreSubresourceContent(gl::LevelIndex level, uint32_t layerIndex);
void restoreSubresourceStencilContent(gl::LevelIndex level, uint32_t layerIndex);
private:
enum class UpdateSource
{
......@@ -1736,6 +1760,31 @@ class ImageHelper final : public Resource, public angle::Subject
void appendSubresourceUpdate(SubresourceUpdate &&update);
void prependSubresourceUpdate(SubresourceUpdate &&update);
void resetCachedProperties();
void setEntireContentUndefined();
void setContentDefined(LevelIndex levelStart,
uint32_t levelCount,
uint32_t layerStart,
uint32_t layerCount,
VkImageAspectFlags aspectFlags);
// Up to 8 layers are tracked per level for whether contents are defined, above which the
// contents are considered unconditionally defined. This handles the more likely scenarios of:
//
// - Single layer framebuffer attachments,
// - Cube map framebuffer attachments,
// - Multi-view rendering.
//
// If there arises a need to optimize an application that invalidates layer >= 8, an additional
// hash map can be used to track such subresources.
static constexpr uint32_t kMaxContentDefinedLayerCount = 8;
using LevelContentDefinedMask = angle::BitSet8<kMaxContentDefinedLayerCount>;
// Use the following functions to access m*ContentDefined to make sure the correct level index
// is used (i.e. vk::LevelIndex and not gl::LevelIndex).
LevelContentDefinedMask &getLevelContentDefined(LevelIndex level);
LevelContentDefinedMask &getLevelStencilContentDefined(LevelIndex level);
const LevelContentDefinedMask &getLevelContentDefined(LevelIndex level) const;
const LevelContentDefinedMask &getLevelStencilContentDefined(LevelIndex level) const;
angle::Result initLayerImageViewImpl(
Context *context,
......@@ -1788,6 +1837,11 @@ class ImageHelper final : public Resource, public angle::Subject
// image it has been cleared to the specified clear value. If another clear call is made with
// the exact same clear value, we will detect and skip the clear call.
Optional<ClearUpdate> mCurrentSingleClearValue;
// Track whether each subresource has defined contents. Up to 8 layers are tracked per level,
// above which the contents are considered unconditionally defined.
gl::TexLevelArray<LevelContentDefinedMask> mContentDefined;
gl::TexLevelArray<LevelContentDefinedMask> mStencilContentDefined;
};
// A vector of image views, such as one per level or one per layer.
......
......@@ -576,7 +576,10 @@ class CopyTextureTestWebGL : public CopyTextureTest
};
class CopyTextureTestES3 : public CopyTextureTest
{};
{
protected:
void invalidateBlitThenBlendCommon(GLsizei layerCount);
};
// Test that CopyTexture cannot redefine an immutable texture and CopySubTexture can copy data to
// immutable textures
......@@ -2368,6 +2371,148 @@ TEST_P(CopyTextureTestES3, SwizzleOnSource)
EXPECT_PIXEL_COLOR_EQ(0, 0, kSourceColor);
}
// Test that copy after invalidate works
TEST_P(CopyTextureTestES3, InvalidateCopyThenBlend)
{
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
// http://anglebug.com/5155
ANGLE_SKIP_TEST_IF(IsOSX() && IsIntel() && IsOpenGL());
// http://anglebug.com/5156
ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsOpenGL());
constexpr GLsizei kSize = 4;
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kSize * 2, kSize * 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize * 2, kSize * 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA8, kSize / 2, kSize / 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA8, kSize / 4, kSize / 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 2);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Invalidate the framebuffer.
const GLenum discards[] = {GL_COLOR_ATTACHMENT0};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards);
ASSERT_GL_NO_ERROR();
// Copy into the framebuffer attachment.
const std::vector<GLColor> kSourceColor(kSize * kSize, GLColor::green);
GLTexture sourceTexture;
glBindTexture(GL_TEXTURE_2D, sourceTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
kSourceColor.data());
// Note: flipY is used to avoid direct transfer between textures and force a draw-based path.
glCopyTextureCHROMIUM(sourceTexture, 0, GL_TEXTURE_2D, texture, 2, GL_RGBA8, GL_UNSIGNED_BYTE,
true, false, false);
ASSERT_GL_NO_ERROR();
// Draw and blend, making sure both the copy and draw happen correctly.
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Make sure the blend was correctly done.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::yellow);
}
void CopyTextureTestES3::invalidateBlitThenBlendCommon(GLsizei layerCount)
{
// http://anglebug.com/5152
ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL());
// http://anglebug.com/5155
ANGLE_SKIP_TEST_IF(IsOSX() && IsIntel() && IsOpenGL());
// http://anglebug.com/5156
ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsOpenGL());
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
constexpr GLsizei kSize = 4;
GLTexture texture;
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kSize * 2, kSize * 2, layerCount, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, kSize * 2, kSize * 2, layerCount, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 2, GL_RGBA8, kSize, kSize, layerCount, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 3, GL_RGBA8, kSize / 2, kSize / 2, layerCount, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 4, GL_RGBA8, kSize / 4, kSize / 4, layerCount, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 1);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 4);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 2, layerCount / 2);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
// Invalidate the framebuffer.
const GLenum discards[] = {GL_COLOR_ATTACHMENT0};
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, discards);
ASSERT_GL_NO_ERROR();
// Blit into the framebuffer attachment.
const std::vector<GLColor> kSourceColor(kSize * kSize, GLColor::green);
GLTexture sourceTexture;
glBindTexture(GL_TEXTURE_2D, sourceTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
kSourceColor.data());
GLFramebuffer sourceFramebuffer;
glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebuffer);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sourceTexture,
0);
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Draw and blend, making sure both the blit and draw happen correctly.
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
ASSERT_GL_NO_ERROR();
// Make sure the blend was correctly done.
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::yellow);
}
// Test that blit after invalidate works with non-zero layer
TEST_P(CopyTextureTestES3, InvalidateBlitThenBlend3Layers)
{
invalidateBlitThenBlendCommon(3);
}
// Test that blit after invalidate works with non-zero layer that is very large
TEST_P(CopyTextureTestES3, InvalidateBlitThenBlend1000Layers)
{
invalidateBlitThenBlendCommon(1000);
}
#ifdef Bool
// X11 craziness.
# undef Bool
......
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