1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-21 21:57:39 +01:00

[dxvk] Rework buffer view creation

This commit is contained in:
Philip Rebohle 2024-09-23 22:10:12 +02:00 committed by Philip Rebohle
parent 1fd3c8040d
commit 088ba404a6
14 changed files with 178 additions and 262 deletions

View File

@ -339,7 +339,7 @@ namespace dxvk {
EmitCs([
cDstSlice = buf->GetBufferSlice(DstAlignedByteOffset),
cSrcSlice = counterView->slice()
cSrcSlice = DxvkBufferSlice(counterView)
] (DxvkContext* ctx) {
ctx->copyBuffer(
cDstSlice.buffer(),
@ -446,7 +446,7 @@ namespace dxvk {
|| bufferView->info().format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) {
EmitCs([
cClearValue = clearValue.color.uint32[0],
cDstSlice = bufferView->slice()
cDstSlice = DxvkBufferSlice(bufferView)
] (DxvkContext* ctx) {
ctx->clearBuffer(
cDstSlice.buffer(),
@ -460,8 +460,7 @@ namespace dxvk {
DxvkBufferViewCreateInfo info = bufferView->info();
info.format = rawFormat;
bufferView = m_device->createBufferView(
bufferView->buffer(), info);
bufferView = bufferView->buffer()->createView(info);
}
EmitCs([
@ -534,8 +533,7 @@ namespace dxvk {
bufferViewInfo.rangeLength = bufferInfo.size;
bufferViewInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
Rc<DxvkBufferView> bufferView = m_device->createBufferView(buffer,
bufferViewInfo);
Rc<DxvkBufferView> bufferView = buffer->createView(bufferViewInfo);
EmitCs([
cDstView = std::move(imageView),
@ -3781,7 +3779,7 @@ namespace dxvk {
: VK_SHADER_STAGE_ALL_GRAPHICS;
if (cCounterView != nullptr && cCounterValue != ~0u) {
auto counterSlice = cCounterView->slice();
DxvkBufferSlice counterSlice(cCounterView);
ctx->updateBuffer(
counterSlice.buffer(),

View File

@ -61,7 +61,7 @@ namespace dxvk {
if (counterView == nullptr)
return;
auto counterSlice = counterView->slice();
DxvkBufferSlice counterSlice(counterView);
std::lock_guard<dxvk::mutex> lock(m_mutex);
m_transferCommands += 1;

View File

@ -69,8 +69,7 @@ namespace dxvk {
m_info.Buffer.Length = viewInfo.rangeLength;
// Create underlying buffer view object
m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
buffer->GetBuffer(), viewInfo);
m_bufferView = buffer->GetBuffer()->createView(viewInfo);
} else {
auto texture = GetCommonTexture(pResource);
auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());

View File

@ -51,8 +51,7 @@ namespace dxvk {
m_info.Buffer.Offset = viewInfo.rangeOffset;
m_info.Buffer.Length = viewInfo.rangeLength;
m_bufferView = pDevice->GetDXVKDevice()->createBufferView(
buffer->GetBuffer(), viewInfo);
m_bufferView = buffer->GetBuffer()->createView(viewInfo);
} else {
auto texture = GetCommonTexture(pResource);
auto formatInfo = pDevice->LookupFormat(pDesc->Format, texture->GetFormatMode());
@ -457,7 +456,7 @@ namespace dxvk {
viewInfo.rangeLength = sizeof(uint32_t);
viewInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
return device->createBufferView(buffer, viewInfo);
return buffer->createView(viewInfo);
}
}

View File

@ -97,7 +97,7 @@ namespace dxvk {
bufferViewInfo.rangeOffset = srcSlice.offset();
bufferViewInfo.rangeLength = srcSlice.length();
bufferViewInfo.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
auto tmpBufferView = m_device->createBufferView(srcSlice.buffer(), bufferViewInfo);
auto tmpBufferView = srcSlice.buffer()->createView(bufferViewInfo);
m_context->setSpecConstant(VK_PIPELINE_BIND_POINT_COMPUTE, 0, specConstantValue);
m_context->bindResourceImageView(VK_SHADER_STAGE_COMPUTE_BIT, BindingIds::Image, std::move(tmpImageView));

View File

@ -41,80 +41,20 @@ namespace dxvk {
DxvkBufferView::DxvkBufferView(
DxvkDevice* device,
const Rc<DxvkBuffer>& buffer,
const DxvkBufferViewCreateInfo& info)
: m_vkd(device->vkd()), m_info(info), m_buffer(buffer),
m_usage (device->features().khrMaintenance5.maintenance5 ? info.usage : 0u),
m_bufferSlice (getSliceHandle()),
m_bufferView (VK_NULL_HANDLE) {
if (m_info.format != VK_FORMAT_UNDEFINED)
m_bufferView = createBufferView(m_bufferSlice);
}
DxvkBufferView::~DxvkBufferView() {
if (m_views.empty()) {
m_vkd->vkDestroyBufferView(
m_vkd->device(), m_bufferView, nullptr);
} else {
for (const auto& pair : m_views) {
m_vkd->vkDestroyBufferView(
m_vkd->device(), pair.second, nullptr);
}
}
}
VkBufferView DxvkBufferView::createBufferView(
const DxvkBufferSliceHandle& slice) {
VkBufferUsageFlags2CreateInfoKHR viewFlags = { VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO_KHR };
viewFlags.usage = m_usage;
Rc<DxvkBufferView> DxvkBuffer::createView(
const DxvkBufferViewCreateInfo& info) {
DxvkBufferViewKey key = { };
key.format = info.format;
key.offset = info.rangeOffset;
key.size = info.rangeLength;
key.usage = info.usage;
VkBufferViewCreateInfo viewInfo = { VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO };
viewInfo.buffer = slice.handle;
viewInfo.format = m_info.format;
viewInfo.offset = slice.offset;
viewInfo.range = slice.length;
std::unique_lock lock(m_viewMutex);
if (m_usage)
viewInfo.pNext = &viewFlags;
auto entry = m_views.emplace(std::piecewise_construct,
std::make_tuple(key), std::make_tuple(this, key));
VkBufferView result = VK_NULL_HANDLE;
if (m_vkd->vkCreateBufferView(m_vkd->device(),
&viewInfo, nullptr, &result) != VK_SUCCESS) {
throw DxvkError(str::format(
"DxvkBufferView: Failed to create buffer view:",
"\n Offset: ", viewInfo.offset,
"\n Range: ", viewInfo.range,
"\n Format: ", viewInfo.format));
}
return result;
return &entry.first->second;
}
void DxvkBufferView::updateBufferView(
const DxvkBufferSliceHandle& slice) {
if (m_info.format != VK_FORMAT_UNDEFINED) {
if (m_views.empty())
m_views.insert({ m_bufferSlice, m_bufferView });
m_bufferSlice = slice;
auto entry = m_views.find(slice);
if (entry != m_views.end()) {
m_bufferView = entry->second;
} else {
m_bufferView = createBufferView(m_bufferSlice);
m_views.insert({ m_bufferSlice, m_bufferView });
}
} else {
m_bufferSlice = slice;
}
}
}
}

View File

@ -12,6 +12,8 @@
namespace dxvk {
class DxvkBuffer;
/**
* \brief Buffer create info
*
@ -103,6 +105,87 @@ namespace dxvk {
};
/**
* \brief Virtual buffer view
*/
class DxvkBufferView : public DxvkResource {
public:
DxvkBufferView(
DxvkBuffer* buffer,
const DxvkBufferViewKey& key)
: m_buffer(buffer), m_key(key) { }
void incRef();
void decRef();
/**
* \brief Retrieves buffer view handle
*
* Creates a new view if the buffer has been invalidated.
* \returns Vulkan buffer view handle
*/
VkBufferView handle();
/**
* \brief Retrieves buffer slice handle
* \returns Buffer slice handle
*/
DxvkBufferSliceHandle getSliceHandle() const;
/**
* \brief Element count
*
* Number of typed elements contained in the buffer view.
* Depends on the buffer view format.
* \returns Element count
*/
VkDeviceSize elementCount() const {
auto format = lookupFormatInfo(m_key.format);
return m_key.size / format->elementSize;
}
/**
* \brief Buffer view properties
* \returns Buffer view properties
*/
DxvkBufferViewCreateInfo info() const {
DxvkBufferViewCreateInfo info = { };
info.format = m_key.format;
info.rangeOffset = m_key.offset;
info.rangeLength = m_key.size;
info.usage = m_key.usage;
return info;
}
/**
* \brief Underlying buffer object
* \returns Underlying buffer object
*/
DxvkBuffer* buffer() const {
return m_buffer;
}
/**
* \brief View format info
* \returns View format info
*/
const DxvkFormatInfo* formatInfo() const {
return lookupFormatInfo(m_key.format);
}
private:
DxvkBuffer* m_buffer = nullptr;
DxvkBufferViewKey m_key = { };
uint32_t m_version = 0u;
VkBufferView m_handle = VK_NULL_HANDLE;
};
/**
* \brief Virtual buffer resource
*
@ -111,7 +194,7 @@ namespace dxvk {
* if allocated on an appropriate memory type.
*/
class DxvkBuffer : public DxvkPagedResource {
friend class DxvkBufferView;
friend DxvkBufferView;
constexpr static VkDeviceSize MaxAllocationSize = DxvkPageAllocator::PageSize;
constexpr static VkDeviceSize MinAllocationSize = DxvkPoolAllocator::MinSize;
@ -273,6 +356,9 @@ namespace dxvk {
m_storage = std::move(slice);
m_bufferInfo = m_storage->getBufferInfo();
// Implicitly invalidate views
m_version += 1u;
return result;
}
@ -292,6 +378,15 @@ namespace dxvk {
return m_import.buffer != VK_NULL_HANDLE;
}
/**
* \brief Creates or retrieves a buffer view
*
* \param [in] info Buffer view create info
* \returns Newly created buffer view
*/
Rc<DxvkBufferView> createView(
const DxvkBufferViewCreateInfo& info);
private:
Rc<vk::DeviceFn> m_vkd;
@ -302,12 +397,17 @@ namespace dxvk {
DxvkBufferCreateInfo m_info = { };
DxvkBufferImportInfo m_import = { };
VkDeviceSize m_xfbStride = 0u;
uint32_t m_xfbStride = 0u;
uint32_t m_version = 0u;
DxvkResourceBufferInfo m_bufferInfo = { };
Rc<DxvkResourceAllocation> m_storage;
dxvk::mutex m_viewMutex;
std::unordered_map<DxvkBufferViewKey,
DxvkBufferView, DxvkHash, DxvkEq> m_views;
};
@ -323,17 +423,20 @@ namespace dxvk {
public:
DxvkBufferSlice() { }
DxvkBufferSlice(
const Rc<DxvkBuffer>& buffer,
Rc<DxvkBuffer> buffer,
VkDeviceSize rangeOffset,
VkDeviceSize rangeLength)
: m_buffer(buffer),
: m_buffer(std::move(buffer)),
m_offset(rangeOffset),
m_length(rangeLength) { }
explicit DxvkBufferSlice(const Rc<DxvkBuffer>& buffer)
: DxvkBufferSlice(buffer, 0, buffer->info().size) { }
explicit DxvkBufferSlice(Rc<DxvkBuffer> buffer)
: DxvkBufferSlice(std::move(buffer), 0, buffer->info().size) { }
explicit DxvkBufferSlice(const Rc<DxvkBufferView>& view)
: DxvkBufferSlice(view->buffer(), view->info().rangeOffset, view->info().rangeLength) { }
DxvkBufferSlice(const DxvkBufferSlice& ) = default;
DxvkBufferSlice( DxvkBufferSlice&&) = default;
@ -502,135 +605,31 @@ namespace dxvk {
VkDeviceSize m_length = 0;
};
/**
* \brief Buffer view
*
* Allows the application to interpret buffer
* contents like formatted pixel data. These
* buffer views are used as texel buffers.
*/
class DxvkBufferView : public DxvkResource {
public:
DxvkBufferView(
DxvkDevice* device,
const Rc<DxvkBuffer>& buffer,
const DxvkBufferViewCreateInfo& info);
~DxvkBufferView();
/**
* \brief Buffer view handle
* \returns Buffer view handle
*/
VkBufferView handle() const {
return m_bufferView;
}
/**
* \brief Element cound
*
* Number of typed elements contained
* in the buffer view. Depends on the
* buffer view format.
* \returns Element count
*/
VkDeviceSize elementCount() const {
auto format = lookupFormatInfo(m_info.format);
return m_info.rangeLength / format->elementSize;
}
/**
* \brief Buffer view properties
* \returns Buffer view properties
*/
const DxvkBufferViewCreateInfo& info() const {
return m_info;
}
/**
* \brief Underlying buffer object
* \returns Underlying buffer object
*/
const Rc<DxvkBuffer>& buffer() const {
return m_buffer;
}
/**
* \brief Underlying buffer info
* \returns Underlying buffer info
*/
const DxvkBufferCreateInfo& bufferInfo() const {
return m_buffer->info();
}
/**
* \brief View format info
* \returns View format info
*/
const DxvkFormatInfo* formatInfo() const {
return lookupFormatInfo(m_info.format);
}
/**
* \brief Retrieves buffer slice handle
* \returns Buffer slice handle
*/
DxvkBufferSliceHandle getSliceHandle() const {
return m_buffer->getSliceHandle(
m_info.rangeOffset,
m_info.rangeLength);
}
/**
* \brief Underlying buffer slice
* \returns Slice backing the view
*/
DxvkBufferSlice slice() const {
return DxvkBufferSlice(m_buffer,
m_info.rangeOffset,
m_info.rangeLength);
}
/**
* \brief Updates the buffer view
*
* If the buffer has been invalidated ever since
* the view was created, the view is invalid as
* well and needs to be re-created. Call this
* prior to using the buffer view handle.
*/
void updateView() {
DxvkBufferSliceHandle slice = getSliceHandle();
if (!m_bufferSlice.eq(slice))
this->updateBufferView(slice);
}
private:
Rc<vk::DeviceFn> m_vkd;
DxvkBufferViewCreateInfo m_info;
Rc<DxvkBuffer> m_buffer;
VkBufferUsageFlags m_usage;
DxvkBufferSliceHandle m_bufferSlice;
VkBufferView m_bufferView;
inline VkBufferView DxvkBufferView::handle() {
if (likely(m_version == m_buffer->m_version))
return m_handle;
std::unordered_map<
DxvkBufferSliceHandle,
VkBufferView,
DxvkHash, DxvkEq> m_views;
VkBufferView createBufferView(
const DxvkBufferSliceHandle& slice);
void updateBufferView(
const DxvkBufferSliceHandle& slice);
};
m_handle = m_buffer->m_storage->createBufferView(m_key);
m_version = m_buffer->m_version;
return m_handle;
}
inline DxvkBufferSliceHandle DxvkBufferView::getSliceHandle() const {
return m_buffer->getSliceHandle(m_key.offset, m_key.size);
}
inline void DxvkBufferView::incRef() {
m_buffer->incRef();
}
inline void DxvkBufferView::decRef() {
m_buffer->decRef();
}
}

View File

@ -261,6 +261,12 @@ namespace dxvk {
m_resources.trackResource<Access>(rc.ptr());
}
template<DxvkAccess Access, typename T>
void trackResource(T* rc) {
// TODO remove this jank once things are refactored
m_resources.trackResource<Access>(rc);
}
/**
* \brief Tracks a GPU event
*

View File

@ -253,10 +253,6 @@ namespace dxvk {
this->spillRenderPass(true);
this->invalidateState();
// The view range might have been invalidated, so
// we need to make sure the handle is up to date
bufferView->updateView();
auto bufferSlice = bufferView->getSliceHandle();
if (m_execBarriers.isBufferDirty(bufferSlice, DxvkAccess::Write))
@ -308,8 +304,8 @@ namespace dxvk {
m_execBarriers.accessBuffer(bufferSlice,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
bufferView->bufferInfo().stages,
bufferView->bufferInfo().access);
bufferView->buffer()->info().stages,
bufferView->buffer()->info().access);
m_cmd->trackResource<DxvkAccess::None>(bufferView);
m_cmd->trackResource<DxvkAccess::Write>(bufferView->buffer());
@ -874,7 +870,7 @@ namespace dxvk {
viewInfo.rangeOffset = dstBufferOffset;
viewInfo.rangeLength = dstBufferSlice.length;
viewInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
Rc<DxvkBufferView> dstView = m_device->createBufferView(dstBuffer, viewInfo);
Rc<DxvkBufferView> dstView = dstBuffer->createView(viewInfo);
viewInfo.rangeOffset = srcBufferOffset;
viewInfo.rangeLength = srcBufferSlice.length;
@ -917,11 +913,11 @@ namespace dxvk {
VK_ACCESS_SHADER_READ_BIT);
viewInfo.rangeOffset = 0;
srcView = m_device->createBufferView(tmpBuffer, viewInfo);
srcView = tmpBuffer->createView(viewInfo);
m_cmd->trackResource<DxvkAccess::Write>(tmpBuffer);
} else {
srcView = m_device->createBufferView(srcBuffer, viewInfo);
srcView = srcBuffer->createView(viewInfo);
}
auto pipeInfo = m_common->metaCopy().getCopyBufferImagePipeline();
@ -1076,8 +1072,8 @@ namespace dxvk {
tmpViewInfoS.rangeLength = dataSizeS;
tmpViewInfoS.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
auto tmpBufferViewD = m_device->createBufferView(tmpBuffer, tmpViewInfoD);
auto tmpBufferViewS = m_device->createBufferView(tmpBuffer, tmpViewInfoS);
auto tmpBufferViewD = tmpBuffer->createView(tmpViewInfoD);
auto tmpBufferViewS = tmpBuffer->createView(tmpViewInfoS);
// Create descriptor set for the unpack operation
DxvkMetaUnpackDescriptors descriptors;
@ -5326,7 +5322,6 @@ namespace dxvk {
const auto& res = m_rc[binding.resourceBinding];
if (res.bufferView != nullptr) {
res.bufferView->updateView();
descriptorInfo.texelBuffer = res.bufferView->handle();
if (m_rcTracked.set(binding.resourceBinding)) {
@ -5342,7 +5337,6 @@ namespace dxvk {
const auto& res = m_rc[binding.resourceBinding];
if (res.bufferView != nullptr) {
res.bufferView->updateView();
descriptorInfo.texelBuffer = res.bufferView->handle();
if (m_rcTracked.set(binding.resourceBinding)) {
@ -6106,7 +6100,7 @@ namespace dxvk {
for (uint32_t i = 0; i < slices.size() && !requiresBarrier; i++) {
if ((slices[i]->length())
&& (slices[i]->bufferInfo().access & storageBufferAccess)) {
&& (slices[i]->buffer()->info().access & storageBufferAccess)) {
requiresBarrier = this->checkBufferBarrier<DoEmit>(*slices[i],
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT);
@ -6191,8 +6185,7 @@ namespace dxvk {
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
if ((slot.bufferView != nullptr)
&& (slot.bufferView->bufferInfo().access & storageBufferAccess)) {
slot.bufferView->updateView();
&& (slot.bufferView->buffer()->info().access & storageBufferAccess)) {
requiresBarrier = this->checkBufferViewBarrier<DoEmit>(slot.bufferView,
util::pipelineStages(binding.stage), binding.access);
}
@ -6258,8 +6251,8 @@ namespace dxvk {
m_execBarriers.accessBuffer(
bufferView->getSliceHandle(),
stages, access,
bufferView->bufferInfo().stages,
bufferView->bufferInfo().access);
bufferView->buffer()->info().stages,
bufferView->buffer()->info().access);
return false;
} else {
DxvkAccessFlags dstAccess = DxvkBarrierSet::getAccessTypes(access);

View File

@ -247,7 +247,7 @@ namespace dxvk {
m_rc[slot].imageView = nullptr;
if (view != nullptr) {
m_rc[slot].bufferSlice = view->slice();
m_rc[slot].bufferSlice = DxvkBufferSlice(view);
m_rc[slot].bufferView = std::move(view);
} else {
m_rc[slot].bufferSlice = DxvkBufferSlice();

View File

@ -164,13 +164,6 @@ namespace dxvk {
}
Rc<DxvkBufferView> DxvkDevice::createBufferView(
const Rc<DxvkBuffer>& buffer,
const DxvkBufferViewCreateInfo& createInfo) {
return new DxvkBufferView(this, buffer, createInfo);
}
Rc<DxvkImage> DxvkDevice::createImage(
const DxvkImageCreateInfo& createInfo,
VkMemoryPropertyFlags memoryType) {

View File

@ -311,18 +311,7 @@ namespace dxvk {
Rc<DxvkBuffer> createBuffer(
const DxvkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags memoryType);
/**
* \brief Creates a buffer view
*
* \param [in] buffer The buffer to view
* \param [in] createInfo Buffer view properties
* \returns The buffer view object
*/
Rc<DxvkBufferView> createBufferView(
const Rc<DxvkBuffer>& buffer,
const DxvkBufferViewCreateInfo& createInfo);
/**
* \brief Creates an image object
*

View File

@ -775,7 +775,7 @@ namespace dxvk::hud {
viewInfo.rangeLength = info.size;
viewInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
m_pageMaskView = m_device->createBufferView(m_pageMaskBuffer, viewInfo);
m_pageMaskView = m_pageMaskBuffer->createView(viewInfo);
}
if (!m_stats.pageMasks.empty()) {

View File

@ -254,7 +254,7 @@ namespace dxvk::hud {
info.rangeLength = m_dataBuffer->info().size;
info.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
return m_device->createBufferView(m_dataBuffer, info);
return m_dataBuffer->createView(info);
}
@ -279,7 +279,7 @@ namespace dxvk::hud {
info.rangeLength = m_fontBuffer->info().size;
info.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
return m_device->createBufferView(m_fontBuffer, info);
return m_fontBuffer->createView(info);
}