Repository: google/filament
File: filament/backend/src/vulkan/VulkanStagePool.h (C/C++)

Code before:

struct VulkanStageImage {
    VkFormat format;
    uint32_t width;
    uint32_t height;
    mutable uint64_t lastAccessed;
    VmaAllocation memory;
    VkImage image;
};

// Manages a pool of stages, periodically releasing stages that have been unused for a while.
// This class manages two types of host-mappable staging areas: buffer stages and image stages.
class VulkanStagePool {
public:
    VulkanStagePool(VmaAllocator allocator, fvkmemory::ResourceManager* resManager,
            VulkanCommands* commands, const VkPhysicalDeviceLimits* deviceLimits);

    // Finds or creates a stage block whose capacity is at least the given
    // number of bytes. Internally, creates and manages and subdivides large
    // buffers so that we have less objects around that we have to keep track
    // of.
    // This function is NOT thread-safe.
    // numBytes - the number of bytes required by this segment.
    // alignment - (optional) the multiple that
    fvkmemory::resource_ptr<VulkanStage::Segment> acquireStage(uint32_t numBytes,
            std::optional<uint32_t> alignment = std::nullopt);

    // Images have VK_IMAGE_LAYOUT_GENERAL and must not be transitioned to any other layout
    VulkanStageImage const* acquireImage(PixelDataFormat format, PixelDataType type,
            uint32_t width, uint32_t height);

    // Evicts old unused stages and bumps the current frame number.
    void gc() noexcept;

    // Destroys all unused stages and asserts that there are no stages currently in use.
    // This should be called while the context's VkDevice is still alive.
    // Note: it is expected that all resources have been reclaimed before this
    // is called. It is also expected that this stage pool does not hold any
    // resource_ptrs, as this would lead to undefined behavior.
    void terminate() noexcept;

private:
    VmaAllocator mAllocator;
    fvkmemory::ResourceManager* mResManager;
    VulkanCommands* mCommands;
    const VkPhysicalDeviceLimits* mDeviceLimits;

    // Takes a number of bytes, and aligns it to the non-coherent atom size.
    // This allows us to ensure that when we flush buffers from the host, we
    // never flush more atoms than we need to.
    uint32_t alignToNonCoherentAtomSize(uint32_t numBytes);

Review comment (suggestion):
Maybe we don't need the optional and just make `alignment = 0`. I `alignValue()` handles that case by not doing any alignment.

Code after:
struct VulkanStageImage {
    VkFormat format;
    uint32_t width;
    uint32_t height;
    mutable uint64_t lastAccessed;
    VmaAllocation memory;
    VkImage image;
};

// Manages a pool of stages, periodically releasing stages that have been unused for a while.
// This class manages two types of host-mappable staging areas: buffer stages and image stages.
class VulkanStagePool {
public:
    VulkanStagePool(VmaAllocator allocator, fvkmemory::ResourceManager* resManager,
            VulkanCommands* commands, const VkPhysicalDeviceLimits* deviceLimits);

    // Finds or creates a stage block whose capacity is at least the given
    // number of bytes. Internally, creates and manages and subdivides large
    // buffers so that we have less objects around that we have to keep track
    // of.
    // This function is NOT thread-safe.
    // numBytes - the number of bytes required by this segment.
    // alignment - the multiple to align the buffer offset to
    fvkmemory::resource_ptr<VulkanStage::Segment> acquireStage(uint32_t numBytes,
            uint32_t alignment = 0);

    // Images have VK_IMAGE_LAYOUT_GENERAL and must not be transitioned to any other layout
    VulkanStageImage const* acquireImage(PixelDataFormat format, PixelDataType type,
            uint32_t width, uint32_t height);

    // Evicts old unused stages and bumps the current frame number.
    void gc() noexcept;

    // Destroys all unused stages and asserts that there are no stages currently in use.
    // This should be called while the context's VkDevice is still alive.
    // Note: it is expected that all resources have been reclaimed before this
    // is called. It is also expected that this stage pool does not hold any
    // resource_ptrs, as this would lead to undefined behavior.
    void terminate() noexcept;

private:
    VmaAllocator mAllocator;
    fvkmemory::ResourceManager* mResManager;
    VulkanCommands* mCommands;
    const VkPhysicalDeviceLimits* mDeviceLimits;

    // Takes a number of bytes, and aligns it to the non-coherent atom size.
    // This allows us to ensure that when we flush buffers from the host, we
    // never flush more atoms than we need to.
    uint32_t alignToNonCoherentAtomSize(uint32_t numBytes);