mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-22 22:46:41 +00:00
Skip unmapped subresources when serialising sparse init states on D3D12
This commit is contained in:
@@ -208,6 +208,8 @@ uint64_t PageTable::setMipTailRange(uint64_t resourceByteOffset, ResourceId memo
|
||||
memoryByteOffset += m_PageByteSize;
|
||||
}
|
||||
|
||||
mapping.simplifyUnmapped();
|
||||
|
||||
// return how much of the mip tail we consumed, clamped to the size. Note resourceByteOffset has
|
||||
// been remapped to be mip-tail relative here
|
||||
return m_MipTail.byteOffset +
|
||||
@@ -287,6 +289,9 @@ uint64_t PageTable::setMipTailRange(uint64_t resourceByteOffset, ResourceId memo
|
||||
// if we don't have enough remaining to hit the stride, we just zero-out the number of bytes
|
||||
// remaining
|
||||
byteSize -= RDCMIN(byteSize, m_MipTail.byteStride - mipTailSubresourceByteSize);
|
||||
|
||||
// simplify current mapping before moving on to next subresource
|
||||
mapping.simplifyUnmapped();
|
||||
sub++;
|
||||
}
|
||||
else
|
||||
@@ -299,6 +304,11 @@ uint64_t PageTable::setMipTailRange(uint64_t resourceByteOffset, ResourceId memo
|
||||
}
|
||||
}
|
||||
|
||||
// simplify the last tail that we touched, as long as it's still valid. If we just incremented
|
||||
// past the last, we will have simplified above where sub is incremented
|
||||
if(sub < m_MipTail.mappings.size())
|
||||
m_MipTail.mappings[sub].simplifyUnmapped();
|
||||
|
||||
if(byteSize > 0)
|
||||
RDCERR("Unclaimed bytes being assigned to image after iterating over all subresources");
|
||||
|
||||
@@ -383,6 +393,8 @@ void PageTable::setImageBoxRange(uint32_t subresource, const Sparse::Coord &coor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub.simplifyUnmapped();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,6 +521,9 @@ rdcpair<uint32_t, Coord> PageTable::setImageWrappedRange(uint32_t subresource,
|
||||
byteSize -= m_PageByteSize;
|
||||
}
|
||||
|
||||
if(updateMappings)
|
||||
sub.simplifyUnmapped();
|
||||
|
||||
// if we consumed all bytes and didn't get to the end of the subresource, calculate where we
|
||||
// ended up
|
||||
if(byteSize == 0 && startingPage + numPages < numSubresourcePages)
|
||||
@@ -667,6 +682,8 @@ void PageTable::copyImageBoxRange(uint32_t dstSubresource, const Coord &coordInT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dstSub.simplifyUnmapped();
|
||||
}
|
||||
|
||||
void PageTable::copyImageWrappedRange(uint32_t dstSubresource, const Coord &coordInTiles,
|
||||
@@ -802,12 +819,17 @@ void PageTable::copyImageWrappedRange(uint32_t dstSubresource, const Coord &coor
|
||||
dstSubresource++;
|
||||
}
|
||||
|
||||
// simplify the mapping before we move on
|
||||
dstMapping->simplifyUnmapped();
|
||||
|
||||
dstSubSize = calcSubresourcePageDim(dstSubresource);
|
||||
dstMapping = &m_Subresources[dstSubresource];
|
||||
}
|
||||
|
||||
if(srcSubresource >= srcPageTable.getNumSubresources())
|
||||
{
|
||||
dstMapping->simplifyUnmapped();
|
||||
|
||||
RDCERR(
|
||||
"Number of tiles %u in image wrapped range copy exceeded source page table subresource "
|
||||
"count %u",
|
||||
@@ -817,6 +839,8 @@ void PageTable::copyImageWrappedRange(uint32_t dstSubresource, const Coord &coor
|
||||
|
||||
if(dstSubresource >= getNumSubresources())
|
||||
{
|
||||
dstMapping->simplifyUnmapped();
|
||||
|
||||
RDCERR(
|
||||
"Number of tiles %u in image wrapped range copy exceeded dest page table subresource "
|
||||
"count %u",
|
||||
@@ -824,6 +848,10 @@ void PageTable::copyImageWrappedRange(uint32_t dstSubresource, const Coord &coor
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// simplify the last mapping we were working on
|
||||
if(dstMapping < m_Subresources.end())
|
||||
dstMapping->simplifyUnmapped();
|
||||
}
|
||||
|
||||
Coord PageTable::calcSubresourcePageDim(uint32_t subresource) const
|
||||
@@ -2723,6 +2751,78 @@ TEST_CASE("Test sparse page table mapping", "[sparse]")
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
SECTION("Test unmapped checks")
|
||||
{
|
||||
// create a 256x256 texture with 32x32 pages, 6 mips (the last two are in the mip tail)
|
||||
pageTable.Initialise({256, 256, 1}, 6, 1, 64, {32, 32, 1}, 4, 0, 0, 8192);
|
||||
|
||||
CHECK_FALSE(pageTable.getSubresource(0).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(1).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(2).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(3).isMapped());
|
||||
CHECK_FALSE(pageTable.getMipTail().mappings[0].isMapped());
|
||||
};
|
||||
|
||||
SECTION("Test unmapped simplification")
|
||||
{
|
||||
// create a 256x256 texture with 32x32 pages, 6 mips (the last two are in the mip tail)
|
||||
pageTable.Initialise({256, 256, 1}, 6, 1, 64, {32, 32, 1}, 4, 0, 0, 8192);
|
||||
|
||||
CHECK_FALSE(pageTable.getSubresource(0).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(1).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(2).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(3).isMapped());
|
||||
CHECK_FALSE(pageTable.getMipTail().mappings[0].isMapped());
|
||||
|
||||
ResourceId mem = ResourceIDGen::GetNewUniqueID();
|
||||
|
||||
pageTable.setMipTailRange(0, mem, 128, 256, false);
|
||||
|
||||
CHECK_FALSE(pageTable.getSubresource(0).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(1).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(2).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(3).isMapped());
|
||||
CHECK(pageTable.getMipTail().mappings[0].isMapped());
|
||||
|
||||
pageTable.setMipTailRange(0, ResourceId(), 128, 256, false);
|
||||
|
||||
CHECK_FALSE(pageTable.getSubresource(0).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(1).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(2).isMapped());
|
||||
CHECK_FALSE(pageTable.getSubresource(3).isMapped());
|
||||
CHECK_FALSE(pageTable.getMipTail().mappings[0].isMapped());
|
||||
|
||||
pageTable.setImageWrappedRange(0, {0, 0, 0}, ~0U, mem, 0, false);
|
||||
|
||||
CHECK(pageTable.getSubresource(0).isMapped());
|
||||
CHECK(pageTable.getSubresource(1).isMapped());
|
||||
CHECK(pageTable.getSubresource(2).isMapped());
|
||||
CHECK(pageTable.getSubresource(3).isMapped());
|
||||
CHECK(pageTable.getMipTail().mappings[0].isMapped());
|
||||
|
||||
ResourceId mem2 = ResourceIDGen::GetNewUniqueID();
|
||||
|
||||
pageTable.setImageBoxRange(0, {0, 0, 0}, {32, 32, 1}, mem2, 1024, false);
|
||||
|
||||
CHECK(pageTable.getSubresource(0).isMapped());
|
||||
|
||||
pageTable.setImageBoxRange(0, {64, 0, 0}, {32, 32, 1}, ResourceId(), 1024, false);
|
||||
|
||||
CHECK(pageTable.getSubresource(0).isMapped());
|
||||
|
||||
pageTable.setImageBoxRange(0, {0, 0, 0}, {32, 32, 1}, ResourceId(), 1024, false);
|
||||
|
||||
CHECK(pageTable.getSubresource(0).isMapped());
|
||||
|
||||
pageTable.setImageBoxRange(0, {0, 0, 0}, {256, 192, 1}, ResourceId(), 1024, false);
|
||||
|
||||
CHECK(pageTable.getSubresource(0).isMapped());
|
||||
|
||||
pageTable.setImageBoxRange(0, {0, 192, 0}, {256, 64, 1}, ResourceId(), 1024, false);
|
||||
|
||||
CHECK_FALSE(pageTable.getSubresource(0).isMapped());
|
||||
};
|
||||
};
|
||||
|
||||
#endif // ENABLED(ENABLE_UNIT_TESTS)
|
||||
|
||||
@@ -70,6 +70,23 @@ struct PageRangeMapping
|
||||
// the memory mappings per-page if there are different mappings per-page
|
||||
rdcarray<Page> pages;
|
||||
|
||||
bool isMapped() const { return !pages.empty() || singleMapping.memory != ResourceId(); }
|
||||
void simplifyUnmapped()
|
||||
{
|
||||
// if we're already using singleMapping, don't check anything
|
||||
if(pages.empty())
|
||||
return;
|
||||
|
||||
// if we find a single page with memory mapped, we're not entirely unmapped
|
||||
for(size_t i = 0; i < pages.size(); i++)
|
||||
if(pages[i].memory != ResourceId())
|
||||
return;
|
||||
|
||||
// we're entirely unmapped - revert back to a single page mapping
|
||||
pages.clear();
|
||||
singleMapping = Page();
|
||||
singlePageReused = false;
|
||||
}
|
||||
Page getPage(uint32_t idx, uint32_t pageSize) const
|
||||
{
|
||||
if(pages.empty())
|
||||
@@ -175,6 +192,13 @@ public:
|
||||
{
|
||||
return m_Subresources[subresource];
|
||||
}
|
||||
const PageRangeMapping &getPageRangeMapping(uint32_t subresource) const
|
||||
{
|
||||
if(isSubresourceInMipTail(subresource))
|
||||
return getMipTailMapping(subresource);
|
||||
else
|
||||
return getSubresource(subresource);
|
||||
}
|
||||
const MipTail &getMipTail() const { return m_MipTail; }
|
||||
const PageRangeMapping &getMipTailMapping(uint32_t subresource) const
|
||||
{
|
||||
|
||||
@@ -922,7 +922,7 @@ RDResult WrappedID3D12CommandQueue::ReplayLog(CaptureState readType, uint32_t st
|
||||
|
||||
ser.SetStringDatabase(&m_StringDB);
|
||||
ser.SetUserData(GetResourceManager());
|
||||
ser.SetVersion(m_pDevice->GetLogVersion());
|
||||
ser.SetVersion(m_pDevice->GetCaptureVersion());
|
||||
|
||||
if(IsLoading(m_State) || IsStructuredExporting(m_State))
|
||||
{
|
||||
|
||||
@@ -235,6 +235,10 @@ bool D3D12InitParams::IsSupportedVersion(uint64_t ver)
|
||||
if(ver == 0xC)
|
||||
return true;
|
||||
|
||||
// 0xD -> 0xE - Initial contents of sparse resources only serialise subresources with mapped pages
|
||||
if(ver == 0xD)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ struct D3D12InitParams
|
||||
UINT SDKVersion = 0;
|
||||
|
||||
// check if a frame capture section version is supported
|
||||
static const uint64_t CurrentVersion = 0xD;
|
||||
static const uint64_t CurrentVersion = 0xE;
|
||||
|
||||
static bool IsSupportedVersion(uint64_t ver);
|
||||
};
|
||||
@@ -850,7 +850,7 @@ public:
|
||||
m_ReplayAGS = ags;
|
||||
}
|
||||
const ReplayOptions &GetReplayOptions() { return m_ReplayOptions; }
|
||||
uint64_t GetLogVersion() { return m_SectionVersion; }
|
||||
uint64_t GetCaptureVersion() { return m_SectionVersion; }
|
||||
CaptureState GetState() { return m_State; }
|
||||
D3D12Replay *GetReplay() { return m_Replay; }
|
||||
WrappedID3D12CommandQueue *GetQueue() { return m_Queue; }
|
||||
|
||||
@@ -61,11 +61,16 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res)
|
||||
|
||||
D3D12InitialContents initContents;
|
||||
|
||||
Sparse::PageTable *sparseTable = NULL;
|
||||
|
||||
if(GetRecord(r)->sparseTable)
|
||||
sparseTable = new Sparse::PageTable(*GetRecord(r)->sparseTable);
|
||||
|
||||
if(desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
|
||||
{
|
||||
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||
|
||||
if(GetRecord(r)->sparseTable == NULL)
|
||||
if(sparseTable == NULL)
|
||||
r->GetHeapProperties(&heapProps, NULL);
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
@@ -185,6 +190,8 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res)
|
||||
bool isDepth =
|
||||
IsDepthFormat(desc.Format) || (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) != 0;
|
||||
|
||||
bool isMSAA = false;
|
||||
|
||||
if(desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D && desc.SampleDesc.Count > 1)
|
||||
{
|
||||
desc.Alignment = 0;
|
||||
@@ -212,6 +219,7 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res)
|
||||
RDCASSERTEQUAL(hr, S_OK);
|
||||
|
||||
destState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
isMSAA = true;
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList *list = Unwrap(m_Device->GetInitialStateList());
|
||||
@@ -288,7 +296,7 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res)
|
||||
bufDesc.MipLevels = 1;
|
||||
bufDesc.SampleDesc.Count = 1;
|
||||
bufDesc.SampleDesc.Quality = 0;
|
||||
bufDesc.Width = 1;
|
||||
bufDesc.Width = 0;
|
||||
|
||||
UINT numSubresources = desc.MipLevels;
|
||||
if(desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D)
|
||||
@@ -305,11 +313,33 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res)
|
||||
numSubresources *= planes;
|
||||
}
|
||||
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts =
|
||||
new D3D12_PLACED_SUBRESOURCE_FOOTPRINT[numSubresources];
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout = {};
|
||||
|
||||
m_Device->GetCopyableFootprints(&desc, 0, numSubresources, 0, layouts, NULL, NULL,
|
||||
&bufDesc.Width);
|
||||
rdcarray<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> copyLayouts;
|
||||
rdcarray<uint32_t> subresources;
|
||||
|
||||
for(UINT i = 0; i < numSubresources; i++)
|
||||
{
|
||||
// skip non-MSAA sparse subresources that are not mapped at all
|
||||
if(!isMSAA && sparseTable && !sparseTable->getPageRangeMapping(i).isMapped())
|
||||
continue;
|
||||
|
||||
UINT64 subSize = 0;
|
||||
m_Device->GetCopyableFootprints(&desc, i, 1, bufDesc.Width, &layout, NULL, NULL, &subSize);
|
||||
|
||||
copyLayouts.push_back(layout);
|
||||
subresources.push_back(i);
|
||||
bufDesc.Width += subSize;
|
||||
bufDesc.Width = AlignUp<UINT64>(bufDesc.Width, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
|
||||
}
|
||||
|
||||
if(bufDesc.Width == 0)
|
||||
bufDesc.Width = 1U;
|
||||
|
||||
// If we're not a sparse single-sampled texture, we copy the whole resource with all
|
||||
// subresources.
|
||||
if(isMSAA || sparseTable == NULL)
|
||||
subresources = {~0U};
|
||||
|
||||
ID3D12Resource *copyDst = NULL;
|
||||
HRESULT hr = m_Device->GetReal()->CreateCommittedResource(
|
||||
@@ -318,7 +348,7 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res)
|
||||
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
for(UINT i = 0; i < numSubresources; i++)
|
||||
for(UINT i = 0; i < copyLayouts.size(); i++)
|
||||
{
|
||||
D3D12_TEXTURE_COPY_LOCATION dst, src;
|
||||
|
||||
@@ -328,7 +358,7 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res)
|
||||
|
||||
dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
dst.pResource = copyDst;
|
||||
dst.PlacedFootprint = layouts[i];
|
||||
dst.PlacedFootprint = copyLayouts[i];
|
||||
|
||||
list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL);
|
||||
}
|
||||
@@ -365,15 +395,12 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res)
|
||||
}
|
||||
|
||||
SAFE_RELEASE(arrayTexture);
|
||||
SAFE_DELETE_ARRAY(layouts);
|
||||
|
||||
initContents = D3D12InitialContents(copyDst);
|
||||
initContents.subresources = subresources;
|
||||
}
|
||||
|
||||
if(GetRecord(r)->sparseTable)
|
||||
{
|
||||
initContents.sparseTable = new Sparse::PageTable(*GetRecord(r)->sparseTable);
|
||||
}
|
||||
initContents.sparseTable = sparseTable;
|
||||
|
||||
SetInitialContents(GetResID(r), initContents);
|
||||
return true;
|
||||
@@ -628,6 +655,21 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI
|
||||
}
|
||||
|
||||
SparseBinds *sparseBinds = NULL;
|
||||
bool skipUnmapped = false;
|
||||
rdcarray<uint32_t> subresourcesIncluded;
|
||||
if(initial)
|
||||
subresourcesIncluded = initial->subresources;
|
||||
|
||||
// default to {~0U} if this isn't present, which means 'all subresources serialised', since an
|
||||
// empty array is valid and means NO subresources were serialised.
|
||||
if(ser.VersionAtLeast(0xE))
|
||||
{
|
||||
SERIALISE_ELEMENT(subresourcesIncluded);
|
||||
}
|
||||
else
|
||||
{
|
||||
subresourcesIncluded = {~0U};
|
||||
}
|
||||
|
||||
if(ser.VersionAtLeast(0xB))
|
||||
{
|
||||
@@ -773,6 +815,8 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI
|
||||
|
||||
initContents.sparseBinds = sparseBinds;
|
||||
|
||||
initContents.subresources = subresourcesIncluded;
|
||||
|
||||
D3D12_RESOURCE_DESC resDesc = liveRes->GetDesc();
|
||||
|
||||
// for MSAA textures we upload to an MSAA texture here so we're ready to copy the image in
|
||||
@@ -1006,6 +1050,7 @@ void D3D12ResourceManager::Create_InitialState(ResourceId id, ID3D12DeviceChild
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create initial state copy: %s", ToStr(hr).c_str());
|
||||
m_Device->CheckHRESULT(hr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1229,7 +1274,7 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live,
|
||||
|
||||
// we only accounted for planes in version 0x6, before then we only copied the first plane
|
||||
// so the buffer won't have enough data
|
||||
if(m_Device->GetLogVersion() >= 0x6)
|
||||
if(m_Device->GetCaptureVersion() >= 0x6)
|
||||
{
|
||||
D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = {};
|
||||
formatInfo.Format = desc.Format;
|
||||
@@ -1240,13 +1285,19 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live,
|
||||
numSubresources *= planes;
|
||||
}
|
||||
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT *layouts =
|
||||
new D3D12_PLACED_SUBRESOURCE_FOOTPRINT[numSubresources];
|
||||
const uint32_t *nextIncludedSubresource = data.subresources.begin();
|
||||
if(data.subresources.empty() || *nextIncludedSubresource == ~0U)
|
||||
nextIncludedSubresource = NULL;
|
||||
|
||||
m_Device->GetCopyableFootprints(&desc, 0, numSubresources, 0, layouts, NULL, NULL, NULL);
|
||||
UINT64 offset = 0;
|
||||
UINT64 subSize = 0;
|
||||
|
||||
for(UINT i = 0; i < numSubresources; i++)
|
||||
{
|
||||
// if we have a list of subresources included, only copy those
|
||||
if(nextIncludedSubresource && *nextIncludedSubresource != i)
|
||||
continue;
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION dst, src;
|
||||
|
||||
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
@@ -1255,12 +1306,23 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live,
|
||||
|
||||
src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
src.pResource = Unwrap(copySrc);
|
||||
src.PlacedFootprint = layouts[i];
|
||||
|
||||
m_Device->GetCopyableFootprints(&desc, i, 1, offset, &src.PlacedFootprint, NULL, NULL,
|
||||
&subSize);
|
||||
|
||||
list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL);
|
||||
}
|
||||
|
||||
delete[] layouts;
|
||||
offset += subSize;
|
||||
offset = AlignUp<UINT64>(offset, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
|
||||
|
||||
if(nextIncludedSubresource)
|
||||
{
|
||||
nextIncludedSubresource++;
|
||||
// no more subresource after this one were included, even if they exist
|
||||
if(nextIncludedSubresource >= data.subresources.end())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// transition back to whatever it was before
|
||||
|
||||
@@ -671,6 +671,8 @@ struct D3D12InitialContents
|
||||
byte *srcData;
|
||||
size_t dataSize;
|
||||
|
||||
rdcarray<uint32_t> subresources;
|
||||
|
||||
// only valid on capture - the snapshotted table at prepare time
|
||||
Sparse::PageTable *sparseTable;
|
||||
// only valid on replay, the table above converted into a set of binds
|
||||
|
||||
Reference in New Issue
Block a user