mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
[dxvk] Implemented recycling of command buffers and staging buffers
This commit is contained in:
parent
037e9a643d
commit
68ca71d8a4
@ -22,7 +22,7 @@ namespace dxvk {
|
||||
// Create swap chain for the surface
|
||||
DxvkSwapchainProperties swapchainProperties;
|
||||
swapchainProperties.preferredSurfaceFormat = this->pickFormat(bufferFormat);
|
||||
swapchainProperties.preferredPresentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
swapchainProperties.preferredPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
swapchainProperties.preferredBufferSize.width = bufferWidth;
|
||||
swapchainProperties.preferredBufferSize.height = bufferHeight;
|
||||
|
||||
@ -207,7 +207,7 @@ namespace dxvk {
|
||||
DXGI_FORMAT bufferFormat) {
|
||||
DxvkSwapchainProperties swapchainProperties;
|
||||
swapchainProperties.preferredSurfaceFormat = this->pickFormat(bufferFormat);
|
||||
swapchainProperties.preferredPresentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
swapchainProperties.preferredPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
swapchainProperties.preferredBufferSize.width = bufferWidth;
|
||||
swapchainProperties.preferredBufferSize.height = bufferHeight;
|
||||
|
||||
|
@ -33,12 +33,20 @@ namespace dxvk {
|
||||
|
||||
|
||||
Rc<DxvkStagingBuffer> DxvkDevice::allocStagingBuffer(VkDeviceSize size) {
|
||||
// TODO actually recycle old buffers
|
||||
const VkDeviceSize baseSize = 64 * 1024 * 1024;
|
||||
const VkDeviceSize bufferSize = std::max(baseSize, size);
|
||||
// In case we need a standard-size staging buffer, try
|
||||
// to recycle an old one that has been returned earlier
|
||||
if (size <= DefaultStagingBufferSize) {
|
||||
const Rc<DxvkStagingBuffer> buffer
|
||||
= m_recycledStagingBuffers.retrieveObject();
|
||||
|
||||
if (buffer != nullptr)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Staging buffers only need to be able to handle transfer
|
||||
// operations, and they need to be in host-visible memory.
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = bufferSize;
|
||||
info.size = size;
|
||||
info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
| VK_PIPELINE_STAGE_HOST_BIT;
|
||||
@ -49,18 +57,32 @@ namespace dxvk {
|
||||
= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
|
||||
// Don't create buffers that are too small. A staging
|
||||
// buffer should be able to serve multiple uploads.
|
||||
if (info.size < DefaultStagingBufferSize)
|
||||
info.size = DefaultStagingBufferSize;
|
||||
|
||||
return new DxvkStagingBuffer(this->createBuffer(info, memFlags));
|
||||
}
|
||||
|
||||
|
||||
void DxvkDevice::recycleStagingBuffer(const Rc<DxvkStagingBuffer>& buffer) {
|
||||
// TODO implement
|
||||
// Drop staging buffers that are bigger than the
|
||||
// standard ones to save memory, recycle the rest
|
||||
if (buffer->size() == DefaultStagingBufferSize)
|
||||
m_recycledStagingBuffers.returnObject(buffer);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkCommandList> DxvkDevice::createCommandList() {
|
||||
return new DxvkCommandList(m_vkd, this,
|
||||
m_adapter->graphicsQueueFamily());
|
||||
Rc<DxvkCommandList> cmdList = m_recycledCommandLists.retrieveObject();
|
||||
|
||||
if (cmdList == nullptr) {
|
||||
cmdList = new DxvkCommandList(m_vkd,
|
||||
this, m_adapter->graphicsQueueFamily());
|
||||
}
|
||||
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
|
||||
@ -176,6 +198,9 @@ namespace dxvk {
|
||||
// TODO Delay synchronization by putting these into a ring buffer
|
||||
fence->wait(std::numeric_limits<uint64_t>::max());
|
||||
commandList->reset();
|
||||
|
||||
// FIXME this must go away once the ring buffer is implemented
|
||||
m_recycledCommandLists.returnObject(commandList);
|
||||
return fence;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "dxvk_image.h"
|
||||
#include "dxvk_memory.h"
|
||||
#include "dxvk_pipemanager.h"
|
||||
#include "dxvk_recycler.h"
|
||||
#include "dxvk_renderpass.h"
|
||||
#include "dxvk_sampler.h"
|
||||
#include "dxvk_shader.h"
|
||||
@ -28,7 +29,7 @@ namespace dxvk {
|
||||
* contexts. Multiple contexts can be created for a device.
|
||||
*/
|
||||
class DxvkDevice : public RcObject {
|
||||
|
||||
constexpr static VkDeviceSize DefaultStagingBufferSize = 64 * 1024 * 1024;
|
||||
public:
|
||||
|
||||
DxvkDevice(
|
||||
@ -266,8 +267,12 @@ namespace dxvk {
|
||||
Rc<DxvkRenderPassPool> m_renderPassPool;
|
||||
Rc<DxvkPipelineManager> m_pipelineManager;
|
||||
|
||||
VkQueue m_graphicsQueue;
|
||||
VkQueue m_presentQueue;
|
||||
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
|
||||
VkQueue m_presentQueue = VK_NULL_HANDLE;
|
||||
|
||||
// TODO fine-tune buffer sizes
|
||||
DxvkRecycler<DxvkCommandList, 16> m_recycledCommandLists;
|
||||
DxvkRecycler<DxvkStagingBuffer, 4> m_recycledStagingBuffers;
|
||||
|
||||
};
|
||||
|
||||
|
63
src/dxvk/dxvk_recycler.h
Normal file
63
src/dxvk/dxvk_recycler.h
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Object recycler
|
||||
*
|
||||
* Implements a thread-safe buffer that can store up to
|
||||
* a given number of objects of a certain type. This way,
|
||||
* DXVK can efficiently reuse and reset objects instead
|
||||
* of destroying them and creating them anew.
|
||||
* \tparam T Type of the objects to store
|
||||
* \tparam N Maximum number of objects to store
|
||||
*/
|
||||
template<typename T, size_t N>
|
||||
class DxvkRecycler {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Retrieves an object if possible
|
||||
*
|
||||
* Returns an object that was returned to the recycler
|
||||
* earier. In case no objects are available, this will
|
||||
* return \c nullptr and a new object has to be created.
|
||||
* \return An object, or \c nullptr
|
||||
*/
|
||||
Rc<T> retrieveObject() {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (m_objectId == 0)
|
||||
return nullptr;
|
||||
|
||||
return m_objects.at(--m_objectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns an object to the recycler
|
||||
*
|
||||
* If the buffer is full, the object will be destroyed
|
||||
* once the last reference runs out of scope. No further
|
||||
* action needs to be taken in this case.
|
||||
* \param [in] object The object to return
|
||||
*/
|
||||
void returnObject(const Rc<T>& object) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (m_objectId < N)
|
||||
m_objects.at(m_objectId++) = object;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::array<Rc<T>, N> m_objects;
|
||||
size_t m_objectId = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -15,6 +15,11 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
VkDeviceSize DxvkStagingBuffer::size() const {
|
||||
return m_bufferSize;
|
||||
}
|
||||
|
||||
|
||||
VkDeviceSize DxvkStagingBuffer::freeBytes() const {
|
||||
return m_bufferSize - m_bufferOffset;
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ namespace dxvk {
|
||||
|
||||
~DxvkStagingBuffer();
|
||||
|
||||
VkDeviceSize size() const;
|
||||
|
||||
VkDeviceSize freeBytes() const;
|
||||
|
||||
bool alloc(
|
||||
|
Loading…
x
Reference in New Issue
Block a user