mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
[dxvk] Implemented buffer renaming
This commit is contained in:
parent
d9f38a7f42
commit
d3b2174180
@ -78,47 +78,27 @@ namespace dxvk {
|
|||||||
if (pMappedSubresource == nullptr)
|
if (pMappedSubresource == nullptr)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
if (!buffer->isInUse()) {
|
if (buffer->isInUse()) {
|
||||||
// Simple case: The buffer is currently not being
|
|
||||||
// used by the device, we can return the pointer.
|
|
||||||
pMappedSubresource->pData = buffer->mapPtr(0);
|
|
||||||
pMappedSubresource->RowPitch = buffer->info().size;
|
|
||||||
pMappedSubresource->DepthPitch = buffer->info().size;
|
|
||||||
return S_OK;
|
|
||||||
} else {
|
|
||||||
// Don't wait if the application tells us not to
|
// Don't wait if the application tells us not to
|
||||||
if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT)
|
if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT)
|
||||||
return DXGI_ERROR_WAS_STILL_DRAWING;
|
return DXGI_ERROR_WAS_STILL_DRAWING;
|
||||||
|
|
||||||
// TODO optimize this. In order to properly cover common use cases
|
// Invalidate the buffer in order to avoid synchronization
|
||||||
// like frequent constant buffer updates, we must implement buffer
|
// if the application does not need the buffer contents to
|
||||||
// renaming techniques. The current approach is inefficient as it
|
// be preserved. The No Overwrite mode does not require any
|
||||||
// leads to a lot of Flush() and Synchronize() calls.
|
// sort of synchronization, but should be used with care.
|
||||||
//
|
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||||
// Possible solution:
|
pContext->GetDXVKContext()->invalidateBuffer(m_buffer);
|
||||||
// (1) Create buffers with a significantly larger size if they
|
} else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
|
||||||
// can be mapped by the host for writing. If mapping the
|
pContext->Flush();
|
||||||
// buffer would stall on D3D11_MAP_WRITE_DISCARD, map the
|
pContext->Synchronize();
|
||||||
// next slice. on D3D11_MAP_WRITE_NO_OVERWRITE, return the
|
}
|
||||||
// current slice. If the buffer is bound, update bindings.
|
|
||||||
// (2) If no more slices are available, create a new buffer.
|
|
||||||
// Limit the number of buffers to a small, fixed number.
|
|
||||||
// (3) If no more buffers are available, flush and synchronize.
|
|
||||||
// (4) When renaming the buffer internally, all active bindings
|
|
||||||
// need to be updated internally as well.
|
|
||||||
//
|
|
||||||
// In order to support deferred contexts, the immediate context
|
|
||||||
// must commit all changes to the initial buffer slice prior to
|
|
||||||
// executing a command list. When mapping on deferred contexts,
|
|
||||||
// the deferred context shall create local buffer objects.
|
|
||||||
pContext->Flush();
|
|
||||||
pContext->Synchronize();
|
|
||||||
|
|
||||||
pMappedSubresource->pData = buffer->mapPtr(0);
|
|
||||||
pMappedSubresource->RowPitch = buffer->info().size;
|
|
||||||
pMappedSubresource->DepthPitch = buffer->info().size;
|
|
||||||
return S_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pMappedSubresource->pData = buffer->mapPtr(0);
|
||||||
|
pMappedSubresource->RowPitch = buffer->info().size;
|
||||||
|
pMappedSubresource->DepthPitch = buffer->info().size;
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
#include "dxvk_buffer.h"
|
#include "dxvk_buffer.h"
|
||||||
|
#include "dxvk_device.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
DxvkBuffer::DxvkBuffer(
|
DxvkBufferResource::DxvkBufferResource(
|
||||||
const Rc<vk::DeviceFn>& vkd,
|
const Rc<vk::DeviceFn>& vkd,
|
||||||
const DxvkBufferCreateInfo& createInfo,
|
const DxvkBufferCreateInfo& createInfo,
|
||||||
DxvkMemoryAllocator& memAlloc,
|
DxvkMemoryAllocator& memAlloc,
|
||||||
VkMemoryPropertyFlags memFlags)
|
VkMemoryPropertyFlags memFlags)
|
||||||
: m_vkd(vkd), m_info(createInfo) {
|
: m_vkd(vkd) {
|
||||||
|
|
||||||
VkBufferCreateInfo info;
|
VkBufferCreateInfo info;
|
||||||
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
@ -34,12 +35,28 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkBuffer::~DxvkBuffer() {
|
DxvkBufferResource::~DxvkBufferResource() {
|
||||||
if (m_buffer != VK_NULL_HANDLE)
|
if (m_buffer != VK_NULL_HANDLE)
|
||||||
m_vkd->vkDestroyBuffer(m_vkd->device(), m_buffer, nullptr);
|
m_vkd->vkDestroyBuffer(m_vkd->device(), m_buffer, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBuffer::DxvkBuffer(
|
||||||
|
DxvkDevice* device,
|
||||||
|
const DxvkBufferCreateInfo& createInfo,
|
||||||
|
VkMemoryPropertyFlags memoryType)
|
||||||
|
: m_device (device),
|
||||||
|
m_info (createInfo),
|
||||||
|
m_memFlags(memoryType) {
|
||||||
|
this->allocateResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkBuffer::allocateResource() {
|
||||||
|
m_resource = m_device->allocBufferResource(m_info, m_memFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkBufferView::DxvkBufferView(
|
DxvkBufferView::DxvkBufferView(
|
||||||
const Rc<vk::DeviceFn>& vkd,
|
const Rc<vk::DeviceFn>& vkd,
|
||||||
const Rc<DxvkBuffer>& buffer,
|
const Rc<DxvkBuffer>& buffer,
|
||||||
|
@ -47,30 +47,54 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Buffer resource
|
* \brief Physical buffer resource
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class DxvkBufferResource : public DxvkResource {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxvkBufferResource(
|
||||||
|
const Rc<vk::DeviceFn>& vkd,
|
||||||
|
const DxvkBufferCreateInfo& createInfo,
|
||||||
|
DxvkMemoryAllocator& memAlloc,
|
||||||
|
VkMemoryPropertyFlags memFlags);
|
||||||
|
|
||||||
|
~DxvkBufferResource();
|
||||||
|
|
||||||
|
VkBuffer handle() const {
|
||||||
|
return m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* mapPtr(VkDeviceSize offset) const {
|
||||||
|
return m_memory.mapPtr(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Rc<vk::DeviceFn> m_vkd;
|
||||||
|
DxvkMemory m_memory;
|
||||||
|
VkBuffer m_buffer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Virtual buffer resource
|
||||||
*
|
*
|
||||||
* A simple buffer resource that stores linear,
|
* A simple buffer resource that stores linear,
|
||||||
* unformatted data. Can be accessed by the host
|
* unformatted data. Can be accessed by the host
|
||||||
* if allocated on an appropriate memory type.
|
* if allocated on an appropriate memory type.
|
||||||
*/
|
*/
|
||||||
class DxvkBuffer : public DxvkResource {
|
class DxvkBuffer : public RcObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxvkBuffer(
|
DxvkBuffer(
|
||||||
const Rc<vk::DeviceFn>& vkd,
|
DxvkDevice* device,
|
||||||
const DxvkBufferCreateInfo& createInfo,
|
const DxvkBufferCreateInfo& createInfo,
|
||||||
DxvkMemoryAllocator& memAlloc,
|
VkMemoryPropertyFlags memoryType);
|
||||||
VkMemoryPropertyFlags memFlags);
|
|
||||||
~DxvkBuffer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Buffer handle
|
|
||||||
* \returns Buffer handle
|
|
||||||
*/
|
|
||||||
VkBuffer handle() const {
|
|
||||||
return m_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Buffer properties
|
* \brief Buffer properties
|
||||||
@ -80,6 +104,14 @@ namespace dxvk {
|
|||||||
return m_info;
|
return m_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Buffer handle
|
||||||
|
* \returns Buffer handle
|
||||||
|
*/
|
||||||
|
VkBuffer handle() const {
|
||||||
|
return m_resource->handle();;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Map pointer
|
* \brief Map pointer
|
||||||
*
|
*
|
||||||
@ -90,15 +122,49 @@ namespace dxvk {
|
|||||||
* \returns Pointer to mapped memory region
|
* \returns Pointer to mapped memory region
|
||||||
*/
|
*/
|
||||||
void* mapPtr(VkDeviceSize offset) const {
|
void* mapPtr(VkDeviceSize offset) const {
|
||||||
return m_memory.mapPtr(offset);
|
return m_resource->mapPtr(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checks whether the buffer is in use
|
||||||
|
*
|
||||||
|
* Returns \c true if the underlying buffer resource
|
||||||
|
* is in use. If it is, it should not be accessed by
|
||||||
|
* the host for reading or writing, but reallocating
|
||||||
|
* the buffer is a valid strategy to overcome this.
|
||||||
|
* \returns \c true if the buffer is in use
|
||||||
|
*/
|
||||||
|
bool isInUse() const {
|
||||||
|
return m_resource->isInUse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Underlying buffer resource
|
||||||
|
*
|
||||||
|
* Use this for lifetime tracking.
|
||||||
|
* \returns The resource object
|
||||||
|
*/
|
||||||
|
Rc<DxvkResource> resource() const {
|
||||||
|
return m_resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Allocates new backing resource
|
||||||
|
*
|
||||||
|
* Replaces the underlying buffer and implicitly marks
|
||||||
|
* any buffer views using this resource as dirty. Do
|
||||||
|
* not call this directly as this is called implicitly
|
||||||
|
* by the context's \c invalidateBuffer method.
|
||||||
|
*/
|
||||||
|
void allocateResource();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Rc<vk::DeviceFn> m_vkd;
|
DxvkDevice* m_device;
|
||||||
DxvkBufferCreateInfo m_info;
|
DxvkBufferCreateInfo m_info;
|
||||||
DxvkMemory m_memory;
|
VkMemoryPropertyFlags m_memFlags;
|
||||||
VkBuffer m_buffer = VK_NULL_HANDLE;
|
|
||||||
|
Rc<DxvkBufferResource> m_resource;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -310,8 +310,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
m_barriers.recordCommands(m_cmd);
|
m_barriers.recordCommands(m_cmd);
|
||||||
|
|
||||||
m_cmd->trackResource(dstBuffer);
|
m_cmd->trackResource(dstBuffer->resource());
|
||||||
m_cmd->trackResource(srcBuffer);
|
m_cmd->trackResource(srcBuffer->resource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,6 +368,29 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkContext::invalidateBuffer(const Rc<DxvkBuffer>& buffer) {
|
||||||
|
// Allocate new backing resource
|
||||||
|
buffer->allocateResource();
|
||||||
|
|
||||||
|
// We also need to update all bindings that the buffer
|
||||||
|
// may be bound to either directly or through views.
|
||||||
|
const VkBufferUsageFlags usage = buffer->info().usage;
|
||||||
|
|
||||||
|
if (usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT)
|
||||||
|
m_flags.set(DxvkContextFlag::GpDirtyIndexBuffer);
|
||||||
|
|
||||||
|
if (usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
|
||||||
|
m_flags.set(DxvkContextFlag::GpDirtyVertexBuffers);
|
||||||
|
|
||||||
|
if (usage & (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
||||||
|
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
||||||
|
| VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT
|
||||||
|
| VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT))
|
||||||
|
m_flags.set(DxvkContextFlag::GpDirtyResources,
|
||||||
|
DxvkContextFlag::CpDirtyResources);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkContext::resolveImage(
|
void DxvkContext::resolveImage(
|
||||||
const Rc<DxvkImage>& dstImage,
|
const Rc<DxvkImage>& dstImage,
|
||||||
const VkImageSubresourceLayers& dstSubresources,
|
const VkImageSubresourceLayers& dstSubresources,
|
||||||
@ -471,7 +494,7 @@ namespace dxvk {
|
|||||||
buffer->info().access);
|
buffer->info().access);
|
||||||
m_barriers.recordCommands(m_cmd);
|
m_barriers.recordCommands(m_cmd);
|
||||||
|
|
||||||
m_cmd->trackResource(buffer);
|
m_cmd->trackResource(buffer->resource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -785,7 +808,6 @@ namespace dxvk {
|
|||||||
gpState.rsDepthBiasSlope = m_state.rs.depthBiasSlope;
|
gpState.rsDepthBiasSlope = m_state.rs.depthBiasSlope;
|
||||||
gpState.rsViewportCount = m_state.vp.viewportCount;
|
gpState.rsViewportCount = m_state.vp.viewportCount;
|
||||||
|
|
||||||
// TODO implement multisampling support properly
|
|
||||||
gpState.msSampleCount = m_state.om.framebuffer->sampleCount();
|
gpState.msSampleCount = m_state.om.framebuffer->sampleCount();
|
||||||
gpState.msSampleMask = m_state.ms.sampleMask;
|
gpState.msSampleMask = m_state.ms.sampleMask;
|
||||||
gpState.msEnableAlphaToCoverage = m_state.ms.enableAlphaToCoverage;
|
gpState.msEnableAlphaToCoverage = m_state.ms.enableAlphaToCoverage;
|
||||||
@ -837,6 +859,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
auto layout = m_state.cp.pipeline->layout();
|
auto layout = m_state.cp.pipeline->layout();
|
||||||
|
|
||||||
|
// TODO refcount used resources
|
||||||
|
|
||||||
m_cmd->bindResourceDescriptors(
|
m_cmd->bindResourceDescriptors(
|
||||||
VK_PIPELINE_BIND_POINT_COMPUTE,
|
VK_PIPELINE_BIND_POINT_COMPUTE,
|
||||||
layout->pipelineLayout(),
|
layout->pipelineLayout(),
|
||||||
@ -904,7 +928,7 @@ namespace dxvk {
|
|||||||
m_state.vi.indexBuffer.offset(),
|
m_state.vi.indexBuffer.offset(),
|
||||||
m_state.vi.indexType);
|
m_state.vi.indexType);
|
||||||
m_cmd->trackResource(
|
m_cmd->trackResource(
|
||||||
m_state.vi.indexBuffer.buffer());
|
m_state.vi.indexBuffer.buffer()->resource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -922,7 +946,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
if (handle != VK_NULL_HANDLE) {
|
if (handle != VK_NULL_HANDLE) {
|
||||||
m_cmd->cmdBindVertexBuffers(i, 1, &handle, &offset);
|
m_cmd->cmdBindVertexBuffers(i, 1, &handle, &offset);
|
||||||
m_cmd->trackResource(vbo.buffer());
|
m_cmd->trackResource(vbo.buffer()->resource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,8 +244,23 @@ namespace dxvk {
|
|||||||
* \param [in] subresources Image subresources
|
* \param [in] subresources Image subresources
|
||||||
*/
|
*/
|
||||||
void initImage(
|
void initImage(
|
||||||
const Rc<DxvkImage>& image,
|
const Rc<DxvkImage>& image,
|
||||||
const VkImageSubresourceRange& subresources);
|
const VkImageSubresourceRange& subresources);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Invalidates a buffer's contents
|
||||||
|
*
|
||||||
|
* Discards a buffer's contents by allocating a new
|
||||||
|
* backing resource. This allows the host to access
|
||||||
|
* the buffer while the GPU is still accessing the
|
||||||
|
* original backing resource.
|
||||||
|
*
|
||||||
|
* \warning If the buffer is used by another context,
|
||||||
|
* invalidating it will result in undefined behaviour.
|
||||||
|
* \param [in] buffer The buffer to invalidate
|
||||||
|
*/
|
||||||
|
void invalidateBuffer(
|
||||||
|
const Rc<DxvkBuffer>& buffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Resolves a multisampled image resource
|
* \brief Resolves a multisampled image resource
|
||||||
|
@ -29,6 +29,14 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Rc<DxvkBufferResource> DxvkDevice::allocBufferResource(
|
||||||
|
const DxvkBufferCreateInfo& createInfo,
|
||||||
|
VkMemoryPropertyFlags memoryType) {
|
||||||
|
return new DxvkBufferResource(m_vkd,
|
||||||
|
createInfo, *m_memory, memoryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Rc<DxvkStagingBuffer> DxvkDevice::allocStagingBuffer(VkDeviceSize size) {
|
Rc<DxvkStagingBuffer> DxvkDevice::allocStagingBuffer(VkDeviceSize size) {
|
||||||
// In case we need a standard-size staging buffer, try
|
// In case we need a standard-size staging buffer, try
|
||||||
// to recycle an old one that has been returned earlier
|
// to recycle an old one that has been returned earlier
|
||||||
@ -102,9 +110,7 @@ namespace dxvk {
|
|||||||
const DxvkBufferCreateInfo& createInfo,
|
const DxvkBufferCreateInfo& createInfo,
|
||||||
VkMemoryPropertyFlags memoryType) {
|
VkMemoryPropertyFlags memoryType) {
|
||||||
m_statCounters.increment(DxvkStat::ResBufferCreations, 1);
|
m_statCounters.increment(DxvkStat::ResBufferCreations, 1);
|
||||||
|
return new DxvkBuffer(this, createInfo, memoryType);
|
||||||
return new DxvkBuffer(m_vkd,
|
|
||||||
createInfo, *m_memory, memoryType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -119,9 +125,7 @@ namespace dxvk {
|
|||||||
const DxvkImageCreateInfo& createInfo,
|
const DxvkImageCreateInfo& createInfo,
|
||||||
VkMemoryPropertyFlags memoryType) {
|
VkMemoryPropertyFlags memoryType) {
|
||||||
m_statCounters.increment(DxvkStat::ResImageCreations, 1);
|
m_statCounters.increment(DxvkStat::ResImageCreations, 1);
|
||||||
|
return new DxvkImage(m_vkd, createInfo, *m_memory, memoryType);
|
||||||
return new DxvkImage(m_vkd,
|
|
||||||
createInfo, *m_memory, memoryType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,6 +75,17 @@ namespace dxvk {
|
|||||||
return m_features;
|
return m_features;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Allocates buffer resource
|
||||||
|
*
|
||||||
|
* \param [in] createInfo Buffer create info
|
||||||
|
* \param [in] memoryType Memory property flags
|
||||||
|
* \returns The buffer resource object
|
||||||
|
*/
|
||||||
|
Rc<DxvkBufferResource> allocBufferResource(
|
||||||
|
const DxvkBufferCreateInfo& createInfo,
|
||||||
|
VkMemoryPropertyFlags memoryType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Allocates a staging buffer
|
* \brief Allocates a staging buffer
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user