Commit 65d10f3b by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Implement robust resource initialization

If a texture or renderbuffer needs to be cleared for robust access or due to having emulated channels, it is immediately cleared. The former relies on a front-end feature that optimizes robust access clears only to levels and layers that are not fully initialized through data upload. Bug: angleproject:2722 Change-Id: Icdab856eb4ffe963f78569b6d80d9ff5cb27ff9b Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1535056 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 8413faba
...@@ -172,9 +172,6 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const ...@@ -172,9 +172,6 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->createContextRobustness = true; outExtensions->createContextRobustness = true;
outExtensions->surfaceOrientation = true; outExtensions->surfaceOrientation = true;
outExtensions->displayTextureShareGroup = true; outExtensions->displayTextureShareGroup = true;
// TODO(geofflang): Extension is exposed but not implemented so that other aspects of the Vulkan
// backend can be tested in Chrome. http://anglebug.com/2722
outExtensions->robustResourceInitialization = true; outExtensions->robustResourceInitialization = true;
// The Vulkan implementation will always say that EGL_KHR_swap_buffers_with_damage is supported. // The Vulkan implementation will always say that EGL_KHR_swap_buffers_with_damage is supported.
......
...@@ -182,8 +182,11 @@ angle::Result RenderTargetVk::ensureImageInitialized(ContextVk *contextVk) ...@@ -182,8 +182,11 @@ angle::Result RenderTargetVk::ensureImageInitialized(ContextVk *contextVk)
{ {
if (mOwner) if (mOwner)
{ {
// If the render target source is a texture, make sure the image is initialized and its
// staged updates flushed.
return mOwner->ensureImageInitialized(contextVk); return mOwner->ensureImageInitialized(contextVk);
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -17,14 +17,6 @@ ...@@ -17,14 +17,6 @@
namespace rx namespace rx
{ {
namespace
{
constexpr VkClearDepthStencilValue kDefaultClearDepthStencilValue = {0.0f, 1};
constexpr VkClearColorValue kBlackClearColorValue = {{0}};
} // anonymous namespace
RenderbufferVk::RenderbufferVk(const gl::RenderbufferState &state) RenderbufferVk::RenderbufferVk(const gl::RenderbufferState &state)
: RenderbufferImpl(state), mOwnsImage(false), mImage(nullptr) : RenderbufferImpl(state), mOwnsImage(false), mImage(nullptr)
{} {}
...@@ -92,18 +84,12 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context, ...@@ -92,18 +84,12 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context,
ANGLE_TRY(mImage->initImageView(contextVk, gl::TextureType::_2D, aspect, gl::SwizzleState(), ANGLE_TRY(mImage->initImageView(contextVk, gl::TextureType::_2D, aspect, gl::SwizzleState(),
&mImageView, 0, 1)); &mImageView, 0, 1));
// TODO(jmadill): Fold this into the RenderPass load/store ops. http://anglebug.com/2361 // Clear the renderbuffer if it has emulated channels.
vk::CommandBuffer *commandBuffer = nullptr; if (vkFormat.hasEmulatedChannels())
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
if (isDepthOrStencilFormat)
{ {
mImage->clearDepthStencil(aspect, aspect, kDefaultClearDepthStencilValue, mImage->stageSubresourceEmulatedClear(gl::ImageIndex::Make2D(0),
commandBuffer); vkFormat.angleFormat());
} ANGLE_TRY(mImage->flushAllStagedUpdates(vk::GetImpl(context)));
else
{
mImage->clearColor(kBlackClearColorValue, 0, 1, commandBuffer);
} }
mRenderTarget.init(mImage, &mImageView, 0, 0, nullptr); mRenderTarget.init(mImage, &mImageView, 0, 0, nullptr);
...@@ -172,8 +158,8 @@ angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *conte ...@@ -172,8 +158,8 @@ angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *conte
angle::Result RenderbufferVk::initializeContents(const gl::Context *context, angle::Result RenderbufferVk::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) const gl::ImageIndex &imageIndex)
{ {
UNIMPLEMENTED(); mImage->stageSubresourceRobustClear(imageIndex, mImage->getFormat().angleFormat());
return angle::Result::Continue; return mImage->flushAllStagedUpdates(vk::GetImpl(context));
} }
void RenderbufferVk::releaseOwnershipOfImage(const gl::Context *context) void RenderbufferVk::releaseOwnershipOfImage(const gl::Context *context)
......
...@@ -256,7 +256,21 @@ angle::Result OffscreenSurfaceVk::getAttachmentRenderTarget( ...@@ -256,7 +256,21 @@ angle::Result OffscreenSurfaceVk::getAttachmentRenderTarget(
angle::Result OffscreenSurfaceVk::initializeContents(const gl::Context *context, angle::Result OffscreenSurfaceVk::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) const gl::ImageIndex &imageIndex)
{ {
UNIMPLEMENTED(); ContextVk *contextVk = vk::GetImpl(context);
if (mColorAttachment.image.valid())
{
mColorAttachment.image.stageSubresourceRobustClear(
imageIndex, mColorAttachment.image.getFormat().angleFormat());
ANGLE_TRY(mColorAttachment.image.flushAllStagedUpdates(contextVk));
}
if (mDepthStencilAttachment.image.valid())
{
mDepthStencilAttachment.image.stageSubresourceRobustClear(
imageIndex, mDepthStencilAttachment.image.getFormat().angleFormat());
ANGLE_TRY(mDepthStencilAttachment.image.flushAllStagedUpdates(contextVk));
}
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -544,12 +558,6 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk, ...@@ -544,12 +558,6 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
ANGLE_VK_TRY(displayVk, ANGLE_VK_TRY(displayVk,
vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, swapchainImages.data())); vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, swapchainImages.data()));
VkClearColorValue transparentBlack = {};
transparentBlack.float32[0] = 0.0f;
transparentBlack.float32[1] = 0.0f;
transparentBlack.float32[2] = 0.0f;
transparentBlack.float32[3] = 0.0f;
mSwapchainImages.resize(imageCount); mSwapchainImages.resize(imageCount);
ANGLE_TRY(resizeSwapHistory(displayVk, imageCount)); ANGLE_TRY(resizeSwapHistory(displayVk, imageCount));
...@@ -561,13 +569,6 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk, ...@@ -561,13 +569,6 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
ANGLE_TRY(member.image.initImageView(displayVk, gl::TextureType::_2D, ANGLE_TRY(member.image.initImageView(displayVk, gl::TextureType::_2D,
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
&member.imageView, 0, 1)); &member.imageView, 0, 1));
// Allocate a command buffer for clearing our images to black.
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(member.image.recordCommands(displayVk, &commandBuffer));
// Set transfer dest layout, and clear the image to black.
member.image.clearColor(transparentBlack, 0, 1, commandBuffer);
} }
// Initialize depth/stencil if requested. // Initialize depth/stencil if requested.
...@@ -583,13 +584,6 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk, ...@@ -583,13 +584,6 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
const VkImageAspectFlags aspect = vk::GetDepthStencilAspectFlags(dsFormat.textureFormat()); const VkImageAspectFlags aspect = vk::GetDepthStencilAspectFlags(dsFormat.textureFormat());
VkClearDepthStencilValue depthStencilClearValue = {1.0f, 0};
// Clear the image.
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mDepthStencilImage.recordCommands(displayVk, &commandBuffer));
mDepthStencilImage.clearDepthStencil(aspect, aspect, depthStencilClearValue, commandBuffer);
ANGLE_TRY(mDepthStencilImage.initImageView(displayVk, gl::TextureType::_2D, aspect, ANGLE_TRY(mDepthStencilImage.initImageView(displayVk, gl::TextureType::_2D, aspect,
gl::SwizzleState(), &mDepthStencilImageView, 0, gl::SwizzleState(), &mDepthStencilImageView, 0,
1)); 1));
...@@ -1093,7 +1087,22 @@ angle::Result WindowSurfaceVk::generateSemaphoresForFlush(vk::Context *context, ...@@ -1093,7 +1087,22 @@ angle::Result WindowSurfaceVk::generateSemaphoresForFlush(vk::Context *context,
angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context, angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) const gl::ImageIndex &imageIndex)
{ {
UNIMPLEMENTED(); ContextVk *contextVk = vk::GetImpl(context);
ASSERT(mSwapchainImages.size() > 0);
ASSERT(mCurrentSwapchainImageIndex < mSwapchainImages.size());
vk::ImageHelper *image = &mSwapchainImages[mCurrentSwapchainImageIndex].image;
image->stageSubresourceRobustClear(imageIndex, image->getFormat().angleFormat());
ANGLE_TRY(image->flushAllStagedUpdates(contextVk));
if (mDepthStencilImage.valid())
{
mDepthStencilImage.stageSubresourceRobustClear(
gl::ImageIndex::Make2D(0), mDepthStencilImage.getFormat().angleFormat());
ANGLE_TRY(mDepthStencilImage.flushAllStagedUpdates(contextVk));
}
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -382,17 +382,28 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context, ...@@ -382,17 +382,28 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
gl::Rectangle destArea(destOffset.x, destOffset.y, clippedSourceArea.width,
clippedSourceArea.height);
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
FramebufferVk *framebufferVk = vk::GetImpl(source); FramebufferVk *framebufferVk = vk::GetImpl(source);
const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index); const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index);
const gl::Offset modifiedDestOffset(destOffset.x, destOffset.y, 0);
const vk::Format &srcFormat = framebufferVk->getColorReadRenderTarget()->getImageFormat(); // If negative offsets are given, clippedSourceArea ensures we don't read from those offsets.
// However, that changes the sourceOffset->destOffset mapping. Here, destOffset is shifted by
// the same amount as clipped to correct the error.
//
// TODO(syoussefi): a bug here is that we need to clip the extents to make sure the copy
// region does not overflow the image size. For example, if an FBO of size 16x16 is used as
// source and glCopyTexImage2D(..., -8, -8, 16, 16, ...) is used, then we will be copying to
// the region expanding from (8, 8) through (23, 23), while the image is only 16x16.
// http://anglebug.com/3355
const gl::Offset modifiedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
destOffset.y + clippedSourceArea.y - sourceArea.y, 0);
RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget();
ANGLE_TRY(colorReadRT->ensureImageInitialized(contextVk));
const vk::Format &srcFormat = colorReadRT->getImageFormat();
const vk::Format &destFormat = renderer->getFormat(internalFormat.sizedInternalFormat); const vk::Format &destFormat = renderer->getFormat(internalFormat.sizedInternalFormat);
bool isViewportFlipY = contextVk->isViewportFlipEnabledForDrawFBO(); bool isViewportFlipY = contextVk->isViewportFlipEnabledForDrawFBO();
...@@ -400,8 +411,6 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context, ...@@ -400,8 +411,6 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
// If it's possible to perform the copy with a transfer, that's the best option. // If it's possible to perform the copy with a transfer, that's the best option.
if (!isViewportFlipY && CanCopyWithTransfer(renderer, srcFormat, destFormat)) if (!isViewportFlipY && CanCopyWithTransfer(renderer, srcFormat, destFormat))
{ {
RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget();
return copySubImageImplWithTransfer(contextVk, offsetImageIndex, modifiedDestOffset, return copySubImageImplWithTransfer(contextVk, offsetImageIndex, modifiedDestOffset,
destFormat, 0, clippedSourceArea, destFormat, 0, clippedSourceArea,
&colorReadRT->getImage()); &colorReadRT->getImage());
...@@ -412,8 +421,6 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context, ...@@ -412,8 +421,6 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
// If it's possible to perform the copy with a draw call, do that. // If it's possible to perform the copy with a draw call, do that.
if (CanCopyWithDraw(renderer, srcFormat, destFormat) && !forceCpuPath) if (CanCopyWithDraw(renderer, srcFormat, destFormat) && !forceCpuPath)
{ {
RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget();
// Layer count can only be 1 as the source is a framebuffer. // Layer count can only be 1 as the source is a framebuffer.
ASSERT(offsetImageIndex.getLayerCount() == 1); ASSERT(offsetImageIndex.getLayerCount() == 1);
...@@ -1016,7 +1023,8 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context) ...@@ -1016,7 +1023,8 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), getLevelCount(), return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), mImage->getLevelCount(),
getNativeImageLayer(0), mImage->getLayerCount(),
commandBuffer); commandBuffer);
} }
...@@ -1027,7 +1035,7 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context) ...@@ -1027,7 +1035,7 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context)
// Some data is pending, or the image has not been defined at all yet // Some data is pending, or the image has not been defined at all yet
if (!mImage->valid()) if (!mImage->valid())
{ {
// lets initialize the image so we can generate the next levels. // Let's initialize the image so we can generate the next levels.
if (mImage->hasStagedUpdates()) if (mImage->hasStagedUpdates())
{ {
ANGLE_TRY(ensureImageInitialized(contextVk)); ANGLE_TRY(ensureImageInitialized(contextVk));
...@@ -1142,6 +1150,7 @@ angle::Result TextureVk::ensureImageInitializedImpl(ContextVk *contextVk, ...@@ -1142,6 +1150,7 @@ angle::Result TextureVk::ensureImageInitializedImpl(ContextVk *contextVk,
{ {
return angle::Result::Continue; return angle::Result::Continue;
} }
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
...@@ -1150,7 +1159,9 @@ angle::Result TextureVk::ensureImageInitializedImpl(ContextVk *contextVk, ...@@ -1150,7 +1159,9 @@ angle::Result TextureVk::ensureImageInitializedImpl(ContextVk *contextVk,
ANGLE_TRY(initImage(contextVk, format, baseLevelExtents, levelCount, commandBuffer)); ANGLE_TRY(initImage(contextVk, format, baseLevelExtents, levelCount, commandBuffer));
} }
return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), levelCount, commandBuffer); return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), mImage->getLevelCount(),
getNativeImageLayer(0), mImage->getLayerCount(),
commandBuffer);
} }
angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk) angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk)
...@@ -1229,7 +1240,12 @@ angle::Result TextureVk::setStorageMultisample(const gl::Context *context, ...@@ -1229,7 +1240,12 @@ angle::Result TextureVk::setStorageMultisample(const gl::Context *context,
angle::Result TextureVk::initializeContents(const gl::Context *context, angle::Result TextureVk::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) const gl::ImageIndex &imageIndex)
{ {
UNIMPLEMENTED(); const gl::ImageDesc &desc = mState.getImageDesc(imageIndex);
const vk::Format &format =
vk::GetImpl(context)->getRenderer()->getFormat(desc.format.info->sizedInternalFormat);
mImage->stageSubresourceRobustClear(imageIndex, format.angleFormat());
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1302,14 +1318,14 @@ angle::Result TextureVk::initImage(ContextVk *contextVk, ...@@ -1302,14 +1318,14 @@ angle::Result TextureVk::initImage(ContextVk *contextVk,
const uint32_t levelCount, const uint32_t levelCount,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
{ {
const RendererVk *renderer = contextVk->getRenderer(); const RendererVk *renderer = contextVk->getRenderer();
const angle::Format &angleFormat = format.textureFormat(); const angle::Format &textureFormat = format.textureFormat();
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT; VK_IMAGE_USAGE_SAMPLED_BIT;
if (!angleFormat.isBlock) if (!textureFormat.isBlock)
{ {
imageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; imageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
} }
...@@ -1324,13 +1340,20 @@ angle::Result TextureVk::initImage(ContextVk *contextVk, ...@@ -1324,13 +1340,20 @@ angle::Result TextureVk::initImage(ContextVk *contextVk,
ANGLE_TRY(initImageViews(contextVk, format, levelCount)); ANGLE_TRY(initImageViews(contextVk, format, levelCount));
if (!angleFormat.isBlock) // If the image has an emulated channel, always clear it. These channels will be masked out in
// future writes, and shouldn't contain uninitialized values.
if (format.hasEmulatedChannels())
{ {
// TODO(jmadill): Fold this into the RenderPass load/store ops if possible, or defer to uint32_t levelCount = mImage->getLevelCount();
// first use. This is only necessary if robustness is required. http://anglebug.com/2361 uint32_t layerCount = mImage->getLayerCount();
VkClearColorValue black = {{0, 0, 0, 1.0f}};
mImage->clearColor(black, 0, levelCount, commandBuffer); for (uint32_t level = 0; level < levelCount; ++level)
{
gl::ImageIndex index = gl::ImageIndex::Make2DArrayRange(level, 0, layerCount);
mImage->stageSubresourceEmulatedClear(index, format.angleFormat());
}
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -178,6 +178,18 @@ size_t Format::getImageCopyBufferAlignment() const ...@@ -178,6 +178,18 @@ size_t Format::getImageCopyBufferAlignment() const
return alignment; return alignment;
} }
bool Format::hasEmulatedChannels() const
{
const angle::Format &angleFmt = angleFormat();
const angle::Format &textureFmt = textureFormat();
return (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0) ||
(angleFmt.blueBits == 0 && textureFmt.blueBits > 0) ||
(angleFmt.greenBits == 0 && textureFmt.greenBits > 0) ||
(angleFmt.depthBits == 0 && textureFmt.depthBits > 0) ||
(angleFmt.stencilBits == 0 && textureFmt.stencilBits > 0);
}
bool operator==(const Format &lhs, const Format &rhs) bool operator==(const Format &lhs, const Format &rhs)
{ {
return &lhs == &rhs; return &lhs == &rhs;
......
...@@ -73,6 +73,8 @@ struct Format final : private angle::NonCopyable ...@@ -73,6 +73,8 @@ struct Format final : private angle::NonCopyable
} }
size_t getImageCopyBufferAlignment() const; size_t getImageCopyBufferAlignment() const;
bool hasEmulatedChannels() const;
angle::FormatID angleFormatID; angle::FormatID angleFormatID;
GLenum internalFormat; GLenum internalFormat;
angle::FormatID textureFormatID; angle::FormatID textureFormatID;
......
...@@ -599,14 +599,14 @@ class ImageHelper final : public CommandGraphResource ...@@ -599,14 +599,14 @@ class ImageHelper final : public CommandGraphResource
GLint samples); GLint samples);
void resetImageWeakReference(); void resetImageWeakReference();
const Image &getImage() const; const Image &getImage() const { return mImage; }
const DeviceMemory &getDeviceMemory() const; const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; }
const gl::Extents &getExtents() const; const gl::Extents &getExtents() const { return mExtents; }
uint32_t getLayerCount() const { return mLayerCount; } uint32_t getLayerCount() const { return mLayerCount; }
uint32_t getLevelCount() const { return mLevelCount; } uint32_t getLevelCount() const { return mLevelCount; }
const Format &getFormat() const; const Format &getFormat() const { return *mFormat; }
GLint getSamples() const; GLint getSamples() const { return mSamples; }
VkImageLayout getCurrentLayout() const; VkImageLayout getCurrentLayout() const;
...@@ -614,22 +614,13 @@ class ImageHelper final : public CommandGraphResource ...@@ -614,22 +614,13 @@ class ImageHelper final : public CommandGraphResource
// image. // image.
gl::Extents getLevelExtents2D(uint32_t level) const; gl::Extents getLevelExtents2D(uint32_t level) const;
void clearColor(const VkClearColorValue &color, // Clear either color or depth/stencil based on image format.
uint32_t baseMipLevel, void clear(const VkClearValue &value,
uint32_t levelCount, uint32_t mipLevel,
vk::CommandBuffer *commandBuffer); uint32_t baseArrayLayer,
uint32_t layerCount,
void clearColorLayer(const VkClearColorValue &color, vk::CommandBuffer *commandBuffer);
uint32_t baseMipLevel,
uint32_t levelCount,
uint32_t baseArrayLayer,
uint32_t layerCount,
vk::CommandBuffer *commandBuffer);
void clearDepthStencil(VkImageAspectFlags imageAspectFlags,
VkImageAspectFlags clearAspectFlags,
const VkClearDepthStencilValue &depthStencil,
vk::CommandBuffer *commandBuffer);
gl::Extents getSize(const gl::ImageIndex &index) const; gl::Extents getSize(const gl::ImageIndex &index) const;
static void Copy(ImageHelper *srcImage, static void Copy(ImageHelper *srcImage,
...@@ -676,6 +667,13 @@ class ImageHelper final : public CommandGraphResource ...@@ -676,6 +667,13 @@ class ImageHelper final : public CommandGraphResource
const gl::Offset &destOffset, const gl::Offset &destOffset,
const gl::Extents &extents); const gl::Extents &extents);
// Stage a clear operation to a clear value based on WebGL requirements.
void stageSubresourceRobustClear(const gl::ImageIndex &index, const angle::Format &format);
// Stage a clear operation to a clear value that initializes emulated channels to the desired
// values.
void stageSubresourceEmulatedClear(const gl::ImageIndex &index, const angle::Format &format);
// This will use the underlying dynamic buffer to allocate some memory to be used as a src or // This will use the underlying dynamic buffer to allocate some memory to be used as a src or
// dst. // dst.
angle::Result allocateStagingMemory(ContextVk *contextVk, angle::Result allocateStagingMemory(ContextVk *contextVk,
...@@ -685,12 +683,21 @@ class ImageHelper final : public CommandGraphResource ...@@ -685,12 +683,21 @@ class ImageHelper final : public CommandGraphResource
VkDeviceSize *offsetOut, VkDeviceSize *offsetOut,
bool *newBufferAllocatedOut); bool *newBufferAllocatedOut);
// Flushes staged updates to a range of levels and layers from start to (but not including) end.
// Due to the nature of updates (done wholly to a VkImageSubresourceLayers), some unsolicited
// layers may also be updated.
angle::Result flushStagedUpdates(Context *context, angle::Result flushStagedUpdates(Context *context,
uint32_t baseLevel, uint32_t levelStart,
uint32_t levelCount, uint32_t levelEnd,
uint32_t layerStart,
uint32_t layerEnd,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
// Creates a command buffer and flushes all staged updates. This is used for one-time
// initialization of resources that we don't expect to accumulate further staged updates, such
// as with renderbuffers or surface images.
angle::Result flushAllStagedUpdates(Context *context);
bool hasStagedUpdates() const; bool hasStagedUpdates() const { return !mSubresourceUpdates.empty(); }
// changeLayout automatically skips the layout change if it's unnecessary. This function can be // changeLayout automatically skips the layout change if it's unnecessary. This function can be
// used to prevent creating a command graph node and subsequently a command buffer for the sole // used to prevent creating a command graph node and subsequently a command buffer for the sole
...@@ -717,17 +724,36 @@ class ImageHelper final : public CommandGraphResource ...@@ -717,17 +724,36 @@ class ImageHelper final : public CommandGraphResource
uint32_t newQueueFamilyIndex, uint32_t newQueueFamilyIndex,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
void stageSubresourceClear(const gl::ImageIndex &index,
const angle::Format &format,
const VkClearColorValue &colorValue,
const VkClearDepthStencilValue &depthStencilValue);
void clearColor(const VkClearColorValue &color,
uint32_t baseMipLevel,
uint32_t levelCount,
uint32_t baseArrayLayer,
uint32_t layerCount,
vk::CommandBuffer *commandBuffer);
void clearDepthStencil(VkImageAspectFlags imageAspectFlags,
VkImageAspectFlags clearAspectFlags,
const VkClearDepthStencilValue &depthStencil,
vk::CommandBuffer *commandBuffer);
struct SubresourceUpdate struct SubresourceUpdate
{ {
SubresourceUpdate(); SubresourceUpdate();
SubresourceUpdate(VkBuffer bufferHandle, const VkBufferImageCopy &copyRegion); SubresourceUpdate(VkBuffer bufferHandle, const VkBufferImageCopy &copyRegion);
SubresourceUpdate(vk::ImageHelper *image, const VkImageCopy &copyRegion); SubresourceUpdate(vk::ImageHelper *image, const VkImageCopy &copyRegion);
SubresourceUpdate(const VkClearValue &clearValue, const gl::ImageIndex &imageIndex);
SubresourceUpdate(const SubresourceUpdate &other); SubresourceUpdate(const SubresourceUpdate &other);
void release(RendererVk *renderer); void release(RendererVk *renderer);
const VkImageSubresourceLayers &dstSubresource() const const VkImageSubresourceLayers &dstSubresource() const
{ {
ASSERT(updateSource == UpdateSource::Buffer || updateSource == UpdateSource::Image);
return updateSource == UpdateSource::Buffer ? buffer.copyRegion.imageSubresource return updateSource == UpdateSource::Buffer ? buffer.copyRegion.imageSubresource
: image.copyRegion.dstSubresource; : image.copyRegion.dstSubresource;
} }
...@@ -735,9 +761,17 @@ class ImageHelper final : public CommandGraphResource ...@@ -735,9 +761,17 @@ class ImageHelper final : public CommandGraphResource
enum class UpdateSource enum class UpdateSource
{ {
Clear,
Buffer, Buffer,
Image, Image,
}; };
struct ClearUpdate
{
VkClearValue value;
uint32_t levelIndex;
uint32_t layerIndex;
uint32_t layerCount;
};
struct BufferUpdate struct BufferUpdate
{ {
VkBuffer bufferHandle; VkBuffer bufferHandle;
...@@ -752,6 +786,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -752,6 +786,7 @@ class ImageHelper final : public CommandGraphResource
UpdateSource updateSource; UpdateSource updateSource;
union union
{ {
ClearUpdate clear;
BufferUpdate buffer; BufferUpdate buffer;
ImageUpdate image; ImageUpdate image;
}; };
......
...@@ -262,8 +262,11 @@ VkImageAspectFlags GetDepthStencilAspectFlags(const angle::Format &format) ...@@ -262,8 +262,11 @@ VkImageAspectFlags GetDepthStencilAspectFlags(const angle::Format &format)
VkImageAspectFlags GetFormatAspectFlags(const angle::Format &format) VkImageAspectFlags GetFormatAspectFlags(const angle::Format &format)
{ {
return (format.redBits > 0 ? VK_IMAGE_ASPECT_COLOR_BIT : 0) | VkImageAspectFlags dsAspect = GetDepthStencilAspectFlags(format);
GetDepthStencilAspectFlags(format); // If the image is not depth stencil, assume color aspect. Note that detecting color formats
// is less trivial than depth/stencil, e.g. as block formats don't indicate any bits for RGBA
// channels.
return dsAspect != 0 ? dsAspect : VK_IMAGE_ASPECT_COLOR_BIT;
} }
VkImageAspectFlags GetDepthStencilAspectFlagsForCopy(bool copyDepth, bool copyStencil) VkImageAspectFlags GetDepthStencilAspectFlagsForCopy(bool copyDepth, bool copyStencil)
......
...@@ -307,7 +307,8 @@ class RobustResourceInitTestES31 : public RobustResourceInitTest ...@@ -307,7 +307,8 @@ class RobustResourceInitTestES31 : public RobustResourceInitTest
// it only works on the implemented renderers // it only works on the implemented renderers
TEST_P(RobustResourceInitTest, ExpectedRendererSupport) TEST_P(RobustResourceInitTest, ExpectedRendererSupport)
{ {
bool shouldHaveSupport = IsD3D11() || IsD3D11_FL93() || IsD3D9() || IsOpenGL() || IsOpenGLES(); bool shouldHaveSupport =
IsD3D11() || IsD3D11_FL93() || IsD3D9() || IsOpenGL() || IsOpenGLES() || IsVulkan();
EXPECT_EQ(shouldHaveSupport, hasGLExtension()); EXPECT_EQ(shouldHaveSupport, hasGLExtension());
EXPECT_EQ(shouldHaveSupport, hasEGLExtension()); EXPECT_EQ(shouldHaveSupport, hasEGLExtension());
EXPECT_EQ(shouldHaveSupport, hasRobustSurfaceInit()); EXPECT_EQ(shouldHaveSupport, hasRobustSurfaceInit());
...@@ -775,7 +776,7 @@ TEST_P(RobustResourceInitTest, UninitializedPartsOfCopied2DTexturesAreBlack) ...@@ -775,7 +776,7 @@ TEST_P(RobustResourceInitTest, UninitializedPartsOfCopied2DTexturesAreBlack)
// succeed with all bytes set to 0. Regression test for a bug where the zeroing out of the // succeed with all bytes set to 0. Regression test for a bug where the zeroing out of the
// texture was done via the same code path as glTexImage2D, causing the PIXEL_UNPACK_BUFFER // texture was done via the same code path as glTexImage2D, causing the PIXEL_UNPACK_BUFFER
// to be used. // to be used.
TEST_P(RobustResourceInitTestES3, ReadingOutOfboundsCopiedTextureWithUnpackBuffer) TEST_P(RobustResourceInitTestES3, ReadingOutOfBoundsCopiedTextureWithUnpackBuffer)
{ {
ANGLE_SKIP_TEST_IF(!hasGLExtension()); ANGLE_SKIP_TEST_IF(!hasGLExtension());
// TODO(geofflang@chromium.org): CopyTexImage from GL_RGBA4444 to GL_ALPHA fails when looking // TODO(geofflang@chromium.org): CopyTexImage from GL_RGBA4444 to GL_ALPHA fails when looking
...@@ -834,7 +835,7 @@ TEST_P(RobustResourceInitTestES3, ReadingOutOfboundsCopiedTextureWithUnpackBuffe ...@@ -834,7 +835,7 @@ TEST_P(RobustResourceInitTestES3, ReadingOutOfboundsCopiedTextureWithUnpackBuffe
// Reading an uninitialized portion of a texture (copyTexImage2D with negative x and y) should // Reading an uninitialized portion of a texture (copyTexImage2D with negative x and y) should
// succeed with all bytes set to 0. // succeed with all bytes set to 0.
TEST_P(RobustResourceInitTest, ReadingOutOfboundsCopiedTexture) TEST_P(RobustResourceInitTest, ReadingOutOfBoundsCopiedTexture)
{ {
ANGLE_SKIP_TEST_IF(!hasGLExtension()); ANGLE_SKIP_TEST_IF(!hasGLExtension());
...@@ -1827,6 +1828,9 @@ TEST_P(RobustResourceInitTestES31, Multisample2DTextureArray) ...@@ -1827,6 +1828,9 @@ TEST_P(RobustResourceInitTestES31, Multisample2DTextureArray)
// Tests that using an out of bounds draw offset with a dynamic array succeeds. // Tests that using an out of bounds draw offset with a dynamic array succeeds.
TEST_P(RobustResourceInitTest, DynamicVertexArrayOffsetOutOfBounds) TEST_P(RobustResourceInitTest, DynamicVertexArrayOffsetOutOfBounds)
{ {
// Not implemented on Vulkan. http://anglebug.com/3350
ANGLE_SKIP_TEST_IF(IsVulkan());
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
glUseProgram(program); glUseProgram(program);
...@@ -1851,7 +1855,8 @@ ANGLE_INSTANTIATE_TEST(RobustResourceInitTest, ...@@ -1851,7 +1855,8 @@ ANGLE_INSTANTIATE_TEST(RobustResourceInitTest,
ES2_OPENGL(), ES2_OPENGL(),
ES3_OPENGL(), ES3_OPENGL(),
ES2_OPENGLES(), ES2_OPENGLES(),
ES3_OPENGLES()); ES3_OPENGLES(),
ES2_VULKAN());
ANGLE_INSTANTIATE_TEST(RobustResourceInitTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(RobustResourceInitTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
......
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