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;
} }
...@@ -1303,13 +1319,13 @@ angle::Result TextureVk::initImage(ContextVk *contextVk, ...@@ -1303,13 +1319,13 @@ angle::Result TextureVk::initImage(ContextVk *contextVk,
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;
......
...@@ -23,6 +23,14 @@ namespace vk ...@@ -23,6 +23,14 @@ namespace vk
{ {
namespace namespace
{ {
// WebGL requires color textures to be initialized to transparent black.
constexpr VkClearColorValue kWebGLInitColorValue = {{0, 0, 0, 0}};
// When emulating a texture, we want the emulated channels to be 0, with alpha 1.
constexpr VkClearColorValue kEmulatedInitColorValue = {{0, 0, 0, 1.0f}};
// WebGL requires depth/stencil textures to be initialized to depth=1, stencil=0. We are fine with
// these values for emulated depth/stencil textures too.
constexpr VkClearDepthStencilValue kWebGLInitDepthStencilValue = {1.0f, 0};
constexpr VkBufferUsageFlags kLineLoopDynamicBufferUsage = constexpr VkBufferUsageFlags kLineLoopDynamicBufferUsage =
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
...@@ -1257,6 +1265,7 @@ ImageHelper::ImageHelper(ImageHelper &&other) ...@@ -1257,6 +1265,7 @@ ImageHelper::ImageHelper(ImageHelper &&other)
mStagingBuffer(std::move(other.mStagingBuffer)), mStagingBuffer(std::move(other.mStagingBuffer)),
mSubresourceUpdates(std::move(other.mSubresourceUpdates)) mSubresourceUpdates(std::move(other.mSubresourceUpdates))
{ {
ASSERT(this != &other);
other.mCurrentLayout = ImageLayout::Undefined; other.mCurrentLayout = ImageLayout::Undefined;
other.mLayerCount = 0; other.mLayerCount = 0;
other.mLevelCount = 0; other.mLevelCount = 0;
...@@ -1516,31 +1525,6 @@ void ImageHelper::dumpResources(Serial serial, std::vector<GarbageObject> *garba ...@@ -1516,31 +1525,6 @@ void ImageHelper::dumpResources(Serial serial, std::vector<GarbageObject> *garba
mDeviceMemory.dumpResources(serial, garbageQueue); mDeviceMemory.dumpResources(serial, garbageQueue);
} }
const Image &ImageHelper::getImage() const
{
return mImage;
}
const DeviceMemory &ImageHelper::getDeviceMemory() const
{
return mDeviceMemory;
}
const gl::Extents &ImageHelper::getExtents() const
{
return mExtents;
}
const Format &ImageHelper::getFormat() const
{
return *mFormat;
}
GLint ImageHelper::getSamples() const
{
return mSamples;
}
VkImageLayout ImageHelper::getCurrentLayout() const VkImageLayout ImageHelper::getCurrentLayout() const
{ {
return kImageMemoryBarrierData[mCurrentLayout].layout; return kImageMemoryBarrierData[mCurrentLayout].layout;
...@@ -1620,14 +1604,6 @@ void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask, ...@@ -1620,14 +1604,6 @@ void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
void ImageHelper::clearColor(const VkClearColorValue &color, void ImageHelper::clearColor(const VkClearColorValue &color,
uint32_t baseMipLevel, uint32_t baseMipLevel,
uint32_t levelCount, uint32_t levelCount,
vk::CommandBuffer *commandBuffer)
{
clearColorLayer(color, baseMipLevel, levelCount, 0, mLayerCount, commandBuffer);
}
void ImageHelper::clearColorLayer(const VkClearColorValue &color,
uint32_t baseMipLevel,
uint32_t levelCount,
uint32_t baseArrayLayer, uint32_t baseArrayLayer,
uint32_t layerCount, uint32_t layerCount,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
...@@ -1666,6 +1642,27 @@ void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags, ...@@ -1666,6 +1642,27 @@ void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags,
commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(), depthStencil, 1, &clearRange); commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(), depthStencil, 1, &clearRange);
} }
void ImageHelper::clear(const VkClearValue &value,
uint32_t mipLevel,
uint32_t baseArrayLayer,
uint32_t layerCount,
vk::CommandBuffer *commandBuffer)
{
const angle::Format &angleFormat = mFormat->angleFormat();
bool isDepthStencil = angleFormat.depthBits > 0 || angleFormat.stencilBits > 0;
if (isDepthStencil)
{
ASSERT(mipLevel == 0 && baseArrayLayer == 0 && layerCount == 1);
const VkImageAspectFlags aspect = vk::GetDepthStencilAspectFlags(mFormat->textureFormat());
clearDepthStencil(aspect, aspect, value.depthStencil, commandBuffer);
}
else
{
clearColor(value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
}
}
gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const
{ {
ASSERT(mExtents.depth == 1); ASSERT(mExtents.depth == 1);
...@@ -2052,6 +2049,40 @@ void ImageHelper::stageSubresourceUpdateFromImage(vk::ImageHelper *image, ...@@ -2052,6 +2049,40 @@ void ImageHelper::stageSubresourceUpdateFromImage(vk::ImageHelper *image,
mSubresourceUpdates.emplace_back(image, copyToImage); mSubresourceUpdates.emplace_back(image, copyToImage);
} }
void ImageHelper::stageSubresourceRobustClear(const gl::ImageIndex &index,
const angle::Format &format)
{
stageSubresourceClear(index, format, kWebGLInitColorValue, kWebGLInitDepthStencilValue);
}
void ImageHelper::stageSubresourceEmulatedClear(const gl::ImageIndex &index,
const angle::Format &format)
{
stageSubresourceClear(index, format, kEmulatedInitColorValue, kWebGLInitDepthStencilValue);
}
void ImageHelper::stageSubresourceClear(const gl::ImageIndex &index,
const angle::Format &format,
const VkClearColorValue &colorValue,
const VkClearDepthStencilValue &depthStencilValue)
{
VkClearValue clearValue;
bool isDepthStencil = format.depthBits > 0 || format.stencilBits > 0;
if (isDepthStencil)
{
clearValue.depthStencil = depthStencilValue;
}
else
{
clearValue.color = colorValue;
}
// Note that clears can arrive out of order from the front-end with respect to staged changes,
// but they are intended to be done first.
mSubresourceUpdates.emplace(mSubresourceUpdates.begin(), clearValue, index);
}
angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk, angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk,
size_t sizeInBytes, size_t sizeInBytes,
uint8_t **ptrOut, uint8_t **ptrOut,
...@@ -2064,8 +2095,10 @@ angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk, ...@@ -2064,8 +2095,10 @@ angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk,
} }
angle::Result ImageHelper::flushStagedUpdates(Context *context, angle::Result ImageHelper::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)
{ {
if (mSubresourceUpdates.empty()) if (mSubresourceUpdates.empty())
...@@ -2078,40 +2111,69 @@ angle::Result ImageHelper::flushStagedUpdates(Context *context, ...@@ -2078,40 +2111,69 @@ angle::Result ImageHelper::flushStagedUpdates(Context *context,
ANGLE_TRY(mStagingBuffer.flush(context)); ANGLE_TRY(mStagingBuffer.flush(context));
std::vector<SubresourceUpdate> updatesToKeep; std::vector<SubresourceUpdate> updatesToKeep;
const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(mFormat->textureFormat());
for (SubresourceUpdate &update : mSubresourceUpdates) for (SubresourceUpdate &update : mSubresourceUpdates)
{ {
ASSERT((update.updateSource == SubresourceUpdate::UpdateSource::Buffer && ASSERT(update.updateSource == SubresourceUpdate::UpdateSource::Clear ||
(update.updateSource == SubresourceUpdate::UpdateSource::Buffer &&
update.buffer.bufferHandle != VK_NULL_HANDLE) || update.buffer.bufferHandle != VK_NULL_HANDLE) ||
(update.updateSource == SubresourceUpdate::UpdateSource::Image && (update.updateSource == SubresourceUpdate::UpdateSource::Image &&
update.image.image != nullptr && update.image.image->valid())); update.image.image != nullptr && update.image.image->valid()));
const uint32_t updateMipLevel = update.dstSubresource().mipLevel; uint32_t updateMipLevel;
uint32_t updateBaseLayer;
uint32_t updateLayerCount;
if (update.updateSource == SubresourceUpdate::UpdateSource::Clear)
{
updateMipLevel = update.clear.levelIndex;
updateBaseLayer = update.clear.layerIndex;
updateLayerCount = update.clear.layerCount;
if (updateLayerCount == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
{
updateLayerCount = mLayerCount;
}
}
else
{
const VkImageSubresourceLayers &dstSubresource = update.dstSubresource();
updateMipLevel = dstSubresource.mipLevel;
updateBaseLayer = dstSubresource.baseArrayLayer;
updateLayerCount = dstSubresource.layerCount;
}
// If the update level is not within the requested range, skip the update.
const bool isUpdateLevelOutsideRange =
updateMipLevel < levelStart || updateMipLevel >= levelEnd;
// If the update layers don't intersect the requested layers, skip the update.
const bool areUpdateLayersOutsideRange =
updateBaseLayer + updateLayerCount <= layerStart || updateBaseLayer >= layerEnd;
// It's possible we've accumulated updates that are no longer applicable if the image has if (isUpdateLevelOutsideRange || areUpdateLayersOutsideRange)
// never been flushed but the image description has changed. Check if this level exist for
// this image.
if (updateMipLevel < baseLevel || updateMipLevel >= baseLevel + levelCount)
{ {
updatesToKeep.emplace_back(update); updatesToKeep.emplace_back(update);
continue; continue;
} }
// Conservatively flush all writes to the image. We could use a more restricted barrier. // Conservatively add a barrier between every update. This is to avoid races when updating
// Do not move this above the for loop, otherwise multiple updates can have race conditions // the same subresource. A possible optimization could be to only issue this barrier when
// and not be applied correctly as seen in: // an overlap in updates is observed.
// dEQP-gles2.functional_texture_specification_texsubimage2d_align_2d* tests on Windows AMD changeLayout(aspectFlags, vk::ImageLayout::TransferDst, commandBuffer);
changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst, commandBuffer);
if (update.updateSource == SubresourceUpdate::UpdateSource::Buffer) if (update.updateSource == SubresourceUpdate::UpdateSource::Clear)
{
clear(update.clear.value, updateMipLevel, updateBaseLayer, updateLayerCount,
commandBuffer);
}
else if (update.updateSource == SubresourceUpdate::UpdateSource::Buffer)
{ {
commandBuffer->copyBufferToImage(update.buffer.bufferHandle, mImage, getCurrentLayout(), commandBuffer->copyBufferToImage(update.buffer.bufferHandle, mImage, getCurrentLayout(),
1, &update.buffer.copyRegion); 1, &update.buffer.copyRegion);
} }
else else
{ {
update.image.image->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, update.image.image->changeLayout(aspectFlags, vk::ImageLayout::TransferSrc,
vk::ImageLayout::TransferSrc, commandBuffer); commandBuffer);
update.image.image->addReadDependency(this); update.image.image->addReadDependency(this);
...@@ -2130,18 +2192,16 @@ angle::Result ImageHelper::flushStagedUpdates(Context *context, ...@@ -2130,18 +2192,16 @@ angle::Result ImageHelper::flushStagedUpdates(Context *context,
{ {
mStagingBuffer.releaseRetainedBuffers(context->getRenderer()); mStagingBuffer.releaseRetainedBuffers(context->getRenderer());
} }
else
{
WARN() << "Internal Vulkan buffer could not be released. This is likely due to having "
"extra images defined in the Texture.";
}
return angle::Result::Continue; return angle::Result::Continue;
} }
bool ImageHelper::hasStagedUpdates() const angle::Result ImageHelper::flushAllStagedUpdates(Context *context)
{ {
return !mSubresourceUpdates.empty(); // Clear the image.
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(recordCommands(context, &commandBuffer));
return flushStagedUpdates(context, 0, mLevelCount, 0, mLayerCount, commandBuffer);
} }
// ImageHelper::SubresourceUpdate implementation // ImageHelper::SubresourceUpdate implementation
...@@ -2159,10 +2219,24 @@ ImageHelper::SubresourceUpdate::SubresourceUpdate(vk::ImageHelper *imageIn, ...@@ -2159,10 +2219,24 @@ ImageHelper::SubresourceUpdate::SubresourceUpdate(vk::ImageHelper *imageIn,
: updateSource(UpdateSource::Image), image{imageIn, copyRegionIn} : updateSource(UpdateSource::Image), image{imageIn, copyRegionIn}
{} {}
ImageHelper::SubresourceUpdate::SubresourceUpdate(const VkClearValue &clearValue,
const gl::ImageIndex &imageIndex)
: updateSource(UpdateSource::Clear)
{
clear.value = clearValue;
clear.levelIndex = imageIndex.getLevelIndex();
clear.layerIndex = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
clear.layerCount = imageIndex.getLayerCount();
}
ImageHelper::SubresourceUpdate::SubresourceUpdate(const SubresourceUpdate &other) ImageHelper::SubresourceUpdate::SubresourceUpdate(const SubresourceUpdate &other)
: updateSource(other.updateSource) : updateSource(other.updateSource)
{ {
if (updateSource == UpdateSource::Buffer) if (updateSource == UpdateSource::Clear)
{
clear = other.clear;
}
else if (updateSource == UpdateSource::Buffer)
{ {
buffer = other.buffer; buffer = other.buffer;
} }
...@@ -2185,6 +2259,11 @@ void ImageHelper::SubresourceUpdate::release(RendererVk *renderer) ...@@ -2185,6 +2259,11 @@ void ImageHelper::SubresourceUpdate::release(RendererVk *renderer)
bool ImageHelper::SubresourceUpdate::isUpdateToLayerLevel(uint32_t layerIndex, bool ImageHelper::SubresourceUpdate::isUpdateToLayerLevel(uint32_t layerIndex,
uint32_t levelIndex) const uint32_t levelIndex) const
{ {
if (updateSource == UpdateSource::Clear)
{
return clear.levelIndex == levelIndex && clear.layerIndex == layerIndex;
}
const VkImageSubresourceLayers &dst = dstSubresource(); const VkImageSubresourceLayers &dst = dstSubresource();
return dst.baseArrayLayer == layerIndex && dst.mipLevel == levelIndex; return dst.baseArrayLayer == layerIndex && dst.mipLevel == levelIndex;
} }
......
...@@ -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);
void clearColorLayer(const VkClearColorValue &color,
uint32_t baseMipLevel,
uint32_t levelCount,
uint32_t baseArrayLayer, uint32_t baseArrayLayer,
uint32_t layerCount, uint32_t layerCount,
vk::CommandBuffer *commandBuffer); 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