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 ...@@ -75,6 +75,9 @@ class Serial final
static constexpr uint64_t kInvalid = 0; static constexpr uint64_t kInvalid = 0;
}; };
// Used as default/initial serial
static constexpr Serial kZeroSerial = Serial();
template <typename SerialBaseType> template <typename SerialBaseType>
class SerialFactoryBase final : angle::NonCopyable class SerialFactoryBase final : angle::NonCopyable
{ {
......
...@@ -110,9 +110,6 @@ constexpr size_t kInFlightCommandsLimit = 100u; ...@@ -110,9 +110,6 @@ constexpr size_t kInFlightCommandsLimit = 100u;
// Initially dumping the command graphs is disabled. // Initially dumping the command graphs is disabled.
constexpr bool kEnableCommandGraphDiagnostics = false; constexpr bool kEnableCommandGraphDiagnostics = false;
// Used as fallback serial for null sampler objects
constexpr Serial kZeroSerial = Serial();
void InitializeSubmitInfo(VkSubmitInfo *submitInfo, void InitializeSubmitInfo(VkSubmitInfo *submitInfo,
const vk::PrimaryCommandBuffer &commandBuffer, const vk::PrimaryCommandBuffer &commandBuffer,
const std::vector<VkSemaphore> &waitSemaphores, const std::vector<VkSemaphore> &waitSemaphores,
...@@ -3556,7 +3553,7 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context) ...@@ -3556,7 +3553,7 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
if (sampler == nullptr) if (sampler == nullptr)
{ {
samplerVk = nullptr; samplerVk = nullptr;
samplerSerial = kZeroSerial; samplerSerial = rx::kZeroSerial;
} }
else else
{ {
......
...@@ -570,6 +570,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -570,6 +570,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
// avoid calling vkAllocateDesctiporSets each texture update. // avoid calling vkAllocateDesctiporSets each texture update.
Serial generateTextureSerial() { return mTextureSerialFactory.generate(); } Serial generateTextureSerial() { return mTextureSerialFactory.generate(); }
const vk::TextureDescriptorDesc &getActiveTexturesDesc() const { return mActiveTexturesDesc; } const vk::TextureDescriptorDesc &getActiveTexturesDesc() const { return mActiveTexturesDesc; }
Serial generateAttachmentImageSerial() { return mAttachmentImageSerialFactory.generate(); }
angle::Result updateScissor(const gl::State &glState); angle::Result updateScissor(const gl::State &glState);
...@@ -1023,8 +1024,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -1023,8 +1024,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
// double. // double.
uint64_t mGpuEventTimestampOrigin; uint64_t mGpuEventTimestampOrigin;
// Generator for texure serials. // Generators for texture & framebuffer serials.
SerialFactory mTextureSerialFactory; SerialFactory mTextureSerialFactory;
SerialFactory mAttachmentImageSerialFactory;
gl::State::DirtyBits mPipelineDirtyBitsMask; gl::State::DirtyBits mPipelineDirtyBitsMask;
......
...@@ -114,11 +114,12 @@ class FramebufferVk : public FramebufferImpl ...@@ -114,11 +114,12 @@ class FramebufferVk : public FramebufferImpl
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
vk::CommandBuffer **commandBufferOut) vk::CommandBuffer **commandBufferOut)
{ {
return mFramebuffer.appendToStartedRenderPass(resourceUseList, renderArea, ASSERT(mFramebuffer);
commandBufferOut); return mFramebuffer->appendToStartedRenderPass(resourceUseList, renderArea,
commandBufferOut);
} }
vk::FramebufferHelper *getFramebuffer() { return &mFramebuffer; } vk::FramebufferHelper *getFramebuffer() { return mFramebuffer; }
angle::Result startNewRenderPass(ContextVk *context, angle::Result startNewRenderPass(ContextVk *context,
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
...@@ -128,6 +129,7 @@ class FramebufferVk : public FramebufferImpl ...@@ -128,6 +129,7 @@ class FramebufferVk : public FramebufferImpl
GLint getSamples() const; GLint getSamples() const;
const vk::RenderPassDesc &getRenderPassDesc() const { return mRenderPassDesc; } const vk::RenderPassDesc &getRenderPassDesc() const { return mRenderPassDesc; }
const vk::FramebufferDesc &getFramebufferDesc() const { return mCurrentFramebufferDesc; }
private: private:
FramebufferVk(RendererVk *renderer, FramebufferVk(RendererVk *renderer,
...@@ -179,11 +181,13 @@ class FramebufferVk : public FramebufferImpl ...@@ -179,11 +181,13 @@ class FramebufferVk : public FramebufferImpl
void updateRenderPassDesc(); void updateRenderPassDesc();
angle::Result updateColorAttachment(const gl::Context *context, size_t colorIndex); angle::Result updateColorAttachment(const gl::Context *context, size_t colorIndex);
angle::Result invalidateImpl(ContextVk *contextVk, size_t count, const GLenum *attachments); 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; WindowSurfaceVk *mBackbuffer;
vk::RenderPassDesc mRenderPassDesc; vk::RenderPassDesc mRenderPassDesc;
vk::FramebufferHelper mFramebuffer; vk::FramebufferHelper *mFramebuffer;
RenderTargetCache<RenderTargetVk> mRenderTargetCache; RenderTargetCache<RenderTargetVk> mRenderTargetCache;
// These two variables are used to quickly compute if we need to do a masked clear. If a color // 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 ...@@ -197,6 +201,9 @@ class FramebufferVk : public FramebufferImpl
// the framebuffer does not, we need to mask out the alpha channel. This DrawBufferMask will // 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. // contain the mask to apply to the alpha channel when drawing.
gl::DrawBufferMask mEmulatedAlphaAttachmentMask; gl::DrawBufferMask mEmulatedAlphaAttachmentMask;
vk::FramebufferDesc mCurrentFramebufferDesc;
std::unordered_map<vk::FramebufferDesc, vk::FramebufferHelper> mFramebufferCache;
}; };
} // namespace rx } // namespace rx
......
...@@ -54,6 +54,20 @@ void RenderTargetVk::reset() ...@@ -54,6 +54,20 @@ void RenderTargetVk::reset()
mLayerIndex = 0; 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, angle::Result RenderTargetVk::onColorDraw(ContextVk *contextVk,
vk::FramebufferHelper *framebufferVk, vk::FramebufferHelper *framebufferVk,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
......
...@@ -48,6 +48,8 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -48,6 +48,8 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
uint32_t levelIndex, uint32_t levelIndex,
uint32_t layerIndex); uint32_t layerIndex);
void reset(); 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. // Note: RenderTargets should be called in order, with the depth/stencil onRender last.
angle::Result onColorDraw(ContextVk *contextVk, angle::Result onColorDraw(ContextVk *contextVk,
......
...@@ -353,11 +353,6 @@ DestT Int4Array_Get(const uint8_t *arrayBytes, uint32_t arrayIndex) ...@@ -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. // When converting a byte number to a transition bit index we can shift instead of divide.
constexpr size_t kTransitionByteShift = Log2(kGraphicsPipelineDirtyBitBytes); constexpr size_t kTransitionByteShift = Log2(kGraphicsPipelineDirtyBitBytes);
...@@ -1650,6 +1645,37 @@ bool TextureDescriptorDesc::operator==(const TextureDescriptorDesc &other) const ...@@ -1650,6 +1645,37 @@ bool TextureDescriptorDesc::operator==(const TextureDescriptorDesc &other) const
return memcmp(mSerials.data(), other.mSerials.data(), sizeof(TexUnitSerials) * mMaxIndex) == 0; 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 } // namespace vk
// RenderPassCache implementation. // RenderPassCache implementation.
......
...@@ -28,6 +28,11 @@ using PipelineAndSerial = ObjectAndSerial<Pipeline>; ...@@ -28,6 +28,11 @@ using PipelineAndSerial = ObjectAndSerial<Pipeline>;
using RefCountedDescriptorSetLayout = RefCounted<DescriptorSetLayout>; using RefCountedDescriptorSetLayout = RefCounted<DescriptorSetLayout>;
using RefCountedPipelineLayout = RefCounted<PipelineLayout>; 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. // Packed Vk resource descriptions.
// Most Vk types use many more bits than required to represent the underlying data. // 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 // Since ANGLE wants to cache things like RenderPasses and Pipeline State Objects using
...@@ -715,6 +720,41 @@ class TextureDescriptorDesc ...@@ -715,6 +720,41 @@ class TextureDescriptorDesc
}; };
gl::ActiveTextureArray<TexUnitSerials> mSerials; 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 vk
} // namespace rx } // namespace rx
...@@ -756,6 +796,12 @@ struct hash<rx::vk::TextureDescriptorDesc> ...@@ -756,6 +796,12 @@ struct hash<rx::vk::TextureDescriptorDesc>
{ {
size_t operator()(const rx::vk::TextureDescriptorDesc &key) const { return key.hash(); } 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 std
namespace rx namespace rx
......
...@@ -1733,6 +1733,7 @@ ImageHelper::ImageHelper() ...@@ -1733,6 +1733,7 @@ ImageHelper::ImageHelper()
: CommandGraphResource(CommandGraphResourceType::Image), : CommandGraphResource(CommandGraphResourceType::Image),
mFormat(nullptr), mFormat(nullptr),
mSamples(1), mSamples(1),
mSerial(rx::kZeroSerial),
mCurrentLayout(ImageLayout::Undefined), mCurrentLayout(ImageLayout::Undefined),
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()), mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
mBaseLevel(0), mBaseLevel(0),
...@@ -1748,6 +1749,7 @@ ImageHelper::ImageHelper(ImageHelper &&other) ...@@ -1748,6 +1749,7 @@ ImageHelper::ImageHelper(ImageHelper &&other)
mExtents(other.mExtents), mExtents(other.mExtents),
mFormat(other.mFormat), mFormat(other.mFormat),
mSamples(other.mSamples), mSamples(other.mSamples),
mSerial(other.mSerial),
mCurrentLayout(other.mCurrentLayout), mCurrentLayout(other.mCurrentLayout),
mCurrentQueueFamilyIndex(other.mCurrentQueueFamilyIndex), mCurrentQueueFamilyIndex(other.mCurrentQueueFamilyIndex),
mBaseLevel(other.mBaseLevel), mBaseLevel(other.mBaseLevel),
...@@ -1763,6 +1765,7 @@ ImageHelper::ImageHelper(ImageHelper &&other) ...@@ -1763,6 +1765,7 @@ ImageHelper::ImageHelper(ImageHelper &&other)
other.mMaxLevel = 0; other.mMaxLevel = 0;
other.mLayerCount = 0; other.mLayerCount = 0;
other.mLevelCount = 0; other.mLevelCount = 0;
other.mSerial = rx::kZeroSerial;
} }
ImageHelper::~ImageHelper() ImageHelper::~ImageHelper()
...@@ -1790,6 +1793,7 @@ angle::Result ImageHelper::init(Context *context, ...@@ -1790,6 +1793,7 @@ angle::Result ImageHelper::init(Context *context,
uint32_t mipLevels, uint32_t mipLevels,
uint32_t layerCount) uint32_t layerCount)
{ {
mSerial = rx::kZeroSerial;
return initExternal(context, textureType, extents, format, samples, usage, return initExternal(context, textureType, extents, format, samples, usage,
ImageLayout::Undefined, nullptr, baseLevel, maxLevel, mipLevels, ImageLayout::Undefined, nullptr, baseLevel, maxLevel, mipLevels,
layerCount); layerCount);
...@@ -1851,6 +1855,7 @@ angle::Result ImageHelper::initExternal(Context *context, ...@@ -1851,6 +1855,7 @@ angle::Result ImageHelper::initExternal(Context *context,
void ImageHelper::releaseImage(RendererVk *renderer) void ImageHelper::releaseImage(RendererVk *renderer)
{ {
mSerial = rx::kZeroSerial;
renderer->collectGarbageAndReinit(&mUse, &mImage, &mDeviceMemory); renderer->collectGarbageAndReinit(&mUse, &mImage, &mDeviceMemory);
} }
...@@ -1955,6 +1960,7 @@ void ImageHelper::destroy(VkDevice device) ...@@ -1955,6 +1960,7 @@ void ImageHelper::destroy(VkDevice device)
mCurrentLayout = ImageLayout::Undefined; mCurrentLayout = ImageLayout::Undefined;
mLayerCount = 0; mLayerCount = 0;
mLevelCount = 0; mLevelCount = 0;
mSerial = rx::kZeroSerial;
} }
void ImageHelper::init2DWeakReference(VkImage handle, void ImageHelper::init2DWeakReference(VkImage handle,
...@@ -2196,6 +2202,15 @@ gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const ...@@ -2196,6 +2202,15 @@ gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const
std::max(1u, mExtents.height >> mipLevel), mExtents.depth); std::max(1u, mExtents.height >> mipLevel), mExtents.depth);
} }
Serial ImageHelper::getAssignSerial(ContextVk *contextVk)
{
if (mSerial.getValue() == 0)
{
mSerial = contextVk->generateAttachmentImageSerial();
}
return mSerial;
}
// static // static
void ImageHelper::Copy(ImageHelper *srcImage, void ImageHelper::Copy(ImageHelper *srcImage,
ImageHelper *dstImage, ImageHelper *dstImage,
...@@ -3515,6 +3530,18 @@ FramebufferHelper::FramebufferHelper() : CommandGraphResource(CommandGraphResour ...@@ -3515,6 +3530,18 @@ FramebufferHelper::FramebufferHelper() : CommandGraphResource(CommandGraphResour
FramebufferHelper::~FramebufferHelper() = default; 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, angle::Result FramebufferHelper::init(ContextVk *contextVk,
const VkFramebufferCreateInfo &createInfo) const VkFramebufferCreateInfo &createInfo)
{ {
......
...@@ -777,6 +777,10 @@ class ImageHelper final : public CommandGraphResource ...@@ -777,6 +777,10 @@ class ImageHelper final : public CommandGraphResource
gl::Extents getSize(const gl::ImageIndex &index) const; 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, static void Copy(ImageHelper *srcImage,
ImageHelper *dstImage, ImageHelper *dstImage,
const gl::Offset &srcOffset, const gl::Offset &srcOffset,
...@@ -1058,6 +1062,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -1058,6 +1062,7 @@ class ImageHelper final : public CommandGraphResource
VkExtent3D mExtents; VkExtent3D mExtents;
const Format *mFormat; const Format *mFormat;
GLint mSamples; GLint mSamples;
Serial mSerial;
// Current state. // Current state.
ImageLayout mCurrentLayout; ImageLayout mCurrentLayout;
...@@ -1168,6 +1173,9 @@ class FramebufferHelper : public CommandGraphResource ...@@ -1168,6 +1173,9 @@ class FramebufferHelper : public CommandGraphResource
FramebufferHelper(); FramebufferHelper();
~FramebufferHelper() override; ~FramebufferHelper() override;
FramebufferHelper(FramebufferHelper &&other);
FramebufferHelper &operator=(FramebufferHelper &&other);
angle::Result init(ContextVk *contextVk, const VkFramebufferCreateInfo &createInfo); angle::Result init(ContextVk *contextVk, const VkFramebufferCreateInfo &createInfo);
void release(ContextVk *contextVk); 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