From 6d64fc7a1a85d14a108b6d27deb8ec75bc23b591 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 28 Jan 2015 02:23:17 +0000 Subject: [PATCH] Handle NULL index buffer being bound for indexed draws better --- renderdoc/driver/d3d11/d3d11_debug.cpp | 27 ++++++++++++++---- renderdoc/driver/gl/gl_debug.cpp | 38 ++++++++++++++++++-------- renderdocui/Windows/BufferViewer.cs | 18 ++++++++++-- 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index f0d5a7e3e..1ebd44577 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -3952,6 +3952,11 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) indices.insert(it, i32); } + // if we read out of bounds, we'll also have a 0 index being referenced + // (as 0 is read) + if(numIndices < drawcall->numIndices) + indices.insert(indices.begin(), 0); + // An index buffer could be something like: 500, 501, 502, 501, 503, 502 // in which case we can't use the existing index buffer without filling 499 slots of vertex // data with padding. Instead we rebase the indices based on the smallest vertex so it becomes @@ -3979,7 +3984,10 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) D3D11_BUFFER_DESC desc = { UINT(sizeof(uint32_t)*indices.size()), D3D11_USAGE_IMMUTABLE, D3D11_BIND_INDEX_BUFFER, 0, 0, 0 }; D3D11_SUBRESOURCE_DATA initData = { &indices[0], desc.ByteWidth, desc.ByteWidth }; - m_pDevice->CreateBuffer(&desc, &initData, &idxBuf); + if(!indices.empty()) + m_pDevice->CreateBuffer(&desc, &initData, &idxBuf); + else + idxBuf = NULL; m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); m_pImmediateContext->IASetIndexBuffer(idxBuf, DXGI_FORMAT_R32_UINT, 0); @@ -4010,7 +4018,10 @@ void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) initData.pSysMem = &idxdata[0]; initData.SysMemPitch = initData.SysMemSlicePitch = desc.ByteWidth; - m_WrappedDevice->CreateBuffer(&desc, &initData, &idxBuf); + if(desc.ByteWidth > 0) + m_WrappedDevice->CreateBuffer(&desc, &initData, &idxBuf); + else + idxBuf = NULL; } m_pImmediateContext->End(m_SOStatsQuery); @@ -4783,6 +4794,8 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec m_pImmediateContext->IASetVertexBuffers(0, 2, vbs, str, offs); if(ibuf) m_pImmediateContext->IASetIndexBuffer(ibuf, ifmt, ioffs); + else + m_pImmediateContext->IASetIndexBuffer(NULL, DXGI_FORMAT_UNKNOWN, NULL); // draw solid shaded mode if(cfg.solidShadeMode != eShade_None && cfg.position.topo < eTopology_PatchList_1CPs) @@ -4811,7 +4824,7 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec m_pImmediateContext->GSSetShader(m_DebugRender.MeshGS, NULL, 0); } - if(ibuf) + if(cfg.position.idxByteWidth) m_pImmediateContext->DrawIndexed(cfg.position.numVerts, 0, 0); else m_pImmediateContext->Draw(cfg.position.numVerts, 0); @@ -4841,7 +4854,7 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec else m_pImmediateContext->IASetPrimitiveTopology(topo); - if(ibuf) + if(cfg.position.idxByteWidth) m_pImmediateContext->DrawIndexed(cfg.position.numVerts, 0, 0); else m_pImmediateContext->Draw(cfg.position.numVerts, 0); @@ -4907,7 +4920,7 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec m_HighlightCache.data = GetBufferData(cfg.position.buf, 0, 0); - if(ibuf == NULL || stage == eMeshDataStage_GSOut) + if(cfg.position.idxByteWidth == 0 || stage == eMeshDataStage_GSOut) { m_HighlightCache.indices.clear(); m_HighlightCache.useidx = false; @@ -4916,7 +4929,9 @@ void D3D11DebugManager::RenderMesh(uint32_t frameID, uint32_t eventID, const vec { m_HighlightCache.useidx = true; - vector idxdata = GetBufferData(cfg.position.idxbuf, ioffs, cfg.position.numVerts*bytesize); + vector idxdata; + if(cfg.position.idxbuf != ResourceId()) + idxdata = GetBufferData(cfg.position.idxbuf, ioffs, cfg.position.numVerts*bytesize); uint16_t *idx16 = (uint16_t *)&idxdata[0]; uint32_t *idx32 = (uint32_t *)&idxdata[0]; diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index d03da09b8..29f4013c1 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -1918,6 +1918,11 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) indices.insert(it, i32); } + // if we read out of bounds, we'll also have a 0 index being referenced + // (as 0 is read) + if(numIndices < drawcall->numIndices) + indices.insert(indices.begin(), 0); + // An index buffer could be something like: 500, 501, 502, 501, 503, 502 // in which case we can't use the existing index buffer without filling 499 slots of vertex // data with padding. Instead we rebase the indices based on the smallest vertex so it becomes @@ -1984,9 +1989,12 @@ void GLReplay::InitPostVSBuffers(uint32_t frameID, uint32_t eventID) // make the index buffer that can be used to render this postvs data - the original // indices, rebased with minindex being 0 (since we transform feedback to the start // of our feedback buffer). - gl.glGenBuffers(1, &idxBuf); - gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, idxBuf); - gl.glNamedBufferStorageEXT(idxBuf, (GLsizeiptr)idxdata.size(), &idxdata[0], 0); + if(!idxdata.empty()) + { + gl.glGenBuffers(1, &idxBuf); + gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, idxBuf); + gl.glNamedBufferStorageEXT(idxBuf, (GLsizeiptr)idxdata.size(), &idxdata[0], 0); + } // restore previous element array buffer binding gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, elArrayBuffer); @@ -2794,7 +2802,7 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vectorGetResourceManager()->GetCurrentResource(cfg.position.idxbuf).name; - gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); + if(cfg.position.idxbuf != ResourceId()) + { + GLuint ib = m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.idxbuf).name; + gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); + } gl.glDrawElements(topo, cfg.position.numVerts, idxtype, (const void *)(cfg.position.idxoffs)); } else @@ -2834,7 +2845,7 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vectorGetResourceManager()->GetCurrentResource(cfg.position.idxbuf).name; - gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); + if(cfg.position.idxbuf != ResourceId()) + { + GLuint ib = m_pDriver->GetResourceManager()->GetCurrentResource(cfg.position.idxbuf).name; + gl.glBindBuffer(eGL_ELEMENT_ARRAY_BUFFER, ib); + } gl.glDrawElements(topo != eGL_PATCHES ? topo : eGL_POINTS, cfg.position.numVerts, idxtype, (const void *)(cfg.position.idxoffs)); } else @@ -2902,7 +2916,7 @@ void GLReplay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector idxdata = GetBufferData(cfg.position.idxbuf, cfg.position.idxoffs, cfg.position.numVerts*bytesize); + vector idxdata; + if(cfg.position.idxbuf != ResourceId()) + idxdata = GetBufferData(cfg.position.idxbuf, cfg.position.idxoffs, cfg.position.numVerts*bytesize); uint8_t *idx8 = (uint8_t *)&idxdata[0]; uint16_t *idx16 = (uint16_t *)&idxdata[0]; diff --git a/renderdocui/Windows/BufferViewer.cs b/renderdocui/Windows/BufferViewer.cs index a3cc61e7c..d368e9303 100644 --- a/renderdocui/Windows/BufferViewer.cs +++ b/renderdocui/Windows/BufferViewer.cs @@ -891,7 +891,7 @@ namespace renderdocui.Windows foreach (var f in input.BufferFormats) stride += f.ByteSize; - if (stride != 0) + if (stride != 0 && (input.Drawcall.flags & DrawcallFlags.UseIBuffer) == 0) ret.IndexCount = Math.Min(ret.IndexCount, (uint)ret.Buffers[0].Length / stride); } @@ -1585,7 +1585,8 @@ namespace renderdocui.Windows index = data.Indices[rowIdx]; } } - else if (input.Drawcall != null && (input.Drawcall.flags & DrawcallFlags.UseIBuffer) != 0 && state == m_VSIn) + else if (input.Drawcall != null && (input.Drawcall.flags & DrawcallFlags.UseIBuffer) != 0 && + (state == m_VSIn || state == m_VSOut)) { // no index buffer, but indexed drawcall index = 0; @@ -2296,7 +2297,7 @@ namespace renderdocui.Windows { m_MeshDisplay.position.idxbuf = ui.m_Data.PostVS.idxbuf; m_MeshDisplay.position.idxoffs = 0; - m_MeshDisplay.position.idxByteWidth = ui.m_Data.PostVS.idxByteWidth; + m_MeshDisplay.position.idxByteWidth = ui.m_Input.Drawcall.indexByteWidth; m_MeshDisplay.position.buf = ui.m_Data.PostVS.buf; m_MeshDisplay.position.offset = ui.m_Data.PostVS.offset + pos.offset; @@ -2306,6 +2307,17 @@ namespace renderdocui.Windows m_MeshDisplay.position.numVerts = ui.m_Data.PostVS.numVerts; } + if ((ui.m_Input.Drawcall.flags & DrawcallFlags.UseIBuffer) == 0) + { + m_MeshDisplay.position.idxbuf = ResourceId.Null; + m_MeshDisplay.position.idxoffs = 0; + m_MeshDisplay.position.idxByteWidth = 0; + } + else + { + m_MeshDisplay.position.idxByteWidth = Math.Max(1, m_MeshDisplay.position.idxByteWidth); + } + m_MeshDisplay.position.unproject = false; // near and far plane handled elsewhere