From a703dc54d005db6d90015dec71989f2a98f5722f Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 28 Jan 2015 02:21:14 +0000 Subject: [PATCH] Fix instancing support for post-vs mesh views on D3D11 and GL * We stream-out or transform feedback the whole instanced draw at once, producing a buffer containing all N instances in one. Then when the client requests postvs data, an offset into the buffer is calculated (in 1/N chunks) and carried through everywhere. * Since we were using the offset to indicate where the system position output lay for since-last-clear auto drawing of meshes, we rearrange the output attribute order so system position is always first in the list. * Also since-last-clear now doesn't include the current event, but does include any previous instances before the current instance. --- renderdoc/api/replay/control_types.h | 1 + renderdoc/api/replay/renderdoc_replay.h | 2 +- renderdoc/core/image_viewer.cpp | 2 +- renderdoc/core/replay_proxy.cpp | 7 +- renderdoc/core/replay_proxy.h | 2 +- renderdoc/driver/d3d11/d3d11_analyse.cpp | 5 +- renderdoc/driver/d3d11/d3d11_debug.cpp | 137 +++++++++++++++-------- renderdoc/driver/d3d11/d3d11_debug.h | 10 +- renderdoc/driver/d3d11/d3d11_replay.cpp | 4 +- renderdoc/driver/d3d11/d3d11_replay.h | 2 +- renderdoc/driver/gl/gl_debug.cpp | 105 +++++++++++++---- renderdoc/driver/gl/gl_replay.h | 17 ++- renderdoc/replay/replay_driver.h | 2 +- renderdoc/replay/replay_output.cpp | 55 ++++++--- renderdoc/replay/replay_renderer.cpp | 10 +- renderdoc/replay/replay_renderer.h | 2 +- renderdocui/Interop/FetchInfo.cs | 1 + renderdocui/Interop/ReplayRenderer.cs | 6 +- renderdocui/Windows/BufferViewer.cs | 127 ++++++++++++--------- 19 files changed, 332 insertions(+), 165 deletions(-) diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index 1a715e0e5..7d2bc04f4 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -66,6 +66,7 @@ struct MeshDisplay float fov, aspect; bool32 thisDrawOnly; + uint32_t curInstance; uint32_t highlightVert; MeshFormat position; diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index fb8114f13..df761fe34 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -164,7 +164,7 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetCBufferVariableCo extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_SaveTexture(ReplayRenderer *rend, const TextureSave &saveData, const char *path); -extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetPostVSData(ReplayRenderer *rend, MeshDataStage stage, MeshFormat *data); +extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetPostVSData(ReplayRenderer *rend, uint32_t instID, MeshDataStage stage, MeshFormat *data); extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetMinMax(ReplayRenderer *rend, ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *minval, PixelValue *maxval); extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetHistogram(ReplayRenderer *rend, ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, float minval, float maxval, bool32 channels[4], rdctype::array *histogram); diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 7938b6a9b..9abca1639 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -118,7 +118,7 @@ class ImageViewer : public IReplayDriver void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data) {} vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) { return vector(); } void InitPostVSBuffers(uint32_t frameID, uint32_t eventID) {} - MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) { MeshFormat ret; RDCEraseEl(ret); return ret; } + MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage) { MeshFormat ret; RDCEraseEl(ret); return ret; } ResourceId RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID, const vector &passEvents) { return ResourceId(); } ShaderReflection *GetShader(ResourceId id) { return NULL; } bool HasCallstacks() { return false; } diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index bf046c3b2..5963d4d01 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -808,7 +808,7 @@ bool ProxySerialiser::Tick() InitPostVSBuffers(0, 0); break; case eCommand_GetPostVS: - GetPostVSBuffers(0, 0, eMeshDataStage_Unknown); + GetPostVSBuffers(0, 0, 0, eMeshDataStage_Unknown); break; case eCommand_BuildTargetShader: BuildTargetShader("", "", 0, eShaderStage_Vertex, NULL, NULL); @@ -1307,17 +1307,18 @@ void ProxySerialiser::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) } } -MeshFormat ProxySerialiser::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) +MeshFormat ProxySerialiser::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage) { MeshFormat ret; m_ToReplaySerialiser->Serialise("", frameID); m_ToReplaySerialiser->Serialise("", eventID); + m_ToReplaySerialiser->Serialise("", instID); m_ToReplaySerialiser->Serialise("", stage); if(m_ReplayHost) { - ret = m_Remote->GetPostVSBuffers(frameID, eventID, stage); + ret = m_Remote->GetPostVSBuffers(frameID, eventID, instID, stage); } else { diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index bd671e330..fc73df1ac 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -288,7 +288,7 @@ class ProxySerialiser : public IReplayDriver, Callstack::StackResolver byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize); void InitPostVSBuffers(uint32_t frameID, uint32_t eventID); - MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage); + MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage); ResourceId RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID, const vector &passEvents); diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp index 6d315e28c..716944282 100644 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -3030,10 +3030,9 @@ ResourceId D3D11DebugManager::RenderOverlay(ResourceId texid, TextureDisplayOver vector events = passEvents; if(overlay == eTexOverlay_QuadOverdrawDraw) - { events.clear(); - events.push_back(eventID); - } + + events.push_back(eventID); if(!events.empty()) { diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index 4ebeb7bb4..f0d5a7e3e 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -359,18 +359,18 @@ static uint32_t strhash(const char *str, uint32_t seed = 5381) { if(str == NULL) return seed; - uint32_t hash = seed; - int c = *str; + uint32_t hash = seed; + int c = *str; str++; - while(c) + while(c) { - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ c = *str; str++; } - return hash; + return hash; } string D3D11DebugManager::GetShaderBlob(const char *source, const char *entry, const uint32_t compileFlags, const char *profile, ID3DBlob **srcblob) @@ -3707,7 +3707,7 @@ void D3D11DebugManager::RenderCheckerboard(Vec3f light, Vec3f dark) } } -MeshFormat D3D11DebugManager::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) +MeshFormat D3D11DebugManager::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage) { PostVSData postvs; RDCEraseEl(postvs); @@ -3732,7 +3732,7 @@ MeshFormat D3D11DebugManager::GetPostVSBuffers(uint32_t frameID, uint32_t eventI else ret.buf = ResourceId(); - ret.offset = s.posOffset; + ret.offset = s.instStride*instID; ret.stride = s.vertStride; ret.compCount = 4; @@ -3745,7 +3745,7 @@ MeshFormat D3D11DebugManager::GetPostVSBuffers(uint32_t frameID, uint32_t eventI ret.topo = MakePrimitiveTopology(s.topo); ret.numVerts = s.numVerts; - ret.unproject = true; + ret.unproject = s.hasPosOut; ret.nearPlane = s.nearPlane; ret.farPlane = s.farPlane; @@ -3837,7 +3837,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) vector sodecls; UINT stride = 0; - UINT posoffset = ~0U; + int posidx = -1; int numPosComponents = 0; ID3D11GeometryShader *streamoutGS = NULL; @@ -3858,24 +3858,24 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) decl.StartComponent = 0; decl.ComponentCount = sign.compCount&0xff; - string a = strupper(string(decl.SemanticName)); - - if(a.find("POSITION") != string::npos) + if(sign.systemValue == eAttr_Position) { - // force to 4 components, as we need it, and store its offset - if(a.find("SV_POSITION") != string::npos || sign.systemValue == eAttr_Position || posoffset == ~0U) - { - if(a.find("SV_POSITION") != string::npos || sign.systemValue == eAttr_Position) - decl.ComponentCount = 4; - - posoffset = stride; - numPosComponents = decl.ComponentCount; - } + posidx = (int)sodecls.size(); + numPosComponents = decl.ComponentCount = 4; } stride += decl.ComponentCount * sizeof(float); sodecls.push_back(decl); } + + // shift position attribute up to first, keeping order otherwise + // the same + if(posidx > 0) + { + D3D11_SO_DECLARATION_ENTRY pos = sodecls[posidx]; + sodecls.erase(sodecls.begin()+posidx); + sodecls.insert(sodecls.begin(), pos); + } HRESULT hr = m_pDevice->CreateGeometryShaderWithStreamOutput( (void *)&dxbcVS->m_ShaderBlob[0], @@ -3911,7 +3911,10 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) if((drawcall->flags & eDraw_UseIBuffer) == 0) { m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); - m_pImmediateContext->Draw(drawcall->numIndices, drawcall->vertexOffset); + if(drawcall->flags & eDraw_Instanced) + m_pImmediateContext->DrawInstanced(drawcall->numIndices, drawcall->numInstances, drawcall->vertexOffset, drawcall->instanceOffset); + else + m_pImmediateContext->Draw(drawcall->numIndices, drawcall->vertexOffset); m_pImmediateContext->IASetPrimitiveTopology(topo); } else // drawcall is indexed @@ -3983,13 +3986,9 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) SAFE_RELEASE(idxBuf); if(drawcall->flags & eDraw_Instanced) - { m_pImmediateContext->DrawIndexedInstanced((UINT)indices.size(), drawcall->numInstances, 0, drawcall->vertexOffset, drawcall->instanceOffset); - } else - { m_pImmediateContext->DrawIndexed((UINT)indices.size(), 0, drawcall->vertexOffset); - } m_pImmediateContext->IASetPrimitiveTopology(topo); m_pImmediateContext->IASetIndexBuffer(UNWRAP(WrappedID3D11Buffer, origBuf), idxFmt, idxOffs); @@ -4089,7 +4088,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) float nearp = 0.1f; float farp = 100.0f; - Vec4f *pos0 = (Vec4f *)(byteData + posoffset); + Vec4f *pos0 = (Vec4f *)byteData; for(UINT64 i=1; numPosComponents == 4 && i < numPrims.NumPrimitivesWritten; i++) { @@ -4111,7 +4110,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // two points, and we pick them reasonably distinct on z to reduce floating-point // error - Vec4f *pos = (Vec4f *)(byteData + posoffset + i*stride); + Vec4f *pos = (Vec4f *)(byteData + i*stride); if(fabs(pos->w - pos0->w) > 0.01f) { @@ -4134,13 +4133,16 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) m_PostVSData[idx].vsin.topo = topo; m_PostVSData[idx].vsout.buf = vsoutBuffer; - m_PostVSData[idx].vsout.posOffset = posoffset; m_PostVSData[idx].vsout.vertStride = stride; m_PostVSData[idx].vsout.nearPlane = nearp; m_PostVSData[idx].vsout.farPlane = farp; m_PostVSData[idx].vsout.useIndices = (drawcall->flags & eDraw_UseIBuffer) > 0; m_PostVSData[idx].vsout.numVerts = drawcall->numIndices; + + m_PostVSData[idx].vsout.instStride = 0; + if(drawcall->flags & eDraw_Instanced) + m_PostVSData[idx].vsout.instStride = bufferDesc.ByteWidth / RDCMAX(1U, drawcall->numInstances); m_PostVSData[idx].vsout.idxBuf = NULL; if(m_PostVSData[idx].vsout.useIndices && idxBuf) @@ -4149,6 +4151,8 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) m_PostVSData[idx].vsout.idxFmt = idxFmt; } + m_PostVSData[idx].vsout.hasPosOut = posidx >= 0; + m_PostVSData[idx].vsout.topo = topo; } else @@ -4156,11 +4160,12 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // empty vertex output signature m_PostVSData[idx].vsin.topo = topo; m_PostVSData[idx].vsout.buf = NULL; - m_PostVSData[idx].vsout.posOffset = ~0U; + m_PostVSData[idx].vsout.instStride = 0; m_PostVSData[idx].vsout.vertStride = 0; m_PostVSData[idx].vsout.nearPlane = 0.0f; m_PostVSData[idx].vsout.farPlane = 0.0f; m_PostVSData[idx].vsout.useIndices = false; + m_PostVSData[idx].vsout.hasPosOut = false; m_PostVSData[idx].vsout.idxBuf = NULL; m_PostVSData[idx].vsout.topo = topo; @@ -4169,7 +4174,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) if(dxbcGS || dxbcDS) { stride = 0; - posoffset = ~0U; + posidx = -1; numPosComponents = 0; DXBC::DXBCFile *lastShader = dxbcGS; @@ -4193,26 +4198,26 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) decl.SemanticIndex = sign.semanticIndex; decl.StartComponent = 0; decl.ComponentCount = sign.compCount&0xff; - - string a = strupper(string(decl.SemanticName)); - if(a.find("POSITION") != string::npos) + if(sign.systemValue == eAttr_Position) { - // force to 4 components, as we need it, and store its offset - if(a.find("SV_POSITION") != string::npos || sign.systemValue == eAttr_Position || posoffset == ~0U) - { - if(a.find("SV_POSITION") != string::npos || sign.systemValue == eAttr_Position) - decl.ComponentCount = 4; - - posoffset = stride; - numPosComponents = decl.ComponentCount; - } + posidx = (int)sodecls.size(); + numPosComponents = decl.ComponentCount = 4; } stride += decl.ComponentCount * sizeof(float); sodecls.push_back(decl); } + // shift position attribute up to first, keeping order otherwise + // the same + if(posidx > 0) + { + D3D11_SO_DECLARATION_ENTRY pos = sodecls[posidx]; + sodecls.erase(sodecls.begin()+posidx); + sodecls.insert(sodecls.begin(), pos); + } + streamoutGS = NULL; HRESULT hr = m_pDevice->CreateGeometryShaderWithStreamOutput( @@ -4246,9 +4251,36 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // 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 & eDraw_Auto) + { m_pImmediateContext->Draw(drawcall->numIndices, 0); + } else - m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw); + { + if(drawcall->flags & eDraw_UseIBuffer) + { + if(drawcall->flags & eDraw_Instanced) + { + m_pImmediateContext->DrawIndexedInstanced(drawcall->numIndices, drawcall->numInstances, drawcall->indexOffset, + drawcall->vertexOffset, drawcall->instanceOffset); + } + else + { + m_pImmediateContext->DrawIndexed(drawcall->numIndices, drawcall->indexOffset, drawcall->vertexOffset); + } + } + else + { + if(drawcall->flags & eDraw_Instanced) + { + m_pImmediateContext->DrawInstanced(drawcall->numIndices, drawcall->numInstances, drawcall->vertexOffset, drawcall->instanceOffset); + } + else + { + m_pImmediateContext->Draw(drawcall->numIndices, drawcall->vertexOffset); + } + } + } + m_pImmediateContext->End(m_SOStatsQuery); m_pImmediateContext->GSSetShader(NULL, NULL, 0); @@ -4319,7 +4351,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) float nearp = 0.1f; float farp = 100.0f; - Vec4f *pos0 = (Vec4f *)(byteData + posoffset); + Vec4f *pos0 = (Vec4f *)byteData; for(UINT64 i=1; numPosComponents == 4 && i < numPrims.NumPrimitivesWritten; i++) { @@ -4341,7 +4373,7 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // two points, and we pick them reasonably distinct on z to reduce floating-point // error - Vec4f *pos = (Vec4f *)(byteData + posoffset + i*stride); + Vec4f *pos = (Vec4f *)(byteData + i*stride); if(fabs(pos->w - pos0->w) > 0.01f) { @@ -4363,11 +4395,14 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) m_pImmediateContext->Unmap(m_SOStagingBuffer, 0); m_PostVSData[idx].gsout.buf = gsoutBuffer; - m_PostVSData[idx].gsout.posOffset = posoffset; + m_PostVSData[idx].gsout.instStride = 0; + if(drawcall->flags & eDraw_Instanced) + m_PostVSData[idx].gsout.instStride = bufferDesc.ByteWidth / RDCMAX(1U, drawcall->numInstances); m_PostVSData[idx].gsout.vertStride = stride; m_PostVSData[idx].gsout.nearPlane = nearp; m_PostVSData[idx].gsout.farPlane = farp; m_PostVSData[idx].gsout.useIndices = false; + m_PostVSData[idx].gsout.hasPosOut = posidx >= 0; m_PostVSData[idx].gsout.idxBuf = NULL; D3D11_PRIMITIVE_TOPOLOGY topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; @@ -4422,6 +4457,9 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ: m_PostVSData[idx].gsout.numVerts = (uint32_t)numPrims.NumPrimitivesWritten*3; break; } + + if(drawcall->flags & eDraw_Instanced) + m_PostVSData[idx].gsout.numVerts /= RDCMAX(1U, drawcall->numInstances); } } @@ -4856,9 +4894,12 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec { MeshDataStage stage = cfg.type; - if(m_HighlightCache.EID != eventID || stage != m_HighlightCache.stage) + if(m_HighlightCache.EID != eventID || stage != m_HighlightCache.stage || + cfg.position.buf != m_HighlightCache.buf || cfg.position.offset != m_HighlightCache.offs) { m_HighlightCache.EID = eventID; + m_HighlightCache.buf = cfg.position.buf; + m_HighlightCache.offs = cfg.position.offset; m_HighlightCache.stage = stage; bool index16 = (ifmt == DXGI_FORMAT_R16_UINT); diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index a3d29a7e9..512881e24 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -58,13 +58,15 @@ struct PostVSData D3D11_PRIMITIVE_TOPOLOGY topo; uint32_t numVerts; - uint32_t posOffset; uint32_t vertStride; + uint32_t instStride; bool useIndices; ID3D11Buffer *idxBuf; DXGI_FORMAT idxFmt; + bool hasPosOut; + float nearPlane; float farPlane; } vsin, vsout, gsout; @@ -113,7 +115,7 @@ class D3D11DebugManager int GetHeight() { return m_height; } void InitPostVSBuffers(uint32_t frameID, uint32_t eventID); - MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage); + MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage); uint32_t GetStructCount(ID3D11UnorderedAccessView *uav); vector GetBufferData(ID3D11Buffer *buff, uint32_t offset, uint32_t len); @@ -298,8 +300,10 @@ class D3D11DebugManager // mesh, not jumping back and forth much between meshes. struct HighlightCache { - HighlightCache() : EID(0), stage(eMeshDataStage_Unknown), useidx(false) {} + HighlightCache() : EID(0), buf(), offs(0), stage(eMeshDataStage_Unknown), useidx(false) {} uint32_t EID; + ResourceId buf; + uint32_t offs; MeshDataStage stage; bool useidx; diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index 7997322a4..91a02123a 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -1260,9 +1260,9 @@ bool D3D11Replay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mi return m_pDevice->GetDebugManager()->GetHistogram(texid, sliceFace, mip, sample, minval, maxval, channels, histogram); } -MeshFormat D3D11Replay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) +MeshFormat D3D11Replay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage) { - return m_pDevice->GetDebugManager()->GetPostVSBuffers(frameID, eventID, stage); + return m_pDevice->GetDebugManager()->GetPostVSBuffers(frameID, eventID, instID, stage); } vector D3D11Replay::GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 625f03f4a..c9e0dc0fb 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -87,7 +87,7 @@ class D3D11Replay : public IReplayDriver bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, float *minval, float *maxval); bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, float minval, float maxval, bool channels[4], vector &histogram); - MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage); + MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage); vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len); byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize); diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 2f9f0d033..d03da09b8 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -1716,18 +1716,27 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) varyings.clear(); uint32_t stride = 0; - uint32_t posoffset = ~0U; + int32_t posidx = -1; for(int32_t i=0; i < vsRefl->OutputSig.count; i++) { varyings.push_back(vsRefl->OutputSig[i].varName.elems); - if(!strcmp(vsRefl->OutputSig[i].varName.elems, "gl_Position")) - posoffset = stride; + if(vsRefl->OutputSig[i].systemValue == eAttr_Position) + posidx = i; stride += sizeof(float)*vsRefl->OutputSig[i].compCount; } + // shift position attribute up to first, keeping order otherwise + // the same + if(posidx > 0) + { + const char *pos = varyings[posidx]; + varyings.erase(varyings.begin()+posidx); + varyings.insert(varyings.begin(), pos); + } + // this is REALLY ugly, but I've seen problems with varying specification, so we try and // do some fixup by removing prefixes from the results we got from PROGRAM_OUTPUT. // @@ -1872,7 +1881,11 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) if((drawcall->flags & eDraw_UseIBuffer) == 0) { - gl.glDrawArrays(eGL_POINTS, drawcall->vertexOffset, drawcall->numIndices); + if(drawcall->flags & eDraw_Instanced) + gl.glDrawArraysInstancedBaseInstance(eGL_POINTS, drawcall->vertexOffset, drawcall->numIndices, + drawcall->numInstances, drawcall->instanceOffset); + else + gl.glDrawArrays(eGL_POINTS, drawcall->vertexOffset, drawcall->numIndices); } else // drawcall is indexed { @@ -1936,7 +1949,15 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, indexSetBuffer); gl.glNamedBufferStorageEXT(indexSetBuffer, sizeof(uint32_t)*indices.size(), &indices[0], 0); - gl.glDrawElementsBaseVertex(eGL_POINTS, (GLsizei)indices.size(), eGL_UNSIGNED_INT, NULL, drawcall->vertexOffset); + if(drawcall->flags & eDraw_Instanced) + { + gl.glDrawElementsInstancedBaseVertexBaseInstance(eGL_POINTS, (GLsizei)indices.size(), eGL_UNSIGNED_INT, NULL, + drawcall->numInstances, drawcall->vertexOffset, drawcall->instanceOffset); + } + else + { + gl.glDrawElementsBaseVertex(eGL_POINTS, (GLsizei)indices.size(), eGL_UNSIGNED_INT, NULL, drawcall->vertexOffset); + } // delete the buffer, we don't need it anymore gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, elArrayBuffer); @@ -1993,9 +2014,9 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) float nearp = 0.1f; float farp = 100.0f; - Vec4f *pos0 = (Vec4f *)(byteData + posoffset); + Vec4f *pos0 = (Vec4f *)byteData; - for(GLuint i=1; posoffset != ~0U && i < primsWritten; i++) + for(GLuint i=1; posidx != -1 && i < primsWritten; i++) { ////////////////////////////////////////////////////////////////////////////////// // derive near/far, assuming a standard perspective matrix @@ -2015,7 +2036,7 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // two points, and we pick them reasonably distinct on z to reduce floating-point // error - Vec4f *pos = (Vec4f *)(byteData + posoffset + i*stride); + Vec4f *pos = (Vec4f *)(byteData + i*stride); if(fabs(pos->w - pos0->w) > 0.01f) { @@ -2039,13 +2060,16 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // store everything out to the PostVS data cache m_PostVSData[idx].vsin.topo = drawcall->topology; m_PostVSData[idx].vsout.buf = vsoutBuffer; - m_PostVSData[idx].vsout.posOffset = posoffset; m_PostVSData[idx].vsout.vertStride = stride; m_PostVSData[idx].vsout.nearPlane = nearp; m_PostVSData[idx].vsout.farPlane = farp; m_PostVSData[idx].vsout.useIndices = (drawcall->flags & eDraw_UseIBuffer) > 0; m_PostVSData[idx].vsout.numVerts = drawcall->numIndices; + + m_PostVSData[idx].vsout.instStride = 0; + if(drawcall->flags & eDraw_Instanced) + m_PostVSData[idx].vsout.instStride = (stride*primsWritten) / RDCMAX(1U, drawcall->numInstances); m_PostVSData[idx].vsout.idxBuf = 0; m_PostVSData[idx].vsout.idxByteWidth = drawcall->indexByteWidth; @@ -2054,6 +2078,8 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) m_PostVSData[idx].vsout.idxBuf = idxBuf; } + m_PostVSData[idx].vsout.hasPosOut = posidx >= 0; + m_PostVSData[idx].vsout.topo = drawcall->topology; // set vsProg back to no varyings, for future use @@ -2078,17 +2104,26 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) varyings.clear(); stride = 0; - posoffset = ~0U; + posidx = -1; for(int32_t i=0; i < lastRefl->OutputSig.count; i++) { varyings.push_back(lastRefl->OutputSig[i].varName.elems); - if(!strcmp(lastRefl->OutputSig[i].varName.elems, "gl_Position")) - posoffset = stride; + if(lastRefl->OutputSig[i].systemValue == eAttr_Position) + posidx = i; stride += sizeof(float)*lastRefl->OutputSig[i].compCount; } + + // shift position attribute up to first, keeping order otherwise + // the same + if(posidx > 0) + { + const char *pos = varyings[posidx]; + varyings.erase(varyings.begin()+posidx); + varyings.insert(varyings.begin(), pos); + } // see above for the justification/explanation of this monstrosity. @@ -2233,15 +2268,29 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) if((drawcall->flags & eDraw_UseIBuffer) == 0) { - gl.glDrawArrays(drawtopo, drawcall->vertexOffset, drawcall->numIndices); + if(drawcall->flags & eDraw_Instanced) + gl.glDrawArraysInstancedBaseInstance(drawtopo, drawcall->vertexOffset, drawcall->numIndices, + drawcall->numInstances, drawcall->instanceOffset); + else + gl.glDrawArrays(drawtopo, drawcall->vertexOffset, drawcall->numIndices); } else // drawcall is indexed { GLenum idxType = eGL_UNSIGNED_BYTE; if(drawcall->indexByteWidth == 2) idxType = eGL_UNSIGNED_SHORT; else if(drawcall->indexByteWidth == 4) idxType = eGL_UNSIGNED_INT; - gl.glDrawElementsBaseVertex(drawtopo, drawcall->numIndices, idxType, - (const void *)(drawcall->indexOffset*drawcall->indexByteWidth), drawcall->vertexOffset); + + if(drawcall->flags & eDraw_Instanced) + { + gl.glDrawElementsInstancedBaseVertexBaseInstance(drawtopo, drawcall->numIndices, idxType, + (const void *)(drawcall->indexOffset*drawcall->indexByteWidth), drawcall->numInstances, + drawcall->vertexOffset, drawcall->instanceOffset); + } + else + { + gl.glDrawElementsBaseVertex(drawtopo, drawcall->numIndices, idxType, + (const void *)(drawcall->indexOffset*drawcall->indexByteWidth), drawcall->vertexOffset); + } } gl.glEndTransformFeedback(); gl.glEndQuery(eGL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); @@ -2284,9 +2333,9 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) float nearp = 0.1f; float farp = 100.0f; - Vec4f *pos0 = (Vec4f *)(byteData + posoffset); + Vec4f *pos0 = (Vec4f *)byteData; - for(uint32_t i=1; posoffset != ~0U && i < m_PostVSData[idx].gsout.numVerts; i++) + for(uint32_t i=1; posidx != -1 && i < m_PostVSData[idx].gsout.numVerts; i++) { ////////////////////////////////////////////////////////////////////////////////// // derive near/far, assuming a standard perspective matrix @@ -2306,7 +2355,7 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // two points, and we pick them reasonably distinct on z to reduce floating-point // error - Vec4f *pos = (Vec4f *)(byteData + posoffset + i*stride); + Vec4f *pos = (Vec4f *)(byteData + i*stride); if(fabs(pos->w - pos0->w) > 0.01f) { @@ -2329,13 +2378,20 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // store everything out to the PostVS data cache m_PostVSData[idx].gsout.buf = lastoutBuffer; - m_PostVSData[idx].gsout.posOffset = posoffset; + m_PostVSData[idx].gsout.instStride = 0; + if(drawcall->flags & eDraw_Instanced) + { + m_PostVSData[idx].gsout.numVerts /= RDCMAX(1U, drawcall->numInstances); + m_PostVSData[idx].gsout.instStride = stride*m_PostVSData[idx].gsout.numVerts; + } m_PostVSData[idx].gsout.vertStride = stride; m_PostVSData[idx].gsout.nearPlane = nearp; m_PostVSData[idx].gsout.farPlane = farp; m_PostVSData[idx].gsout.useIndices = false; + m_PostVSData[idx].gsout.hasPosOut = posidx >= 0; + m_PostVSData[idx].gsout.idxBuf = 0; m_PostVSData[idx].gsout.idxByteWidth = 0; @@ -2366,7 +2422,7 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) gl.glEnable(eGL_RASTERIZER_DISCARD); } -MeshFormat GLReplay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) +MeshFormat GLReplay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage) { GLPostVSData postvs; RDCEraseEl(postvs); @@ -2391,7 +2447,7 @@ MeshFormat GLReplay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDa else ret.buf = ResourceId(); - ret.offset = s.posOffset; + ret.offset = s.instStride*instID; ret.stride = s.vertStride; ret.compCount = 4; @@ -2404,7 +2460,7 @@ MeshFormat GLReplay::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDa ret.topo = s.topo; ret.numVerts = s.numVerts; - ret.unproject = true; + ret.unproject = s.hasPosOut; ret.nearPlane = s.nearPlane; ret.farPlane = s.farPlane; @@ -2834,9 +2890,12 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector &histogram); - MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage); + MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage); vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len); byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize); @@ -278,8 +283,10 @@ class GLReplay : public IReplayDriver // mesh, not jumping back and forth much between meshes. struct HighlightCache { - HighlightCache() : EID(0), stage(eMeshDataStage_Unknown), useidx(false) {} + HighlightCache() : EID(0), buf(), offs(0), stage(eMeshDataStage_Unknown), useidx(false) {} uint32_t EID; + ResourceId buf; + uint32_t offs; MeshDataStage stage; bool useidx; @@ -287,8 +294,8 @@ class GLReplay : public IReplayDriver vector indices; } m_HighlightCache; - // -> data - std::map, GLPostVSData> m_PostVSData; + // -> data + map< pair, GLPostVSData > m_PostVSData; void InitDebugData(); void DeleteDebugData(); diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index d2d74d913..b8dab17f4 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -81,7 +81,7 @@ class IRemoteDriver virtual ResourceId GetLiveID(ResourceId id) = 0; - virtual MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage) = 0; + virtual MeshFormat GetPostVSBuffers(uint32_t frameID, uint32_t eventID, uint32_t instID, MeshDataStage stage) = 0; virtual vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) = 0; virtual byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, bool resolve, bool forceRGBA8unorm, float blackPoint, float whitePoint, size_t &dataSize) = 0; diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index 45497a900..2001b002a 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -142,14 +142,14 @@ void ReplayOutput::RefreshOverlay() while(start) { + if(start == draw) + break; + if(start->flags & eDraw_Drawcall) { passEvents.push_back(start->eventID); } - if(start == draw) - break; - start = m_pRenderer->GetDrawcallByEID((uint32_t)start->next, 0); } } @@ -170,12 +170,10 @@ void ReplayOutput::RefreshOverlay() if(draw == NULL || (draw->flags & eDraw_Drawcall) == 0) return; + + m_pDevice->InitPostVSBuffers(m_FrameID, draw->eventID); - if(m_RenderData.meshDisplay.thisDrawOnly) - { - m_pDevice->InitPostVSBuffers(m_FrameID, draw->eventID); - } - else if(!passEvents.empty()) + if(!m_RenderData.meshDisplay.thisDrawOnly && !passEvents.empty()) { uint32_t prev = 0; @@ -188,7 +186,12 @@ void ReplayOutput::RefreshOverlay() prev = passEvents[i]; } - m_pDevice->InitPostVSBuffers(m_FrameID, passEvents[i]); + FetchDrawcall *d = m_pRenderer->GetDrawcallByEID(m_EventID, m_LastDeferredEvent); + + if(d) + { + m_pDevice->InitPostVSBuffers(m_FrameID, passEvents[i]); + } } m_pDevice->ReplayLog(m_FrameID, 0, m_EventID, eReplay_WithoutDraw); @@ -571,10 +574,36 @@ void ReplayOutput::DisplayMesh() for(size_t i=0; i < passEvents.size(); i++) { - // get the 'most final' stage - MeshFormat fmt = m_pDevice->GetPostVSBuffers(m_FrameID, passEvents[i], eMeshDataStage_GSOut); - if(fmt.buf == ResourceId()) fmt = m_pDevice->GetPostVSBuffers(m_FrameID, passEvents[i], eMeshDataStage_VSOut); - secondaryDraws.push_back(fmt); + FetchDrawcall *d = m_pRenderer->GetDrawcallByEID(passEvents[i], m_LastDeferredEvent); + + if(d) + { + for(uint32_t inst=0; inst < RDCMAX(1U, draw->numInstances); inst++) + { + // get the 'most final' stage + MeshFormat fmt = m_pDevice->GetPostVSBuffers(m_FrameID, passEvents[i], inst, eMeshDataStage_GSOut); + if(fmt.buf == ResourceId()) fmt = m_pDevice->GetPostVSBuffers(m_FrameID, passEvents[i], inst, eMeshDataStage_VSOut); + + // if unproject is marked, this output had a 'real' system position output + if(fmt.unproject) + secondaryDraws.push_back(fmt); + } + } + } + + // draw previous instances in the current drawcall + if(draw->flags & eDraw_Instanced) + { + for(uint32_t inst=0; inst < RDCMAX(1U, draw->numInstances) && inst < m_RenderData.meshDisplay.curInstance; inst++) + { + // get the 'most final' stage + MeshFormat fmt = m_pDevice->GetPostVSBuffers(m_FrameID, draw->eventID, inst, eMeshDataStage_GSOut); + if(fmt.buf == ResourceId()) fmt = m_pDevice->GetPostVSBuffers(m_FrameID, draw->eventID, inst, eMeshDataStage_VSOut); + + // if unproject is marked, this output had a 'real' system position output + if(fmt.unproject) + secondaryDraws.push_back(fmt); + } } } diff --git a/renderdoc/replay/replay_renderer.cpp b/renderdoc/replay/replay_renderer.cpp index 651e2b602..f9a82015d 100644 --- a/renderdoc/replay/replay_renderer.cpp +++ b/renderdoc/replay/replay_renderer.cpp @@ -356,7 +356,7 @@ bool ReplayRenderer::GetUsage(ResourceId id, rdctype::array *usage) return false; } -bool ReplayRenderer::GetPostVSData(MeshDataStage stage, MeshFormat *data) +bool ReplayRenderer::GetPostVSData(uint32_t instID, MeshDataStage stage, MeshFormat *data) { if(data == NULL) return false; @@ -367,7 +367,9 @@ bool ReplayRenderer::GetPostVSData(MeshDataStage stage, MeshFormat *data) if(draw == NULL || (draw->flags & eDraw_Drawcall) == 0) return false; - *data = m_pDevice->GetPostVSBuffers(m_FrameID, draw->eventID, stage); + if(instID >= RDCMAX(1U, draw->numInstances)) return false; + + *data = m_pDevice->GetPostVSBuffers(m_FrameID, draw->eventID, instID, stage); return true; } @@ -1521,8 +1523,8 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetCBufferVariableCo extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_SaveTexture(ReplayRenderer *rend, const TextureSave &saveData, const char *path) { return rend->SaveTexture(saveData, path); } -extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetPostVSData(ReplayRenderer *rend, MeshDataStage stage, MeshFormat *data) -{ return rend->GetPostVSData(stage, data); } +extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetPostVSData(ReplayRenderer *rend, uint32_t instID, MeshDataStage stage, MeshFormat *data) +{ return rend->GetPostVSData(instID, stage, data); } extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetMinMax(ReplayRenderer *rend, ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *minval, PixelValue *maxval) { return rend->GetMinMax(tex, sliceFace, mip, sample, minval, maxval); } diff --git a/renderdoc/replay/replay_renderer.h b/renderdoc/replay/replay_renderer.h index f292f47ad..ae8207488 100644 --- a/renderdoc/replay/replay_renderer.h +++ b/renderdoc/replay/replay_renderer.h @@ -166,7 +166,7 @@ struct ReplayRenderer bool DebugPixel(uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive, ShaderDebugTrace *trace); bool DebugThread(uint32_t groupid[3], uint32_t threadid[3], ShaderDebugTrace *trace); - bool GetPostVSData(MeshDataStage stage, MeshFormat *data); + bool GetPostVSData(uint32_t instID, MeshDataStage stage, MeshFormat *data); bool GetMinMax(ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, PixelValue *minval, PixelValue *maxval); bool GetHistogram(ResourceId tex, uint32_t sliceFace, uint32_t mip, uint32_t sample, float minval, float maxval, bool channels[4], rdctype::array *histogram); diff --git a/renderdocui/Interop/FetchInfo.cs b/renderdocui/Interop/FetchInfo.cs index 519e1599a..a43335b77 100644 --- a/renderdocui/Interop/FetchInfo.cs +++ b/renderdocui/Interop/FetchInfo.cs @@ -398,6 +398,7 @@ namespace renderdoc public float aspect = 0.0f; public bool thisDrawOnly = true; + public UInt32 curInstance = 0; public UInt32 highlightVert; public MeshFormat position; diff --git a/renderdocui/Interop/ReplayRenderer.cs b/renderdocui/Interop/ReplayRenderer.cs index fa0e5d7a0..77783eff9 100644 --- a/renderdocui/Interop/ReplayRenderer.cs +++ b/renderdocui/Interop/ReplayRenderer.cs @@ -240,7 +240,7 @@ namespace renderdoc private static extern bool ReplayRenderer_SaveTexture(IntPtr real, TextureSave saveData, IntPtr path); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] - private static extern bool ReplayRenderer_GetPostVSData(IntPtr real, MeshDataStage stage, IntPtr outdata); + private static extern bool ReplayRenderer_GetPostVSData(IntPtr real, UInt32 instID, MeshDataStage stage, IntPtr outdata); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetMinMax(IntPtr real, ResourceId tex, UInt32 sliceFace, UInt32 mip, UInt32 sample, IntPtr outminval, IntPtr outmaxval); @@ -636,14 +636,14 @@ namespace renderdoc return ret; } - public MeshFormat GetPostVSData(MeshDataStage stage) + public MeshFormat GetPostVSData(UInt32 instID, MeshDataStage stage) { IntPtr mem = CustomMarshal.Alloc(typeof(MeshFormat)); MeshFormat ret = new MeshFormat(); ret.buf = ResourceId.Null; - bool success = ReplayRenderer_GetPostVSData(m_Real, stage, mem); + bool success = ReplayRenderer_GetPostVSData(m_Real, instID, stage, mem); if (success) ret = (MeshFormat)CustomMarshal.PtrToStructure(mem, typeof(MeshFormat), true); diff --git a/renderdocui/Windows/BufferViewer.cs b/renderdocui/Windows/BufferViewer.cs index 7b07605fe..a3cc61e7c 100644 --- a/renderdocui/Windows/BufferViewer.cs +++ b/renderdocui/Windows/BufferViewer.cs @@ -194,8 +194,6 @@ namespace renderdocui.Windows private Core m_Core; private ReplayOutput m_Output = null; - private uint m_CurInst = 0; - private byte[] m_Zeroes = null; private OutputConfig m_OutConfig = new OutputConfig(); @@ -249,30 +247,7 @@ namespace renderdocui.Windows render.MouseWheelHandler = render_MouseWheel; (render as Control).KeyDown += new KeyEventHandler(BufferViewer_KeyDown); (render as Control).KeyUp += new KeyEventHandler(BufferViewer_KeyUp); - - m_OutConfig.m_Type = OutputType.MeshDisplay; - - m_MeshDisplay.type = MeshDataStage.VSIn; - m_MeshDisplay.fov = 90.0f; - - m_MeshDisplay.solidShadeMode = SolidShadeMode.None; - solidShading.SelectedIndex = 0; - - m_MeshDisplay.thisDrawOnly = true; - drawRange.SelectedIndex = 0; - - m_MeshDisplay.currentMeshColour = new FloatVector(1, 0, 0, 1); - m_MeshDisplay.prevMeshColour = new FloatVector(0, 0, 0, 1); - - m_Arcball = new ArcballCamera(m_Camera); - m_Flycam = new FlyCamera(m_Camera); - m_CurrentCamera = m_Arcball; - m_Updater = new TimedUpdate(10, TimerUpdate); - - m_Arcball.SpeedMultiplier = m_Flycam.SpeedMultiplier = (float)camSpeed.Value; - - fovGuess.Text = m_MeshDisplay.fov.ToString("G"); - controlType.SelectedIndex = 0; + ResetConfig(); MeshView = meshview; @@ -297,6 +272,33 @@ namespace renderdocui.Windows m_Core.AddLogViewer(this); } + private void ResetConfig() + { + m_OutConfig.m_Type = OutputType.MeshDisplay; + + m_MeshDisplay = new MeshDisplay(); + m_MeshDisplay.type = MeshDataStage.VSIn; + m_MeshDisplay.fov = 90.0f; + + m_MeshDisplay.solidShadeMode = SolidShadeMode.None; + solidShading.SelectedIndex = 0; + + m_MeshDisplay.thisDrawOnly = true; + drawRange.SelectedIndex = 0; + + m_MeshDisplay.currentMeshColour = new FloatVector(1, 0, 0, 1); + m_MeshDisplay.prevMeshColour = new FloatVector(0, 0, 0, 1); + + m_Arcball = new ArcballCamera(m_Camera); + m_Flycam = new FlyCamera(m_Camera); + m_CurrentCamera = m_Arcball; + m_Updater = new TimedUpdate(10, TimerUpdate); + + m_Arcball.SpeedMultiplier = m_Flycam.SpeedMultiplier = (float)camSpeed.Value; + + fovGuess.Text = m_MeshDisplay.fov.ToString("G"); + controlType.SelectedIndex = 0; + } private void UI_SetupDocks(bool meshview) { if (meshview) @@ -412,6 +414,8 @@ namespace renderdocui.Windows { m_Output = null; + ResetConfig(); + ClearStoredData(); exportToToolStripMenuItem.Enabled = exportToolItem.Enabled = false; @@ -702,7 +706,6 @@ namespace renderdocui.Windows if (!MeshView) return null; - FormatElement[] f = null; Input ret = new Input(); ret.Drawcall = draw; ret.Topology = draw.topology; @@ -739,14 +742,14 @@ namespace renderdocui.Windows if (details == null) return null; - f = new FormatElement[details.OutputSig.Length]; + List f = new List(); - uint offset = 0; + int posidx = -1; for (int i = 0; i < details.OutputSig.Length; i++) { var sig = details.OutputSig[i]; - f[i] = new FormatElement(); + f.Add(new FormatElement()); f[i].buffer = 0; f[i].name = details.OutputSig[i].varName.Length > 0 ? details.OutputSig[i].varName : details.OutputSig[i].semanticIdxName; @@ -755,16 +758,33 @@ namespace renderdocui.Windows f[i].format.compType = sig.compType; f[i].format.special = false; f[i].format.rawType = 0; - f[i].offset = offset; f[i].perinstance = false; + f[i].instancerate = 1; f[i].rowmajor = false; f[i].matrixdim = 1; f[i].systemValue = sig.systemValue; - offset += details.OutputSig[i].compCount * sizeof(float); + if(f[i].systemValue == SystemAttribute.Position) + posidx = i; } - ret.BufferFormats = f; + // shift position attribute up to first, keeping order otherwise + // the same + if (posidx > 0) + { + FormatElement pos = f[posidx]; + f.RemoveAt(posidx); + f.Insert(0, pos); + } + + uint offset = 0; + for (int i = 0; i < details.OutputSig.Length; i++) + { + f[i].offset = offset; + offset += f[i].format.compCount * sizeof(float); + } + + ret.BufferFormats = f.ToArray(); ret.Strides = new uint[] { offset }; ret.Offsets = new uint[] { 0 }; ret.Buffers = null; @@ -786,6 +806,8 @@ namespace renderdocui.Windows } { + FormatElement[] f = null; + var vinputs = m_Core.CurPipelineState.GetVertexInputs(); f = new FormatElement[vinputs.Length]; @@ -802,12 +824,12 @@ namespace renderdocui.Windows false); i++; } - } - ret.BufferFormats = f; - ret.Strides = s; - ret.Offsets = o; - ret.Buffers = bs; + ret.BufferFormats = f; + ret.Strides = s; + ret.Offsets = o; + ret.Buffers = bs; + } return ret; } @@ -848,7 +870,7 @@ namespace renderdocui.Windows if (type != MeshDataStage.VSIn) { - ret.PostVS = r.GetPostVSData(type); + ret.PostVS = r.GetPostVSData(Math.Min(m_MeshDisplay.curInstance, Math.Max(1U, input.Drawcall.numInstances)), type); ret.Buffers = new byte[1][]; @@ -859,11 +881,11 @@ namespace renderdocui.Windows } else { - ret.Buffers[0] = r.GetBufferData(ret.PostVS.buf, 0, 0); + ret.Buffers[0] = r.GetBufferData(ret.PostVS.buf, ret.PostVS.offset, 0); ret.Topology = ret.PostVS.topo; - ret.IndexCount = (uint)ret.Buffers[0].Length / ret.PostVS.stride; + ret.IndexCount = ret.PostVS.numVerts; uint stride = 0; foreach (var f in input.BufferFormats) @@ -1298,7 +1320,7 @@ namespace renderdocui.Windows var data = state.m_Data; Input input = state.m_Input; - uint instance = m_CurInst; + uint instance = m_MeshDisplay.curInstance; Thread th = Helpers.NewThread(new ThreadStart(() => { @@ -1527,7 +1549,7 @@ namespace renderdocui.Windows var data = state.m_Data; Input input = state.m_Input; - uint instance = m_CurInst; + uint instance = m_MeshDisplay.curInstance; if (data.Buffers == null) return; @@ -2277,7 +2299,7 @@ namespace renderdocui.Windows m_MeshDisplay.position.idxByteWidth = ui.m_Data.PostVS.idxByteWidth; m_MeshDisplay.position.buf = ui.m_Data.PostVS.buf; - m_MeshDisplay.position.offset = pos.offset; + m_MeshDisplay.position.offset = ui.m_Data.PostVS.offset + pos.offset; m_MeshDisplay.position.stride = ui.m_Data.PostVS.stride; m_MeshDisplay.position.topo = ui.m_Data.PostVS.topo; @@ -2337,7 +2359,7 @@ namespace renderdocui.Windows else if (ui.m_Stage != MeshDataStage.VSIn && ui.m_Data != null && ui.m_Data.PostVS.buf != ResourceId.Null) { m_MeshDisplay.secondary.buf = ui.m_Data.PostVS.buf; - m_MeshDisplay.secondary.offset = tex.offset; + m_MeshDisplay.secondary.offset = ui.m_Data.PostVS.offset + tex.offset; m_MeshDisplay.secondary.stride = ui.m_Data.PostVS.stride; } } @@ -2473,9 +2495,10 @@ namespace renderdocui.Windows uint inst = 0; if (uint.TryParse(instanceIdxToolitem.Text, out inst)) { - if (inst != m_CurInst && inst >= 0 && m_Core.CurDrawcall != null && inst < m_Core.CurDrawcall.numInstances) + if (inst != m_MeshDisplay.curInstance && inst >= 0 && m_Core.CurDrawcall != null && inst < m_Core.CurDrawcall.numInstances) { - m_CurInst = inst; + m_MeshDisplay.curInstance = inst; + OnEventSelected(m_Core.CurFrame, m_Core.CurEvent); } @@ -2581,9 +2604,9 @@ namespace renderdocui.Windows uint inst = 0; if (uint.TryParse(instanceIdx.Text, out inst)) { - if (inst != m_CurInst && inst >= 0 && m_Core.CurDrawcall != null && inst < m_Core.CurDrawcall.numInstances) + if (inst != m_MeshDisplay.curInstance && inst >= 0 && m_Core.CurDrawcall != null && inst < m_Core.CurDrawcall.numInstances) { - m_CurInst = inst; + m_MeshDisplay.curInstance = inst; OnEventSelected(m_Core.CurFrame, m_Core.CurEvent); } @@ -2695,14 +2718,14 @@ namespace renderdocui.Windows m_Core.Renderer.Invoke((ReplayRenderer r) => { - trace = r.DebugVertex((UInt32)row, (UInt32)m_CurInst, idx, draw.instanceOffset, draw.vertexOffset); + trace = r.DebugVertex((UInt32)row, m_MeshDisplay.curInstance, idx, draw.instanceOffset, draw.vertexOffset); }); this.BeginInvoke(new Action(() => { string debugContext = String.Format("Vertex {0}", row); if (draw.numInstances > 1) - debugContext += String.Format(", Instance {0}", m_CurInst); + debugContext += String.Format(", Instance {0}", m_MeshDisplay.curInstance); ShaderViewer s = new ShaderViewer(m_Core, shaderDetails, ShaderStageType.Vertex, trace, debugContext); @@ -2816,7 +2839,7 @@ namespace renderdocui.Windows private void UpdateHighlightVerts(UIState ui) { - if (ui.m_RawData == null) return; + if (ui == null || ui.m_RawData == null) return; if (ui.m_GridView.SelectedRows.Count == 0) return; if (!MeshView) return;