From 39bfe99ae58efb24d1c7fda46504255f5fcf8aa5 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 4 Oct 2016 17:47:32 +0200 Subject: [PATCH] Implement common pipeline state abstraction --- qrenderdoc/Code/CaptureContext.h | 3 +- qrenderdoc/Code/CommonPipelineState.cpp | 1208 +++++++++++++++++ qrenderdoc/Code/CommonPipelineState.h | 254 ++++ qrenderdoc/qrenderdoc.pro | 8 +- qrenderdoc/qrenderdoc_local.vcxproj | 2 + qrenderdoc/qrenderdoc_local.vcxproj.filters | 6 + renderdoc/api/replay/shader_types.h | 25 + renderdoc/driver/d3d12/d3d12_common.cpp | 4 +- .../shaders/spirv/spirv_disassemble.cpp | 6 +- 9 files changed, 1508 insertions(+), 8 deletions(-) create mode 100644 qrenderdoc/Code/CommonPipelineState.cpp create mode 100644 qrenderdoc/Code/CommonPipelineState.h diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index e362e768d..c21b86b9a 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -28,6 +28,7 @@ #include #include #include +#include "CommonPipelineState.h" #include "RenderManager.h" struct ILogViewerForm @@ -125,7 +126,7 @@ public: D3D11PipelineState CurD3D11PipelineState; GLPipelineState CurGLPipelineState; VulkanPipelineState CurVulkanPipelineState; - // CommonPipelineState CurPipelineState; + CommonPipelineState CurPipelineState; private: RenderManager m_Renderer; diff --git a/qrenderdoc/Code/CommonPipelineState.cpp b/qrenderdoc/Code/CommonPipelineState.cpp new file mode 100644 index 000000000..805edaace --- /dev/null +++ b/qrenderdoc/Code/CommonPipelineState.cpp @@ -0,0 +1,1208 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "CommonPipelineState.h" + +QString CommonPipelineState::GetImageLayout(ResourceId id) +{ + /* + if (LogLoaded) + { + if (IsLogVK && m_Vulkan->Images.ContainsKey(id)) + return m_Vulkan->Images[id].layouts[0].name; + + if (IsLogD3D12 && m_D3D12->Resources.ContainsKey(id)) + return m_D3D12->Resources[id].states[0].name; + } + */ + + return "Unknown"; +} + +QString CommonPipelineState::Abbrev(ShaderStageType stage) +{ + if(IsLogD3D11() || (!LogLoaded() && DefaultType == eGraphicsAPI_D3D11) || IsLogD3D12() || + (!LogLoaded() && DefaultType == eGraphicsAPI_D3D12)) + { + switch(stage) + { + case eShaderStage_Vertex: return "VS"; + case eShaderStage_Hull: return "HS"; + case eShaderStage_Domain: return "DS"; + case eShaderStage_Geometry: return "GS"; + case eShaderStage_Pixel: return "PS"; + case eShaderStage_Compute: return "CS"; + } + } + else if(IsLogGL() || (!LogLoaded() && DefaultType == eGraphicsAPI_OpenGL) || IsLogVK() || + (!LogLoaded() && DefaultType == eGraphicsAPI_Vulkan)) + { + switch(stage) + { + case eShaderStage_Vertex: return "VS"; + case eShaderStage_Tess_Control: return "TCS"; + case eShaderStage_Tess_Eval: return "TES"; + case eShaderStage_Geometry: return "GS"; + case eShaderStage_Fragment: return "FS"; + case eShaderStage_Compute: return "CS"; + } + } + + return "?S"; +} + +QString CommonPipelineState::OutputAbbrev() +{ + if(IsLogGL() || (!LogLoaded() && DefaultType == eGraphicsAPI_OpenGL) || IsLogVK() || + (!LogLoaded() && DefaultType == eGraphicsAPI_Vulkan)) + { + return "FB"; + } + + return "RT"; +} + +Viewport CommonPipelineState::GetViewport(int index) +{ + Viewport ret; + + // default to a 1x1 viewport just to avoid having to check for 0s all over + ret.x = ret.y = 0.0f; + ret.width = ret.height = 1.0f; + + if(LogLoaded()) + { + if(IsLogD3D11() && index < m_D3D11->m_RS.Viewports.count) + { + ret.x = m_D3D11->m_RS.Viewports[index].TopLeft[0]; + ret.y = m_D3D11->m_RS.Viewports[index].TopLeft[1]; + ret.width = m_D3D11->m_RS.Viewports[index].Width; + ret.height = m_D3D11->m_RS.Viewports[index].Height; + } + else if(IsLogD3D12() && index < m_D3D12->m_RS.Viewports.count) + { + ret.x = m_D3D12->m_RS.Viewports[index].TopLeft[0]; + ret.y = m_D3D12->m_RS.Viewports[index].TopLeft[1]; + ret.width = m_D3D12->m_RS.Viewports[index].Width; + ret.height = m_D3D12->m_RS.Viewports[index].Height; + } + else if(IsLogGL() && index < m_GL->m_Rasterizer.Viewports.count) + { + ret.x = m_GL->m_Rasterizer.Viewports[index].Left; + ret.y = m_GL->m_Rasterizer.Viewports[index].Bottom; + ret.width = m_GL->m_Rasterizer.Viewports[index].Width; + ret.height = m_GL->m_Rasterizer.Viewports[index].Height; + } + else if(IsLogVK() && index < m_Vulkan->VP.viewportScissors.count) + { + ret.x = m_Vulkan->VP.viewportScissors[index].vp.x; + ret.y = m_Vulkan->VP.viewportScissors[index].vp.y; + ret.width = m_Vulkan->VP.viewportScissors[index].vp.width; + ret.height = m_Vulkan->VP.viewportScissors[index].vp.height; + } + } + + return ret; +} + +ShaderBindpointMapping CommonPipelineState::GetBindpointMapping(ShaderStageType stage) +{ + if(LogLoaded()) + { + if(IsLogD3D11()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_D3D11->m_VS.BindpointMapping; + case eShaderStage_Domain: return m_D3D11->m_DS.BindpointMapping; + case eShaderStage_Hull: return m_D3D11->m_HS.BindpointMapping; + case eShaderStage_Geometry: return m_D3D11->m_GS.BindpointMapping; + case eShaderStage_Pixel: return m_D3D11->m_PS.BindpointMapping; + case eShaderStage_Compute: return m_D3D11->m_CS.BindpointMapping; + } + } + else if(IsLogD3D12()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_D3D12->m_VS.BindpointMapping; + case eShaderStage_Domain: return m_D3D12->m_DS.BindpointMapping; + case eShaderStage_Hull: return m_D3D12->m_HS.BindpointMapping; + case eShaderStage_Geometry: return m_D3D12->m_GS.BindpointMapping; + case eShaderStage_Pixel: return m_D3D12->m_PS.BindpointMapping; + case eShaderStage_Compute: return m_D3D12->m_CS.BindpointMapping; + } + } + else if(IsLogGL()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_GL->m_VS.BindpointMapping; + case eShaderStage_Tess_Control: return m_GL->m_TCS.BindpointMapping; + case eShaderStage_Tess_Eval: return m_GL->m_TES.BindpointMapping; + case eShaderStage_Geometry: return m_GL->m_GS.BindpointMapping; + case eShaderStage_Fragment: return m_GL->m_FS.BindpointMapping; + case eShaderStage_Compute: return m_GL->m_CS.BindpointMapping; + } + } + else if(IsLogVK()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_Vulkan->VS.BindpointMapping; + case eShaderStage_Tess_Control: return m_Vulkan->TCS.BindpointMapping; + case eShaderStage_Tess_Eval: return m_Vulkan->TES.BindpointMapping; + case eShaderStage_Geometry: return m_Vulkan->GS.BindpointMapping; + case eShaderStage_Fragment: return m_Vulkan->FS.BindpointMapping; + case eShaderStage_Compute: return m_Vulkan->CS.BindpointMapping; + } + } + } + + return ShaderBindpointMapping(); +} + +ShaderReflection *CommonPipelineState::GetShaderReflection(ShaderStageType stage) +{ + if(LogLoaded()) + { + if(IsLogD3D11()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_D3D11->m_VS.ShaderDetails; + case eShaderStage_Domain: return m_D3D11->m_DS.ShaderDetails; + case eShaderStage_Hull: return m_D3D11->m_HS.ShaderDetails; + case eShaderStage_Geometry: return m_D3D11->m_GS.ShaderDetails; + case eShaderStage_Pixel: return m_D3D11->m_PS.ShaderDetails; + case eShaderStage_Compute: return m_D3D11->m_CS.ShaderDetails; + } + } + else if(IsLogD3D12()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_D3D12->m_VS.ShaderDetails; + case eShaderStage_Domain: return m_D3D12->m_DS.ShaderDetails; + case eShaderStage_Hull: return m_D3D12->m_HS.ShaderDetails; + case eShaderStage_Geometry: return m_D3D12->m_GS.ShaderDetails; + case eShaderStage_Pixel: return m_D3D12->m_PS.ShaderDetails; + case eShaderStage_Compute: return m_D3D12->m_CS.ShaderDetails; + } + } + else if(IsLogGL()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_GL->m_VS.ShaderDetails; + case eShaderStage_Tess_Control: return m_GL->m_TCS.ShaderDetails; + case eShaderStage_Tess_Eval: return m_GL->m_TES.ShaderDetails; + case eShaderStage_Geometry: return m_GL->m_GS.ShaderDetails; + case eShaderStage_Fragment: return m_GL->m_FS.ShaderDetails; + case eShaderStage_Compute: return m_GL->m_CS.ShaderDetails; + } + } + else if(IsLogVK()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_Vulkan->VS.ShaderDetails; + case eShaderStage_Tess_Control: return m_Vulkan->TCS.ShaderDetails; + case eShaderStage_Tess_Eval: return m_Vulkan->TES.ShaderDetails; + case eShaderStage_Geometry: return m_Vulkan->GS.ShaderDetails; + case eShaderStage_Fragment: return m_Vulkan->FS.ShaderDetails; + case eShaderStage_Compute: return m_Vulkan->CS.ShaderDetails; + } + } + } + + return NULL; +} + +QString CommonPipelineState::GetShaderEntryPoint(ShaderStageType stage) +{ + if(LogLoaded() && IsLogVK()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_Vulkan->VS.entryPoint.elems; + case eShaderStage_Tess_Control: return m_Vulkan->TCS.entryPoint.elems; + case eShaderStage_Tess_Eval: return m_Vulkan->TES.entryPoint.elems; + case eShaderStage_Geometry: return m_Vulkan->GS.entryPoint.elems; + case eShaderStage_Fragment: return m_Vulkan->FS.entryPoint.elems; + case eShaderStage_Compute: return m_Vulkan->CS.entryPoint.elems; + } + } + + return ""; +} + +ResourceId CommonPipelineState::GetShader(ShaderStageType stage) +{ + if(LogLoaded()) + { + if(IsLogD3D11()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_D3D11->m_VS.Shader; + case eShaderStage_Domain: return m_D3D11->m_DS.Shader; + case eShaderStage_Hull: return m_D3D11->m_HS.Shader; + case eShaderStage_Geometry: return m_D3D11->m_GS.Shader; + case eShaderStage_Pixel: return m_D3D11->m_PS.Shader; + case eShaderStage_Compute: return m_D3D11->m_CS.Shader; + } + } + else if(IsLogD3D12()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_D3D12->m_VS.Shader; + case eShaderStage_Domain: return m_D3D12->m_DS.Shader; + case eShaderStage_Hull: return m_D3D12->m_HS.Shader; + case eShaderStage_Geometry: return m_D3D12->m_GS.Shader; + case eShaderStage_Pixel: return m_D3D12->m_PS.Shader; + case eShaderStage_Compute: return m_D3D12->m_CS.Shader; + } + } + else if(IsLogGL()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_GL->m_VS.Shader; + case eShaderStage_Tess_Control: return m_GL->m_TCS.Shader; + case eShaderStage_Tess_Eval: return m_GL->m_TES.Shader; + case eShaderStage_Geometry: return m_GL->m_GS.Shader; + case eShaderStage_Fragment: return m_GL->m_FS.Shader; + case eShaderStage_Compute: return m_GL->m_CS.Shader; + } + } + else if(IsLogVK()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_Vulkan->VS.Shader; + case eShaderStage_Tess_Control: return m_Vulkan->TCS.Shader; + case eShaderStage_Tess_Eval: return m_Vulkan->TES.Shader; + case eShaderStage_Geometry: return m_Vulkan->GS.Shader; + case eShaderStage_Fragment: return m_Vulkan->FS.Shader; + case eShaderStage_Compute: return m_Vulkan->CS.Shader; + } + } + } + + return ResourceId(); +} + +QString CommonPipelineState::GetShaderName(ShaderStageType stage) +{ + if(LogLoaded()) + { + if(IsLogD3D11()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_D3D11->m_VS.ShaderName.elems; + case eShaderStage_Domain: return m_D3D11->m_DS.ShaderName.elems; + case eShaderStage_Hull: return m_D3D11->m_HS.ShaderName.elems; + case eShaderStage_Geometry: return m_D3D11->m_GS.ShaderName.elems; + case eShaderStage_Pixel: return m_D3D11->m_PS.ShaderName.elems; + case eShaderStage_Compute: return m_D3D11->m_CS.ShaderName.elems; + } + } + else if(IsLogD3D12()) + { + switch(stage) + { + case eShaderStage_Vertex: return QString(m_D3D12->PipelineName.elems) + " VS"; + case eShaderStage_Domain: return QString(m_D3D12->PipelineName.elems) + " DS"; + case eShaderStage_Hull: return QString(m_D3D12->PipelineName.elems) + " HS"; + case eShaderStage_Geometry: return QString(m_D3D12->PipelineName.elems) + " GS"; + case eShaderStage_Pixel: return QString(m_D3D12->PipelineName.elems) + " PS"; + case eShaderStage_Compute: return QString(m_D3D12->PipelineName.elems) + " CS"; + } + } + else if(IsLogGL()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_GL->m_VS.ShaderName.elems; + case eShaderStage_Tess_Control: return m_GL->m_TCS.ShaderName.elems; + case eShaderStage_Tess_Eval: return m_GL->m_TES.ShaderName.elems; + case eShaderStage_Geometry: return m_GL->m_GS.ShaderName.elems; + case eShaderStage_Fragment: return m_GL->m_FS.ShaderName.elems; + case eShaderStage_Compute: return m_GL->m_CS.ShaderName.elems; + } + } + else if(IsLogVK()) + { + switch(stage) + { + case eShaderStage_Vertex: return m_Vulkan->VS.ShaderName.elems; + case eShaderStage_Domain: return m_Vulkan->TCS.ShaderName.elems; + case eShaderStage_Hull: return m_Vulkan->TES.ShaderName.elems; + case eShaderStage_Geometry: return m_Vulkan->GS.ShaderName.elems; + case eShaderStage_Pixel: return m_Vulkan->FS.ShaderName.elems; + case eShaderStage_Compute: return m_Vulkan->CS.ShaderName.elems; + } + } + } + + return ""; +} + +void CommonPipelineState::GetIBuffer(ResourceId &buf, uint64_t &ByteOffset) +{ + if(LogLoaded()) + { + if(IsLogD3D11()) + { + buf = m_D3D11->m_IA.ibuffer.Buffer; + ByteOffset = m_D3D11->m_IA.ibuffer.Offset; + + return; + } + else if(IsLogD3D12()) + { + buf = m_D3D12->m_IA.ibuffer.Buffer; + ByteOffset = m_D3D12->m_IA.ibuffer.Offset; + + return; + } + else if(IsLogGL()) + { + buf = m_GL->m_VtxIn.ibuffer; + ByteOffset = 0; // GL only has per-draw index offset + + return; + } + else if(IsLogVK()) + { + buf = m_Vulkan->IA.ibuffer.buf; + ByteOffset = m_Vulkan->IA.ibuffer.offs; + + return; + } + } + + buf = ResourceId(); + ByteOffset = 0; +} + +bool CommonPipelineState::IsStripRestartEnabled() +{ + if(LogLoaded()) + { + if(IsLogD3D11()) + { + // D3D11 this is always enabled + return true; + } + else if(IsLogD3D12()) + { + return m_D3D12->m_IA.indexStripCutValue != 0; + } + else if(IsLogGL()) + { + return m_GL->m_VtxIn.primitiveRestart; + } + else if(IsLogVK()) + { + return m_Vulkan->IA.primitiveRestartEnable; + } + } + + return false; +} + +uint32_t CommonPipelineState::GetStripRestartIndex(uint32_t indexByteWidth) +{ + if(LogLoaded()) + { + if(IsLogD3D11() || IsLogVK()) + { + // D3D11 or Vulkan this is always '-1' in whichever size of index we're using + return indexByteWidth == 2 ? UINT16_MAX : UINT32_MAX; + } + else if(IsLogD3D12()) + { + return m_D3D12->m_IA.indexStripCutValue; + } + else if(IsLogGL()) + { + uint32_t maxval = UINT32_MAX; + if(indexByteWidth == 2) + maxval = UINT16_MAX; + else if(indexByteWidth == 1) + maxval = 0xff; + return qMin(maxval, m_GL->m_VtxIn.restartIndex); + } + } + + return UINT32_MAX; +} + +QVector CommonPipelineState::GetVBuffers() +{ + QVector ret; + + if(LogLoaded()) + { + if(IsLogD3D11()) + { + ret.resize(m_D3D11->m_IA.vbuffers.count); + for(int i = 0; i < m_D3D11->m_IA.vbuffers.count; i++) + { + ret[i].Buffer = m_D3D11->m_IA.vbuffers[i].Buffer; + ret[i].ByteOffset = m_D3D11->m_IA.vbuffers[i].Offset; + ret[i].ByteStride = m_D3D11->m_IA.vbuffers[i].Stride; + } + } + else if(IsLogD3D12()) + { + ret.resize(m_D3D12->m_IA.vbuffers.count); + for(int i = 0; i < m_D3D12->m_IA.vbuffers.count; i++) + { + ret[i].Buffer = m_D3D12->m_IA.vbuffers[i].Buffer; + ret[i].ByteOffset = m_D3D12->m_IA.vbuffers[i].Offset; + ret[i].ByteStride = m_D3D12->m_IA.vbuffers[i].Stride; + } + } + else if(IsLogGL()) + { + ret.resize(m_GL->m_VtxIn.vbuffers.count); + for(int i = 0; i < m_GL->m_VtxIn.vbuffers.count; i++) + { + ret[i].Buffer = m_GL->m_VtxIn.vbuffers[i].Buffer; + ret[i].ByteOffset = m_GL->m_VtxIn.vbuffers[i].Offset; + ret[i].ByteStride = m_GL->m_VtxIn.vbuffers[i].Stride; + } + } + else if(IsLogVK()) + { + ret.resize(m_Vulkan->VI.binds.count); + for(int i = 0; i < m_Vulkan->VI.binds.count; i++) + { + ret[i].Buffer = + i < m_Vulkan->VI.vbuffers.count ? m_Vulkan->VI.vbuffers[i].buffer : ResourceId(); + ret[i].ByteOffset = i < m_Vulkan->VI.vbuffers.count ? m_Vulkan->VI.vbuffers[i].offset : 0; + ret[i].ByteStride = m_Vulkan->VI.binds[i].bytestride; + } + } + } + + return ret; +} + +QVector CommonPipelineState::GetVertexInputs() +{ + if(LogLoaded()) + { + if(IsLogD3D11()) + { + uint32_t byteOffs[128] = {}; + + auto &layouts = m_D3D11->m_IA.layouts; + + QVector ret(layouts.count); + for(int i = 0; i < layouts.count; i++) + { + QString semName(layouts[i].SemanticName.elems); + + bool needsSemanticIdx = false; + for(int j = 0; j < layouts.count; j++) + { + if(i != j && !semName.compare(QString(layouts[j].SemanticName.elems), Qt::CaseInsensitive)) + { + needsSemanticIdx = true; + break; + } + } + + uint32_t offs = layouts[i].ByteOffset; + if(offs == UINT32_MAX) // APPEND_ALIGNED + offs = byteOffs[layouts[i].InputSlot]; + else + byteOffs[layouts[i].InputSlot] = offs = layouts[i].ByteOffset; + + byteOffs[layouts[i].InputSlot] += + layouts[i].Format.compByteWidth * layouts[i].Format.compCount; + + ret[i].Name = semName + (needsSemanticIdx ? QString::number(layouts[i].SemanticIndex) : ""); + ret[i].VertexBuffer = (int)layouts[i].InputSlot; + ret[i].RelativeByteOffset = offs; + ret[i].PerInstance = layouts[i].PerInstance; + ret[i].InstanceRate = (int)layouts[i].InstanceDataStepRate; + ret[i].Format = layouts[i].Format; + memset(&ret[i].GenericValue, 0, sizeof(PixelValue)); + ret[i].Used = false; + + if(m_D3D11->m_IA.Bytecode != NULL) + { + rdctype::array &sig = m_D3D11->m_IA.Bytecode->InputSig; + for(int ia = 0; ia < sig.count; ia++) + { + if(!semName.compare(QString(sig[ia].semanticName.elems), Qt::CaseInsensitive) && + sig[ia].semanticIndex == layouts[i].SemanticIndex) + { + ret[i].Used = true; + break; + } + } + } + } + + return ret; + } + else if(IsLogD3D12()) + { + uint32_t byteOffs[128] = {}; + + auto &layouts = m_D3D12->m_IA.layouts; + + QVector ret(layouts.count); + for(int i = 0; i < layouts.count; i++) + { + QString semName(layouts[i].SemanticName.elems); + + bool needsSemanticIdx = false; + for(int j = 0; j < layouts.count; j++) + { + if(i != j && !semName.compare(QString(layouts[j].SemanticName.elems), Qt::CaseInsensitive)) + { + needsSemanticIdx = true; + break; + } + } + + uint32_t offs = layouts[i].ByteOffset; + if(offs == UINT32_MAX) // APPEND_ALIGNED + offs = byteOffs[layouts[i].InputSlot]; + else + byteOffs[layouts[i].InputSlot] = offs = layouts[i].ByteOffset; + + byteOffs[layouts[i].InputSlot] += + layouts[i].Format.compByteWidth * layouts[i].Format.compCount; + + ret[i].Name = semName + (needsSemanticIdx ? QString::number(layouts[i].SemanticIndex) : ""); + ret[i].VertexBuffer = (int)layouts[i].InputSlot; + ret[i].RelativeByteOffset = offs; + ret[i].PerInstance = layouts[i].PerInstance; + ret[i].InstanceRate = (int)layouts[i].InstanceDataStepRate; + ret[i].Format = layouts[i].Format; + memset(&ret[i].GenericValue, 0, sizeof(PixelValue)); + ret[i].Used = false; + + if(m_D3D12->m_VS.ShaderDetails != NULL) + { + rdctype::array &sig = m_D3D12->m_VS.ShaderDetails->InputSig; + for(int ia = 0; ia < sig.count; ia++) + { + if(!semName.compare(QString(sig[ia].semanticName.elems), Qt::CaseInsensitive) && + sig[ia].semanticIndex == layouts[i].SemanticIndex) + { + ret[i].Used = true; + break; + } + } + } + } + + return ret; + } + else if(IsLogGL()) + { + auto &attrs = m_GL->m_VtxIn.attributes; + + int num = 0; + for(int i = 0; i < attrs.count; i++) + { + int attrib = -1; + if(m_GL->m_VS.ShaderDetails != NULL) + attrib = m_GL->m_VS.BindpointMapping.InputAttributes[i]; + else + attrib = i; + + if(attrib >= 0) + num++; + } + + int a = 0; + QVector ret(attrs.count); + for(int i = 0; i < attrs.count && a < num; i++) + { + ret[a].Name = QString("attr%1").arg(i); + memset(&ret[a].GenericValue, 0, sizeof(PixelValue)); + ret[a].VertexBuffer = (int)attrs[i].BufferSlot; + ret[a].RelativeByteOffset = attrs[i].RelativeOffset; + ret[a].PerInstance = m_GL->m_VtxIn.vbuffers[attrs[i].BufferSlot].Divisor > 0; + ret[a].InstanceRate = (int)m_GL->m_VtxIn.vbuffers[attrs[i].BufferSlot].Divisor; + ret[a].Format = attrs[i].Format; + ret[a].Used = true; + + if(m_GL->m_VS.ShaderDetails != NULL) + { + int attrib = m_GL->m_VS.BindpointMapping.InputAttributes[i]; + + if(attrib >= 0 && attrib < m_GL->m_VS.ShaderDetails->InputSig.count) + ret[a].Name = m_GL->m_VS.ShaderDetails->InputSig[attrib].varName.elems; + + if(attrib == -1) + continue; + + if(!attrs[i].Enabled) + { + uint32_t compCount = m_GL->m_VS.ShaderDetails->InputSig[attrib].compCount; + FormatComponentType compType = m_GL->m_VS.ShaderDetails->InputSig[attrib].compType; + + for(uint32_t c = 0; c < compCount; c++) + { + if(compType == eCompType_Float) + ret[a].GenericValue.value_f[c] = attrs[i].GenericValue.f[c]; + else if(compType == eCompType_UInt) + ret[a].GenericValue.value_u[c] = attrs[i].GenericValue.u[c]; + else if(compType == eCompType_SInt) + ret[a].GenericValue.value_i[c] = attrs[i].GenericValue.i[c]; + else if(compType == eCompType_UScaled) + ret[a].GenericValue.value_f[c] = (float)attrs[i].GenericValue.u[c]; + else if(compType == eCompType_SScaled) + ret[a].GenericValue.value_f[c] = (float)attrs[i].GenericValue.i[c]; + } + + ret[a].PerInstance = false; + ret[a].InstanceRate = 0; + ret[a].Format.compByteWidth = 4; + ret[a].Format.compCount = compCount; + ret[a].Format.compType = compType; + ret[a].Format.special = false; + ret[a].Format.srgbCorrected = false; + } + } + + a++; + } + + return ret; + } + else if(IsLogVK()) + { + auto &attrs = m_Vulkan->VI.attrs; + + int num = 0; + for(int i = 0; i < attrs.count; i++) + { + int attrib = -1; + if(m_Vulkan->VS.ShaderDetails != NULL) + { + if(attrs[i].location < (uint32_t)m_Vulkan->VS.BindpointMapping.InputAttributes.count) + attrib = m_Vulkan->VS.BindpointMapping.InputAttributes[attrs[i].location]; + } + else + attrib = i; + + if(attrib >= 0) + num++; + } + + int a = 0; + QVector ret(num); + for(int i = 0; i < attrs.count && a < num; i++) + { + ret[a].Name = QString("attr%1").arg(i); + memset(&ret[a].GenericValue, 0, sizeof(PixelValue)); + ret[a].VertexBuffer = (int)attrs[i].binding; + ret[a].RelativeByteOffset = attrs[i].byteoffset; + ret[a].PerInstance = false; + if(attrs[i].binding < (uint32_t)m_Vulkan->VI.binds.count) + ret[a].PerInstance = m_Vulkan->VI.binds[attrs[i].binding].perInstance; + ret[a].InstanceRate = 1; + ret[a].Format = attrs[i].format; + ret[a].Used = true; + + if(m_Vulkan->VS.ShaderDetails != NULL) + { + int attrib = -1; + + if(attrs[i].location < (uint32_t)m_Vulkan->VS.BindpointMapping.InputAttributes.count) + attrib = m_Vulkan->VS.BindpointMapping.InputAttributes[attrs[i].location]; + + if(attrib >= 0 && attrib < m_Vulkan->VS.ShaderDetails->InputSig.count) + ret[a].Name = m_Vulkan->VS.ShaderDetails->InputSig[attrib].varName.elems; + + if(attrib == -1) + continue; + } + + a++; + } + + return ret; + } + } + + return QVector(); +} + +void CommonPipelineState::GetConstantBuffer(ShaderStageType stage, uint32_t BufIdx, + uint32_t ArrayIdx, ResourceId &buf, + uint64_t &ByteOffset, uint64_t &ByteSize) +{ + if(LogLoaded()) + { + if(IsLogD3D11()) + { + const D3D11PipelineState::ShaderStage &s = GetD3D11Stage(stage); + + if(BufIdx < (uint32_t)s.ConstantBuffers.count) + { + buf = s.ConstantBuffers[BufIdx].Buffer; + ByteOffset = s.ConstantBuffers[BufIdx].VecOffset * 4 * sizeof(float); + ByteSize = s.ConstantBuffers[BufIdx].VecCount * 4 * sizeof(float); + + return; + } + } + else if(IsLogD3D12()) + { + const D3D12PipelineState::ShaderStage &s = GetD3D12Stage(stage); + + if(s.ShaderDetails != NULL && BufIdx < (uint32_t)s.ShaderDetails->ConstantBlocks.count) + { + const BindpointMap &bind = + s.BindpointMapping.ConstantBlocks[s.ShaderDetails->ConstantBlocks[BufIdx].bindPoint]; + + if(bind.bindset >= s.Spaces.count || bind.bind >= s.Spaces[bind.bindset].ConstantBuffers.count) + { + buf = ResourceId(); + ByteOffset = 0; + ByteSize = 0; + return; + } + + const D3D12PipelineState::CBuffer &descriptor = + s.Spaces[bind.bindset].ConstantBuffers[bind.bind]; + + buf = descriptor.Buffer; + ByteOffset = descriptor.Offset; + ByteSize = descriptor.ByteSize; + + return; + } + } + else if(IsLogGL()) + { + const GLPipelineState::ShaderStage &s = GetGLStage(stage); + + if(s.ShaderDetails != NULL && BufIdx < (uint32_t)s.ShaderDetails->ConstantBlocks.count) + { + if(s.ShaderDetails->ConstantBlocks[BufIdx].bindPoint >= 0) + { + int uboIdx = + s.BindpointMapping.ConstantBlocks[s.ShaderDetails->ConstantBlocks[BufIdx].bindPoint].bind; + if(uboIdx >= 0 && uboIdx < m_GL->UniformBuffers.count) + { + GLPipelineState::Buffer &b = m_GL->UniformBuffers[uboIdx]; + + buf = b.Resource; + ByteOffset = b.Offset; + ByteSize = b.Size; + + return; + } + } + } + } + else if(IsLogVK()) + { + VulkanPipelineState::Pipeline &pipe = + stage == eShaderStage_Compute ? m_Vulkan->compute : m_Vulkan->graphics; + const VulkanPipelineState::ShaderStage &s = GetVulkanStage(stage); + + if(s.ShaderDetails != NULL && BufIdx < (uint32_t)s.ShaderDetails->ConstantBlocks.count) + { + const BindpointMap &bind = + s.BindpointMapping.ConstantBlocks[s.ShaderDetails->ConstantBlocks[BufIdx].bindPoint]; + + if(s.ShaderDetails->ConstantBlocks[BufIdx].bufferBacked == false) + { + // dummy values, it would be nice to fetch these properly + buf = ResourceId(); + ByteOffset = 0; + ByteSize = 1024; + return; + } + + auto &descriptorBind = pipe.DescSets[bind.bindset].bindings[bind.bind].binds[ArrayIdx]; + + buf = descriptorBind.res; + ByteOffset = descriptorBind.offset; + ByteSize = descriptorBind.size; + + return; + } + } + } + + buf = ResourceId(); + ByteOffset = 0; + ByteSize = 0; +} + +QMap> CommonPipelineState::GetReadOnlyResources(ShaderStageType stage) +{ + QMap> ret; + + if(LogLoaded()) + { + if(IsLogD3D11()) + { + const D3D11PipelineState::ShaderStage &s = GetD3D11Stage(stage); + + for(int i = 0; i < s.SRVs.count; i++) + { + BindpointMap key(0, i); + BoundResource val; + + val.Id = s.SRVs[i].Resource; + val.HighestMip = (int)s.SRVs[i].HighestMip; + val.FirstSlice = (int)s.SRVs[i].FirstArraySlice; + val.typeHint = s.SRVs[i].Format.compType; + + ret[key] = {val}; + } + + return ret; + } + else if(IsLogD3D12()) + { + const D3D12PipelineState::ShaderStage &s = GetD3D12Stage(stage); + + for(int space = 0; space < s.Spaces.count; space++) + { + for(int reg = 0; reg < s.Spaces[space].SRVs.count; reg++) + { + const D3D12PipelineState::ResourceView &bind = s.Spaces[space].SRVs[reg]; + BindpointMap key(space, reg); + BoundResource val; + + val.Id = bind.Resource; + val.HighestMip = (int)bind.HighestMip; + val.FirstSlice = (int)bind.FirstArraySlice; + val.typeHint = bind.Format.compType; + + ret[key] = {val}; + } + } + + return ret; + } + else if(IsLogGL()) + { + for(int i = 0; i < m_GL->Textures.count; i++) + { + BindpointMap key(0, i); + BoundResource val; + + val.Id = m_GL->Textures[i].Resource; + val.HighestMip = (int)m_GL->Textures[i].HighestMip; + val.FirstSlice = (int)m_GL->Textures[i].FirstSlice; + val.typeHint = eCompType_None; + + ret[key] = {val}; + } + + return ret; + } + else if(IsLogVK()) + { + const auto &descsets = + stage == eShaderStage_Compute ? m_Vulkan->compute.DescSets : m_Vulkan->graphics.DescSets; + + ShaderStageBits mask = (ShaderStageBits)(1 << (int)stage); + + for(int set = 0; set < descsets.count; set++) + { + const auto &descset = descsets[set]; + for(int slot = 0; slot < descset.bindings.count; slot++) + { + const auto &bind = descset.bindings[slot]; + if((bind.type == eBindType_ImageSampler || bind.type == eBindType_InputAttachment || + bind.type == eBindType_ReadOnlyImage || bind.type == eBindType_ReadOnlyTBuffer) && + (bind.stageFlags & mask) == mask) + { + BindpointMap key(set, slot); + QVector val(bind.descriptorCount); + + for(uint32_t i = 0; i < bind.descriptorCount; i++) + { + val[i].Id = bind.binds[i].res; + val[i].HighestMip = (int)bind.binds[i].baseMip; + val[i].FirstSlice = (int)bind.binds[i].baseLayer; + val[i].typeHint = bind.binds[i].viewfmt.compType; + } + + ret[key] = val; + } + } + } + + return ret; + } + } + + return ret; +} + +QMap> CommonPipelineState::GetReadWriteResources( + ShaderStageType stage) +{ + QMap> ret; + + if(LogLoaded()) + { + if(IsLogD3D11()) + { + if(stage == eShaderStage_Compute) + { + for(int i = 0; i < m_D3D11->m_CS.UAVs.count; i++) + { + BindpointMap key(0, i); + BoundResource val; + + val.Id = m_D3D11->m_CS.UAVs[i].Resource; + val.HighestMip = (int)m_D3D11->m_CS.UAVs[i].HighestMip; + val.FirstSlice = (int)m_D3D11->m_CS.UAVs[i].FirstArraySlice; + val.typeHint = m_D3D11->m_CS.UAVs[i].Format.compType; + + ret[key] = {val}; + } + } + else + { + for(int i = 0; i < m_D3D11->m_OM.UAVs.count; i++) + { + BindpointMap key(0, i); + BoundResource val; + + val.Id = m_D3D11->m_OM.UAVs[i].Resource; + val.HighestMip = (int)m_D3D11->m_OM.UAVs[i].HighestMip; + val.FirstSlice = (int)m_D3D11->m_OM.UAVs[i].FirstArraySlice; + val.typeHint = m_D3D11->m_OM.UAVs[i].Format.compType; + + ret[key] = {val}; + } + } + } + else if(IsLogD3D12()) + { + const D3D12PipelineState::ShaderStage &s = GetD3D12Stage(stage); + + for(int space = 0; space < s.Spaces.count; space++) + { + for(int reg = 0; reg < s.Spaces[space].UAVs.count; reg++) + { + const D3D12PipelineState::ResourceView &bind = s.Spaces[space].UAVs[reg]; + BindpointMap key(space, reg); + BoundResource val; + + val.Id = bind.Resource; + val.HighestMip = (int)bind.HighestMip; + val.FirstSlice = (int)bind.FirstArraySlice; + val.typeHint = bind.Format.compType; + + ret[key] = {val}; + } + } + } + else if(IsLogGL()) + { + for(int i = 0; i < m_GL->Images.count; i++) + { + BindpointMap key(0, i); + BoundResource val; + + val.Id = m_GL->Images[i].Resource; + val.HighestMip = (int)m_GL->Images[i].Level; + val.FirstSlice = (int)m_GL->Images[i].Layer; + val.typeHint = m_GL->Images[i].Format.compType; + + ret[key] = {val}; + } + } + else if(IsLogVK()) + { + const auto &descsets = + stage == eShaderStage_Compute ? m_Vulkan->compute.DescSets : m_Vulkan->graphics.DescSets; + + ShaderStageBits mask = (ShaderStageBits)(1 << (int)stage); + + for(int set = 0; set < descsets.count; set++) + { + const auto &descset = descsets[set]; + for(int slot = 0; slot < descset.bindings.count; slot++) + { + const auto &bind = descset.bindings[slot]; + if((bind.type == eBindType_ReadWriteBuffer || bind.type == eBindType_ReadWriteImage || + bind.type == eBindType_ReadWriteTBuffer) && + (bind.stageFlags & mask) == mask) + { + BindpointMap key(set, slot); + QVector val(bind.descriptorCount); + + for(uint32_t i = 0; i < bind.descriptorCount; i++) + { + val[i].Id = bind.binds[i].res; + val[i].HighestMip = (int)bind.binds[i].baseMip; + val[i].FirstSlice = (int)bind.binds[i].baseLayer; + val[i].typeHint = bind.binds[i].viewfmt.compType; + } + + ret[key] = val; + } + } + } + } + } + + return ret; +} + +BoundResource CommonPipelineState::GetDepthTarget() +{ + if(LogLoaded()) + { + if(IsLogD3D11()) + { + BoundResource ret; + ret.Id = m_D3D11->m_OM.DepthTarget.Resource; + ret.HighestMip = (int)m_D3D11->m_OM.DepthTarget.HighestMip; + ret.FirstSlice = (int)m_D3D11->m_OM.DepthTarget.FirstArraySlice; + ret.typeHint = m_D3D11->m_OM.DepthTarget.Format.compType; + return ret; + } + else if(IsLogD3D12()) + { + BoundResource ret; + ret.Id = m_D3D12->m_OM.DepthTarget.Resource; + ret.HighestMip = (int)m_D3D12->m_OM.DepthTarget.HighestMip; + ret.FirstSlice = (int)m_D3D12->m_OM.DepthTarget.FirstArraySlice; + ret.typeHint = m_D3D12->m_OM.DepthTarget.Format.compType; + return ret; + } + else if(IsLogGL()) + { + BoundResource ret; + ret.Id = m_GL->m_FB.m_DrawFBO.Depth.Obj; + ret.HighestMip = (int)m_GL->m_FB.m_DrawFBO.Depth.Mip; + ret.FirstSlice = (int)m_GL->m_FB.m_DrawFBO.Depth.Layer; + ret.typeHint = eCompType_None; + return ret; + } + else if(IsLogVK()) + { + const auto &rp = m_Vulkan->Pass.renderpass; + const auto &fb = m_Vulkan->Pass.framebuffer; + + if(rp.depthstencilAttachment >= 0 && rp.depthstencilAttachment < fb.attachments.count) + { + BoundResource ret; + ret.Id = fb.attachments[rp.depthstencilAttachment].img; + ret.HighestMip = (int)fb.attachments[rp.depthstencilAttachment].baseMip; + ret.FirstSlice = (int)fb.attachments[rp.depthstencilAttachment].baseLayer; + ret.typeHint = fb.attachments[rp.depthstencilAttachment].viewfmt.compType; + return ret; + } + + return BoundResource(); + } + } + + return BoundResource(); +} + +QVector CommonPipelineState::GetOutputTargets() +{ + QVector ret; + + if(LogLoaded()) + { + if(IsLogD3D11()) + { + ret.resize(m_D3D11->m_OM.RenderTargets.count); + for(int i = 0; i < m_D3D11->m_OM.RenderTargets.count; i++) + { + ret[i].Id = m_D3D11->m_OM.RenderTargets[i].Resource; + ret[i].HighestMip = (int)m_D3D11->m_OM.RenderTargets[i].HighestMip; + ret[i].FirstSlice = (int)m_D3D11->m_OM.RenderTargets[i].FirstArraySlice; + ret[i].typeHint = m_D3D11->m_OM.RenderTargets[i].Format.compType; + } + } + else if(IsLogD3D12()) + { + ret.resize(m_D3D12->m_OM.RenderTargets.count); + for(int i = 0; i < m_D3D12->m_OM.RenderTargets.count; i++) + { + ret[i].Id = m_D3D12->m_OM.RenderTargets[i].Resource; + ret[i].HighestMip = (int)m_D3D12->m_OM.RenderTargets[i].HighestMip; + ret[i].FirstSlice = (int)m_D3D12->m_OM.RenderTargets[i].FirstArraySlice; + ret[i].typeHint = m_D3D12->m_OM.RenderTargets[i].Format.compType; + } + } + else if(IsLogGL()) + { + ret.resize(m_GL->m_FB.m_DrawFBO.DrawBuffers.count); + for(int i = 0; i < m_GL->m_FB.m_DrawFBO.DrawBuffers.count; i++) + { + int db = m_GL->m_FB.m_DrawFBO.DrawBuffers[i]; + + if(db >= 0) + { + ret[i].Id = m_GL->m_FB.m_DrawFBO.Color[db].Obj; + ret[i].HighestMip = (int)m_GL->m_FB.m_DrawFBO.Color[db].Mip; + ret[i].FirstSlice = (int)m_GL->m_FB.m_DrawFBO.Color[db].Layer; + ret[i].typeHint = eCompType_None; + } + } + } + else if(IsLogVK()) + { + const auto &rp = m_Vulkan->Pass.renderpass; + const auto &fb = m_Vulkan->Pass.framebuffer; + + ret.resize(rp.colorAttachments.count); + for(int i = 0; i < rp.colorAttachments.count; i++) + { + if(rp.colorAttachments[i] < (uint32_t)fb.attachments.count) + { + ret[i].Id = fb.attachments[rp.colorAttachments[i]].img; + ret[i].HighestMip = (int)fb.attachments[rp.colorAttachments[i]].baseMip; + ret[i].FirstSlice = (int)fb.attachments[rp.colorAttachments[i]].baseLayer; + ret[i].typeHint = fb.attachments[rp.colorAttachments[i]].viewfmt.compType; + } + } + } + } + + return ret; +} diff --git a/qrenderdoc/Code/CommonPipelineState.h b/qrenderdoc/Code/CommonPipelineState.h new file mode 100644 index 000000000..5732042ff --- /dev/null +++ b/qrenderdoc/Code/CommonPipelineState.h @@ -0,0 +1,254 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include "renderdoc_replay.h" + +struct BoundResource +{ + BoundResource() + { + Id = ResourceId(); + HighestMip = -1; + FirstSlice = -1; + typeHint = eCompType_None; + } + BoundResource(ResourceId id) + { + Id = id; + HighestMip = -1; + FirstSlice = -1; + typeHint = eCompType_None; + } + + ResourceId Id; + int HighestMip; + int FirstSlice; + FormatComponentType typeHint; +}; + +struct BoundVBuffer +{ + ResourceId Buffer; + uint64_t ByteOffset; + uint32_t ByteStride; +}; + +struct VertexInputAttribute +{ + QString Name; + int VertexBuffer; + uint32_t RelativeByteOffset; + bool PerInstance; + int InstanceRate; + ResourceFormat Format; + PixelValue GenericValue; + bool Used; +}; + +struct Viewport +{ + float x, y, width, height; +}; + +class CommonPipelineState +{ +public: + CommonPipelineState() {} + void SetStates(APIProperties props, D3D11PipelineState *d3d11, D3D12PipelineState *d3d12, + GLPipelineState *gl, VulkanPipelineState *vk) + { + m_APIProps = props; + m_D3D11 = d3d11; + m_D3D12 = d3d12; + m_GL = gl; + m_Vulkan = vk; + } + + GraphicsAPI DefaultType = eGraphicsAPI_D3D11; + + bool LogLoaded() + { + return m_D3D11 != NULL || m_D3D12 != NULL || m_GL != NULL || m_Vulkan != NULL; + } + + bool IsLogD3D11() + { + return LogLoaded() && m_APIProps.pipelineType == eGraphicsAPI_D3D11 && m_D3D11 != NULL; + } + + bool IsLogD3D12() + { + return LogLoaded() && m_APIProps.pipelineType == eGraphicsAPI_D3D12 && m_D3D12 != NULL; + } + + bool IsLogGL() + { + return LogLoaded() && m_APIProps.pipelineType == eGraphicsAPI_OpenGL && m_GL != NULL; + } + + bool IsLogVK() + { + return LogLoaded() && m_APIProps.pipelineType == eGraphicsAPI_Vulkan && m_Vulkan != NULL; + } + + // add a bunch of generic properties that people can check to save having to see which pipeline + // state + // is valid and look at the appropriate part of it + bool IsTessellationEnabled() + { + if(LogLoaded()) + { + if(IsLogD3D11()) + return m_D3D11 != NULL && m_D3D11->m_HS.Shader != ResourceId(); + + if(IsLogD3D12()) + return m_D3D12 != NULL && m_D3D12->m_HS.Shader != ResourceId(); + + if(IsLogGL()) + return m_GL != NULL && m_GL->m_TES.Shader != ResourceId(); + + if(IsLogVK()) + return m_Vulkan != NULL && m_Vulkan->TES.Shader != ResourceId(); + } + + return false; + } + + bool SupportsResourceArrays() { return LogLoaded() && IsLogVK(); } + bool SupportsBarriers() { return LogLoaded() && (IsLogVK() || IsLogD3D12()); } + // whether or not the PostVS data is aligned in the typical fashion + // ie. vectors not crossing float4 boundaries). APIs that use stream-out + // or transform feedback have tightly packed data, but APIs that rewrite + // shaders to dump data might have these alignment requirements + bool HasAlignedPostVSData() { return LogLoaded() && IsLogVK(); } + QString GetImageLayout(ResourceId id); + QString Abbrev(ShaderStageType stage); + QString OutputAbbrev(); + + Viewport GetViewport(int index); + ShaderBindpointMapping GetBindpointMapping(ShaderStageType stage); + ShaderReflection *GetShaderReflection(ShaderStageType stage); + QString GetShaderEntryPoint(ShaderStageType stage); + ResourceId GetShader(ShaderStageType stage); + QString GetShaderName(ShaderStageType stage); + void GetIBuffer(ResourceId &buf, uint64_t &ByteOffset); + bool IsStripRestartEnabled(); + uint32_t GetStripRestartIndex(uint32_t indexByteWidth); + QVector GetVBuffers(); + QVector GetVertexInputs(); + void GetConstantBuffer(ShaderStageType stage, uint32_t BufIdx, uint32_t ArrayIdx, ResourceId &buf, + uint64_t &ByteOffset, uint64_t &ByteSize); + QMap> GetReadOnlyResources(ShaderStageType stage); + QMap> GetReadWriteResources(ShaderStageType stage); + BoundResource GetDepthTarget(); + QVector GetOutputTargets(); + +private: + D3D11PipelineState *m_D3D11 = NULL; + D3D12PipelineState *m_D3D12 = NULL; + GLPipelineState *m_GL = NULL; + VulkanPipelineState *m_Vulkan = NULL; + APIProperties m_APIProps; + + const D3D11PipelineState::ShaderStage &GetD3D11Stage(ShaderStageType stage) + { + if(stage == eShaderStage_Vertex) + return m_D3D11->m_VS; + if(stage == eShaderStage_Domain) + return m_D3D11->m_DS; + if(stage == eShaderStage_Hull) + return m_D3D11->m_HS; + if(stage == eShaderStage_Geometry) + return m_D3D11->m_GS; + if(stage == eShaderStage_Pixel) + return m_D3D11->m_PS; + if(stage == eShaderStage_Compute) + return m_D3D11->m_CS; + + RENDERDOC_LogText("Error - invalid stage"); + return m_D3D11->m_CS; + } + + const D3D12PipelineState::ShaderStage &GetD3D12Stage(ShaderStageType stage) + { + if(stage == eShaderStage_Vertex) + return m_D3D12->m_VS; + if(stage == eShaderStage_Domain) + return m_D3D12->m_DS; + if(stage == eShaderStage_Hull) + return m_D3D12->m_HS; + if(stage == eShaderStage_Geometry) + return m_D3D12->m_GS; + if(stage == eShaderStage_Pixel) + return m_D3D12->m_PS; + if(stage == eShaderStage_Compute) + return m_D3D12->m_CS; + + RENDERDOC_LogText("Error - invalid stage"); + return m_D3D12->m_CS; + } + + const GLPipelineState::ShaderStage &GetGLStage(ShaderStageType stage) + { + if(stage == eShaderStage_Vertex) + return m_GL->m_VS; + if(stage == eShaderStage_Tess_Control) + return m_GL->m_TCS; + if(stage == eShaderStage_Tess_Eval) + return m_GL->m_TES; + if(stage == eShaderStage_Geometry) + return m_GL->m_GS; + if(stage == eShaderStage_Fragment) + return m_GL->m_FS; + if(stage == eShaderStage_Compute) + return m_GL->m_CS; + + RENDERDOC_LogText("Error - invalid stage"); + return m_GL->m_CS; + } + + const VulkanPipelineState::ShaderStage &GetVulkanStage(ShaderStageType stage) + { + if(stage == eShaderStage_Vertex) + return m_Vulkan->VS; + if(stage == eShaderStage_Tess_Control) + return m_Vulkan->TCS; + if(stage == eShaderStage_Tess_Eval) + return m_Vulkan->TES; + if(stage == eShaderStage_Geometry) + return m_Vulkan->GS; + if(stage == eShaderStage_Fragment) + return m_Vulkan->FS; + if(stage == eShaderStage_Compute) + return m_Vulkan->CS; + + RENDERDOC_LogText("Error - invalid stage"); + return m_Vulkan->CS; + } +}; \ No newline at end of file diff --git a/qrenderdoc/qrenderdoc.pro b/qrenderdoc/qrenderdoc.pro index 7c79172cb..3472e8ffb 100644 --- a/qrenderdoc/qrenderdoc.pro +++ b/qrenderdoc/qrenderdoc.pro @@ -94,7 +94,9 @@ SOURCES += Code/main.cpp \ 3rdparty/flowlayout/FlowLayout.cpp \ Widgets/ResourcePreview.cpp \ Widgets/RDLabel.cpp \ - Widgets/ThumbnailStrip.cpp + Widgets/ThumbnailStrip.cpp \ + Code/CaptureContext.cpp \ + Code/CommonPipelineState.cpp HEADERS += Windows/MainWindow.h \ Windows/EventBrowser.h \ @@ -110,7 +112,9 @@ HEADERS += Windows/MainWindow.h \ 3rdparty/flowlayout/FlowLayout.h \ Widgets/ResourcePreview.h \ Widgets/RDLabel.h \ - Widgets/ThumbnailStrip.h + Widgets/ThumbnailStrip.h \ + Code/CaptureContext.h \ + Code/CommonPipelineState.h FORMS += Windows/MainWindow.ui \ Windows/EventBrowser.ui \ diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index eb3f36679..057ee1612 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -276,6 +276,7 @@ + @@ -316,6 +317,7 @@ + diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index 5f9c58b3a..8916e42d2 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -130,6 +130,9 @@ Generated Files + + Generated Files + @@ -183,6 +186,9 @@ Code + + Code + diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 766cae56f..5153f6201 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -265,6 +265,31 @@ struct ShaderReflection struct BindpointMap { +#ifdef __cplusplus + BindpointMap() + { + bindset = 0; + bind = 0; + used = false; + arraySize = 1; + } + + BindpointMap(int32_t s, int32_t b) + { + bindset = s; + bind = b; + used = false; + arraySize = 1; + } + + bool operator<(const BindpointMap &o) const + { + if(bindset != o.bindset) + return bindset < o.bindset; + return bind < o.bind; + } +#endif + int32_t bindset; int32_t bind; bool32 used; diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index c027be267..4423493ea 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -170,7 +170,7 @@ void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl, cb.byteSize = dxbc->m_CBuffers[i].descriptor.byteSize; cb.bindPoint = (uint32_t)c; - BindpointMap map = {}; + BindpointMap map; map.arraySize = 1; map.bind = (int32_t)i; map.used = true; @@ -305,7 +305,7 @@ void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl, res.bindPoint = IsReadWrite ? rwidx : roidx; - BindpointMap map = {}; + BindpointMap map; map.arraySize = 1; map.bind = r.bindPoint; map.used = true; diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index 8084e8765..e04c42ded 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -4020,7 +4020,7 @@ void SPVModule::MakeReflection(const string &entryPoint, ShaderReflection *refle cblock.name = StringFormat::Fmt("uniforms%u", inst->id); cblock.bufferBacked = !pushConst; - BindpointMap bindmap = {0}; + BindpointMap bindmap; // set can be implicitly 0, but the binding must be set explicitly. // If no binding is found, we set -1 and sort to the end of the resources // list as it's not bound anywhere (most likely, declared but not used) @@ -4182,7 +4182,7 @@ void SPVModule::MakeReflection(const string &entryPoint, ShaderReflection *refle res.variableType.descriptor.rowMajorStorage = false; res.variableType.descriptor.rowMajorStorage = false; - BindpointMap bindmap = {0}; + BindpointMap bindmap; // set can be implicitly 0, but the binding must be set explicitly. // If no binding is found, we set -1 and sort to the end of the resources // list as it's not bound anywhere (most likely, declared but not used) @@ -4243,7 +4243,7 @@ void SPVModule::MakeReflection(const string &entryPoint, ShaderReflection *refle cblock.bufferBacked = false; cblock.byteSize = 0; - BindpointMap bindmap = {0}; + BindpointMap bindmap; // set something crazy so this doesn't overlap with a real buffer binding // also identify this as specialization constant data