mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-18 11:52:12 +01:00
[dxvk] Add functionality to query sparse metadata
This commit is contained in:
parent
e923cc5b69
commit
bc3affc264
186
src/dxvk/dxvk_sparse.cpp
Normal file
186
src/dxvk/dxvk_sparse.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
#include "dxvk_buffer.h"
|
||||
#include "dxvk_device.h"
|
||||
#include "dxvk_image.h"
|
||||
#include "dxvk_sparse.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkSparsePageTable::DxvkSparsePageTable() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DxvkSparsePageTable::DxvkSparsePageTable(
|
||||
DxvkDevice* device,
|
||||
const DxvkBuffer* buffer)
|
||||
: m_buffer(buffer) {
|
||||
VkDeviceSize bufferSize = buffer->info().size;
|
||||
|
||||
// For linear buffers, the mapping is very simple
|
||||
// and consists of consecutive 64k pages
|
||||
size_t pageCount = align(bufferSize, SparseMemoryPageSize) / SparseMemoryPageSize;
|
||||
m_metadata.resize(pageCount);
|
||||
|
||||
for (size_t i = 0; i < pageCount; i++) {
|
||||
VkDeviceSize pageOffset = SparseMemoryPageSize * i;
|
||||
m_metadata[i].type = DxvkSparsePageType::Buffer;
|
||||
m_metadata[i].buffer.offset = pageOffset;
|
||||
m_metadata[i].buffer.length = std::min(SparseMemoryPageSize, bufferSize - pageOffset);
|
||||
}
|
||||
|
||||
// Initialize properties and subresource info so that we can
|
||||
// easily query this without having to know the resource type
|
||||
m_subresources.resize(1);
|
||||
m_subresources[0].pageCount = { uint32_t(pageCount), 1u, 1u };
|
||||
m_subresources[0].pageIndex = 0;
|
||||
|
||||
m_properties.pageRegionExtent = { uint32_t(SparseMemoryPageSize), 1u, 1u };
|
||||
}
|
||||
|
||||
|
||||
DxvkSparsePageTable::DxvkSparsePageTable(
|
||||
DxvkDevice* device,
|
||||
const DxvkImage* image)
|
||||
: m_image(image) {
|
||||
auto vk = device->vkd();
|
||||
|
||||
// Query sparse memory requirements
|
||||
uint32_t reqCount = 0;
|
||||
vk->vkGetImageSparseMemoryRequirements(vk->device(), image->handle(), &reqCount, nullptr);
|
||||
|
||||
std::vector<VkSparseImageMemoryRequirements> req(reqCount);
|
||||
vk->vkGetImageSparseMemoryRequirements(vk->device(), image->handle(), &reqCount, req.data());
|
||||
|
||||
// Find first non-metadata struct and use it to fill in the image properties
|
||||
bool foundMainAspect = false;
|
||||
|
||||
for (const auto& r : req) {
|
||||
if (r.formatProperties.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) {
|
||||
VkDeviceSize metadataSize = r.imageMipTailSize;
|
||||
|
||||
if (!(r.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT))
|
||||
metadataSize *= m_image->info().numLayers;
|
||||
|
||||
m_properties.metadataPageCount += uint32_t(metadataSize / SparseMemoryPageSize);
|
||||
} else if (!foundMainAspect) {
|
||||
m_properties.flags = r.formatProperties.flags;
|
||||
m_properties.pageRegionExtent = r.formatProperties.imageGranularity;
|
||||
|
||||
if (r.imageMipTailFirstLod < image->info().mipLevels && r.imageMipTailSize) {
|
||||
m_properties.pagedMipCount = r.imageMipTailFirstLod;
|
||||
m_properties.mipTailOffset = r.imageMipTailOffset;
|
||||
m_properties.mipTailSize = r.imageMipTailSize;
|
||||
m_properties.mipTailStride = r.imageMipTailStride;
|
||||
} else {
|
||||
m_properties.pagedMipCount = image->info().mipLevels;
|
||||
}
|
||||
|
||||
foundMainAspect = true;
|
||||
} else {
|
||||
Logger::err(str::format("Found multiple aspects for sparse image:"
|
||||
"\n Type: ", image->info().type,
|
||||
"\n Format: ", image->info().format,
|
||||
"\n Flags: ", image->info().flags,
|
||||
"\n Extent: ", "(", image->info().extent.width,
|
||||
",", image->info().extent.height,
|
||||
",", image->info().extent.depth, ")",
|
||||
"\n Mip levels: ", image->info().mipLevels,
|
||||
"\n Array layers: ", image->info().numLayers,
|
||||
"\n Samples: ", image->info().sampleCount,
|
||||
"\n Usage: ", image->info().usage,
|
||||
"\n Tiling: ", image->info().tiling));
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in subresource metadata and compute page count
|
||||
uint32_t totalPageCount = 0;
|
||||
uint32_t subresourceCount = image->info().numLayers * image->info().mipLevels;
|
||||
m_subresources.reserve(subresourceCount);
|
||||
|
||||
for (uint32_t l = 0; l < image->info().numLayers; l++) {
|
||||
for (uint32_t m = 0; m < image->info().mipLevels; m++) {
|
||||
if (m < m_properties.pagedMipCount) {
|
||||
// Compute block count for current mip based on image properties
|
||||
DxvkSparseImageSubresourceProperties subresourceInfo;
|
||||
subresourceInfo.isMipTail = VK_FALSE;
|
||||
subresourceInfo.pageCount = util::computeBlockCount(
|
||||
image->mipLevelExtent(m), m_properties.pageRegionExtent);
|
||||
|
||||
// Advance total page count by number of pages in the subresource
|
||||
subresourceInfo.pageIndex = totalPageCount;
|
||||
totalPageCount += util::flattenImageExtent(subresourceInfo.pageCount);
|
||||
|
||||
m_subresources.push_back(subresourceInfo);
|
||||
} else {
|
||||
DxvkSparseImageSubresourceProperties subresourceInfo = { };
|
||||
subresourceInfo.isMipTail = VK_TRUE;
|
||||
subresourceInfo.pageCount = { 0u, 0u, 0u };
|
||||
subresourceInfo.pageIndex = 0u;
|
||||
m_subresources.push_back(subresourceInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_properties.mipTailSize) {
|
||||
m_properties.mipTailPageIndex = totalPageCount;
|
||||
|
||||
// We may need multiple mip tails for the image
|
||||
uint32_t mipTailPageCount = m_properties.mipTailSize / SparseMemoryPageSize;
|
||||
|
||||
if (!(m_properties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT))
|
||||
mipTailPageCount *= m_image->info().numLayers;
|
||||
|
||||
totalPageCount += mipTailPageCount;
|
||||
}
|
||||
|
||||
// Fill in page metadata
|
||||
m_metadata.reserve(totalPageCount);
|
||||
|
||||
for (uint32_t l = 0; l < image->info().numLayers; l++) {
|
||||
for (uint32_t m = 0; m < m_properties.pagedMipCount; m++) {
|
||||
VkExtent3D mipExtent = image->mipLevelExtent(m);
|
||||
VkExtent3D pageCount = util::computeBlockCount(mipExtent, m_properties.pageRegionExtent);
|
||||
|
||||
for (uint32_t z = 0; z < pageCount.depth; z++) {
|
||||
for (uint32_t y = 0; y < pageCount.height; y++) {
|
||||
for (uint32_t x = 0; x < pageCount.width; x++) {
|
||||
DxvkSparsePageInfo pageInfo;
|
||||
pageInfo.type = DxvkSparsePageType::Image;
|
||||
pageInfo.image.subresource.aspectMask = image->formatInfo()->aspectMask;
|
||||
pageInfo.image.subresource.mipLevel = m;
|
||||
pageInfo.image.subresource.arrayLayer = l;
|
||||
pageInfo.image.offset.x = x * m_properties.pageRegionExtent.width;
|
||||
pageInfo.image.offset.y = y * m_properties.pageRegionExtent.height;
|
||||
pageInfo.image.offset.z = z * m_properties.pageRegionExtent.depth;
|
||||
pageInfo.image.extent.width = std::min(m_properties.pageRegionExtent.width, mipExtent.width - pageInfo.image.offset.x);
|
||||
pageInfo.image.extent.height = std::min(m_properties.pageRegionExtent.height, mipExtent.height - pageInfo.image.offset.y);
|
||||
pageInfo.image.extent.depth = std::min(m_properties.pageRegionExtent.depth, mipExtent.depth - pageInfo.image.offset.z);
|
||||
m_metadata.push_back(pageInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_properties.mipTailSize) {
|
||||
uint32_t pageCount = m_properties.mipTailSize / SparseMemoryPageSize;
|
||||
uint32_t layerCount = 1;
|
||||
|
||||
if (!(m_properties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT))
|
||||
layerCount = image->info().numLayers;
|
||||
|
||||
for (uint32_t i = 0; i < layerCount; i++) {
|
||||
for (uint32_t j = 0; j < pageCount; j++) {
|
||||
DxvkSparsePageInfo pageInfo;
|
||||
pageInfo.type = DxvkSparsePageType::ImageMipTail;
|
||||
pageInfo.mipTail.resourceOffset = m_properties.mipTailOffset
|
||||
+ i * m_properties.mipTailStride
|
||||
+ j * SparseMemoryPageSize;
|
||||
pageInfo.mipTail.resourceLength = SparseMemoryPageSize;
|
||||
m_metadata.push_back(pageInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
200
src/dxvk/dxvk_sparse.h
Normal file
200
src/dxvk/dxvk_sparse.h
Normal file
@ -0,0 +1,200 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_memory.h"
|
||||
#include "dxvk_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class DxvkCommandList;
|
||||
class DxvkDevice;
|
||||
class DxvkBuffer;
|
||||
class DxvkImage;
|
||||
class DxvkSparsePage;
|
||||
class DxvkSparsePagePool;
|
||||
|
||||
constexpr static VkDeviceSize SparseMemoryPageSize = 1ull << 16;
|
||||
|
||||
/**
|
||||
* \brief Sparse page handle
|
||||
*/
|
||||
struct DxvkSparsePageHandle {
|
||||
VkDeviceMemory memory;
|
||||
VkDeviceSize offset;
|
||||
VkDeviceSize length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Buffer info for sparse page
|
||||
*
|
||||
* Stores the buffer region backed by
|
||||
* any given page.
|
||||
*/
|
||||
struct DxvkSparsePageBufferInfo {
|
||||
VkDeviceSize offset;
|
||||
VkDeviceSize length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Image info for sparse page
|
||||
*
|
||||
* Stores the image region backed by
|
||||
* any given page.
|
||||
*/
|
||||
struct DxvkSparsePageImageInfo {
|
||||
VkImageSubresource subresource;
|
||||
VkOffset3D offset;
|
||||
VkExtent3D extent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Image mip tail info for sparse page
|
||||
*
|
||||
* Stores the virtual resource offset and size
|
||||
* within the mip tail backed by any given page.
|
||||
*/
|
||||
struct DxvkSparsePageMipTailInfo {
|
||||
VkDeviceSize resourceOffset;
|
||||
VkDeviceSize resourceLength;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Page type
|
||||
*/
|
||||
enum class DxvkSparsePageType : uint32_t {
|
||||
None = 0,
|
||||
Buffer = 1,
|
||||
Image = 2,
|
||||
ImageMipTail = 3,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Sparse page table metadata
|
||||
*
|
||||
* Stores the resource region backed by any given page.
|
||||
*/
|
||||
struct DxvkSparsePageInfo {
|
||||
DxvkSparsePageType type;
|
||||
union {
|
||||
DxvkSparsePageBufferInfo buffer;
|
||||
DxvkSparsePageImageInfo image;
|
||||
DxvkSparsePageMipTailInfo mipTail;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Image tiling info
|
||||
*/
|
||||
struct DxvkSparseImageProperties {
|
||||
VkSparseImageFormatFlags flags;
|
||||
VkExtent3D pageRegionExtent;
|
||||
uint32_t pagedMipCount;
|
||||
uint32_t metadataPageCount;
|
||||
uint32_t mipTailPageIndex;
|
||||
VkDeviceSize mipTailOffset;
|
||||
VkDeviceSize mipTailSize;
|
||||
VkDeviceSize mipTailStride;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Image subresource tiling info
|
||||
*/
|
||||
struct DxvkSparseImageSubresourceProperties {
|
||||
VkBool32 isMipTail;
|
||||
VkExtent3D pageCount;
|
||||
uint32_t pageIndex;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Sparse page table
|
||||
*
|
||||
* Stores mappings from a resource region to a given memory page,
|
||||
* as well as mapping tile indices to the given resource region.
|
||||
*/
|
||||
class DxvkSparsePageTable {
|
||||
|
||||
public:
|
||||
|
||||
DxvkSparsePageTable();
|
||||
|
||||
DxvkSparsePageTable(
|
||||
DxvkDevice* device,
|
||||
const DxvkBuffer* buffer);
|
||||
|
||||
DxvkSparsePageTable(
|
||||
DxvkDevice* device,
|
||||
const DxvkImage* image);
|
||||
|
||||
/**
|
||||
* \brief Counts total number of pages in the resources
|
||||
*
|
||||
* Counts the number of pages for the entire resource, both
|
||||
* for paged subresources as well as the mip tail.
|
||||
* \returns Total number of pages
|
||||
*/
|
||||
uint32_t getPageCount() const {
|
||||
return uint32_t(m_metadata.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Counts number of subresource infos
|
||||
* \returns Subresource info count
|
||||
*/
|
||||
uint32_t getSubresourceCount() const {
|
||||
return uint32_t(m_subresources.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves image properties
|
||||
*
|
||||
* Only contains meaningful info if the page
|
||||
* table object was created for an image.
|
||||
* \returns Image properties
|
||||
*/
|
||||
DxvkSparseImageProperties getProperties() const {
|
||||
return m_properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves image subresource properties
|
||||
*
|
||||
* \param [in] subresource The subresource to query
|
||||
* \returns Properties of the given subresource
|
||||
*/
|
||||
DxvkSparseImageSubresourceProperties getSubresourceProperties(uint32_t subresource) const {
|
||||
return subresource < getSubresourceCount()
|
||||
? m_subresources[subresource]
|
||||
: DxvkSparseImageSubresourceProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Queries info for a given page
|
||||
*
|
||||
* \param [in] page Page index
|
||||
* \returns Page info
|
||||
*/
|
||||
DxvkSparsePageInfo getPageInfo(uint32_t page) const {
|
||||
return page < getPageCount()
|
||||
? m_metadata[page]
|
||||
: DxvkSparsePageInfo();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const DxvkBuffer* m_buffer = nullptr;
|
||||
const DxvkImage* m_image = nullptr;
|
||||
|
||||
DxvkSparseImageProperties m_properties = { };
|
||||
std::vector<DxvkSparseImageSubresourceProperties> m_subresources;
|
||||
std::vector<DxvkSparsePageInfo> m_metadata;
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -98,6 +98,7 @@ dxvk_src = [
|
||||
'dxvk_shader.cpp',
|
||||
'dxvk_shader_key.cpp',
|
||||
'dxvk_signal.cpp',
|
||||
'dxvk_sparse.cpp',
|
||||
'dxvk_staging.cpp',
|
||||
'dxvk_state_cache.cpp',
|
||||
'dxvk_stats.cpp',
|
||||
|
Loading…
x
Reference in New Issue
Block a user