mirror of
https://github.com/Takiiiiiiii/strato.git
synced 2025-07-17 08:46:39 +00:00
Implement thread-safe MegaBuffer pool
We currently have a global `MegaBuffer` instance that is shared across all channels, this is very problematic as `MegaBuffer` fundamentally works like a state machine with allocations (especially resetting/freeing) and is thread-specific. Therefore, we now have a pool of several `MegaBuffer`s which is allocated from by the `CommandExecutor` and kept channel specific as a result which also limits its usage to a single thread, this allows for individually resetting or freeing any allocations.
This commit is contained in:
@ -6,19 +6,67 @@
|
||||
#include "buffer.h"
|
||||
|
||||
namespace skyline::gpu {
|
||||
class MegaBuffer;
|
||||
|
||||
/**
|
||||
* @brief The Buffer Manager is responsible for maintaining a global view of buffers being mapped from the guest to the host, any lookups and creation of host buffer from equivalent guest buffer alongside reconciliation of any overlaps with existing textures
|
||||
*/
|
||||
class BufferManager {
|
||||
private:
|
||||
GPU &gpu;
|
||||
std::mutex mutex; //!< Synchronizes access to the buffer mappings
|
||||
std::vector<std::shared_ptr<Buffer>> buffers; //!< A sorted vector of all buffer mappings
|
||||
|
||||
friend class MegaBuffer;
|
||||
|
||||
/**
|
||||
* @brief A wrapper around a buffer which can be utilized as backing storage for a megabuffer and can track its state to avoid concurrent usage
|
||||
*/
|
||||
struct MegaBufferSlot {
|
||||
std::atomic_flag active{true}; //!< If the megabuffer is currently being utilized, we want to construct a buffer as active
|
||||
std::shared_ptr<FenceCycle> cycle; //!< The latest cycle on the fence, all waits must be performed through this
|
||||
|
||||
constexpr static vk::DeviceSize Size{100 * 1024 * 1024}; //!< Size in bytes of the megabuffer (100MiB)
|
||||
memory::Buffer backing; //!< The GPU buffer as the backing storage for the megabuffer
|
||||
|
||||
MegaBufferSlot(GPU &gpu);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return If the end of the supplied buffer is less than the supplied pointer
|
||||
*/
|
||||
static bool BufferLessThan(const std::shared_ptr<Buffer> &it, u8 *pointer);
|
||||
|
||||
public:
|
||||
std::list<MegaBufferSlot> megaBuffers; //!< A pool of all allocated megabuffers, these are dynamically utilized
|
||||
|
||||
BufferManager(GPU &gpu);
|
||||
|
||||
/**
|
||||
* @return A dynamically allocated megabuffer which can be used to store buffer modifications allowing them to be replayed in-sequence on the GPU
|
||||
* @note This object **must** be destroyed to be reclaimed by the manager and prevent a memory leak
|
||||
*/
|
||||
MegaBuffer AcquireMegaBuffer(const std::shared_ptr<FenceCycle> &cycle);
|
||||
|
||||
/**
|
||||
* @return A pre-existing or newly created Buffer object which covers the supplied mappings
|
||||
*/
|
||||
BufferView FindOrCreate(GuestBuffer guestMapping, const std::shared_ptr<FenceCycle> &cycle = nullptr);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A simple linearly allocated GPU-side buffer used to temporarily store buffer modifications allowing them to be replayed in-sequence on the GPU
|
||||
* @note This class is **not** thread-safe and any calls must be externally synchronized
|
||||
*/
|
||||
class MegaBuffer {
|
||||
private:
|
||||
constexpr static vk::DeviceSize Size{0x6'400'000}; //!< Size in bytes of the megabuffer (100MiB)
|
||||
|
||||
memory::Buffer backing; //!< The backing GPU buffer
|
||||
std::mutex mutex; //!< Synchronizes access to freeRegion
|
||||
span<u8> freeRegion; //!< Span of unallocated space in the megabuffer
|
||||
BufferManager::MegaBufferSlot &slot;
|
||||
span<u8> freeRegion; //!< The unallocated space in the megabuffer
|
||||
|
||||
public:
|
||||
MegaBuffer(GPU &gpu);
|
||||
MegaBuffer(BufferManager::MegaBufferSlot &slot);
|
||||
|
||||
~MegaBuffer();
|
||||
|
||||
/**
|
||||
* @brief Resets the free region of the megabuffer to its initial state, data is left intact but may be overwritten
|
||||
@ -36,29 +84,4 @@ namespace skyline::gpu {
|
||||
*/
|
||||
vk::DeviceSize Push(span<u8> data, bool pageAlign = false);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The Buffer Manager is responsible for maintaining a global view of buffers being mapped from the guest to the host, any lookups and creation of host buffer from equivalent guest buffer alongside reconciliation of any overlaps with existing textures
|
||||
*/
|
||||
class BufferManager {
|
||||
private:
|
||||
GPU &gpu;
|
||||
std::mutex mutex; //!< Synchronizes access to the buffer mappings
|
||||
std::vector<std::shared_ptr<Buffer>> buffers; //!< A sorted vector of all buffer mappings
|
||||
|
||||
/**
|
||||
* @return If the end of the supplied buffer is less than the supplied pointer
|
||||
*/
|
||||
static bool BufferLessThan(const std::shared_ptr<Buffer> &it, u8 *pointer);
|
||||
|
||||
public:
|
||||
MegaBuffer megaBuffer; //!< The megabuffer used to temporarily store buffer modifications allowing them to be replayed in-sequence on the GPU
|
||||
|
||||
BufferManager(GPU &gpu);
|
||||
|
||||
/**
|
||||
* @return A pre-existing or newly created Buffer object which covers the supplied mappings
|
||||
*/
|
||||
BufferView FindOrCreate(GuestBuffer guestMapping, const std::shared_ptr<FenceCycle> &cycle = nullptr);
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user