Merge pull request #2686 from ReinUsesLisp/vk-scheduler
vk_scheduler: Drop execution context in favor of views
This commit is contained in:
		| @@ -109,8 +109,8 @@ void VKBufferCache::Reserve(std::size_t max_size) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| VKExecutionContext VKBufferCache::Send(VKExecutionContext exctx) { | ||||
|     return stream_buffer->Send(exctx, buffer_offset - buffer_offset_base); | ||||
| void VKBufferCache::Send() { | ||||
|     stream_buffer->Send(buffer_offset - buffer_offset_base); | ||||
| } | ||||
|  | ||||
| void VKBufferCache::AlignBuffer(std::size_t alignment) { | ||||
|   | ||||
| @@ -77,7 +77,7 @@ public: | ||||
|     void Reserve(std::size_t max_size); | ||||
|  | ||||
|     /// Ensures that the set data is sent to the device. | ||||
|     [[nodiscard]] VKExecutionContext Send(VKExecutionContext exctx); | ||||
|     void Send(); | ||||
|  | ||||
|     /// Returns the buffer cache handle. | ||||
|     vk::Buffer GetBuffer() const { | ||||
|   | ||||
| @@ -19,23 +19,19 @@ VKScheduler::VKScheduler(const VKDevice& device, VKResourceManager& resource_man | ||||
|  | ||||
| VKScheduler::~VKScheduler() = default; | ||||
|  | ||||
| VKExecutionContext VKScheduler::GetExecutionContext() const { | ||||
|     return VKExecutionContext(current_fence, current_cmdbuf); | ||||
| } | ||||
|  | ||||
| VKExecutionContext VKScheduler::Flush(vk::Semaphore semaphore) { | ||||
| void VKScheduler::Flush(bool release_fence, vk::Semaphore semaphore) { | ||||
|     SubmitExecution(semaphore); | ||||
|     if (release_fence) | ||||
|         current_fence->Release(); | ||||
|     AllocateNewContext(); | ||||
|     return GetExecutionContext(); | ||||
| } | ||||
|  | ||||
| VKExecutionContext VKScheduler::Finish(vk::Semaphore semaphore) { | ||||
| void VKScheduler::Finish(bool release_fence, vk::Semaphore semaphore) { | ||||
|     SubmitExecution(semaphore); | ||||
|     current_fence->Wait(); | ||||
|     if (release_fence) | ||||
|         current_fence->Release(); | ||||
|     AllocateNewContext(); | ||||
|     return GetExecutionContext(); | ||||
| } | ||||
|  | ||||
| void VKScheduler::SubmitExecution(vk::Semaphore semaphore) { | ||||
|   | ||||
| @@ -10,10 +10,43 @@ | ||||
| namespace Vulkan { | ||||
|  | ||||
| class VKDevice; | ||||
| class VKExecutionContext; | ||||
| class VKFence; | ||||
| class VKResourceManager; | ||||
|  | ||||
| class VKFenceView { | ||||
| public: | ||||
|     VKFenceView() = default; | ||||
|     VKFenceView(VKFence* const& fence) : fence{fence} {} | ||||
|  | ||||
|     VKFence* operator->() const noexcept { | ||||
|         return fence; | ||||
|     } | ||||
|  | ||||
|     operator VKFence&() const noexcept { | ||||
|         return *fence; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     VKFence* const& fence; | ||||
| }; | ||||
|  | ||||
| class VKCommandBufferView { | ||||
| public: | ||||
|     VKCommandBufferView() = default; | ||||
|     VKCommandBufferView(const vk::CommandBuffer& cmdbuf) : cmdbuf{cmdbuf} {} | ||||
|  | ||||
|     const vk::CommandBuffer* operator->() const noexcept { | ||||
|         return &cmdbuf; | ||||
|     } | ||||
|  | ||||
|     operator vk::CommandBuffer() const noexcept { | ||||
|         return cmdbuf; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const vk::CommandBuffer& cmdbuf; | ||||
| }; | ||||
|  | ||||
| /// The scheduler abstracts command buffer and fence management with an interface that's able to do | ||||
| /// OpenGL-like operations on Vulkan command buffers. | ||||
| class VKScheduler { | ||||
| @@ -21,16 +54,21 @@ public: | ||||
|     explicit VKScheduler(const VKDevice& device, VKResourceManager& resource_manager); | ||||
|     ~VKScheduler(); | ||||
|  | ||||
|     /// Gets the current execution context. | ||||
|     [[nodiscard]] VKExecutionContext GetExecutionContext() const; | ||||
|     /// Gets a reference to the current fence. | ||||
|     VKFenceView GetFence() const { | ||||
|         return current_fence; | ||||
|     } | ||||
|  | ||||
|     /// Sends the current execution context to the GPU. It invalidates the current execution context | ||||
|     /// and returns a new one. | ||||
|     VKExecutionContext Flush(vk::Semaphore semaphore = nullptr); | ||||
|     /// Gets a reference to the current command buffer. | ||||
|     VKCommandBufferView GetCommandBuffer() const { | ||||
|         return current_cmdbuf; | ||||
|     } | ||||
|  | ||||
|     /// Sends the current execution context to the GPU and waits for it to complete. It invalidates | ||||
|     /// the current execution context and returns a new one. | ||||
|     VKExecutionContext Finish(vk::Semaphore semaphore = nullptr); | ||||
|     /// Sends the current execution context to the GPU. | ||||
|     void Flush(bool release_fence = true, vk::Semaphore semaphore = nullptr); | ||||
|  | ||||
|     /// Sends the current execution context to the GPU and waits for it to complete. | ||||
|     void Finish(bool release_fence = true, vk::Semaphore semaphore = nullptr); | ||||
|  | ||||
| private: | ||||
|     void SubmitExecution(vk::Semaphore semaphore); | ||||
| @@ -44,26 +82,4 @@ private: | ||||
|     VKFence* next_fence = nullptr; | ||||
| }; | ||||
|  | ||||
| class VKExecutionContext { | ||||
|     friend class VKScheduler; | ||||
|  | ||||
| public: | ||||
|     VKExecutionContext() = default; | ||||
|  | ||||
|     VKFence& GetFence() const { | ||||
|         return *fence; | ||||
|     } | ||||
|  | ||||
|     vk::CommandBuffer GetCommandBuffer() const { | ||||
|         return cmdbuf; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     explicit VKExecutionContext(VKFence* fence, vk::CommandBuffer cmdbuf) | ||||
|         : fence{fence}, cmdbuf{cmdbuf} {} | ||||
|  | ||||
|     VKFence* fence{}; | ||||
|     vk::CommandBuffer cmdbuf; | ||||
| }; | ||||
|  | ||||
| } // namespace Vulkan | ||||
|   | ||||
| @@ -46,12 +46,12 @@ std::tuple<u8*, u64, bool> VKStreamBuffer::Reserve(u64 size) { | ||||
|     return {mapped_pointer + offset, offset, invalidation_mark.has_value()}; | ||||
| } | ||||
|  | ||||
| VKExecutionContext VKStreamBuffer::Send(VKExecutionContext exctx, u64 size) { | ||||
| void VKStreamBuffer::Send(u64 size) { | ||||
|     ASSERT_MSG(size <= mapped_size, "Reserved size is too small"); | ||||
|  | ||||
|     if (invalidation_mark) { | ||||
|         // TODO(Rodrigo): Find a better way to invalidate than waiting for all watches to finish. | ||||
|         exctx = scheduler.Flush(); | ||||
|         scheduler.Flush(); | ||||
|         std::for_each(watches.begin(), watches.begin() + *invalidation_mark, | ||||
|                       [&](auto& resource) { resource->Wait(); }); | ||||
|         invalidation_mark = std::nullopt; | ||||
| @@ -62,11 +62,9 @@ VKExecutionContext VKStreamBuffer::Send(VKExecutionContext exctx, u64 size) { | ||||
|         ReserveWatches(WATCHES_RESERVE_CHUNK); | ||||
|     } | ||||
|     // Add a watch for this allocation. | ||||
|     watches[used_watches++]->Watch(exctx.GetFence()); | ||||
|     watches[used_watches++]->Watch(scheduler.GetFence()); | ||||
|  | ||||
|     offset += size; | ||||
|  | ||||
|     return exctx; | ||||
| } | ||||
|  | ||||
| void VKStreamBuffer::CreateBuffers(VKMemoryManager& memory_manager, vk::BufferUsageFlags usage) { | ||||
|   | ||||
| @@ -37,7 +37,7 @@ public: | ||||
|     std::tuple<u8*, u64, bool> Reserve(u64 size); | ||||
|  | ||||
|     /// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy. | ||||
|     [[nodiscard]] VKExecutionContext Send(VKExecutionContext exctx, u64 size); | ||||
|     void Send(u64 size); | ||||
|  | ||||
|     vk::Buffer GetBuffer() const { | ||||
|         return *buffer; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user