From a0a373a8e1a5b2076ee685f47baff59f5e07410e Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 29 May 2020 14:03:03 +0100 Subject: [PATCH] Fix handling of buffer truncation and zero-sized buffers --- qrenderdoc/Code/QRDUtils.cpp | 2 +- qrenderdoc/Windows/BufferViewer.cpp | 92 +++++--- .../Windows/ConstantBufferPreviewer.cpp | 6 +- .../D3D12PipelineStateViewer.cpp | 50 ++--- qrenderdoc/Windows/TextureViewer.cpp | 2 +- renderdoc/api/replay/common_pipestate.h | 7 +- renderdoc/api/replay/control_types.h | 4 + renderdoc/api/replay/pipestate.inl | 34 +-- renderdoc/driver/d3d11/d3d11_postvs.cpp | 6 + renderdoc/driver/d3d12/d3d12_postvs.cpp | 9 +- renderdoc/driver/d3d12/d3d12_rendermesh.cpp | 12 +- renderdoc/driver/d3d12/d3d12_shaderdebug.cpp | 22 +- renderdoc/driver/gl/gl_postvs.cpp | 6 + renderdoc/driver/vulkan/vk_postvs.cpp | 6 + .../vulkan/wrappers/vk_device_funcs.cpp | 3 + renderdoc/replay/renderdoc_serialise.inl | 4 +- util/test/demos/CMakeLists.txt | 2 + .../demos/d3d11/d3d11_buffer_truncation.cpp | 161 ++++++++++++++ .../demos/d3d12/d3d12_buffer_truncation.cpp | 198 ++++++++++++++++++ util/test/demos/demos.vcxproj | 5 +- util/test/demos/demos.vcxproj.filters | 15 +- util/test/demos/gl/gl_buffer_truncation.cpp | 159 ++++++++++++++ ...d_cbuffer.cpp => vk_buffer_truncation.cpp} | 92 ++++---- util/test/demos/vk/vk_cbuffer_zoo.cpp | 15 +- util/test/demos/vk/vk_secondary_cmdbuf.cpp | 10 +- util/test/demos/vk/vk_shader_editing.cpp | 15 +- util/test/demos/vk/vk_texture_zoo.cpp | 12 +- util/test/rdtest/__init__.py | 1 + util/test/rdtest/analyse.py | 91 ++++++-- util/test/rdtest/shared/Buffer_Truncation.py | 161 ++++++++++++++ util/test/rdtest/testcase.py | 18 +- .../tests/D3D11/D3D11_Buffer_Truncation.py | 7 + .../tests/D3D12/D3D12_Buffer_Truncation.py | 7 + util/test/tests/GL/GL_Buffer_Truncation.py | 7 + .../test/tests/Vulkan/VK_Buffer_Truncation.py | 7 + .../test/tests/Vulkan/VK_Truncated_CBuffer.py | 32 --- 36 files changed, 1038 insertions(+), 242 deletions(-) create mode 100644 util/test/demos/d3d11/d3d11_buffer_truncation.cpp create mode 100644 util/test/demos/d3d12/d3d12_buffer_truncation.cpp create mode 100644 util/test/demos/gl/gl_buffer_truncation.cpp rename util/test/demos/vk/{vk_truncated_cbuffer.cpp => vk_buffer_truncation.cpp} (60%) create mode 100644 util/test/rdtest/shared/Buffer_Truncation.py create mode 100644 util/test/tests/D3D11/D3D11_Buffer_Truncation.py create mode 100644 util/test/tests/D3D12/D3D12_Buffer_Truncation.py create mode 100644 util/test/tests/GL/GL_Buffer_Truncation.py create mode 100644 util/test/tests/Vulkan/VK_Buffer_Truncation.py delete mode 100644 util/test/tests/Vulkan/VK_Truncated_CBuffer.py diff --git a/qrenderdoc/Code/QRDUtils.cpp b/qrenderdoc/Code/QRDUtils.cpp index f7e584898..6037f7d7c 100644 --- a/qrenderdoc/Code/QRDUtils.cpp +++ b/qrenderdoc/Code/QRDUtils.cpp @@ -752,7 +752,7 @@ bool RichResourceTextMouseEvent(const QWidget *owner, const QVariant &var, QRect formatter = BufferFormatter::DeclareStruct(ptrType.descriptor.name, ptrType.members, ptrType.descriptor.arrayByteStride); - IBufferViewer *view = ctx.ViewBuffer(ptr->offset, 0, ptr->base, formatter); + IBufferViewer *view = ctx.ViewBuffer(ptr->offset, ~0ULL, ptr->base, formatter); ctx.AddDockWindow(view->Widget(), DockReference::MainToolArea, NULL); } diff --git a/qrenderdoc/Windows/BufferViewer.cpp b/qrenderdoc/Windows/BufferViewer.cpp index ff08a32ae..fca37adbb 100644 --- a/qrenderdoc/Windows/BufferViewer.cpp +++ b/qrenderdoc/Windows/BufferViewer.cpp @@ -1522,16 +1522,23 @@ static void ConfigureMeshColumns(ICaptureContext &ctx, PopulateBufferData *bufda BoundVBuffer ib = ctx.CurPipelineState().GetIBuffer(); - uint32_t bytesAvailable = 0; + uint32_t bytesAvailable = ib.byteSize; - BufferDescription *buf = ctx.GetBuffer(ib.resourceId); - if(buf) + if(bytesAvailable == ~0U) { - uint64_t offset = ib.byteOffset - draw->indexOffset * draw->indexByteWidth; - if(offset > buf->length) - bytesAvailable = 0; + BufferDescription *buf = ctx.GetBuffer(ib.resourceId); + if(buf) + { + uint64_t offset = ib.byteOffset - draw->indexOffset * draw->indexByteWidth; + if(offset > buf->length) + bytesAvailable = 0; + else + bytesAvailable = buf->length - offset; + } else - bytesAvailable = buf->length - offset; + { + bytesAvailable = 0; + } } // drawing more than this many indices will read off the end of the index buffer - which while @@ -1548,12 +1555,25 @@ static void ConfigureMeshColumns(ICaptureContext &ctx, PopulateBufferData *bufda if(vb.byteStride == 0) continue; - BufferDescription *buf = ctx.GetBuffer(vb.resourceId); - if(buf) + uint32_t bytesAvailable = vb.byteSize; + + if(bytesAvailable == ~0U) { - numRowsUpperBound = qMax(numRowsUpperBound, - uint32_t(buf->length - vb.byteOffset) / qMax(1U, vb.byteStride)); + BufferDescription *buf = ctx.GetBuffer(vb.resourceId); + if(buf) + { + if(vb.byteOffset > buf->length) + bytesAvailable = 0; + else + bytesAvailable = buf->length - vb.byteOffset; + } + else + { + bytesAvailable = 0; + } } + + numRowsUpperBound = qMax(numRowsUpperBound, bytesAvailable / qMax(1U, vb.byteStride)); } // if there are no vertex buffers we can't clamp. @@ -1596,8 +1616,18 @@ static void RT_FetchMeshData(IReplayController *r, ICaptureContext &ctx, Populat bytebuf idata; if(ib.resourceId != ResourceId() && draw && (draw->flags & DrawFlags::Indexed)) - idata = r->GetBufferData(ib.resourceId, ib.byteOffset + draw->indexOffset * draw->indexByteWidth, - draw->numIndices * draw->indexByteWidth); + { + uint64_t readBytes = draw->numIndices * draw->indexByteWidth; + uint32_t offset = draw->indexOffset * draw->indexByteWidth; + + if(ib.byteSize > offset) + readBytes = qMin(ib.byteSize - offset, readBytes); + else + readBytes = 0; + + if(readBytes > 0) + idata = r->GetBufferData(ib.resourceId, ib.byteOffset + offset, readBytes); + } if(data->vsinConfig.indices) data->vsinConfig.indices->deref(); @@ -1605,7 +1635,8 @@ static void RT_FetchMeshData(IReplayController *r, ICaptureContext &ctx, Populat data->vsinConfig.indices = new BufferData(); if(draw && draw->indexByteWidth != 0 && !idata.isEmpty()) - data->vsinConfig.indices->storage.resize(sizeof(uint32_t) * draw->numIndices); + data->vsinConfig.indices->storage.resize( + sizeof(uint32_t) * qMin(draw->numIndices, ((uint32_t)idata.size() / draw->indexByteWidth))); else if(draw && (draw->flags & DrawFlags::Indexed)) data->vsinConfig.indices->storage.resize(sizeof(uint32_t)); @@ -1716,8 +1747,17 @@ static void RT_FetchMeshData(IReplayController *r, ICaptureContext &ctx, Populat BufferData *buf = new BufferData; if(used) { - buf->storage = r->GetBufferData(vb.resourceId, vb.byteOffset + offset * vb.byteStride, - qMax(maxIdx, maxIdx + 1) * vb.byteStride + maxAttrOffset); + uint64_t readBytes = qMax(maxIdx, maxIdx + 1) * vb.byteStride + maxAttrOffset; + + offset *= vb.byteStride; + + if(vb.byteSize > offset) + readBytes = qMin(vb.byteSize - offset, readBytes); + else + readBytes = 0; + + if(readBytes > 0) + buf->storage = r->GetBufferData(vb.resourceId, vb.byteOffset + offset, readBytes); buf->stride = vb.byteStride; } @@ -2410,12 +2450,8 @@ void BufferViewer::OnEventChanged(uint32_t eventId) } else { - uint64_t len = m_ByteSize; - if(len == UINT64_MAX) - len = 0; - QString errors; - ShaderConstant constant = BufferFormatter::ParseFormatString(m_Format, len, true, errors); + ShaderConstant constant = BufferFormatter::ParseFormatString(m_Format, m_ByteSize, true, errors); UnrollConstant(constant, bufdata->vsinConfig.columns, bufdata->vsinConfig.props); @@ -2487,8 +2523,6 @@ void BufferViewer::OnEventChanged(uint32_t eventId) uint64_t unclampedLen = m_ByteSize; if(unclampedLen == UINT64_MAX) - unclampedLen = 0; - if(unclampedLen == 0) { uint64_t bufLen = m_IsBuffer ? m_Ctx.GetBuffer(m_BufferID)->length : 0; uint64_t bufOffs = m_ByteOffset; @@ -2505,7 +2539,8 @@ void BufferViewer::OnEventChanged(uint32_t eventId) if(m_IsBuffer) { - buf->storage = r->GetBufferData(m_BufferID, CurrentByteOffset(), clampedLen); + if(clampedLen > 0) + buf->storage = r->GetBufferData(m_BufferID, CurrentByteOffset(), clampedLen); } else { @@ -2949,6 +2984,7 @@ void BufferViewer::UI_CalculateMeshFormats() BoundVBuffer ib = m_Ctx.CurPipelineState().GetIBuffer(); m_VSInPosition.indexResourceId = ib.resourceId; m_VSInPosition.indexByteOffset = ib.byteOffset + draw->indexOffset * draw->indexByteWidth; + m_VSInPosition.indexByteSize = ib.byteSize; if((draw->flags & DrawFlags::Indexed) && m_VSInPosition.indexByteStride == 0) m_VSInPosition.indexByteStride = 4U; @@ -2966,6 +3002,7 @@ void BufferViewer::UI_CalculateMeshFormats() m_VSInPosition.vertexByteStride = vbs[prop.buffer].byteStride; m_VSInPosition.vertexByteOffset = vbs[prop.buffer].byteOffset + el.byteOffset + draw->vertexOffset * m_VSInPosition.vertexByteStride; + m_VSInPosition.vertexByteSize = vbs[prop.buffer].byteSize; } else { @@ -2993,6 +3030,7 @@ void BufferViewer::UI_CalculateMeshFormats() m_VSInSecondary.vertexByteStride = vbs[prop.buffer].byteStride; m_VSInSecondary.vertexByteOffset = vbs[prop.buffer].byteOffset + el.byteOffset + draw->vertexOffset * m_VSInSecondary.vertexByteStride; + m_VSInSecondary.vertexByteSize = vbs[prop.buffer].byteSize; } else { @@ -3770,11 +3808,7 @@ void BufferViewer::processFormat(const QString &format) BufferConfiguration bufconfig; - uint64_t len = m_ByteSize; - if(len == UINT64_MAX) - len = 0; - - ShaderConstant cols = BufferFormatter::ParseFormatString(format, len, true, errors); + ShaderConstant cols = BufferFormatter::ParseFormatString(format, m_ByteSize, true, errors); CalcColumnWidth(MaxNumRows(cols)); diff --git a/qrenderdoc/Windows/ConstantBufferPreviewer.cpp b/qrenderdoc/Windows/ConstantBufferPreviewer.cpp index 8d8a8c03e..7b06c269f 100644 --- a/qrenderdoc/Windows/ConstantBufferPreviewer.cpp +++ b/qrenderdoc/Windows/ConstantBufferPreviewer.cpp @@ -136,7 +136,9 @@ void ConstantBufferPreviewer::OnEventChanged(uint32_t eventId) if(!m_formatOverride.type.members.empty()) { m_Ctx.Replay().AsyncInvoke([this, offset, size, wasEmpty](IReplayController *r) { - bytebuf data = r->GetBufferData(m_cbuffer, offset, size); + bytebuf data; + if(size > 0) + data = r->GetBufferData(m_cbuffer, offset, size); rdcarray vars = applyFormatOverride(data); GUIInvoke::call(this, [this, vars, wasEmpty] { RDTreeViewExpansionState state; @@ -279,7 +281,7 @@ void ConstantBufferPreviewer::processFormat(const QString &format) { QString errors; - m_formatOverride = BufferFormatter::ParseFormatString(format, 0, false, errors); + m_formatOverride = BufferFormatter::ParseFormatString(format, ~0ULL, false, errors); ui->formatSpecifier->setErrors(errors); } diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index a7aa9222e..75e831caf 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -38,15 +38,17 @@ struct D3D12VBIBTag { D3D12VBIBTag() { offset = 0; } - D3D12VBIBTag(ResourceId i, uint64_t offs, QString f = QString()) + D3D12VBIBTag(ResourceId i, uint64_t offs, uint64_t sz, QString f = QString()) { id = i; offset = offs; + size = sz; format = f; } ResourceId id; uint64_t offset; + uint64_t size; QString format; }; @@ -1384,13 +1386,10 @@ void D3D12PipelineStateViewer::setState() { if(ibufferUsed || ui->showUnused->isChecked()) { - uint64_t length = 0; + uint64_t length = state.inputAssembly.indexBuffer.byteSize; BufferDescription *buf = m_Ctx.GetBuffer(state.inputAssembly.indexBuffer.resourceId); - if(buf) - length = buf->length; - RDTreeWidgetItem *node = new RDTreeWidgetItem( {tr("Index"), state.inputAssembly.indexBuffer.resourceId, draw ? draw->indexByteWidth : 0, (qulonglong)state.inputAssembly.indexBuffer.byteOffset, (qulonglong)length, QString()}); @@ -1408,11 +1407,12 @@ void D3D12PipelineStateViewer::setState() iformat += lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(draw->topology)); } - node->setTag( - QVariant::fromValue(D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId, - state.inputAssembly.indexBuffer.byteOffset + - (draw ? draw->indexOffset * draw->indexByteWidth : 0), - iformat))); + uint32_t drawOffset = (draw ? draw->indexOffset * draw->indexByteWidth : 0); + + node->setTag(QVariant::fromValue( + D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId, + state.inputAssembly.indexBuffer.byteOffset + drawOffset, + qMin(state.inputAssembly.indexBuffer.byteSize - drawOffset, 0U), iformat))); for(const D3D12Pipe::ResourceData &res : m_Ctx.CurD3D12PipelineState()->resourceStates) { @@ -1455,11 +1455,12 @@ void D3D12PipelineStateViewer::setState() iformat += lit(" indices[%1]").arg(RENDERDOC_NumVerticesPerPrimitive(draw->topology)); } - node->setTag( - QVariant::fromValue(D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId, - state.inputAssembly.indexBuffer.byteOffset + - (draw ? draw->indexOffset * draw->indexByteWidth : 0), - iformat))); + uint32_t drawOffset = (draw ? draw->indexOffset * draw->indexByteWidth : 0); + + node->setTag(QVariant::fromValue( + D3D12VBIBTag(state.inputAssembly.indexBuffer.resourceId, + state.inputAssembly.indexBuffer.byteOffset + drawOffset, + qMin(state.inputAssembly.indexBuffer.byteSize - drawOffset, 0U), iformat))); for(const D3D12Pipe::ResourceData &res : m_Ctx.CurD3D12PipelineState()->resourceStates) { @@ -1489,7 +1490,7 @@ void D3D12PipelineStateViewer::setState() { RDTreeWidgetItem *node = new RDTreeWidgetItem({i, tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()}); - node->setTag(QVariant::fromValue(D3D12VBIBTag(ResourceId(), 0))); + node->setTag(QVariant::fromValue(D3D12VBIBTag(ResourceId(), 0, 0))); setEmptyRow(node); m_EmptyNodes.push_back(node); @@ -1513,11 +1514,9 @@ void D3D12PipelineStateViewer::setState() if(showNode(usedSlot, filledSlot)) { - qulonglong length = 0; + qulonglong length = v.byteSize; BufferDescription *buf = m_Ctx.GetBuffer(v.resourceId); - if(buf) - length = buf->length; RDTreeWidgetItem *node = NULL; @@ -1528,8 +1527,8 @@ void D3D12PipelineStateViewer::setState() node = new RDTreeWidgetItem({i, tr("No Buffer Set"), lit("-"), lit("-"), lit("-"), QString()}); - node->setTag(QVariant::fromValue( - D3D12VBIBTag(v.resourceId, v.byteOffset, m_Common.GetVBufferFormatString(i)))); + node->setTag(QVariant::fromValue(D3D12VBIBTag(v.resourceId, v.byteOffset, v.byteSize, + m_Common.GetVBufferFormatString(i)))); for(const D3D12Pipe::ResourceData &res : m_Ctx.CurD3D12PipelineState()->resourceStates) { @@ -1610,13 +1609,10 @@ void D3D12PipelineStateViewer::setState() if(showNode(usedSlot, filledSlot)) { - qulonglong length = 0; + qulonglong length = s.byteSize; BufferDescription *buf = m_Ctx.GetBuffer(s.resourceId); - if(buf) - length = buf->length; - RDTreeWidgetItem *node = new RDTreeWidgetItem( {i, s.resourceId, (qulonglong)s.byteOffset, length, s.writtenCountResourceId, (qulonglong)s.writtenCountByteOffset, QString()}); @@ -1975,7 +1971,7 @@ void D3D12PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in { if(buf->resourceId == m_Ctx.CurD3D12PipelineState()->streamOut.outputs[i].resourceId) { - size -= m_Ctx.CurD3D12PipelineState()->streamOut.outputs[i].byteOffset; + size = m_Ctx.CurD3D12PipelineState()->streamOut.outputs[i].byteSize; offs += m_Ctx.CurD3D12PipelineState()->streamOut.outputs[i].byteOffset; break; } @@ -2068,7 +2064,7 @@ void D3D12PipelineStateViewer::on_iaBuffers_itemActivated(RDTreeWidgetItem *item if(buf.id != ResourceId()) { - IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.offset, UINT64_MAX, buf.id, buf.format); + IBufferViewer *viewer = m_Ctx.ViewBuffer(buf.offset, buf.size, buf.id, buf.format); m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); } diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index c93a91bd2..50a0d0baa 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -2067,7 +2067,7 @@ void TextureViewer::ViewTexture(ResourceId ID, bool focus) BufferDescription *buf = m_Ctx.GetBuffer(ID); if(buf) { - IBufferViewer *viewer = m_Ctx.ViewBuffer(0, 0, ID); + IBufferViewer *viewer = m_Ctx.ViewBuffer(0, ~0ULL, ID); m_Ctx.AddDockWindow(viewer->Widget(), DockReference::AddTo, this); } diff --git a/renderdoc/api/replay/common_pipestate.h b/renderdoc/api/replay/common_pipestate.h index 15ba67b67..ba630dc90 100644 --- a/renderdoc/api/replay/common_pipestate.h +++ b/renderdoc/api/replay/common_pipestate.h @@ -346,7 +346,8 @@ struct BoundVBuffer bool operator==(const BoundVBuffer &o) const { - return resourceId == o.resourceId && byteOffset == o.byteOffset && byteStride == o.byteStride; + return resourceId == o.resourceId && byteOffset == o.byteOffset && byteStride == o.byteStride && + byteSize == o.byteSize; } bool operator<(const BoundVBuffer &o) const { @@ -356,6 +357,8 @@ struct BoundVBuffer return byteOffset < o.byteOffset; if(byteStride != o.byteStride) return byteStride < o.byteStride; + if(byteSize != o.byteSize) + return byteSize < o.byteSize; return false; } DOCUMENT("A :class:`~renderdoc.ResourceId` identifying the buffer."); @@ -364,6 +367,8 @@ struct BoundVBuffer uint64_t byteOffset = 0; DOCUMENT("The stride in bytes between the start of one element and the start of the next."); uint32_t byteStride = 0; + DOCUMENT("The size of the buffer binding, or 0xFFFFFFFF if the whole buffer is bound."); + uint64_t byteSize = 0; }; DECLARE_REFLECTION_STRUCT(BoundVBuffer); diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index 3fa3301db..c76794fef 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -46,6 +46,8 @@ struct MeshFormat uint64_t indexByteOffset = 0; DOCUMENT("The width in bytes of each index. Valid values are 1 (depending on API), 2 or 4."); uint32_t indexByteStride = 0; + DOCUMENT("The number of bytes to use from the index buffer. Only valid on APIs that allow it."); + uint64_t indexByteSize = 0; DOCUMENT("For indexed meshes, a value added to each index before using it to read the vertex."); int32_t baseVertex = 0; @@ -55,6 +57,8 @@ struct MeshFormat uint64_t vertexByteOffset = 0; DOCUMENT("The stride in bytes between the start of one vertex and the start of another."); uint32_t vertexByteStride = 0; + DOCUMENT("The number of bytes to use from the vertex buffer. Only valid on APIs that allow it."); + uint64_t vertexByteSize = 0; DOCUMENT("The :class:`ResourceFormat` describing this mesh component."); ResourceFormat format; diff --git a/renderdoc/api/replay/pipestate.inl b/renderdoc/api/replay/pipestate.inl index cc2b91c88..fd4707620 100644 --- a/renderdoc/api/replay/pipestate.inl +++ b/renderdoc/api/replay/pipestate.inl @@ -466,37 +466,36 @@ ResourceId PipeState::GetShader(ShaderStage stage) const BoundVBuffer PipeState::GetIBuffer() const { - ResourceId buf; - uint64_t ByteOffset = 0; + BoundVBuffer ret; if(IsCaptureLoaded()) { if(IsCaptureD3D11()) { - buf = m_D3D11->inputAssembly.indexBuffer.resourceId; - ByteOffset = m_D3D11->inputAssembly.indexBuffer.byteOffset; + ret.resourceId = m_D3D11->inputAssembly.indexBuffer.resourceId; + ret.byteOffset = m_D3D11->inputAssembly.indexBuffer.byteOffset; + ret.byteSize = ~0ULL; } else if(IsCaptureD3D12()) { - buf = m_D3D12->inputAssembly.indexBuffer.resourceId; - ByteOffset = m_D3D12->inputAssembly.indexBuffer.byteOffset; + ret.resourceId = m_D3D12->inputAssembly.indexBuffer.resourceId; + ret.byteOffset = m_D3D12->inputAssembly.indexBuffer.byteOffset; + ret.byteSize = m_D3D12->inputAssembly.indexBuffer.byteSize; } else if(IsCaptureGL()) { - buf = m_GL->vertexInput.indexBuffer; - ByteOffset = 0; // GL only has per-draw index offset + ret.resourceId = m_GL->vertexInput.indexBuffer; + ret.byteOffset = 0; // GL only has per-draw index offset + ret.byteSize = ~0ULL; } else if(IsCaptureVK()) { - buf = m_Vulkan->inputAssembly.indexBuffer.resourceId; - ByteOffset = m_Vulkan->inputAssembly.indexBuffer.byteOffset; + ret.resourceId = m_Vulkan->inputAssembly.indexBuffer.resourceId; + ret.byteOffset = m_Vulkan->inputAssembly.indexBuffer.byteOffset; + ret.byteSize = ~0ULL; } } - BoundVBuffer ret; - ret.resourceId = buf; - ret.byteOffset = ByteOffset; - return ret; } @@ -562,6 +561,7 @@ rdcarray PipeState::GetVBuffers() const ret[i].resourceId = m_D3D11->inputAssembly.vertexBuffers[i].resourceId; ret[i].byteOffset = m_D3D11->inputAssembly.vertexBuffers[i].byteOffset; ret[i].byteStride = m_D3D11->inputAssembly.vertexBuffers[i].byteStride; + ret[i].byteSize = ~0ULL; } } else if(IsCaptureD3D12()) @@ -572,6 +572,7 @@ rdcarray PipeState::GetVBuffers() const ret[i].resourceId = m_D3D12->inputAssembly.vertexBuffers[i].resourceId; ret[i].byteOffset = m_D3D12->inputAssembly.vertexBuffers[i].byteOffset; ret[i].byteStride = m_D3D12->inputAssembly.vertexBuffers[i].byteStride; + ret[i].byteSize = m_D3D12->inputAssembly.vertexBuffers[i].byteSize; } } else if(IsCaptureGL()) @@ -582,6 +583,7 @@ rdcarray PipeState::GetVBuffers() const ret[i].resourceId = m_GL->vertexInput.vertexBuffers[i].resourceId; ret[i].byteOffset = m_GL->vertexInput.vertexBuffers[i].byteOffset; ret[i].byteStride = m_GL->vertexInput.vertexBuffers[i].byteStride; + ret[i].byteSize = ~0ULL; } } else if(IsCaptureVK()) @@ -592,6 +594,7 @@ rdcarray PipeState::GetVBuffers() const ret[i].resourceId = m_Vulkan->vertexInput.vertexBuffers[i].resourceId; ret[i].byteOffset = m_Vulkan->vertexInput.vertexBuffers[i].byteOffset; ret[i].byteStride = 0; + ret[i].byteSize = ~0ULL; // find the binding that corresponds to this VB to get the stride. Valid use suggests there // should be at most 1, so stop at first result. If there are 0 then the stride is just 0 @@ -964,6 +967,9 @@ BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, ui buf = b.resourceId; ByteOffset = b.byteOffset; ByteSize = b.byteSize; + + if(ByteSize == 0) + ByteSize = ~0ULL; } } } diff --git a/renderdoc/driver/d3d11/d3d11_postvs.cpp b/renderdoc/driver/d3d11/d3d11_postvs.cpp index 0a0108811..cdc854a50 100644 --- a/renderdoc/driver/d3d11/d3d11_postvs.cpp +++ b/renderdoc/driver/d3d11/d3d11_postvs.cpp @@ -128,6 +128,7 @@ MeshFormat D3D11Replay::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint { ret.indexResourceId = ((WrappedID3D11Buffer *)s.idxBuf)->GetResourceID(); ret.indexByteStride = s.idxFmt == DXGI_FORMAT_R16_UINT ? 2 : 4; + ret.indexByteSize = ~0ULL; } else { @@ -136,9 +137,14 @@ MeshFormat D3D11Replay::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint } if(s.buf) + { ret.vertexResourceId = ((WrappedID3D11Buffer *)s.buf)->GetResourceID(); + ret.vertexByteSize = ~0ULL; + } else + { ret.vertexResourceId = ResourceId(); + } ret.vertexByteOffset = s.instStride * instID; ret.vertexByteStride = s.vertStride; diff --git a/renderdoc/driver/d3d12/d3d12_postvs.cpp b/renderdoc/driver/d3d12/d3d12_postvs.cpp index dcb400d0b..10262f719 100644 --- a/renderdoc/driver/d3d12/d3d12_postvs.cpp +++ b/renderdoc/driver/d3d12/d3d12_postvs.cpp @@ -400,7 +400,7 @@ void D3D12Replay::InitPostVSBuffers(uint32_t eventId) else // drawcall is indexed { bytebuf idxdata; - if(rs.ibuffer.buf != ResourceId()) + if(rs.ibuffer.buf != ResourceId() && rs.ibuffer.size > 0) GetBufferData(rs.ibuffer.buf, rs.ibuffer.offs + drawcall->indexOffset * rs.ibuffer.bytewidth, RDCMIN(drawcall->numIndices * rs.ibuffer.bytewidth, rs.ibuffer.size), idxdata); @@ -1361,6 +1361,7 @@ MeshFormat D3D12Replay::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint { ret.indexResourceId = GetResID(s.idxBuf); ret.indexByteStride = s.idxFmt == DXGI_FORMAT_R16_UINT ? 2 : 4; + ret.indexByteSize = ~0ULL; } else { @@ -1371,9 +1372,15 @@ MeshFormat D3D12Replay::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint ret.baseVertex = 0; if(s.buf != NULL) + { ret.vertexResourceId = GetResID(s.buf); + ret.vertexByteSize = ~0ULL; + } else + { ret.vertexResourceId = ResourceId(); + ret.vertexByteSize = 0; + } ret.vertexByteOffset = s.instStride * instID; ret.vertexByteStride = s.vertStride; diff --git a/renderdoc/driver/d3d12/d3d12_rendermesh.cpp b/renderdoc/driver/d3d12/d3d12_rendermesh.cpp index 076c12f03..1f9ab259f 100644 --- a/renderdoc/driver/d3d12/d3d12_rendermesh.cpp +++ b/renderdoc/driver/d3d12/d3d12_rendermesh.cpp @@ -328,7 +328,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray &secon D3D12_VERTEX_BUFFER_VIEW view; view.BufferLocation = vb->GetGPUVirtualAddress() + offs; view.StrideInBytes = fmt.vertexByteStride; - view.SizeInBytes = UINT(vb->GetDesc().Width - offs); + view.SizeInBytes = (UINT)fmt.vertexByteSize; list->IASetVertexBuffers(0, 1, &view); // set it to the secondary buffer too just as dummy info @@ -348,7 +348,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray &secon D3D12_INDEX_BUFFER_VIEW iview; iview.BufferLocation = ib->GetGPUVirtualAddress() + fmt.indexByteOffset; - iview.SizeInBytes = UINT(ib->GetDesc().Width - fmt.indexByteOffset); + iview.SizeInBytes = (UINT)fmt.indexByteSize; iview.Format = fmt.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; list->IASetIndexBuffer(&iview); @@ -380,7 +380,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray &secon D3D12_VERTEX_BUFFER_VIEW view; view.BufferLocation = vb->GetGPUVirtualAddress() + offs; view.StrideInBytes = cfg.position.vertexByteStride; - view.SizeInBytes = UINT(vb->GetDesc().Width - offs); + view.SizeInBytes = (UINT)cfg.position.vertexByteSize; list->IASetVertexBuffers(0, 1, &view); // set it to the secondary buffer too just as dummy info @@ -413,7 +413,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray &secon D3D12_VERTEX_BUFFER_VIEW view; view.BufferLocation = vb->GetGPUVirtualAddress() + offs; view.StrideInBytes = cfg.second.vertexByteStride; - view.SizeInBytes = UINT(vb->GetDesc().Width - offs); + view.SizeInBytes = (UINT)cfg.second.vertexByteSize; list->IASetVertexBuffers(1, 1, &view); } @@ -470,7 +470,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray &secon D3D12_INDEX_BUFFER_VIEW view; view.BufferLocation = ib->GetGPUVirtualAddress() + cfg.position.indexByteOffset; - view.SizeInBytes = UINT(ib->GetDesc().Width - cfg.position.indexByteOffset); + view.SizeInBytes = (UINT)cfg.position.indexByteSize; view.Format = cfg.position.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; list->IASetIndexBuffer(&view); @@ -511,7 +511,7 @@ void D3D12Replay::RenderMesh(uint32_t eventId, const rdcarray &secon D3D12_INDEX_BUFFER_VIEW view; view.BufferLocation = ib->GetGPUVirtualAddress() + cfg.position.indexByteOffset; - view.SizeInBytes = UINT(ib->GetDesc().Width - cfg.position.indexByteOffset); + view.SizeInBytes = (UINT)cfg.position.indexByteSize; view.Format = cfg.position.indexByteStride == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; list->IASetIndexBuffer(&view); diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp index 6a787f84c..f0c717f37 100644 --- a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp @@ -1680,7 +1680,9 @@ void GatherConstantBuffers(WrappedID3D12Device *pDevice, const DXBCBytecode::Pro pDevice->GetResourceManager()->GetCurrentAs(resId); cbufData.clear(); - pDevice->GetDebugManager()->GetBufferData(pCbvResource, byteOffset, 0, cbufData); + if(cbv.SizeInBytes > 0) + pDevice->GetDebugManager()->GetBufferData(pCbvResource, byteOffset, cbv.SizeInBytes, + cbufData); AddCBufferToGlobalState(program, global, sourceVars, refl, mapping, slot, cbufData); desc++; @@ -1777,18 +1779,22 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui { D3D12RenderState::VertBuffer &vb = rs.vbuffers[i]; ID3D12Resource *buffer = m_pDevice->GetResourceManager()->GetCurrentAs(vb.buf); - GetDebugManager()->GetBufferData(buffer, vb.offs + vb.stride * (draw->vertexOffset + idx), - vb.stride, vertData[i]); + + if(vb.stride * (draw->vertexOffset + idx) < vb.size) + GetDebugManager()->GetBufferData(buffer, vb.offs + vb.stride * (draw->vertexOffset + idx), + vb.stride, vertData[i]); for(UINT isr = 1; isr <= MaxStepRate; isr++) { - GetDebugManager()->GetBufferData( - buffer, vb.offs + vb.stride * (draw->instanceOffset + (instid / isr)), vb.stride, - instData[i * MaxStepRate + isr - 1]); + if((draw->instanceOffset + (instid / isr)) < vb.size) + GetDebugManager()->GetBufferData( + buffer, vb.offs + vb.stride * (draw->instanceOffset + (instid / isr)), vb.stride, + instData[i * MaxStepRate + isr - 1]); } - GetDebugManager()->GetBufferData(buffer, vb.offs + vb.stride * draw->instanceOffset, - vb.stride, staticData[i]); + if(vb.stride * draw->instanceOffset < vb.size) + GetDebugManager()->GetBufferData(buffer, vb.offs + vb.stride * draw->instanceOffset, + vb.stride, staticData[i]); } } diff --git a/renderdoc/driver/gl/gl_postvs.cpp b/renderdoc/driver/gl/gl_postvs.cpp index 2128b9195..745a27e5c 100644 --- a/renderdoc/driver/gl/gl_postvs.cpp +++ b/renderdoc/driver/gl/gl_postvs.cpp @@ -1946,6 +1946,7 @@ MeshFormat GLReplay::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint32_ { ret.indexResourceId = m_pDriver->GetResourceManager()->GetID(BufferRes(ctx, s.idxBuf)); ret.indexByteStride = s.idxByteWidth; + ret.indexByteSize = ~0ULL; } else { @@ -1956,9 +1957,14 @@ MeshFormat GLReplay::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint32_ ret.baseVertex = 0; if(s.buf) + { ret.vertexResourceId = m_pDriver->GetResourceManager()->GetID(BufferRes(ctx, s.buf)); + ret.vertexByteSize = ~0ULL; + } else + { ret.vertexResourceId = ResourceId(); + } ret.vertexByteOffset = s.instStride * instID; ret.vertexByteStride = s.vertStride; diff --git a/renderdoc/driver/vulkan/vk_postvs.cpp b/renderdoc/driver/vulkan/vk_postvs.cpp index 96c87a82a..bc9d5fc06 100644 --- a/renderdoc/driver/vulkan/vk_postvs.cpp +++ b/renderdoc/driver/vulkan/vk_postvs.cpp @@ -3037,6 +3037,7 @@ MeshFormat VulkanReplay::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uin ret.indexByteStride = 1; else ret.indexByteStride = 2; + ret.indexByteSize = ~0ULL; } else { @@ -3047,9 +3048,14 @@ MeshFormat VulkanReplay::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uin ret.baseVertex = s.baseVertex; if(s.buf != VK_NULL_HANDLE) + { ret.vertexResourceId = GetResID(s.buf); + ret.vertexByteSize = ~0ULL; + } else + { ret.vertexResourceId = ResourceId(); + } ret.vertexByteOffset = s.instStride * (instID + viewID * numInstances); ret.vertexByteStride = s.vertStride; diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index 227d3e52d..8379473c2 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -401,7 +401,10 @@ ReplayStatus WrappedVulkan::Initialise(VkInitParams ¶ms, uint64_t sectionVer SAFE_DELETE_ARRAY(extscstr); if(ret != VK_SUCCESS) + { + RDCLOG("Instance creation returned %s", ToStr(ret).c_str()); return ReplayStatus::APIHardwareUnsupported; + } RDCASSERTEQUAL(ret, VK_SUCCESS); diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index dbdf8feab..3b5e70c25 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -793,10 +793,12 @@ void DoSerialise(SerialiserType &ser, MeshFormat &el) SERIALISE_MEMBER(indexResourceId); SERIALISE_MEMBER(indexByteOffset); SERIALISE_MEMBER(indexByteStride); + SERIALISE_MEMBER(indexByteSize); SERIALISE_MEMBER(baseVertex); SERIALISE_MEMBER(vertexResourceId); SERIALISE_MEMBER(vertexByteOffset); SERIALISE_MEMBER(vertexByteStride); + SERIALISE_MEMBER(vertexByteSize); SERIALISE_MEMBER(format); SERIALISE_MEMBER(meshColor); SERIALISE_MEMBER(topology); @@ -808,7 +810,7 @@ void DoSerialise(SerialiserType &ser, MeshFormat &el) SERIALISE_MEMBER(instanced); SERIALISE_MEMBER(showAlpha); - SIZE_CHECK(96); + SIZE_CHECK(128); } template diff --git a/util/test/demos/CMakeLists.txt b/util/test/demos/CMakeLists.txt index a1a2cbe2f..1118f7174 100644 --- a/util/test/demos/CMakeLists.txt +++ b/util/test/demos/CMakeLists.txt @@ -8,6 +8,7 @@ set(VULKAN_SRC vk/vk_helpers.cpp vk/vk_test.cpp vk/vk_adv_cbuffer_zoo.cpp + vk/vk_buffer_truncation.cpp vk/vk_cbuffer_zoo.cpp vk/vk_custom_border_color.cpp vk/vk_descriptor_index.cpp @@ -51,6 +52,7 @@ set(OPENGL_SRC gl/gl_test.cpp gl/gl_test_linux.cpp gl/gl_buffer_spam.cpp + gl/gl_buffer_truncation.cpp gl/gl_buffer_updates.cpp gl/gl_callstacks.cpp gl/gl_cbuffer_zoo.cpp diff --git a/util/test/demos/d3d11/d3d11_buffer_truncation.cpp b/util/test/demos/d3d11/d3d11_buffer_truncation.cpp new file mode 100644 index 000000000..10d013ed2 --- /dev/null +++ b/util/test/demos/d3d11/d3d11_buffer_truncation.cpp @@ -0,0 +1,161 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2020 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "d3d11_test.h" + +RD_TEST(D3D11_Buffer_Truncation, D3D11GraphicsTest) +{ + static constexpr const char *Description = + "Tests using a constant buffer that is truncated by range (when supported), as well as " + "vertex/index buffers truncated by size."; + + std::string vertex = R"EOSHADER( + +struct vertin +{ + float3 pos : POSITION; + float4 col : COLOR0; + float2 uv : TEXCOORD0; +}; + +struct v2f +{ + float4 svpos : SV_POSITION; + float4 pos : OUTPOSITION; + float4 col : OUTCOLOR; +}; + +v2f main(vertin IN) +{ + v2f OUT = (v2f)0; + + OUT.svpos = OUT.pos = float4(IN.pos.xyz, 1); + OUT.col = IN.col; + + return OUT; +} + +)EOSHADER"; + + std::string pixel = R"EOSHADER( + +cbuffer consts : register(b0) +{ + float4 padding[16]; + float4 outcol; +}; + +float4 main() : SV_Target0 +{ + return outcol; +} + +)EOSHADER"; + + int main() + { + // initialise, create window, create device, etc + if(!Init()) + return 3; + + const DefaultA2V OffsetTri[] = { + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + + {Vec3f(9.9f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + + {Vec3f(-0.5f, -0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.0f, 0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.5f, -0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + {Vec3f(8.8f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + }; + uint16_t indices[] = {99, 99, 99, 1, 2, 3, 4, 5}; + Vec4f cbufferdata[64] = {}; + cbufferdata[32] = Vec4f(1.0f, 2.0f, 3.0f, 4.0f); + + if(!opts.ConstantBufferOffsetting) + cbufferdata[16] = Vec4f(1.0f, 2.0f, 3.0f, 4.0f); + + ID3DBlobPtr vsblob = Compile(vertex, "main", "vs_5_0"); + ID3DBlobPtr psblob = Compile(pixel, "main", "ps_5_0"); + + CreateDefaultInputLayout(vsblob); + + ID3D11VertexShaderPtr vs = CreateVS(vsblob); + ID3D11PixelShaderPtr ps = CreatePS(psblob); + + ID3D11BufferPtr vb = MakeBuffer().Vertex().Data(OffsetTri); + ID3D11BufferPtr ib = MakeBuffer().Index().Data(indices); + ID3D11BufferPtr cb = + MakeBuffer() + .Constant() + .Data(cbufferdata) + .Size(opts.ConstantBufferOffsetting ? sizeof(cbufferdata) : sizeof(Vec4f) * 16); + + ID3D11Texture2DPtr fltTex = + MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, screenWidth, screenHeight).RTV().SRV(); + ID3D11RenderTargetViewPtr fltRT = MakeRTV(fltTex); + + while(Running()) + { + ClearRenderTargetView(bbRTV, {0.2f, 0.2f, 0.2f, 1.0f}); + + IASetVertexBuffer(vb, sizeof(DefaultA2V), sizeof(DefaultA2V) * 3); + ctx->IASetIndexBuffer(ib, DXGI_FORMAT_R16_UINT, sizeof(uint16_t) * 3); + ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->IASetInputLayout(defaultLayout); + + ctx->VSSetShader(vs, NULL, 0); + ctx->PSSetShader(ps, NULL, 0); + + if(opts.ConstantBufferOffsetting) + { + UINT offset = 16; + UINT count = 16; + ctx1->PSSetConstantBuffers1(0, 1, &cb.GetInterfacePtr(), &offset, &count); + } + else + { + setMarker("NoCBufferRange"); + ctx->PSSetConstantBuffers(0, 1, &cb.GetInterfacePtr()); + } + + RSSetViewport({0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f}); + + ctx->OMSetRenderTargets(1, &fltRT.GetInterfacePtr(), NULL); + + ctx->DrawIndexed(6, 0, 0); + + blitToSwap(fltTex); + + Present(); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/demos/d3d12/d3d12_buffer_truncation.cpp b/util/test/demos/d3d12/d3d12_buffer_truncation.cpp new file mode 100644 index 000000000..2f601a565 --- /dev/null +++ b/util/test/demos/d3d12/d3d12_buffer_truncation.cpp @@ -0,0 +1,198 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2020 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "d3d12_test.h" + +RD_TEST(D3D12_Buffer_Truncation, D3D12GraphicsTest) +{ + static constexpr const char *Description = + "Tests using a constant buffer that is truncated by range, as well as " + "vertex/index buffers truncated by size."; + + std::string vertex = R"EOSHADER( + +struct vertin +{ + float3 pos : POSITION; + float4 col : COLOR0; + float2 uv : TEXCOORD0; +}; + +struct v2f +{ + float4 svpos : SV_POSITION; + float4 pos : OUTPOSITION; + float4 col : OUTCOLOR; +}; + +v2f main(vertin IN) +{ + v2f OUT = (v2f)0; + + OUT.svpos = OUT.pos = float4(IN.pos.xyz, 1); + OUT.col = IN.col; + + return OUT; +} + +)EOSHADER"; + + std::string pixel = R"EOSHADER( + +cbuffer consts : register(b0) +{ + float4 padding[16]; + float4 outcol; +}; + +float4 main() : SV_Target0 +{ + return outcol; +} + +)EOSHADER"; + + int main() + { + // initialise, create window, create device, etc + if(!Init()) + return 3; + + ID3DBlobPtr vsblob = Compile(vertex, "main", "vs_5_0"); + ID3DBlobPtr psblob = Compile(pixel, "main", "ps_5_0"); + + const DefaultA2V OffsetTri[] = { + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + + {Vec3f(9.9f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + + {Vec3f(-0.5f, -0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.0f, 0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.5f, -0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + {Vec3f(8.8f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + + {Vec3f(3.3f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(3.3f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(3.3f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(3.3f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(3.3f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(3.3f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + }; + uint16_t indices[] = {99, 99, 99, 1, 2, 3, 4, 5, 88, 88, 88, 88, 88}; + Vec4f cbufferdata[64] = {}; + cbufferdata[32] = Vec4f(1.0f, 2.0f, 3.0f, 4.0f); + + ID3D12ResourcePtr vb = MakeBuffer().Data(OffsetTri); + ID3D12ResourcePtr ib = MakeBuffer().Data(indices); + ID3D12ResourcePtr cb = MakeBuffer().Data(cbufferdata); + + ID3D12RootSignaturePtr sig = MakeSig({ + tableParam(D3D12_SHADER_VISIBILITY_PIXEL, D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 0, 0, 1), + }); + + ID3D12PipelineStatePtr pso = MakePSO().RootSig(sig).InputLayout().VS(vsblob).PS(psblob).RTVs( + {DXGI_FORMAT_R32G32B32A32_FLOAT}); + + ResourceBarrier(vb, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + ResourceBarrier(ib, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_INDEX_BUFFER); + ResourceBarrier(cb, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + + D3D12_CONSTANT_BUFFER_VIEW_DESC cbview; + cbview.BufferLocation = cb->GetGPUVirtualAddress() + sizeof(Vec4f) * 16; + cbview.SizeInBytes = sizeof(Vec4f) * 16; + dev->CreateConstantBufferView(&cbview, m_CBVUAVSRV->GetCPUDescriptorHandleForHeapStart()); + + ID3D12ResourcePtr rtvtex = MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, screenWidth, screenHeight) + .RTV() + .InitialState(D3D12_RESOURCE_STATE_RENDER_TARGET); + + while(Running()) + { + ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer(); + + Reset(cmd); + + ID3D12ResourcePtr bb = StartUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET); + + D3D12_CPU_DESCRIPTOR_HANDLE bbrtv = + MakeRTV(bb).Format(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).CreateCPU(0); + + ClearRenderTargetView(cmd, bbrtv, {0.2f, 0.2f, 0.2f, 1.0f}); + + D3D12_CPU_DESCRIPTOR_HANDLE offrtv = MakeRTV(rtvtex).CreateCPU(0); + + ClearRenderTargetView(cmd, offrtv, {0.2f, 0.2f, 0.2f, 1.0f}); + + cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + D3D12_VERTEX_BUFFER_VIEW vbview; + vbview.BufferLocation = vb->GetGPUVirtualAddress() + sizeof(DefaultA2V) * 3; + vbview.SizeInBytes = sizeof(DefaultA2V) * 5; + vbview.StrideInBytes = sizeof(DefaultA2V); + cmd->IASetVertexBuffers(0, 1, &vbview); + + D3D12_INDEX_BUFFER_VIEW ibview; + ibview.BufferLocation = ib->GetGPUVirtualAddress() + sizeof(uint16_t) * 3; + ibview.SizeInBytes = sizeof(uint16_t) * 5; + ibview.Format = DXGI_FORMAT_R16_UINT; + cmd->IASetIndexBuffer(&ibview); + + cmd->SetDescriptorHeaps(1, &m_CBVUAVSRV.GetInterfacePtr()); + + cmd->SetPipelineState(pso); + cmd->SetGraphicsRootSignature(sig); + cmd->SetGraphicsRootDescriptorTable(0, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart()); + + RSSetViewport(cmd, {0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f}); + RSSetScissorRect(cmd, {0, 0, screenWidth, screenHeight}); + + OMSetRenderTargets(cmd, {offrtv}, {}); + + cmd->DrawIndexedInstanced(6, 1, 0, 0, 0); + + ResourceBarrier(cmd, rtvtex, D3D12_RESOURCE_STATE_RENDER_TARGET, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + + blitToSwap(cmd, rtvtex, bb); + + ResourceBarrier(cmd, rtvtex, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_RENDER_TARGET); + + FinishUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET); + + cmd->Close(); + + Submit({cmd}); + + Present(); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index 9281d22aa..f995c2073 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -123,6 +123,7 @@ + @@ -168,6 +169,7 @@ + @@ -205,6 +207,7 @@ + @@ -275,7 +278,7 @@ - + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index 51a6f4da4..0b37082db 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -403,9 +403,6 @@ D3D12\demos - - Vulkan\demos - D3D12\demos @@ -502,6 +499,18 @@ Vulkan\demos + + Vulkan\demos + + + OpenGL\demos + + + D3D12\demos + + + D3D11\demos + diff --git a/util/test/demos/gl/gl_buffer_truncation.cpp b/util/test/demos/gl/gl_buffer_truncation.cpp new file mode 100644 index 000000000..09f8ae25f --- /dev/null +++ b/util/test/demos/gl/gl_buffer_truncation.cpp @@ -0,0 +1,159 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2020 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "gl_test.h" + +RD_TEST(GL_Buffer_Truncation, OpenGLGraphicsTest) +{ + static constexpr const char *Description = + "Tests using a uniform buffer that is truncated by range, as well as " + "vertex/index buffers truncated by size."; + + const std::string vertex = R"EOSHADER( +#version 460 core + +layout(location = 0) in vec3 POSITION; +layout(location = 1) in vec4 COLOR; + +layout(location = 0) out vec4 OUTPOSITION; +layout(location = 1) out vec4 OUTCOLOR; + +void main() +{ + gl_Position = OUTPOSITION = vec4(POSITION.xyz, 1); + OUTCOLOR = COLOR; +} + +)EOSHADER"; + + const std::string pixel = R"EOSHADER( +#version 460 core + +layout(location = 0, index = 0) out vec4 Color; + +layout(binding = 0, std140) uniform constsbuf +{ + vec4 padding[16]; + vec4 outcol; +}; + +void main() +{ + Color = outcol; +} + +)EOSHADER"; + + int main() + { + // initialise, create window, create context, etc + if(!Init()) + return 3; + + const DefaultA2V OffsetTri[] = { + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + + {Vec3f(9.9f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + + {Vec3f(-0.5f, -0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.0f, 0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.5f, -0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + {Vec3f(8.8f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + }; + uint16_t indices[] = {99, 99, 99, 1, 2, 3, 4, 5}; + Vec4f cbufferdata[64] = {}; + cbufferdata[32] = Vec4f(1.0f, 2.0f, 3.0f, 4.0f); + + GLuint vao = MakeVAO(); + glBindVertexArray(vao); + + GLuint vb = MakeBuffer(); + glBindBuffer(GL_ARRAY_BUFFER, vb); + glBufferStorage(GL_ARRAY_BUFFER, sizeof(OffsetTri), OffsetTri, 0); + + glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0); + glVertexAttribFormat(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vec3f)); + glVertexAttribFormat(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vec3f) + sizeof(Vec4f)); + + glVertexAttribBinding(0, 0); + glVertexAttribBinding(1, 0); + glVertexAttribBinding(2, 0); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + GLuint ib = MakeBuffer(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib); + glBufferStorage(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, 0); + + GLuint program = MakeProgram(vertex, pixel); + + GLuint cb = MakeBuffer(); + glBindBuffer(GL_UNIFORM_BUFFER, cb); + glBufferStorage(GL_UNIFORM_BUFFER, sizeof(cbufferdata), cbufferdata, GL_MAP_WRITE_BIT); + + GLuint fbo = MakeFBO(); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + // Color render texture + GLuint colattach = MakeTexture(); + + glBindTexture(GL_TEXTURE_2D, colattach); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, screenWidth, screenHeight); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colattach, 0); + + while(Running()) + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + float col[] = {0.2f, 0.2f, 0.2f, 1.0f}; + glClearBufferfv(GL_COLOR, 0, col); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glBindVertexArray(vao); + + glBindBufferRange(GL_UNIFORM_BUFFER, 0, cb, 16 * sizeof(Vec4f), 16 * sizeof(Vec4f)); + + glUseProgram(program); + + glViewport(0, 0, GLsizei(screenWidth), GLsizei(screenHeight)); + + glBindVertexBuffer(0, vb, sizeof(DefaultA2V) * 3, sizeof(DefaultA2V)); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void *)(sizeof(uint16_t) * 3)); + + blitToSwap(colattach); + + Present(); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/demos/vk/vk_truncated_cbuffer.cpp b/util/test/demos/vk/vk_buffer_truncation.cpp similarity index 60% rename from util/test/demos/vk/vk_truncated_cbuffer.cpp rename to util/test/demos/vk/vk_buffer_truncation.cpp index abc97f816..8adc034aa 100644 --- a/util/test/demos/vk/vk_truncated_cbuffer.cpp +++ b/util/test/demos/vk/vk_buffer_truncation.cpp @@ -24,45 +24,31 @@ #include "vk_test.h" -RD_TEST(VK_Truncated_CBuffer, VulkanGraphicsTest) +RD_TEST(VK_Buffer_Truncation, VulkanGraphicsTest) { static constexpr const char *Description = - "Draws using a cbuffer that is truncated by the descriptor range."; - - std::string common = R"EOSHADER( - -#version 420 core - -struct v2f -{ - vec4 pos; - vec4 col; - vec4 uv; -}; - -)EOSHADER"; + "Tests using a uniform buffer that is truncated by the descriptor range, as well as " + "vertex/index buffers truncated by size."; const std::string vertex = R"EOSHADER( +#version 460 core -layout(location = 0) in vec3 Position; -layout(location = 1) in vec4 Color; -layout(location = 2) in vec2 UV; +layout(location = 0) in vec3 POSITION; +layout(location = 1) in vec4 COLOR; -layout(location = 0) out v2f vertOut; +layout(location = 0) out vec4 OUTPOSITION; +layout(location = 1) out vec4 OUTCOLOR; void main() { - vertOut.pos = vec4(Position.xyz*vec3(1,-1,1), 1); - gl_Position = vertOut.pos; - vertOut.col = Color; - vertOut.uv = vec4(UV.xy, 0, 1); + gl_Position = OUTPOSITION = vec4(POSITION.xyz, 1); + OUTCOLOR = COLOR; } )EOSHADER"; const std::string pixel = R"EOSHADER( - -layout(location = 0) in v2f vertIn; +#version 460 core layout(location = 0, index = 0) out vec4 Color; @@ -93,6 +79,23 @@ void main() if(!Init()) return 3; + const DefaultA2V OffsetTri[] = { + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(7.7f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + + {Vec3f(9.9f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + + {Vec3f(-0.5f, -0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.0f, 0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.5f, -0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + + {Vec3f(8.8f, 0.0f, 0.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, + }; + uint16_t indices[] = {99, 99, 99, 1, 2, 3, 4, 5}; + Vec4f cbufferdata[64] = {}; + cbufferdata[32] = Vec4f(1.0f, 2.0f, 3.0f, 4.0f); + VkDescriptorSetLayout setlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({ {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, })); @@ -111,38 +114,40 @@ void main() }; pipeCreateInfo.stages = { - CompileShaderModule(common + vertex, ShaderLang::glsl, ShaderStage::vert, "main"), - CompileShaderModule(common + pixel, ShaderLang::glsl, ShaderStage::frag, "main"), + CompileShaderModule(vertex, ShaderLang::glsl, ShaderStage::vert, "main"), + CompileShaderModule(pixel, ShaderLang::glsl, ShaderStage::frag, "main"), }; VkPipeline pipe = createGraphicsPipeline(pipeCreateInfo); AllocatedBuffer vb( - this, vkh::BufferCreateInfo(sizeof(DefaultTri), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT), + this, vkh::BufferCreateInfo(sizeof(OffsetTri), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); - vb.upload(DefaultTri); + vb.upload(OffsetTri); - Vec4f data[20]; + AllocatedBuffer ib(this, + vkh::BufferCreateInfo(sizeof(indices), VK_BUFFER_USAGE_INDEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); - data[16] = Vec4f(1.0f, 2.0f, 3.0f, 4.0f); + ib.upload(indices); AllocatedBuffer cb( - this, vkh::BufferCreateInfo(sizeof(Vec4f) * 20, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT), + this, vkh::BufferCreateInfo(sizeof(cbufferdata), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); - - cb.upload(data); + cb.upload(cbufferdata); VkDescriptorSet descset = allocateDescriptorSet(setlayout); vkh::updateDescriptorSets( - device, - { - vkh::WriteDescriptorSet(descset, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - {vkh::DescriptorBufferInfo(cb.buffer, 0, sizeof(Vec4f) * 16)}), - }); + device, { + vkh::WriteDescriptorSet(descset, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + {vkh::DescriptorBufferInfo( + cb.buffer, sizeof(Vec4f) * 16, sizeof(Vec4f) * 16)}), + }); while(Running()) { @@ -164,9 +169,10 @@ void main() vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); vkCmdSetViewport(cmd, 0, 1, &mainWindow->viewport); vkCmdSetScissor(cmd, 0, 1, &mainWindow->scissor); - vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {0}); + vkCmdBindIndexBuffer(cmd, ib.buffer, sizeof(uint16_t) * 3, VK_INDEX_TYPE_UINT16); + vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {sizeof(DefaultA2V) * 3}); vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, {descset}, {}); - vkCmdDraw(cmd, 3, 1, 0, 0); + vkCmdDrawIndexed(cmd, 6, 1, 0, 0, 0); vkCmdEndRenderPass(cmd); diff --git a/util/test/demos/vk/vk_cbuffer_zoo.cpp b/util/test/demos/vk/vk_cbuffer_zoo.cpp index fe5f10ad8..1efef36a1 100644 --- a/util/test/demos/vk/vk_cbuffer_zoo.cpp +++ b/util/test/demos/vk/vk_cbuffer_zoo.cpp @@ -716,20 +716,7 @@ float4 main() : SV_Target0 VK_IMAGE_LAYOUT_GENERAL, img.image), }); - VkImageBlit region = {}; - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.srcSubresource.layerCount = 1; - region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.dstSubresource.layerCount = 1; - region.srcOffsets[1].x = mainWindow->scissor.extent.width; - region.srcOffsets[1].y = mainWindow->scissor.extent.height; - region.srcOffsets[1].z = 1; - region.dstOffsets[1].x = mainWindow->scissor.extent.width; - region.dstOffsets[1].y = mainWindow->scissor.extent.height; - region.dstOffsets[1].z = 1; - - vkCmdBlitImage(cmd, img.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL, 1, - ®ion, VK_FILTER_LINEAR); + blitToSwap(cmd, img.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL); FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); diff --git a/util/test/demos/vk/vk_secondary_cmdbuf.cpp b/util/test/demos/vk/vk_secondary_cmdbuf.cpp index 701c8399b..1e0d61f86 100644 --- a/util/test/demos/vk/vk_secondary_cmdbuf.cpp +++ b/util/test/demos/vk/vk_secondary_cmdbuf.cpp @@ -215,15 +215,7 @@ void main() VK_IMAGE_LAYOUT_GENERAL, img.image), }); - region.srcOffsets[1].x = size.extent.width; - region.srcOffsets[1].y = size.extent.height; - region.srcOffsets[1].z = 1; - region.dstOffsets[1].x = mainWindow->scissor.extent.width; - region.dstOffsets[1].y = mainWindow->scissor.extent.height; - region.dstOffsets[1].z = 1; - - vkCmdBlitImage(cmd, img.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL, 1, - ®ion, VK_FILTER_LINEAR); + blitToSwap(cmd, img.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL); FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); diff --git a/util/test/demos/vk/vk_shader_editing.cpp b/util/test/demos/vk/vk_shader_editing.cpp index 350dc8ed4..7aa24ca01 100644 --- a/util/test/demos/vk/vk_shader_editing.cpp +++ b/util/test/demos/vk/vk_shader_editing.cpp @@ -158,20 +158,7 @@ void main() VK_IMAGE_LAYOUT_GENERAL, img.image), }); - VkImageBlit region = {}; - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.srcSubresource.layerCount = 1; - region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.dstSubresource.layerCount = 1; - region.srcOffsets[1].x = mainWindow->scissor.extent.width; - region.srcOffsets[1].y = mainWindow->scissor.extent.height; - region.srcOffsets[1].z = 1; - region.dstOffsets[1].x = mainWindow->scissor.extent.width; - region.dstOffsets[1].y = mainWindow->scissor.extent.height; - region.dstOffsets[1].z = 1; - - vkCmdBlitImage(cmd, img.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL, 1, - ®ion, VK_FILTER_LINEAR); + blitToSwap(cmd, img.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL); FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); diff --git a/util/test/demos/vk/vk_texture_zoo.cpp b/util/test/demos/vk/vk_texture_zoo.cpp index 84c453b8b..7d919bc96 100644 --- a/util/test/demos/vk/vk_texture_zoo.cpp +++ b/util/test/demos/vk/vk_texture_zoo.cpp @@ -1464,17 +1464,7 @@ void main() vkCmdEndRenderPass(cmd); - VkImageBlit region = {}; - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.srcSubresource.layerCount = 1; - region.dstSubresource = region.srcSubresource; - region.srcOffsets[1].x = mainWindow->scissor.extent.width; - region.srcOffsets[1].y = mainWindow->scissor.extent.height; - region.srcOffsets[1].z = 1; - region.dstOffsets[1] = region.srcOffsets[1]; - - vkCmdBlitImage(cmd, fltTex.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, swapimg, - VK_IMAGE_LAYOUT_GENERAL, 1, ®ion, VK_FILTER_LINEAR); + blitToSwap(cmd, fltTex.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL); FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); diff --git a/util/test/rdtest/__init__.py b/util/test/rdtest/__init__.py index 1d2cbcdb7..236612c04 100644 --- a/util/test/rdtest/__init__.py +++ b/util/test/rdtest/__init__.py @@ -7,3 +7,4 @@ from .shared.Texture_Zoo import * from .shared.Mesh_Zoo import * from .shared.Draw_Zoo import * from .shared.Overlay_Test import * +from .shared.Buffer_Truncation import * diff --git a/util/test/rdtest/analyse.py b/util/test/rdtest/analyse.py index 1dada4667..7ecd64e2c 100644 --- a/util/test/rdtest/analyse.py +++ b/util/test/rdtest/analyse.py @@ -56,32 +56,52 @@ def open_capture(filename="", cap: rd.CaptureFile=None, opts: rd.ReplayOptions=N def fetch_indices(controller: rd.ReplayController, draw: rd.DrawcallDescription, mesh: rd.MeshFormat, index_offset: int, first_index: int, num_indices: int): - # Get the character for the width of index - index_fmt = 'B' - if mesh.indexByteStride == 2: - index_fmt = 'H' - elif mesh.indexByteStride == 4: - index_fmt = 'I' pipe = controller.GetPipelineState() restart_idx = pipe.GetStripRestartIndex() & ((1 << (mesh.indexByteStride*8)) - 1) restart_enabled = pipe.IsStripRestartEnabled() and rd.IsStrip(draw.topology) - # Duplicate the format by the number of indices - index_fmt = '=' + str(num_indices) + index_fmt - # If we have an index buffer if mesh.indexResourceId != rd.ResourceId.Null(): + offset = mesh.indexByteStride*(first_index + index_offset) + + avail_bytes = mesh.indexByteSize + if avail_bytes > offset: + avail_bytes = avail_bytes - offset + else: + avail_bytes = 0 + + read_bytes = min([avail_bytes, mesh.indexByteStride*num_indices]) + # Fetch the data - ibdata = controller.GetBufferData(mesh.indexResourceId, - mesh.indexByteOffset + mesh.indexByteStride*(first_index + index_offset), - mesh.indexByteStride*num_indices) + if read_bytes > 0: + ibdata = controller.GetBufferData(mesh.indexResourceId, + mesh.indexByteOffset + offset, + read_bytes) + else: + ibdata = bytes() + + # Get the character for the width of index + index_fmt = 'B' + if mesh.indexByteStride == 2: + index_fmt = 'H' + elif mesh.indexByteStride == 4: + index_fmt = 'I' + + avail_indices = int(len(ibdata) / mesh.indexByteStride) + + # Duplicate the format by the number of indices + index_fmt = '=' + str(min([avail_indices, num_indices])) + index_fmt # Unpack all the indices indices = struct.unpack_from(index_fmt, ibdata) + extra = [] + if avail_indices < num_indices: + extra = [None] * (num_indices - avail_indices) + # Apply the baseVertex offset - return [i if restart_enabled and i == restart_idx else i + mesh.baseVertex for i in indices] + return [i if restart_enabled and i == restart_idx else i + mesh.baseVertex for i in indices] + extra else: # With no index buffer, just generate a range return tuple(range(first_index, first_index + num_indices)) @@ -107,11 +127,14 @@ def get_vsin_attrs(controller: rd.ReplayController, vertexOffset: int, index_mes attr.name = a.name attr.mesh = rd.MeshFormat(index_mesh) + offs = a.byteOffset + vertexOffset * attr.mesh.vertexByteStride + attr.mesh.vertexByteStride = vbs[a.vertexBuffer].byteStride attr.mesh.instStepRate = a.instanceRate attr.mesh.instanced = a.perInstance attr.mesh.vertexResourceId = vbs[a.vertexBuffer].resourceId - attr.mesh.vertexByteOffset = vbs[a.vertexBuffer].byteOffset + a.byteOffset + vertexOffset * attr.mesh.vertexByteStride + attr.mesh.vertexByteOffset = vbs[a.vertexBuffer].byteOffset + offs + attr.mesh.vertexByteSize = max([0, vbs[a.vertexBuffer].byteSize - offs]) attr.mesh.format = a.format @@ -205,6 +228,9 @@ def unpack_data(fmt: rd.ResourceFormat, data: bytes, data_offset: int): # We need to fetch compCount components vertex_format = '=' + str(fmt.compCount) + format_chars[fmt.compType][fmt.compByteWidth] + if data_offset >= len(data): + return None + # Unpack the data try: value = struct.unpack_from(vertex_format, data, data_offset) @@ -231,9 +257,29 @@ def unpack_data(fmt: rd.ResourceFormat, data: bytes, data_offset: int): def decode_mesh_data(controller: rd.ReplayController, indices: List[int], display_indices: List[int], attrs: List[MeshAttribute], instance: int = 0, indexOffset: int = 0): - buffer_cache = {} ret = [] + buffer_ranges = {} + for attr in attrs: + begin = attr.mesh.vertexByteOffset + end = min(begin + attr.mesh.vertexByteSize, 0xffffffffffffffff) + + # This could be more optimal if we figure out the lower/upper bounds of any attribute and only fetch the + # data we need. For each referenced buffer, pick the attribute that references the largest range and fetch that + if attr.mesh.vertexResourceId in buffer_ranges: + buf_range = buffer_ranges[attr.mesh.vertexResourceId] + + if buf_range[0] < begin: + begin = buf_range[0] + if buf_range[1] > end: + end = buf_range[1] + + buffer_ranges[attr.mesh.vertexResourceId] = (begin, end) + + buffer_data = {} + for buf, buf_range in buffer_ranges.items(): + buffer_data[buf] = controller.GetBufferData(buf, buf_range[0], buf_range[1] - buf_range[0]) + # Calculate the strip restart index for this index width striprestart_index = None if controller.GetPipelineState().IsStripRestartEnabled() and attrs[0].mesh.indexResourceId != rd.ResourceId.Null(): @@ -245,18 +291,19 @@ def decode_mesh_data(controller: rd.ReplayController, indices: List[int], displa if striprestart_index is None or idx != striprestart_index: for attr in attrs: - offset = attr.mesh.vertexByteOffset + attr.mesh.vertexByteStride * idx + if idx is None: + vertex[attr.name] = None + continue + + offset = attr.mesh.vertexByteStride * idx if attr.mesh.instanced: offset = (attr.mesh.vertexByteStride + attr.mesh.vertexByteStride * int(instance / max(attr.mesh.instStepRate, 1))) - # This could be more optimal if we figure out the lower/upper bounds of any attribute and only fetch the - # data we need. - if attr.mesh.vertexResourceId not in buffer_cache: - buffer_cache[attr.mesh.vertexResourceId] = controller.GetBufferData(attr.mesh.vertexResourceId, 0, 0) - - vertex[attr.name] = unpack_data(attr.mesh.format, buffer_cache[attr.mesh.vertexResourceId], offset) + vertex[attr.name] = unpack_data(attr.mesh.format, buffer_data[attr.mesh.vertexResourceId], + attr.mesh.vertexByteOffset + offset - + buffer_ranges[attr.mesh.vertexResourceId][0]) ret.append(vertex) diff --git a/util/test/rdtest/shared/Buffer_Truncation.py b/util/test/rdtest/shared/Buffer_Truncation.py new file mode 100644 index 000000000..4326fa92d --- /dev/null +++ b/util/test/rdtest/shared/Buffer_Truncation.py @@ -0,0 +1,161 @@ +import renderdoc as rd +import rdtest +from typing import List, Tuple +import time +import os + + +# Not a direct test, re-used by API-specific tests +class Buffer_Truncation(rdtest.TestCase): + internal = True + + def check_capture(self): + draw = self.find_draw("Draw") + + self.check(draw is not None) + + self.controller.SetFrameEvent(draw.eventId, False) + + vsin_ref = { + 0: { + 'vtx': 0, + 'idx': 1, + 'POSITION': [-0.5, -0.5, 0.0], + 'COLOR': [0.0, 1.0, 0.0, 1.0], + }, + 1: { + 'vtx': 1, + 'idx': 2, + 'POSITION': [0.0, 0.5, 0.0], + 'COLOR': [0.0, 1.0, 0.0, 1.0], + }, + 2: { + 'vtx': 2, + 'idx': 3, + 'POSITION': [0.5, -0.5, 0.0], + 'COLOR': [0.0, 1.0, 0.0, 1.0], + }, + 3: { + 'vtx': 3, + 'idx': 4, + 'POSITION': [8.8, 0.0, 0.0], + 'COLOR': [0.0, 0.0, 0.0, 1.0], + }, + 4: { + 'vtx': 4, + 'idx': 5, + 'POSITION': None, + 'COLOR': None, + }, + 5: { + 'vtx': 5, + 'idx': None, + 'POSITION': None, + 'COLOR': None, + }, + } + + self.check_mesh_data(vsin_ref, self.get_vsin(draw)) + + postvs_data = self.get_postvs(draw, rd.MeshDataStage.VSOut, 0, draw.numIndices) + + postvs_ref = { + 0: { + 'vtx': 0, + 'idx': 1, + 'OUTPOSITION': [-0.5, -0.5, 0.0, 1.0], + 'OUTCOLOR': [0.0, 1.0, 0.0, 1.0], + }, + 1: { + 'vtx': 1, + 'idx': 2, + 'OUTPOSITION': [0.0, 0.5, 0.0, 1.0], + 'OUTCOLOR': [0.0, 1.0, 0.0, 1.0], + }, + 2: { + 'vtx': 2, + 'idx': 3, + 'OUTPOSITION': [0.5, -0.5, 0.0, 1.0], + 'OUTCOLOR': [0.0, 1.0, 0.0, 1.0], + }, + 3: { + 'vtx': 3, + 'idx': 4, + 'OUTPOSITION': [8.8, 0.0, 0.0, 1.0], + 'OUTCOLOR': [0.0, 0.0, 0.0, 1.0], + }, + 4: { + 'vtx': 4, + 'idx': 5, + # don't rely on any particular OOB behaviour for postvs, as this may come from the driver/API + }, + 5: { + 'vtx': 5, + 'idx': None, + # don't rely on any particular OOB behaviour for postvs, as this may come from the driver/API + }, + } + + self.check_mesh_data(postvs_ref, postvs_data) + + rdtest.log.success("vertex/index buffers were truncated as expected") + + pipe: rd.PipeState = self.controller.GetPipelineState() + + stage = rd.ShaderStage.Pixel + + cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 0, 0) + + if self.find_draw('NoCBufferRange') == None: + self.check(cbuf.byteSize == 256) + + variables = self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(), + pipe.GetShader(stage), + pipe.GetShaderEntryPoint(stage), 0, + cbuf.resourceId, cbuf.byteOffset, cbuf.byteSize) + + outcol: rd.ShaderVariable = variables[1] + + self.check(outcol.name == "outcol") + if not rdtest.value_compare(outcol.value.fv[0:4], [0.0, 0.0, 0.0, 0.0]): + raise rdtest.TestFailureException("expected outcol to be 0s, but got {}".format(outcol.value.fv[0:4])) + + if self.controller.GetAPIProperties().shaderDebugging: + # Debug the shader + trace: rd.ShaderDebugTrace = self.controller.DebugPixel(int(pipe.GetViewport(0).width/2), + int(pipe.GetViewport(0).height/2), + rd.ReplayController.NoPreference, + rd.ReplayController.NoPreference) + + if trace.debugger is None: + self.controller.FreeTrace(trace) + raise rdtest.TestFailureException("Shader did not debug at all") + else: + cycles, variables = self.process_trace(trace) + + cbuf_sourceVars = [s for s in trace.sourceVars if s.variables[0].type == rd.DebugVariableType.Constant and s.rows > 0] + + # Vulkan style, one source var for the cbuffer + if len(cbuf_sourceVars) == 1: + debugged_cb = trace.constantBlocks[0] + + self.check(debugged_cb.members[0].name == 'padding') + self.check(debugged_cb.members[1].name == 'outcol') + + if not rdtest.value_compare(debugged_cb.members[1].value.fv[0:4], [0.0, 0.0, 0.0, 0.0]): + raise rdtest.TestFailureException("expected outcol to be 0s, but got {}".format(debugged_cb.members[1].value.fv[0:4])) + # D3D style, one source var for each member mapping to a register + elif len(cbuf_sourceVars) == 17: + debugged_cb = trace.constantBlocks[0].members[16] + + self.check(all(['consts.padding[' in c.name for c in cbuf_sourceVars[0:16]])) + self.check(cbuf_sourceVars[16].name == 'consts.outcol') + + self.check(cbuf_sourceVars[16].variables[0].name == 'cb0[16]') + + if not rdtest.value_compare(debugged_cb.value.fv[0:4], [0.0, 0.0, 0.0, 0.0]): + raise rdtest.TestFailureException("expected outcol to be 0s, but got {}".format(debugged_cb.members[1].value.fv[0:4])) + else: + raise rdtest.TestFailureException("Unexpected number of constant buffer source vars {}".format(len(cbuf_sourceVars))) + + rdtest.log.success("CBuffer value was truncated as expected") diff --git a/util/test/rdtest/testcase.py b/util/test/rdtest/testcase.py index ddb8754f8..240aecee4 100644 --- a/util/test/rdtest/testcase.py +++ b/util/test/rdtest/testcase.py @@ -259,13 +259,20 @@ class TestCase: else: num_indices = min(num_indices, draw.numIndices) + ioffs = draw.indexOffset * draw.indexByteWidth + mesh = rd.MeshFormat() mesh.numIndices = num_indices - mesh.indexByteOffset = ib.byteOffset + draw.indexOffset * draw.indexByteWidth + mesh.indexByteOffset = ib.byteOffset + ioffs mesh.indexByteStride = draw.indexByteWidth mesh.indexResourceId = ib.resourceId mesh.baseVertex = draw.baseVertex + if ib.byteSize > ioffs: + mesh.indexByteSize = ib.byteSize - ioffs + else: + mesh.indexByteSize = 0 + if not (draw.flags & rd.DrawFlags.Indexed): mesh.indexByteOffset = 0 mesh.indexByteStride = 0 @@ -295,13 +302,20 @@ class TestCase: ib: rd.BoundVBuffer = self.controller.GetPipelineState().GetIBuffer() + ioffs = draw.indexOffset * draw.indexByteWidth + in_mesh = rd.MeshFormat() in_mesh.numIndices = num_indices - in_mesh.indexByteOffset = ib.byteOffset + draw.indexOffset * draw.indexByteWidth + in_mesh.indexByteOffset = ib.byteOffset + ioffs in_mesh.indexByteStride = draw.indexByteWidth in_mesh.indexResourceId = ib.resourceId in_mesh.baseVertex = draw.baseVertex + if ib.byteSize > ioffs: + in_mesh.indexByteSize = ib.byteSize - ioffs + else: + in_mesh.indexByteSize = 0 + if not (draw.flags & rd.DrawFlags.Indexed): in_mesh.indexByteOffset = 0 in_mesh.indexByteStride = 0 diff --git a/util/test/tests/D3D11/D3D11_Buffer_Truncation.py b/util/test/tests/D3D11/D3D11_Buffer_Truncation.py new file mode 100644 index 000000000..cb0d42a75 --- /dev/null +++ b/util/test/tests/D3D11/D3D11_Buffer_Truncation.py @@ -0,0 +1,7 @@ +import rdtest +import renderdoc as rd + + +class D3D11_Buffer_Truncation(rdtest.Buffer_Truncation): + demos_test_name = 'D3D11_Buffer_Truncation' + internal = False \ No newline at end of file diff --git a/util/test/tests/D3D12/D3D12_Buffer_Truncation.py b/util/test/tests/D3D12/D3D12_Buffer_Truncation.py new file mode 100644 index 000000000..e3adf8f86 --- /dev/null +++ b/util/test/tests/D3D12/D3D12_Buffer_Truncation.py @@ -0,0 +1,7 @@ +import rdtest +import renderdoc as rd + + +class D3D12_Buffer_Truncation(rdtest.Buffer_Truncation): + demos_test_name = 'D3D12_Buffer_Truncation' + internal = False \ No newline at end of file diff --git a/util/test/tests/GL/GL_Buffer_Truncation.py b/util/test/tests/GL/GL_Buffer_Truncation.py new file mode 100644 index 000000000..a1cd9c36c --- /dev/null +++ b/util/test/tests/GL/GL_Buffer_Truncation.py @@ -0,0 +1,7 @@ +import rdtest +import renderdoc as rd + + +class GL_Buffer_Truncation(rdtest.Buffer_Truncation): + demos_test_name = 'GL_Buffer_Truncation' + internal = False \ No newline at end of file diff --git a/util/test/tests/Vulkan/VK_Buffer_Truncation.py b/util/test/tests/Vulkan/VK_Buffer_Truncation.py new file mode 100644 index 000000000..a1613e61e --- /dev/null +++ b/util/test/tests/Vulkan/VK_Buffer_Truncation.py @@ -0,0 +1,7 @@ +import rdtest +import renderdoc as rd + + +class VK_Buffer_Truncation(rdtest.Buffer_Truncation): + demos_test_name = 'VK_Buffer_Truncation' + internal = False \ No newline at end of file diff --git a/util/test/tests/Vulkan/VK_Truncated_CBuffer.py b/util/test/tests/Vulkan/VK_Truncated_CBuffer.py deleted file mode 100644 index 44461b721..000000000 --- a/util/test/tests/Vulkan/VK_Truncated_CBuffer.py +++ /dev/null @@ -1,32 +0,0 @@ -import rdtest -import renderdoc as rd - - -class VK_Truncated_CBuffer(rdtest.TestCase): - demos_test_name = 'VK_Truncated_CBuffer' - - def check_capture(self): - draw = self.find_draw("Draw") - - self.check(draw is not None) - - self.controller.SetFrameEvent(draw.eventId, False) - - pipe: rd.PipeState = self.controller.GetPipelineState() - - stage = rd.ShaderStage.Pixel - - cbuf: rd.BoundCBuffer = pipe.GetConstantBuffer(stage, 0, 0) - - variables = self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(), - pipe.GetShader(stage), - pipe.GetShaderEntryPoint(stage), 0, - cbuf.resourceId, cbuf.byteOffset, cbuf.byteSize) - - outcol: rd.ShaderVariable = variables[1] - - self.check(outcol.name == "outcol") - if not rdtest.value_compare(outcol.value.fv[0:4], [0.0, 0.0, 0.0, 0.0]): - raise rdtest.TestFailureException("expected outcol to be 0s, but got {}".format(outcol.value.fv[0:4])) - - rdtest.log.success("CBuffer value was truncated as expected")