From 319d1448919f602ab26f9b140384f2db934162d2 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 24 Apr 2017 17:24:04 +0100 Subject: [PATCH] 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. --- renderdoc/driver/d3d11/d3d11_debug.cpp | 259 ++++++++------ renderdoc/driver/d3d11/d3d11_debug.h | 7 +- renderdoc/driver/d3d12/d3d12_debug.cpp | 449 ++++++++++++++++++------- renderdoc/driver/d3d12/d3d12_debug.h | 16 +- renderdoc/driver/gl/gl_debug.cpp | 162 ++++++++- renderdoc/driver/gl/gl_replay.h | 1 + 6 files changed, 648 insertions(+), 246 deletions(-) diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index ded75fb07..bd57dd797 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -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 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 instData; if((drawcall->flags & DrawFlags::Instanced) && drawcall->numInstances > 1) diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index e1da23870..330f92e9b 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -336,9 +336,9 @@ private: bool m_ShaderCacheDirty, m_CacheShaders; map 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 m_SOStatsQueries; // event -> data map m_PostVSData; @@ -369,6 +369,7 @@ private: ID3D11Buffer *m_TriHighlightHelper; bool InitStreamOut(); + void CreateSOBuffers(); void ShutdownStreamOut(); // font/text rendering diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index 0429914e6..790951c50 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -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 &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 &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 &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 &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]); { diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h index 28dd8242c..8c59660fe 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.h +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -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 m_PostVSData; map m_PostVSAlias; diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 9beca3339..461f2b9a0 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -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) diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index b14b7d720..e5d3c4dee 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -340,6 +340,7 @@ private: GLuint feedbackObj; std::vector feedbackQueries; GLuint feedbackBuffer; + uint32_t feedbackBufferSize = 32 * 1024 * 1024; GLuint pickPixelTex; GLuint pickPixelFBO;