mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-26 16:36:31 +00:00
Remove fixed limit on stream-out size for D3D11/D3D12. Refs #585
* For VS output we can statically determine how much space is needed and allocate more if we need to. * For tessellation/geometry shader output, we need to run a query to see if there was enough output space, then reallocate and run it again. * On GL there isn't a built-in xfb query, only as an extension with poor support, so we just resize to allow the maximum expansion.
This commit is contained in:
@@ -1189,24 +1189,12 @@ void D3D11DebugManager::ShutdownStreamOut()
|
||||
|
||||
bool D3D11DebugManager::InitStreamOut()
|
||||
{
|
||||
CreateSOBuffers();
|
||||
|
||||
m_MeshDisplayLayout = NULL;
|
||||
|
||||
D3D11_BUFFER_DESC bufferDesc = {
|
||||
m_SOBufferSize, D3D11_USAGE_DEFAULT, D3D11_BIND_STREAM_OUTPUT, 0, 0, 0};
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
hr = m_pDevice->CreateBuffer(&bufferDesc, NULL, &m_SOBuffer);
|
||||
|
||||
if(FAILED(hr))
|
||||
RDCERR("Failed to create m_SOBuffer %08x", hr);
|
||||
|
||||
bufferDesc.Usage = D3D11_USAGE_STAGING;
|
||||
bufferDesc.BindFlags = 0;
|
||||
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
hr = m_pDevice->CreateBuffer(&bufferDesc, NULL, &m_SOStagingBuffer);
|
||||
if(FAILED(hr))
|
||||
RDCERR("Failed to create m_SOStagingBuffer %08x", hr);
|
||||
|
||||
D3D11_QUERY_DESC qdesc;
|
||||
qdesc.MiscFlags = 0;
|
||||
qdesc.Query = D3D11_QUERY_SO_STATISTICS;
|
||||
@@ -1351,6 +1339,29 @@ bool D3D11DebugManager::InitStreamOut()
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11DebugManager::CreateSOBuffers()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
SAFE_RELEASE(m_SOBuffer);
|
||||
SAFE_RELEASE(m_SOStagingBuffer);
|
||||
|
||||
D3D11_BUFFER_DESC bufferDesc = {
|
||||
m_SOBufferSize, D3D11_USAGE_DEFAULT, D3D11_BIND_STREAM_OUTPUT, 0, 0, 0};
|
||||
|
||||
hr = m_pDevice->CreateBuffer(&bufferDesc, NULL, &m_SOBuffer);
|
||||
|
||||
if(FAILED(hr))
|
||||
RDCERR("Failed to create m_SOBuffer %08x", hr);
|
||||
|
||||
bufferDesc.Usage = D3D11_USAGE_STAGING;
|
||||
bufferDesc.BindFlags = 0;
|
||||
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
hr = m_pDevice->CreateBuffer(&bufferDesc, NULL, &m_SOStagingBuffer);
|
||||
if(FAILED(hr))
|
||||
RDCERR("Failed to create m_SOStagingBuffer %08x", hr);
|
||||
}
|
||||
|
||||
bool D3D11DebugManager::InitFontRendering()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
@@ -3832,33 +3843,48 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
SAFE_RELEASE(streamoutGS);
|
||||
|
||||
UINT offset = 0;
|
||||
m_pImmediateContext->SOSetTargets(1, &m_SOBuffer, &offset);
|
||||
|
||||
m_pImmediateContext->Begin(m_SOStatsQueries[0]);
|
||||
|
||||
ID3D11Buffer *idxBuf = NULL;
|
||||
DXGI_FORMAT idxFmt = DXGI_FORMAT_UNKNOWN;
|
||||
UINT idxOffs = 0;
|
||||
|
||||
m_WrappedContext->IAGetIndexBuffer(&idxBuf, &idxFmt, &idxOffs);
|
||||
|
||||
ID3D11Buffer *origBuf = idxBuf;
|
||||
|
||||
if(!(drawcall->flags & DrawFlags::UseIBuffer))
|
||||
{
|
||||
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
|
||||
|
||||
uint32_t outputSize = stride * drawcall->numIndices;
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
outputSize *= drawcall->numInstances;
|
||||
|
||||
if(m_SOBufferSize < outputSize)
|
||||
{
|
||||
int oldSize = m_SOBufferSize;
|
||||
while(m_SOBufferSize < outputSize)
|
||||
m_SOBufferSize *= 2;
|
||||
RDCWARN("Resizing stream-out buffer from %d to %d", oldSize, m_SOBufferSize);
|
||||
CreateSOBuffers();
|
||||
}
|
||||
|
||||
m_pImmediateContext->SOSetTargets(1, &m_SOBuffer, &offset);
|
||||
|
||||
m_pImmediateContext->Begin(m_SOStatsQueries[0]);
|
||||
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
m_pImmediateContext->DrawInstanced(drawcall->numIndices, drawcall->numInstances,
|
||||
drawcall->vertexOffset, drawcall->instanceOffset);
|
||||
else
|
||||
m_pImmediateContext->Draw(drawcall->numIndices, drawcall->vertexOffset);
|
||||
m_pImmediateContext->IASetPrimitiveTopology(topo);
|
||||
|
||||
m_pImmediateContext->End(m_SOStatsQueries[0]);
|
||||
}
|
||||
else // drawcall is indexed
|
||||
{
|
||||
UINT idxOffs = 0;
|
||||
|
||||
m_WrappedContext->IAGetIndexBuffer(&idxBuf, &idxFmt, &idxOffs);
|
||||
bool index16 = (idxFmt == DXGI_FORMAT_R16_UINT);
|
||||
UINT bytesize = index16 ? 2 : 4;
|
||||
|
||||
ID3D11Buffer *origBuf = idxBuf;
|
||||
|
||||
vector<byte> idxdata;
|
||||
GetBufferData(idxBuf, idxOffs + drawcall->indexOffset * bytesize,
|
||||
drawcall->numIndices * bytesize, idxdata, true);
|
||||
@@ -3941,14 +3967,30 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
m_pImmediateContext->IASetIndexBuffer(idxBuf, DXGI_FORMAT_R32_UINT, 0);
|
||||
SAFE_RELEASE(idxBuf);
|
||||
|
||||
uint32_t outputSize = stride * (uint32_t)indices.size();
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
outputSize *= drawcall->numInstances;
|
||||
|
||||
if(m_SOBufferSize < outputSize)
|
||||
{
|
||||
int oldSize = m_SOBufferSize;
|
||||
while(m_SOBufferSize < outputSize)
|
||||
m_SOBufferSize *= 2;
|
||||
RDCWARN("Resizing stream-out buffer from %d to %d", oldSize, m_SOBufferSize);
|
||||
CreateSOBuffers();
|
||||
}
|
||||
|
||||
m_pImmediateContext->SOSetTargets(1, &m_SOBuffer, &offset);
|
||||
|
||||
m_pImmediateContext->Begin(m_SOStatsQueries[0]);
|
||||
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
m_pImmediateContext->DrawIndexedInstanced((UINT)indices.size(), drawcall->numInstances, 0,
|
||||
0, drawcall->instanceOffset);
|
||||
else
|
||||
m_pImmediateContext->DrawIndexed((UINT)indices.size(), 0, 0);
|
||||
|
||||
m_pImmediateContext->IASetPrimitiveTopology(topo);
|
||||
m_pImmediateContext->IASetIndexBuffer(UNWRAP(WrappedID3D11Buffer, origBuf), idxFmt, idxOffs);
|
||||
m_pImmediateContext->End(m_SOStatsQueries[0]);
|
||||
|
||||
// rebase existing index buffer to point to the right elements in our stream-out'd
|
||||
// vertex buffer
|
||||
@@ -3984,7 +4026,8 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
idxBuf = NULL;
|
||||
}
|
||||
|
||||
m_pImmediateContext->End(m_SOStatsQueries[0]);
|
||||
m_pImmediateContext->IASetPrimitiveTopology(topo);
|
||||
m_pImmediateContext->IASetIndexBuffer(UNWRAP(WrappedID3D11Buffer, origBuf), idxFmt, idxOffs);
|
||||
|
||||
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
|
||||
m_pImmediateContext->SOSetTargets(0, NULL, NULL);
|
||||
@@ -4023,15 +4066,6 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
0,
|
||||
0};
|
||||
|
||||
if(bufferDesc.ByteWidth >= m_SOBufferSize)
|
||||
{
|
||||
RDCERR("Generated output data too large: %08x", bufferDesc.ByteWidth);
|
||||
|
||||
m_pImmediateContext->Unmap(m_SOStagingBuffer, 0);
|
||||
SAFE_RELEASE(idxBuf);
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D11Buffer *vsoutBuffer = NULL;
|
||||
|
||||
// we need to map this data into memory for read anyway, might as well make this VB
|
||||
@@ -4222,60 +4256,18 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
SAFE_RELEASE(streamoutGS);
|
||||
|
||||
UINT offset = 0;
|
||||
m_pImmediateContext->SOSetTargets(1, &m_SOBuffer, &offset);
|
||||
|
||||
// instanced draws must be replayed one at a time so we can record the number of primitives from
|
||||
// each drawcall, as due to expansion this can vary per-instance.
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
D3D11_QUERY_DATA_SO_STATISTICS numPrims = {0};
|
||||
|
||||
// do the whole draw, and if our output buffer isn't large enough then loop around.
|
||||
while(true)
|
||||
{
|
||||
// if there is only one instance it's a trivial case and we don't need to bother with the
|
||||
// expensive path
|
||||
if(drawcall->numInstances > 1)
|
||||
m_pImmediateContext->Begin(m_SOStatsQueries[0]);
|
||||
|
||||
m_pImmediateContext->SOSetTargets(1, &m_SOBuffer, &offset);
|
||||
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
{
|
||||
// ensure we have enough queries
|
||||
while(m_SOStatsQueries.size() < drawcall->numInstances)
|
||||
{
|
||||
D3D11_QUERY_DESC qdesc;
|
||||
qdesc.MiscFlags = 0;
|
||||
qdesc.Query = D3D11_QUERY_SO_STATISTICS;
|
||||
|
||||
ID3D11Query *q = NULL;
|
||||
hr = m_pDevice->CreateQuery(&qdesc, &q);
|
||||
if(FAILED(hr))
|
||||
RDCERR("Failed to create m_SOStatsQuery %08x", hr);
|
||||
|
||||
m_SOStatsQueries.push_back(q);
|
||||
}
|
||||
|
||||
// do incremental draws to get the output size. We have to do this O(N^2) style because
|
||||
// there's no way to replay only a single instance. We have to replay 1, 2, 3, ... N
|
||||
// instances and count the total number of verts each time, then we can see from the
|
||||
// difference how much each instance wrote.
|
||||
for(uint32_t inst = 1; inst <= drawcall->numInstances; inst++)
|
||||
{
|
||||
if(drawcall->flags & DrawFlags::UseIBuffer)
|
||||
{
|
||||
m_pImmediateContext->SOSetTargets(1, &m_SOBuffer, &offset);
|
||||
m_pImmediateContext->Begin(m_SOStatsQueries[inst - 1]);
|
||||
m_pImmediateContext->DrawIndexedInstanced(drawcall->numIndices, inst,
|
||||
drawcall->indexOffset, drawcall->baseVertex,
|
||||
drawcall->instanceOffset);
|
||||
m_pImmediateContext->End(m_SOStatsQueries[inst - 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pImmediateContext->SOSetTargets(1, &m_SOBuffer, &offset);
|
||||
m_pImmediateContext->Begin(m_SOStatsQueries[inst - 1]);
|
||||
m_pImmediateContext->DrawInstanced(drawcall->numIndices, inst, drawcall->vertexOffset,
|
||||
drawcall->instanceOffset);
|
||||
m_pImmediateContext->End(m_SOStatsQueries[inst - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pImmediateContext->Begin(m_SOStatsQueries[0]);
|
||||
|
||||
if(drawcall->flags & DrawFlags::UseIBuffer)
|
||||
{
|
||||
m_pImmediateContext->DrawIndexedInstanced(drawcall->numIndices, drawcall->numInstances,
|
||||
@@ -4287,34 +4279,92 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
m_pImmediateContext->DrawInstanced(drawcall->numIndices, drawcall->numInstances,
|
||||
drawcall->vertexOffset, drawcall->instanceOffset);
|
||||
}
|
||||
|
||||
m_pImmediateContext->End(m_SOStatsQueries[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pImmediateContext->Begin(m_SOStatsQueries[0]);
|
||||
|
||||
// trying to stream out a stream-out-auto based drawcall would be bad!
|
||||
// instead just draw the number of verts we pre-calculated
|
||||
if(drawcall->flags & DrawFlags::Auto)
|
||||
{
|
||||
m_pImmediateContext->Draw(drawcall->numIndices, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(drawcall->flags & DrawFlags::UseIBuffer)
|
||||
// trying to stream out a stream-out-auto based drawcall would be bad!
|
||||
// instead just draw the number of verts we pre-calculated
|
||||
if(drawcall->flags & DrawFlags::Auto)
|
||||
{
|
||||
m_pImmediateContext->DrawIndexed(drawcall->numIndices, drawcall->indexOffset,
|
||||
drawcall->baseVertex);
|
||||
m_pImmediateContext->Draw(drawcall->numIndices, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pImmediateContext->Draw(drawcall->numIndices, drawcall->vertexOffset);
|
||||
if(drawcall->flags & DrawFlags::UseIBuffer)
|
||||
{
|
||||
m_pImmediateContext->DrawIndexed(drawcall->numIndices, drawcall->indexOffset,
|
||||
drawcall->baseVertex);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pImmediateContext->Draw(drawcall->numIndices, drawcall->vertexOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_pImmediateContext->End(m_SOStatsQueries[0]);
|
||||
|
||||
do
|
||||
{
|
||||
hr = m_pImmediateContext->GetData(m_SOStatsQueries[0], &numPrims,
|
||||
sizeof(D3D11_QUERY_DATA_SO_STATISTICS), 0);
|
||||
} while(hr == S_FALSE);
|
||||
|
||||
if(m_SOBufferSize < stride * (uint32_t)numPrims.PrimitivesStorageNeeded * 3)
|
||||
{
|
||||
int oldSize = m_SOBufferSize;
|
||||
while(m_SOBufferSize < stride * (uint32_t)numPrims.PrimitivesStorageNeeded * 3)
|
||||
m_SOBufferSize *= 2;
|
||||
RDCWARN("Resizing stream-out buffer from %d to %d", oldSize, m_SOBufferSize);
|
||||
CreateSOBuffers();
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// instanced draws must be replayed one at a time so we can record the number of primitives from
|
||||
// each drawcall, as due to expansion this can vary per-instance.
|
||||
if(drawcall->flags & DrawFlags::Instanced && drawcall->numInstances > 1)
|
||||
{
|
||||
// ensure we have enough queries
|
||||
while(m_SOStatsQueries.size() < drawcall->numInstances)
|
||||
{
|
||||
D3D11_QUERY_DESC qdesc;
|
||||
qdesc.MiscFlags = 0;
|
||||
qdesc.Query = D3D11_QUERY_SO_STATISTICS;
|
||||
|
||||
ID3D11Query *q = NULL;
|
||||
hr = m_pDevice->CreateQuery(&qdesc, &q);
|
||||
if(FAILED(hr))
|
||||
RDCERR("Failed to create m_SOStatsQuery %08x", hr);
|
||||
|
||||
m_SOStatsQueries.push_back(q);
|
||||
}
|
||||
|
||||
// do incremental draws to get the output size. We have to do this O(N^2) style because
|
||||
// there's no way to replay only a single instance. We have to replay 1, 2, 3, ... N
|
||||
// instances and count the total number of verts each time, then we can see from the
|
||||
// difference how much each instance wrote.
|
||||
for(uint32_t inst = 1; inst <= drawcall->numInstances; inst++)
|
||||
{
|
||||
if(drawcall->flags & DrawFlags::UseIBuffer)
|
||||
{
|
||||
m_pImmediateContext->SOSetTargets(1, &m_SOBuffer, &offset);
|
||||
m_pImmediateContext->Begin(m_SOStatsQueries[inst - 1]);
|
||||
m_pImmediateContext->DrawIndexedInstanced(drawcall->numIndices, inst, drawcall->indexOffset,
|
||||
drawcall->baseVertex, drawcall->instanceOffset);
|
||||
m_pImmediateContext->End(m_SOStatsQueries[inst - 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pImmediateContext->SOSetTargets(1, &m_SOBuffer, &offset);
|
||||
m_pImmediateContext->Begin(m_SOStatsQueries[inst - 1]);
|
||||
m_pImmediateContext->DrawInstanced(drawcall->numIndices, inst, drawcall->vertexOffset,
|
||||
drawcall->instanceOffset);
|
||||
m_pImmediateContext->End(m_SOStatsQueries[inst - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
|
||||
@@ -4322,7 +4372,6 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
|
||||
m_pImmediateContext->CopyResource(m_SOStagingBuffer, m_SOBuffer);
|
||||
|
||||
D3D11_QUERY_DATA_SO_STATISTICS numPrims = {0};
|
||||
std::vector<D3D11PostVSData::InstData> instData;
|
||||
|
||||
if((drawcall->flags & DrawFlags::Instanced) && drawcall->numInstances > 1)
|
||||
|
||||
@@ -336,9 +336,9 @@ private:
|
||||
bool m_ShaderCacheDirty, m_CacheShaders;
|
||||
map<uint32_t, ID3DBlob *> m_ShaderCache;
|
||||
|
||||
static const int m_SOBufferSize = 32 * 1024 * 1024;
|
||||
ID3D11Buffer *m_SOBuffer;
|
||||
ID3D11Buffer *m_SOStagingBuffer;
|
||||
uint32_t m_SOBufferSize = 32 * 1024 * 1024;
|
||||
ID3D11Buffer *m_SOBuffer = NULL;
|
||||
ID3D11Buffer *m_SOStagingBuffer = NULL;
|
||||
std::vector<ID3D11Query *> m_SOStatsQueries;
|
||||
// event -> data
|
||||
map<uint32_t, D3D11PostVSData> m_PostVSData;
|
||||
@@ -369,6 +369,7 @@ private:
|
||||
ID3D11Buffer *m_TriHighlightHelper;
|
||||
|
||||
bool InitStreamOut();
|
||||
void CreateSOBuffers();
|
||||
void ShutdownStreamOut();
|
||||
|
||||
// font/text rendering
|
||||
|
||||
@@ -216,65 +216,7 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
|
||||
|
||||
m_CustomShaderTex = NULL;
|
||||
|
||||
{
|
||||
D3D12_RESOURCE_DESC soBufDesc;
|
||||
soBufDesc.Alignment = 0;
|
||||
soBufDesc.DepthOrArraySize = 1;
|
||||
soBufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
// need to allow UAV access to reset the counter each time
|
||||
soBufDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
soBufDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
soBufDesc.Height = 1;
|
||||
soBufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
soBufDesc.MipLevels = 1;
|
||||
soBufDesc.SampleDesc.Count = 1;
|
||||
soBufDesc.SampleDesc.Quality = 0;
|
||||
// add 64 bytes for the counter at the start
|
||||
soBufDesc.Width = m_SOBufferSize + 64;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps;
|
||||
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProps.CreationNodeMask = 1;
|
||||
heapProps.VisibleNodeMask = 1;
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &soBufDesc,
|
||||
D3D12_RESOURCE_STATE_STREAM_OUT, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&m_SOBuffer);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create SO output buffer, HRESULT: 0x%08x", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
soBufDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
heapProps.Type = D3D12_HEAP_TYPE_READBACK;
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(
|
||||
&heapProps, D3D12_HEAP_FLAG_NONE, &soBufDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&m_SOStagingBuffer);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create readback buffer, HRESULT: 0x%08x", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
soBufDesc.Width = m_SOPatchedIndexBufferSize;
|
||||
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(
|
||||
&heapProps, D3D12_HEAP_FLAG_NONE, &soBufDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&m_SOPatchedIndexBuffer);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create SO index buffer, HRESULT: 0x%08x", hr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
CreateSOBuffers();
|
||||
|
||||
{
|
||||
D3D12_RESOURCE_DESC readbackDesc;
|
||||
@@ -1406,6 +1348,100 @@ D3D12DebugManager::~D3D12DebugManager()
|
||||
RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this);
|
||||
}
|
||||
|
||||
void D3D12DebugManager::CreateSOBuffers()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
SAFE_RELEASE(m_SOBuffer);
|
||||
SAFE_RELEASE(m_SOStagingBuffer);
|
||||
SAFE_RELEASE(m_SOPatchedIndexBuffer);
|
||||
SAFE_RELEASE(m_SOQueryHeap);
|
||||
|
||||
D3D12_RESOURCE_DESC soBufDesc;
|
||||
soBufDesc.Alignment = 0;
|
||||
soBufDesc.DepthOrArraySize = 1;
|
||||
soBufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
// need to allow UAV access to reset the counter each time
|
||||
soBufDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
soBufDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
soBufDesc.Height = 1;
|
||||
soBufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
soBufDesc.MipLevels = 1;
|
||||
soBufDesc.SampleDesc.Count = 1;
|
||||
soBufDesc.SampleDesc.Quality = 0;
|
||||
// add 64 bytes for the counter at the start
|
||||
soBufDesc.Width = m_SOBufferSize + 64;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps;
|
||||
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProps.CreationNodeMask = 1;
|
||||
heapProps.VisibleNodeMask = 1;
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &soBufDesc,
|
||||
D3D12_RESOURCE_STATE_STREAM_OUT, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&m_SOBuffer);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create SO output buffer, HRESULT: 0x%08x", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
soBufDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
heapProps.Type = D3D12_HEAP_TYPE_READBACK;
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(
|
||||
&heapProps, D3D12_HEAP_FLAG_NONE, &soBufDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&m_SOStagingBuffer);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create readback buffer, HRESULT: 0x%08x", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
// this is a buffer of unique indices, so it allows for
|
||||
// the worst case - float4 per vertex, all unique indices.
|
||||
soBufDesc.Width = m_SOBufferSize / sizeof(Vec4f);
|
||||
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(
|
||||
&heapProps, D3D12_HEAP_FLAG_NONE, &soBufDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&m_SOPatchedIndexBuffer);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create SO index buffer, HRESULT: 0x%08x", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
D3D12_QUERY_HEAP_DESC queryDesc;
|
||||
queryDesc.Count = 16;
|
||||
queryDesc.NodeMask = 1;
|
||||
queryDesc.Type = D3D12_QUERY_HEAP_TYPE_SO_STATISTICS;
|
||||
hr = m_WrappedDevice->CreateQueryHeap(&queryDesc, __uuidof(m_SOQueryHeap), (void **)&m_SOQueryHeap);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create SO query heap, HRESULT: 0x%08x", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC counterDesc = {};
|
||||
counterDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
|
||||
counterDesc.Format = DXGI_FORMAT_R32_UINT;
|
||||
counterDesc.Buffer.FirstElement = 0;
|
||||
counterDesc.Buffer.NumElements = 4;
|
||||
|
||||
m_WrappedDevice->CreateUnorderedAccessView(m_SOBuffer, NULL, &counterDesc,
|
||||
GetCPUHandle(STREAM_OUT_UAV));
|
||||
|
||||
m_WrappedDevice->CreateUnorderedAccessView(m_SOBuffer, NULL, &counterDesc,
|
||||
GetUAVClearHandle(STREAM_OUT_UAV));
|
||||
}
|
||||
|
||||
string D3D12DebugManager::GetShaderBlob(const char *source, const char *entry,
|
||||
const uint32_t compileFlags, const char *profile,
|
||||
ID3DBlob **srcblob)
|
||||
@@ -3911,8 +3947,28 @@ void D3D12DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
|
||||
ID3D12Resource *idxBuf = NULL;
|
||||
|
||||
bool recreate = false;
|
||||
uint64_t outputSize = stride * drawcall->numIndices * drawcall->numInstances;
|
||||
|
||||
if(m_SOBufferSize < outputSize)
|
||||
{
|
||||
uint64_t oldSize = m_SOBufferSize;
|
||||
while(m_SOBufferSize < outputSize)
|
||||
m_SOBufferSize *= 2;
|
||||
RDCWARN("Resizing stream-out buffer from %llu to %llu for output data", oldSize,
|
||||
m_SOBufferSize);
|
||||
recreate = true;
|
||||
}
|
||||
|
||||
if(!(drawcall->flags & DrawFlags::UseIBuffer))
|
||||
{
|
||||
if(recreate)
|
||||
{
|
||||
m_WrappedDevice->GPUSync();
|
||||
|
||||
CreateSOBuffers();
|
||||
}
|
||||
|
||||
m_DebugList->Reset(m_DebugAlloc, NULL);
|
||||
|
||||
rs.ApplyState(m_DebugList);
|
||||
@@ -4000,10 +4056,20 @@ void D3D12DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
indexRemap[indices[i]] = i;
|
||||
}
|
||||
|
||||
if(indices.size() > m_SOPatchedIndexBufferSize / sizeof(uint32_t))
|
||||
if(m_SOBufferSize / sizeof(Vec4f) < indices.size() * sizeof(uint32_t))
|
||||
{
|
||||
RDCWARN("Too many unique indices, clamping.");
|
||||
indices.resize(m_SOPatchedIndexBufferSize / sizeof(uint32_t));
|
||||
uint64_t oldSize = m_SOBufferSize;
|
||||
while(m_SOBufferSize / sizeof(Vec4f) < indices.size() * sizeof(uint32_t))
|
||||
m_SOBufferSize *= 2;
|
||||
RDCWARN("Resizing stream-out buffer from %llu to %llu for indices", oldSize, m_SOBufferSize);
|
||||
recreate = true;
|
||||
}
|
||||
|
||||
if(recreate)
|
||||
{
|
||||
m_WrappedDevice->GPUSync();
|
||||
|
||||
CreateSOBuffers();
|
||||
}
|
||||
|
||||
FillBuffer(m_SOPatchedIndexBuffer, 0, &indices[0], indices.size() * sizeof(uint32_t));
|
||||
@@ -4118,18 +4184,6 @@ void D3D12DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
m_DebugList->DiscardResource(m_SOBuffer, NULL);
|
||||
m_DebugList->ResourceBarrier(1, &sobarr);
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC counterDesc = {};
|
||||
counterDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
|
||||
counterDesc.Format = DXGI_FORMAT_R32_UINT;
|
||||
counterDesc.Buffer.FirstElement = 0;
|
||||
counterDesc.Buffer.NumElements = 4;
|
||||
|
||||
m_WrappedDevice->CreateUnorderedAccessView(m_SOBuffer, NULL, &counterDesc,
|
||||
GetCPUHandle(STREAM_OUT_UAV));
|
||||
|
||||
m_WrappedDevice->CreateUnorderedAccessView(m_SOBuffer, NULL, &counterDesc,
|
||||
GetUAVClearHandle(STREAM_OUT_UAV));
|
||||
|
||||
UINT zeroes[4] = {0, 0, 0, 0};
|
||||
m_DebugList->ClearUnorderedAccessViewUint(
|
||||
GetGPUHandle(STREAM_OUT_UAV), GetUAVClearHandle(STREAM_OUT_UAV), m_SOBuffer, zeroes, 0, NULL);
|
||||
@@ -4169,16 +4223,6 @@ void D3D12DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
// skip past the counter
|
||||
byteData += 64;
|
||||
|
||||
if(numBytesWritten >= m_SOBufferSize)
|
||||
{
|
||||
RDCERR("Generated output data too large: %08x", numBytesWritten);
|
||||
|
||||
m_SOStagingBuffer->Unmap(0, &range);
|
||||
SAFE_RELEASE(idxBuf);
|
||||
SAFE_RELEASE(soSig);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t numPrims = numBytesWritten / stride;
|
||||
|
||||
ID3D12Resource *vsoutBuffer = NULL;
|
||||
@@ -4390,27 +4434,126 @@ void D3D12DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
return;
|
||||
}
|
||||
|
||||
m_DebugList->Reset(m_DebugAlloc, NULL);
|
||||
|
||||
rs.ApplyState(m_DebugList);
|
||||
|
||||
m_DebugList->SetPipelineState(pipe);
|
||||
|
||||
if(soSig)
|
||||
{
|
||||
m_DebugList->SetGraphicsRootSignature(soSig);
|
||||
rs.ApplyGraphicsRootElements(m_DebugList);
|
||||
}
|
||||
|
||||
D3D12_STREAM_OUTPUT_BUFFER_VIEW view;
|
||||
|
||||
view.BufferFilledSizeLocation = m_SOBuffer->GetGPUVirtualAddress();
|
||||
view.BufferLocation = m_SOBuffer->GetGPUVirtualAddress() + 64;
|
||||
view.SizeInBytes = m_SOBufferSize;
|
||||
|
||||
// draws with multiple instances must be replayed one at a time so we can record the number of
|
||||
// primitives from each drawcall, as due to expansion this can vary per-instance.
|
||||
if(drawcall->numInstances > 1)
|
||||
{
|
||||
m_DebugList->Reset(m_DebugAlloc, NULL);
|
||||
|
||||
rs.ApplyState(m_DebugList);
|
||||
|
||||
m_DebugList->SetPipelineState(pipe);
|
||||
|
||||
if(soSig)
|
||||
{
|
||||
m_DebugList->SetGraphicsRootSignature(soSig);
|
||||
rs.ApplyGraphicsRootElements(m_DebugList);
|
||||
}
|
||||
|
||||
view.BufferFilledSizeLocation = m_SOBuffer->GetGPUVirtualAddress();
|
||||
view.BufferLocation = m_SOBuffer->GetGPUVirtualAddress() + 64;
|
||||
view.SizeInBytes = m_SOBufferSize;
|
||||
|
||||
// do a dummy draw to make sure we have enough space in the output buffer
|
||||
m_DebugList->SOSetTargets(0, 1, &view);
|
||||
|
||||
m_DebugList->BeginQuery(m_SOQueryHeap, D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0, 0);
|
||||
|
||||
// because the result is expanded we don't have to remap index buffers or anything
|
||||
if(drawcall->flags & DrawFlags::UseIBuffer)
|
||||
{
|
||||
m_DebugList->DrawIndexedInstanced(drawcall->numIndices, drawcall->numInstances,
|
||||
drawcall->indexOffset, drawcall->baseVertex,
|
||||
drawcall->instanceOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DebugList->DrawInstanced(drawcall->numIndices, drawcall->numInstances,
|
||||
drawcall->vertexOffset, drawcall->instanceOffset);
|
||||
}
|
||||
|
||||
m_DebugList->EndQuery(m_SOQueryHeap, D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0, 0);
|
||||
|
||||
m_DebugList->ResolveQueryData(m_SOQueryHeap, D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0, 0, 1,
|
||||
m_SOStagingBuffer, 0);
|
||||
|
||||
m_DebugList->Close();
|
||||
|
||||
ID3D12CommandList *l = m_DebugList;
|
||||
m_WrappedDevice->GetQueue()->ExecuteCommandLists(1, &l);
|
||||
m_WrappedDevice->GPUSync();
|
||||
|
||||
// check that things are OK, and resize up if needed
|
||||
D3D12_RANGE range;
|
||||
range.Begin = 0;
|
||||
range.End = (SIZE_T)sizeof(D3D12_QUERY_DATA_SO_STATISTICS);
|
||||
|
||||
D3D12_QUERY_DATA_SO_STATISTICS *data;
|
||||
hr = m_SOStagingBuffer->Map(0, &range, (void **)&data);
|
||||
|
||||
D3D12_QUERY_DATA_SO_STATISTICS result = *data;
|
||||
|
||||
range.End = 0;
|
||||
m_SOStagingBuffer->Unmap(0, &range);
|
||||
|
||||
if(m_SOBufferSize < data->PrimitivesStorageNeeded * 3 * stride)
|
||||
{
|
||||
uint64_t oldSize = m_SOBufferSize;
|
||||
while(m_SOBufferSize < data->PrimitivesStorageNeeded * 3 * stride)
|
||||
m_SOBufferSize *= 2;
|
||||
RDCWARN("Resizing stream-out buffer from %llu to %llu for output", oldSize, m_SOBufferSize);
|
||||
CreateSOBuffers();
|
||||
}
|
||||
|
||||
view.BufferFilledSizeLocation = m_SOBuffer->GetGPUVirtualAddress();
|
||||
view.BufferLocation = m_SOBuffer->GetGPUVirtualAddress() + 64;
|
||||
view.SizeInBytes = m_SOBufferSize;
|
||||
|
||||
m_DebugAlloc->Reset();
|
||||
|
||||
// now do the actual stream out
|
||||
m_DebugList->Reset(m_DebugAlloc, NULL);
|
||||
|
||||
// first need to reset the counter byte values which may have either been written to above, or
|
||||
// are newly created
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER sobarr = {};
|
||||
sobarr.Transition.pResource = m_SOBuffer;
|
||||
sobarr.Transition.StateBefore = D3D12_RESOURCE_STATE_STREAM_OUT;
|
||||
sobarr.Transition.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
|
||||
m_DebugList->ResourceBarrier(1, &sobarr);
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC counterDesc = {};
|
||||
counterDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
|
||||
counterDesc.Format = DXGI_FORMAT_R32_UINT;
|
||||
counterDesc.Buffer.FirstElement = 0;
|
||||
counterDesc.Buffer.NumElements = 4;
|
||||
|
||||
UINT zeroes[4] = {0, 0, 0, 0};
|
||||
m_DebugList->ClearUnorderedAccessViewUint(GetGPUHandle(STREAM_OUT_UAV),
|
||||
GetUAVClearHandle(STREAM_OUT_UAV), m_SOBuffer,
|
||||
zeroes, 0, NULL);
|
||||
|
||||
std::swap(sobarr.Transition.StateBefore, sobarr.Transition.StateAfter);
|
||||
m_DebugList->ResourceBarrier(1, &sobarr);
|
||||
}
|
||||
|
||||
rs.ApplyState(m_DebugList);
|
||||
|
||||
m_DebugList->SetPipelineState(pipe);
|
||||
|
||||
if(soSig)
|
||||
{
|
||||
m_DebugList->SetGraphicsRootSignature(soSig);
|
||||
rs.ApplyGraphicsRootElements(m_DebugList);
|
||||
}
|
||||
|
||||
// reserve space for enough 'buffer filled size' locations
|
||||
view.BufferLocation = m_SOBuffer->GetGPUVirtualAddress() +
|
||||
AlignUp(uint64_t(drawcall->numInstances * sizeof(UINT64)), 64ULL);
|
||||
@@ -4439,26 +4582,93 @@ void D3D12DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
}
|
||||
}
|
||||
|
||||
m_DebugList->Close();
|
||||
|
||||
l = m_DebugList;
|
||||
m_WrappedDevice->GetQueue()->ExecuteCommandLists(1, &l);
|
||||
m_WrappedDevice->GPUSync();
|
||||
|
||||
// the last draw will have written the actual data we want into the buffer
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DebugList->SOSetTargets(0, 1, &view);
|
||||
// this only loops if we find from a query that we need to resize up
|
||||
while(true)
|
||||
{
|
||||
m_DebugList->Reset(m_DebugAlloc, NULL);
|
||||
|
||||
// because the result is expanded we don't have to remap index buffers or anything
|
||||
if(drawcall->flags & DrawFlags::UseIBuffer)
|
||||
{
|
||||
m_DebugList->DrawIndexedInstanced(drawcall->numIndices, drawcall->numInstances,
|
||||
drawcall->indexOffset, drawcall->baseVertex,
|
||||
drawcall->instanceOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DebugList->DrawInstanced(drawcall->numIndices, drawcall->numInstances,
|
||||
drawcall->vertexOffset, drawcall->instanceOffset);
|
||||
rs.ApplyState(m_DebugList);
|
||||
|
||||
m_DebugList->SetPipelineState(pipe);
|
||||
|
||||
if(soSig)
|
||||
{
|
||||
m_DebugList->SetGraphicsRootSignature(soSig);
|
||||
rs.ApplyGraphicsRootElements(m_DebugList);
|
||||
}
|
||||
|
||||
view.BufferFilledSizeLocation = m_SOBuffer->GetGPUVirtualAddress();
|
||||
view.BufferLocation = m_SOBuffer->GetGPUVirtualAddress() + 64;
|
||||
view.SizeInBytes = m_SOBufferSize;
|
||||
|
||||
m_DebugList->SOSetTargets(0, 1, &view);
|
||||
|
||||
m_DebugList->BeginQuery(m_SOQueryHeap, D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0, 0);
|
||||
|
||||
// because the result is expanded we don't have to remap index buffers or anything
|
||||
if(drawcall->flags & DrawFlags::UseIBuffer)
|
||||
{
|
||||
m_DebugList->DrawIndexedInstanced(drawcall->numIndices, drawcall->numInstances,
|
||||
drawcall->indexOffset, drawcall->baseVertex,
|
||||
drawcall->instanceOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DebugList->DrawInstanced(drawcall->numIndices, drawcall->numInstances,
|
||||
drawcall->vertexOffset, drawcall->instanceOffset);
|
||||
}
|
||||
|
||||
m_DebugList->EndQuery(m_SOQueryHeap, D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0, 0);
|
||||
|
||||
m_DebugList->ResolveQueryData(m_SOQueryHeap, D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0, 0, 1,
|
||||
m_SOStagingBuffer, 0);
|
||||
|
||||
m_DebugList->Close();
|
||||
|
||||
ID3D12CommandList *l = m_DebugList;
|
||||
m_WrappedDevice->GetQueue()->ExecuteCommandLists(1, &l);
|
||||
m_WrappedDevice->GPUSync();
|
||||
|
||||
// check that things are OK, and resize up if needed
|
||||
D3D12_RANGE range;
|
||||
range.Begin = 0;
|
||||
range.End = (SIZE_T)sizeof(D3D12_QUERY_DATA_SO_STATISTICS);
|
||||
|
||||
D3D12_QUERY_DATA_SO_STATISTICS *data;
|
||||
hr = m_SOStagingBuffer->Map(0, &range, (void **)&data);
|
||||
|
||||
if(m_SOBufferSize < data->PrimitivesStorageNeeded * 3 * stride)
|
||||
{
|
||||
uint64_t oldSize = m_SOBufferSize;
|
||||
while(m_SOBufferSize < data->PrimitivesStorageNeeded * 3 * stride)
|
||||
m_SOBufferSize *= 2;
|
||||
RDCWARN("Resizing stream-out buffer from %llu to %llu for output", oldSize, m_SOBufferSize);
|
||||
CreateSOBuffers();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
range.End = 0;
|
||||
m_SOStagingBuffer->Unmap(0, &range);
|
||||
|
||||
m_DebugAlloc->Reset();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_DebugList->Reset(m_DebugAlloc, NULL);
|
||||
|
||||
D3D12_RESOURCE_BARRIER sobarr = {};
|
||||
sobarr.Transition.pResource = m_SOBuffer;
|
||||
sobarr.Transition.StateBefore = D3D12_RESOURCE_STATE_STREAM_OUT;
|
||||
@@ -4542,15 +4752,6 @@ void D3D12DebugManager::InitPostVSBuffers(uint32_t eventID)
|
||||
// skip past the counter(s)
|
||||
byteData += (view.BufferLocation - m_SOBuffer->GetGPUVirtualAddress());
|
||||
|
||||
if(numBytesWritten >= m_SOBufferSize)
|
||||
{
|
||||
RDCERR("Generated output data too large: %08x", numBytesWritten);
|
||||
|
||||
m_SOStagingBuffer->Unmap(0, &range);
|
||||
SAFE_RELEASE(soSig);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t numVerts = numBytesWritten / stride;
|
||||
|
||||
ID3D12Resource *gsoutBuffer = NULL;
|
||||
@@ -5298,6 +5499,9 @@ void D3D12DebugManager::RenderMesh(uint32_t eventID, const vector<MeshFormat> &s
|
||||
|
||||
list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(fmt.topo));
|
||||
|
||||
if(PatchList_Count(fmt.topo) > 0)
|
||||
list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
|
||||
|
||||
if(fmt.idxByteWidth && fmt.idxbuf != ResourceId())
|
||||
{
|
||||
ID3D12Resource *ib =
|
||||
@@ -5337,6 +5541,9 @@ void D3D12DebugManager::RenderMesh(uint32_t eventID, const vector<MeshFormat> &s
|
||||
list->IASetVertexBuffers(1, 1, &view);
|
||||
|
||||
list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(cfg.position.topo));
|
||||
|
||||
if(PatchList_Count(cfg.position.topo) > 0)
|
||||
list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
|
||||
}
|
||||
|
||||
SolidShade solidShadeMode = cfg.solidShadeMode;
|
||||
@@ -5639,6 +5846,9 @@ void D3D12DebugManager::RenderMesh(uint32_t eventID, const vector<MeshFormat> &s
|
||||
|
||||
list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(helper.topo));
|
||||
|
||||
if(PatchList_Count(helper.topo) > 0)
|
||||
list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
|
||||
|
||||
list->SetGraphicsRootConstantBufferView(0, UploadConstants(&vertexData, sizeof(vertexData)));
|
||||
|
||||
list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Solid]);
|
||||
@@ -5702,6 +5912,9 @@ void D3D12DebugManager::RenderMesh(uint32_t eventID, const vector<MeshFormat> &s
|
||||
|
||||
list->IASetPrimitiveTopology(MakeD3DPrimitiveTopology(helper.topo));
|
||||
|
||||
if(PatchList_Count(helper.topo) > 0)
|
||||
list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
|
||||
|
||||
list->SetPipelineState(cache.pipes[MeshDisplayPipelines::ePipe_Solid]);
|
||||
|
||||
{
|
||||
|
||||
@@ -39,7 +39,6 @@ class D3D12DebugManager
|
||||
{
|
||||
public:
|
||||
D3D12DebugManager(WrappedID3D12Device *wrapper);
|
||||
|
||||
~D3D12DebugManager();
|
||||
|
||||
uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth);
|
||||
@@ -319,6 +318,8 @@ private:
|
||||
const char *profile, ID3DBlob **srcblob);
|
||||
ID3DBlob *MakeFixedColShader(float overlayConsts[4]);
|
||||
|
||||
void CreateSOBuffers();
|
||||
|
||||
struct MeshDisplayPipelines
|
||||
{
|
||||
enum
|
||||
@@ -390,14 +391,11 @@ private:
|
||||
uint32_t m_PickSize;
|
||||
ID3D12Resource *m_PickResultBuf;
|
||||
|
||||
static const int m_SOBufferSize = 32 * 1024 * 1024;
|
||||
ID3D12Resource *m_SOBuffer;
|
||||
ID3D12Resource *m_SOStagingBuffer;
|
||||
|
||||
// this is a buffer of unique indices, so it allows for
|
||||
// the worst case - float4 per vertex, all unique indices.
|
||||
static const int m_SOPatchedIndexBufferSize = m_SOBufferSize / 16;
|
||||
ID3D12Resource *m_SOPatchedIndexBuffer;
|
||||
uint64_t m_SOBufferSize = 128;
|
||||
ID3D12Resource *m_SOBuffer = NULL;
|
||||
ID3D12Resource *m_SOStagingBuffer = NULL;
|
||||
ID3D12Resource *m_SOPatchedIndexBuffer = NULL;
|
||||
ID3D12QueryHeap *m_SOQueryHeap = NULL;
|
||||
|
||||
map<uint32_t, D3D12PostVSData> m_PostVSData;
|
||||
map<uint32_t, uint32_t> m_PostVSAlias;
|
||||
|
||||
@@ -665,7 +665,8 @@ void GLReplay::InitDebugData()
|
||||
|
||||
gl.glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, DebugData.feedbackObj);
|
||||
gl.glBindBuffer(eGL_TRANSFORM_FEEDBACK_BUFFER, DebugData.feedbackBuffer);
|
||||
gl.glNamedBufferDataEXT(DebugData.feedbackBuffer, 32 * 1024 * 1024, NULL, eGL_DYNAMIC_READ);
|
||||
gl.glNamedBufferDataEXT(DebugData.feedbackBuffer, DebugData.feedbackBufferSize, NULL,
|
||||
eGL_DYNAMIC_READ);
|
||||
gl.glBindBufferBase(eGL_TRANSFORM_FEEDBACK_BUFFER, 0, DebugData.feedbackBuffer);
|
||||
gl.glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, 0);
|
||||
|
||||
@@ -3581,19 +3582,35 @@ void GLReplay::InitPostVSBuffers(uint32_t eventID)
|
||||
|
||||
gl.glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, DebugData.feedbackObj);
|
||||
|
||||
// need to rebind this here because of an AMD bug that seems to ignore the buffer
|
||||
// bindings in the feedback object - or at least it errors if the default feedback
|
||||
// object has no buffers bound. Fortunately the state is still object-local so
|
||||
// we don't have to restore the buffer binding on the default feedback object.
|
||||
gl.glBindBufferBase(eGL_TRANSFORM_FEEDBACK_BUFFER, 0, DebugData.feedbackBuffer);
|
||||
|
||||
GLuint idxBuf = 0;
|
||||
|
||||
gl.glBeginQuery(eGL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, DebugData.feedbackQueries[0]);
|
||||
gl.glBeginTransformFeedback(eGL_POINTS);
|
||||
|
||||
if(!(drawcall->flags & DrawFlags::UseIBuffer))
|
||||
{
|
||||
uint32_t outputSize = drawcall->numIndices * drawcall->numInstances * stride;
|
||||
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
outputSize *= drawcall->numInstances;
|
||||
|
||||
// resize up the buffer if needed for the vertex output data
|
||||
if(DebugData.feedbackBufferSize < outputSize)
|
||||
{
|
||||
uint32_t oldSize = DebugData.feedbackBufferSize;
|
||||
while(DebugData.feedbackBufferSize < outputSize)
|
||||
DebugData.feedbackBufferSize *= 2;
|
||||
RDCWARN("Resizing xfb buffer from %u to %u for output", oldSize, DebugData.feedbackBufferSize);
|
||||
gl.glNamedBufferDataEXT(DebugData.feedbackBuffer, DebugData.feedbackBufferSize, NULL,
|
||||
eGL_DYNAMIC_READ);
|
||||
}
|
||||
|
||||
// need to rebind this here because of an AMD bug that seems to ignore the buffer
|
||||
// bindings in the feedback object - or at least it errors if the default feedback
|
||||
// object has no buffers bound. Fortunately the state is still object-local so
|
||||
// we don't have to restore the buffer binding on the default feedback object.
|
||||
gl.glBindBufferBase(eGL_TRANSFORM_FEEDBACK_BUFFER, 0, DebugData.feedbackBuffer);
|
||||
|
||||
gl.glBeginQuery(eGL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, DebugData.feedbackQueries[0]);
|
||||
gl.glBeginTransformFeedback(eGL_POINTS);
|
||||
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
{
|
||||
if(HasExt[ARB_base_instance])
|
||||
@@ -3682,6 +3699,31 @@ void GLReplay::InitPostVSBuffers(uint32_t eventID)
|
||||
gl.glNamedBufferDataEXT(indexSetBuffer, sizeof(uint32_t) * indices.size(), &indices[0],
|
||||
eGL_STATIC_DRAW);
|
||||
|
||||
uint32_t outputSize = (uint32_t)indices.size() * drawcall->numInstances * stride;
|
||||
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
outputSize *= drawcall->numInstances;
|
||||
|
||||
// resize up the buffer if needed for the vertex output data
|
||||
if(DebugData.feedbackBufferSize < outputSize)
|
||||
{
|
||||
uint32_t oldSize = DebugData.feedbackBufferSize;
|
||||
while(DebugData.feedbackBufferSize < outputSize)
|
||||
DebugData.feedbackBufferSize *= 2;
|
||||
RDCWARN("Resizing xfb buffer from %u to %u for output", oldSize, DebugData.feedbackBufferSize);
|
||||
gl.glNamedBufferDataEXT(DebugData.feedbackBuffer, DebugData.feedbackBufferSize, NULL,
|
||||
eGL_DYNAMIC_READ);
|
||||
}
|
||||
|
||||
// need to rebind this here because of an AMD bug that seems to ignore the buffer
|
||||
// bindings in the feedback object - or at least it errors if the default feedback
|
||||
// object has no buffers bound. Fortunately the state is still object-local so
|
||||
// we don't have to restore the buffer binding on the default feedback object.
|
||||
gl.glBindBufferBase(eGL_TRANSFORM_FEEDBACK_BUFFER, 0, DebugData.feedbackBuffer);
|
||||
|
||||
gl.glBeginQuery(eGL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, DebugData.feedbackQueries[0]);
|
||||
gl.glBeginTransformFeedback(eGL_POINTS);
|
||||
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
{
|
||||
if(HasExt[ARB_base_instance])
|
||||
@@ -4104,28 +4146,126 @@ void GLReplay::InitPostVSBuffers(uint32_t eventID)
|
||||
GLenum shaderOutMode = eGL_TRIANGLES;
|
||||
GLenum lastOutTopo = eGL_TRIANGLES;
|
||||
|
||||
uint32_t maxOutputSize = stride;
|
||||
|
||||
if(drawcall->flags & DrawFlags::Instanced)
|
||||
maxOutputSize *= drawcall->numInstances;
|
||||
|
||||
uint32_t numInputPrimitives = drawcall->numIndices;
|
||||
GLenum drawtopo = MakeGLPrimitiveTopology(drawcall->topology);
|
||||
|
||||
switch(drawcall->topology)
|
||||
{
|
||||
case Topology::PointList: break;
|
||||
case Topology::LineList: numInputPrimitives /= 2; break;
|
||||
case Topology::LineStrip: numInputPrimitives -= 1; break;
|
||||
case Topology::LineLoop: break;
|
||||
case Topology::TriangleList: numInputPrimitives /= 3; break;
|
||||
case Topology::TriangleStrip:
|
||||
case Topology::TriangleFan: numInputPrimitives -= 2; break;
|
||||
case Topology::LineList_Adj: numInputPrimitives /= 4; break;
|
||||
case Topology::LineStrip_Adj: numInputPrimitives -= 3; break;
|
||||
case Topology::TriangleList_Adj: numInputPrimitives /= 6; break;
|
||||
case Topology::TriangleStrip_Adj: numInputPrimitives -= 5; break;
|
||||
case Topology::PatchList_1CPs:
|
||||
case Topology::PatchList_2CPs:
|
||||
case Topology::PatchList_3CPs:
|
||||
case Topology::PatchList_4CPs:
|
||||
case Topology::PatchList_5CPs:
|
||||
case Topology::PatchList_6CPs:
|
||||
case Topology::PatchList_7CPs:
|
||||
case Topology::PatchList_8CPs:
|
||||
case Topology::PatchList_9CPs:
|
||||
case Topology::PatchList_10CPs:
|
||||
case Topology::PatchList_11CPs:
|
||||
case Topology::PatchList_12CPs:
|
||||
case Topology::PatchList_13CPs:
|
||||
case Topology::PatchList_14CPs:
|
||||
case Topology::PatchList_15CPs:
|
||||
case Topology::PatchList_16CPs:
|
||||
case Topology::PatchList_17CPs:
|
||||
case Topology::PatchList_18CPs:
|
||||
case Topology::PatchList_19CPs:
|
||||
case Topology::PatchList_20CPs:
|
||||
case Topology::PatchList_21CPs:
|
||||
case Topology::PatchList_22CPs:
|
||||
case Topology::PatchList_23CPs:
|
||||
case Topology::PatchList_24CPs:
|
||||
case Topology::PatchList_25CPs:
|
||||
case Topology::PatchList_26CPs:
|
||||
case Topology::PatchList_27CPs:
|
||||
case Topology::PatchList_28CPs:
|
||||
case Topology::PatchList_29CPs:
|
||||
case Topology::PatchList_30CPs:
|
||||
case Topology::PatchList_31CPs:
|
||||
case Topology::PatchList_32CPs:
|
||||
numInputPrimitives /= PatchList_Count(drawcall->topology);
|
||||
break;
|
||||
}
|
||||
|
||||
if(lastProg == gsProg)
|
||||
{
|
||||
gl.glGetProgramiv(gsProg, eGL_GEOMETRY_OUTPUT_TYPE, (GLint *)&shaderOutMode);
|
||||
|
||||
GLint maxVerts = 1;
|
||||
|
||||
gl.glGetProgramiv(gsProg, eGL_GEOMETRY_VERTICES_OUT, (GLint *)&maxVerts);
|
||||
|
||||
if(shaderOutMode == eGL_TRIANGLE_STRIP)
|
||||
{
|
||||
lastOutTopo = eGL_TRIANGLES;
|
||||
maxVerts = RDCMAX(3, maxVerts);
|
||||
}
|
||||
else if(shaderOutMode == eGL_LINE_STRIP)
|
||||
{
|
||||
lastOutTopo = eGL_LINES;
|
||||
maxVerts = RDCMAX(2, maxVerts);
|
||||
}
|
||||
else if(shaderOutMode == eGL_POINTS)
|
||||
{
|
||||
lastOutTopo = eGL_POINTS;
|
||||
maxVerts = RDCMAX(1, maxVerts);
|
||||
}
|
||||
|
||||
maxOutputSize *= maxVerts * numInputPrimitives;
|
||||
}
|
||||
else if(lastProg == tesProg)
|
||||
{
|
||||
gl.glGetProgramiv(tesProg, eGL_TESS_GEN_MODE, (GLint *)&shaderOutMode);
|
||||
|
||||
uint32_t outputPrimitiveVerts = 1;
|
||||
|
||||
if(shaderOutMode == eGL_QUADS)
|
||||
{
|
||||
lastOutTopo = eGL_TRIANGLES;
|
||||
outputPrimitiveVerts = 3;
|
||||
}
|
||||
else if(shaderOutMode == eGL_ISOLINES)
|
||||
{
|
||||
lastOutTopo = eGL_LINES;
|
||||
outputPrimitiveVerts = 2;
|
||||
}
|
||||
else if(shaderOutMode == eGL_TRIANGLES)
|
||||
{
|
||||
lastOutTopo = eGL_TRIANGLES;
|
||||
outputPrimitiveVerts = 3;
|
||||
}
|
||||
|
||||
// assume an average maximum tessellation level of 32
|
||||
maxOutputSize *= 32 * outputPrimitiveVerts * numInputPrimitives;
|
||||
}
|
||||
|
||||
GLenum drawtopo = MakeGLPrimitiveTopology(drawcall->topology);
|
||||
// resize up the buffer if needed for the vertex output data
|
||||
if(DebugData.feedbackBufferSize < maxOutputSize)
|
||||
{
|
||||
uint32_t oldSize = DebugData.feedbackBufferSize;
|
||||
while(DebugData.feedbackBufferSize < maxOutputSize)
|
||||
DebugData.feedbackBufferSize *= 2;
|
||||
RDCWARN("Conservatively resizing xfb buffer from %u to %u for output", oldSize,
|
||||
DebugData.feedbackBufferSize);
|
||||
gl.glNamedBufferDataEXT(DebugData.feedbackBuffer, DebugData.feedbackBufferSize, NULL,
|
||||
eGL_DYNAMIC_READ);
|
||||
}
|
||||
|
||||
GLenum idxType = eGL_UNSIGNED_BYTE;
|
||||
if(drawcall->indexByteWidth == 2)
|
||||
|
||||
@@ -340,6 +340,7 @@ private:
|
||||
GLuint feedbackObj;
|
||||
std::vector<GLuint> feedbackQueries;
|
||||
GLuint feedbackBuffer;
|
||||
uint32_t feedbackBufferSize = 32 * 1024 * 1024;
|
||||
|
||||
GLuint pickPixelTex;
|
||||
GLuint pickPixelFBO;
|
||||
|
||||
Reference in New Issue
Block a user