mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-10-13 07:39:22 +00:00
Add API independent sparse page table tracker
This commit is contained in:
8 files changed
+2085
-18
No files matched your search
@@ -155,6 +155,8 @@ set(sources
|
||||
core/plugins.h
|
||||
core/resource_manager.cpp
|
||||
core/resource_manager.h
|
||||
core/sparse_page_table.cpp
|
||||
core/sparse_page_table.h
|
||||
data/glsl/glsl_ubos.h
|
||||
data/glsl/glsl_ubos_cpp.h
|
||||
hooks/hooks.cpp
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,240 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/replay/data_types.h"
|
||||
#include "api/replay/rdcarray.h"
|
||||
#include "api/replay/rdcpair.h"
|
||||
#include "api/replay/resourceid.h"
|
||||
#include "api/replay/stringise.h"
|
||||
|
||||
namespace Sparse
|
||||
{
|
||||
class PageTable;
|
||||
}; // namespace Sparse
|
||||
|
||||
// we pre-declare this function so we can make it a friend inside the PageTable implementation
|
||||
template <class SerialiserType>
|
||||
void DoSerialise(SerialiserType &ser, Sparse::PageTable &el);
|
||||
|
||||
namespace Sparse
|
||||
{
|
||||
// used for co-ordinates as well as dimensions
|
||||
struct Coord
|
||||
{
|
||||
uint32_t x, y, z;
|
||||
|
||||
bool operator==(const Coord &o) const { return x == o.x && y == o.y && z == o.z; }
|
||||
};
|
||||
|
||||
struct Page
|
||||
{
|
||||
ResourceId memory;
|
||||
uint64_t offset;
|
||||
|
||||
bool operator==(const Page &o) const { return memory == o.memory && offset == o.offset; }
|
||||
};
|
||||
|
||||
struct PageRangeMapping
|
||||
{
|
||||
bool hasSingleMapping() const { return pages.empty(); }
|
||||
// the memory mapping if there's a single mapping. Only valid if pages below is empty
|
||||
Page singleMapping;
|
||||
|
||||
// since with a single mapping we only store the 'base' page, we need an additional bool to
|
||||
// indicate if it's a single page re-used or if it's all subsequent pages used.
|
||||
bool singlePageReused = false;
|
||||
|
||||
// the memory mappings per-page if there are different mappings per-page
|
||||
rdcarray<Page> pages;
|
||||
|
||||
void createPages(uint32_t numPages, uint32_t pageSize);
|
||||
};
|
||||
|
||||
struct MipTail
|
||||
{
|
||||
// the first mip that is in the mip tail
|
||||
uint32_t firstMip = 0;
|
||||
|
||||
// the offset in bytes for the mip tail.
|
||||
uint64_t byteOffset = 0;
|
||||
|
||||
// the stride in bytes for the mip tail between each array slice's mip stride. This is set to 0
|
||||
// if there is only one mip tail
|
||||
uint64_t byteStride = 0;
|
||||
|
||||
// the size in bytes for the mip tail
|
||||
uint64_t totalPackedByteSize = 0;
|
||||
|
||||
// the pages for the mip tail (or buffer pages for buffers). If byteStride is 0 this is the
|
||||
// single set of pages for all array slices. If byteStride is non-zero then the first N pages
|
||||
// (with N = byteStride / pageByteSize) are for slice 0, the next N for slice 1, etc.
|
||||
rdcarray<PageRangeMapping> mappings;
|
||||
};
|
||||
|
||||
// shadows the page table for a sparse resource - buffer or texture - and handles updates and
|
||||
// retrieval. Currently the system is simple - we first store a page mapping per subresource. This
|
||||
// should hopefully cover most applications and avoids needing to allocate, update, and store/apply
|
||||
// a whole page table. If we detect a partial update we allocate a full page table and store the
|
||||
// mapping for each page.
|
||||
class PageTable
|
||||
{
|
||||
public:
|
||||
// initialise the page table for a buffer. We just need to know its size and the page size
|
||||
void Initialise(uint64_t bufferByteSize, uint32_t pageByteSize);
|
||||
// initialise the page table for a texture. We specify various properties about the texture and
|
||||
// its page shape/size and mip tail.
|
||||
// The mip tail starts at firstTailMip - if this is >= numMips then there is no mip tail.
|
||||
// mipTailOffset is an arbitrary offset which all mip tail bindings are relative to. It does
|
||||
// nothing but rebase the offset provided setMipTailRange.
|
||||
// mipTailStride is the byte stride between mip tails if they are stored separately per slice in
|
||||
// an array texture. Again this is arbitrary to offset the binding resource offset. If the stride
|
||||
// is 0 this means all slices have their mip tails consecutively packed.
|
||||
// mipTailTotalPackedSize is the *total packed size of the mip tails*. This can be calculated with
|
||||
// the size of one array slice's mip tail multiplied by the number of array slices. If the stride
|
||||
// is 0 this is the size of the whole mip tail of the resource.
|
||||
void Initialise(const Coord &overallTexelDim, uint32_t numMips, uint32_t numArraySlices,
|
||||
uint32_t pageByteSize, const Coord &pageTexelDim, uint32_t firstTailMip,
|
||||
uint64_t mipTailOffset, uint64_t mipTailStride, uint64_t mipTailTotalPackedSize);
|
||||
|
||||
uint64_t GetSerialiseSize() const;
|
||||
|
||||
inline uint32_t getPageByteSize() const { return m_PageByteSize; }
|
||||
inline Coord getPageTexelSize() const { return m_PageTexelSize; }
|
||||
// useful for D3D where the mip tail is indexed by subresource/array slice even if we treat it all
|
||||
// as one
|
||||
inline uint64_t getMipTailByteOffsetForSubresource(uint32_t subresource) const
|
||||
{
|
||||
const uint32_t arraySlice = (subresource / m_MipCount) % m_ArraySize;
|
||||
return m_MipTail.byteOffset + m_MipTail.byteStride * arraySlice;
|
||||
}
|
||||
|
||||
inline uint32_t calcSubresource(uint32_t arraySlice, uint32_t mipLevel) const
|
||||
{
|
||||
return arraySlice * m_MipCount + mipLevel;
|
||||
}
|
||||
Coord calcSubresourcePageDim(uint32_t subresource) const;
|
||||
|
||||
// is this subresource in the mip tail
|
||||
inline bool isSubresourceInMipTail(uint32_t subresource) const
|
||||
{
|
||||
const uint32_t mipLevel = subresource % m_MipCount;
|
||||
return mipLevel >= m_MipTail.firstMip;
|
||||
}
|
||||
// is this byte offset in the resource (according to the mip tail - no other offsets are known)
|
||||
inline bool isByteOffsetInResource(uint64_t byteOffset) const
|
||||
{
|
||||
const uint64_t mipTailSize = m_MipTail.byteStride == 0 ? m_MipTail.totalPackedByteSize
|
||||
: m_MipTail.byteStride * m_ArraySize;
|
||||
return byteOffset >= m_MipTail.byteOffset && byteOffset < m_MipTail.byteOffset + mipTailSize;
|
||||
}
|
||||
|
||||
// read-only accessors to get current state
|
||||
const uint32_t getNumSubresources() const { return (uint32_t)m_Subresources.size(); }
|
||||
const uint32_t getArraySize() const { return m_ArraySize; }
|
||||
const uint32_t getMipCount() const { return m_MipCount; }
|
||||
const PageRangeMapping &getSubresource(uint32_t subresource) const
|
||||
{
|
||||
return m_Subresources[subresource];
|
||||
}
|
||||
const MipTail &getMipTail() const { return m_MipTail; }
|
||||
const uint64_t getSubresourceByteSize(uint32_t subresource) const
|
||||
{
|
||||
const Coord subresourcePageDim = calcSubresourcePageDim(subresource);
|
||||
|
||||
return subresourcePageDim.x * subresourcePageDim.y * subresourcePageDim.z * m_PageByteSize;
|
||||
}
|
||||
|
||||
// set a contiguous range of pages, with offsets and sizes applied in bytes.
|
||||
// This is when you are setting XYZ resource pages to point to ABC memory pages.
|
||||
// useSinglePage means only one page of memory will be used for all pages in the resource. Think
|
||||
// of the case of mapping a single 'black' page to large areas of the resource, or NULL'ing out
|
||||
// mappings.
|
||||
// as a convenience it returns the resource offset where it finishes, since D3D allows
|
||||
// mismatched boundaries for tile ranges and memory regions
|
||||
uint64_t setMipTailRange(uint64_t resourceByteOffset, ResourceId memory,
|
||||
uint64_t memoryByteOffset, uint64_t byteSize, bool useSinglePage);
|
||||
inline uint64_t setBufferRange(uint64_t resourceByteOffset, ResourceId memory,
|
||||
uint64_t memoryByteOffset, uint64_t byteSize, bool useSinglePage)
|
||||
{
|
||||
return setMipTailRange(resourceByteOffset, memory, memoryByteOffset, byteSize, useSinglePage);
|
||||
}
|
||||
|
||||
// set a 3D box of texel pages to a range of memory.
|
||||
// useSinglePage means only one page of memory will be used for all pages in the resource. Think
|
||||
// of the case of mapping a single 'black' page to large areas of the resource, or NULL'ing out
|
||||
// mappings.
|
||||
void setImageBoxRange(uint32_t subresource, const Coord &coord, const Coord &dim,
|
||||
ResourceId memory, uint64_t memoryByteOffset, bool useSinglePage);
|
||||
|
||||
// set a series of tiles in x, y, z order starting at a given point and wrapping around the
|
||||
// overall image dimensions. In theory you could e.g. map 10 pages starting at page 6, when there
|
||||
// are only 8 pages to a row. It would update pages 6 and 7 in the first row then all pages in the
|
||||
// next row. This also allows wrapping from one subresource to the next
|
||||
// we accept a byte size for consistency with all other calls that work in bytes not pages, even
|
||||
// though this is only expected to be used by D3D which has this wrapping update operation and it
|
||||
// operates in pages - the calling code can mutiply by getPageByteSize().
|
||||
// useSinglePage means only one page of memory will be used for all pages in the resource. Think
|
||||
// of the case of mapping a single 'black' page to large areas of the resource, or NULL'ing out
|
||||
// mappings
|
||||
// as a convenience it returns the co-ordinate and subresource where it finishes, since D3D allows
|
||||
// mismatched boundaries for tile ranges and memory regions
|
||||
rdcpair<uint32_t, Coord> setImageWrappedRange(uint32_t subresource, const Coord &coord,
|
||||
uint64_t byteSize, ResourceId memory,
|
||||
uint64_t memoryByteOffset, bool useSinglePage);
|
||||
|
||||
private:
|
||||
// The image dimensions that we need. We don't care about the format or anything, we just need to
|
||||
// know the size in pages and the subresource setup
|
||||
Coord m_TextureDim = {};
|
||||
uint32_t m_MipCount = 1;
|
||||
uint32_t m_ArraySize = 1;
|
||||
|
||||
// the byte size of a page, constant over a resource
|
||||
uint32_t m_PageByteSize = 0;
|
||||
|
||||
// the size of a page in texels
|
||||
Coord m_PageTexelSize = {};
|
||||
|
||||
// the page tables for each subresource, if this is an image. Note for buffers everything goes in
|
||||
// the "mipTail".
|
||||
// For simplicity and robustness of access every subresource has an entry here, even those
|
||||
// corresponding to mips that are in mip tails - the overhead is nominal with each entry being
|
||||
// 5*ptrsize = 40 bytes.
|
||||
rdcarray<PageRangeMapping> m_Subresources;
|
||||
|
||||
MipTail m_MipTail;
|
||||
|
||||
template <typename SerialiserType>
|
||||
friend void ::DoSerialise(SerialiserType &ser, PageTable &el);
|
||||
};
|
||||
|
||||
}; // namespace Sparse
|
||||
|
||||
DECLARE_REFLECTION_STRUCT(Sparse::Coord);
|
||||
DECLARE_REFLECTION_STRUCT(Sparse::Page);
|
||||
DECLARE_REFLECTION_STRUCT(Sparse::PageRangeMapping);
|
||||
DECLARE_REFLECTION_STRUCT(Sparse::MipTail);
|
||||
DECLARE_REFLECTION_STRUCT(Sparse::PageTable);
|
||||
@@ -26,13 +26,6 @@
|
||||
#include "vk_core.h"
|
||||
#include "vk_debug.h"
|
||||
|
||||
template <typename SerialiserType>
|
||||
void DoSerialise(SerialiserType &ser, MemIDOffset &el)
|
||||
{
|
||||
SERIALISE_MEMBER(memory);
|
||||
SERIALISE_MEMBER(memOffs);
|
||||
}
|
||||
|
||||
// VKTODOLOW there's a lot of duplicated code in this file for creating a buffer to do
|
||||
// a memory copy and saving to disk.
|
||||
|
||||
@@ -911,7 +904,7 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, V
|
||||
uint32_t numBinds = 0;
|
||||
SERIALISE_ELEMENT(numBinds).Hidden();
|
||||
|
||||
MemIDOffset *memDataOffs = NULL;
|
||||
Sparse::Page *memDataOffs = NULL;
|
||||
ser.Serialise("memDataOffs"_lit, memDataOffs, 0, SerialiserFlags::NoFlags).Hidden();
|
||||
uint32_t numUniqueMems = 0;
|
||||
SERIALISE_ELEMENT(numUniqueMems).Hidden();
|
||||
@@ -963,14 +956,14 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, V
|
||||
static const uint32_t numLegacyAspects = 4;
|
||||
for(uint32_t a = 0; a < numLegacyAspects; a++)
|
||||
{
|
||||
MemIDOffset *pages = NULL;
|
||||
Sparse::Page *pages = NULL;
|
||||
ser.Serialise("pages"_lit, pages, 0, SerialiserFlags::NoFlags).Hidden();
|
||||
}
|
||||
|
||||
uint32_t pageCount[numLegacyAspects] = {};
|
||||
SERIALISE_ELEMENT(pageCount).Hidden();
|
||||
|
||||
MemIDOffset *memDataOffs = NULL;
|
||||
Sparse::Page *memDataOffs = NULL;
|
||||
ser.Serialise("memDataOffs"_lit, memDataOffs, 0, SerialiserFlags::NoFlags).Hidden();
|
||||
uint32_t numUniqueMems = 0;
|
||||
SERIALISE_ELEMENT(numUniqueMems).Hidden();
|
||||
|
||||
@@ -29,14 +29,6 @@
|
||||
|
||||
class WrappedVulkan;
|
||||
|
||||
struct MemIDOffset
|
||||
{
|
||||
ResourceId memory;
|
||||
VkDeviceSize memOffs;
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_STRUCT(MemIDOffset);
|
||||
|
||||
// this struct is copied around and for that reason we explicitly keep it simple and POD. The
|
||||
// lifetime of the memory allocated is controlled by the resource manager - when preparing or
|
||||
// serialising, we explicitly set the initial contents, then when the whole system is done with them
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "core/bit_flag_iterator.h"
|
||||
#include "core/intervals.h"
|
||||
#include "core/resource_manager.h"
|
||||
#include "core/sparse_page_table.h"
|
||||
#include "vk_common.h"
|
||||
#include "vk_dispatch_defs.h"
|
||||
#include "vk_hookset_defs.h"
|
||||
|
||||
@@ -214,6 +214,7 @@
|
||||
<ClInclude Include="core\remote_server.h" />
|
||||
<ClInclude Include="core\replay_proxy.h" />
|
||||
<ClInclude Include="core\resource_manager.h" />
|
||||
<ClInclude Include="core\sparse_page_table.h" />
|
||||
<ClInclude Include="data\embedded_files.h" />
|
||||
<ClInclude Include="data\glsl\glsl_ubos.h" />
|
||||
<ClInclude Include="data\glsl\glsl_ubos_cpp.h" />
|
||||
@@ -534,6 +535,7 @@
|
||||
<ClCompile Include="core\precompiled.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="core\sparse_page_table.cpp" />
|
||||
<ClCompile Include="core\target_control.cpp" />
|
||||
<ClCompile Include="core\remote_server.cpp" />
|
||||
<ClCompile Include="core\replay_proxy.cpp" />
|
||||
|
||||
@@ -561,6 +561,9 @@
|
||||
<ClInclude Include="3rdparty\superluminal\PerformanceAPI_capi.h">
|
||||
<Filter>3rdparty\superluminal</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="core\sparse_page_table.h">
|
||||
<Filter>Core</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="maths\camera.cpp">
|
||||
@@ -971,6 +974,9 @@
|
||||
<ClCompile Include="3rdparty\superluminal\superluminal.cpp">
|
||||
<Filter>3rdparty\superluminal</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="core\sparse_page_table.cpp">
|
||||
<Filter>Core</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="os\win32\comexport.def">
|
||||
|
||||
Reference in new issue
Block a user