Commit d201ed8b by Jamie Madill Committed by Commit Bot

Vulkan: Track used Images in RenderPass.

Adding a simple ImageSerial tracking map in our RenderPass allows us to know when we do or do not need to close the RenderPass on a new Image access. This simple tracking scheme improves Manhattan performance by up to 25% on Android. The improved perf comes from reducing our RenderPass count (23->18 RenderPasses in our capture scene). Adds a FastUnorderedSet class to manage the used RP Image serials. Updates the Query helpers to explicitly flush the RP before inserting queries. Bug: angleproject:4911 Change-Id: I0c34fc8e307514ebdf3e81e08d8e5aedb70ebe8f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2334346Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 3e57e349
......@@ -474,6 +474,36 @@ class FastUnorderedMap final
FastVector<Pair, N> mData;
};
template <class T, size_t N>
class FastUnorderedSet final
{
public:
FastUnorderedSet() {}
~FastUnorderedSet() {}
bool empty() const { return mData.empty(); }
void insert(T value)
{
ASSERT(!contains(value));
mData.push_back(value);
}
bool contains(T needle) const
{
for (T value : mData)
{
if (value == needle)
return true;
}
return false;
}
void clear() { mData.clear(); }
private:
FastVector<T, N> mData;
};
} // namespace angle
#endif // COMMON_FASTVECTOR_H_
......@@ -264,4 +264,29 @@ TEST(FastUnorderedMap, BasicUsage)
EXPECT_FALSE(value);
}
}
// Basic functionality for FastUnorderedSet
TEST(FastUnorderedSet, BasicUsage)
{
FastUnorderedSet<int, 3> testMap;
EXPECT_TRUE(testMap.empty());
testMap.insert(5);
EXPECT_TRUE(testMap.contains(5));
EXPECT_FALSE(testMap.contains(6));
EXPECT_FALSE(testMap.empty());
testMap.clear();
EXPECT_TRUE(testMap.empty());
for (int i = 0; i < 10; ++i)
{
testMap.insert(i);
}
for (int i = 0; i < 10; ++i)
{
EXPECT_TRUE(testMap.contains(i));
}
}
} // namespace angle
......@@ -533,20 +533,17 @@ class ContextVk : public ContextImpl, public vk::Context
vk::ImageHelper *image)
{
ASSERT(mRenderPassCommands->started());
mRenderPassCommands->imageWrite(&mResourceUseList, aspectFlags, imageLayout, image);
mRenderPassCommands->imageWrite(&mResourceUseList, aspectFlags, imageLayout,
vk::AliasingMode::Allowed, image);
}
angle::Result getOutsideRenderPassCommandBuffer(vk::CommandBuffer **commandBufferOut)
{
// Only one command buffer should be active at a time
// TODO(jmadill): Do not end RenderPass. http://anglebug.com/4911
ASSERT(mOutsideRenderPassCommands->empty() || mRenderPassCommands->empty());
ANGLE_TRY(endRenderPass());
*commandBufferOut = &mOutsideRenderPassCommands->getCommandBuffer();
return angle::Result::Continue;
}
angle::Result flushAndBeginRenderPass(const vk::Framebuffer &framebuffer,
angle::Result beginNewRenderPass(const vk::Framebuffer &framebuffer,
const gl::Rectangle &renderArea,
const vk::RenderPassDesc &renderPassDesc,
const vk::AttachmentOpsArray &renderPassAttachmentOps,
......@@ -580,7 +577,7 @@ class ContextVk : public ContextImpl, public vk::Context
egl::ContextPriority getContextPriority() const override { return mContextPriority; }
angle::Result startRenderPass(gl::Rectangle renderArea, vk::CommandBuffer **commandBufferOut);
angle::Result endRenderPass();
angle::Result flushCommandsAndEndRenderPass();
angle::Result syncExternalMemory();
......@@ -910,6 +907,8 @@ class ContextVk : public ContextImpl, public vk::Context
// Pull an available CBH ptr from the CBH queue and set to specified hasRenderPass state
void getNextAvailableCommandBuffer(vk::CommandBufferHelper **commandBuffer, bool hasRenderPass);
angle::Result endRenderPassIfImageUsed(const vk::ImageHelper &image);
angle::Result endRenderPassIfTransformFeedbackBuffer(const vk::BufferHelper *buffer);
void populateTransformFeedbackBufferSet(
......@@ -1125,7 +1124,7 @@ ANGLE_INLINE angle::Result ContextVk::endRenderPassIfTransformFeedbackBuffer(
return angle::Result::Continue;
}
return endRenderPass();
return flushCommandsAndEndRenderPass();
}
ANGLE_INLINE angle::Result ContextVk::onIndexBufferChange(
......
......@@ -464,35 +464,25 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
vk::Framebuffer *currentFramebuffer = nullptr;
ANGLE_TRY(getFramebuffer(contextVk, &currentFramebuffer));
gl::DrawBufferMask clearColorDrawBuffersMask;
if (clearColorWithRenderPassLoadOp)
{
clearColorDrawBuffersMask = clearColorBuffers;
}
// If we are in an active renderpass that has recorded commands and the framebuffer hasn't
// changed, inline the clear
if (contextVk->hasStartedRenderPassWithCommands() &&
contextVk->hasStartedRenderPassWithFramebuffer(currentFramebuffer))
{
// Have active renderpass, add inline clear
gl::DrawBufferMask clearBuffersWithInlineClear;
if (clearColorWithRenderPassLoadOp)
{
clearBuffersWithInlineClear = clearColorBuffers;
}
clearWithClearAttachment(
&contextVk->getStartedRenderPassCommands().getCommandBuffer(), scissoredRenderArea,
clearBuffersWithInlineClear, clearDepthWithRenderPassLoadOp,
clearStencilWithRenderPassLoadOp, clearColorValue, clearDepthStencilValue);
clearWithCommand(&contextVk->getStartedRenderPassCommands().getCommandBuffer(),
scissoredRenderArea, clearColorDrawBuffersMask,
clearDepthWithRenderPassLoadOp, clearStencilWithRenderPassLoadOp,
clearColorValue, clearDepthStencilValue);
}
else
{
// Clearing color is indicated by the set bits in this mask. If not clearing colors
// with render pass loadOp, the default value of all-zeros means the clear is not done
// in clearWithRenderPassOp below. In that case, only clear depth/stencil with render
// pass loadOp.
gl::DrawBufferMask clearBuffersWithRenderPassLoadOp;
if (clearColorWithRenderPassLoadOp)
{
clearBuffersWithRenderPassLoadOp = clearColorBuffers;
}
clearWithRenderPassOp(clearBuffersWithRenderPassLoadOp, clearDepthWithRenderPassLoadOp,
clearWithLoadOp(contextVk, clearColorDrawBuffersMask, clearDepthWithRenderPassLoadOp,
clearStencilWithRenderPassLoadOp, clearColorValue,
clearDepthStencilValue);
}
......@@ -1406,7 +1396,7 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
// tests this pattern, this optimization may not be necessary if no application does this.
// It is expected that an application would invalidate() when it's done with the
// framebuffer, so the render pass would have closed either way.
ANGLE_TRY(contextVk->endRenderPass());
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
}
// If not a partial invalidate, mark the contents of the invalidated attachments as undefined,
......@@ -1656,7 +1646,7 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
mActiveColorComponentMasksForClear[0].any(), mActiveColorComponentMasksForClear[1].any(),
mActiveColorComponentMasksForClear[2].any(), mActiveColorComponentMasksForClear[3].any());
ANGLE_TRY(contextVk->endRenderPass());
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
// Notify the ContextVk to update the pipeline desc.
updateRenderPassDesc();
......@@ -1952,23 +1942,13 @@ VkClearValue FramebufferVk::getCorrectedColorClearValue(size_t colorIndexGL,
return clearValue;
}
void FramebufferVk::clearWithRenderPassOp(gl::DrawBufferMask clearColorBuffers,
void FramebufferVk::clearWithLoadOp(ContextVk *contextVk,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue)
{
// Go through clearColorBuffers and set the appropriate loadOp and clear values.
for (size_t colorIndexGL : clearColorBuffers)
{
ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL);
VkClearValue clearValue = getCorrectedColorClearValue(colorIndexGL, clearColorValue);
gl::ImageIndex imageIndex = renderTarget->getImageIndex();
renderTarget->getImageForWrite().stageClear(imageIndex, VK_IMAGE_ASPECT_COLOR_BIT,
clearValue);
}
// Set the appropriate loadOp and clear values for depth and stencil.
VkImageAspectFlags dsAspectFlags = 0;
if (clearDepth)
......@@ -1981,6 +1961,45 @@ void FramebufferVk::clearWithRenderPassOp(gl::DrawBufferMask clearColorBuffers,
dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
if (contextVk->hasStartedRenderPass())
{
vk::CommandBufferHelper &commands = contextVk->getStartedRenderPassCommands();
ASSERT(commands.getCommandBuffer().empty());
// The clear colors are packed with no gaps. The draw buffers mask is unpacked
// and can have gaps. Thus we need to count the packed index explicitly in this loop.
size_t colorCount = 0;
for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
{
if (clearColorBuffers[colorIndexGL])
{
VkClearValue clearValue =
getCorrectedColorClearValue(colorIndexGL, clearColorValue);
commands.updateRenderPassColorClear(colorCount, clearValue);
}
colorCount++;
}
if (dsAspectFlags)
{
VkClearValue clearValue;
clearValue.depthStencil = clearDepthStencilValue;
commands.updateRenderPassDepthStencilClear(dsAspectFlags, clearValue);
}
}
else
{
for (size_t colorIndexGL : clearColorBuffers)
{
ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL);
VkClearValue clearValue = getCorrectedColorClearValue(colorIndexGL, clearColorValue);
gl::ImageIndex imageIndex = renderTarget->getImageIndex();
renderTarget->getImageForWrite().stageClear(imageIndex, VK_IMAGE_ASPECT_COLOR_BIT,
clearValue);
}
if (dsAspectFlags)
{
RenderTargetVk *renderTarget = getDepthStencilRenderTarget();
......@@ -1992,9 +2011,10 @@ void FramebufferVk::clearWithRenderPassOp(gl::DrawBufferMask clearColorBuffers,
gl::ImageIndex imageIndex = renderTarget->getImageIndex();
renderTarget->getImageForWrite().stageClear(imageIndex, dsAspectFlags, clearValue);
}
}
}
void FramebufferVk::clearWithClearAttachment(vk::CommandBuffer *renderPassCommandBuffer,
void FramebufferVk::clearWithCommand(vk::CommandBuffer *renderPassCommandBuffer,
const gl::Rectangle &scissoredRenderArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
......@@ -2056,7 +2076,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
vk::Framebuffer *framebuffer = nullptr;
ANGLE_TRY(getFramebuffer(contextVk, &framebuffer));
ANGLE_TRY(contextVk->endRenderPass());
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
// Initialize RenderPass info.
vk::AttachmentOpsArray renderPassAttachmentOps;
......@@ -2202,9 +2222,9 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
stencilStoreOp);
}
ANGLE_TRY(contextVk->flushAndBeginRenderPass(
*framebuffer, renderArea, mRenderPassDesc, renderPassAttachmentOps,
depthStencilAttachmentIndex, packedClearValues, commandBufferOut));
ANGLE_TRY(contextVk->beginNewRenderPass(*framebuffer, renderArea, mRenderPassDesc,
renderPassAttachmentOps, depthStencilAttachmentIndex,
packedClearValues, commandBufferOut));
// Transition the images to the correct layout (through onColorDraw) after the
// resolve-to-multisampled copies are done.
......
......@@ -185,12 +185,13 @@ class FramebufferVk : public FramebufferImpl
uint8_t stencilMask,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
void clearWithRenderPassOp(gl::DrawBufferMask clearColorBuffers,
void clearWithLoadOp(ContextVk *contextVk,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
bool clearStencil,
const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue);
void clearWithClearAttachment(vk::CommandBuffer *renderPassCommandBuffer,
void clearWithCommand(vk::CommandBuffer *renderPassCommandBuffer,
const gl::Rectangle &scissoredRenderArea,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth,
......
......@@ -986,7 +986,7 @@ void ProgramExecutableVk::updateBuffersDescriptorSet(ContextVk *contextVk,
VkAccessFlags accessFlags = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
commandBufferHelper->bufferWrite(resourceUseList, accessFlags,
kPipelineStageShaderMap[shaderType],
vk::BufferAliasingMode::Allowed, &bufferHelper);
vk::AliasingMode::Allowed, &bufferHelper);
}
else
{
......@@ -1056,7 +1056,7 @@ void ProgramExecutableVk::updateAtomicCounterBuffersDescriptorSet(
// We set SHADER_READ_BIT to be conservative.
commandBufferHelper->bufferWrite(
resourceUseList, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
kPipelineStageShaderMap[shaderType], vk::BufferAliasingMode::Allowed, &bufferHelper);
kPipelineStageShaderMap[shaderType], vk::AliasingMode::Allowed, &bufferHelper);
writtenBindings.set(binding);
}
......
......@@ -1126,9 +1126,9 @@ angle::Result UtilsVk::startRenderPass(ContextVk *contextVk,
renderPassAttachmentOps.initWithLoadStore(0, vk::ImageLayout::ColorAttachment,
vk::ImageLayout::ColorAttachment);
ANGLE_TRY(contextVk->flushAndBeginRenderPass(
framebuffer, renderArea, renderPassDesc, renderPassAttachmentOps,
vk::kInvalidAttachmentIndex, clearValues, commandBufferOut));
ANGLE_TRY(contextVk->beginNewRenderPass(framebuffer, renderArea, renderPassDesc,
renderPassAttachmentOps, vk::kInvalidAttachmentIndex,
clearValues, commandBufferOut));
contextVk->addGarbage(&framebuffer);
......@@ -1853,7 +1853,7 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk,
descriptorPoolBinding.reset();
// Close the render pass for this temporary framebuffer.
ANGLE_TRY(contextVk->endRenderPass());
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
return angle::Result::Continue;
}
......
......@@ -1549,6 +1549,18 @@ void AttachmentOpsArray::setStencilOps(size_t index,
SetBitField(ops.stencilStoreOp, storeOp);
}
void AttachmentOpsArray::setClearOp(size_t index)
{
PackedAttachmentOpsDesc &ops = mOps[index];
SetBitField(ops.loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
}
void AttachmentOpsArray::setClearStencilOp(size_t index)
{
PackedAttachmentOpsDesc &ops = mOps[index];
SetBitField(ops.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
}
size_t AttachmentOpsArray::hash() const
{
return angle::ComputeGenericHash(mOps);
......
......@@ -182,6 +182,9 @@ class AttachmentOpsArray final
void setOps(size_t index, VkAttachmentLoadOp loadOp, VkAttachmentStoreOp storeOp);
void setStencilOps(size_t index, VkAttachmentLoadOp loadOp, VkAttachmentStoreOp storeOp);
void setClearOp(size_t index);
void setClearStencilOp(size_t index);
size_t hash() const;
private:
......@@ -786,19 +789,28 @@ class PipelineHelper final : angle::NonCopyable
ANGLE_INLINE PipelineHelper::PipelineHelper(Pipeline &&pipeline) : mPipeline(std::move(pipeline)) {}
struct ImageViewSubresourceSerial
struct ImageSubresourceRange
{
ImageViewSerial imageViewSerial;
uint16_t level : 10; // GL max is 1000 (fits in 10 bits).
uint16_t levelCount : 6; // Max 63 levels (2 ** 6 - 1). If we need more, take from layer.
uint16_t layer : 15; // Implementation max is 2048 (11 bits).
uint16_t singleLayer : 1; // true/false only. Not possible to use sub-slices of levels.
};
static_assert(sizeof(ImageSubresourceRange) == sizeof(uint32_t), "Size mismatch");
constexpr ImageSubresourceRange kInvalidImageSubresourceRange = {0, 0, 0, 0};
struct ImageViewSubresourceSerial
{
ImageViewSerial imageViewSerial;
ImageSubresourceRange subresource;
};
static_assert(sizeof(ImageViewSubresourceSerial) == sizeof(uint64_t), "Size mismatch");
constexpr ImageViewSubresourceSerial kInvalidImageViewSubresourceSerial = {kInvalidImageViewSerial,
0, 0, 0, 0};
constexpr ImageViewSubresourceSerial kInvalidImageViewSubresourceSerial = {
kInvalidImageViewSerial, kInvalidImageSubresourceRange};
class TextureDescriptorDesc
{
......
......@@ -604,7 +604,7 @@ void CommandBufferHelper::bufferRead(ResourceUseList *resourceUseList,
void CommandBufferHelper::bufferWrite(ResourceUseList *resourceUseList,
VkAccessFlags writeAccessType,
PipelineStage writeStage,
BufferAliasingMode aliasingMode,
AliasingMode aliasingMode,
BufferHelper *buffer)
{
buffer->retain(resourceUseList);
......@@ -618,7 +618,7 @@ void CommandBufferHelper::bufferWrite(ResourceUseList *resourceUseList,
// We support aliasing by not tracking storage buffers. This works well with the GL API
// because storage buffers are required to be externally synchronized.
// Compute / XFB emulation buffers are not allowed to alias.
if (aliasingMode == BufferAliasingMode::Disallowed)
if (aliasingMode == AliasingMode::Disallowed)
{
ASSERT(!usesBuffer(*buffer));
mUsedBuffers.insert(buffer->getBufferSerial(), BufferAccess::Write);
......@@ -641,11 +641,22 @@ void CommandBufferHelper::imageRead(ResourceUseList *resourceUseList,
mPipelineBarrierMask.set(barrierIndex);
}
}
if (mIsRenderPassCommandBuffer)
{
// As noted in the header we don't support multiple layouts reads for Images.
// We allow duplicate uses in the RP to accomodate for normal GL sampler usage.
if (!usesImageInRenderPass(*image))
{
mRenderPassUsedImages.insert(image->getImageSerial());
}
}
}
void CommandBufferHelper::imageWrite(ResourceUseList *resourceUseList,
VkImageAspectFlags aspectFlags,
ImageLayout imageLayout,
AliasingMode aliasingMode,
ImageHelper *image)
{
image->retain(resourceUseList);
......@@ -658,6 +669,19 @@ void CommandBufferHelper::imageWrite(ResourceUseList *resourceUseList,
{
mPipelineBarrierMask.set(barrierIndex);
}
if (mIsRenderPassCommandBuffer)
{
// When used as a storage buffer we allow for aliased writes.
if (aliasingMode == AliasingMode::Disallowed)
{
ASSERT(!usesImageInRenderPass(*image));
}
if (!usesImageInRenderPass(*image))
{
mRenderPassUsedImages.insert(image->getImageSerial());
}
}
}
void CommandBufferHelper::executeBarriers(PrimaryCommandBuffer *primary)
......@@ -928,11 +952,13 @@ void CommandBufferHelper::reset()
mDepthTestEverEnabled = false;
mStencilTestEverEnabled = false;
mDepthStencilAttachmentIndex = kInvalidAttachmentIndex;
mRenderPassUsedImages.clear();
}
// This state should never change for non-renderPass command buffer
ASSERT(mRenderPassStarted == false);
ASSERT(mValidTransformFeedbackBufferCount == 0);
ASSERT(mRebindTransformFeedbackBuffers == false);
ASSERT(mRenderPassUsedImages.empty());
}
void CommandBufferHelper::releaseToContextQueue(ContextVk *contextVk)
......@@ -969,6 +995,35 @@ void CommandBufferHelper::pauseTransformFeedbackIfStarted()
mTransformFeedbackCounterBuffers.data());
}
void CommandBufferHelper::updateRenderPassColorClear(size_t colorIndex,
const VkClearValue &clearValue)
{
mAttachmentOps.setClearOp(colorIndex);
mClearValues.store(static_cast<uint32_t>(colorIndex), VK_IMAGE_ASPECT_COLOR_BIT, clearValue);
}
void CommandBufferHelper::updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue)
{
// Don't overwrite prior clear values for individual aspects.
VkClearValue combinedClearValue = mClearValues[mDepthStencilAttachmentIndex];
if ((aspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
{
mAttachmentOps.setClearOp(mDepthStencilAttachmentIndex);
combinedClearValue.depthStencil.depth = clearValue.depthStencil.depth;
}
if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
{
mAttachmentOps.setClearStencilOp(mDepthStencilAttachmentIndex);
combinedClearValue.depthStencil.stencil = clearValue.depthStencil.stencil;
}
// Bypass special D/S handling. This clear values array stores values packed.
mClearValues.storeNoDepthStencil(mDepthStencilAttachmentIndex, combinedClearValue);
}
// DynamicBuffer implementation.
DynamicBuffer::DynamicBuffer()
: mUsage(0),
......@@ -1766,6 +1821,11 @@ void QueryHelper::resetQueryPool(ContextVk *contextVk,
angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
{
if (contextVk->hasStartedRenderPass())
{
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
}
CommandBuffer *outsideRenderPassCommandBuffer;
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&outsideRenderPassCommandBuffer));
const QueryPool &queryPool = getQueryPool();
......@@ -1777,6 +1837,11 @@ angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
angle::Result QueryHelper::endQuery(ContextVk *contextVk)
{
if (contextVk->hasStartedRenderPass())
{
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
}
CommandBuffer *outsideRenderPassCommandBuffer;
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&outsideRenderPassCommandBuffer));
outsideRenderPassCommandBuffer->endQuery(getQueryPool().getHandle(), mQuery);
......@@ -1800,14 +1865,21 @@ void QueryHelper::endOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderP
angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk)
{
if (contextVk->hasStartedRenderPass())
{
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
}
CommandBuffer *outsideRenderPassCommandBuffer;
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&outsideRenderPassCommandBuffer));
writeTimestamp(contextVk, outsideRenderPassCommandBuffer);
return angle::Result::Continue;
}
void QueryHelper::writeTimestamp(ContextVk *contextVk, PrimaryCommandBuffer *primary)
void QueryHelper::writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBuffer *primary)
{
// Note that commands may not be flushed at this point.
const QueryPool &queryPool = getQueryPool();
primary->resetQueryPool(queryPool, mQuery, 1);
primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
......@@ -4550,11 +4622,6 @@ angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
ANGLE_TRY(allocateStagingMemory(contextVk, *bufferSize, outDataPtr, bufferOut, bufferOffsetsOut,
nullptr));
CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(contextVk->onImageTransferRead(aspectFlags, this));
ANGLE_TRY(contextVk->onBufferTransferWrite(*bufferOut));
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&commandBuffer));
uint32_t sourceLevelVk = static_cast<uint32_t>(sourceLevelGL) - mBaseLevel;
VkBufferImageCopy regions[2] = {};
......@@ -4603,10 +4670,14 @@ angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
regions[1].imageSubresource.baseArrayLayer = baseLayer;
regions[1].imageSubresource.layerCount = layerCount;
regions[1].imageSubresource.mipLevel = sourceLevelVk;
commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(),
(*bufferOut)->getBuffer().getHandle(), 1, &regions[1]);
}
CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(contextVk->onBufferTransferWrite(*bufferOut));
ANGLE_TRY(contextVk->onImageTransferRead(aspectFlags, this));
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&commandBuffer));
commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(),
(*bufferOut)->getBuffer().getHandle(), 1, regions);
......@@ -5365,10 +5436,10 @@ ImageViewSubresourceSerial ImageViewHelper::getSubresourceSerial(uint32_t levelG
ImageViewSubresourceSerial serial;
serial.imageViewSerial = mImageViewSerial;
SetBitField(serial.level, levelGL);
SetBitField(serial.levelCount, levelCount);
SetBitField(serial.layer, layer);
SetBitField(serial.singleLayer, layerMode == LayerMode::Single ? 1 : 0);
SetBitField(serial.subresource.level, levelGL);
SetBitField(serial.subresource.levelCount, levelCount);
SetBitField(serial.subresource.layer, layer);
SetBitField(serial.subresource.singleLayer, layerMode == LayerMode::Single ? 1 : 0);
return serial;
}
......
......@@ -422,7 +422,7 @@ class QueryHelper final
angle::Result flushAndWriteTimestamp(ContextVk *contextVk);
// When syncing gpu/cpu time, main thread accesses primary directly
void writeTimestamp(ContextVk *contextVk, PrimaryCommandBuffer *primary);
void writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBuffer *primary);
// All other timestamp accesses should be made on outsideRenderPassCommandBuffer
void writeTimestamp(ContextVk *contextVk, CommandBuffer *outsideRenderPassCommandBuffer);
......@@ -837,7 +837,7 @@ enum class BufferAccess
Write,
};
enum class BufferAliasingMode
enum class AliasingMode
{
Allowed,
Disallowed,
......@@ -851,7 +851,7 @@ enum class BufferAliasingMode
// into the CBH and then pass the CBH off to a worker thread that will
// process the commands into a primary command buffer and then submit
// those commands to the queue.
struct CommandBufferHelper : angle::NonCopyable
class CommandBufferHelper : angle::NonCopyable
{
public:
CommandBufferHelper();
......@@ -867,17 +867,17 @@ struct CommandBufferHelper : angle::NonCopyable
void bufferWrite(ResourceUseList *resourceUseList,
VkAccessFlags writeAccessType,
PipelineStage writeStage,
BufferAliasingMode aliasingMode,
AliasingMode aliasingMode,
BufferHelper *buffer);
void imageRead(ResourceUseList *resourceUseList,
VkImageAspectFlags aspectFlags,
ImageLayout imageLayout,
ImageHelper *image);
void imageWrite(ResourceUseList *resourceUseList,
VkImageAspectFlags aspectFlags,
ImageLayout imageLayout,
AliasingMode aliasingMode,
ImageHelper *image);
CommandBuffer &getCommandBuffer() { return mCommandBuffer; }
......@@ -946,6 +946,10 @@ struct CommandBufferHelper : angle::NonCopyable
SetBitField(mAttachmentOps[attachmentIndex].finalLayout, finalLayout);
}
void updateRenderPassColorClear(size_t colorIndex, const VkClearValue &colorClearValue);
void updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue);
const gl::Rectangle &getRenderArea() const
{
ASSERT(mIsRenderPassCommandBuffer);
......@@ -971,6 +975,7 @@ struct CommandBufferHelper : angle::NonCopyable
bool usesBuffer(const BufferHelper &buffer) const;
bool usesBufferForWrite(const BufferHelper &buffer) const;
bool usesImageInRenderPass(const ImageHelper &image) const;
// Dumping the command stream is disabled by default.
static constexpr bool kEnableCommandStreamDiagnostics = false;
......@@ -1011,8 +1016,11 @@ struct CommandBufferHelper : angle::NonCopyable
uint32_t mDepthStencilAttachmentIndex;
// Tracks resources used in the command buffer.
static constexpr uint32_t kFastMapSize = 8;
// For Buffers, we track the read/write access type so we can enable simuntaneous reads.
// Images have unique layouts unlike buffers therefore we don't support multi-read.
static constexpr uint32_t kFastMapSize = 16;
angle::FastUnorderedMap<BufferSerial, BufferAccess, kFastMapSize> mUsedBuffers;
angle::FastUnorderedSet<ImageSerial, kFastMapSize> mRenderPassUsedImages;
};
static constexpr uint32_t kInvalidAttachmentIndex = -1;
......@@ -1963,6 +1971,12 @@ class ActiveHandleCounter final : angle::NonCopyable
angle::PackedEnumMap<HandleType, uint32_t> mActiveCounts;
angle::PackedEnumMap<HandleType, uint32_t> mAllocatedCounts;
};
ANGLE_INLINE bool CommandBufferHelper::usesImageInRenderPass(const ImageHelper &image) const
{
ASSERT(mIsRenderPassCommandBuffer);
return mRenderPassUsedImages.contains(image.getImageSerial());
}
} // namespace vk
} // namespace rx
......
......@@ -741,15 +741,20 @@ void ClearValuesArray::store(uint32_t index,
// Ensure for packed DS we're writing to the depth index.
ASSERT(index == kClearValueDepthIndex ||
(index == kClearValueStencilIndex && aspectFlags == VK_IMAGE_ASPECT_STENCIL_BIT));
mValues[kClearValueStencilIndex] = clearValue;
mEnabled.set(kClearValueStencilIndex);
storeNoDepthStencil(kClearValueStencilIndex, clearValue);
}
if (aspectFlags != VK_IMAGE_ASPECT_STENCIL_BIT)
{
storeNoDepthStencil(index, clearValue);
}
}
void ClearValuesArray::storeNoDepthStencil(uint32_t index, const VkClearValue &clearValue)
{
mValues[index] = clearValue;
mEnabled.set(index);
}
}
// ResourceSerialFactory implementation.
......
......@@ -659,6 +659,7 @@ class ClearValuesArray final
ClearValuesArray &operator=(const ClearValuesArray &rhs);
void store(uint32_t index, VkImageAspectFlags aspectFlags, const VkClearValue &clearValue);
void storeNoDepthStencil(uint32_t index, const VkClearValue &clearValue);
void reset(size_t index)
{
......
......@@ -1382,7 +1382,7 @@ TEST_P(VertexAttributeTest, DisabledAttribArrays)
drawQuad(program, "a_position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green) << "color index " << colorIndex;
glDeleteProgram(program);
}
......
......@@ -39,9 +39,6 @@ class VulkanPerformanceCounterTest : public ANGLETest
// Tests that texture updates to unused textures don't break the RP.
TEST_P(VulkanPerformanceCounterTest, NewTextureDoesNotBreakRenderPass)
{
// TODO(jmadill): Fix test. http://anglebug.com/4911
ANGLE_SKIP_TEST_IF(IsVulkan());
const rx::vk::PerfCounters &counters = hackANGLE();
GLColor kInitialData[4] = {GLColor::red, GLColor::blue, GLColor::green, GLColor::yellow};
......
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