blob: 75defd52fe2e1598c44b8e2810d883230258c22a [file] [log] [blame]
//
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// AllocatorHelperRing:
// Manages the ring buffer allocators used in the command buffers.
//
#ifndef LIBANGLE_RENDERER_VULKAN_ALLOCATORHELPERRING_H_
#define LIBANGLE_RENDERER_VULKAN_ALLOCATORHELPERRING_H_
#include "common/RingBufferAllocator.h"
#include "common/vulkan/vk_headers.h"
#include "libANGLE/renderer/vulkan/vk_command_buffer_utils.h"
#include "libANGLE/renderer/vulkan/vk_wrapper.h"
namespace rx
{
namespace vk
{
namespace priv
{
class SecondaryCommandBuffer;
} // namespace priv
using SharedCommandMemoryAllocator = angle::SharedRingBufferAllocator;
using RingBufferAllocator = angle::RingBufferAllocator;
// Used in CommandBufferHelperCommon
class SharedCommandBlockAllocator
{
public:
SharedCommandBlockAllocator() : mAllocator(nullptr), mAllocSharedCP(nullptr) {}
void resetAllocator();
bool hasAllocatorLinks() const { return mAllocator || mAllocSharedCP; }
void init() {}
void attachAllocator(SharedCommandMemoryAllocator *allocator);
SharedCommandMemoryAllocator *detachAllocator(bool isCommandBufferEmpty);
SharedCommandMemoryAllocator *getAllocator() { return mAllocator; }
private:
// Using a ring buffer allocator for less memory overhead (observed with the async queue
// ex-feature)
SharedCommandMemoryAllocator *mAllocator;
angle::SharedRingBufferAllocatorCheckPoint *mAllocSharedCP;
angle::RingBufferAllocatorCheckPoint mAllocReleaseCP;
};
// Used in SecondaryCommandBuffer
class SharedCommandBlockPool final : angle::RingBufferAllocateListener
{
public:
SharedCommandBlockPool()
: mLastCommandBlock(nullptr), mFinishedCommandSize(0), mCommandBuffer(nullptr)
{}
static constexpr size_t kCommandHeaderSize = 4;
using CommandHeaderIDType = uint16_t;
// Make sure the size of command header ID type is less than total command header size.
static_assert(sizeof(CommandHeaderIDType) < kCommandHeaderSize, "Check size of CommandHeader");
void setCommandBuffer(priv::SecondaryCommandBuffer *commandBuffer)
{
mCommandBuffer = commandBuffer;
}
void resetCommandBuffer() { mCommandBuffer = nullptr; }
void reset(CommandBufferCommandTracker *commandBufferTracker)
{
mLastCommandBlock = nullptr;
mFinishedCommandSize = 0;
if (mAllocator.valid())
{
mAllocator.release(mAllocator.getReleaseCheckPoint());
pushNewCommandBlock(mAllocator.allocate(0));
}
}
angle::Result initialize(SharedCommandMemoryAllocator *allocator)
{
return angle::Result::Continue;
}
// Always valid (even if allocator is detached).
bool valid() const { return true; }
bool empty() const { return getCommandSize() == 0; }
void getMemoryUsageStats(size_t *usedMemoryOut, size_t *allocatedMemoryOut) const;
void terminateLastCommandBlock()
{
if (mLastCommandBlock)
{
ASSERT(mAllocator.valid());
ASSERT(mAllocator.getPointer() >= mLastCommandBlock);
ASSERT(mAllocator.getFragmentSize() >= kCommandHeaderSize);
reinterpret_cast<CommandHeaderIDType &>(*(mAllocator.getPointer())) = 0;
}
}
// Initialize the SecondaryCommandBuffer by setting the allocator it will use
void attachAllocator(SharedCommandMemoryAllocator *source);
void detachAllocator(SharedCommandMemoryAllocator *destination);
void onNewVariableSizedCommand(const size_t requiredSize,
const size_t allocationSize,
uint8_t **headerOut)
{
*headerOut = allocateCommand(allocationSize);
}
void onNewCommand(const size_t requiredSize, const size_t allocationSize, uint8_t **headerOut)
{
*headerOut = allocateCommand(allocationSize);
}
private:
uint8_t *allocateCommand(size_t allocationSize)
{
ASSERT(mLastCommandBlock);
return mAllocator.allocate(static_cast<uint32_t>(allocationSize));
}
// The following is used to give the size of the command buffer in bytes
uint32_t getCommandSize() const
{
uint32_t result = mFinishedCommandSize;
if (mLastCommandBlock)
{
ASSERT(mAllocator.valid());
ASSERT(mAllocator.getPointer() >= mLastCommandBlock);
result += static_cast<uint32_t>(mAllocator.getPointer() - mLastCommandBlock);
}
return result;
}
void pushNewCommandBlock(uint8_t *block);
void finishLastCommandBlock();
// Functions derived from RingBufferAllocateListener
virtual void onRingBufferNewFragment() override;
virtual void onRingBufferFragmentEnd() override;
// Using a ring buffer allocator for less memory overhead (observed with the async queue
// ex-feature)
RingBufferAllocator mAllocator;
uint8_t *mLastCommandBlock;
uint32_t mFinishedCommandSize;
// Points to the parent command buffer.
priv::SecondaryCommandBuffer *mCommandBuffer;
};
} // namespace vk
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_ALLOCATORHELPERRING_H_