Commit 68bd685a by Shahbaz Youssefi Committed by Commit Bot

Reland: "4 Vulkan content defined CLs."

Reland "Vulkan: Avoid content restore by detecting no-op stencil" This relands commit 243d0f89. Reland "Vulkan: Restore at the end of RP if write-after-invalidate" This relands commit e5d52ac3. Reland "Vulkan: Invalidate/restore depth/stencil separately." This relands commit 61fa0878. Reland "Vulkan: Move content-defined tracking to ImageHelper" This relands commit 2392e6b3. Reason for revert: Caused crashes in Fuchsia x64 and on ARM. Reland fixes content defined for external images. Original CL message: 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 Bug: angleproject:5159 Change-Id: If5c1ae7152657fd7c94db7d55bea4fb9ddf835ba Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2464825Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 3345e5fd
...@@ -14,6 +14,23 @@ ...@@ -14,6 +14,23 @@
namespace gl namespace gl
{ {
namespace
{
bool IsStencilNoOp(GLenum stencilFunc,
GLenum stencilFail,
GLenum stencilPassDepthFail,
GLenum stencilPassDepthPass)
{
const bool isNeverAndKeep = stencilFunc == GL_NEVER && stencilFail == GL_KEEP;
const bool isAlwaysAndKeepOrAllKeep = (stencilFunc == GL_ALWAYS || stencilFail == GL_KEEP) &&
stencilPassDepthFail == GL_KEEP &&
stencilPassDepthPass == GL_KEEP;
return isNeverAndKeep || isAlwaysAndKeepOrAllKeep;
}
} // anonymous namespace
RasterizerState::RasterizerState() RasterizerState::RasterizerState()
{ {
memset(this, 0, sizeof(RasterizerState)); memset(this, 0, sizeof(RasterizerState));
...@@ -114,6 +131,20 @@ bool DepthStencilState::isStencilMaskedOut() const ...@@ -114,6 +131,20 @@ bool DepthStencilState::isStencilMaskedOut() const
return (stencilMask & stencilWritemask) == 0; return (stencilMask & stencilWritemask) == 0;
} }
bool DepthStencilState::isStencilNoOp() const
{
return isStencilMaskedOut() ||
IsStencilNoOp(stencilFunc, stencilFail, stencilPassDepthFail, stencilPassDepthPass);
}
bool DepthStencilState::isStencilBackNoOp() const
{
const bool isStencilBackMaskedOut = (stencilBackMask & stencilBackWritemask) == 0;
return isStencilBackMaskedOut ||
IsStencilNoOp(stencilBackFunc, stencilBackFail, stencilBackPassDepthFail,
stencilBackPassDepthPass);
}
bool operator==(const DepthStencilState &a, const DepthStencilState &b) bool operator==(const DepthStencilState &a, const DepthStencilState &b)
{ {
return memcmp(&a, &b, sizeof(DepthStencilState)) == 0; return memcmp(&a, &b, sizeof(DepthStencilState)) == 0;
......
...@@ -199,6 +199,8 @@ struct DepthStencilState final ...@@ -199,6 +199,8 @@ struct DepthStencilState final
bool isDepthMaskedOut() const; bool isDepthMaskedOut() const;
bool isStencilMaskedOut() const; bool isStencilMaskedOut() const;
bool isStencilNoOp() const;
bool isStencilBackNoOp() const;
bool depthTest; bool depthTest;
GLenum depthFunc; GLenum depthFunc;
......
...@@ -300,7 +300,7 @@ vk::ResourceAccess GetDepthAccess(const gl::DepthStencilState &dsState) ...@@ -300,7 +300,7 @@ vk::ResourceAccess GetDepthAccess(const gl::DepthStencilState &dsState)
{ {
return vk::ResourceAccess::Unused; return vk::ResourceAccess::Unused;
} }
return dsState.depthMask ? vk::ResourceAccess::Write : vk::ResourceAccess::ReadOnly; return dsState.isDepthMaskedOut() ? vk::ResourceAccess::ReadOnly : vk::ResourceAccess::Write;
} }
vk::ResourceAccess GetStencilAccess(const gl::DepthStencilState &dsState) vk::ResourceAccess GetStencilAccess(const gl::DepthStencilState &dsState)
...@@ -309,8 +309,9 @@ vk::ResourceAccess GetStencilAccess(const gl::DepthStencilState &dsState) ...@@ -309,8 +309,9 @@ vk::ResourceAccess GetStencilAccess(const gl::DepthStencilState &dsState)
{ {
return vk::ResourceAccess::Unused; return vk::ResourceAccess::Unused;
} }
// Simplify this check by returning write instead of checking the mask.
return vk::ResourceAccess::Write; return dsState.isStencilNoOp() && dsState.isStencilBackNoOp() ? vk::ResourceAccess::ReadOnly
: vk::ResourceAccess::Write;
} }
} // anonymous namespace } // anonymous namespace
...@@ -2567,7 +2568,8 @@ void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle) ...@@ -2567,7 +2568,8 @@ void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle)
mRenderPassCommands->invalidateRenderPassStencilAttachment(dsState); mRenderPassCommands->invalidateRenderPassStencilAttachment(dsState);
mRenderPassCommands->invalidateRenderPassDepthAttachment(dsState); mRenderPassCommands->invalidateRenderPassDepthAttachment(dsState);
// Mark content as invalid so that we will not load them in next renderpass // Mark content as invalid so that we will not load them in next renderpass
depthStencilRenderTarget->invalidateEntireContent(); depthStencilRenderTarget->invalidateEntireContent(this);
depthStencilRenderTarget->invalidateEntireStencilContent(this);
} }
// Use finalLayout instead of extra barrier for layout change to present // Use finalLayout instead of extra barrier for layout change to present
...@@ -4202,8 +4204,17 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context, ...@@ -4202,8 +4204,17 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context,
} }
VkImageAspectFlags aspectFlags = image->getAspectFlags(); VkImageAspectFlags aspectFlags = image->getAspectFlags();
commandBufferHelper->imageWrite(&mResourceUseList, aspectFlags, imageLayout, uint32_t layerStart = 0;
vk::AliasingMode::Allowed, image); 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; return angle::Result::Continue;
...@@ -4635,7 +4646,11 @@ angle::Result ContextVk::onImageRead(VkImageAspectFlags aspectFlags, ...@@ -4635,7 +4646,11 @@ angle::Result ContextVk::onImageRead(VkImageAspectFlags aspectFlags,
return angle::Result::Continue; 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::ImageLayout imageLayout,
vk::ImageHelper *image) vk::ImageHelper *image)
{ {
...@@ -4647,7 +4662,7 @@ angle::Result ContextVk::onImageWrite(VkImageAspectFlags aspectFlags, ...@@ -4647,7 +4662,7 @@ angle::Result ContextVk::onImageWrite(VkImageAspectFlags aspectFlags,
image->recordWriteBarrier(aspectFlags, imageLayout, image->recordWriteBarrier(aspectFlags, imageLayout,
&mOutsideRenderPassCommands->getCommandBuffer()); &mOutsideRenderPassCommands->getCommandBuffer());
image->retain(&mResourceUseList); image->retain(&mResourceUseList);
image->onWrite(); image->onWrite(levelStart, levelCount, layerStart, layerCount, aspectFlags);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -5115,16 +5130,8 @@ angle::Result ContextVk::updateRenderPassDepthStencilAccess() ...@@ -5115,16 +5130,8 @@ angle::Result ContextVk::updateRenderPassDepthStencilAccess()
} }
else else
{ {
if (mRenderPassCommands->onDepthAccess(depthAccess)) mRenderPassCommands->onDepthAccess(depthAccess);
{ mRenderPassCommands->onStencilAccess(stencilAccess);
// The attachment is no longer invalidated, so set mContentDefined to true
mDrawFramebuffer->restoreDepthStencilDefinedContents();
}
if (mRenderPassCommands->onStencilAccess(stencilAccess))
{
// The attachment is no longer invalidated, so set mContentDefined to true
mDrawFramebuffer->restoreDepthStencilDefinedContents();
}
mDrawFramebuffer->updateRenderPassReadOnlyDepthMode(this, mRenderPassCommands); mDrawFramebuffer->updateRenderPassReadOnlyDepthMode(this, mRenderPassCommands);
} }
......
...@@ -511,17 +511,29 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -511,17 +511,29 @@ class ContextVk : public ContextImpl, public vk::Context
{ {
return onImageRead(aspectFlags, vk::ImageLayout::TransferSrc, image); 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) angle::Result onImageComputeShaderRead(VkImageAspectFlags aspectFlags, vk::ImageHelper *image)
{ {
return onImageRead(aspectFlags, vk::ImageLayout::ComputeShaderReadOnly, 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, void onImageRenderPassRead(VkImageAspectFlags aspectFlags,
...@@ -532,19 +544,26 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -532,19 +544,26 @@ class ContextVk : public ContextImpl, public vk::Context
mRenderPassCommands->imageRead(&mResourceUseList, aspectFlags, imageLayout, image); 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::ImageLayout imageLayout,
vk::ImageHelper *image) vk::ImageHelper *image)
{ {
ASSERT(mRenderPassCommands->started()); ASSERT(mRenderPassCommands->started());
mRenderPassCommands->imageWrite(&mResourceUseList, aspectFlags, imageLayout, mRenderPassCommands->imageWrite(&mResourceUseList, level, layerStart, layerCount,
vk::AliasingMode::Allowed, image); 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()); ASSERT(mRenderPassCommands->started());
mRenderPassCommands->depthStencilImagesDraw(&mResourceUseList, image, resolveImage); mRenderPassCommands->depthStencilImagesDraw(&mResourceUseList, level, layer, image,
resolveImage);
} }
void onImageHelperRelease(const vk::ImageHelper *image) void onImageHelperRelease(const vk::ImageHelper *image)
...@@ -930,7 +949,11 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -930,7 +949,11 @@ class ContextVk : public ContextImpl, public vk::Context
angle::Result onImageRead(VkImageAspectFlags aspectFlags, angle::Result onImageRead(VkImageAspectFlags aspectFlags,
vk::ImageLayout imageLayout, vk::ImageLayout imageLayout,
vk::ImageHelper *image); 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::ImageLayout imageLayout,
vk::ImageHelper *image); vk::ImageHelper *image);
......
...@@ -824,7 +824,9 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk, ...@@ -824,7 +824,9 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
} }
ANGLE_TRY(contextVk->onImageTransferRead(imageAspectMask, srcImage)); 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(); vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
VkImageBlit blit = {}; VkImageBlit blit = {};
...@@ -1360,8 +1362,9 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk, ...@@ -1360,8 +1362,9 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
{ {
RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL]; RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
ANGLE_TRY(contextVk->onImageTransferWrite(VK_IMAGE_ASPECT_COLOR_BIT, ANGLE_TRY(contextVk->onImageTransferWrite(
&drawRenderTarget->getImageForWrite())); drawRenderTarget->getLevelIndex(), 1, drawRenderTarget->getLayerIndex(), 1,
VK_IMAGE_ASPECT_COLOR_BIT, &drawRenderTarget->getImageForWrite()));
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer(); vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
...@@ -1515,15 +1518,21 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk, ...@@ -1515,15 +1518,21 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
{ {
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget); ASSERT(colorRenderTarget);
colorRenderTarget->invalidateEntireContent(); colorRenderTarget->invalidateEntireContent(contextVk);
} }
} }
// If we have a depth / stencil render target AND we invalidate both we'll mark it as // If we have a depth / stencil render target, invalidate its aspects.
// invalid. Maybe in the future add separate depth & stencil invalid flags. if (depthStencilRenderTarget)
if (depthStencilRenderTarget && invalidateDepthBuffer && invalidateStencilBuffer)
{ {
depthStencilRenderTarget->invalidateEntireContent(); if (invalidateDepthBuffer)
{
depthStencilRenderTarget->invalidateEntireContent(contextVk);
}
if (invalidateStencilBuffer)
{
depthStencilRenderTarget->invalidateEntireStencilContent(contextVk);
}
} }
} }
...@@ -2189,11 +2198,7 @@ angle::Result FramebufferVk::clearWithCommand( ...@@ -2189,11 +2198,7 @@ angle::Result FramebufferVk::clearWithCommand(
dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
dsClearValue.depthStencil = clearDepthStencilValue; dsClearValue.depthStencil = clearDepthStencilValue;
// Explicitly mark a depth write because we are clearing the depth buffer. // Explicitly mark a depth write because we are clearing the depth buffer.
if (renderpassCommands->onDepthAccess(vk::ResourceAccess::Write)) renderpassCommands->onDepthAccess(vk::ResourceAccess::Write);
{
// The attachment is no longer invalidated, so set mContentDefined to true
restoreDepthStencilDefinedContents();
}
} }
if (clearStencil) if (clearStencil)
...@@ -2201,11 +2206,7 @@ angle::Result FramebufferVk::clearWithCommand( ...@@ -2201,11 +2206,7 @@ angle::Result FramebufferVk::clearWithCommand(
dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
dsClearValue.depthStencil = clearDepthStencilValue; dsClearValue.depthStencil = clearDepthStencilValue;
// Explicitly mark a stencil write because we are clearing the stencil buffer. // Explicitly mark a stencil write because we are clearing the stencil buffer.
if (renderpassCommands->onStencilAccess(vk::ResourceAccess::Write)) renderpassCommands->onStencilAccess(vk::ResourceAccess::Write);
{
// The attachment is no longer invalidated, so set mContentDefined to true
restoreDepthStencilDefinedContents();
}
} }
if (dsAspectFlags != 0) if (dsAspectFlags != 0)
...@@ -2344,7 +2345,11 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2344,7 +2345,11 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
if (!depthStencilRenderTarget->hasDefinedContent() || if (!depthStencilRenderTarget->hasDefinedContent() ||
depthStencilRenderTarget->isEntirelyTransient()) depthStencilRenderTarget->isEntirelyTransient())
{ {
depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
if (!depthStencilRenderTarget->hasDefinedStencilContent() ||
depthStencilRenderTarget->isEntirelyTransient())
{
stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
} }
...@@ -2479,7 +2484,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2479,7 +2484,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
if (depthStencilRenderTarget) if (depthStencilRenderTarget)
{ {
// This must be called after hasDefinedContent() since it will set content to valid. We are // This must be called after hasDefined*Content() since it will set content to valid. We are
// tracking content valid very loosely here that as long as it is attached, it assumes will // tracking content valid very loosely here that as long as it is attached, it assumes will
// have valid content. The only time it has undefined content is between swap and // have valid content. The only time it has undefined content is between swap and
// startNewRenderPass // startNewRenderPass
...@@ -2504,18 +2509,6 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2504,18 +2509,6 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
void FramebufferVk::restoreDepthStencilDefinedContents()
{
// If the depthStencilRenderTarget does not have "defined content" (i.e. meaning that a future
// render pass should use a loadOp of DONT_CARE), we should restore it (i.e. so that a future
// render pass uses a loadOp of LOAD).
RenderTargetVk *depthStencilRenderTarget = mRenderTargetCache.getDepthStencil();
if (depthStencilRenderTarget)
{
depthStencilRenderTarget->restoreEntireContent();
}
}
void FramebufferVk::updateActiveColorMasks(size_t colorIndexGL, bool r, bool g, bool b, bool a) void FramebufferVk::updateActiveColorMasks(size_t colorIndexGL, bool r, bool g, bool b, bool a)
{ {
gl::BlendStateExt::ColorMaskStorage::SetValueIndexed( gl::BlendStateExt::ColorMaskStorage::SetValueIndexed(
......
...@@ -118,7 +118,6 @@ class FramebufferVk : public FramebufferImpl ...@@ -118,7 +118,6 @@ class FramebufferVk : public FramebufferImpl
angle::Result startNewRenderPass(ContextVk *contextVk, angle::Result startNewRenderPass(ContextVk *contextVk,
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
vk::CommandBuffer **commandBufferOut); vk::CommandBuffer **commandBufferOut);
void restoreDepthStencilDefinedContents();
RenderTargetVk *getFirstRenderTarget() const; RenderTargetVk *getFirstRenderTarget() const;
GLint getSamples() const; GLint getSamples() const;
......
...@@ -120,7 +120,8 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk) ...@@ -120,7 +120,8 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk)
// Copy font data from staging buffer. // Copy font data from staging buffer.
ANGLE_TRY(contextVk->onBufferTransferRead(&fontDataBuffer.get())); 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(); vk::CommandBuffer &fontDataUpload = contextVk->getOutsideRenderPassCommandBuffer();
VkBufferImageCopy copy = {}; VkBufferImageCopy copy = {};
......
...@@ -1221,9 +1221,6 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet( ...@@ -1221,9 +1221,6 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
// Note: binding.access is unused because it is implied by the shader. // 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 // Lazily allocate the descriptor set, since we may not need one if all of the image
// uniforms are inactive. // uniforms are inactive.
if (descriptorSet == VK_NULL_HANDLE) if (descriptorSet == VK_NULL_HANDLE)
......
...@@ -31,8 +31,7 @@ RenderTargetVk::RenderTargetVk(RenderTargetVk &&other) ...@@ -31,8 +31,7 @@ RenderTargetVk::RenderTargetVk(RenderTargetVk &&other)
mResolveImage(other.mResolveImage), mResolveImage(other.mResolveImage),
mResolveImageViews(other.mResolveImageViews), mResolveImageViews(other.mResolveImageViews),
mLevelIndexGL(other.mLevelIndexGL), mLevelIndexGL(other.mLevelIndexGL),
mLayerIndex(other.mLayerIndex), mLayerIndex(other.mLayerIndex)
mContentDefined(other.mContentDefined)
{ {
other.reset(); other.reset();
} }
...@@ -52,9 +51,6 @@ void RenderTargetVk::init(vk::ImageHelper *image, ...@@ -52,9 +51,6 @@ void RenderTargetVk::init(vk::ImageHelper *image,
mLevelIndexGL = levelIndexGL; mLevelIndexGL = levelIndexGL;
mLayerIndex = layerIndex; mLayerIndex = layerIndex;
// Conservatively assume the content is defined.
mContentDefined = true;
mTransience = transience; mTransience = transience;
} }
...@@ -66,7 +62,6 @@ void RenderTargetVk::reset() ...@@ -66,7 +62,6 @@ void RenderTargetVk::reset()
mResolveImageViews = nullptr; mResolveImageViews = nullptr;
mLevelIndexGL = gl::LevelIndex(0); mLevelIndexGL = gl::LevelIndex(0);
mLayerIndex = 0; mLayerIndex = 0;
mContentDefined = false;
} }
vk::ImageViewSubresourceSerial RenderTargetVk::getSubresourceSerialImpl( vk::ImageViewSubresourceSerial RenderTargetVk::getSubresourceSerialImpl(
...@@ -95,16 +90,14 @@ void RenderTargetVk::onColorDraw(ContextVk *contextVk) ...@@ -95,16 +90,14 @@ void RenderTargetVk::onColorDraw(ContextVk *contextVk)
{ {
ASSERT(!mImage->getFormat().actualImageFormat().hasDepthOrStencilBits()); ASSERT(!mImage->getFormat().actualImageFormat().hasDepthOrStencilBits());
contextVk->onImageRenderPassWrite(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment, contextVk->onImageRenderPassWrite(mLevelIndexGL, mLayerIndex, 1, VK_IMAGE_ASPECT_COLOR_BIT,
mImage); vk::ImageLayout::ColorAttachment, mImage);
if (mResolveImage) if (mResolveImage)
{ {
contextVk->onImageRenderPassWrite(VK_IMAGE_ASPECT_COLOR_BIT, contextVk->onImageRenderPassWrite(mLevelIndexGL, mLayerIndex, 1, VK_IMAGE_ASPECT_COLOR_BIT,
vk::ImageLayout::ColorAttachment, mResolveImage); vk::ImageLayout::ColorAttachment, mResolveImage);
} }
retainImageViews(contextVk); retainImageViews(contextVk);
mContentDefined = true;
} }
void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk) void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk)
...@@ -112,10 +105,8 @@ void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk) ...@@ -112,10 +105,8 @@ void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk)
const angle::Format &format = mImage->getFormat().actualImageFormat(); const angle::Format &format = mImage->getFormat().actualImageFormat();
ASSERT(format.hasDepthOrStencilBits()); ASSERT(format.hasDepthOrStencilBits());
contextVk->onDepthStencilDraw(mImage, mResolveImage); contextVk->onDepthStencilDraw(mLevelIndexGL, mLayerIndex, mImage, mResolveImage);
retainImageViews(contextVk); retainImageViews(contextVk);
mContentDefined = true;
} }
vk::ImageHelper &RenderTargetVk::getImageForRenderPass() vk::ImageHelper &RenderTargetVk::getImageForRenderPass()
...@@ -175,6 +166,11 @@ bool RenderTargetVk::isResolveImageOwnerOfData() const ...@@ -175,6 +166,11 @@ bool RenderTargetVk::isResolveImageOwnerOfData() const
return isImageTransient(); return isImageTransient();
} }
vk::ImageHelper *RenderTargetVk::getOwnerOfData() const
{
return isResolveImageOwnerOfData() ? mResolveImage : mImage;
}
angle::Result RenderTargetVk::getAndRetainCopyImageView(ContextVk *contextVk, angle::Result RenderTargetVk::getAndRetainCopyImageView(ContextVk *contextVk,
const vk::ImageView **imageViewOut) const const vk::ImageView **imageViewOut) const
{ {
...@@ -226,23 +222,19 @@ void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image, ...@@ -226,23 +222,19 @@ void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image,
vk::ImageHelper &RenderTargetVk::getImageForCopy() const vk::ImageHelper &RenderTargetVk::getImageForCopy() const
{ {
ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid())); ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
return isResolveImageOwnerOfData() ? *mResolveImage : *mImage; return *getOwnerOfData();
} }
vk::ImageHelper &RenderTargetVk::getImageForWrite() const vk::ImageHelper &RenderTargetVk::getImageForWrite() const
{ {
ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid())); ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
return isResolveImageOwnerOfData() ? *mResolveImage : *mImage; return *getOwnerOfData();
} }
angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk, angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
vk::ClearValuesArray *deferredClears, vk::ClearValuesArray *deferredClears,
uint32_t deferredClearIndex) 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())); ASSERT(mImage->valid() && (!isResolveImageOwnerOfData() || mResolveImage->valid()));
// Note that the layer index for 3D textures is always zero according to Vulkan. // Note that the layer index for 3D textures is always zero according to Vulkan.
...@@ -252,7 +244,7 @@ angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk, ...@@ -252,7 +244,7 @@ angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
layerIndex = 0; 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 // 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 // multisampled-render-to-texture framebuffers, that is the resolve image. In that case, even
...@@ -283,6 +275,42 @@ void RenderTargetVk::retainImageViews(ContextVk *contextVk) const ...@@ -283,6 +275,42 @@ void RenderTargetVk::retainImageViews(ContextVk *contextVk) const
} }
} }
bool RenderTargetVk::hasDefinedContent() const
{
vk::ImageHelper *image = getOwnerOfData();
return image->hasSubresourceDefinedContent(mLevelIndexGL, mLayerIndex);
}
bool RenderTargetVk::hasDefinedStencilContent() const
{
vk::ImageHelper *image = getOwnerOfData();
return image->hasSubresourceDefinedStencilContent(mLevelIndexGL, mLayerIndex);
}
void RenderTargetVk::invalidateEntireContent(ContextVk *contextVk)
{
vk::ImageHelper *image = getOwnerOfData();
image->invalidateSubresourceContent(contextVk, mLevelIndexGL, mLayerIndex);
}
void RenderTargetVk::invalidateEntireStencilContent(ContextVk *contextVk)
{
vk::ImageHelper *image = getOwnerOfData();
image->invalidateSubresourceStencilContent(contextVk, mLevelIndexGL, mLayerIndex);
}
void RenderTargetVk::restoreEntireContent()
{
vk::ImageHelper *image = getOwnerOfData();
image->restoreSubresourceContent(mLevelIndexGL, mLayerIndex);
}
void RenderTargetVk::restoreEntireStencilContent()
{
vk::ImageHelper *image = getOwnerOfData();
image->restoreSubresourceStencilContent(mLevelIndexGL, mLayerIndex);
}
gl::ImageIndex RenderTargetVk::getImageIndex() const gl::ImageIndex RenderTargetVk::getImageIndex() const
{ {
// Determine the GL type from the Vk Image properties. // Determine the GL type from the Vk Image properties.
......
...@@ -108,11 +108,14 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -108,11 +108,14 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
void retainImageViews(ContextVk *contextVk) const; void retainImageViews(ContextVk *contextVk) const;
bool hasDefinedContent() const { return mContentDefined; } bool hasDefinedContent() const;
bool hasDefinedStencilContent() const;
// Mark content as undefined so that certain optimizations are possible such as using DONT_CARE // 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. // as loadOp of the render target in the next renderpass.
void invalidateEntireContent() { mContentDefined = false; } void invalidateEntireContent(ContextVk *contextVk);
void restoreEntireContent() { mContentDefined = true; } void invalidateEntireStencilContent(ContextVk *contextVk);
void restoreEntireContent();
void restoreEntireStencilContent();
// See the description of mTransience for details of how the following two can interact. // See the description of mTransience for details of how the following two can interact.
bool hasResolveAttachment() const { return mResolveImage != nullptr && !isEntirelyTransient(); } bool hasResolveAttachment() const { return mResolveImage != nullptr && !isEntirelyTransient(); }
...@@ -131,6 +134,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -131,6 +134,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
vk::ImageViewSubresourceSerial getSubresourceSerialImpl(vk::ImageViewHelper *imageViews) const; vk::ImageViewSubresourceSerial getSubresourceSerialImpl(vk::ImageViewHelper *imageViews) const;
bool isResolveImageOwnerOfData() const; bool isResolveImageOwnerOfData() const;
vk::ImageHelper *getOwnerOfData() const;
// The color or depth/stencil attachment of the framebuffer and its view. // The color or depth/stencil attachment of the framebuffer and its view.
vk::ImageHelper *mImage; vk::ImageHelper *mImage;
...@@ -140,7 +144,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -140,7 +144,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
// implement GL_EXT_multisampled_render_to_texture, so while the rendering is done on mImage // implement GL_EXT_multisampled_render_to_texture, so while the rendering is done on mImage
// during the renderpass, the resolved image is the one that actually holds the data. This // during the renderpass, the resolved image is the one that actually holds the data. This
// means that data uploads and blit are done on this image, copies are done out of this image // means that data uploads and blit are done on this image, copies are done out of this image
// etc. This means that if there is no clear, and hasDefinedContent(), the contents of // etc. This means that if there is no clear, and hasDefined*Content(), the contents of
// mResolveImage must be copied to mImage since the loadOp of the attachment must be set to // mResolveImage must be copied to mImage since the loadOp of the attachment must be set to
// LOAD. // LOAD.
vk::ImageHelper *mResolveImage; vk::ImageHelper *mResolveImage;
...@@ -150,10 +154,6 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -150,10 +154,6 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
gl::LevelIndex mLevelIndexGL; gl::LevelIndex mLevelIndexGL;
uint32_t mLayerIndex; 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 // If resolve attachment exists, |mTransience| could be *Transient if the multisampled results
// need to be discarded. // need to be discarded.
// //
......
...@@ -1197,7 +1197,8 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk, ...@@ -1197,7 +1197,8 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
{ {
// Transition the multisampled image to TRANSFER_SRC for resolve. // Transition the multisampled image to TRANSFER_SRC for resolve.
ANGLE_TRY(contextVk->onImageTransferRead(VK_IMAGE_ASPECT_COLOR_BIT, &mColorImageMS)); 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(); commandBuffer = &contextVk->getOutsideRenderPassCommandBuffer();
VkImageResolve resolveRegion = {}; VkImageResolve resolveRegion = {};
......
...@@ -842,7 +842,8 @@ angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk, ...@@ -842,7 +842,8 @@ angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk,
// Make sure any updates to the image are already flushed. // Make sure any updates to the image are already flushed.
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels)); 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(); vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
VkImageSubresourceLayers destSubresource = srcSubresource; VkImageSubresourceLayers destSubresource = srcSubresource;
...@@ -875,7 +876,8 @@ angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk, ...@@ -875,7 +876,8 @@ angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk,
gl::Extents(sourceBox.width, sourceBox.height, 1), gl::Extents(sourceBox.width, sourceBox.height, 1),
destFormat, kTransferStagingImageFlags, layerCount)); 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(); vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
VkImageSubresourceLayers destSubresource = srcSubresource; VkImageSubresourceLayers destSubresource = srcSubresource;
...@@ -961,6 +963,8 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk, ...@@ -961,6 +963,8 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
break; break;
} }
gl::LevelIndex level(index.getLevelIndex());
UtilsVk::CopyImageParameters params; UtilsVk::CopyImageParameters params;
params.srcOffset[0] = rotatedSourceBox.x; params.srcOffset[0] = rotatedSourceBox.x;
params.srcOffset[1] = rotatedSourceBox.y; params.srcOffset[1] = rotatedSourceBox.y;
...@@ -970,13 +974,13 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk, ...@@ -970,13 +974,13 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
params.destOffset[1] = destOffset.y; params.destOffset[1] = destOffset.y;
params.srcMip = srcImage->toVkLevel(sourceLevelGL).get(); params.srcMip = srcImage->toVkLevel(sourceLevelGL).get();
params.srcHeight = srcExtents.height; params.srcHeight = srcExtents.height;
params.dstMip = level;
params.srcPremultiplyAlpha = unpackPremultiplyAlpha && !unpackUnmultiplyAlpha; params.srcPremultiplyAlpha = unpackPremultiplyAlpha && !unpackUnmultiplyAlpha;
params.srcUnmultiplyAlpha = unpackUnmultiplyAlpha && !unpackPremultiplyAlpha; params.srcUnmultiplyAlpha = unpackUnmultiplyAlpha && !unpackPremultiplyAlpha;
params.srcFlipY = isSrcFlipY; params.srcFlipY = isSrcFlipY;
params.destFlipY = unpackFlipY; params.destFlipY = unpackFlipY;
params.srcRotation = srcFramebufferRotation; params.srcRotation = srcFramebufferRotation;
gl::LevelIndex level(index.getLevelIndex());
uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : destOffset.z; uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : destOffset.z;
uint32_t layerCount = sourceBox.depth; uint32_t layerCount = sourceBox.depth;
...@@ -1001,6 +1005,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk, ...@@ -1001,6 +1005,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
{ {
params.srcLayer = layerIndex + sourceBox.z; params.srcLayer = layerIndex + sourceBox.z;
params.dstLayer = baseLayer + layerIndex;
const vk::ImageView *destView; const vk::ImageView *destView;
ANGLE_TRY(getLevelLayerImageView(contextVk, level, baseLayer + layerIndex, &destView)); ANGLE_TRY(getLevelLayerImageView(contextVk, level, baseLayer + layerIndex, &destView));
...@@ -1028,6 +1033,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk, ...@@ -1028,6 +1033,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
{ {
params.srcLayer = layerIndex + sourceBox.z; params.srcLayer = layerIndex + sourceBox.z;
params.dstLayer = layerIndex;
// Create a temporary view for this layer. // Create a temporary view for this layer.
vk::ImageView stagingView; vk::ImageView stagingView;
...@@ -1447,15 +1453,24 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk, ...@@ -1447,15 +1453,24 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk,
// Vulkan Spec requires the bufferOffset to be a multiple of 4 for vkCmdCopyBufferToImage. // Vulkan Spec requires the bufferOffset to be a multiple of 4 for vkCmdCopyBufferToImage.
ASSERT((offset & (kBufferOffsetMultiple - 1)) == 0); ASSERT((offset & (kBufferOffsetMultiple - 1)) == 0);
GLuint layerCount = 0; gl::LevelIndex level = gl::LevelIndex(index.getLevelIndex());
GLuint layerIndex = 0; GLuint layerCount = 0;
GLuint layerIndex = 0;
GetRenderTargetLayerCountAndIndex(mImage, index, &layerCount, &layerIndex); 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. // Make sure the source is initialized and its images are flushed.
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels)); ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
ANGLE_TRY(contextVk->onBufferTransferRead(srcBuffer)); 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(); vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
...@@ -1465,21 +1480,14 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk, ...@@ -1465,21 +1480,14 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk,
region.bufferImageHeight = imageHeight; region.bufferImageHeight = imageHeight;
region.imageExtent.width = sourceArea.width; region.imageExtent.width = sourceArea.width;
region.imageExtent.height = sourceArea.height; region.imageExtent.height = sourceArea.height;
region.imageExtent.depth = sourceArea.depth; region.imageExtent.depth = depth;
region.imageOffset.x = sourceArea.x; region.imageOffset.x = sourceArea.x;
region.imageOffset.y = sourceArea.y; region.imageOffset.y = sourceArea.y;
region.imageOffset.z = sourceArea.z; region.imageOffset.z = sourceArea.z;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.baseArrayLayer = layerIndex; region.imageSubresource.baseArrayLayer = layerIndex;
region.imageSubresource.layerCount = 1; region.imageSubresource.layerCount = layerCount;
region.imageSubresource.mipLevel = region.imageSubresource.mipLevel = mImage->toVkLevel(level).get();
mImage->toVkLevel(gl::LevelIndex(index.getLevelIndex())).get();
if (index.getType() == gl::TextureType::_2DArray)
{
region.imageExtent.depth = 1;
region.imageSubresource.layerCount = sourceArea.depth;
}
commandBuffer.copyBufferToImage(srcBuffer->getBuffer().getHandle(), mImage->getImage(), commandBuffer.copyBufferToImage(srcBuffer->getBuffer().getHandle(), mImage->getImage(),
mImage->getCurrentLayout(), 1, &region); mImage->getCurrentLayout(), 1, &region);
...@@ -1529,7 +1537,11 @@ angle::Result TextureVk::generateMipmapsWithCompute(ContextVk *contextVk) ...@@ -1529,7 +1537,11 @@ angle::Result TextureVk::generateMipmapsWithCompute(ContextVk *contextVk)
destBaseLevelVk < vk::LevelIndex(mImage->getLevelCount()); destBaseLevelVk < vk::LevelIndex(mImage->getLevelCount());
destBaseLevelVk = destBaseLevelVk + maxGenerateLevels.get()) 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. // Generate mipmaps for every layer separately.
for (uint32_t layer = 0; layer < mImage->getLayerCount(); ++layer) for (uint32_t layer = 0; layer < mImage->getLayerCount(); ++layer)
......
...@@ -1893,8 +1893,9 @@ angle::Result UtilsVk::stencilBlitResolveNoShaderExport(ContextVk *contextVk, ...@@ -1893,8 +1893,9 @@ angle::Result UtilsVk::stencilBlitResolveNoShaderExport(ContextVk *contextVk,
// Change source layout prior to computation. // Change source layout prior to computation.
ANGLE_TRY(contextVk->onImageComputeShaderRead(src->getAspectFlags(), src)); ANGLE_TRY(contextVk->onImageComputeShaderRead(src->getAspectFlags(), src));
ANGLE_TRY( ANGLE_TRY(contextVk->onImageTransferWrite(
contextVk->onImageTransferWrite(depthStencilImage->getAspectFlags(), depthStencilImage)); depthStencilRenderTarget->getLevelIndex(), 1, depthStencilRenderTarget->getLayerIndex(), 1,
depthStencilImage->getAspectFlags(), depthStencilImage));
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer(); vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
...@@ -2125,8 +2126,8 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk, ...@@ -2125,8 +2126,8 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk,
// Change source layout inside render pass. // Change source layout inside render pass.
contextVk->onImageRenderPassRead(VK_IMAGE_ASPECT_COLOR_BIT, contextVk->onImageRenderPassRead(VK_IMAGE_ASPECT_COLOR_BIT,
vk::ImageLayout::FragmentShaderReadOnly, src); vk::ImageLayout::FragmentShaderReadOnly, src);
contextVk->onImageRenderPassWrite(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment, contextVk->onImageRenderPassWrite(params.dstMip, params.dstLayer, 1, VK_IMAGE_ASPECT_COLOR_BIT,
dest); vk::ImageLayout::ColorAttachment, dest);
VkDescriptorImageInfo imageInfo = {}; VkDescriptorImageInfo imageInfo = {};
imageInfo.imageView = srcView->getHandle(); imageInfo.imageView = srcView->getHandle();
...@@ -2438,8 +2439,11 @@ angle::Result UtilsVk::cullOverlayWidgets(ContextVk *contextVk, ...@@ -2438,8 +2439,11 @@ angle::Result UtilsVk::cullOverlayWidgets(ContextVk *contextVk,
ANGLE_TRY(allocateDescriptorSet(contextVk, Function::OverlayCull, &descriptorPoolBinding, ANGLE_TRY(allocateDescriptorSet(contextVk, Function::OverlayCull, &descriptorPoolBinding,
&descriptorSet)); &descriptorSet));
ASSERT(dest->getLevelCount() == 1 && dest->getLayerCount() == 1 &&
dest->getBaseLevel() == gl::LevelIndex(0));
ANGLE_TRY(contextVk->onBufferComputeShaderRead(enabledWidgetsBuffer)); 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(); vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
...@@ -2508,7 +2512,10 @@ angle::Result UtilsVk::drawOverlay(ContextVk *contextVk, ...@@ -2508,7 +2512,10 @@ angle::Result UtilsVk::drawOverlay(ContextVk *contextVk,
ANGLE_TRY(allocateDescriptorSet(contextVk, Function::OverlayDraw, &descriptorPoolBinding, ANGLE_TRY(allocateDescriptorSet(contextVk, Function::OverlayDraw, &descriptorPoolBinding,
&descriptorSet)); &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, culledWidgets));
ANGLE_TRY(contextVk->onImageComputeShaderRead(VK_IMAGE_ASPECT_COLOR_BIT, font)); ANGLE_TRY(contextVk->onImageComputeShaderRead(VK_IMAGE_ASPECT_COLOR_BIT, font));
ANGLE_TRY(contextVk->onBufferComputeShaderRead(textWidgetsBuffer)); ANGLE_TRY(contextVk->onBufferComputeShaderRead(textWidgetsBuffer));
......
...@@ -132,6 +132,8 @@ class UtilsVk : angle::NonCopyable ...@@ -132,6 +132,8 @@ class UtilsVk : angle::NonCopyable
int srcMip; int srcMip;
int srcLayer; int srcLayer;
int srcHeight; int srcHeight;
gl::LevelIndex dstMip;
int dstLayer;
bool srcPremultiplyAlpha; bool srcPremultiplyAlpha;
bool srcUnmultiplyAlpha; bool srcUnmultiplyAlpha;
bool srcFlipY; bool srcFlipY;
......
...@@ -945,12 +945,17 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -945,12 +945,17 @@ class CommandBufferHelper : angle::NonCopyable
ImageLayout imageLayout, ImageLayout imageLayout,
ImageHelper *image); ImageHelper *image);
void imageWrite(ResourceUseList *resourceUseList, void imageWrite(ResourceUseList *resourceUseList,
gl::LevelIndex level,
uint32_t layerStart,
uint32_t layerCount,
VkImageAspectFlags aspectFlags, VkImageAspectFlags aspectFlags,
ImageLayout imageLayout, ImageLayout imageLayout,
AliasingMode aliasingMode, AliasingMode aliasingMode,
ImageHelper *image); ImageHelper *image);
void depthStencilImagesDraw(ResourceUseList *resourceUseList, void depthStencilImagesDraw(ResourceUseList *resourceUseList,
gl::LevelIndex level,
uint32_t layer,
ImageHelper *image, ImageHelper *image,
ImageHelper *resolveImage); ImageHelper *resolveImage);
...@@ -1029,9 +1034,10 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1029,9 +1034,10 @@ class CommandBufferHelper : angle::NonCopyable
// Keep track of the size of commands in the command buffer. If the size grows in the // Keep track of the size of commands in the command buffer. If the size grows in the
// future, that implies that drawing occured since invalidated. // future, that implies that drawing occured since invalidated.
mDepthCmdSizeInvalidated = mCommandBuffer.getCommandSize(); mDepthCmdSizeInvalidated = mCommandBuffer.getCommandSize();
// Also track the size if the attachment is currently disabled. // Also track the size if the attachment is currently disabled.
mDepthCmdSizeDisabled = const bool isDepthWriteEnabled = dsState.depthTest && dsState.depthMask;
(dsState.depthTest && dsState.depthMask) ? kInfiniteCmdSize : mDepthCmdSizeInvalidated; mDepthCmdSizeDisabled = isDepthWriteEnabled ? kInfiniteCmdSize : mDepthCmdSizeInvalidated;
} }
void invalidateRenderPassStencilAttachment(const gl::DepthStencilState &dsState) void invalidateRenderPassStencilAttachment(const gl::DepthStencilState &dsState)
...@@ -1040,9 +1046,12 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1040,9 +1046,12 @@ class CommandBufferHelper : angle::NonCopyable
// Keep track of the size of commands in the command buffer. If the size grows in the // Keep track of the size of commands in the command buffer. If the size grows in the
// future, that implies that drawing occured since invalidated. // future, that implies that drawing occured since invalidated.
mStencilCmdSizeInvalidated = mCommandBuffer.getCommandSize(); mStencilCmdSizeInvalidated = mCommandBuffer.getCommandSize();
// Also track the size if the attachment is currently disabled. // Also track the size if the attachment is currently disabled.
const bool isStencilWriteEnabled =
dsState.stencilTest && (!dsState.isStencilNoOp() || !dsState.isStencilBackNoOp());
mStencilCmdSizeDisabled = mStencilCmdSizeDisabled =
dsState.stencilTest ? kInfiniteCmdSize : mStencilCmdSizeInvalidated; isStencilWriteEnabled ? kInfiniteCmdSize : mStencilCmdSizeInvalidated;
} }
bool hasWriteAfterInvalidate(uint32_t cmdCountInvalidated, uint32_t cmdCountDisabled) bool hasWriteAfterInvalidate(uint32_t cmdCountInvalidated, uint32_t cmdCountDisabled)
...@@ -1103,8 +1112,8 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1103,8 +1112,8 @@ class CommandBufferHelper : angle::NonCopyable
// Dumping the command stream is disabled by default. // Dumping the command stream is disabled by default.
static constexpr bool kEnableCommandStreamDiagnostics = false; static constexpr bool kEnableCommandStreamDiagnostics = false;
bool onDepthAccess(ResourceAccess access); void onDepthAccess(ResourceAccess access);
bool onStencilAccess(ResourceAccess access); void onStencilAccess(ResourceAccess access);
void updateRenderPassForResolve(vk::Framebuffer *newFramebuffer, void updateRenderPassForResolve(vk::Framebuffer *newFramebuffer,
const vk::RenderPassDesc &renderPassDesc); const vk::RenderPassDesc &renderPassDesc);
...@@ -1125,6 +1134,8 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1125,6 +1134,8 @@ class CommandBufferHelper : angle::NonCopyable
bool onDepthStencilAccess(ResourceAccess access, bool onDepthStencilAccess(ResourceAccess access,
uint32_t *cmdCountInvalidated, uint32_t *cmdCountInvalidated,
uint32_t *cmdCountDisabled); uint32_t *cmdCountDisabled);
void restoreDepthContent();
void restoreStencilContent();
void finalizeDepthStencilImageLayout(); void finalizeDepthStencilImageLayout();
void finalizeDepthStencilResolveImageLayout(); void finalizeDepthStencilResolveImageLayout();
...@@ -1181,6 +1192,8 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1181,6 +1192,8 @@ class CommandBufferHelper : angle::NonCopyable
ImageHelper *mDepthStencilImage; ImageHelper *mDepthStencilImage;
ImageHelper *mDepthStencilResolveImage; ImageHelper *mDepthStencilResolveImage;
gl::LevelIndex mDepthStencilLevelIndex;
uint32_t mDepthStencilLayerIndex;
}; };
// Imagine an image going through a few layout transitions: // Imagine an image going through a few layout transitions:
...@@ -1630,10 +1643,29 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1630,10 +1643,29 @@ class ImageHelper final : public Resource, public angle::Subject
GLuint *inputDepthPitch, GLuint *inputDepthPitch,
GLuint *inputSkipBytes); 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; } bool hasImmutableSampler() { return mExternalFormat != 0; }
uint64_t getExternalFormat() const { return mExternalFormat; } 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: private:
enum class UpdateSource enum class UpdateSource
{ {
...@@ -1737,6 +1769,32 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1737,6 +1769,32 @@ class ImageHelper final : public Resource, public angle::Subject
void appendSubresourceUpdate(SubresourceUpdate &&update); void appendSubresourceUpdate(SubresourceUpdate &&update);
void prependSubresourceUpdate(SubresourceUpdate &&update); void prependSubresourceUpdate(SubresourceUpdate &&update);
void resetCachedProperties(); void resetCachedProperties();
void setEntireContentDefined();
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( angle::Result initLayerImageViewImpl(
Context *context, Context *context,
...@@ -1789,6 +1847,11 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1789,6 +1847,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 // 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. // the exact same clear value, we will detect and skip the clear call.
Optional<ClearUpdate> mCurrentSingleClearValue; 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. // A vector of image views, such as one per level or one per layer.
......
...@@ -576,7 +576,10 @@ class CopyTextureTestWebGL : public CopyTextureTest ...@@ -576,7 +576,10 @@ class CopyTextureTestWebGL : public CopyTextureTest
}; };
class CopyTextureTestES3 : 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 // Test that CopyTexture cannot redefine an immutable texture and CopySubTexture can copy data to
// immutable textures // immutable textures
...@@ -2368,6 +2371,148 @@ TEST_P(CopyTextureTestES3, SwizzleOnSource) ...@@ -2368,6 +2371,148 @@ TEST_P(CopyTextureTestES3, SwizzleOnSource)
EXPECT_PIXEL_COLOR_EQ(0, 0, kSourceColor); 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 #ifdef Bool
// X11 craziness. // X11 craziness.
# undef Bool # 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