mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-19 05:52:11 +01:00
[dxvk] Reimplement DxvkBuffer
Avoids the DxvkPhysicalBuffer indirection and keeps all buffer objects alive until the DxvkBuffer itself gets destroyed.
This commit is contained in:
parent
cc61e38b9c
commit
8b5db80fbd
@ -98,7 +98,7 @@ namespace dxvk {
|
||||
// Create the buffer and set the entire buffer slice as mapped,
|
||||
// so that we only have to update it when invalidating th buffer
|
||||
m_buffer = m_device->GetDXVKDevice()->createBuffer(info, memoryFlags);
|
||||
m_mapped = m_buffer->slice();
|
||||
m_mapped = m_buffer->getSliceHandle();
|
||||
|
||||
// For Stream Output buffers we need a counter
|
||||
if (pDesc->BindFlags & D3D11_BIND_STREAM_OUTPUT)
|
||||
|
@ -79,12 +79,12 @@ namespace dxvk {
|
||||
return m_soCounter;
|
||||
}
|
||||
|
||||
DxvkPhysicalBufferSlice DiscardSlice() {
|
||||
m_mapped = m_buffer->allocPhysicalSlice();
|
||||
DxvkBufferSliceHandle DiscardSlice() {
|
||||
m_mapped = m_buffer->allocSlice();
|
||||
return m_mapped;
|
||||
}
|
||||
|
||||
DxvkPhysicalBufferSlice GetMappedSlice() const {
|
||||
DxvkBufferSliceHandle GetMappedSlice() const {
|
||||
return m_mapped;
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ namespace dxvk {
|
||||
|
||||
Rc<DxvkBuffer> m_buffer;
|
||||
DxvkBufferSlice m_soCounter;
|
||||
DxvkPhysicalBufferSlice m_mapped;
|
||||
DxvkBufferSliceHandle m_mapped;
|
||||
|
||||
D3D10Buffer m_d3d10;
|
||||
|
||||
|
@ -181,9 +181,9 @@ namespace dxvk {
|
||||
if (pBuffer->Desc()->Usage == D3D11_USAGE_DYNAMIC && m_csFlags.test(DxvkCsChunkFlag::SingleUse)) {
|
||||
// For resources that cannot be written by the GPU,
|
||||
// we may write to the buffer resource directly and
|
||||
// just swap in the physical buffer slice as needed.
|
||||
pMapEntry->BufferSlice = buffer->allocPhysicalSlice();
|
||||
pMapEntry->MapPointer = pMapEntry->BufferSlice.mapPtr(0);
|
||||
// just swap in the buffer slice as needed.
|
||||
pMapEntry->BufferSlice = buffer->allocSlice();
|
||||
pMapEntry->MapPointer = pMapEntry->BufferSlice.mapPtr;
|
||||
} else {
|
||||
// For GPU-writable resources, we need a data slice
|
||||
// to perform the update operation at execution time.
|
||||
@ -257,8 +257,8 @@ namespace dxvk {
|
||||
cDstBuffer = pBuffer->GetBuffer(),
|
||||
cDataSlice = pMapEntry->DataSlice
|
||||
] (DxvkContext* ctx) {
|
||||
DxvkPhysicalBufferSlice slice = cDstBuffer->allocPhysicalSlice();
|
||||
std::memcpy(slice.mapPtr(0), cDataSlice.ptr(), cDataSlice.length());
|
||||
DxvkBufferSliceHandle slice = cDstBuffer->allocSlice();
|
||||
std::memcpy(slice.mapPtr, cDataSlice.ptr(), cDataSlice.length());
|
||||
ctx->invalidateBuffer(cDstBuffer, slice);
|
||||
});
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace dxvk {
|
||||
UINT RowPitch;
|
||||
UINT DepthPitch;
|
||||
DxvkDataSlice DataSlice;
|
||||
DxvkPhysicalBufferSlice BufferSlice;
|
||||
DxvkBufferSliceHandle BufferSlice;
|
||||
void* MapPointer;
|
||||
};
|
||||
|
||||
|
@ -351,32 +351,32 @@ namespace dxvk {
|
||||
// Allocate a new backing slice for the buffer and set
|
||||
// it as the 'new' mapped slice. This assumes that the
|
||||
// only way to invalidate a buffer is by mapping it.
|
||||
auto physicalSlice = pResource->DiscardSlice();
|
||||
pMappedResource->pData = physicalSlice.mapPtr(0);
|
||||
auto physSlice = pResource->DiscardSlice();
|
||||
pMappedResource->pData = physSlice.mapPtr;
|
||||
pMappedResource->RowPitch = pResource->Desc()->ByteWidth;
|
||||
pMappedResource->DepthPitch = pResource->Desc()->ByteWidth;
|
||||
|
||||
EmitCs([
|
||||
cBuffer = std::move(buffer),
|
||||
cPhysicalSlice = std::move(physicalSlice)
|
||||
cBuffer = std::move(buffer),
|
||||
cBufferSlice = std::move(physSlice)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cBuffer, cPhysicalSlice);
|
||||
ctx->invalidateBuffer(cBuffer, cBufferSlice);
|
||||
});
|
||||
|
||||
return S_OK;
|
||||
} else {
|
||||
// Wait until the resource is no longer in use
|
||||
if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
|
||||
if (!WaitForResource(buffer->resource(), MapFlags))
|
||||
if (!WaitForResource(buffer, MapFlags))
|
||||
return DXGI_ERROR_WAS_STILL_DRAWING;
|
||||
}
|
||||
|
||||
// Use map pointer from previous map operation. This
|
||||
// way we don't have to synchronize with the CS thread
|
||||
// if the map mode is D3D11_MAP_WRITE_NO_OVERWRITE.
|
||||
DxvkPhysicalBufferSlice physicalSlice = pResource->GetMappedSlice();
|
||||
DxvkBufferSliceHandle physSlice = pResource->GetMappedSlice();
|
||||
|
||||
pMappedResource->pData = physicalSlice.mapPtr(0);
|
||||
pMappedResource->pData = physSlice.mapPtr;
|
||||
pMappedResource->RowPitch = pResource->Desc()->ByteWidth;
|
||||
pMappedResource->DepthPitch = pResource->Desc()->ByteWidth;
|
||||
return S_OK;
|
||||
@ -449,10 +449,10 @@ namespace dxvk {
|
||||
cImageBuffer, 0, cImage, layers, offset, extent, cFormat);
|
||||
});
|
||||
|
||||
WaitForResource(mappedBuffer->resource(), 0);
|
||||
WaitForResource(mappedBuffer, 0);
|
||||
|
||||
DxvkPhysicalBufferSlice physicalSlice = mappedBuffer->slice();
|
||||
pMappedResource->pData = physicalSlice.mapPtr(0);
|
||||
DxvkBufferSliceHandle physSlice = mappedBuffer->getSliceHandle();
|
||||
pMappedResource->pData = physSlice.mapPtr;
|
||||
pMappedResource->RowPitch = packFormatInfo->elementSize * levelExtent.width;
|
||||
pMappedResource->DepthPitch = packFormatInfo->elementSize * levelExtent.width * levelExtent.height;
|
||||
return S_OK;
|
||||
@ -460,18 +460,18 @@ namespace dxvk {
|
||||
VkExtent3D levelExtent = mappedImage->mipLevelExtent(subresource.mipLevel);
|
||||
VkExtent3D blockCount = util::computeBlockCount(levelExtent, formatInfo->blockSize);
|
||||
|
||||
DxvkPhysicalBufferSlice physicalSlice;
|
||||
DxvkBufferSliceHandle physSlice;
|
||||
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
// We do not have to preserve the contents of the
|
||||
// buffer if the entire image gets discarded.
|
||||
physicalSlice = mappedBuffer->allocPhysicalSlice();
|
||||
physSlice = mappedBuffer->allocSlice();
|
||||
|
||||
EmitCs([
|
||||
cImageBuffer = mappedBuffer,
|
||||
cPhysicalSlice = physicalSlice
|
||||
cImageBuffer = mappedBuffer,
|
||||
cBufferSlice = physSlice
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cImageBuffer, cPhysicalSlice);
|
||||
ctx->invalidateBuffer(cImageBuffer, cBufferSlice);
|
||||
});
|
||||
} else {
|
||||
// When using any map mode which requires the image contents
|
||||
@ -495,12 +495,12 @@ namespace dxvk {
|
||||
});
|
||||
}
|
||||
|
||||
WaitForResource(mappedBuffer->resource(), 0);
|
||||
physicalSlice = mappedBuffer->slice();
|
||||
WaitForResource(mappedBuffer, 0);
|
||||
physSlice = mappedBuffer->getSliceHandle();
|
||||
}
|
||||
|
||||
// Set up map pointer. Data is tightly packed within the mapped buffer.
|
||||
pMappedResource->pData = physicalSlice.mapPtr(0);
|
||||
pMappedResource->pData = physSlice.mapPtr;
|
||||
pMappedResource->RowPitch = formatInfo->elementSize * blockCount.width;
|
||||
pMappedResource->DepthPitch = formatInfo->elementSize * blockCount.width * blockCount.height;
|
||||
return S_OK;
|
||||
|
@ -6,27 +6,37 @@ namespace dxvk {
|
||||
DxvkBuffer::DxvkBuffer(
|
||||
DxvkDevice* device,
|
||||
const DxvkBufferCreateInfo& createInfo,
|
||||
VkMemoryPropertyFlags memoryType)
|
||||
DxvkMemoryAllocator& memAlloc,
|
||||
VkMemoryPropertyFlags memFlags)
|
||||
: m_device (device),
|
||||
m_info (createInfo),
|
||||
m_memFlags (memoryType) {
|
||||
// Align physical buffer slices to 256 bytes, which guarantees
|
||||
// that we don't violate any Vulkan alignment requirements
|
||||
m_memAlloc (&memAlloc),
|
||||
m_memFlags (memFlags) {
|
||||
// Align slices to 256 bytes, which guarantees that
|
||||
// we don't violate any Vulkan alignment requirements
|
||||
m_physSliceLength = createInfo.size;
|
||||
m_physSliceStride = align(createInfo.size, 256);
|
||||
|
||||
// Allocate a single buffer slice
|
||||
m_physSlice = this->allocPhysicalBuffer(1)
|
||||
->slice(0, m_physSliceStride);
|
||||
m_buffer = allocBuffer(1);
|
||||
|
||||
m_physSlice.handle = m_buffer.buffer;
|
||||
m_physSlice.offset = 0;
|
||||
m_physSlice.length = m_physSliceLength;
|
||||
m_physSlice.mapPtr = m_buffer.memory.mapPtr(0);
|
||||
}
|
||||
|
||||
|
||||
DxvkBuffer::~DxvkBuffer() {
|
||||
|
||||
auto vkd = m_device->vkd();
|
||||
|
||||
for (const auto& buffer : m_buffers)
|
||||
vkd->vkDestroyBuffer(vkd->device(), buffer.buffer, nullptr);
|
||||
vkd->vkDestroyBuffer(vkd->device(), m_buffer.buffer, nullptr);
|
||||
}
|
||||
|
||||
|
||||
DxvkPhysicalBufferSlice DxvkBuffer::allocPhysicalSlice() {
|
||||
DxvkBufferSliceHandle DxvkBuffer::allocSlice() {
|
||||
std::unique_lock<sync::Spinlock> freeLock(m_freeMutex);
|
||||
|
||||
// If no slices are available, swap the two free lists.
|
||||
@ -34,47 +44,99 @@ namespace dxvk {
|
||||
std::unique_lock<sync::Spinlock> swapLock(m_swapMutex);
|
||||
std::swap(m_freeSlices, m_nextSlices);
|
||||
}
|
||||
|
||||
|
||||
// If there are still no slices available, create a new
|
||||
// physical buffer and add all slices to the free list.
|
||||
// backing buffer and add all slices to the free list.
|
||||
if (m_freeSlices.size() == 0) {
|
||||
std::unique_lock<sync::Spinlock> swapLock(m_swapMutex);
|
||||
m_physBuffer = this->allocPhysicalBuffer(m_physSliceCount);
|
||||
DxvkBufferHandle handle = allocBuffer(m_physSliceCount);
|
||||
|
||||
for (uint32_t i = 0; i < m_physSliceCount; i++) {
|
||||
m_freeSlices.push_back(m_physBuffer->slice(
|
||||
m_physSliceStride * i,
|
||||
m_physSliceLength));
|
||||
DxvkBufferSliceHandle slice;
|
||||
slice.handle = handle.buffer;
|
||||
slice.offset = m_physSliceStride * i;
|
||||
slice.length = m_physSliceLength;
|
||||
slice.mapPtr = handle.memory.mapPtr(slice.offset);
|
||||
m_freeSlices.push_back(slice);
|
||||
}
|
||||
|
||||
m_buffers.push_back(std::move(handle));
|
||||
m_physSliceCount *= 2;
|
||||
}
|
||||
|
||||
// Take the first slice from the queue
|
||||
DxvkPhysicalBufferSlice result = std::move(m_freeSlices.back());
|
||||
DxvkBufferSliceHandle result = std::move(m_freeSlices.back());
|
||||
m_freeSlices.pop_back();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void DxvkBuffer::freePhysicalSlice(const DxvkPhysicalBufferSlice& slice) {
|
||||
void DxvkBuffer::freeSlice(const DxvkBufferSliceHandle& slice) {
|
||||
// Add slice to a separate free list to reduce lock contention.
|
||||
std::unique_lock<sync::Spinlock> swapLock(m_swapMutex);
|
||||
m_nextSlices.push_back(slice);
|
||||
}
|
||||
|
||||
|
||||
DxvkBufferHandle DxvkBuffer::allocBuffer(VkDeviceSize sliceCount) const {
|
||||
auto vkd = m_device->vkd();
|
||||
|
||||
// Discard slices allocated from other physical buffers.
|
||||
// This may make descriptor set binding more efficient.
|
||||
if (m_physBuffer->handle() == slice.handle())
|
||||
m_nextSlices.push_back(slice);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkPhysicalBuffer> DxvkBuffer::allocPhysicalBuffer(VkDeviceSize sliceCount) const {
|
||||
DxvkBufferCreateInfo createInfo = m_info;
|
||||
createInfo.size = sliceCount * m_physSliceStride;
|
||||
VkBufferCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.size = m_physSliceStride * sliceCount;
|
||||
info.usage = m_info.usage;
|
||||
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
info.queueFamilyIndexCount = 0;
|
||||
info.pQueueFamilyIndices = nullptr;
|
||||
|
||||
return m_device->allocPhysicalBuffer(createInfo, m_memFlags);
|
||||
DxvkBufferHandle handle;
|
||||
|
||||
if (vkd->vkCreateBuffer(vkd->device(),
|
||||
&info, nullptr, &handle.buffer) != VK_SUCCESS) {
|
||||
throw DxvkError(str::format(
|
||||
"DxvkBuffer: Failed to create buffer:"
|
||||
"\n size: ", info.size,
|
||||
"\n usage: ", info.usage));
|
||||
}
|
||||
|
||||
VkMemoryDedicatedRequirementsKHR dedicatedRequirements;
|
||||
dedicatedRequirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR;
|
||||
dedicatedRequirements.pNext = VK_NULL_HANDLE;
|
||||
dedicatedRequirements.prefersDedicatedAllocation = VK_FALSE;
|
||||
dedicatedRequirements.requiresDedicatedAllocation = VK_FALSE;
|
||||
|
||||
VkMemoryRequirements2KHR memReq;
|
||||
memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR;
|
||||
memReq.pNext = &dedicatedRequirements;
|
||||
|
||||
VkBufferMemoryRequirementsInfo2KHR memReqInfo;
|
||||
memReqInfo.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR;
|
||||
memReqInfo.buffer = handle.buffer;
|
||||
memReqInfo.pNext = VK_NULL_HANDLE;
|
||||
|
||||
VkMemoryDedicatedAllocateInfoKHR dedMemoryAllocInfo;
|
||||
dedMemoryAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
|
||||
dedMemoryAllocInfo.pNext = VK_NULL_HANDLE;
|
||||
dedMemoryAllocInfo.buffer = handle.buffer;
|
||||
dedMemoryAllocInfo.image = VK_NULL_HANDLE;
|
||||
|
||||
vkd->vkGetBufferMemoryRequirements2KHR(
|
||||
vkd->device(), &memReqInfo, &memReq);
|
||||
|
||||
bool useDedicated = dedicatedRequirements.prefersDedicatedAllocation;
|
||||
handle.memory = m_memAlloc->alloc(&memReq.memoryRequirements,
|
||||
useDedicated ? &dedMemoryAllocInfo : nullptr, m_memFlags);
|
||||
|
||||
if (vkd->vkBindBufferMemory(vkd->device(), handle.buffer,
|
||||
handle.memory.memory(), handle.memory.offset()) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkBuffer: Failed to bind device memory");
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
DxvkBufferView::DxvkBufferView(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
@ -132,7 +194,7 @@ namespace dxvk {
|
||||
|
||||
m_bufferSlice = m_buffer->getSliceHandle();
|
||||
auto entry = m_views.find(m_bufferSlice);
|
||||
|
||||
|
||||
if (entry != m_views.end()) {
|
||||
m_bufferView = entry->second;
|
||||
} else {
|
||||
@ -147,15 +209,15 @@ namespace dxvk {
|
||||
|
||||
|
||||
void DxvkBufferTracker::freeBufferSlice(
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
const DxvkPhysicalBufferSlice& slice) {
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
const DxvkBufferSliceHandle& slice) {
|
||||
m_entries.push_back({ buffer, slice });
|
||||
}
|
||||
|
||||
|
||||
void DxvkBufferTracker::reset() {
|
||||
for (const auto& e : m_entries)
|
||||
e.buffer->freePhysicalSlice(e.slice);
|
||||
e.buffer->freeSlice(e.slice);
|
||||
|
||||
m_entries.clear();
|
||||
}
|
||||
|
@ -8,6 +8,18 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Buffer info
|
||||
*
|
||||
* Stores a Vulkan buffer handle and the
|
||||
* memory object that is bound to the buffer.
|
||||
*/
|
||||
struct DxvkBufferHandle {
|
||||
VkBuffer buffer = VK_NULL_HANDLE;
|
||||
DxvkMemory memory;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Buffer slice info
|
||||
*
|
||||
@ -44,14 +56,15 @@ namespace dxvk {
|
||||
* unformatted data. Can be accessed by the host
|
||||
* if allocated on an appropriate memory type.
|
||||
*/
|
||||
class DxvkBuffer : public RcObject {
|
||||
class DxvkBuffer : public DxvkResource {
|
||||
friend class DxvkBufferView;
|
||||
public:
|
||||
|
||||
DxvkBuffer(
|
||||
DxvkDevice* device,
|
||||
const DxvkBufferCreateInfo& createInfo,
|
||||
VkMemoryPropertyFlags memoryType);
|
||||
DxvkMemoryAllocator& memAlloc,
|
||||
VkMemoryPropertyFlags memFlags);
|
||||
|
||||
~DxvkBuffer();
|
||||
|
||||
@ -84,33 +97,15 @@ namespace dxvk {
|
||||
* \returns Pointer to mapped memory region
|
||||
*/
|
||||
void* mapPtr(VkDeviceSize offset) const {
|
||||
return m_physSlice.mapPtr(offset);
|
||||
return reinterpret_cast<char*>(m_physSlice.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_physSlice.resource()->isInUse();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves slice handle
|
||||
* \returns Buffer slice handle
|
||||
*/
|
||||
DxvkBufferSliceHandle getSliceHandle() const {
|
||||
DxvkBufferSliceHandle result;
|
||||
result.handle = m_physSlice.handle();
|
||||
result.offset = m_physSlice.offset();
|
||||
result.length = m_physSlice.length();
|
||||
result.mapPtr = m_physSlice.mapPtr(0);
|
||||
return result;
|
||||
return m_physSlice;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,10 +117,10 @@ namespace dxvk {
|
||||
*/
|
||||
DxvkBufferSliceHandle getSliceHandle(VkDeviceSize offset, VkDeviceSize length) const {
|
||||
DxvkBufferSliceHandle result;
|
||||
result.handle = m_physSlice.handle();
|
||||
result.offset = m_physSlice.offset() + offset;
|
||||
result.handle = m_physSlice.handle;
|
||||
result.offset = m_physSlice.offset + offset;
|
||||
result.length = length;
|
||||
result.mapPtr = m_physSlice.mapPtr(offset);
|
||||
result.mapPtr = mapPtr(offset);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -138,8 +133,8 @@ namespace dxvk {
|
||||
*/
|
||||
DxvkDescriptorInfo getDescriptor(VkDeviceSize offset, VkDeviceSize length) const {
|
||||
DxvkDescriptorInfo result;
|
||||
result.buffer.buffer = m_physSlice.handle();
|
||||
result.buffer.offset = m_physSlice.offset() + offset;
|
||||
result.buffer.buffer = m_physSlice.handle;
|
||||
result.buffer.offset = m_physSlice.offset + offset;
|
||||
result.buffer.range = length;
|
||||
return result;
|
||||
}
|
||||
@ -148,43 +143,10 @@ namespace dxvk {
|
||||
* \brief Retrieves dynamic offset
|
||||
*
|
||||
* \param [in] offset Offset into the buffer
|
||||
* \returns Physical buffer slice offset
|
||||
* \returns Offset for dynamic descriptors
|
||||
*/
|
||||
VkDeviceSize getDynamicOffset(VkDeviceSize offset) const {
|
||||
return m_physSlice.offset() + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Underlying buffer resource
|
||||
*
|
||||
* Use this for lifetime tracking.
|
||||
* \returns The resource object
|
||||
*/
|
||||
Rc<DxvkResource> resource() const {
|
||||
return m_physSlice.resource();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Physical buffer slice
|
||||
*
|
||||
* Retrieves a slice into the physical
|
||||
* buffer which backs this buffer.
|
||||
* \returns The backing slice
|
||||
*/
|
||||
DxvkPhysicalBufferSlice slice() const {
|
||||
return m_physSlice;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Physical buffer sub slice
|
||||
*
|
||||
* Retrieves a sub slice into the backing buffer.
|
||||
* \param [in] offset Offset into the buffer
|
||||
* \param [in] length Length of the slice
|
||||
* \returns The sub slice
|
||||
*/
|
||||
DxvkPhysicalBufferSlice subSlice(VkDeviceSize offset, VkDeviceSize length) const {
|
||||
return m_physSlice.subSlice(offset, length);
|
||||
return m_physSlice.offset + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -197,10 +159,8 @@ namespace dxvk {
|
||||
* \param [in] slice The new backing resource
|
||||
* \returns Previous buffer slice
|
||||
*/
|
||||
DxvkPhysicalBufferSlice rename(const DxvkPhysicalBufferSlice& slice) {
|
||||
DxvkPhysicalBufferSlice prevSlice = std::move(m_physSlice);
|
||||
m_physSlice = slice;
|
||||
return prevSlice;
|
||||
DxvkBufferSliceHandle rename(const DxvkBufferSliceHandle& slice) {
|
||||
return std::exchange(m_physSlice, slice);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,45 +186,47 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocates new physical resource
|
||||
* \returns The new backing buffer slice
|
||||
* \brief Allocates new buffer slice
|
||||
* \returns The new buffer slice
|
||||
*/
|
||||
DxvkPhysicalBufferSlice allocPhysicalSlice();
|
||||
DxvkBufferSliceHandle allocSlice();
|
||||
|
||||
/**
|
||||
* \brief Frees a physical buffer slice
|
||||
* \brief Frees a buffer slice
|
||||
*
|
||||
* Marks the slice as free so that it can be used for
|
||||
* subsequent allocations. Called automatically when
|
||||
* the slice is no longer needed by the GPU.
|
||||
* \param [in] slice The buffer slice to free
|
||||
*/
|
||||
void freePhysicalSlice(
|
||||
const DxvkPhysicalBufferSlice& slice);
|
||||
void freeSlice(
|
||||
const DxvkBufferSliceHandle& slice);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
DxvkDevice* m_device;
|
||||
DxvkBufferCreateInfo m_info;
|
||||
DxvkMemoryAllocator* m_memAlloc;
|
||||
VkMemoryPropertyFlags m_memFlags;
|
||||
|
||||
DxvkPhysicalBufferSlice m_physSlice;
|
||||
DxvkBufferHandle m_buffer;
|
||||
DxvkBufferSliceHandle m_physSlice;
|
||||
|
||||
uint32_t m_vertexStride = 0;
|
||||
|
||||
sync::Spinlock m_freeMutex;
|
||||
sync::Spinlock m_swapMutex;
|
||||
|
||||
std::vector<DxvkPhysicalBufferSlice> m_freeSlices;
|
||||
std::vector<DxvkPhysicalBufferSlice> m_nextSlices;
|
||||
std::vector<DxvkBufferHandle> m_buffers;
|
||||
std::vector<DxvkBufferSliceHandle> m_freeSlices;
|
||||
std::vector<DxvkBufferSliceHandle> m_nextSlices;
|
||||
|
||||
VkDeviceSize m_physSliceLength = 0;
|
||||
VkDeviceSize m_physSliceStride = 0;
|
||||
VkDeviceSize m_physSliceCount = 2;
|
||||
|
||||
Rc<DxvkPhysicalBuffer> m_physBuffer;
|
||||
|
||||
Rc<DxvkPhysicalBuffer> allocPhysicalBuffer(
|
||||
VkDeviceSize sliceCount) const;
|
||||
DxvkBufferHandle allocBuffer(
|
||||
VkDeviceSize sliceCount) const;
|
||||
|
||||
};
|
||||
|
||||
@ -365,20 +327,6 @@ namespace dxvk {
|
||||
: DxvkBufferSliceHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Physical slice
|
||||
*
|
||||
* Retrieves the physical slice that currently
|
||||
* backs the virtual slice. This may change
|
||||
* when the virtual buffer gets invalidated.
|
||||
* \returns The physical buffer slice
|
||||
*/
|
||||
DxvkPhysicalBufferSlice physicalSlice() const {
|
||||
return m_buffer != nullptr
|
||||
? m_buffer->subSlice(m_offset, m_length)
|
||||
: DxvkPhysicalBufferSlice();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves descriptor info
|
||||
* \returns Buffer slice descriptor
|
||||
@ -409,14 +357,6 @@ namespace dxvk {
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Resource pointer
|
||||
* \returns Resource pointer
|
||||
*/
|
||||
Rc<DxvkResource> resource() const {
|
||||
return m_buffer->resource();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether two slices are equal
|
||||
*
|
||||
@ -502,14 +442,6 @@ namespace dxvk {
|
||||
const DxvkBufferCreateInfo& bufferInfo() const {
|
||||
return m_buffer->info();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Backing buffer resource
|
||||
* \returns Backing buffer resource
|
||||
*/
|
||||
Rc<DxvkResource> bufferResource() const {
|
||||
return m_buffer->resource();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves buffer slice handle
|
||||
@ -581,16 +513,16 @@ namespace dxvk {
|
||||
~DxvkBufferTracker();
|
||||
|
||||
void freeBufferSlice(
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
const DxvkPhysicalBufferSlice& slice);
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
const DxvkBufferSliceHandle& slice);
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
|
||||
struct Entry {
|
||||
Rc<DxvkBuffer> buffer;
|
||||
DxvkPhysicalBufferSlice slice;
|
||||
Rc<DxvkBuffer> buffer;
|
||||
DxvkBufferSliceHandle slice;
|
||||
};
|
||||
|
||||
std::vector<Entry> m_entries;
|
||||
|
@ -108,17 +108,17 @@ namespace dxvk {
|
||||
void endRecording();
|
||||
|
||||
/**
|
||||
* \brief Frees physical buffer slice
|
||||
* \brief Frees buffer slice
|
||||
*
|
||||
* After the command buffer execution has finished,
|
||||
* the given physical slice will be released to the
|
||||
* the given buffer slice will be released to the
|
||||
* virtual buffer object so that it can be reused.
|
||||
* \param [in] buffer The virtual buffer object
|
||||
* \param [in] slice The physical buffer slice
|
||||
* \param [in] slice The buffer slice handle
|
||||
*/
|
||||
void freePhysicalBufferSlice(
|
||||
void freeBufferSlice(
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
const DxvkPhysicalBufferSlice& slice) {
|
||||
const DxvkBufferSliceHandle& slice) {
|
||||
m_bufferTracker.freeBufferSlice(buffer, slice);
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ namespace dxvk {
|
||||
buffer->info().stages,
|
||||
buffer->info().access);
|
||||
|
||||
m_cmd->trackResource(buffer->resource());
|
||||
m_cmd->trackResource(buffer);
|
||||
}
|
||||
|
||||
|
||||
@ -347,7 +347,7 @@ namespace dxvk {
|
||||
bufferView->bufferInfo().access);
|
||||
|
||||
m_cmd->trackResource(bufferView);
|
||||
m_cmd->trackResource(bufferView->bufferResource());
|
||||
m_cmd->trackResource(bufferView->buffer());
|
||||
}
|
||||
|
||||
|
||||
@ -657,8 +657,8 @@ namespace dxvk {
|
||||
dstBuffer->info().stages,
|
||||
dstBuffer->info().access);
|
||||
|
||||
m_cmd->trackResource(dstBuffer->resource());
|
||||
m_cmd->trackResource(srcBuffer->resource());
|
||||
m_cmd->trackResource(dstBuffer);
|
||||
m_cmd->trackResource(srcBuffer);
|
||||
}
|
||||
|
||||
|
||||
@ -761,7 +761,7 @@ namespace dxvk {
|
||||
srcBuffer->info().access);
|
||||
|
||||
m_cmd->trackResource(dstImage);
|
||||
m_cmd->trackResource(srcBuffer->resource());
|
||||
m_cmd->trackResource(srcBuffer);
|
||||
}
|
||||
|
||||
|
||||
@ -920,7 +920,7 @@ namespace dxvk {
|
||||
dstBuffer->info().access);
|
||||
|
||||
m_cmd->trackResource(srcImage);
|
||||
m_cmd->trackResource(dstBuffer->resource());
|
||||
m_cmd->trackResource(dstBuffer);
|
||||
}
|
||||
|
||||
|
||||
@ -1030,14 +1030,14 @@ namespace dxvk {
|
||||
m_cmd->trackResource(sView);
|
||||
|
||||
m_cmd->trackResource(srcImage);
|
||||
m_cmd->trackResource(dstBuffer->resource());
|
||||
m_cmd->trackResource(dstBuffer);
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::discardBuffer(
|
||||
const Rc<DxvkBuffer>& buffer) {
|
||||
if (m_barriers.isBufferDirty(buffer->getSliceHandle(), DxvkAccess::Write))
|
||||
this->invalidateBuffer(buffer, buffer->allocPhysicalSlice());
|
||||
this->invalidateBuffer(buffer, buffer->allocSlice());
|
||||
}
|
||||
|
||||
|
||||
@ -1343,10 +1343,10 @@ namespace dxvk {
|
||||
|
||||
void DxvkContext::invalidateBuffer(
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
const DxvkPhysicalBufferSlice& slice) {
|
||||
const DxvkBufferSliceHandle& slice) {
|
||||
// Allocate new backing resource
|
||||
DxvkPhysicalBufferSlice prevSlice = buffer->rename(slice);
|
||||
m_cmd->freePhysicalBufferSlice(buffer, prevSlice);
|
||||
DxvkBufferSliceHandle prevSlice = buffer->rename(slice);
|
||||
m_cmd->freeBufferSlice(buffer, prevSlice);
|
||||
|
||||
// We also need to update all bindings that the buffer
|
||||
// may be bound to either directly or through views.
|
||||
@ -1372,7 +1372,7 @@ namespace dxvk {
|
||||
|
||||
if (usage & (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
||||
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)) {
|
||||
if (prevSlice.handle() != slice.handle()) {
|
||||
if (prevSlice.handle != slice.handle) {
|
||||
m_flags.set(DxvkContextFlag::GpDirtyResources,
|
||||
DxvkContextFlag::CpDirtyResources);
|
||||
} else {
|
||||
@ -1473,7 +1473,7 @@ namespace dxvk {
|
||||
buffer->info().stages,
|
||||
buffer->info().access);
|
||||
|
||||
m_cmd->trackResource(buffer->resource());
|
||||
m_cmd->trackResource(buffer);
|
||||
}
|
||||
|
||||
|
||||
@ -2464,7 +2464,7 @@ namespace dxvk {
|
||||
ctrOffsets[i] = physSlice.offset;
|
||||
|
||||
if (physSlice.handle != VK_NULL_HANDLE)
|
||||
m_cmd->trackResource(m_state.xfb.counters[i].resource());
|
||||
m_cmd->trackResource(m_state.xfb.counters[i].buffer());
|
||||
}
|
||||
|
||||
m_cmd->cmdBeginTransformFeedback(
|
||||
@ -2490,7 +2490,7 @@ namespace dxvk {
|
||||
ctrOffsets[i] = physSlice.offset;
|
||||
|
||||
if (physSlice.handle != VK_NULL_HANDLE)
|
||||
m_cmd->trackResource(m_state.xfb.counters[i].resource());
|
||||
m_cmd->trackResource(m_state.xfb.counters[i].buffer());
|
||||
}
|
||||
|
||||
m_queries.endQueries(m_cmd,
|
||||
@ -2767,7 +2767,7 @@ namespace dxvk {
|
||||
m_descInfos[i].texelBuffer = res.bufferView->handle();
|
||||
|
||||
m_cmd->trackResource(res.bufferView);
|
||||
m_cmd->trackResource(res.bufferView->bufferResource());
|
||||
m_cmd->trackResource(res.bufferView->buffer());
|
||||
} else {
|
||||
updatePipelineState |= bindMask.setUnbound(i);
|
||||
m_descInfos[i].texelBuffer = m_device->dummyBufferViewDescriptor();
|
||||
@ -2779,7 +2779,7 @@ namespace dxvk {
|
||||
updatePipelineState |= bindMask.setBound(i);
|
||||
m_descInfos[i] = res.bufferSlice.getDescriptor();
|
||||
|
||||
m_cmd->trackResource(res.bufferSlice.resource());
|
||||
m_cmd->trackResource(res.bufferSlice.buffer());
|
||||
} else {
|
||||
updatePipelineState |= bindMask.setUnbound(i);
|
||||
m_descInfos[i].buffer = m_device->dummyBufferDescriptor();
|
||||
@ -2792,7 +2792,7 @@ namespace dxvk {
|
||||
m_descInfos[i] = res.bufferSlice.getDescriptor();
|
||||
m_descInfos[i].buffer.offset = 0;
|
||||
|
||||
m_cmd->trackResource(res.bufferSlice.resource());
|
||||
m_cmd->trackResource(res.bufferSlice.buffer());
|
||||
} else {
|
||||
updatePipelineState |= bindMask.setUnbound(i);
|
||||
m_descInfos[i].buffer = m_device->dummyBufferDescriptor();
|
||||
@ -2887,7 +2887,7 @@ namespace dxvk {
|
||||
bufferInfo.buffer.offset,
|
||||
m_state.vi.indexType);
|
||||
m_cmd->trackResource(
|
||||
m_state.vi.indexBuffer.resource());
|
||||
m_state.vi.indexBuffer.buffer());
|
||||
} else {
|
||||
m_cmd->cmdBindIndexBuffer(
|
||||
m_device->dummyBufferHandle(),
|
||||
@ -2920,7 +2920,7 @@ namespace dxvk {
|
||||
|
||||
bindingMask |= 1u << binding;
|
||||
|
||||
m_cmd->trackResource(m_state.vi.vertexBuffers[binding].resource());
|
||||
m_cmd->trackResource(m_state.vi.vertexBuffers[binding].buffer());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2975,7 +2975,7 @@ namespace dxvk {
|
||||
auto buffer = m_state.xfb.buffers[i].buffer();
|
||||
buffer->setXfbVertexStride(gsOptions.xfbStrides[i]);
|
||||
|
||||
m_cmd->trackResource(buffer->resource());
|
||||
m_cmd->trackResource(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3291,7 +3291,7 @@ namespace dxvk {
|
||||
m_flags.clr(DxvkContextFlag::DirtyDrawBuffer);
|
||||
|
||||
if (m_state.id.argBuffer.defined())
|
||||
m_cmd->trackResource(m_state.id.argBuffer.resource());
|
||||
m_cmd->trackResource(m_state.id.argBuffer.buffer());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -575,11 +575,11 @@ namespace dxvk {
|
||||
* \warning If the buffer is used by another context,
|
||||
* invalidating it will result in undefined behaviour.
|
||||
* \param [in] buffer The buffer to invalidate
|
||||
* \param [in] slice New physical buffer slice
|
||||
* \param [in] slice New buffer slice handle
|
||||
*/
|
||||
void invalidateBuffer(
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
const DxvkPhysicalBufferSlice& slice);
|
||||
const DxvkBufferSliceHandle& slice);
|
||||
|
||||
/**
|
||||
* \brief Resolves a multisampled image resource
|
||||
|
@ -52,14 +52,6 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkPhysicalBuffer> DxvkDevice::allocPhysicalBuffer(
|
||||
const DxvkBufferCreateInfo& createInfo,
|
||||
VkMemoryPropertyFlags memoryType) {
|
||||
return new DxvkPhysicalBuffer(m_vkd,
|
||||
createInfo, *m_memory, memoryType);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkStagingBuffer> DxvkDevice::allocStagingBuffer(VkDeviceSize size) {
|
||||
// In case we need a standard-size staging buffer, try
|
||||
// to recycle an old one that has been returned earlier
|
||||
@ -155,7 +147,7 @@ namespace dxvk {
|
||||
Rc<DxvkBuffer> DxvkDevice::createBuffer(
|
||||
const DxvkBufferCreateInfo& createInfo,
|
||||
VkMemoryPropertyFlags memoryType) {
|
||||
return new DxvkBuffer(this, createInfo, memoryType);
|
||||
return new DxvkBuffer(this, createInfo, *m_memory, memoryType);
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,17 +139,6 @@ namespace dxvk {
|
||||
*/
|
||||
DxvkDeviceOptions options() const;
|
||||
|
||||
/**
|
||||
* \brief Allocates a physical buffer
|
||||
*
|
||||
* \param [in] createInfo Buffer create info
|
||||
* \param [in] memoryType Memory property flags
|
||||
* \returns The buffer resource object
|
||||
*/
|
||||
Rc<DxvkPhysicalBuffer> allocPhysicalBuffer(
|
||||
const DxvkBufferCreateInfo& createInfo,
|
||||
VkMemoryPropertyFlags memoryType);
|
||||
|
||||
/**
|
||||
* \brief Allocates a staging buffer
|
||||
*
|
||||
|
@ -103,8 +103,8 @@ namespace dxvk::hud {
|
||||
|
||||
|
||||
void Hud::updateUniformBuffer(const Rc<DxvkContext>& ctx, const HudUniformData& data) {
|
||||
auto slice = m_uniformBuffer->allocPhysicalSlice();
|
||||
std::memcpy(slice.mapPtr(0), &data, sizeof(data));
|
||||
auto slice = m_uniformBuffer->allocSlice();
|
||||
std::memcpy(slice.mapPtr, &data, sizeof(data));
|
||||
|
||||
ctx->invalidateBuffer(m_uniformBuffer, slice);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ namespace dxvk::hud {
|
||||
|
||||
|
||||
void HudRenderer::beginFrame(const Rc<DxvkContext>& context) {
|
||||
auto vertexSlice = m_vertexBuffer->allocPhysicalSlice();
|
||||
auto vertexSlice = m_vertexBuffer->allocSlice();
|
||||
context->invalidateBuffer(m_vertexBuffer, vertexSlice);
|
||||
|
||||
const std::array<DxvkVertexAttribute, 3> ilAttributes = {{
|
||||
|
Loading…
x
Reference in New Issue
Block a user