Commit cf2ec3b1 by Tobin Ehlis Committed by Commit Bot

Vulkan:Add FramebufferVk cache

This adds a FramebufferVk cache. Cache signature is based on unique Serial values that are assigned to ImageHelper objects backing all color and DS rendertargets as well as level/layer values unique to the imageView. Update the Serials and cache signature at FramebufferVk::syncState() time. L0 cache is a currently active framebuffer. L1 cache retrieves previously created framebuffer from new cache. If neither of those hit, create new FramebufferVk and add to L1. Bug: angleproject:4322 Change-Id: I3f585271798ddfb9e5f194020adca8cf8a6b19dd Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2033869 Commit-Queue: Tobin Ehlis <tobine@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com>
parent 709f6285
......@@ -75,6 +75,9 @@ class Serial final
static constexpr uint64_t kInvalid = 0;
};
// Used as default/initial serial
static constexpr Serial kZeroSerial = Serial();
template <typename SerialBaseType>
class SerialFactoryBase final : angle::NonCopyable
{
......
......@@ -110,9 +110,6 @@ constexpr size_t kInFlightCommandsLimit = 100u;
// Initially dumping the command graphs is disabled.
constexpr bool kEnableCommandGraphDiagnostics = false;
// Used as fallback serial for null sampler objects
constexpr Serial kZeroSerial = Serial();
void InitializeSubmitInfo(VkSubmitInfo *submitInfo,
const vk::PrimaryCommandBuffer &commandBuffer,
const std::vector<VkSemaphore> &waitSemaphores,
......@@ -3556,7 +3553,7 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
if (sampler == nullptr)
{
samplerVk = nullptr;
samplerSerial = kZeroSerial;
samplerSerial = rx::kZeroSerial;
}
else
{
......
......@@ -570,6 +570,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
// avoid calling vkAllocateDesctiporSets each texture update.
Serial generateTextureSerial() { return mTextureSerialFactory.generate(); }
const vk::TextureDescriptorDesc &getActiveTexturesDesc() const { return mActiveTexturesDesc; }
Serial generateAttachmentImageSerial() { return mAttachmentImageSerialFactory.generate(); }
angle::Result updateScissor(const gl::State &glState);
......@@ -1023,8 +1024,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
// double.
uint64_t mGpuEventTimestampOrigin;
// Generator for texure serials.
// Generators for texture & framebuffer serials.
SerialFactory mTextureSerialFactory;
SerialFactory mAttachmentImageSerialFactory;
gl::State::DirtyBits mPipelineDirtyBitsMask;
......
......@@ -134,7 +134,10 @@ FramebufferVk *FramebufferVk::CreateDefaultFBO(RendererVk *renderer,
FramebufferVk::FramebufferVk(RendererVk *renderer,
const gl::FramebufferState &state,
WindowSurfaceVk *backbuffer)
: FramebufferImpl(state), mBackbuffer(backbuffer), mActiveColorComponents(0)
: FramebufferImpl(state),
mBackbuffer(backbuffer),
mFramebuffer(nullptr),
mActiveColorComponents(0)
{
mReadPixelBuffer.init(renderer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, kReadPixelsBufferAlignment,
kMinReadPixelsBufferSize, true);
......@@ -142,12 +145,22 @@ FramebufferVk::FramebufferVk(RendererVk *renderer,
FramebufferVk::~FramebufferVk() = default;
void FramebufferVk::clearCache(ContextVk *contextVk)
{
for (auto &entry : mFramebufferCache)
{
vk::FramebufferHelper &tmpFB = entry.second;
tmpFB.release(contextVk);
}
mFramebufferCache.clear();
}
void FramebufferVk::destroy(const gl::Context *context)
{
ContextVk *contextVk = vk::GetImpl(context);
mFramebuffer.release(contextVk);
mReadPixelBuffer.release(contextVk->getRenderer());
clearCache(contextVk);
}
angle::Result FramebufferVk::discard(const gl::Context *context,
......@@ -162,13 +175,15 @@ angle::Result FramebufferVk::invalidate(const gl::Context *context,
const GLenum *attachments)
{
ContextVk *contextVk = vk::GetImpl(context);
mFramebuffer.onResourceAccess(&contextVk->getResourceUseList());
if (mFramebuffer.valid())
if (mFramebuffer != nullptr)
{
ASSERT(mFramebuffer->valid());
mFramebuffer->onResourceAccess(&contextVk->getResourceUseList());
if (contextVk->commandGraphEnabled())
{
if (mFramebuffer.hasStartedRenderPass())
if (mFramebuffer->hasStartedRenderPass())
{
ANGLE_TRY(invalidateImpl(contextVk, count, attachments));
}
......@@ -191,16 +206,16 @@ angle::Result FramebufferVk::invalidateSub(const gl::Context *context,
const gl::Rectangle &area)
{
ContextVk *contextVk = vk::GetImpl(context);
mFramebuffer.onResourceAccess(&contextVk->getResourceUseList());
// RenderPass' storeOp cannot be made conditional to a specific region, so we only apply this
// hint if the requested area encompasses the render area.
if (mFramebuffer.valid())
if (mFramebuffer != nullptr)
{
ASSERT(mFramebuffer->valid());
if (contextVk->commandGraphEnabled())
{
if (mFramebuffer.hasStartedRenderPass() &&
area.encloses(mFramebuffer.getRenderPassRenderArea()))
if (mFramebuffer->hasStartedRenderPass() &&
area.encloses(mFramebuffer->getRenderPassRenderArea()))
{
ANGLE_TRY(invalidateImpl(contextVk, count, attachments));
}
......@@ -256,8 +271,6 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
return angle::Result::Continue;
}
mFramebuffer.updateCurrentAccessNodes();
// This function assumes that only enabled attachments are asked to be cleared.
ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers);
......@@ -547,7 +560,7 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
ASSERT(colorBlit != (depthBlit || stencilBlit));
vk::ImageHelper *srcImage = &readRenderTarget->getImage();
vk::ImageHelper *dstImage = drawRenderTarget->getImageForWrite(contextVk, &mFramebuffer);
vk::ImageHelper *dstImage = drawRenderTarget->getImageForWrite(contextVk, mFramebuffer);
VkImageAspectFlags imageAspectMask = srcImage->getAspectFlags();
VkImageAspectFlags blitAspectMask = imageAspectMask;
......@@ -571,9 +584,9 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
ANGLE_TRY(srcImage->recordCommands(contextVk, &srcLayoutChange));
srcImage->changeLayout(imageAspectMask, vk::ImageLayout::TransferSrc, srcLayoutChange);
}
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
ANGLE_TRY(mFramebuffer->recordCommands(contextVk, &commandBuffer));
srcImage->addReadDependency(contextVk, &mFramebuffer);
srcImage->addReadDependency(contextVk, mFramebuffer);
// Requirement of the copyImageToBuffer, the dst image must be in
// VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL layout.
......@@ -915,10 +928,10 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
srcLayoutChange);
}
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
ANGLE_TRY(mFramebuffer->recordCommands(contextVk, &commandBuffer));
// Source's layout change should happen before rendering
srcImage->addReadDependency(contextVk, &mFramebuffer);
srcImage->addReadDependency(contextVk, mFramebuffer);
}
else
{
......@@ -949,7 +962,7 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
if (contextVk->commandGraphEnabled())
{
vk::ImageHelper *drawImage =
drawRenderTarget->getImageForWrite(contextVk, &mFramebuffer);
drawRenderTarget->getImageForWrite(contextVk, mFramebuffer);
drawImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst,
commandBuffer);
}
......@@ -1056,7 +1069,7 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
{
if (contextVk->commandGraphEnabled())
{
mFramebuffer.invalidateRenderPassColorAttachment(attachmentIndexVk);
mFramebuffer->invalidateRenderPassColorAttachment(attachmentIndexVk);
}
else
{
......@@ -1074,7 +1087,7 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
{
if (contextVk->commandGraphEnabled())
{
mFramebuffer.invalidateRenderPassDepthAttachment(attachmentIndexVk);
mFramebuffer->invalidateRenderPassDepthAttachment(attachmentIndexVk);
}
else
{
......@@ -1087,7 +1100,7 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
{
if (contextVk->commandGraphEnabled())
{
mFramebuffer.invalidateRenderPassStencilAttachment(attachmentIndexVk);
mFramebuffer->invalidateRenderPassStencilAttachment(attachmentIndexVk);
}
else
{
......@@ -1112,7 +1125,7 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
// render pass would have closed either way.
if (contextVk->commandGraphEnabled())
{
mFramebuffer.finishCurrentCommands(contextVk);
mFramebuffer->finishCurrentCommands(contextVk);
}
else
{
......@@ -1127,27 +1140,65 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
{
ContextVk *contextVk = vk::GetImpl(context);
// For any updated attachments we'll update their Serials below
ASSERT(dirtyBits.any());
for (size_t dirtyBit : dirtyBits)
{
switch (dirtyBit)
{
case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState));
if (mRenderTargetCache.getDepthStencil() != nullptr)
{
mCurrentFramebufferDesc.update(
vk::kFramebufferDescDepthIndex,
mRenderTargetCache.getDepthStencil()->getAssignSerial(contextVk));
}
else
{
mCurrentFramebufferDesc.update(vk::kFramebufferDescDepthIndex,
vk::kZeroAttachmentSerial);
}
break;
case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState));
if (mRenderTargetCache.getDepthStencil() != nullptr)
{
mCurrentFramebufferDesc.update(
vk::kFramebufferDescStencilIndex,
mRenderTargetCache.getDepthStencil()->getAssignSerial(contextVk));
}
else
{
mCurrentFramebufferDesc.update(vk::kFramebufferDescStencilIndex,
vk::kZeroAttachmentSerial);
}
break;
case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS:
ANGLE_TRY(mRenderTargetCache.getDepthStencil()->flushStagedUpdates(contextVk));
ASSERT(mRenderTargetCache.getDepthStencil() != nullptr);
mCurrentFramebufferDesc.update(
vk::kFramebufferDescDepthIndex,
mRenderTargetCache.getDepthStencil()->getAssignSerial(contextVk));
break;
case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS:
ANGLE_TRY(mRenderTargetCache.getDepthStencil()->flushStagedUpdates(contextVk));
ASSERT(mRenderTargetCache.getDepthStencil() != nullptr);
mCurrentFramebufferDesc.update(
vk::kFramebufferDescStencilIndex,
mRenderTargetCache.getDepthStencil()->getAssignSerial(contextVk));
break;
case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
break;
case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
// Invalidate the cache. If we have performance critical code hitting this path we
// can add related data (such as width/height) to the cache
clearCache(contextVk);
break;
default:
{
......@@ -1157,6 +1208,18 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
size_t colorIndexGL = static_cast<size_t>(
dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
ANGLE_TRY(updateColorAttachment(context, colorIndexGL));
if (mRenderTargetCache.getColors()[colorIndexGL] != nullptr)
{
mCurrentFramebufferDesc.update(
static_cast<uint32_t>(colorIndexGL),
mRenderTargetCache.getColors()[colorIndexGL]->getAssignSerial(
contextVk));
}
else
{
mCurrentFramebufferDesc.update(static_cast<uint32_t>(colorIndexGL),
vk::kZeroAttachmentSerial);
}
}
else
{
......@@ -1166,12 +1229,16 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
ANGLE_TRY(mRenderTargetCache.getColors()[colorIndexGL]->flushStagedUpdates(
contextVk));
ASSERT(mRenderTargetCache.getColors()[colorIndexGL] != nullptr);
mCurrentFramebufferDesc.update(
static_cast<uint32_t>(colorIndexGL),
mRenderTargetCache.getColors()[colorIndexGL]->getAssignSerial(contextVk));
}
}
}
}
// The FBOs new attachment may have changed the renderable area
// The FBO's new attachment may have changed the renderable area
const gl::State &glState = context->getState();
ANGLE_TRY(contextVk->updateScissor(glState));
......@@ -1179,13 +1246,11 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
mActiveColorComponentMasksForClear[0].any(), mActiveColorComponentMasksForClear[1].any(),
mActiveColorComponentMasksForClear[2].any(), mActiveColorComponentMasksForClear[3].any());
mFramebuffer.release(contextVk);
if (contextVk->commandGraphEnabled())
{
// Will freeze the current set of dependencies on this FBO. The next time we render we will
// create a new entry in the command graph.
mFramebuffer.finishCurrentCommands(contextVk);
mFramebuffer->finishCurrentCommands(contextVk);
}
else
{
......@@ -1200,6 +1265,8 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
{
contextVk->onDrawFramebufferChange(this);
}
// Deactivate Framebuffer
mFramebuffer = nullptr;
return angle::Result::Continue;
}
......@@ -1236,13 +1303,19 @@ void FramebufferVk::updateRenderPassDesc()
angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, vk::Framebuffer **framebufferOut)
{
// If we've already created our cached Framebuffer, return it.
if (mFramebuffer.valid())
// First return a presently valid Framebuffer
if (mFramebuffer != nullptr)
{
*framebufferOut = &mFramebuffer.getFramebuffer();
*framebufferOut = &mFramebuffer->getFramebuffer();
return angle::Result::Continue;
}
// No current FB, so now check for previously cached Framebuffer
auto iter = mFramebufferCache.find(mCurrentFramebufferDesc);
if (iter != mFramebufferCache.end())
{
*framebufferOut = &iter->second.getFramebuffer();
return angle::Result::Continue;
}
vk::RenderPass *compatibleRenderPass = nullptr;
ANGLE_TRY(contextVk->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
......@@ -1291,7 +1364,6 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, vk::Framebuffe
attachmentsSize.width = mState.getDefaultWidth();
attachmentsSize.depth = 0;
}
VkFramebufferCreateInfo framebufferInfo = {};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
......@@ -1303,9 +1375,12 @@ angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, vk::Framebuffe
framebufferInfo.height = static_cast<uint32_t>(attachmentsSize.height);
framebufferInfo.layers = 1;
ANGLE_TRY(mFramebuffer.init(contextVk, framebufferInfo));
vk::FramebufferHelper newFramebuffer;
ANGLE_TRY(newFramebuffer.init(contextVk, framebufferInfo));
*framebufferOut = &mFramebuffer.getFramebuffer();
mFramebufferCache[mCurrentFramebufferDesc] = std::move(newFramebuffer);
mFramebuffer = &mFramebufferCache[mCurrentFramebufferDesc];
*framebufferOut = &mFramebuffer->getFramebuffer();
return angle::Result::Continue;
}
......@@ -1328,8 +1403,9 @@ angle::Result FramebufferVk::clearWithRenderPassOp(
// exactly as specified by the scissor for the loadOp to clear only that area. See
// ContextVk::updateScissor for more information.
if (!mFramebuffer.valid() || !mFramebuffer.renderPassStartedButEmpty() ||
mFramebuffer.getRenderPassRenderArea() != clearArea)
if (mFramebuffer == nullptr || !mFramebuffer->valid() ||
!mFramebuffer->renderPassStartedButEmpty() ||
mFramebuffer->getRenderPassRenderArea() != clearArea)
{
vk::CommandBuffer *commandBuffer;
ANGLE_TRY(startNewRenderPass(contextVk, clearArea, &commandBuffer));
......@@ -1352,7 +1428,7 @@ angle::Result FramebufferVk::clearWithRenderPassOp(
SetEmulatedAlphaValue(renderTarget->getImageFormat(), &value);
}
mFramebuffer.clearRenderPassColorAttachment(attachmentIndexVk, value);
mFramebuffer->clearRenderPassColorAttachment(attachmentIndexVk, value);
}
++attachmentIndexVk;
}
......@@ -1363,17 +1439,16 @@ angle::Result FramebufferVk::clearWithRenderPassOp(
{
if (clearDepth)
{
mFramebuffer.clearRenderPassDepthAttachment(attachmentIndexVk,
clearDepthStencilValue.depth);
mFramebuffer->clearRenderPassDepthAttachment(attachmentIndexVk,
clearDepthStencilValue.depth);
}
if (clearStencil)
{
mFramebuffer.clearRenderPassStencilAttachment(attachmentIndexVk,
clearDepthStencilValue.stencil);
mFramebuffer->clearRenderPassStencilAttachment(attachmentIndexVk,
clearDepthStencilValue.stencil);
}
}
return angle::Result::Continue;
}
......@@ -1447,7 +1522,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
vk::CommandBuffer *writeCommands = nullptr;
if (contextVk->commandGraphEnabled())
{
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &writeCommands));
ANGLE_TRY(mFramebuffer->recordCommands(contextVk, &writeCommands));
}
else
{
......@@ -1461,7 +1536,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget);
ANGLE_TRY(colorRenderTarget->onColorDraw(contextVk, &mFramebuffer, writeCommands));
ANGLE_TRY(colorRenderTarget->onColorDraw(contextVk, mFramebuffer, writeCommands));
renderPassAttachmentOps.initWithLoadStore(attachmentClearValues.size(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
......@@ -1473,7 +1548,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
if (depthStencilRenderTarget)
{
ANGLE_TRY(
depthStencilRenderTarget->onDepthStencilDraw(contextVk, &mFramebuffer, writeCommands));
depthStencilRenderTarget->onDepthStencilDraw(contextVk, mFramebuffer, writeCommands));
renderPassAttachmentOps.initWithLoadStore(attachmentClearValues.size(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
......@@ -1483,9 +1558,9 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
if (contextVk->commandGraphEnabled())
{
return mFramebuffer.beginRenderPass(contextVk, *framebuffer, renderArea, mRenderPassDesc,
renderPassAttachmentOps, attachmentClearValues,
commandBufferOut);
return mFramebuffer->beginRenderPass(contextVk, *framebuffer, renderArea, mRenderPassDesc,
renderPassAttachmentOps, attachmentClearValues,
commandBufferOut);
}
else
{
......
......@@ -114,11 +114,12 @@ class FramebufferVk : public FramebufferImpl
const gl::Rectangle &renderArea,
vk::CommandBuffer **commandBufferOut)
{
return mFramebuffer.appendToStartedRenderPass(resourceUseList, renderArea,
commandBufferOut);
ASSERT(mFramebuffer);
return mFramebuffer->appendToStartedRenderPass(resourceUseList, renderArea,
commandBufferOut);
}
vk::FramebufferHelper *getFramebuffer() { return &mFramebuffer; }
vk::FramebufferHelper *getFramebuffer() { return mFramebuffer; }
angle::Result startNewRenderPass(ContextVk *context,
const gl::Rectangle &renderArea,
......@@ -128,6 +129,7 @@ class FramebufferVk : public FramebufferImpl
GLint getSamples() const;
const vk::RenderPassDesc &getRenderPassDesc() const { return mRenderPassDesc; }
const vk::FramebufferDesc &getFramebufferDesc() const { return mCurrentFramebufferDesc; }
private:
FramebufferVk(RendererVk *renderer,
......@@ -179,11 +181,13 @@ class FramebufferVk : public FramebufferImpl
void updateRenderPassDesc();
angle::Result updateColorAttachment(const gl::Context *context, size_t colorIndex);
angle::Result invalidateImpl(ContextVk *contextVk, size_t count, const GLenum *attachments);
// Release all FramebufferVk objects in the cache and clear cache
void clearCache(ContextVk *contextVk);
WindowSurfaceVk *mBackbuffer;
vk::RenderPassDesc mRenderPassDesc;
vk::FramebufferHelper mFramebuffer;
vk::FramebufferHelper *mFramebuffer;
RenderTargetCache<RenderTargetVk> mRenderTargetCache;
// These two variables are used to quickly compute if we need to do a masked clear. If a color
......@@ -197,6 +201,9 @@ class FramebufferVk : public FramebufferImpl
// the framebuffer does not, we need to mask out the alpha channel. This DrawBufferMask will
// contain the mask to apply to the alpha channel when drawing.
gl::DrawBufferMask mEmulatedAlphaAttachmentMask;
vk::FramebufferDesc mCurrentFramebufferDesc;
std::unordered_map<vk::FramebufferDesc, vk::FramebufferHelper> mFramebufferCache;
};
} // namespace rx
......
......@@ -54,6 +54,20 @@ void RenderTargetVk::reset()
mLayerIndex = 0;
}
vk::AttachmentSerial RenderTargetVk::getAssignSerial(ContextVk *contextVk)
{
ASSERT(mImage && mImage->valid());
vk::AttachmentSerial attachmentSerial;
ASSERT(mLayerIndex < std::numeric_limits<uint16_t>::max());
ASSERT(mLevelIndex < std::numeric_limits<uint16_t>::max());
Serial imageSerial = mImage->getAssignSerial(contextVk);
ASSERT(imageSerial.getValue() < std::numeric_limits<uint32_t>::max());
SetBitField(attachmentSerial.layer, mLayerIndex);
SetBitField(attachmentSerial.level, mLevelIndex);
SetBitField(attachmentSerial.imageSerial, imageSerial.getValue());
return attachmentSerial;
}
angle::Result RenderTargetVk::onColorDraw(ContextVk *contextVk,
vk::FramebufferHelper *framebufferVk,
vk::CommandBuffer *commandBuffer)
......
......@@ -48,6 +48,8 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
uint32_t levelIndex,
uint32_t layerIndex);
void reset();
// This returns the serial from underlying ImageHelper, first assigning one if required
vk::AttachmentSerial getAssignSerial(ContextVk *contextVk);
// Note: RenderTargets should be called in order, with the depth/stencil onRender last.
angle::Result onColorDraw(ContextVk *contextVk,
......
......@@ -353,11 +353,6 @@ DestT Int4Array_Get(const uint8_t *arrayBytes, uint32_t arrayIndex)
}
}
// Helper macro that casts to a bitfield type then verifies no bits were dropped.
#define SetBitField(lhs, rhs) \
lhs = static_cast<typename std::decay<decltype(lhs)>::type>(rhs); \
ASSERT(static_cast<decltype(rhs)>(lhs) == (rhs))
// When converting a byte number to a transition bit index we can shift instead of divide.
constexpr size_t kTransitionByteShift = Log2(kGraphicsPipelineDirtyBitBytes);
......@@ -1650,6 +1645,37 @@ bool TextureDescriptorDesc::operator==(const TextureDescriptorDesc &other) const
return memcmp(mSerials.data(), other.mSerials.data(), sizeof(TexUnitSerials) * mMaxIndex) == 0;
}
FramebufferDesc::FramebufferDesc()
{
clearSerials();
}
FramebufferDesc::~FramebufferDesc() = default;
FramebufferDesc::FramebufferDesc(const FramebufferDesc &other) = default;
FramebufferDesc &FramebufferDesc::operator=(const FramebufferDesc &other) = default;
void FramebufferDesc::update(uint32_t index, AttachmentSerial serial)
{
ASSERT(index < kMaxFramebufferAttachments);
mSerials[index] = serial;
}
size_t FramebufferDesc::hash() const
{
return angle::ComputeGenericHash(&mSerials,
sizeof(AttachmentSerial) * kMaxFramebufferAttachments);
}
void FramebufferDesc::clearSerials()
{
memset(&mSerials, 0, sizeof(AttachmentSerial) * kMaxFramebufferAttachments);
}
bool FramebufferDesc::operator==(const FramebufferDesc &other) const
{
return memcmp(&mSerials, &other.mSerials, sizeof(Serial) * kMaxFramebufferAttachments) == 0;
}
} // namespace vk
// RenderPassCache implementation.
......
......@@ -28,6 +28,11 @@ using PipelineAndSerial = ObjectAndSerial<Pipeline>;
using RefCountedDescriptorSetLayout = RefCounted<DescriptorSetLayout>;
using RefCountedPipelineLayout = RefCounted<PipelineLayout>;
// Helper macro that casts to a bitfield type then verifies no bits were dropped.
#define SetBitField(lhs, rhs) \
lhs = static_cast<typename std::decay<decltype(lhs)>::type>(rhs); \
ASSERT(static_cast<decltype(rhs)>(lhs) == (rhs))
// Packed Vk resource descriptions.
// Most Vk types use many more bits than required to represent the underlying data.
// Since ANGLE wants to cache things like RenderPasses and Pipeline State Objects using
......@@ -715,6 +720,41 @@ class TextureDescriptorDesc
};
gl::ActiveTextureArray<TexUnitSerials> mSerials;
};
// This is IMPLEMENTATION_MAX_DRAW_BUFFERS + 1 for DS attachment
constexpr size_t kMaxFramebufferAttachments = gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS;
// Color serials are at index [0:gl::IMPLEMENTATION_MAX_DRAW_BUFFERS-1]
// Depth index is at gl::IMPLEMENTATION_MAX_DRAW_BUFFERS
// Stencil index is at gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1
constexpr size_t kFramebufferDescDepthIndex = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
constexpr size_t kFramebufferDescStencilIndex = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
// Struct for AttachmentSerial cache signatures. Includes level/layer for imageView as
// well as a unique Serial value for the underlying image
struct AttachmentSerial
{
uint16_t level;
uint16_t layer;
uint32_t imageSerial;
};
constexpr AttachmentSerial kZeroAttachmentSerial = {0, 0, 0};
class FramebufferDesc
{
public:
FramebufferDesc();
~FramebufferDesc();
FramebufferDesc(const FramebufferDesc &other);
FramebufferDesc &operator=(const FramebufferDesc &other);
void update(uint32_t index, AttachmentSerial serial);
size_t hash() const;
bool operator==(const FramebufferDesc &other) const;
private:
void clearSerials();
gl::AttachmentArray<AttachmentSerial> mSerials;
};
} // namespace vk
} // namespace rx
......@@ -756,6 +796,12 @@ struct hash<rx::vk::TextureDescriptorDesc>
{
size_t operator()(const rx::vk::TextureDescriptorDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::vk::FramebufferDesc>
{
size_t operator()(const rx::vk::FramebufferDesc &key) const { return key.hash(); }
};
} // namespace std
namespace rx
......
......@@ -1733,6 +1733,7 @@ ImageHelper::ImageHelper()
: CommandGraphResource(CommandGraphResourceType::Image),
mFormat(nullptr),
mSamples(1),
mSerial(rx::kZeroSerial),
mCurrentLayout(ImageLayout::Undefined),
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
mBaseLevel(0),
......@@ -1748,6 +1749,7 @@ ImageHelper::ImageHelper(ImageHelper &&other)
mExtents(other.mExtents),
mFormat(other.mFormat),
mSamples(other.mSamples),
mSerial(other.mSerial),
mCurrentLayout(other.mCurrentLayout),
mCurrentQueueFamilyIndex(other.mCurrentQueueFamilyIndex),
mBaseLevel(other.mBaseLevel),
......@@ -1763,6 +1765,7 @@ ImageHelper::ImageHelper(ImageHelper &&other)
other.mMaxLevel = 0;
other.mLayerCount = 0;
other.mLevelCount = 0;
other.mSerial = rx::kZeroSerial;
}
ImageHelper::~ImageHelper()
......@@ -1790,6 +1793,7 @@ angle::Result ImageHelper::init(Context *context,
uint32_t mipLevels,
uint32_t layerCount)
{
mSerial = rx::kZeroSerial;
return initExternal(context, textureType, extents, format, samples, usage,
ImageLayout::Undefined, nullptr, baseLevel, maxLevel, mipLevels,
layerCount);
......@@ -1851,6 +1855,7 @@ angle::Result ImageHelper::initExternal(Context *context,
void ImageHelper::releaseImage(RendererVk *renderer)
{
mSerial = rx::kZeroSerial;
renderer->collectGarbageAndReinit(&mUse, &mImage, &mDeviceMemory);
}
......@@ -1955,6 +1960,7 @@ void ImageHelper::destroy(VkDevice device)
mCurrentLayout = ImageLayout::Undefined;
mLayerCount = 0;
mLevelCount = 0;
mSerial = rx::kZeroSerial;
}
void ImageHelper::init2DWeakReference(VkImage handle,
......@@ -2196,6 +2202,15 @@ gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const
std::max(1u, mExtents.height >> mipLevel), mExtents.depth);
}
Serial ImageHelper::getAssignSerial(ContextVk *contextVk)
{
if (mSerial.getValue() == 0)
{
mSerial = contextVk->generateAttachmentImageSerial();
}
return mSerial;
}
// static
void ImageHelper::Copy(ImageHelper *srcImage,
ImageHelper *dstImage,
......@@ -3515,6 +3530,18 @@ FramebufferHelper::FramebufferHelper() : CommandGraphResource(CommandGraphResour
FramebufferHelper::~FramebufferHelper() = default;
FramebufferHelper::FramebufferHelper(FramebufferHelper &&other)
: CommandGraphResource(CommandGraphResourceType::Framebuffer)
{
mFramebuffer = std::move(other.mFramebuffer);
}
FramebufferHelper &FramebufferHelper::operator=(FramebufferHelper &&other)
{
std::swap(mFramebuffer, other.mFramebuffer);
return *this;
}
angle::Result FramebufferHelper::init(ContextVk *contextVk,
const VkFramebufferCreateInfo &createInfo)
{
......
......@@ -777,6 +777,10 @@ class ImageHelper final : public CommandGraphResource
gl::Extents getSize(const gl::ImageIndex &index) const;
// Return unique Serial for underlying image, first assigning it if it hasn't been set yet
Serial getAssignSerial(ContextVk *contextVk);
void resetSerial() { mSerial = rx::kZeroSerial; }
static void Copy(ImageHelper *srcImage,
ImageHelper *dstImage,
const gl::Offset &srcOffset,
......@@ -1058,6 +1062,7 @@ class ImageHelper final : public CommandGraphResource
VkExtent3D mExtents;
const Format *mFormat;
GLint mSamples;
Serial mSerial;
// Current state.
ImageLayout mCurrentLayout;
......@@ -1168,6 +1173,9 @@ class FramebufferHelper : public CommandGraphResource
FramebufferHelper();
~FramebufferHelper() override;
FramebufferHelper(FramebufferHelper &&other);
FramebufferHelper &operator=(FramebufferHelper &&other);
angle::Result init(ContextVk *contextVk, const VkFramebufferCreateInfo &createInfo);
void release(ContextVk *contextVk);
......
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