From 69dcb42a050f55cc50a9c24173b32ffe1a1f3a52 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 25 Aug 2023 16:17:13 +0100 Subject: [PATCH] Add enums and API-agnostic handling for new task and mesh shader stages * The enums are given after compute, to preserve indices for the normal vertex pipeline. * Mesh dispatches are considered a new action type, rather than being bundled into the `Drawcall` type. This will allow them to be distinguished by API backends as needed. The UI treats them as drawcalls * We apply this universally even though it's not relevant to D3D11/GL. It means a couple of empty array entries but it should not cause any significant issues. * Shader messages will be identified by group and thread as with compute shaders. For mesh shaders there is an additional subdivision to identify them by task group, since each task group can submit a grid of mesh groups. --- docs/python_api/renderdoc/outputs.rst | 8 +- .../python_api/renderdoc/pipelines/common.rst | 3 + qrenderdoc/Code/CaptureContext.cpp | 5 +- .../Code/Interface/ShaderProcessingTool.cpp | 5 +- qrenderdoc/Code/QRDUtils.cpp | 104 ++++---- qrenderdoc/Code/pyrenderdoc/renderdoc.i | 2 + qrenderdoc/Windows/BufferViewer.cpp | 226 +++++++++-------- .../PipelineState/PipelineStateViewer.h | 2 +- qrenderdoc/Windows/ShaderMessageViewer.cpp | 227 +++++++++++++++++- qrenderdoc/Windows/ShaderMessageViewer.h | 5 +- qrenderdoc/Windows/ShaderMessageViewer.ui | 20 ++ qrenderdoc/Windows/ShaderViewer.cpp | 2 + qrenderdoc/Windows/StatisticsViewer.cpp | 2 +- qrenderdoc/Windows/TextureViewer.cpp | 11 +- qrenderdoc/Windows/TextureViewer.h | 4 +- renderdoc/api/replay/common_pipestate.h | 74 +++++- renderdoc/api/replay/control_types.h | 103 +++++++- renderdoc/api/replay/d3d12_pipestate.h | 10 + renderdoc/api/replay/pipestate.h | 4 + renderdoc/api/replay/pipestate.inl | 108 +++++++++ renderdoc/api/replay/renderdoc_tostr.inl | 11 +- renderdoc/api/replay/replay_enums.h | 145 +++++++++-- renderdoc/api/replay/shader_types.h | 24 +- renderdoc/api/replay/vk_pipestate.h | 12 + renderdoc/core/replay_proxy.cpp | 12 +- renderdoc/driver/d3d11/d3d11_context.cpp | 2 +- renderdoc/driver/d3d11/d3d11_renderstate.cpp | 8 +- renderdoc/driver/d3d11/d3d11_replay.cpp | 2 +- renderdoc/driver/d3d12/d3d12_commands.cpp | 2 +- renderdoc/driver/d3d12/d3d12_device.h | 7 +- renderdoc/driver/d3d12/d3d12_postvs.cpp | 3 - renderdoc/driver/d3d12/d3d12_replay.h | 8 +- .../driver/d3d12/d3d12_shader_feedback.cpp | 2 +- renderdoc/driver/gl/gl_common.h | 4 +- renderdoc/driver/gl/gl_driver.cpp | 12 +- renderdoc/driver/gl/gl_driver.h | 6 +- renderdoc/driver/gl/gl_initstate.h | 2 + renderdoc/driver/gl/gl_pixelhistory.cpp | 17 +- renderdoc/driver/gl/gl_program_iterate.cpp | 8 +- renderdoc/driver/gl/gl_renderstate.h | 2 + renderdoc/driver/gl/gl_replay.cpp | 21 +- .../driver/gl/wrappers/gl_shader_funcs.cpp | 12 +- renderdoc/driver/ihv/amd/amd_isa.cpp | 10 + renderdoc/driver/ihv/nv/nv_vk_counters.cpp | 5 +- .../driver/shaders/dxbc/dxbc_container.cpp | 2 +- renderdoc/driver/shaders/dxbc/dxbc_debug.cpp | 3 +- .../driver/shaders/dxbc/dxbc_reflect.cpp | 2 + .../driver/shaders/spirv/spirv_common.cpp | 8 +- .../driver/shaders/spirv/spirv_compile.cpp | 4 +- .../driver/shaders/spirv/spirv_compile.h | 3 + .../driver/shaders/spirv/spirv_reflect.cpp | 89 ++++++- .../driver/shaders/spirv/spirv_reflect.h | 3 + renderdoc/driver/vulkan/vk_debug.cpp | 30 ++- renderdoc/driver/vulkan/vk_info.h | 2 +- renderdoc/driver/vulkan/vk_overlay.cpp | 2 + renderdoc/driver/vulkan/vk_postvs.cpp | 2 - renderdoc/driver/vulkan/vk_replay.cpp | 4 +- renderdoc/driver/vulkan/vk_replay.h | 12 +- renderdoc/driver/vulkan/vk_shader_cache.cpp | 8 +- .../driver/vulkan/vk_shader_feedback.cpp | 10 +- .../vulkan/wrappers/vk_shader_funcs.cpp | 2 +- renderdoc/replay/renderdoc_serialise.inl | 56 ++++- renderdoc/replay/replay_controller.cpp | 16 +- renderdoc/replay/replay_output.cpp | 16 +- 64 files changed, 1236 insertions(+), 300 deletions(-) diff --git a/docs/python_api/renderdoc/outputs.rst b/docs/python_api/renderdoc/outputs.rst index 7ba929596..07b209c1c 100644 --- a/docs/python_api/renderdoc/outputs.rst +++ b/docs/python_api/renderdoc/outputs.rst @@ -52,6 +52,12 @@ Mesh View .. autoclass:: MeshDataStage :members: +.. autoclass:: MeshletSize + :members: + +.. autoclass:: TaskGroupSize + :members: + .. autoclass:: MeshFormat :members: @@ -67,4 +73,4 @@ Mesh View .. autoclass:: AxisMapping :members: -.. autofunction:: renderdoc.InitCamera \ No newline at end of file +.. autofunction:: renderdoc.InitCamera diff --git a/docs/python_api/renderdoc/pipelines/common.rst b/docs/python_api/renderdoc/pipelines/common.rst index be896362b..1cc1f7bdd 100644 --- a/docs/python_api/renderdoc/pipelines/common.rst +++ b/docs/python_api/renderdoc/pipelines/common.rst @@ -147,6 +147,9 @@ Shader Messages .. autoclass:: renderdoc.ShaderMessageLocation :members: +.. autoclass:: renderdoc.ShaderMeshMessageLocation + :members: + .. autoclass:: renderdoc.ShaderVertexMessageLocation :members: diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index 90ccf0e70..eb1aabdea 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -1701,8 +1701,9 @@ void CaptureContext::RefreshUIStatus(const rdcarray &exclude, bool updateSelectedEvent, bool updateEvent) { // cache and assign pointer type IDs for any known pointer types in current shaders - for(ShaderStage stage : {ShaderStage::Vertex, ShaderStage::Hull, ShaderStage::Domain, - ShaderStage::Geometry, ShaderStage::Pixel, ShaderStage::Compute}) + for(ShaderStage stage : + {ShaderStage::Vertex, ShaderStage::Hull, ShaderStage::Domain, ShaderStage::Geometry, + ShaderStage::Pixel, ShaderStage::Compute, ShaderStage::Task, ShaderStage::Mesh}) { const ShaderReflection *refl = m_CurPipelineState->GetShaderReflection(stage); if(refl) diff --git a/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp b/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp index 4bd4684b2..b396fae87 100644 --- a/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp +++ b/qrenderdoc/Code/Interface/ShaderProcessingTool.cpp @@ -29,11 +29,12 @@ #include "QRDInterface.h" static const QString glsl_stage4[arraydim()] = { - lit("vert"), lit("tesc"), lit("tese"), lit("geom"), lit("frag"), lit("comp"), + lit("vert"), lit("tesc"), lit("tese"), lit("geom"), + lit("frag"), lit("comp"), lit("task"), lit("mesh"), }; static const QString hlsl_stage2[arraydim()] = { - lit("vs"), lit("hs"), lit("ds"), lit("gs"), lit("ps"), lit("cs"), + lit("vs"), lit("hs"), lit("ds"), lit("gs"), lit("ps"), lit("cs"), lit("as"), lit("ms"), }; static QString tmpPath(const QString &filename) diff --git a/qrenderdoc/Code/QRDUtils.cpp b/qrenderdoc/Code/QRDUtils.cpp index d271a5f8b..a6a7b2a63 100644 --- a/qrenderdoc/Code/QRDUtils.cpp +++ b/qrenderdoc/Code/QRDUtils.cpp @@ -1378,31 +1378,37 @@ QString ToQStr(const ResourceUsage usage, const GraphicsAPI apitype) case ResourceUsage::VertexBuffer: return lit("Vertex Buffer"); case ResourceUsage::IndexBuffer: return lit("Index Buffer"); - case ResourceUsage::VS_Constants: return lit("VS - Uniform Buffer"); - case ResourceUsage::GS_Constants: return lit("GS - Uniform Buffer"); - case ResourceUsage::HS_Constants: return lit("HS - Uniform Buffer"); - case ResourceUsage::DS_Constants: return lit("DS - Uniform Buffer"); - case ResourceUsage::CS_Constants: return lit("CS - Uniform Buffer"); - case ResourceUsage::PS_Constants: return lit("PS - Uniform Buffer"); - case ResourceUsage::All_Constants: return lit("All - Uniform Buffer"); + case ResourceUsage::VS_Constants: return lit("VS - Constant Buffer"); + case ResourceUsage::GS_Constants: return lit("GS - Constant Buffer"); + case ResourceUsage::HS_Constants: return lit("TCS - Constant Buffer"); + case ResourceUsage::DS_Constants: return lit("TES - Constant Buffer"); + case ResourceUsage::PS_Constants: return lit("FS - Constant Buffer"); + case ResourceUsage::CS_Constants: return lit("CS - Constant Buffer"); + case ResourceUsage::TS_Constants: return lit("TS - Constant Buffer"); + case ResourceUsage::MS_Constants: return lit("MS - Constant Buffer"); + case ResourceUsage::All_Constants: return lit("All - Constant Buffer"); case ResourceUsage::StreamOut: return lit("Stream Out"); - case ResourceUsage::VS_Resource: return lit("VS - Texture"); - case ResourceUsage::GS_Resource: return lit("GS - Texture"); - case ResourceUsage::HS_Resource: return lit("HS - Texture"); - case ResourceUsage::DS_Resource: return lit("DS - Texture"); - case ResourceUsage::CS_Resource: return lit("CS - Texture"); - case ResourceUsage::PS_Resource: return lit("PS - Texture"); - case ResourceUsage::All_Resource: return lit("All - Texture"); + case ResourceUsage::VS_Resource: return lit("VS - Resource"); + case ResourceUsage::GS_Resource: return lit("GS - Resource"); + case ResourceUsage::HS_Resource: return lit("TCS - Resource"); + case ResourceUsage::DS_Resource: return lit("TES - Resource"); + case ResourceUsage::PS_Resource: return lit("FS - Resource"); + case ResourceUsage::CS_Resource: return lit("CS - Resource"); + case ResourceUsage::TS_Resource: return lit("TS - Resource"); + case ResourceUsage::MS_Resource: return lit("MS - Resource"); + case ResourceUsage::All_Resource: return lit("All - Resource"); - case ResourceUsage::VS_RWResource: return lit("VS - Image/SSBO"); - case ResourceUsage::HS_RWResource: return lit("HS - Image/SSBO"); - case ResourceUsage::DS_RWResource: return lit("DS - Image/SSBO"); - case ResourceUsage::GS_RWResource: return lit("GS - Image/SSBO"); - case ResourceUsage::PS_RWResource: return lit("PS - Image/SSBO"); - case ResourceUsage::CS_RWResource: return lit("CS - Image/SSBO"); - case ResourceUsage::All_RWResource: return lit("All - Image/SSBO"); + case ResourceUsage::VS_RWResource: return lit("VS - UAV"); + case ResourceUsage::HS_RWResource: return lit("TCS - UAV"); + case ResourceUsage::DS_RWResource: return lit("TES - UAV"); + case ResourceUsage::GS_RWResource: return lit("GS - UAV"); + case ResourceUsage::PS_RWResource: return lit("FS - UAV"); + case ResourceUsage::CS_RWResource: return lit("CS - UAV"); + case ResourceUsage::TS_RWResource: return lit("TS - UAV"); + case ResourceUsage::MS_RWResource: return lit("MS - UAV"); + case ResourceUsage::All_RWResource: return lit("All - UAV"); case ResourceUsage::InputTarget: return lit("Color Input"); case ResourceUsage::ColorTarget: return lit("Rendertarget"); @@ -1437,31 +1443,37 @@ QString ToQStr(const ResourceUsage usage, const GraphicsAPI apitype) case ResourceUsage::VertexBuffer: return lit("Vertex Buffer"); case ResourceUsage::IndexBuffer: return lit("Index Buffer"); - case ResourceUsage::VS_Constants: return lit("VS - Constant Buffer"); - case ResourceUsage::GS_Constants: return lit("GS - Constant Buffer"); - case ResourceUsage::HS_Constants: return lit("TCS - Constant Buffer"); - case ResourceUsage::DS_Constants: return lit("TES - Constant Buffer"); - case ResourceUsage::CS_Constants: return lit("CS - Constant Buffer"); - case ResourceUsage::PS_Constants: return lit("FS - Constant Buffer"); - case ResourceUsage::All_Constants: return lit("All - Constant Buffer"); + case ResourceUsage::VS_Constants: return lit("VS - Uniform Buffer"); + case ResourceUsage::GS_Constants: return lit("GS - Uniform Buffer"); + case ResourceUsage::HS_Constants: return lit("HS - Uniform Buffer"); + case ResourceUsage::DS_Constants: return lit("DS - Uniform Buffer"); + case ResourceUsage::PS_Constants: return lit("PS - Uniform Buffer"); + case ResourceUsage::CS_Constants: return lit("CS - Uniform Buffer"); + case ResourceUsage::TS_Constants: return lit("TS - Uniform Buffer"); + case ResourceUsage::MS_Constants: return lit("MS - Uniform Buffer"); + case ResourceUsage::All_Constants: return lit("All - Uniform Buffer"); case ResourceUsage::StreamOut: return lit("Transform Feedback"); - case ResourceUsage::VS_Resource: return lit("VS - Resource"); - case ResourceUsage::GS_Resource: return lit("GS - Resource"); - case ResourceUsage::HS_Resource: return lit("TCS - Resource"); - case ResourceUsage::DS_Resource: return lit("TES - Resource"); - case ResourceUsage::CS_Resource: return lit("CS - Resource"); - case ResourceUsage::PS_Resource: return lit("FS - Resource"); - case ResourceUsage::All_Resource: return lit("All - Resource"); + case ResourceUsage::VS_Resource: return lit("VS - Texture"); + case ResourceUsage::GS_Resource: return lit("GS - Texture"); + case ResourceUsage::HS_Resource: return lit("HS - Texture"); + case ResourceUsage::DS_Resource: return lit("DS - Texture"); + case ResourceUsage::PS_Resource: return lit("PS - Texture"); + case ResourceUsage::CS_Resource: return lit("CS - Texture"); + case ResourceUsage::TS_Resource: return lit("TS - Texture"); + case ResourceUsage::MS_Resource: return lit("MS - Texture"); + case ResourceUsage::All_Resource: return lit("All - Texture"); - case ResourceUsage::VS_RWResource: return lit("VS - UAV"); - case ResourceUsage::HS_RWResource: return lit("TCS - UAV"); - case ResourceUsage::DS_RWResource: return lit("TES - UAV"); - case ResourceUsage::GS_RWResource: return lit("GS - UAV"); - case ResourceUsage::PS_RWResource: return lit("FS - UAV"); - case ResourceUsage::CS_RWResource: return lit("CS - UAV"); - case ResourceUsage::All_RWResource: return lit("All - UAV"); + case ResourceUsage::VS_RWResource: return lit("VS - Image/SSBO"); + case ResourceUsage::HS_RWResource: return lit("HS - Image/SSBO"); + case ResourceUsage::DS_RWResource: return lit("DS - Image/SSBO"); + case ResourceUsage::GS_RWResource: return lit("GS - Image/SSBO"); + case ResourceUsage::PS_RWResource: return lit("PS - Image/SSBO"); + case ResourceUsage::CS_RWResource: return lit("CS - Image/SSBO"); + case ResourceUsage::TS_RWResource: return lit("TS - Image/SSBO"); + case ResourceUsage::MS_RWResource: return lit("MS - Image/SSBO"); + case ResourceUsage::All_RWResource: return lit("All - Image/SSBO"); case ResourceUsage::InputTarget: return lit("FB Input"); case ResourceUsage::ColorTarget: return lit("FB Color"); @@ -1503,6 +1515,8 @@ QString ToQStr(const ShaderStage stage, const GraphicsAPI apitype) case ShaderStage::Geometry: return lit("Geometry"); case ShaderStage::Pixel: return lit("Pixel"); case ShaderStage::Compute: return lit("Compute"); + case ShaderStage::Amplification: return lit("Amplif."); + case ShaderStage::Mesh: return lit("Mesh"); default: break; } } @@ -1516,6 +1530,8 @@ QString ToQStr(const ShaderStage stage, const GraphicsAPI apitype) case ShaderStage::Geometry: return lit("Geometry"); case ShaderStage::Fragment: return lit("Fragment"); case ShaderStage::Compute: return lit("Compute"); + case ShaderStage::Task: return lit("Task"); + case ShaderStage::Mesh: return lit("Mesh"); default: break; } } @@ -1636,6 +1652,7 @@ QString D3DSemanticString(const SigParameter &sig) lit("SV_ShadingRate"), lit("SV_Barycentrics"), lit("SV_CullPrimitive"), + lit("out indices"), }; static_assert(arraydim() == ARRAY_COUNT(sysValues), @@ -1705,7 +1722,8 @@ void CombineUsageEvents(ICaptureContext &ctx, const rdcarray &usage, while(prev != NULL && prev->eventId > end) { - if(!(prev->flags & (ActionFlags::Dispatch | ActionFlags::Drawcall | ActionFlags::CmdList))) + if(!(prev->flags & (ActionFlags::Dispatch | ActionFlags::MeshDispatch | + ActionFlags::Drawcall | ActionFlags::CmdList))) { prev = prev->previous; } diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index 67831228e..97da4a1cd 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -370,6 +370,8 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, EnvironmentModification) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, EventUsage) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, PathEntry) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, PixelModification) +TEMPLATE_ARRAY_INSTANTIATE(rdcarray, TaskGroupSize) +TEMPLATE_ARRAY_INSTANTIATE(rdcarray, MeshletSize) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ResourceDescription) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ResourceId) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, LineColumnInfo) diff --git a/qrenderdoc/Windows/BufferViewer.cpp b/qrenderdoc/Windows/BufferViewer.cpp index c8db1a46e..50c89e402 100644 --- a/qrenderdoc/Windows/BufferViewer.cpp +++ b/qrenderdoc/Windows/BufferViewer.cpp @@ -1473,11 +1473,16 @@ struct PopulateBufferData CBufferData cb; + // {VSIn, VSOut, GSOut} x {primary, secondary} QString highlightNames[6]; - BufferConfiguration vsinConfig, vsoutConfig, gsoutConfig; + bool meshDispatch = false; + BufferConfiguration vsinConfig, vsoutConfig, gsoutConfig; MeshFormat postVS, postGS; + + BufferConfiguration msoutConfig; + MeshFormat postMS; }; struct CalcBoundingBoxData @@ -1564,10 +1569,15 @@ static void ConfigureColumnsForShader(ICaptureContext &ctx, int32_t streamSelect if(sig.stream != (uint32_t)streamSelect) continue; + if(sig.systemValue == ShaderBuiltin::OutputIndices) + continue; + ShaderConstant f; BufferElementProperties p; f.name = !sig.varName.isEmpty() ? sig.varName : sig.semanticIdxName; + if(sig.perPrimitiveRate) + f.name += lit(" (Per-Prim)"); f.type.rows = 1; f.type.columns = sig.compCount; @@ -1624,7 +1634,20 @@ static void ConfigureColumnsForShader(ICaptureContext &ctx, int32_t streamSelect } } -static void ConfigureMeshColumns(ICaptureContext &ctx, PopulateBufferData *bufdata) +static void ConfigureColumnsForMeshPipe(ICaptureContext &ctx, PopulateBufferData *bufdata) +{ + bufdata->vsinConfig.numRows = 0; + bufdata->vsinConfig.unclampedNumRows = 0; + + bufdata->vsinConfig.noVertices = true; + bufdata->vsinConfig.noInstances = true; + + const ShaderReflection *ms = ctx.CurPipelineState().GetShaderReflection(ShaderStage::Mesh); + + ConfigureColumnsForShader(ctx, 0, ms, bufdata->vsoutConfig.columns, bufdata->vsoutConfig.props); +} + +static void ConfigureColumnsForVertexPipe(ICaptureContext &ctx, PopulateBufferData *bufdata) { const ActionDescription *action = ctx.CurAction(); @@ -1634,28 +1657,6 @@ static void ConfigureMeshColumns(ICaptureContext &ctx, PopulateBufferData *bufda bufdata->vsinConfig.noVertices = false; bufdata->vsinConfig.noInstances = false; - if(!action || !(action->flags & ActionFlags::Drawcall)) - { - IEventBrowser *eb = ctx.GetEventBrowser(); - - bufdata->vsinConfig.statusString = bufdata->vsoutConfig.statusString = - bufdata->gsoutConfig.statusString = - lit("No current draw action\nSelected EID @%1 - %2\nEffective EID: @%3 - %4") - .arg(ctx.CurSelectedEvent()) - .arg(QString(eb->GetEventName(ctx.CurSelectedEvent()))) - .arg(ctx.CurEvent()) - .arg(QString(eb->GetEventName(ctx.CurEvent()))); - - ConfigureStatusColumn(bufdata->vsinConfig.columns, bufdata->vsinConfig.props); - ConfigureStatusColumn(bufdata->vsoutConfig.columns, bufdata->vsoutConfig.props); - ConfigureStatusColumn(bufdata->gsoutConfig.columns, bufdata->gsoutConfig.props); - - bufdata->vsinConfig.genericsEnabled.push_back(false); - bufdata->vsinConfig.generics.push_back(PixelValue()); - - return; - } - rdcarray vinputs = ctx.CurPipelineState().GetVertexInputs(); bufdata->vsinConfig.columns.reserve(vinputs.count()); @@ -1696,33 +1697,63 @@ static void ConfigureMeshColumns(ICaptureContext &ctx, PopulateBufferData *bufda bufdata->vsinConfig.props.push_back(p); } - if(action) + bufdata->vsinConfig.numRows = action->numIndices; + bufdata->vsinConfig.unclampedNumRows = 0; + + // calculate an upper bound on the valid number of rows just in case it's an invalid value (e.g. + // 0xdeadbeef) and we want to clamp. + uint32_t numRowsUpperBound = 0; + + if(action->flags & ActionFlags::Indexed) { - bufdata->vsinConfig.numRows = action->numIndices; - bufdata->vsinConfig.unclampedNumRows = 0; + // In an indexed draw we clamp to however many indices are available in the index buffer - // calculate an upper bound on the valid number of rows just in case it's an invalid value (e.g. - // 0xdeadbeef) and we want to clamp. - uint32_t numRowsUpperBound = 0; + BoundVBuffer ib = ctx.CurPipelineState().GetIBuffer(); - if(action->flags & ActionFlags::Indexed) + uint32_t bytesAvailable = ib.byteSize; + + if(bytesAvailable == ~0U) { - // In an indexed draw we clamp to however many indices are available in the index buffer + BufferDescription *buf = ctx.GetBuffer(ib.resourceId); + if(buf) + { + uint64_t offset = ib.byteOffset + action->indexOffset * ib.byteStride; + if(offset > buf->length) + bytesAvailable = 0; + else + bytesAvailable = buf->length - offset; + } + else + { + bytesAvailable = 0; + } + } - BoundVBuffer ib = ctx.CurPipelineState().GetIBuffer(); + // drawing more than this many indices will read off the end of the index buffer - which while + // technically not invalid is certainly not intended, so serves as a good 'upper bound' + numRowsUpperBound = bytesAvailable / qMax(1U, ib.byteStride); + } + else + { + // for a non-indexed draw, we take the largest vertex buffer + rdcarray VBs = ctx.CurPipelineState().GetVBuffers(); - uint32_t bytesAvailable = ib.byteSize; + for(const BoundVBuffer &vb : VBs) + { + if(vb.byteStride == 0) + continue; + + uint32_t bytesAvailable = vb.byteSize; if(bytesAvailable == ~0U) { - BufferDescription *buf = ctx.GetBuffer(ib.resourceId); + BufferDescription *buf = ctx.GetBuffer(vb.resourceId); if(buf) { - uint64_t offset = ib.byteOffset + action->indexOffset * ib.byteStride; - if(offset > buf->length) + if(vb.byteOffset > buf->length) bytesAvailable = 0; else - bytesAvailable = buf->length - offset; + bytesAvailable = buf->length - vb.byteOffset; } else { @@ -1730,61 +1761,28 @@ static void ConfigureMeshColumns(ICaptureContext &ctx, PopulateBufferData *bufda } } - // drawing more than this many indices will read off the end of the index buffer - which while - // technically not invalid is certainly not intended, so serves as a good 'upper bound' - numRowsUpperBound = bytesAvailable / qMax(1U, ib.byteStride); - } - else - { - // for a non-indexed draw, we take the largest vertex buffer - rdcarray VBs = ctx.CurPipelineState().GetVBuffers(); - - for(const BoundVBuffer &vb : VBs) - { - if(vb.byteStride == 0) - continue; - - uint32_t bytesAvailable = vb.byteSize; - - if(bytesAvailable == ~0U) - { - 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. - if(numRowsUpperBound == 0) - numRowsUpperBound = ~0U; + numRowsUpperBound = qMax(numRowsUpperBound, bytesAvailable / qMax(1U, vb.byteStride)); } - // if we have significantly clamped, then set the unclamped number of rows and clamp. - if(numRowsUpperBound != ~0U && numRowsUpperBound + 100 < bufdata->vsinConfig.numRows) - { - bufdata->vsinConfig.unclampedNumRows = bufdata->vsinConfig.numRows; - bufdata->vsinConfig.numRows = numRowsUpperBound + 100; - } + // if there are no vertex buffers we can't clamp. + if(numRowsUpperBound == 0) + numRowsUpperBound = ~0U; + } - if((action->flags & ActionFlags::Drawcall) && action->numIndices == 0) - bufdata->vsinConfig.noVertices = true; + // if we have significantly clamped, then set the unclamped number of rows and clamp. + if(numRowsUpperBound != ~0U && numRowsUpperBound + 100 < bufdata->vsinConfig.numRows) + { + bufdata->vsinConfig.unclampedNumRows = bufdata->vsinConfig.numRows; + bufdata->vsinConfig.numRows = numRowsUpperBound + 100; + } - if((action->flags & ActionFlags::Instanced) && action->numInstances == 0) - { - bufdata->vsinConfig.noInstances = true; - bufdata->vsinConfig.numRows = bufdata->vsinConfig.unclampedNumRows = 0; - } + if((action->flags & ActionFlags::Drawcall) && action->numIndices == 0) + bufdata->vsinConfig.noVertices = true; + + if((action->flags & ActionFlags::Instanced) && action->numInstances == 0) + { + bufdata->vsinConfig.noInstances = true; + bufdata->vsinConfig.numRows = bufdata->vsinConfig.unclampedNumRows = 0; } bufdata->vsoutConfig.columns.clear(); @@ -1792,16 +1790,46 @@ static void ConfigureMeshColumns(ICaptureContext &ctx, PopulateBufferData *bufda bufdata->gsoutConfig.columns.clear(); bufdata->gsoutConfig.props.clear(); - if(action) - { - const ShaderReflection *vs = ctx.CurPipelineState().GetShaderReflection(ShaderStage::Vertex); - const ShaderReflection *last = ctx.CurPipelineState().GetShaderReflection(ShaderStage::Geometry); - if(last == NULL) - last = ctx.CurPipelineState().GetShaderReflection(ShaderStage::Domain); + const ShaderReflection *vs = ctx.CurPipelineState().GetShaderReflection(ShaderStage::Vertex); + const ShaderReflection *last = ctx.CurPipelineState().GetShaderReflection(ShaderStage::Geometry); + if(last == NULL) + last = ctx.CurPipelineState().GetShaderReflection(ShaderStage::Domain); - ConfigureColumnsForShader(ctx, 0, vs, bufdata->vsoutConfig.columns, bufdata->vsoutConfig.props); - ConfigureColumnsForShader(ctx, ctx.CurPipelineState().GetRasterizedStream(), last, - bufdata->gsoutConfig.columns, bufdata->gsoutConfig.props); + ConfigureColumnsForShader(ctx, 0, vs, bufdata->vsoutConfig.columns, bufdata->vsoutConfig.props); + ConfigureColumnsForShader(ctx, ctx.CurPipelineState().GetRasterizedStream(), last, + bufdata->gsoutConfig.columns, bufdata->gsoutConfig.props); +} + +static void ConfigureColumns(ICaptureContext &ctx, PopulateBufferData *bufdata) +{ + const ActionDescription *action = ctx.CurAction(); + + if(action && (action->flags & ActionFlags::MeshDispatch)) + { + ConfigureColumnsForMeshPipe(ctx, bufdata); + } + else if(action && (action->flags & ActionFlags::Drawcall)) + { + ConfigureColumnsForVertexPipe(ctx, bufdata); + } + else + { + IEventBrowser *eb = ctx.GetEventBrowser(); + + bufdata->vsinConfig.statusString = bufdata->vsoutConfig.statusString = + bufdata->gsoutConfig.statusString = + lit("No current draw action\nSelected EID @%1 - %2\nEffective EID: @%3 - %4") + .arg(ctx.CurSelectedEvent()) + .arg(QString(eb->GetEventName(ctx.CurSelectedEvent()))) + .arg(ctx.CurEvent()) + .arg(QString(eb->GetEventName(ctx.CurEvent()))); + + ConfigureStatusColumn(bufdata->vsinConfig.columns, bufdata->vsinConfig.props); + ConfigureStatusColumn(bufdata->vsoutConfig.columns, bufdata->vsoutConfig.props); + ConfigureStatusColumn(bufdata->gsoutConfig.columns, bufdata->gsoutConfig.props); + + bufdata->vsinConfig.genericsEnabled.push_back(false); + bufdata->vsinConfig.generics.push_back(PixelValue()); } } @@ -2860,7 +2888,7 @@ void BufferViewer::OnEventChanged(uint32_t eventId) // GS Out doesn't use primitive restart because it is post-expansion } - ConfigureMeshColumns(m_Ctx, bufdata); + ConfigureColumns(m_Ctx, bufdata); Viewport vp = m_Ctx.CurPipelineState().GetViewport(0); diff --git a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h index bfb0d3b29..98235b789 100644 --- a/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h +++ b/qrenderdoc/Windows/PipelineState/PipelineStateViewer.h @@ -132,7 +132,7 @@ private: Ui::PipelineStateViewer *ui; ICaptureContext &m_Ctx; - QMenu *editMenus[6] = {}; + QMenu *editMenus[NumShaderStages] = {}; RDPreviewTooltip *m_Tooltip = NULL; diff --git a/qrenderdoc/Windows/ShaderMessageViewer.cpp b/qrenderdoc/Windows/ShaderMessageViewer.cpp index ee9c1d69f..5af3b383c 100644 --- a/qrenderdoc/Windows/ShaderMessageViewer.cpp +++ b/qrenderdoc/Windows/ShaderMessageViewer.cpp @@ -144,6 +144,8 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s m_API = m_Ctx.APIProps().pipelineType; + QObject::connect(ui->task, &QToolButton::toggled, [this](bool) { refreshMessages(); }); + QObject::connect(ui->mesh, &QToolButton::toggled, [this](bool) { refreshMessages(); }); QObject::connect(ui->vertex, &QToolButton::toggled, [this](bool) { refreshMessages(); }); QObject::connect(ui->hull, &QToolButton::toggled, [this](bool) { refreshMessages(); }); QObject::connect(ui->domain, &QToolButton::toggled, [this](bool) { refreshMessages(); }); @@ -167,6 +169,8 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s ui->exportButton->setMenu(menu); QObject::connect(ui->exportButton, &QToolButton::clicked, this, &ShaderMessageViewer::exportText); + ui->task->setText(ToQStr(ShaderStage::Task, m_API)); + ui->mesh->setText(ToQStr(ShaderStage::Mesh, m_API)); ui->vertex->setText(ToQStr(ShaderStage::Vertex, m_API)); ui->hull->setText(ToQStr(ShaderStage::Hull, m_API)); ui->domain->setText(ToQStr(ShaderStage::Domain, m_API)); @@ -219,11 +223,30 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s ui->messages->setItemDelegateForColumn(0, m_debugDelegate); m_OrigShaders[5] = pipe.GetShader(ShaderStage::Compute); + m_LayoutStage = ShaderStage::Compute; } else { - ui->messages->setColumns({lit("Debug"), lit("Go to"), tr("Location"), lit("Message")}); - sortColumn = 2; + if(pipe.GetShader(ShaderStage::Task) != ResourceId()) + { + ui->messages->setColumns({lit("Debug"), lit("Go to"), tr("Task group"), tr("Mesh group"), + lit("Thread"), lit("Message")}); + sortColumn = 4; + m_LayoutStage = ShaderStage::Task; + } + else if(pipe.GetShader(ShaderStage::Mesh) != ResourceId()) + { + ui->messages->setColumns( + {lit("Debug"), lit("Go to"), tr("Workgroup"), lit("Thread/Location"), lit("Message")}); + sortColumn = 3; + m_LayoutStage = ShaderStage::Mesh; + } + else + { + ui->messages->setColumns({lit("Debug"), lit("Go to"), tr("Location"), lit("Message")}); + sortColumn = 2; + m_LayoutStage = ShaderStage::Vertex; + } m_gotoDelegate = new ButtonDelegate(Icons::find(), gotoableRole, this); @@ -231,7 +254,15 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s ui->messages->setItemDelegateForColumn(1, m_gotoDelegate); QCheckBox *boxes[] = { - ui->vertex, ui->hull, ui->domain, ui->geometry, ui->pixel, + ui->vertex, + ui->hull, + ui->domain, + ui->geometry, + ui->pixel, + // compute + NULL, + ui->task, + ui->mesh, }; for(ShaderStage s : values()) @@ -314,7 +345,7 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s trace = r->DebugPixel(msg.location.pixel.x, msg.location.pixel.y, msg.location.pixel.sample, msg.location.pixel.primitive); - if(trace->debugger == NULL) + if(trace && trace->debugger == NULL) { r->FreeTrace(trace); trace = NULL; @@ -326,6 +357,7 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s QString debugContext; if(msg.stage == ShaderStage::Compute) + { debugContext = lit("Group [%1,%2,%3] Thread [%4,%5,%6]") .arg(msg.location.compute.workgroup[0]) .arg(msg.location.compute.workgroup[1]) @@ -333,10 +365,57 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s .arg(msg.location.compute.thread[0]) .arg(msg.location.compute.thread[1]) .arg(msg.location.compute.thread[2]); + } else if(msg.stage == ShaderStage::Vertex) + { debugContext = tr("Vertex %1").arg(msg.location.vertex.vertexIndex); + } else if(msg.stage == ShaderStage::Pixel) + { debugContext = tr("Pixel %1,%2").arg(msg.location.pixel.x).arg(msg.location.pixel.y); + } + else if(msg.stage == ShaderStage::Task) + { + QString groupIdx = QFormatStr("%1").arg(msg.location.mesh.taskGroup[0]); + if(msg.location.mesh.taskGroup[1] != ShaderMeshMessageLocation::NotUsed) + groupIdx += QFormatStr(",%1").arg(msg.location.mesh.taskGroup[1]); + if(msg.location.mesh.taskGroup[2] != ShaderMeshMessageLocation::NotUsed) + groupIdx += QFormatStr(",%1").arg(msg.location.mesh.taskGroup[2]); + + QString threadIdx = QFormatStr("%1").arg(msg.location.mesh.thread[0]); + if(msg.location.mesh.thread[1] != ShaderMeshMessageLocation::NotUsed) + threadIdx += QFormatStr(",%1").arg(msg.location.mesh.thread[1]); + if(msg.location.mesh.thread[2] != ShaderMeshMessageLocation::NotUsed) + threadIdx += QFormatStr(",%1").arg(msg.location.mesh.thread[2]); + + debugContext = tr("Task Group [%1] Thread [%2]").arg(groupIdx).arg(threadIdx); + } + else if(msg.stage == ShaderStage::Mesh) + { + QString groupIdx = QFormatStr("%1").arg(msg.location.mesh.meshGroup[0]); + if(msg.location.mesh.meshGroup[1] != ShaderMeshMessageLocation::NotUsed) + groupIdx += QFormatStr(",%1").arg(msg.location.mesh.meshGroup[1]); + if(msg.location.mesh.meshGroup[2] != ShaderMeshMessageLocation::NotUsed) + groupIdx += QFormatStr(",%1").arg(msg.location.mesh.meshGroup[2]); + + QString threadIdx = QFormatStr("%1").arg(msg.location.mesh.thread[0]); + if(msg.location.mesh.thread[1] != ShaderMeshMessageLocation::NotUsed) + threadIdx += QFormatStr(",%1").arg(msg.location.mesh.thread[1]); + if(msg.location.mesh.thread[2] != ShaderMeshMessageLocation::NotUsed) + threadIdx += QFormatStr(",%1").arg(msg.location.mesh.thread[2]); + + debugContext = tr("Mesh Group [%1] Thread [%2]").arg(groupIdx).arg(threadIdx); + + if(msg.location.mesh.taskGroup[0] != ShaderMeshMessageLocation::NotUsed) + { + debugContext += tr(" from Task [%1").arg(msg.location.mesh.taskGroup[0]); + if(msg.location.mesh.taskGroup[1] != ShaderMeshMessageLocation::NotUsed) + debugContext += tr(",%1").arg(msg.location.mesh.taskGroup[1]); + if(msg.location.mesh.taskGroup[2] != ShaderMeshMessageLocation::NotUsed) + debugContext += tr(",%1").arg(msg.location.mesh.taskGroup[2]); + debugContext += lit("]"); + } + } // wait a short while before displaying the progress dialog (which won't show if we're already // done by the time we reach it) @@ -436,6 +515,10 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s msg.location.geometry.primitive), MeshDataStage::GSOut); } + else if(msg.stage == ShaderStage::Task || msg.stage == ShaderStage::Mesh) + { + // TODO mesh shader jumping + } else { qCritical() << "Can't go to a compute thread"; @@ -472,10 +555,43 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s const ShaderMessage &am = m_Messages[a->tag().toInt()]; const ShaderMessage &bm = m_Messages[b->tag().toInt()]; - if(col == 3) + if(col == 5) { + // column 5 is the message when task shaders are used return am.message < bm.message; } + else if(col == 4) + { + // column 4 is the message, except when task shaders are used - then it's + // the thread index + if((am.stage == ShaderStage::Task || am.stage == ShaderStage::Mesh) && + am.location.mesh.taskGroup[0] != ShaderMeshMessageLocation::NotUsed) + { + return am.location.mesh.thread < bm.location.mesh.thread; + } + else + { + return am.message < bm.message; + } + } + else if(col == 3) + { + // column 3 is the mesh thread when only mesh shaders are used, or the mesh group when + // task shaders are used. For non mesh/task it is the message + if((am.stage == ShaderStage::Task || am.stage == ShaderStage::Mesh) && + am.location.mesh.taskGroup[0] != ShaderMeshMessageLocation::NotUsed) + { + return am.location.mesh.meshGroup < bm.location.mesh.meshGroup; + } + else if(am.stage == ShaderStage::Mesh) + { + return am.location.mesh.thread < bm.location.mesh.thread; + } + else + { + return am.message < bm.message; + } + } else if(col == 2 || m_OrigShaders[5] == ResourceId()) { // sort by location either if it's selected, or if it's not dispatch in which case we @@ -517,6 +633,15 @@ ShaderMessageViewer::ShaderMessageViewer(ICaptureContext &ctx, ShaderStageMask s // column 2 is the thread column for compute return am.location.compute.thread < bm.location.compute.thread; } + else if(am.stage == ShaderStage::Task || am.stage == ShaderStage::Mesh) + { + // column 2 is the mesh group column, or the task group column, depending on if + // task shaders were in use + if(am.location.mesh.taskGroup[0] != ShaderMeshMessageLocation::NotUsed) + return am.location.mesh.taskGroup < bm.location.mesh.taskGroup; + else + return am.location.mesh.meshGroup < bm.location.mesh.meshGroup; + } else if(am.stage == ShaderStage::Geometry) { const ShaderGeometryMessageLocation &aloc = am.location.geometry; @@ -571,7 +696,7 @@ void ShaderMessageViewer::OnCaptureClosed() void ShaderMessageViewer::OnEventChanged(uint32_t eventId) { - ResourceId shaders[6]; + ResourceId shaders[NumShaderStages]; bool editsChanged = false; QString staleReason; @@ -740,6 +865,10 @@ void ShaderMessageViewer::refreshMessages() { mask = ShaderStageMask::Unknown; + if(ui->task->isChecked()) + mask |= ShaderStageMask::Task; + if(ui->mesh->isChecked()) + mask |= ShaderStageMask::Mesh; if(ui->vertex->isChecked()) mask |= ShaderStageMask::Vertex; if(ui->hull->isChecked()) @@ -768,6 +897,8 @@ void ShaderMessageViewer::refreshMessages() const ShaderReflection *vsrefl = m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Vertex); const ShaderReflection *psrefl = m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Pixel); const ShaderReflection *csrefl = m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Compute); + const ShaderReflection *tsrefl = m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Task); + const ShaderReflection *msrefl = m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Mesh); for(int i = 0; i < m_Messages.count(); i++) { @@ -846,6 +977,14 @@ void ShaderMessageViewer::refreshMessages() location += lit(", View %1").arg(msg.location.geometry.view); } } + else if(msg.stage == ShaderStage::Task) + { + refl = tsrefl; + } + else if(msg.stage == ShaderStage::Mesh) + { + refl = msrefl; + } else { // no location info for other stages @@ -876,9 +1015,83 @@ void ShaderMessageViewer::refreshMessages() node->setData(0, debuggableRole, refl && refl->debugInfo.debuggable); } + else if(msg.stage == ShaderStage::Task) + { + QString groupIdx = QFormatStr("%1").arg(msg.location.mesh.taskGroup[0]); + if(msg.location.mesh.taskGroup[1] != ShaderMeshMessageLocation::NotUsed) + groupIdx += QFormatStr(",%1").arg(msg.location.mesh.taskGroup[1]); + if(msg.location.mesh.taskGroup[2] != ShaderMeshMessageLocation::NotUsed) + groupIdx += QFormatStr(",%1").arg(msg.location.mesh.taskGroup[2]); + + QString threadIdx = QFormatStr("%1").arg(msg.location.mesh.thread[0]); + if(msg.location.mesh.thread[1] != ShaderMeshMessageLocation::NotUsed) + threadIdx += QFormatStr(",%1").arg(msg.location.mesh.thread[1]); + if(msg.location.mesh.thread[2] != ShaderMeshMessageLocation::NotUsed) + threadIdx += QFormatStr(",%1").arg(msg.location.mesh.thread[2]); + + node = new RDTreeWidgetItem({ + QString(), + QString(), + groupIdx, + lit("-"), + threadIdx, + text, + }); + + node->setData(0, debuggableRole, refl && refl->debugInfo.debuggable); + node->setData(1, gotoableRole, true); + } + else if(msg.stage == ShaderStage::Mesh) + { + QString taskIdx; + if(msg.location.mesh.taskGroup[0] != ShaderMeshMessageLocation::NotUsed) + taskIdx = QFormatStr("%1").arg(msg.location.mesh.taskGroup[0]); + if(msg.location.mesh.taskGroup[1] != ShaderMeshMessageLocation::NotUsed) + taskIdx += QFormatStr(",%1").arg(msg.location.mesh.taskGroup[1]); + if(msg.location.mesh.taskGroup[2] != ShaderMeshMessageLocation::NotUsed) + taskIdx += QFormatStr(",%1").arg(msg.location.mesh.taskGroup[2]); + + QString groupIdx = QFormatStr("%1").arg(msg.location.mesh.meshGroup[0]); + if(msg.location.mesh.meshGroup[1] != ShaderMeshMessageLocation::NotUsed) + groupIdx += QFormatStr(",%1").arg(msg.location.mesh.meshGroup[1]); + if(msg.location.mesh.meshGroup[2] != ShaderMeshMessageLocation::NotUsed) + groupIdx += QFormatStr(",%1").arg(msg.location.mesh.meshGroup[2]); + + QString threadIdx = QFormatStr("%1").arg(msg.location.mesh.thread[0]); + if(msg.location.mesh.thread[1] != ShaderMeshMessageLocation::NotUsed) + threadIdx += QFormatStr(",%1").arg(msg.location.mesh.thread[1]); + if(msg.location.mesh.thread[2] != ShaderMeshMessageLocation::NotUsed) + threadIdx += QFormatStr(",%1").arg(msg.location.mesh.thread[2]); + + if(m_LayoutStage == ShaderStage::Task) + node = new RDTreeWidgetItem({ + QString(), + QString(), + taskIdx, + groupIdx, + threadIdx, + text, + }); + else + node = new RDTreeWidgetItem({ + QString(), + QString(), + groupIdx, + threadIdx, + text, + }); + + node->setData(0, debuggableRole, refl && refl->debugInfo.debuggable); + node->setData(1, gotoableRole, true); + } else { - node = new RDTreeWidgetItem({QString(), QString(), location, text}); + if(m_LayoutStage == ShaderStage::Task) + node = new RDTreeWidgetItem({QString(), QString(), QString(), QString(), location, text}); + else if(m_LayoutStage == ShaderStage::Mesh) + node = new RDTreeWidgetItem({QString(), QString(), QString(), location, text}); + else + node = new RDTreeWidgetItem({QString(), QString(), location, text}); node->setData(0, debuggableRole, refl && refl->debugInfo.debuggable); node->setData(1, gotoableRole, diff --git a/qrenderdoc/Windows/ShaderMessageViewer.h b/qrenderdoc/Windows/ShaderMessageViewer.h index 875bb14dd..9ce78446e 100644 --- a/qrenderdoc/Windows/ShaderMessageViewer.h +++ b/qrenderdoc/Windows/ShaderMessageViewer.h @@ -94,6 +94,7 @@ private: const ActionDescription *m_Action; rdcarray m_Messages; - ResourceId m_OrigShaders[6]; - ResourceId m_ReplacedShaders[6]; + ShaderStage m_LayoutStage; + ResourceId m_OrigShaders[NumShaderStages]; + ResourceId m_ReplacedShaders[NumShaderStages]; }; diff --git a/qrenderdoc/Windows/ShaderMessageViewer.ui b/qrenderdoc/Windows/ShaderMessageViewer.ui index 8a2aa1394..3c9d59c5b 100644 --- a/qrenderdoc/Windows/ShaderMessageViewer.ui +++ b/qrenderdoc/Windows/ShaderMessageViewer.ui @@ -132,6 +132,26 @@ + + + + Task + + + true + + + + + + + Mesh + + + true + + + diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index 853a251de..992ed2f47 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -1109,6 +1109,8 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR if(multipleStreams) name = QFormatStr("Stream %1 : %2").arg(s.stream).arg(name); + if(s.perPrimitiveRate) + name += tr(" (Per-Prim)"); QString semIdx = s.needSemanticIndex ? QString::number(s.semanticIndex) : QString(); diff --git a/qrenderdoc/Windows/StatisticsViewer.cpp b/qrenderdoc/Windows/StatisticsViewer.cpp index 3077fb47d..f2dbe3c6f 100644 --- a/qrenderdoc/Windows/StatisticsViewer.cpp +++ b/qrenderdoc/Windows/StatisticsViewer.cpp @@ -633,7 +633,7 @@ void StatisticsViewer::CountContributingEvents(const ActionDescription &action, if(diagnosticMasked != ActionFlags::NoFlags) diagnosticCount += 1; - if(action.flags & ActionFlags::Drawcall) + if(action.flags & (ActionFlags::MeshDispatch | ActionFlags::Drawcall)) drawCount += 1; if(action.flags & ActionFlags::Dispatch) diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 4f035ea14..daf2ea4e7 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -445,7 +445,8 @@ void TextureViewer::UI_UpdateCachedTexture() const ShaderReflection *shaderDetails = m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Pixel); - if(!m_Ctx.CurAction() || !(m_Ctx.CurAction()->flags & ActionFlags::Drawcall)) + if(!m_Ctx.CurAction() || + !(m_Ctx.CurAction()->flags & (ActionFlags::MeshDispatch | ActionFlags::Drawcall))) { ui->debugPixelContext->setEnabled(false); ui->debugPixelContext->setToolTip(tr("No draw call selected")); @@ -3167,10 +3168,12 @@ void TextureViewer::OnEventChanged(uint32_t eventId) bool copy = false, clear = false, compute = false; Following::GetActionContext(m_Ctx, copy, clear, compute); - ShaderStage stages[] = {ShaderStage::Vertex, ShaderStage::Hull, ShaderStage::Domain, - ShaderStage::Geometry, ShaderStage::Pixel}; + ShaderStage stages[] = { + ShaderStage::Vertex, ShaderStage::Hull, ShaderStage::Domain, ShaderStage::Geometry, + ShaderStage::Pixel, ShaderStage::Task, ShaderStage::Mesh, + }; - int count = 5; + int count = 7; if(compute) { diff --git a/qrenderdoc/Windows/TextureViewer.h b/qrenderdoc/Windows/TextureViewer.h index 213b409b2..d0387d126 100644 --- a/qrenderdoc/Windows/TextureViewer.h +++ b/qrenderdoc/Windows/TextureViewer.h @@ -360,8 +360,8 @@ private: friend struct Following; - rdcarray m_ReadOnlyResources[(uint32_t)ShaderStage::Count]; - rdcarray m_ReadWriteResources[(uint32_t)ShaderStage::Count]; + rdcarray m_ReadOnlyResources[NumShaderStages]; + rdcarray m_ReadWriteResources[NumShaderStages]; QTime m_CustomShaderTimer; int m_CustomShaderWriteTime = 0; diff --git a/renderdoc/api/replay/common_pipestate.h b/renderdoc/api/replay/common_pipestate.h index 30d325963..a7ff24d74 100644 --- a/renderdoc/api/replay/common_pipestate.h +++ b/renderdoc/api/replay/common_pipestate.h @@ -529,6 +529,68 @@ be emulated. DECLARE_REFLECTION_STRUCT(VertexInputAttribute); +DOCUMENT(R"(A task or mesh message's location. + +.. data:: NotUsed + + Set for values of task group/thread index when no task shaders were run. + + Also set for values of a mesh group or thread index when that dimensionality is unused. For + example if the shader declares a group dimension of (128,1,1) then the y and z values for + thread index will be indicated as not used. +)"); +struct ShaderMeshMessageLocation +{ + DOCUMENT(""); + ShaderMeshMessageLocation() = default; + ShaderMeshMessageLocation(const ShaderMeshMessageLocation &) = default; + ShaderMeshMessageLocation &operator=(const ShaderMeshMessageLocation &) = default; + + bool operator==(const ShaderMeshMessageLocation &o) const + { + return taskGroup == o.taskGroup && meshGroup == o.meshGroup && thread == o.thread; + } + bool operator<(const ShaderMeshMessageLocation &o) const + { + if(!(taskGroup == o.taskGroup)) + return taskGroup < o.taskGroup; + if(!(meshGroup == o.meshGroup)) + return meshGroup < o.meshGroup; + if(!(thread == o.thread)) + return thread < o.thread; + return false; + } + + DOCUMENT(R"(The task workgroup index between the task dispatch. + +.. note:: + If no task shader is in use, this will be :data:`NotUsed`, :data:`NotUsed`, :data:`NotUsed`. + +:type: Tuple[int,int,int] +)"); + rdcfixedarray taskGroup; + + DOCUMENT(R"(The mesh workgroup index within the dispatch or launching task workgroup. + +:type: Tuple[int,int,int] +)"); + rdcfixedarray meshGroup; + + DOCUMENT(R"(The thread index within the workgroup, either for a task shader or mesh shader. + +.. note:: + Since task shaders can only emit one set of meshes per group, the task thread is not relevant + for mesh shader messages, so this is the thread either for a task or a mesh shader message. + +:type: Tuple[int,int,int] +)"); + rdcfixedarray thread; + + static const uint32_t NotUsed = ~0U; +}; + +DECLARE_REFLECTION_STRUCT(ShaderMeshMessageLocation); + DOCUMENT("A compute shader message's location."); struct ShaderComputeMessageLocation { @@ -664,6 +726,12 @@ union ShaderMessageLocation )"); ShaderComputeMessageLocation compute; + DOCUMENT(R"(The location if the shader is a task or mesh shader. + +:type: ShaderMeshMessageLocation +)"); + ShaderMeshMessageLocation mesh; + DOCUMENT(R"(The location if the shader is a vertex shader. :type: ShaderVertexMessageLocation @@ -696,7 +764,7 @@ struct ShaderMessage bool operator==(const ShaderMessage &o) const { return stage == o.stage && disassemblyLine == o.disassemblyLine && - location.compute == o.location.compute && message == o.message; + location.mesh == o.location.mesh && message == o.message; } bool operator<(const ShaderMessage &o) const { @@ -704,8 +772,8 @@ struct ShaderMessage return stage < o.stage; if(!(disassemblyLine == o.disassemblyLine)) return disassemblyLine < o.disassemblyLine; - if(!(location.compute == o.location.compute)) - return location.compute < o.location.compute; + if(!(location.mesh == o.location.mesh)) + return location.mesh < o.location.mesh; if(!(message == o.message)) return message < o.message; return false; diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index f55f66093..1ddfff5f9 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -31,6 +31,59 @@ #include "rdcarray.h" #include "replay_enums.h" +DOCUMENT(R"(The size information for a task group. +)"); +struct TaskGroupSize +{ + DOCUMENT("The size in the x dimension."); + uint32_t x; + DOCUMENT("The size in the y dimension."); + uint32_t y; + DOCUMENT("The size in the z dimension."); + uint32_t z; + + bool operator==(const TaskGroupSize &o) const { return x == o.x && y == o.y && z == o.z; } + bool operator<(const TaskGroupSize &o) const + { + if(!(x == o.x)) + return x < o.x; + if(!(y == o.y)) + return y < o.y; + if(!(z == o.z)) + return z < o.z; + return false; + } +}; + +DECLARE_REFLECTION_STRUCT(TaskGroupSize); + +DOCUMENT(R"(The size information for a meshlet. +)"); +struct MeshletSize +{ + DOCUMENT("The number of indices in the meshlet."); + uint32_t numIndices; + DOCUMENT(R"(The number of vertices in this meshlet. This may be larger or smaller than the number +of indices. +)"); + uint32_t numVertices; + + bool operator==(const MeshletSize &o) const + { + return numIndices == o.numIndices && numVertices == o.numVertices; + } + bool operator<(const MeshletSize &o) const + { + if(!(numIndices == o.numIndices)) + return numIndices < o.numIndices; + if(!(numVertices == o.numVertices)) + return numVertices < o.numVertices; + return false; + } +}; + +DECLARE_REFLECTION_STRUCT(MeshletSize); + DOCUMENT(R"(Contains the details of a single element of data (such as position or texture co-ordinates) within a mesh. )"); @@ -60,6 +113,54 @@ struct MeshFormat DOCUMENT("The number of bytes to use from the vertex buffer. Only valid on APIs that allow it."); uint64_t vertexByteSize = 0; + DOCUMENT(R"(The size of each meshlet, for a meshlet based draw. + +Each meshlet lists its individual size, but a cumulative sum can be used for defining boundaries +between meshlets either by raw vertex order (using the number of indices) or by index value (using +the number of vertices). + +:type: List[MeshletSize] +)"); + rdcarray meshletSizes; + + DOCUMENT(R"(The size of each task group's dispatch, for a meshlet based draw. + +Each group of a task shader within a dispatch can itself fill out a payload and dispatch a number +of mesh groups. This list contains the 3-dimensional dimension that each task group emitted. + +:type: List[TaskGroupSize] +)"); + rdcarray taskSizes; + + DOCUMENT(R"(If showing a set of meshlets that don't start from meshlet 0, this is the number of +meshlet to consider skipped before :data:`meshletSizes`. + +Primarily useful for keeping a consistent colouring of meshlets when filtering to a subset + +See also :data:`meshletIndexOffset`. +)"); + uint32_t meshletOffset = 0; + + DOCUMENT(R"(If showing a set of meshlets that don't start from index 0, this is the number of +vertices to consider skipped before :data:`meshletSizes` - equivalent to baseVertex. + +Primarily useful for keeping a consistent colouring of meshlets when filtering to a subset + +See also :data:`meshletOffset`. +)"); + uint32_t meshletIndexOffset = 0; + + DOCUMENT(R"(The offset in bytes to the start of the per-primitive rate vertex data. + +Only for meshlet outputs. +)"); + uint64_t perPrimitiveOffset = 0; + DOCUMENT(R"(The stride in bytes of the per-primitive rate vertex data. + +Only for meshlet outputs. +)"); + uint32_t perPrimitiveStride = 0; + DOCUMENT(R"(The format description of this mesh components elements. :type: ResourceFormat @@ -130,7 +231,7 @@ struct MeshDisplay MeshDisplay &operator=(const MeshDisplay &) = default; DOCUMENT("The :class:`MeshDataStage` where this mesh data comes from."); - MeshDataStage type = MeshDataStage::Unknown; + MeshDataStage type = MeshDataStage::VSIn; DOCUMENT(R"(The camera to use when rendering all of the meshes. diff --git a/renderdoc/api/replay/d3d12_pipestate.h b/renderdoc/api/replay/d3d12_pipestate.h index cf808b7b9..7fa59c7fa 100644 --- a/renderdoc/api/replay/d3d12_pipestate.h +++ b/renderdoc/api/replay/d3d12_pipestate.h @@ -974,6 +974,16 @@ struct State :type: D3D12Shader )"); Shader computeShader; + DOCUMENT(R"(The amplification shader stage. + +:type: D3D12Shader +)"); + Shader ampShader; + DOCUMENT(R"(The mesh shader stage. + +:type: D3D12Shader +)"); + Shader meshShader; DOCUMENT(R"(The stream-out pipeline stage. diff --git a/renderdoc/api/replay/pipestate.h b/renderdoc/api/replay/pipestate.h index bbf574014..fcdaab815 100644 --- a/renderdoc/api/replay/pipestate.h +++ b/renderdoc/api/replay/pipestate.h @@ -442,4 +442,8 @@ private: const D3D12Pipe::Shader &GetD3D12Stage(ShaderStage stage) const; const GLPipe::Shader &GetGLStage(ShaderStage stage) const; const VKPipe::Shader &GetVulkanStage(ShaderStage stage) const; + bool IsD3D11Stage(ShaderStage stage) const; + bool IsD3D12Stage(ShaderStage stage) const; + bool IsGLStage(ShaderStage stage) const; + bool IsVulkanStage(ShaderStage stage) const; }; diff --git a/renderdoc/api/replay/pipestate.inl b/renderdoc/api/replay/pipestate.inl index a33f916ca..5a272c16d 100644 --- a/renderdoc/api/replay/pipestate.inl +++ b/renderdoc/api/replay/pipestate.inl @@ -62,6 +62,8 @@ rdcstr PipeState::Abbrev(ShaderStage stage) const case ShaderStage::Geometry: return "GS"; case ShaderStage::Fragment: return "FS"; case ShaderStage::Compute: return "CS"; + case ShaderStage::Task: return "TS"; + case ShaderStage::Mesh: return "MS"; default: break; } } @@ -75,6 +77,8 @@ rdcstr PipeState::Abbrev(ShaderStage stage) const case ShaderStage::Geometry: return "GS"; case ShaderStage::Pixel: return "PS"; case ShaderStage::Compute: return "CS"; + case ShaderStage::Amplification: return "AS"; + case ShaderStage::Mesh: return "MS"; default: break; } } @@ -92,6 +96,62 @@ rdcstr PipeState::OutputAbbrev() const return "RT"; } +bool PipeState::IsD3D11Stage(ShaderStage stage) const +{ + switch(stage) + { + case ShaderStage::Vertex: + case ShaderStage::Domain: + case ShaderStage::Hull: + case ShaderStage::Geometry: + case ShaderStage::Pixel: + case ShaderStage::Compute: return true; + default: return false; + } +} + +bool PipeState::IsD3D12Stage(ShaderStage stage) const +{ + switch(stage) + { + case ShaderStage::Vertex: + case ShaderStage::Domain: + case ShaderStage::Hull: + case ShaderStage::Geometry: + case ShaderStage::Pixel: + case ShaderStage::Compute: return true; + default: return false; + } +} + +bool PipeState::IsGLStage(ShaderStage stage) const +{ + switch(stage) + { + case ShaderStage::Vertex: + case ShaderStage::Domain: + case ShaderStage::Hull: + case ShaderStage::Geometry: + case ShaderStage::Pixel: + case ShaderStage::Compute: return true; + default: return false; + } +} + +bool PipeState::IsVulkanStage(ShaderStage stage) const +{ + switch(stage) + { + case ShaderStage::Vertex: + case ShaderStage::Domain: + case ShaderStage::Hull: + case ShaderStage::Geometry: + case ShaderStage::Pixel: + case ShaderStage::Compute: return true; + default: return false; + } +} + const D3D11Pipe::Shader &PipeState::GetD3D11Stage(ShaderStage stage) const { if(stage == ShaderStage::Vertex) @@ -952,6 +1012,9 @@ BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, ui { if(IsCaptureD3D11()) { + if(!IsD3D11Stage(stage)) + return ret; + const D3D11Pipe::Shader &s = GetD3D11Stage(stage); if(s.reflection != NULL && BufIdx < (uint32_t)s.reflection->constantBlocks.count()) @@ -971,6 +1034,9 @@ BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, ui } else if(IsCaptureD3D12()) { + if(!IsD3D12Stage(stage)) + return ret; + const D3D12Pipe::Shader &s = GetD3D12Stage(stage); if(s.reflection != NULL && BufIdx < (uint32_t)s.reflection->constantBlocks.count()) @@ -1014,6 +1080,9 @@ BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, ui } else if(IsCaptureGL()) { + if(!IsGLStage(stage)) + return ret; + const GLPipe::Shader &s = GetGLStage(stage); if(s.reflection != NULL && BufIdx < (uint32_t)s.reflection->constantBlocks.count()) @@ -1038,6 +1107,9 @@ BoundCBuffer PipeState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, ui } else if(IsCaptureVK()) { + if(!IsVulkanStage(stage)) + return ret; + const VKPipe::Pipeline &pipe = stage == ShaderStage::Compute ? m_Vulkan->compute : m_Vulkan->graphics; const VKPipe::Shader &s = GetVulkanStage(stage); @@ -1150,6 +1222,9 @@ rdcarray PipeState::GetSamplers(ShaderStage stage) const { if(IsCaptureD3D11()) { + if(!IsD3D11Stage(stage)) + return ret; + const D3D11Pipe::Shader &s = GetD3D11Stage(stage); ret.reserve(s.samplers.size()); @@ -1168,6 +1243,9 @@ rdcarray PipeState::GetSamplers(ShaderStage stage) const } else if(IsCaptureD3D12()) { + if(!IsD3D12Stage(stage)) + return ret; + const D3D12Pipe::Shader &s = GetD3D12Stage(stage); size_t size = s.bindpointMapping.samplers.size(); @@ -1210,6 +1288,9 @@ rdcarray PipeState::GetSamplers(ShaderStage stage) const } else if(IsCaptureGL()) { + if(!IsGLStage(stage)) + return ret; + ret.reserve(m_GL->samplers.size()); for(int i = 0; i < m_GL->samplers.count(); i++) @@ -1226,6 +1307,9 @@ rdcarray PipeState::GetSamplers(ShaderStage stage) const } else if(IsCaptureVK()) { + if(!IsVulkanStage(stage)) + return ret; + const rdcarray &descsets = stage == ShaderStage::Compute ? m_Vulkan->compute.descriptorSets : m_Vulkan->graphics.descriptorSets; @@ -1282,6 +1366,9 @@ rdcarray PipeState::GetReadOnlyResources(ShaderStage stage, { if(IsCaptureD3D11()) { + if(!IsD3D11Stage(stage)) + return ret; + const D3D11Pipe::Shader &s = GetD3D11Stage(stage); ret.reserve(s.srvs.size()); @@ -1303,6 +1390,9 @@ rdcarray PipeState::GetReadOnlyResources(ShaderStage stage, } else if(IsCaptureD3D12()) { + if(!IsD3D12Stage(stage)) + return ret; + const D3D12Pipe::Shader &s = GetD3D12Stage(stage); size_t size = s.bindpointMapping.readOnlyResources.size(); @@ -1370,6 +1460,9 @@ rdcarray PipeState::GetReadOnlyResources(ShaderStage stage, } else if(IsCaptureGL()) { + if(!IsGLStage(stage)) + return ret; + ret.reserve(m_GL->textures.size()); for(int i = 0; i < m_GL->textures.count(); i++) @@ -1389,6 +1482,9 @@ rdcarray PipeState::GetReadOnlyResources(ShaderStage stage, } else if(IsCaptureVK()) { + if(!IsVulkanStage(stage)) + return ret; + const rdcarray &descsets = stage == ShaderStage::Compute ? m_Vulkan->compute.descriptorSets : m_Vulkan->graphics.descriptorSets; @@ -1478,6 +1574,9 @@ rdcarray PipeState::GetReadWriteResources(ShaderStage stage, { if(IsCaptureD3D11()) { + if(!IsD3D11Stage(stage)) + return ret; + if(stage == ShaderStage::Compute) { ret.reserve(m_D3D11->computeShader.uavs.size()); @@ -1526,6 +1625,9 @@ rdcarray PipeState::GetReadWriteResources(ShaderStage stage, } else if(IsCaptureD3D12()) { + if(!IsD3D12Stage(stage)) + return ret; + const D3D12Pipe::Shader &s = GetD3D12Stage(stage); size_t size = s.bindpointMapping.readWriteResources.size(); @@ -1591,6 +1693,9 @@ rdcarray PipeState::GetReadWriteResources(ShaderStage stage, } else if(IsCaptureGL()) { + if(!IsGLStage(stage)) + return ret; + ret.reserve(m_GL->images.size() + m_GL->atomicBuffers.size() + m_GL->shaderStorageBuffers.size()); @@ -1629,6 +1734,9 @@ rdcarray PipeState::GetReadWriteResources(ShaderStage stage, } else if(IsCaptureVK()) { + if(!IsVulkanStage(stage)) + return ret; + const rdcarray &descsets = stage == ShaderStage::Compute ? m_Vulkan->compute.descriptorSets : m_Vulkan->graphics.descriptorSets; diff --git a/renderdoc/api/replay/renderdoc_tostr.inl b/renderdoc/api/replay/renderdoc_tostr.inl index e5d690124..57f3fdb42 100644 --- a/renderdoc/api/replay/renderdoc_tostr.inl +++ b/renderdoc/api/replay/renderdoc_tostr.inl @@ -692,6 +692,7 @@ rdcstr DoStringise(const ShaderBuiltin &el) STRINGISE_ENUM_CLASS_NAMED(PackedFragRate, "Packed Fragment Rate"); STRINGISE_ENUM_CLASS_NAMED(Barycentrics, "Barycentrics"); STRINGISE_ENUM_CLASS_NAMED(CullPrimitive, "Cull Primitive Output"); + STRINGISE_ENUM_CLASS_NAMED(OutputIndices, "Output Indices"); } END_ENUM_STRINGISE(); } @@ -918,6 +919,8 @@ rdcstr DoStringise(const GPUCounter &el) STRINGISE_ENUM_CLASS(GSInvocations); STRINGISE_ENUM_CLASS(PSInvocations); STRINGISE_ENUM_CLASS(CSInvocations); + STRINGISE_ENUM_CLASS(TSInvocations); + STRINGISE_ENUM_CLASS(MSInvocations); } END_ENUM_STRINGISE(); } @@ -948,6 +951,8 @@ rdcstr DoStringise(const ShaderStage &el) STRINGISE_ENUM_CLASS(Geometry); STRINGISE_ENUM_CLASS(Pixel); STRINGISE_ENUM_CLASS(Compute); + STRINGISE_ENUM_CLASS(Task); + STRINGISE_ENUM_CLASS(Mesh); } END_ENUM_STRINGISE(); } @@ -957,10 +962,11 @@ rdcstr DoStringise(const MeshDataStage &el) { BEGIN_ENUM_STRINGISE(MeshDataStage) { - STRINGISE_ENUM_CLASS(Unknown); STRINGISE_ENUM_CLASS(VSIn); STRINGISE_ENUM_CLASS(VSOut); STRINGISE_ENUM_CLASS(GSOut); + STRINGISE_ENUM_CLASS(TaskOut); + STRINGISE_ENUM_CLASS(MeshOut); } END_ENUM_STRINGISE(); } @@ -1214,6 +1220,7 @@ rdcstr DoStringise(const ActionFlags &el) STRINGISE_BITFIELD_CLASS_BIT(Clear); STRINGISE_BITFIELD_CLASS_BIT(Drawcall); STRINGISE_BITFIELD_CLASS_BIT(Dispatch); + STRINGISE_BITFIELD_CLASS_BIT(MeshDispatch); STRINGISE_BITFIELD_CLASS_BIT(CmdList); STRINGISE_BITFIELD_CLASS_BIT(SetMarker); STRINGISE_BITFIELD_CLASS_BIT(PushMarker); @@ -1252,6 +1259,8 @@ rdcstr DoStringise(const ShaderStageMask &el) STRINGISE_BITFIELD_CLASS_BIT(Geometry); STRINGISE_BITFIELD_CLASS_BIT(Pixel); STRINGISE_BITFIELD_CLASS_BIT(Compute); + STRINGISE_BITFIELD_CLASS_BIT(Task); + STRINGISE_BITFIELD_CLASS_BIT(Mesh); } END_BITFIELD_STRINGISE(); } diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index 7b705039b..f334613c7 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -831,7 +831,7 @@ enum class BindType : uint32_t DECLARE_REFLECTION_ENUM(BindType); -DOCUMENT2(R"(Annotates a particular built-in input or output from a shader with a special meaning to +DOCUMENT3(R"(Annotates a particular built-in input or output from a shader with a special meaning to the hardware or API. Some of the built-in inputs or outputs can be declared multiple times in arrays or otherwise indexed @@ -929,6 +929,8 @@ to apply to multiple related things - see :data:`ClipDistance`, :data:`CullDista This is related to :data:`GroupIndex` and :data:`DispatchThreadIndex`. +)", + R"( .. data:: GSInstanceIndex An input to the geometry shader giving the instance being run, if the geometry shader was setup to @@ -956,8 +958,6 @@ to apply to multiple related things - see :data:`ClipDistance`, :data:`CullDista in a pixel were covered by the rasterizer. As an output, it specifies which samples in the destination target should be updated. -)", - R"( .. data:: MSAASamplePosition An input to the pixel shader that contains the location of the current sample relative to the @@ -1034,6 +1034,8 @@ to apply to multiple related things - see :data:`ClipDistance`, :data:`CullDista Indicates if the current invocation is a helper invocation. +)", + R"( .. data:: SubgroupSize The number of invocations in a subgroup. @@ -1103,6 +1105,10 @@ to apply to multiple related things - see :data:`ClipDistance`, :data:`CullDista .. data:: CullPrimitive An output to indicate whether or not a primitive should be culled. + +.. data:: OutputIndices + + An output containing the indices for a meshlet. )"); enum class ShaderBuiltin : uint32_t { @@ -1159,6 +1165,7 @@ enum class ShaderBuiltin : uint32_t PackedFragRate, Barycentrics, CullPrimitive, + OutputIndices, Count, }; @@ -1191,10 +1198,6 @@ DECLARE_REFLECTION_ENUM(ReplayOutputType); DOCUMENT(R"(Describes a particular stage in the geometry transformation pipeline. -.. data:: Unknown - - Unknown or invalid stage. - .. data:: VSIn The inputs to the vertex shader described by the explicit API vertex input bindings. @@ -1208,13 +1211,29 @@ DOCUMENT(R"(Describes a particular stage in the geometry transformation pipeline The final output from the last stage in the pipeline, be that tessellation or geometry shader. This has possibly been expanded/multiplied from the inputs + +.. data:: TaskOut + + Data from a task/amplification shader. + +.. data:: AmpOut + + Data from an amplification shader (alias for :data:`TaskOut`). + +.. data:: MeshOut + + Data from a mesh shader. )"); enum class MeshDataStage : uint32_t { - Unknown = 0, - VSIn, + VSIn = 0, + First = VSIn, VSOut, GSOut, + TaskOut, + AmpOut = TaskOut, + MeshOut, + Count, }; DECLARE_REFLECTION_ENUM(MeshDataStage); @@ -2336,6 +2355,18 @@ DOCUMENT(R"(The stage in a pipeline where a shader runs .. data:: Compute The compute shader. + +.. data:: Amplification + + The amplification shader. See also :data:`Task`. + +.. data:: Task + + The task shader. See also :data:`Amplification`. + +.. data:: Mesh + + The mesh shader. )"); enum class ShaderStage : uint32_t { @@ -2355,12 +2386,19 @@ enum class ShaderStage : uint32_t Compute, + Task, + Amplification = Task, + + Mesh, + Count, }; ITERABLE_OPERATORS(ShaderStage); DECLARE_REFLECTION_ENUM(ShaderStage); +#define NumShaderStages arraydim() + template constexpr inline ShaderStage StageFromIndex(integer stage) { @@ -2528,7 +2566,7 @@ enum class MessageSource : uint32_t DECLARE_REFLECTION_ENUM(MessageSource); -DOCUMENT(R"(How a resource is being used in the pipeline at a particular point. +DOCUMENT2(R"(How a resource is being used in the pipeline at a particular point. Note that a resource may be used for more than one thing in one event, see :class:`EventUsage`. @@ -2570,6 +2608,15 @@ Note that a resource may be used for more than one thing in one event, see :clas The resource is being used for constants in the :data:`compute shader `. +.. data:: TS_Constants + + The resource is being used as a constants in the amplification or + :data:`task shader `. + +.. data:: MS_Constants + + The resource is being used as a constants in the :data:`mesh shader `. + .. data:: All_Constants The resource is being used for constants in all shader stages. @@ -2608,10 +2655,22 @@ Note that a resource may be used for more than one thing in one event, see :clas The resource is being used as a read-only resource in the :data:`compute shader `. +.. data:: TS_Resource + + The resource is being used as a read-only resource in the amplification or + :data:`task shader `. + +.. data:: MS_Resource + + The resource is being used as a read-only resource in the + :data:`mesh shader `. + .. data:: All_Resource The resource is being used as a read-only resource in all shader stages. +)", + R"( .. data:: VS_RWResource The resource is being used as a read-write resource in the @@ -2642,6 +2701,16 @@ Note that a resource may be used for more than one thing in one event, see :clas The resource is being used as a read-write resource in the :data:`compute shader `. +.. data:: TS_RWResource + + The resource is being used as a read-write resource in the amplification or + :data:`task shader `. + +.. data:: MS_RWResource + + The resource is being used as a read-write resource in the + :data:`mesh shader `. + .. data:: All_RWResource The resource is being used as a read-write resource in all shader stages. @@ -2720,6 +2789,8 @@ enum class ResourceUsage : uint32_t GS_Constants, PS_Constants, CS_Constants, + TS_Constants, + MS_Constants, All_Constants, @@ -2731,6 +2802,8 @@ enum class ResourceUsage : uint32_t GS_Resource, PS_Resource, CS_Resource, + TS_Resource, + MS_Resource, All_Resource, @@ -2740,6 +2813,8 @@ enum class ResourceUsage : uint32_t GS_RWResource, PS_RWResource, CS_RWResource, + TS_RWResource, + MS_RWResource, All_RWResource, @@ -2838,6 +2913,10 @@ DOCUMENT(R"(What kind of solid shading to use when rendering a mesh. The mesh should be rendered using the secondary element as color. +.. data:: Meshlet + + The mesh should be rendered colorising each meshlet differently. + )"); enum class SolidShade : uint32_t { @@ -2845,6 +2924,7 @@ enum class SolidShade : uint32_t Solid, Lit, Secondary, + Meshlet, Count, }; @@ -3495,6 +3575,18 @@ enumerated with IDs in the appropriate ranges. Number of times a :data:`compute shader ` was invoked. +.. data:: TSInvocations + + Number of times a :data:`task shader ` was invoked. + +.. data:: ASInvocations + + Number of times a :data:`amplification shader ` was invoked. + +.. data:: MSInvocations + + Number of times a :data:`mesh shader ` was invoked. + .. data:: FirstAMD The AMD-specific counter IDs start from this value. @@ -3554,6 +3646,9 @@ enum class GPUCounter : uint32_t PSInvocations, FSInvocations = PSInvocations, CSInvocations, + ASInvocations, + TSInvocations = ASInvocations, + MSInvocations, Count, // IHV specific counters can be set above this point @@ -4416,7 +4511,10 @@ enum class ShaderStageMask : uint32_t Pixel = 1 << uint32_t(ShaderStage::Pixel), Fragment = Pixel, Compute = 1 << uint32_t(ShaderStage::Compute), - All = Vertex | Hull | Domain | Geometry | Pixel | Compute, + Task = 1 << uint32_t(ShaderStage::Task), + Amplification = Task, + Mesh = 1 << uint32_t(ShaderStage::Mesh), + All = Vertex | Hull | Domain | Geometry | Pixel | Compute | Task | Mesh, }; BITMASK_OPERATORS(ShaderStageMask); @@ -4541,6 +4639,10 @@ actions. The action issues a number of compute workgroups. +.. data:: MeshDispatch + + The action issues a number of mesh groups for a draw. + .. data:: CmdList The action calls into a previously recorded child command list. @@ -4629,16 +4731,17 @@ enum class ActionFlags : uint32_t Clear = 0x0001, Drawcall = 0x0002, Dispatch = 0x0004, - CmdList = 0x0008, - SetMarker = 0x0010, - PushMarker = 0x0020, - PopMarker = 0x0040, // this is only for internal tracking use - Present = 0x0080, - MultiAction = 0x0100, - Copy = 0x0200, - Resolve = 0x0400, - GenMips = 0x0800, - PassBoundary = 0x1000, + MeshDispatch = 0x0008, + CmdList = 0x0010, + SetMarker = 0x0020, + PushMarker = 0x0040, + PopMarker = 0x0080, + Present = 0x0100, + MultiAction = 0x0200, + Copy = 0x0400, + Resolve = 0x0800, + GenMips = 0x1000, + PassBoundary = 0x2000, // flags Indexed = 0x010000, diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 5427d1b3e..1bafe8cdd 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -930,7 +930,12 @@ struct SigParameter DOCUMENT("The combined semantic name and index."); rdcstr semanticIdxName; DOCUMENT("The semantic index of this variable - see :data:`semanticName`."); - uint32_t semanticIndex = 0; + uint16_t semanticIndex = 0; + + DOCUMENT( + "A flag indicating if this parameter is output at per-primitive rate rather than " + "per-vertex."); + bool perPrimitiveRate = false; DOCUMENT(R"(The index of the shader register/binding used to store this signature element. @@ -956,7 +961,7 @@ shader itself, for APIs that pack signatures together. DOCUMENT("A convenience flag - ``True`` if the semantic name is unique and no index is needed."); bool needSemanticIndex = false; - DOCUMENT("The number of components used to store this element. See :data:`compType`."); + DOCUMENT("The number of components used to store this element. See :data:`varType`."); uint32_t compCount = 0; DOCUMENT( "Selects a stream for APIs that provide multiple output streams for the same named output."); @@ -1526,6 +1531,12 @@ struct ShaderReflection )"); rdcfixedarray dispatchThreadsDimension; + DOCUMENT(R"(The output topology for geometry, tessellation and mesh shaders. + +:type: Topology +)"); + Topology outputTopology = Topology::Unknown; + DOCUMENT(R"(The input signature. :type: List[SigParameter] @@ -1574,6 +1585,15 @@ struct ShaderReflection :type: List[ShaderConstantType] )"); rdcarray pointerTypes; + + DOCUMENT(R"(The block layout of the task-mesh communication payload. + +Only relevant for task or mesh shaders, this gives the output payload (for task shaders) or the +input payload (for mesh shaders) + +:type: ConstantBlock +)"); + ConstantBlock taskPayload; }; DECLARE_REFLECTION_STRUCT(ShaderReflection); diff --git a/renderdoc/api/replay/vk_pipestate.h b/renderdoc/api/replay/vk_pipestate.h index 0c311eff5..ea77829c5 100644 --- a/renderdoc/api/replay/vk_pipestate.h +++ b/renderdoc/api/replay/vk_pipestate.h @@ -1394,6 +1394,18 @@ struct State )"); Shader computeShader; + DOCUMENT(R"(The task shader stage. + +:type: VKShader +)"); + Shader taskShader; + + DOCUMENT(R"(The mesh shader stage. + +:type: VKShader +)"); + Shader meshShader; + DOCUMENT(R"(The tessellation stage. :type: VKTessellation diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index c50197c1d..9e54f60ba 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -1762,7 +1762,7 @@ void ReplayProxy::Proxied_SavePipelineState(ParamSerialiser ¶mser, ReturnSer &m_D3D11PipelineState->pixelShader, &m_D3D11PipelineState->computeShader, }; - for(int i = 0; i < 6; i++) + for(size_t i = 0; i < ARRAY_COUNT(stages); i++) if(stages[i]->resourceId != ResourceId()) stages[i]->reflection = GetShader(ResourceId(), GetLiveID(stages[i]->resourceId), ShaderEntryPoint()); @@ -1778,11 +1778,12 @@ void ReplayProxy::Proxied_SavePipelineState(ParamSerialiser ¶mser, ReturnSer &m_D3D12PipelineState->vertexShader, &m_D3D12PipelineState->hullShader, &m_D3D12PipelineState->domainShader, &m_D3D12PipelineState->geometryShader, &m_D3D12PipelineState->pixelShader, &m_D3D12PipelineState->computeShader, + &m_D3D12PipelineState->ampShader, &m_D3D12PipelineState->meshShader, }; ResourceId pipe = GetLiveID(m_D3D12PipelineState->pipelineResourceId); - for(int i = 0; i < 6; i++) + for(size_t i = 0; i < ARRAY_COUNT(stages); i++) if(stages[i]->resourceId != ResourceId()) stages[i]->reflection = GetShader(pipe, GetLiveID(stages[i]->resourceId), ShaderEntryPoint()); @@ -1795,7 +1796,7 @@ void ReplayProxy::Proxied_SavePipelineState(ParamSerialiser ¶mser, ReturnSer &m_GLPipelineState->fragmentShader, &m_GLPipelineState->computeShader, }; - for(int i = 0; i < 6; i++) + for(size_t i = 0; i < ARRAY_COUNT(stages); i++) if(stages[i]->shaderResourceId != ResourceId()) stages[i]->reflection = GetShader(ResourceId(), GetLiveID(stages[i]->shaderResourceId), ShaderEntryPoint()); @@ -1806,11 +1807,12 @@ void ReplayProxy::Proxied_SavePipelineState(ParamSerialiser ¶mser, ReturnSer &m_VulkanPipelineState->vertexShader, &m_VulkanPipelineState->tessControlShader, &m_VulkanPipelineState->tessEvalShader, &m_VulkanPipelineState->geometryShader, &m_VulkanPipelineState->fragmentShader, &m_VulkanPipelineState->computeShader, + &m_VulkanPipelineState->taskShader, &m_VulkanPipelineState->meshShader, }; ResourceId pipe = GetLiveID(m_VulkanPipelineState->graphics.pipelineResourceId); - for(int i = 0; i < 6; i++) + for(size_t i = 0; i < ARRAY_COUNT(stages); i++) { if(i == 5) pipe = GetLiveID(m_VulkanPipelineState->compute.pipelineResourceId); @@ -2930,7 +2932,7 @@ bool ReplayProxy::Tick(int type) InitPostVSBuffers(dummy); break; } - case eReplayProxy_GetPostVS: GetPostVSBuffers(0, 0, 0, MeshDataStage::Unknown); break; + case eReplayProxy_GetPostVS: GetPostVSBuffers(0, 0, 0, MeshDataStage::VSIn); break; case eReplayProxy_BuildTargetShader: { rdcstr entry; diff --git a/renderdoc/driver/d3d11/d3d11_context.cpp b/renderdoc/driver/d3d11/d3d11_context.cpp index 314fb0728..c364d6834 100644 --- a/renderdoc/driver/d3d11/d3d11_context.cpp +++ b/renderdoc/driver/d3d11/d3d11_context.cpp @@ -1036,7 +1036,7 @@ void WrappedID3D11DeviceContext::AddUsage(const ActionDescription &a) ////////////////////////////// // Shaders - const D3D11RenderState::Shader *shArr[6] = { + const D3D11RenderState::Shader *shArr[NumShaderStages] = { &pipe->VS, &pipe->HS, &pipe->DS, &pipe->GS, &pipe->PS, &pipe->CS, }; diff --git a/renderdoc/driver/d3d11/d3d11_renderstate.cpp b/renderdoc/driver/d3d11/d3d11_renderstate.cpp index c3208078f..2fb280004 100644 --- a/renderdoc/driver/d3d11/d3d11_renderstate.cpp +++ b/renderdoc/driver/d3d11/d3d11_renderstate.cpp @@ -107,7 +107,7 @@ void D3D11RenderState::ReleaseRefs() IntRelease(IA.VBs[i]); Shader *stages[] = {&VS, &HS, &DS, &GS, &PS, &CS}; - for(int s = 0; s < 6; s++) + for(int s = 0; s < ARRAY_COUNT(stages); s++) { Shader *sh = stages[s]; @@ -176,7 +176,7 @@ void D3D11RenderState::MarkReferenced(WrappedID3D11DeviceContext *ctx, bool init initial ? eFrameRef_None : eFrameRef_Read); const Shader *stages[] = {&VS, &HS, &DS, &GS, &PS, &CS}; - for(int s = 0; s < 6; s++) + for(int s = 0; s < ARRAY_COUNT(stages); s++) { const Shader *sh = stages[s]; @@ -285,7 +285,7 @@ void D3D11RenderState::AddRefs() IntAddRef(IA.VBs[i]); Shader *stages[] = {&VS, &HS, &DS, &GS, &PS, &CS}; - for(int s = 0; s < 6; s++) + for(int s = 0; s < ARRAY_COUNT(stages); s++) { Shader *sh = stages[s]; @@ -606,7 +606,7 @@ void D3D11RenderState::UnbindRangeForRead(const ResourceRange &range) // const char *names[] = { "VS", "DS", "HS", "GS", "PS", "CS" }; Shader *stages[] = {&VS, &HS, &DS, &GS, &PS, &CS}; - for(int s = 0; s < 6; s++) + for(int s = 0; s < ARRAY_COUNT(stages); s++) { Shader *sh = stages[s]; diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index ad547c87b..ac7c039d9 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -802,7 +802,7 @@ void D3D11Replay::SavePipelineState(uint32_t eventId) const D3D11RenderState::Shader *srcArr[] = {&rs->VS, &rs->HS, &rs->DS, &rs->GS, &rs->PS, &rs->CS}; - for(size_t stage = 0; stage < 6; stage++) + for(size_t stage = 0; stage < ARRAY_COUNT(dstArr); stage++) { D3D11Pipe::Shader &dst = *dstArr[stage]; const D3D11RenderState::Shader &src = *srcArr[stage]; diff --git a/renderdoc/driver/d3d12/d3d12_commands.cpp b/renderdoc/driver/d3d12/d3d12_commands.cpp index c50056cc0..a8bdf31c2 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.cpp +++ b/renderdoc/driver/d3d12/d3d12_commands.cpp @@ -2089,7 +2089,7 @@ void D3D12CommandData::AddUsage(const D3D12RenderState &state, D3D12ActionTreeNo if(state.pipe != ResourceId()) pipe = rm->GetCurrentAs(state.pipe); - const ShaderBindpointMapping *bindMap[6] = {}; + const ShaderBindpointMapping *bindMap[NumShaderStages] = {}; if((a.flags & ActionFlags::Dispatch) && state.compute.rootsig != ResourceId()) { diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index 285531b18..cc5812dcf 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -67,8 +67,11 @@ struct QueueReadbackData ID3D12Resource *readbackBuf = NULL; byte *readbackMapped = NULL; uint64_t readbackSize = 0; - ID3D12GraphicsCommandList *lists[6] = {}; - ID3D12CommandAllocator *allocs[6] = {}; + + static const uint32_t NumCommandTypes = 7; + + ID3D12GraphicsCommandList *lists[NumCommandTypes] = {}; + ID3D12CommandAllocator *allocs[NumCommandTypes] = {}; void Resize(uint64_t size); diff --git a/renderdoc/driver/d3d12/d3d12_postvs.cpp b/renderdoc/driver/d3d12/d3d12_postvs.cpp index a7b115fd8..2c19fcd6b 100644 --- a/renderdoc/driver/d3d12/d3d12_postvs.cpp +++ b/renderdoc/driver/d3d12/d3d12_postvs.cpp @@ -220,7 +220,6 @@ void D3D12Replay::InitPostVSBuffers(uint32_t eventId) D3D_PRIMITIVE_TOPOLOGY topo = rs.topo; - ret.vsin.topo = topo; ret.vsout.topo = topo; const ActionDescription *action = m_pDevice->GetAction(eventId); @@ -789,7 +788,6 @@ void D3D12Replay::InitPostVSBuffers(uint32_t eventId) m_SOStagingBuffer->Unmap(0, &range); - ret.vsin.topo = topo; ret.vsout.buf = vsoutBuffer; ret.vsout.vertStride = stride; ret.vsout.nearPlane = nearp; @@ -816,7 +814,6 @@ void D3D12Replay::InitPostVSBuffers(uint32_t eventId) else { // empty vertex output signature - ret.vsin.topo = topo; ret.vsout.buf = NULL; ret.vsout.instStride = 0; ret.vsout.vertStride = 0; diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index 174c28828..347e803dd 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -333,7 +333,7 @@ private: float farPlane = 0.0f; rdcstr status; - } vsin, vsout, gsout; + } vsout, gsout, ampout, meshout; const StageData &GetStage(MeshDataStage type) { @@ -341,10 +341,14 @@ private: return vsout; else if(type == MeshDataStage::GSOut) return gsout; + else if(type == MeshDataStage::TaskOut) + return ampout; + else if(type == MeshDataStage::MeshOut) + return meshout; else RDCERR("Unexpected mesh data stage!"); - return vsin; + return vsout; } }; diff --git a/renderdoc/driver/d3d12/d3d12_shader_feedback.cpp b/renderdoc/driver/d3d12/d3d12_shader_feedback.cpp index d8c51f3dc..7c9fe9ea6 100644 --- a/renderdoc/driver/d3d12/d3d12_shader_feedback.cpp +++ b/renderdoc/driver/d3d12/d3d12_shader_feedback.cpp @@ -1153,7 +1153,7 @@ bool D3D12Replay::FetchShaderFeedback(uint32_t eventId) m_pDevice->GetShaderCache()->LoadDXC(); #endif - bool dynamicAccessPerStage[6] = {}; + bool dynamicAccessPerStage[NumShaderStages] = {}; if(result.compute) { diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index c500d669b..c87abc341 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -902,8 +902,8 @@ struct ShaderReflection; struct PerStageReflections { - const ShaderReflection *refls[6] = {}; - const ShaderBindpointMapping *mappings[6] = {}; + const ShaderReflection *refls[NumShaderStages] = {}; + const ShaderBindpointMapping *mappings[NumShaderStages] = {}; }; void CopyProgramUniforms(const PerStageReflections &srcStages, GLuint progSrc, diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index f8ad55105..4077248c6 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -1818,7 +1818,7 @@ void WrappedOpenGL::RefreshDerivedReplacements() bool usesReplacedShader = false; - for(int i = 0; i < 6; i++) + for(size_t i = 0; i < NumShaderStages; i++) { if(GetResourceManager()->HasReplacement( GetResourceManager()->GetOriginalID(progdata.stageShaders[i]))) @@ -1839,7 +1839,7 @@ void WrappedOpenGL::RefreshDerivedReplacements() ResourceId progdstid = GetResourceManager()->GetResID(ProgramRes(GetCtx(), progdst)); // attach shaders, going via the original ID to pick up replacements - for(int i = 0; i < 6; i++) + for(size_t i = 0; i < NumShaderStages; i++) { if(progdata.stageShaders[i] != ResourceId()) { @@ -1947,7 +1947,7 @@ void WrappedOpenGL::RefreshDerivedReplacements() bool usesReplacedProgram = false; - for(int i = 0; i < 6; i++) + for(size_t i = 0; i < NumShaderStages; i++) { if(GetResourceManager()->HasReplacement( GetResourceManager()->GetOriginalID(pipedata.stagePrograms[i]))) @@ -1967,7 +1967,7 @@ void WrappedOpenGL::RefreshDerivedReplacements() ResourceId pipedstid = GetResourceManager()->GetResID(ProgramPipeRes(GetCtx(), pipedst)); // attach programs, going via the original ID to pick up replacements - for(int i = 0; i < 6; i++) + for(size_t i = 0; i < NumShaderStages; i++) { if(pipedata.stagePrograms[i] != ResourceId()) { @@ -5436,8 +5436,8 @@ void WrappedOpenGL::AddUsage(const ActionDescription &a) GLRenderState rs; rs.FetchState(this); - ShaderReflection *refl[6] = {NULL}; - ShaderBindpointMapping mapping[6]; + ShaderReflection *refl[NumShaderStages] = {NULL}; + ShaderBindpointMapping mapping[NumShaderStages]; GLuint curProg = 0; GL.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&curProg); diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 7971ad277..cde39ec8a 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -757,7 +757,7 @@ public: // the application to modify anything. bool shaderProgramUnlinkable = false; bool linked; - ResourceId stageShaders[6]; + ResourceId stageShaders[NumShaderStages]; // used only when we're capturing and don't have driver-side reflection so we need to emulate glslang::TProgram *glslangProgram = NULL; @@ -778,8 +778,8 @@ public: GLbitfield use; }; - ResourceId stagePrograms[6]; - ResourceId stageShaders[6]; + ResourceId stagePrograms[NumShaderStages]; + ResourceId stageShaders[NumShaderStages]; }; std::map m_Shaders; diff --git a/renderdoc/driver/gl/gl_initstate.h b/renderdoc/driver/gl/gl_initstate.h index 2062c6c90..5ad76a1c9 100644 --- a/renderdoc/driver/gl/gl_initstate.h +++ b/renderdoc/driver/gl/gl_initstate.h @@ -117,6 +117,8 @@ struct PipelineInitialData { bool valid; GLResource programs[6]; + // since this array is serialised (and because GL will never support other shader stages) we leave + // this at 6 instead of NumShaderStages }; DECLARE_REFLECTION_STRUCT(PipelineInitialData); diff --git a/renderdoc/driver/gl/gl_pixelhistory.cpp b/renderdoc/driver/gl/gl_pixelhistory.cpp index 7b9881d35..aa4f434bb 100644 --- a/renderdoc/driver/gl/gl_pixelhistory.cpp +++ b/renderdoc/driver/gl/gl_pixelhistory.cpp @@ -707,14 +707,15 @@ void CopyMSSample(WrappedOpenGL *driver, const GLPixelHistoryResources &resource driver->glUniform1i(depthMSLoc, 0); driver->glUniform1i(stencilMSLoc, 1); - uint32_t newUniforms[6] = {uint32_t(sampleIdx), - uint32_t(x), - uint32_t(y), - 1, - copyFramebuffer.dsTextureId != 0 || copyFramebuffer.depthTextureId != 0, - copyFramebuffer.dsTextureId != 0 || - copyFramebuffer.stencilTextureId != - 0}; // { sampleIdx, x, y, dstOffset, hasDepth, hasStencil } + // { sampleIdx, x, y, dstOffset, hasDepth, hasStencil } + uint32_t newUniforms[6] = { + uint32_t(sampleIdx), + uint32_t(x), + uint32_t(y), + 1, + copyFramebuffer.dsTextureId != 0 || copyFramebuffer.depthTextureId != 0, + copyFramebuffer.dsTextureId != 0 || copyFramebuffer.stencilTextureId != 0, + }; driver->glNamedBufferSubDataEXT(resources.msCopyUniformBlockBuffer, 0, sizeof(newUniforms), newUniforms); diff --git a/renderdoc/driver/gl/gl_program_iterate.cpp b/renderdoc/driver/gl/gl_program_iterate.cpp index b623d7881..dff728a6c 100644 --- a/renderdoc/driver/gl/gl_program_iterate.cpp +++ b/renderdoc/driver/gl/gl_program_iterate.cpp @@ -291,7 +291,7 @@ static void UnrollConstant(rdcarray &unrolled, const Shad static void UnrollConstants(const PerStageReflections &stages, rdcarray &globals) { - for(size_t s = 0; s < 6; s++) + for(size_t s = 0; s < NumShaderStages; s++) { if(!stages.refls[s]) continue; @@ -569,12 +569,12 @@ static void ForAllProgramUniforms(SerialiserType *ser, CaptureState state, // we only need to process uniform values - for compatibility we still serialise the same, but we // skip fetching or applying UBO bindings etc. bool IsSrcProgramSPIRV = false; - for(size_t i = 0; i < 6; i++) + for(size_t i = 0; i < NumShaderStages; i++) IsSrcProgramSPIRV |= srcStages.refls[i] && srcStages.refls[i]->encoding == ShaderEncoding::OpenGLSPIRV; bool IsDstProgramSPIRV = false; - for(size_t i = 0; i < 6; i++) + for(size_t i = 0; i < NumShaderStages; i++) IsDstProgramSPIRV |= dstStages.refls[i] && dstStages.refls[i]->encoding == ShaderEncoding::OpenGLSPIRV; @@ -1268,7 +1268,7 @@ bool SerialiseProgramBindings(SerialiserType &ser, CaptureState state, // instead just skip the fetch & apply steps, so that we can still serialise in a backwards // compatible way. bool IsProgramSPIRV = false; - for(size_t i = 0; i < 6; i++) + for(size_t i = 0; i < NumShaderStages; i++) IsProgramSPIRV |= stages.refls[i] && stages.refls[i]->encoding == ShaderEncoding::OpenGLSPIRV; const bool hasVert = stages.refls[0] != NULL; diff --git a/renderdoc/driver/gl/gl_renderstate.h b/renderdoc/driver/gl/gl_renderstate.h index c99c206d0..2d011288d 100644 --- a/renderdoc/driver/gl/gl_renderstate.h +++ b/renderdoc/driver/gl/gl_renderstate.h @@ -157,6 +157,8 @@ struct GLRenderState GLint numSubroutines; GLuint Values[128]; } Subroutines[6]; + // since this array is serialised (and because GL will never support other shader stages) we leave + // this at 6 instead of NumShaderStages enum { diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 51f28ae99..1921d361e 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -1054,16 +1054,19 @@ void GLReplay::SavePipelineState(uint32_t eventId) GLuint curProg = 0; drv.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&curProg); - GLPipe::Shader *stages[6] = { + GLPipe::Shader *stages[NumShaderStages] = { &pipe.vertexShader, &pipe.tessControlShader, &pipe.tessEvalShader, &pipe.geometryShader, &pipe.fragmentShader, &pipe.computeShader, }; - ShaderReflection *refls[6] = {NULL}; - ShaderBindpointMapping *mappings[6] = {NULL}; - bool spirv[6] = {false}; + ShaderReflection *refls[NumShaderStages] = {NULL}; + ShaderBindpointMapping *mappings[NumShaderStages] = {NULL}; + bool spirv[NumShaderStages] = {false}; - for(int i = 0; i < 6; i++) + for(size_t i = 0; i < NumShaderStages; i++) { + if(!stages[i]) + continue; + stages[i]->programResourceId = stages[i]->shaderResourceId = ResourceId(); stages[i]->reflection = NULL; stages[i]->bindpointMapping = ShaderBindpointMapping(); @@ -1090,6 +1093,9 @@ void GLReplay::SavePipelineState(uint32_t eventId) for(size_t i = 0; i < ARRAY_COUNT(pipeDetails.stageShaders); i++) { + if(!stages[i]) + continue; + if(pipeDetails.stageShaders[i] != ResourceId()) { curProg = rm->GetCurrentResource(pipeDetails.stagePrograms[i]).name; @@ -1134,6 +1140,9 @@ void GLReplay::SavePipelineState(uint32_t eventId) for(size_t i = 0; i < ARRAY_COUNT(progDetails.stageShaders); i++) { + if(!stages[i]) + continue; + if(progDetails.stageShaders[i] != ResourceId()) { auto &shaderDetails = m_pDriver->m_Shaders[progDetails.stageShaders[i]]; @@ -1214,7 +1223,7 @@ void GLReplay::SavePipelineState(uint32_t eventId) pipe.transformFeedback.active = (p != 0) || m_pDriver->m_WasActiveFeedback; } - for(int i = 0; i < 6; i++) + for(size_t i = 0; i < ARRAY_COUNT(rs.Subroutines); i++) { size_t num = RDCMIN(128, rs.Subroutines[i].numSubroutines); if(num == 0) diff --git a/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp index a142aebea..0b54932ee 100644 --- a/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp @@ -842,7 +842,7 @@ bool WrappedOpenGL::Serialise_glLinkProgram(SerialiserType &ser, GLuint programH progDetails.linked = true; - for(size_t s = 0; s < 6; s++) + for(size_t s = 0; s < NumShaderStages; s++) { for(size_t sh = 0; sh < progDetails.shaders.size(); sh++) { @@ -916,7 +916,7 @@ void WrappedOpenGL::glLinkProgram(GLuint program) progDetails.linked = true; - for(size_t s = 0; s < 6; s++) + for(size_t s = 0; s < NumShaderStages; s++) { for(size_t sh = 0; sh < progDetails.shaders.size(); sh++) { @@ -1494,7 +1494,7 @@ bool WrappedOpenGL::Serialise_glUseProgramStages(SerialiserType &ser, GLuint pip PipelineData &pipeDetails = m_Pipelines[livePipeId]; ProgramData &progDetails = m_Programs[liveProgId]; - for(size_t s = 0; s < 6; s++) + for(size_t s = 0; s < NumShaderStages; s++) { if(stages & ShaderBit(s)) { @@ -1517,7 +1517,7 @@ bool WrappedOpenGL::Serialise_glUseProgramStages(SerialiserType &ser, GLuint pip ResourceId livePipeId = GetResourceManager()->GetResID(pipeline); PipelineData &pipeDetails = m_Pipelines[livePipeId]; - for(size_t s = 0; s < 6; s++) + for(size_t s = 0; s < NumShaderStages; s++) { if(stages & ShaderBit(s)) { @@ -1593,7 +1593,7 @@ void WrappedOpenGL::glUseProgramStages(GLuint pipeline, GLbitfield stages, GLuin PipelineData &pipeDetails = m_Pipelines[pipeID]; ProgramData &progDetails = m_Programs[progID]; - for(size_t s = 0; s < 6; s++) + for(size_t s = 0; s < NumShaderStages; s++) { if(stages & ShaderBit(s)) { @@ -1614,7 +1614,7 @@ void WrappedOpenGL::glUseProgramStages(GLuint pipeline, GLbitfield stages, GLuin ResourceId pipeID = GetResourceManager()->GetResID(ProgramPipeRes(GetCtx(), pipeline)); PipelineData &pipeDetails = m_Pipelines[pipeID]; - for(size_t s = 0; s < 6; s++) + for(size_t s = 0; s < NumShaderStages; s++) { if(stages & ShaderBit(s)) { diff --git a/renderdoc/driver/ihv/amd/amd_isa.cpp b/renderdoc/driver/ihv/amd/amd_isa.cpp index 7a2731114..2cbd5a8f9 100644 --- a/renderdoc/driver/ihv/amd/amd_isa.cpp +++ b/renderdoc/driver/ihv/amd/amd_isa.cpp @@ -296,6 +296,8 @@ rdcstr DisassembleSPIRV(ShaderStage stage, const bytebuf &shaderBytes, const rdc case ShaderStage::Geometry: stageName = "geom"; break; case ShaderStage::Fragment: stageName = "frag"; break; case ShaderStage::Compute: stageName = "comp"; break; + case ShaderStage::Task: stageName = "task"; break; + case ShaderStage::Mesh: stageName = "mesh"; break; case ShaderStage::Count: return "; Cannot identify shader type"; } @@ -400,6 +402,14 @@ rdcstr DisassembleGLSL(ShaderStage stage, const bytebuf &shaderBytes, const rdcs stageIndex = 5; stageName = "comp"; break; + case ShaderStage::Task: + stageIndex = 6; + stageName = "task"; + break; + case ShaderStage::Mesh: + stageIndex = 7; + stageName = "mesh"; + break; case ShaderStage::Count: return "; Cannot identify shader type"; } diff --git a/renderdoc/driver/ihv/nv/nv_vk_counters.cpp b/renderdoc/driver/ihv/nv/nv_vk_counters.cpp index 62881cb36..1e6ebfc52 100644 --- a/renderdoc/driver/ihv/nv/nv_vk_counters.cpp +++ b/renderdoc/driver/ihv/nv/nv_vk_counters.cpp @@ -148,8 +148,9 @@ struct NVVulkanCounters::Impl if(actionnode.events.empty()) return false; // Skip nodes with no events - if(!(actionnode.flags & (ActionFlags::Clear | ActionFlags::Drawcall | ActionFlags::Dispatch | - ActionFlags::Present | ActionFlags::Copy | ActionFlags::Resolve))) + if(!(actionnode.flags & + (ActionFlags::Clear | ActionFlags::MeshDispatch | ActionFlags::Drawcall | + ActionFlags::Dispatch | ActionFlags::Present | ActionFlags::Copy | ActionFlags::Resolve))) return false; // Filter out events we cannot profile return true; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_container.cpp b/renderdoc/driver/shaders/dxbc/dxbc_container.cpp index d221ef32d..1f95edaae 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_container.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_container.cpp @@ -1785,7 +1785,7 @@ DXBCContainer::DXBCContainer(const bytebuf &ByteCode, const rdcstr &debugInfoPat desc.regChannelMask = (uint8_t)(el->mask & 0xff); desc.channelUsedMask = (uint8_t)(el->rwMask & 0xff); desc.regIndex = el->registerNum; - desc.semanticIndex = el->semanticIdx; + desc.semanticIndex = (uint16_t)el->semanticIdx; desc.semanticName = chunkContents + el->nameOffset; desc.systemValue = GetSystemValue(el->systemType); desc.compCount = (desc.regChannelMask & 0x1 ? 1 : 0) + (desc.regChannelMask & 0x2 ? 1 : 0) + diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp index 38796f881..6a700451e 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp @@ -5127,7 +5127,8 @@ void GatherPSInputDataForInitialValues(const DXBC::DXBCContainer *dxbc, } if(arrayLength > 0) - arrays.push_back(make_rdcpair(sig.semanticName, make_rdcpair(sig.semanticIndex, nextIdx - 1))); + arrays.push_back( + make_rdcpair(sig.semanticName, make_rdcpair((uint32_t)sig.semanticIndex, nextIdx - 1))); } if(included) diff --git a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp index eee63555d..99b0ac911 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp @@ -277,6 +277,8 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl, case DXBC::ShaderType::Hull: refl->stage = ShaderStage::Hull; break; case DXBC::ShaderType::Domain: refl->stage = ShaderStage::Domain; break; case DXBC::ShaderType::Compute: refl->stage = ShaderStage::Compute; break; + case DXBC::ShaderType::Amplification: refl->stage = ShaderStage::Amplification; break; + case DXBC::ShaderType::Mesh: refl->stage = ShaderStage::Mesh; break; default: RDCERR("Unexpected DXBC shader type %u", dxbc->m_Type); refl->stage = ShaderStage::Vertex; diff --git a/renderdoc/driver/shaders/spirv/spirv_common.cpp b/renderdoc/driver/shaders/spirv/spirv_common.cpp index 922fca925..77a50e063 100644 --- a/renderdoc/driver/shaders/spirv/spirv_common.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_common.cpp @@ -100,9 +100,9 @@ ShaderStage MakeShaderStage(rdcspv::ExecutionModel model) case rdcspv::ExecutionModel::Geometry: return ShaderStage::Geometry; case rdcspv::ExecutionModel::Fragment: return ShaderStage::Fragment; case rdcspv::ExecutionModel::GLCompute: return ShaderStage::Compute; + case rdcspv::ExecutionModel::TaskEXT: return ShaderStage::Task; + case rdcspv::ExecutionModel::MeshEXT: return ShaderStage::Mesh; case rdcspv::ExecutionModel::Kernel: - case rdcspv::ExecutionModel::TaskEXT: - case rdcspv::ExecutionModel::MeshEXT: case rdcspv::ExecutionModel::RayGenerationKHR: case rdcspv::ExecutionModel::IntersectionKHR: case rdcspv::ExecutionModel::AnyHitKHR: @@ -181,6 +181,10 @@ ShaderBuiltin MakeShaderBuiltin(ShaderStage stage, const rdcspv::BuiltIn el) case rdcspv::BuiltIn::BaryCoordKHR: return ShaderBuiltin::Barycentrics; case rdcspv::BuiltIn::FragSizeEXT: return ShaderBuiltin::FragAreaSize; case rdcspv::BuiltIn::FragInvocationCountEXT: return ShaderBuiltin::FragInvocationCount; + case rdcspv::BuiltIn::PrimitivePointIndicesEXT: return ShaderBuiltin::OutputIndices; + case rdcspv::BuiltIn::PrimitiveLineIndicesEXT: return ShaderBuiltin::OutputIndices; + case rdcspv::BuiltIn::PrimitiveTriangleIndicesEXT: return ShaderBuiltin::OutputIndices; + case rdcspv::BuiltIn::CullPrimitiveEXT: return ShaderBuiltin::CullPrimitive; default: break; } diff --git a/renderdoc/driver/shaders/spirv/spirv_compile.cpp b/renderdoc/driver/shaders/spirv/spirv_compile.cpp index 16c47c831..8319db76d 100644 --- a/renderdoc/driver/shaders/spirv/spirv_compile.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_compile.cpp @@ -59,7 +59,9 @@ rdcstr rdcspv::Compile(const rdcspv::CompilationSettings &settings, const rdcarr (int)EShLangTessControl == (int)rdcspv::ShaderStage::TessControl && (int)EShLangTessEvaluation == (int)rdcspv::ShaderStage::TessEvaluation && (int)EShLangGeometry == (int)rdcspv::ShaderStage::Geometry && - (int)EShLangCompute == (int)rdcspv::ShaderStage::Compute, + (int)EShLangCompute == (int)rdcspv::ShaderStage::Compute && + (int)EShLangTask == (int)rdcspv::ShaderStage::Task && + (int)EShLangMesh == (int)rdcspv::ShaderStage::Mesh, "Shader language enums don't match"); { diff --git a/renderdoc/driver/shaders/spirv/spirv_compile.h b/renderdoc/driver/shaders/spirv/spirv_compile.h index ebbdeebc0..c5c0d253e 100644 --- a/renderdoc/driver/shaders/spirv/spirv_compile.h +++ b/renderdoc/driver/shaders/spirv/spirv_compile.h @@ -37,6 +37,9 @@ enum class ShaderStage Geometry, Fragment, Compute, + // gap of 6 for RT shaders + Task = Compute + 7, + Mesh, Invalid, }; diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp index bb06e024f..21b76b071 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp @@ -278,8 +278,14 @@ static int32_t GetBinding(uint32_t binding) return binding == ~0U ? INVALID_BIND : (uint32_t)binding; } -static bool IsStrippableBuiltin(rdcspv::BuiltIn builtin) +static bool IsStrippableBuiltin(rdcspv::BuiltIn builtin, bool perPrimitive) { + if(perPrimitive && + (builtin == rdcspv::BuiltIn::PrimitiveId || builtin == rdcspv::BuiltIn::Layer || + builtin == rdcspv::BuiltIn::ViewportIndex || builtin == rdcspv::BuiltIn::CullPrimitiveEXT || + builtin == rdcspv::BuiltIn::ShadingRateKHR)) + return true; + return builtin == rdcspv::BuiltIn::PointSize || builtin == rdcspv::BuiltIn::ClipDistance || builtin == rdcspv::BuiltIn::CullDistance; } @@ -871,6 +877,18 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st reflection.dispatchThreadsDimension[2] = e.executionModes.localSize.z; } + { + int idx = e.executionModes.others.indexOf(rdcspv::ExecutionMode::OutputVertices); + if(idx >= 0) + patchData.maxVertices = e.executionModes.others[idx].outputVertices; + } + + { + int idx = e.executionModes.others.indexOf(rdcspv::ExecutionMode::OutputPrimitivesEXT); + if(idx >= 0) + patchData.maxPrimitives = e.executionModes.others[idx].outputPrimitivesEXT; + } + // vulkan spec says "If an object is decorated with the WorkgroupSize decoration, this must take // precedence over any execution mode set for LocalSize." for(auto it : constants) @@ -968,6 +986,10 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st std::set usedIds; std::map> usedStructChildren; + // for arrayed top level builtins like gl_MeshPrimitivesEXT[] there could be an access chain + // first with just the array index, then later the access to the builtin. This map tracks those + // first access chains so the second one can reference the original global + std::map topLevelChildChain; // build the static call tree from the entry point, and build a list of all IDs referenced { @@ -993,10 +1015,37 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st { OpAccessChain access(it); + const DataType &pointeeType = dataTypes[dataTypes[idTypes[access.base]].InnerType()]; + + if(pointeeType.type == DataType::ArrayType) + { + const DataType &innerType = dataTypes[pointeeType.InnerType()]; + + if(innerType.type == DataType::StructType && + (innerType.children[0].decorations.flags & rdcspv::Decorations::HasBuiltIn)) + { + if(access.indexes.size() == 1) + { + topLevelChildChain[access.result] = access.base; + } + else if(access.indexes.size() == 2) + { + usedStructChildren[access.base].insert( + EvaluateConstant(access.indexes[1], specInfo).value.u32v[0]); + } + } + } // save top-level children referenced in structs - if(dataTypes[dataTypes[idTypes[access.base]].InnerType()].type == DataType::StructType) - usedStructChildren[access.base].insert( + else if(pointeeType.type == DataType::StructType) + { + rdcspv::Id globalId = access.base; + + if(topLevelChildChain.find(access.base) != topLevelChildChain.end()) + globalId = topLevelChildChain[access.base]; + + usedStructChildren[globalId].insert( EvaluateConstant(access.indexes[0], specInfo).value.u32v[0]); + } } if(it.opcode() == Op::FunctionCall) @@ -1078,7 +1127,10 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st // // Some compilers generate global variables instead of members of a global struct. If this is // a directly decorated builtin variable which is never used, skip it - if(IsStrippableBuiltin(decorations[global.id].builtIn) && !used) + if(IsStrippableBuiltin( + decorations[global.id].builtIn, + decorations[global.id].others.contains(rdcspv::Decoration::PerPrimitiveEXT)) && + !used) continue; // move to the inner struct if this is an array of structs - e.g. for arrayed shader outputs @@ -1123,7 +1175,9 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st continue; // skip this member if it's unused and of a type that is commonly included 'by accident' - if(IsStrippableBuiltin(structType->children[i].decorations.builtIn) && + if(IsStrippableBuiltin(structType->children[i].decorations.builtIn, + structType->children[i].decorations.others.contains( + rdcspv::Decoration::PerPrimitiveEXT)) && usedchildren.find(i) == usedchildren.end()) continue; @@ -1951,6 +2005,9 @@ void Reflector::AddSignatureParameter(const bool isInput, const ShaderStage stag if(varDecorations.builtIn != BuiltIn::Invalid) sig.systemValue = MakeShaderBuiltin(stage, varDecorations.builtIn); + if(varDecorations.others.contains(rdcspv::Decoration::PerPrimitiveEXT)) + sig.perPrimitiveRate = true; + // fragment shader outputs are implicitly colour outputs. All other builtin outputs do not have a // register index if(stage == ShaderStage::Fragment && !isInput && sig.systemValue == ShaderBuiltin::Undefined) @@ -1981,6 +2038,13 @@ void Reflector::AddSignatureParameter(const bool isInput, const ShaderStage stag if(stage == ShaderStage::Tess_Control) arraySize = 1; + // for mesh shaders too, ignore the root level of array-ness for outputs + if(stage == ShaderStage::Mesh && !isInput) + { + arraySize = 1; + isArray = false; + } + // if this is a root array in the geometry shader, don't reflect it as an array either if(stage == ShaderStage::Geometry && isInput) isArray = false; @@ -2091,6 +2155,21 @@ void Reflector::AddSignatureParameter(const bool isInput, const ShaderStage stag if(isArray) n += StringFormat::Fmt("[%u]", a); + // remove certain common prefixes that generate only useless noise from GLSL. This is mostly + // irrelevant for the majority of cases but is primarily relevant for single-component outputs + // like gl_PointSize or gl_CullPrimitiveEXT + const rdcstr prefixesToRemove[] = { + "gl_PerVertex.", "gl_PerVertex_var.", "gl_MeshVerticesEXT.", + "gl_MeshVerticesEXT_var.", "gl_MeshPrimitivesEXT.", "gl_MeshPrimitivesEXT_var.", + }; + + for(const rdcstr &prefix : prefixesToRemove) + { + int offs = n.find(prefix); + if(offs == 0) + n.erase(0, prefix.length()); + } + sig.varName = n; if(varType->matrix().count <= 1) diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.h b/renderdoc/driver/shaders/spirv/spirv_reflect.h index 3f3929be2..c72b70cba 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.h +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.h @@ -69,6 +69,9 @@ struct SPIRVPatchData // offset of a spec ID. rdcarray specIDs; + // for mesh shaders, the maximum number of vertices/primitives generated by each meshlet + uint32_t maxVertices = 0, maxPrimitives = 0; + // the output topology for tessellation and geometry shaders Topology outTopo = Topology::Unknown; diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 51ebfc130..9341948fa 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -2670,7 +2670,9 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, // start with the limits as they are, and subtract off them incrementally. When any limit would // drop below 0, we fail. - uint32_t maxPerStageDescriptorSamplers[6] = { + uint32_t maxPerStageDescriptorSamplers[NumShaderStages] = { + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSamplers, + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSamplers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSamplers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSamplers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSamplers, @@ -2678,7 +2680,9 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSamplers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSamplers, }; - uint32_t maxPerStageDescriptorUniformBuffers[6] = { + uint32_t maxPerStageDescriptorUniformBuffers[NumShaderStages] = { + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorUniformBuffers, + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorUniformBuffers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorUniformBuffers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorUniformBuffers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorUniformBuffers, @@ -2686,7 +2690,9 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorUniformBuffers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorUniformBuffers, }; - uint32_t maxPerStageDescriptorStorageBuffers[6] = { + uint32_t maxPerStageDescriptorStorageBuffers[NumShaderStages] = { + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageBuffers, + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageBuffers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageBuffers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageBuffers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageBuffers, @@ -2694,7 +2700,9 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageBuffers, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageBuffers, }; - uint32_t maxPerStageDescriptorSampledImages[6] = { + uint32_t maxPerStageDescriptorSampledImages[NumShaderStages] = { + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSampledImages, + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSampledImages, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSampledImages, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSampledImages, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSampledImages, @@ -2702,7 +2710,9 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSampledImages, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorSampledImages, }; - uint32_t maxPerStageDescriptorStorageImages[6] = { + uint32_t maxPerStageDescriptorStorageImages[NumShaderStages] = { + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageImages, + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageImages, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageImages, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageImages, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageImages, @@ -2710,7 +2720,9 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageImages, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorStorageImages, }; - uint32_t maxPerStageDescriptorInputAttachments[6] = { + uint32_t maxPerStageDescriptorInputAttachments[NumShaderStages] = { + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorInputAttachments, + m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorInputAttachments, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorInputAttachments, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorInputAttachments, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorInputAttachments, @@ -2718,7 +2730,9 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorInputAttachments, m_pDriver->GetDeviceProps().limits.maxPerStageDescriptorInputAttachments, }; - uint32_t maxPerStageResources[6] = { + uint32_t maxPerStageResources[NumShaderStages] = { + m_pDriver->GetDeviceProps().limits.maxPerStageResources, + m_pDriver->GetDeviceProps().limits.maxPerStageResources, m_pDriver->GetDeviceProps().limits.maxPerStageResources, m_pDriver->GetDeviceProps().limits.maxPerStageResources, m_pDriver->GetDeviceProps().limits.maxPerStageResources, @@ -2743,7 +2757,7 @@ void VulkanReplay::PatchReservedDescriptors(const VulkanStatePipeline &pipe, m_pDriver->GetDeviceProps().limits.maxDescriptorSetInputAttachments; uint32_t maxDescriptorSetInlineUniformBlocks = 0; - uint32_t maxPerStageDescriptorInlineUniformBlocks[6] = {}; + uint32_t maxPerStageDescriptorInlineUniformBlocks[NumShaderStages] = {}; if(m_pDriver->GetExtensions(NULL).ext_EXT_inline_uniform_block) { diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index acc4aa5ba..64fac6ad6 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -352,7 +352,7 @@ struct VulkanCreationInfo rdcarray specialization; }; - Shader shaders[6]; + Shader shaders[NumShaderStages]; // VkPipelineVertexInputStateCreateInfo struct VertBinding diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index bb16fc0f0..6393ae2a7 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -2678,6 +2678,8 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D MeshFormat fmt = GetPostVSBuffers(events[i], inst, 0, MeshDataStage::GSOut); if(fmt.vertexResourceId == ResourceId()) fmt = GetPostVSBuffers(events[i], inst, 0, MeshDataStage::VSOut); + if(fmt.vertexResourceId == ResourceId()) + fmt = GetPostVSBuffers(events[i], inst, 0, MeshDataStage::MeshOut); if(fmt.vertexResourceId != ResourceId()) { diff --git a/renderdoc/driver/vulkan/vk_postvs.cpp b/renderdoc/driver/vulkan/vk_postvs.cpp index ac9b8750e..f5010040f 100644 --- a/renderdoc/driver/vulkan/vk_postvs.cpp +++ b/renderdoc/driver/vulkan/vk_postvs.cpp @@ -1515,7 +1515,6 @@ void VulkanReplay::FetchVSOut(uint32_t eventId, VulkanRenderState &state) // set defaults so that we don't try to fetch this output again if something goes wrong and the // same event is selected again { - ret.vsin.topo = state.primitiveTopology; ret.vsout.buf = VK_NULL_HANDLE; ret.vsout.bufmem = VK_NULL_HANDLE; ret.vsout.instStride = 0; @@ -2880,7 +2879,6 @@ void VulkanReplay::FetchVSOut(uint32_t eventId, VulkanRenderState &state) } // fill out m_PostVS.Data - ret.vsin.topo = state.primitiveTopology; ret.vsout.topo = state.primitiveTopology; ret.vsout.buf = meshBuffer; ret.vsout.bufmem = meshMem; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 2a3049a9b..d49176a94 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -265,7 +265,7 @@ rdcarray VulkanReplay::GetPassEvents(uint32_t eventId) // so we don't actually do anything (init postvs/action overlay) // but it's useful to have the first part of the pass as part // of the list - if(start->flags & (ActionFlags::Drawcall | ActionFlags::PassBoundary)) + if(start->flags & (ActionFlags::MeshDispatch | ActionFlags::Drawcall | ActionFlags::PassBoundary)) passEvents.push_back(start->eventId); start = start->next; @@ -4390,6 +4390,8 @@ void VulkanReplay::BuildTargetShader(ShaderEncoding sourceEncoding, const bytebu case ShaderStage::Geometry: stage = rdcspv::ShaderStage::Geometry; break; case ShaderStage::Pixel: stage = rdcspv::ShaderStage::Fragment; break; case ShaderStage::Compute: stage = rdcspv::ShaderStage::Compute; break; + case ShaderStage::Task: stage = rdcspv::ShaderStage::Task; break; + case ShaderStage::Mesh: stage = rdcspv::ShaderStage::Mesh; break; default: RDCERR("Unexpected type in BuildShader!"); id = ResourceId(); diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index c5af74e05..93019ea5d 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -191,13 +191,14 @@ struct VulkanPostVSData float farPlane; rdcstr status; - } vsin, vsout, gsout; + } vsout, gsout, taskout, meshout; VulkanPostVSData() { - RDCEraseEl(vsin); RDCEraseEl(vsout); RDCEraseEl(gsout); + RDCEraseEl(taskout); + RDCEraseEl(meshout); } const StageData &GetStage(MeshDataStage type) @@ -206,10 +207,14 @@ struct VulkanPostVSData return vsout; else if(type == MeshDataStage::GSOut) return gsout; + else if(type == MeshDataStage::TaskOut) + return taskout; + else if(type == MeshDataStage::MeshOut) + return meshout; else RDCERR("Unexpected mesh data stage!"); - return vsin; + return vsout; } }; @@ -459,6 +464,7 @@ private: void FetchVSOut(uint32_t eventId, VulkanRenderState &state); void FetchTessGSOut(uint32_t eventId, VulkanRenderState &state); + void FetchMeshOut(uint32_t eventId, VulkanRenderState &state); void ClearPostVSCache(); void RefreshDerivedReplacements(); diff --git a/renderdoc/driver/vulkan/vk_shader_cache.cpp b/renderdoc/driver/vulkan/vk_shader_cache.cpp index 473503141..52a700502 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.cpp +++ b/renderdoc/driver/vulkan/vk_shader_cache.cpp @@ -544,8 +544,8 @@ void VulkanShaderCache::MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &p VulkanResourceManager *rm = m_pDriver->GetResourceManager(); - static VkPipelineShaderStageCreateInfo stages[6]; - static VkSpecializationInfo specInfo[6]; + static VkPipelineShaderStageCreateInfo stages[NumShaderStages]; + static VkSpecializationInfo specInfo[NumShaderStages]; static rdcarray specMapEntries; // the specialization constants can't use more than a uint64_t, so we just over-allocate @@ -553,7 +553,7 @@ void VulkanShaderCache::MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &p size_t specEntries = 0; - for(uint32_t i = 0; i < 6; i++) + for(uint32_t i = 0; i < NumShaderStages; i++) specEntries += pipeInfo.shaders[i].specialization.size(); specMapEntries.resize(specEntries); @@ -566,7 +566,7 @@ void VulkanShaderCache::MakeGraphicsPipelineInfo(VkGraphicsPipelineCreateInfo &p uint32_t dataOffset = 0; // reserve space for spec constants - for(uint32_t i = 0; i < 6; i++) + for(uint32_t i = 0; i < NumShaderStages; i++) { if(pipeInfo.shaders[i].module != ResourceId()) { diff --git a/renderdoc/driver/vulkan/vk_shader_feedback.cpp b/renderdoc/driver/vulkan/vk_shader_feedback.cpp index ff476ccf8..02a96a438 100644 --- a/renderdoc/driver/vulkan/vk_shader_feedback.cpp +++ b/renderdoc/driver/vulkan/vk_shader_feedback.cpp @@ -1761,14 +1761,14 @@ bool VulkanReplay::FetchShaderFeedback(uint32_t eventId) // create vertex shader with modified code VkShaderModuleCreateInfo moduleCreateInfo = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; - VkShaderModule modules[6] = {}; + VkShaderModule modules[NumShaderStages] = {}; - const rdcstr filename[6] = { - "bindless_vertex.spv", "bindless_hull.spv", "bindless_domain.spv", - "bindless_geometry.spv", "bindless_pixel.spv", "bindless_compute.spv", + const rdcstr filename[NumShaderStages] = { + "bindless_vertex.spv", "bindless_hull.spv", "bindless_domain.spv", "bindless_geometry.spv", + "bindless_pixel.spv", "bindless_compute.spv", "bindless_task.spv", "bindless_mesh.spv", }; - std::map printfData[6]; + std::map printfData[NumShaderStages]; if(result.compute) { diff --git a/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp index 2190f4871..9adf93147 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp @@ -490,7 +490,7 @@ bool WrappedVulkan::Serialise_vkCreateGraphicsPipelines( GetResourceManager()->AddLiveResource(Pipeline, pipe); VkGraphicsPipelineCreateInfo shadInstantiatedInfo = CreateInfo; - VkPipelineShaderStageCreateInfo shadInstantiations[6]; + VkPipelineShaderStageCreateInfo shadInstantiations[NumShaderStages]; // search for inline shaders, and create shader modules for them so we have objects to pull // out for recreating graphics pipelines (and to replace for shader editing) diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 54d3b48d6..4c1fb4b6d 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -157,6 +157,7 @@ void DoSerialise(SerialiserType &ser, SigParameter &el) SERIALISE_MEMBER(needSemanticIndex); SERIALISE_MEMBER(compCount); SERIALISE_MEMBER(stream); + SERIALISE_MEMBER(perPrimitiveRate); SIZE_CHECK(96); } @@ -290,6 +291,7 @@ void DoSerialise(SerialiserType &ser, ShaderReflection &el) SERIALISE_MEMBER(encoding); SERIALISE_MEMBER(rawBytes); + SERIALISE_MEMBER(outputTopology); SERIALISE_MEMBER(dispatchThreadsDimension); SERIALISE_MEMBER(inputSignature); @@ -306,7 +308,9 @@ void DoSerialise(SerialiserType &ser, ShaderReflection &el) SERIALISE_MEMBER(pointerTypes); - SIZE_CHECK(392); + SERIALISE_MEMBER(taskPayload); + + SIZE_CHECK(456); } template @@ -783,6 +787,25 @@ void DoSerialise(SerialiserType &ser, FrameRecord &el) SIZE_CHECK(528); } +template +void DoSerialise(SerialiserType &ser, TaskGroupSize &el) +{ + SERIALISE_MEMBER(x); + SERIALISE_MEMBER(y); + SERIALISE_MEMBER(z); + + SIZE_CHECK(12); +} + +template +void DoSerialise(SerialiserType &ser, MeshletSize &el) +{ + SERIALISE_MEMBER(numIndices); + SERIALISE_MEMBER(numVertices); + + SIZE_CHECK(8); +} + template void DoSerialise(SerialiserType &ser, MeshFormat &el) { @@ -795,6 +818,11 @@ void DoSerialise(SerialiserType &ser, MeshFormat &el) SERIALISE_MEMBER(vertexByteOffset); SERIALISE_MEMBER(vertexByteStride); SERIALISE_MEMBER(vertexByteSize); + SERIALISE_MEMBER(meshletSizes); + SERIALISE_MEMBER(taskSizes); + SERIALISE_MEMBER(meshletIndexOffset); + SERIALISE_MEMBER(perPrimitiveOffset); + SERIALISE_MEMBER(perPrimitiveStride); SERIALISE_MEMBER(format); SERIALISE_MEMBER(meshColor); SERIALISE_MEMBER(topology); @@ -807,7 +835,7 @@ void DoSerialise(SerialiserType &ser, MeshFormat &el) SERIALISE_MEMBER(showAlpha); SERIALISE_MEMBER(status); - SIZE_CHECK(152); + SIZE_CHECK(224); } template @@ -1029,6 +1057,16 @@ void DoSerialise(SerialiserType &ser, StencilFace &el) SIZE_CHECK(28); } +template +void DoSerialise(SerialiserType &ser, ShaderMeshMessageLocation &el) +{ + SERIALISE_MEMBER(taskGroup); + SERIALISE_MEMBER(meshGroup); + SERIALISE_MEMBER(thread); + + SIZE_CHECK(36); +} + template void DoSerialise(SerialiserType &ser, ShaderComputeMessageLocation &el) { @@ -1071,9 +1109,9 @@ void DoSerialise(SerialiserType &ser, ShaderGeometryMessageLocation &el) template void DoSerialise(SerialiserType &ser, ShaderMessageLocation &el) { - SERIALISE_MEMBER(compute); + SERIALISE_MEMBER(mesh); - SIZE_CHECK(24); + SIZE_CHECK(36); } template @@ -1083,7 +1121,7 @@ void DoSerialise(SerialiserType &ser, ShaderMessage &el) SERIALISE_MEMBER(location); SERIALISE_MEMBER(message); - SIZE_CHECK(56); + SIZE_CHECK(72); } #pragma endregion @@ -1604,6 +1642,8 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::State &el) SERIALISE_MEMBER(geometryShader); SERIALISE_MEMBER(pixelShader); SERIALISE_MEMBER(computeShader); + SERIALISE_MEMBER(ampShader); + SERIALISE_MEMBER(meshShader); SERIALISE_MEMBER(streamOut); @@ -1613,7 +1653,7 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::State &el) SERIALISE_MEMBER(resourceStates); - SIZE_CHECK(1400); + SIZE_CHECK(1688); } #pragma endregion D3D12 pipeline state @@ -2350,6 +2390,8 @@ void DoSerialise(SerialiserType &ser, VKPipe::State &el) SERIALISE_MEMBER(geometryShader); SERIALISE_MEMBER(fragmentShader); SERIALISE_MEMBER(computeShader); + SERIALISE_MEMBER(taskShader); + SERIALISE_MEMBER(meshShader); SERIALISE_MEMBER(tessellation); @@ -2366,7 +2408,7 @@ void DoSerialise(SerialiserType &ser, VKPipe::State &el) SERIALISE_MEMBER(conditionalRendering); - SIZE_CHECK(2264); + SIZE_CHECK(2712); } #pragma endregion Vulkan pipeline state diff --git a/renderdoc/replay/replay_controller.cpp b/renderdoc/replay/replay_controller.cpp index 6c1c1f9fe..0c606bc5c 100644 --- a/renderdoc/replay/replay_controller.cpp +++ b/renderdoc/replay/replay_controller.cpp @@ -495,7 +495,7 @@ MeshFormat ReplayController::GetPostVSData(uint32_t instID, uint32_t viewID, Mes ActionDescription *action = GetActionByEID(m_EventID); - if(action == NULL || !(action->flags & ActionFlags::Drawcall)) + if(action == NULL || !(action->flags & (ActionFlags::MeshDispatch | ActionFlags::Drawcall))) return MeshFormat(); instID = RDCMIN(instID, action->numInstances - 1); @@ -1479,6 +1479,8 @@ rdcarray ReplayController::PixelHistory(ResourceId target, ui case ResourceUsage::GS_Constants: case ResourceUsage::PS_Constants: case ResourceUsage::CS_Constants: + case ResourceUsage::TS_Constants: + case ResourceUsage::MS_Constants: case ResourceUsage::All_Constants: case ResourceUsage::VS_Resource: case ResourceUsage::HS_Resource: @@ -1486,6 +1488,8 @@ rdcarray ReplayController::PixelHistory(ResourceId target, ui case ResourceUsage::GS_Resource: case ResourceUsage::PS_Resource: case ResourceUsage::CS_Resource: + case ResourceUsage::TS_Resource: + case ResourceUsage::MS_Resource: case ResourceUsage::All_Resource: case ResourceUsage::InputTarget: case ResourceUsage::CopySrc: @@ -1511,6 +1515,8 @@ rdcarray ReplayController::PixelHistory(ResourceId target, ui case ResourceUsage::GS_RWResource: case ResourceUsage::PS_RWResource: case ResourceUsage::CS_RWResource: + case ResourceUsage::TS_RWResource: + case ResourceUsage::MS_RWResource: case ResourceUsage::All_RWResource: case ResourceUsage::ColorTarget: case ResourceUsage::DepthStencilTarget: @@ -1998,7 +2004,9 @@ rdcpair ReplayController::BuildTargetShader( case ShaderStage::Domain: case ShaderStage::Geometry: case ShaderStage::Pixel: - case ShaderStage::Compute: break; + case ShaderStage::Compute: + case ShaderStage::Task: + case ShaderStage::Mesh: break; default: RDCERR("Unexpected type in BuildShader!"); return rdcpair(); } @@ -2037,7 +2045,9 @@ rdcpair ReplayController::BuildCustomShader( case ShaderStage::Domain: case ShaderStage::Geometry: case ShaderStage::Pixel: - case ShaderStage::Compute: break; + case ShaderStage::Compute: + case ShaderStage::Task: + case ShaderStage::Mesh: break; default: RDCERR("Unexpected type in BuildShader!"); return rdcpair(); } diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index 6025931df..076bd8061 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -268,7 +268,7 @@ void ReplayOutput::RefreshOverlay() if(m_Type == ReplayOutputType::Mesh) m_OverlayDirty = false; - if(action != NULL && (action->flags & ActionFlags::Drawcall)) + if(action != NULL && (action->flags & (ActionFlags::MeshDispatch | ActionFlags::Drawcall))) { m_pDevice->InitPostVSBuffers(action->eventId); m_pController->FatalErrorCheck(); @@ -563,9 +563,7 @@ rdcpair ReplayOutput::PickVertex(uint32_t x, uint32_t y) if(!action) return errorReturn; - if(m_RenderData.meshDisplay.type == MeshDataStage::Unknown) - return errorReturn; - if(!(action->flags & ActionFlags::Drawcall)) + if(!(action->flags & (ActionFlags::MeshDispatch | ActionFlags::Drawcall))) return errorReturn; MeshDisplay cfg = m_RenderData.meshDisplay; @@ -1004,8 +1002,8 @@ void ReplayOutput::DisplayMesh() ActionDescription *action = m_pController->GetActionByEID(m_EventID); if(action == NULL || m_MainOutput.outputID == 0 || m_Width <= 0 || m_Height <= 0 || - (m_RenderData.meshDisplay.type == MeshDataStage::Unknown) || - !(action->flags & ActionFlags::Drawcall)) + (m_RenderData.meshDisplay.position.vertexResourceId == ResourceId()) || + !(action->flags & (ActionFlags::MeshDispatch | ActionFlags::Drawcall))) { FloatVector color; m_pDevice->BindOutputWindow(m_MainOutput.outputID, false); @@ -1086,6 +1084,12 @@ void ReplayOutput::DisplayMesh() MeshDataStage::VSOut); m_pController->FatalErrorCheck(); } + if(fmt.vertexResourceId == ResourceId()) + { + fmt = m_pDevice->GetPostVSBuffers(passEvents[i], inst, m_RenderData.meshDisplay.curView, + MeshDataStage::MeshOut); + m_pController->FatalErrorCheck(); + } fmt.meshColor = passDraws;