mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-12 21:10:42 +00:00
2d8930d88e
Gets the resource details for a direct heap access binding
1142 lines
47 KiB
C++
1142 lines
47 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2024 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 "d3d12_dxil_debug.h"
|
|
#include "data/hlsl/hlsl_cbuffers.h"
|
|
#include "driver/dxgi/dxgi_common.h"
|
|
#include "d3d12_command_queue.h"
|
|
#include "d3d12_debug.h"
|
|
#include "d3d12_replay.h"
|
|
#include "d3d12_resources.h"
|
|
#include "d3d12_state.h"
|
|
|
|
using namespace DXIL;
|
|
using namespace DXILDebug;
|
|
|
|
namespace DXILDebug
|
|
{
|
|
static DXBC::ResourceRetType ConvertCompTypeToResourceRetType(const CompType compType)
|
|
{
|
|
switch(compType)
|
|
{
|
|
case CompType::Float: return DXBC::ResourceRetType::RETURN_TYPE_FLOAT;
|
|
case CompType::UNormSRGB:
|
|
case CompType::UNorm: return DXBC::ResourceRetType::RETURN_TYPE_UNORM;
|
|
case CompType::SNorm: return DXBC::ResourceRetType::RETURN_TYPE_SNORM;
|
|
case CompType::UInt: return DXBC::ResourceRetType::RETURN_TYPE_UINT;
|
|
case CompType::SInt: return DXBC::ResourceRetType::RETURN_TYPE_SINT;
|
|
case CompType::Typeless:
|
|
case CompType::UScaled:
|
|
case CompType::SScaled:
|
|
case CompType::Depth:
|
|
default:
|
|
RDCERR("Unexpected component type %s", ToStr(compType).c_str());
|
|
return DXBC::ResourceRetType ::RETURN_TYPE_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
static DXBCBytecode::ResourceDimension ConvertSRVResourceDimensionToResourceDimension(
|
|
D3D12_SRV_DIMENSION dim)
|
|
{
|
|
switch(dim)
|
|
{
|
|
case D3D12_SRV_DIMENSION_UNKNOWN:
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_UNKNOWN;
|
|
case D3D12_SRV_DIMENSION_BUFFER:
|
|
return DXBCBytecode::ResourceDimension ::RESOURCE_DIMENSION_BUFFER;
|
|
case D3D12_SRV_DIMENSION_TEXTURE1D:
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_TEXTURE1D;
|
|
case D3D12_SRV_DIMENSION_TEXTURE1DARRAY:
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_TEXTURE1DARRAY;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2D:
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_TEXTURE2D;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2DARRAY:
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_TEXTURE2DARRAY;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2DMS:
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_TEXTURE2DMS;
|
|
case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY:
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_TEXTURE2DMSARRAY;
|
|
case D3D12_SRV_DIMENSION_TEXTURE3D:
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_TEXTURE3D;
|
|
case D3D12_SRV_DIMENSION_TEXTURECUBE:
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_TEXTURECUBE;
|
|
case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY:
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_TEXTURECUBEARRAY;
|
|
default:
|
|
RDCERR("Unexpected SRV dimension %s", ToStr(dim).c_str());
|
|
return DXBCBytecode::ResourceDimension::RESOURCE_DIMENSION_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
static DXDebug::SamplerMode ConvertSamplerFilterToSamplerMode(D3D12_FILTER filter)
|
|
{
|
|
switch(filter)
|
|
{
|
|
case D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT:
|
|
case D3D12_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR:
|
|
case D3D12_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT:
|
|
case D3D12_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR:
|
|
case D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT:
|
|
case D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
|
|
case D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT:
|
|
case D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR:
|
|
case D3D12_FILTER_COMPARISON_MIN_MAG_ANISOTROPIC_MIP_POINT:
|
|
case D3D12_FILTER_COMPARISON_ANISOTROPIC:
|
|
return DXBCBytecode::SamplerMode::SAMPLER_MODE_COMPARISON;
|
|
break;
|
|
default: break;
|
|
}
|
|
return DXBCBytecode::SamplerMode::SAMPLER_MODE_DEFAULT;
|
|
}
|
|
|
|
static bool IsShaderParameterVisible(DXBC::ShaderType shaderType,
|
|
D3D12_SHADER_VISIBILITY shaderVisibility)
|
|
{
|
|
if(shaderVisibility == D3D12_SHADER_VISIBILITY_ALL)
|
|
return true;
|
|
|
|
if(shaderType == DXBC::ShaderType::Vertex && shaderVisibility == D3D12_SHADER_VISIBILITY_VERTEX)
|
|
return true;
|
|
|
|
if(shaderType == DXBC::ShaderType::Pixel && shaderVisibility == D3D12_SHADER_VISIBILITY_PIXEL)
|
|
return true;
|
|
|
|
if(shaderType == DXBC::ShaderType::Amplification &&
|
|
shaderVisibility == D3D12_SHADER_VISIBILITY_AMPLIFICATION)
|
|
return true;
|
|
|
|
if(shaderType == DXBC::ShaderType::Mesh && shaderVisibility == D3D12_SHADER_VISIBILITY_MESH)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static void FillViewFmtFromResourceFormat(DXGI_FORMAT format, GlobalState::ViewFmt &viewFmt)
|
|
{
|
|
RDCASSERT(format != DXGI_FORMAT_UNKNOWN);
|
|
ResourceFormat fmt = MakeResourceFormat(format);
|
|
|
|
viewFmt.byteWidth = fmt.compByteWidth;
|
|
viewFmt.numComps = fmt.compCount;
|
|
viewFmt.compType = fmt.compType;
|
|
|
|
if(format == DXGI_FORMAT_R11G11B10_FLOAT)
|
|
viewFmt.byteWidth = 11;
|
|
else if(format == DXGI_FORMAT_R10G10B10A2_UINT || format == DXGI_FORMAT_R10G10B10A2_UNORM)
|
|
viewFmt.byteWidth = 10;
|
|
|
|
if(viewFmt.byteWidth == 10 || viewFmt.byteWidth == 11)
|
|
viewFmt.stride = 4; // 10 10 10 2 or 11 11 10
|
|
else
|
|
viewFmt.stride = viewFmt.byteWidth * viewFmt.numComps;
|
|
}
|
|
|
|
// Only valid/used fo root descriptors
|
|
// Root descriptors only have RawBuffer and StructuredBuffer types
|
|
static uint32_t GetUAVBufferStrideFromShaderMetadata(const DXIL::EntryPointInterface *reflection,
|
|
const BindingSlot &slot)
|
|
{
|
|
for(const DXIL::EntryPointInterface::ResourceBase &bind : reflection->uavs)
|
|
{
|
|
if(bind.MatchesBinding(slot.shaderRegister, slot.shaderRegister, slot.registerSpace))
|
|
{
|
|
if(bind.uavData.shape == ResourceKind::RawBuffer ||
|
|
bind.uavData.shape == ResourceKind::StructuredBuffer)
|
|
{
|
|
return bind.uavData.elementStride;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t GetSRVBufferStrideFromShaderMetadata(const DXIL::EntryPointInterface *reflection,
|
|
const BindingSlot &slot)
|
|
{
|
|
for(const DXIL::EntryPointInterface::ResourceBase &bind : reflection->srvs)
|
|
{
|
|
if(bind.MatchesBinding(slot.shaderRegister, slot.shaderRegister, slot.registerSpace))
|
|
{
|
|
if(bind.srvData.shape == ResourceKind::RawBuffer ||
|
|
bind.srvData.shape == ResourceKind::StructuredBuffer)
|
|
{
|
|
return bind.srvData.elementStride;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void FlattenSingleVariable(const rdcstr &cbufferName, uint32_t byteOffset,
|
|
const rdcstr &basename, const ShaderVariable &v,
|
|
rdcarray<ShaderVariable> &outvars,
|
|
rdcarray<SourceVariableMapping> &sourcevars)
|
|
{
|
|
size_t outIdx = byteOffset / 16;
|
|
size_t outComp = (byteOffset % 16) / 4;
|
|
|
|
if(v.RowMajor())
|
|
outvars.resize(RDCMAX(outIdx + v.rows, outvars.size()));
|
|
else
|
|
outvars.resize(RDCMAX(outIdx + v.columns, outvars.size()));
|
|
|
|
if(outvars[outIdx].columns > 0)
|
|
{
|
|
// if we already have a variable in this slot, just copy the data for this variable and add
|
|
// the source mapping. We should not overlap into the next register as that's not allowed.
|
|
memcpy(&outvars[outIdx].value.u32v[outComp], &v.value.u32v[0], sizeof(uint32_t) * v.columns);
|
|
|
|
SourceVariableMapping mapping;
|
|
mapping.name = basename;
|
|
mapping.type = v.type;
|
|
mapping.rows = v.rows;
|
|
mapping.columns = v.columns;
|
|
mapping.offset = byteOffset;
|
|
mapping.variables.resize(v.columns);
|
|
|
|
for(int i = 0; i < v.columns; i++)
|
|
{
|
|
mapping.variables[i].type = DebugVariableType::Constant;
|
|
mapping.variables[i].name = StringFormat::Fmt("%s[%u]", cbufferName.c_str(), outIdx);
|
|
mapping.variables[i].component = uint16_t(outComp + i);
|
|
}
|
|
|
|
sourcevars.push_back(mapping);
|
|
}
|
|
else
|
|
{
|
|
const uint32_t numRegisters = v.RowMajor() ? v.rows : v.columns;
|
|
for(uint32_t reg = 0; reg < numRegisters; reg++)
|
|
{
|
|
outvars[outIdx + reg].rows = 1;
|
|
outvars[outIdx + reg].type = VarType::Unknown;
|
|
outvars[outIdx + reg].columns = v.columns;
|
|
outvars[outIdx + reg].flags = v.flags;
|
|
}
|
|
|
|
if(v.RowMajor())
|
|
{
|
|
for(size_t ri = 0; ri < v.rows; ri++)
|
|
memcpy(&outvars[outIdx + ri].value.u32v[0], &v.value.u32v[ri * v.columns],
|
|
sizeof(uint32_t) * v.columns);
|
|
}
|
|
else
|
|
{
|
|
// if we have a matrix stored in column major order, we need to transpose it back so we can
|
|
// unroll it into vectors.
|
|
for(size_t ci = 0; ci < v.columns; ci++)
|
|
for(size_t ri = 0; ri < v.rows; ri++)
|
|
outvars[outIdx + ci].value.u32v[ri] = v.value.u32v[ri * v.columns + ci];
|
|
}
|
|
|
|
SourceVariableMapping mapping;
|
|
mapping.name = basename;
|
|
mapping.type = v.type;
|
|
mapping.rows = v.rows;
|
|
mapping.columns = v.columns;
|
|
mapping.offset = byteOffset;
|
|
mapping.variables.resize(v.rows * v.columns);
|
|
|
|
RDCASSERT(outComp == 0 || v.rows == 1, outComp, v.rows);
|
|
|
|
size_t i = 0;
|
|
for(uint8_t r = 0; r < v.rows; r++)
|
|
{
|
|
for(uint8_t c = 0; c < v.columns; c++)
|
|
{
|
|
size_t regIndex = outIdx + (v.RowMajor() ? r : c);
|
|
size_t compIndex = outComp + (v.RowMajor() ? c : r);
|
|
|
|
mapping.variables[i].type = DebugVariableType::Constant;
|
|
mapping.variables[i].name = StringFormat::Fmt("%s[%zu]", cbufferName.c_str(), regIndex);
|
|
mapping.variables[i].component = uint16_t(compIndex);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
sourcevars.push_back(mapping);
|
|
}
|
|
}
|
|
|
|
static void FlattenVariables(const rdcstr &cbufferName, const rdcarray<ShaderConstant> &constants,
|
|
const rdcarray<ShaderVariable> &invars,
|
|
rdcarray<ShaderVariable> &outvars, const rdcstr &prefix,
|
|
uint32_t baseOffset, rdcarray<SourceVariableMapping> &sourceVars)
|
|
{
|
|
RDCASSERTEQUAL(constants.size(), invars.size());
|
|
|
|
for(size_t i = 0; i < constants.size(); i++)
|
|
{
|
|
const ShaderConstant &c = constants[i];
|
|
const ShaderVariable &v = invars[i];
|
|
|
|
uint32_t byteOffset = baseOffset + c.byteOffset;
|
|
|
|
rdcstr basename = prefix + rdcstr(v.name);
|
|
|
|
if(v.type == VarType::Struct)
|
|
{
|
|
// check if this is an array of structs or not
|
|
if(c.type.elements == 1)
|
|
{
|
|
FlattenVariables(cbufferName, c.type.members, v.members, outvars, basename + ".",
|
|
byteOffset, sourceVars);
|
|
}
|
|
else
|
|
{
|
|
for(int m = 0; m < v.members.count(); m++)
|
|
{
|
|
FlattenVariables(cbufferName, c.type.members, v.members[m].members, outvars,
|
|
StringFormat::Fmt("%s[%zu].", basename.c_str(), m),
|
|
byteOffset + m * c.type.arrayByteStride, sourceVars);
|
|
}
|
|
}
|
|
}
|
|
else if(c.type.elements > 1 || (v.rows == 0 && v.columns == 0) || !v.members.empty())
|
|
{
|
|
for(int m = 0; m < v.members.count(); m++)
|
|
{
|
|
FlattenSingleVariable(cbufferName, byteOffset + m * c.type.arrayByteStride,
|
|
StringFormat::Fmt("%s[%zu]", basename.c_str(), m), v.members[m],
|
|
outvars, sourceVars);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FlattenSingleVariable(cbufferName, byteOffset, basename, v, outvars, sourceVars);
|
|
}
|
|
}
|
|
}
|
|
static void AddCBufferToGlobalState(const DXIL::Program *program, GlobalState &global,
|
|
rdcarray<SourceVariableMapping> &sourceVars,
|
|
const ShaderReflection &refl, const BindingSlot &slot,
|
|
bytebuf &cbufData)
|
|
{
|
|
// Find the identifier
|
|
size_t numCBs = refl.constantBlocks.size();
|
|
for(size_t i = 0; i < numCBs; ++i)
|
|
{
|
|
const ConstantBlock &cb = refl.constantBlocks[i];
|
|
if(slot.registerSpace == (uint32_t)cb.fixedBindSetOrSpace &&
|
|
slot.shaderRegister >= (uint32_t)cb.fixedBindNumber &&
|
|
slot.shaderRegister < (uint32_t)(cb.fixedBindNumber + cb.bindArraySize))
|
|
{
|
|
uint32_t arrayIndex = slot.shaderRegister - cb.fixedBindNumber;
|
|
|
|
rdcarray<ShaderVariable> &targetVars =
|
|
cb.bindArraySize > 1 ? global.constantBlocks[i].members[arrayIndex].members
|
|
: global.constantBlocks[i].members;
|
|
RDCASSERTMSG("Reassigning previously filled cbuffer", targetVars.empty());
|
|
|
|
global.constantBlocksData[i] = cbufData;
|
|
global.constantBlocks[i].name =
|
|
Debugger::GetResourceReferenceName(program, ResourceClass::CBuffer, slot);
|
|
|
|
SourceVariableMapping cbSourceMapping;
|
|
cbSourceMapping.name = refl.constantBlocks[i].name;
|
|
cbSourceMapping.variables.push_back(
|
|
DebugVariableReference(DebugVariableType::Constant, global.constantBlocks[i].name));
|
|
sourceVars.push_back(cbSourceMapping);
|
|
|
|
rdcstr identifierPrefix = global.constantBlocks[i].name;
|
|
rdcstr variablePrefix = refl.constantBlocks[i].name;
|
|
if(cb.bindArraySize > 1)
|
|
{
|
|
identifierPrefix =
|
|
StringFormat::Fmt("%s[%u]", global.constantBlocks[i].name.c_str(), arrayIndex);
|
|
variablePrefix = StringFormat::Fmt("%s[%u]", refl.constantBlocks[i].name.c_str(), arrayIndex);
|
|
|
|
// The above sourceVar is for the logical identifier, and FlattenVariables adds the
|
|
// individual elements of the constant buffer. For CB arrays, add an extra source
|
|
// var for the CB array index
|
|
SourceVariableMapping cbArrayMapping;
|
|
global.constantBlocks[i].members[arrayIndex].name = StringFormat::Fmt("[%u]", arrayIndex);
|
|
cbArrayMapping.name = variablePrefix;
|
|
cbArrayMapping.variables.push_back(
|
|
DebugVariableReference(DebugVariableType::Constant, identifierPrefix));
|
|
sourceVars.push_back(cbArrayMapping);
|
|
}
|
|
const rdcarray<ShaderConstant> &constants =
|
|
(cb.bindArraySize > 1) ? refl.constantBlocks[i].variables[0].type.members
|
|
: refl.constantBlocks[i].variables;
|
|
|
|
rdcarray<ShaderVariable> vars;
|
|
StandardFillCBufferVariables(refl.resourceId, constants, vars, cbufData);
|
|
FlattenVariables(identifierPrefix, constants, vars, targetVars, variablePrefix + ".", 0,
|
|
sourceVars);
|
|
for(size_t c = 0; c < targetVars.size(); c++)
|
|
targetVars[c].name = StringFormat::Fmt("[%u]", (uint32_t)c);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FetchConstantBufferData(WrappedID3D12Device *device, const DXIL::Program *program,
|
|
const D3D12RenderState::RootSignature &rootsig,
|
|
const ShaderReflection &refl, GlobalState &global,
|
|
rdcarray<SourceVariableMapping> &sourceVars)
|
|
{
|
|
WrappedID3D12RootSignature *pD3D12RootSig =
|
|
device->GetResourceManager()->GetCurrentAs<WrappedID3D12RootSignature>(rootsig.rootsig);
|
|
const DXBC::ShaderType shaderType = program->GetShaderType();
|
|
|
|
size_t numParams = RDCMIN(pD3D12RootSig->sig.Parameters.size(), rootsig.sigelems.size());
|
|
for(size_t i = 0; i < numParams; i++)
|
|
{
|
|
const D3D12RootSignatureParameter &rootSigParam = pD3D12RootSig->sig.Parameters[i];
|
|
const D3D12RenderState::SignatureElement &element = rootsig.sigelems[i];
|
|
if(IsShaderParameterVisible(shaderType, rootSigParam.ShaderVisibility))
|
|
{
|
|
if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS &&
|
|
element.type == eRootConst)
|
|
{
|
|
BindingSlot slot(rootSigParam.Constants.ShaderRegister, rootSigParam.Constants.RegisterSpace);
|
|
UINT sizeBytes = sizeof(uint32_t) * RDCMIN(rootSigParam.Constants.Num32BitValues,
|
|
(UINT)element.constants.size());
|
|
bytebuf cbufData((const byte *)element.constants.data(), sizeBytes);
|
|
AddCBufferToGlobalState(program, global, sourceVars, refl, slot, cbufData);
|
|
}
|
|
else if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV && element.type == eRootCBV)
|
|
{
|
|
BindingSlot slot(rootSigParam.Descriptor.ShaderRegister,
|
|
rootSigParam.Descriptor.RegisterSpace);
|
|
ID3D12Resource *cbv = device->GetResourceManager()->GetCurrentAs<ID3D12Resource>(element.id);
|
|
bytebuf cbufData;
|
|
device->GetDebugManager()->GetBufferData(cbv, element.offset, 0, cbufData);
|
|
AddCBufferToGlobalState(program, global, sourceVars, refl, slot, cbufData);
|
|
}
|
|
else if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE &&
|
|
element.type == eRootTable)
|
|
{
|
|
UINT prevTableOffset = 0;
|
|
WrappedID3D12DescriptorHeap *heap =
|
|
device->GetResourceManager()->GetCurrentAs<WrappedID3D12DescriptorHeap>(element.id);
|
|
|
|
size_t numRanges = rootSigParam.ranges.size();
|
|
for(size_t r = 0; r < numRanges; r++)
|
|
{
|
|
// For this traversal we only care about CBV descriptor ranges, but we still need to
|
|
// calculate the table offsets in case a descriptor table has a combination of
|
|
// different range types
|
|
const D3D12_DESCRIPTOR_RANGE1 &range = rootSigParam.ranges[r];
|
|
|
|
UINT offset = range.OffsetInDescriptorsFromTableStart;
|
|
if(range.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
|
|
offset = prevTableOffset;
|
|
|
|
D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr;
|
|
desc += element.offset;
|
|
desc += offset;
|
|
|
|
UINT numDescriptors = range.NumDescriptors;
|
|
if(numDescriptors == UINT_MAX)
|
|
{
|
|
// Find out how many descriptors are left after
|
|
numDescriptors = heap->GetNumDescriptors() - offset - (UINT)element.offset;
|
|
|
|
// TODO: Look up the bind point in the D3D12 state to try to get
|
|
// a better guess at the number of descriptors
|
|
}
|
|
|
|
prevTableOffset = offset + numDescriptors;
|
|
|
|
if(range.RangeType != D3D12_DESCRIPTOR_RANGE_TYPE_CBV)
|
|
continue;
|
|
|
|
BindingSlot slot(range.BaseShaderRegister, range.RegisterSpace);
|
|
|
|
bytebuf cbufData;
|
|
for(UINT n = 0; n < numDescriptors; ++n, ++slot.shaderRegister)
|
|
{
|
|
const D3D12_CONSTANT_BUFFER_VIEW_DESC &cbv = desc->GetCBV();
|
|
ResourceId resId;
|
|
uint64_t byteOffset = 0;
|
|
WrappedID3D12Resource::GetResIDFromAddr(cbv.BufferLocation, resId, byteOffset);
|
|
ID3D12Resource *pCbvResource =
|
|
device->GetResourceManager()->GetCurrentAs<ID3D12Resource>(resId);
|
|
cbufData.clear();
|
|
|
|
if(cbv.SizeInBytes > 0)
|
|
device->GetDebugManager()->GetBufferData(pCbvResource, byteOffset, cbv.SizeInBytes,
|
|
cbufData);
|
|
AddCBufferToGlobalState(program, global, sourceVars, refl, slot, cbufData);
|
|
|
|
desc++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
InterpolationMode GetInterpolationModeForInputParam(const SigParameter &sig,
|
|
const rdcarray<SigParameter> &stageInputSig,
|
|
const DXIL::Program *program)
|
|
{
|
|
if(sig.varType == VarType::SInt || sig.varType == VarType::UInt)
|
|
return InterpolationMode::INTERPOLATION_CONSTANT;
|
|
|
|
if(sig.varType == VarType::Float)
|
|
{
|
|
// if we're packed with ints on either side, we must be nointerpolation
|
|
size_t numInputs = stageInputSig.size();
|
|
for(size_t j = 0; j < numInputs; j++)
|
|
{
|
|
if(sig.regIndex == stageInputSig[j].regIndex && stageInputSig[j].varType != VarType::Float)
|
|
return DXBC::InterpolationMode::INTERPOLATION_CONSTANT;
|
|
}
|
|
|
|
if(!program)
|
|
{
|
|
RDCERR("No DXIL program");
|
|
return DXBC::InterpolationMode::INTERPOLATION_UNDEFINED;
|
|
}
|
|
// Search the DXIL shader meta data to get the interpolation mode
|
|
const DXIL::EntryPointInterface *entryPoint = program->GetEntryPointInterface();
|
|
if(!entryPoint)
|
|
{
|
|
RDCERR("No entry point interface found in DXIL program");
|
|
return DXBC::InterpolationMode::INTERPOLATION_UNDEFINED;
|
|
}
|
|
for(size_t j = 0; j < entryPoint->inputs.size(); ++j)
|
|
{
|
|
const EntryPointInterface::Signature &dxilSig = entryPoint->inputs[j];
|
|
if(dxilSig.startRow == (int32_t)sig.regIndex)
|
|
{
|
|
const int firstElem = sig.regChannelMask & 0x1 ? 0
|
|
: sig.regChannelMask & 0x2 ? 1
|
|
: sig.regChannelMask & 0x4 ? 2
|
|
: sig.regChannelMask & 0x8 ? 3
|
|
: -1;
|
|
if(dxilSig.startCol == firstElem)
|
|
{
|
|
if(sig.semanticName == dxilSig.name)
|
|
{
|
|
return (InterpolationMode)dxilSig.interpolation;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return DXBC::InterpolationMode::INTERPOLATION_UNDEFINED;
|
|
}
|
|
|
|
RDCERR("Unexpected input signature type: %s", ToStr(sig.varType).c_str());
|
|
return InterpolationMode::INTERPOLATION_UNDEFINED;
|
|
}
|
|
|
|
void GetInterpolationModeForInputParams(const rdcarray<SigParameter> &inputSig,
|
|
const DXIL::Program *program,
|
|
rdcarray<DXBC::InterpolationMode> &interpModes)
|
|
{
|
|
size_t numInputs = inputSig.size();
|
|
interpModes.resize(numInputs);
|
|
for(size_t i = 0; i < numInputs; i++)
|
|
{
|
|
const SigParameter &sig = inputSig[i];
|
|
interpModes[i] = GetInterpolationModeForInputParam(sig, inputSig, program);
|
|
}
|
|
}
|
|
|
|
D3D12APIWrapper::D3D12APIWrapper(WrappedID3D12Device *device, const DXIL::Program &dxilProgram,
|
|
GlobalState &globalState, uint32_t eventId)
|
|
: m_Device(device),
|
|
m_EntryPointInterface(dxilProgram.GetEntryPointInterface()),
|
|
m_GlobalState(globalState),
|
|
m_ShaderType(dxilProgram.GetShaderType()),
|
|
m_EventId(eventId)
|
|
{
|
|
}
|
|
|
|
D3D12APIWrapper::~D3D12APIWrapper()
|
|
{
|
|
// if we replayed to before the action for fetching some UAVs
|
|
// replay back to after the action to keep the state consistent.
|
|
if(m_DidReplay)
|
|
{
|
|
D3D12MarkerRegion region(m_Device->GetQueue()->GetReal(), "ResetReplay");
|
|
// replay the action to get back to 'normal' state for this event
|
|
m_Device->ReplayLog(0, m_EventId, eReplay_OnlyDraw);
|
|
}
|
|
}
|
|
|
|
void D3D12APIWrapper::FetchSRV(const BindingSlot &slot)
|
|
{
|
|
const D3D12RenderState &rs = m_Device->GetQueue()->GetCommandData()->m_RenderState;
|
|
D3D12ResourceManager *rm = m_Device->GetResourceManager();
|
|
|
|
// Get the root signature
|
|
const D3D12RenderState::RootSignature *pRootSignature = NULL;
|
|
if(m_ShaderType == DXBC::ShaderType::Compute)
|
|
{
|
|
if(rs.compute.rootsig != ResourceId())
|
|
{
|
|
pRootSignature = &rs.compute;
|
|
}
|
|
}
|
|
else if(rs.graphics.rootsig != ResourceId())
|
|
{
|
|
pRootSignature = &rs.graphics;
|
|
}
|
|
|
|
DXILDebug::GlobalState::SRVData &srvData = m_GlobalState.srvs[slot];
|
|
|
|
if(pRootSignature)
|
|
{
|
|
WrappedID3D12RootSignature *pD3D12RootSig =
|
|
rm->GetCurrentAs<WrappedID3D12RootSignature>(pRootSignature->rootsig);
|
|
|
|
size_t numParams = RDCMIN(pD3D12RootSig->sig.Parameters.size(), pRootSignature->sigelems.size());
|
|
for(size_t i = 0; i < numParams; ++i)
|
|
{
|
|
const D3D12RootSignatureParameter ¶m = pD3D12RootSig->sig.Parameters[i];
|
|
const D3D12RenderState::SignatureElement &element = pRootSignature->sigelems[i];
|
|
if(IsShaderParameterVisible(m_ShaderType, param.ShaderVisibility))
|
|
{
|
|
if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_SRV && element.type == eRootSRV)
|
|
{
|
|
if(param.Descriptor.ShaderRegister == slot.shaderRegister &&
|
|
param.Descriptor.RegisterSpace == slot.registerSpace)
|
|
{
|
|
// Found the requested SRV
|
|
ID3D12Resource *pResource = rm->GetCurrentAs<ID3D12Resource>(element.id);
|
|
if(pResource)
|
|
{
|
|
D3D12_RESOURCE_DESC resDesc = pResource->GetDesc();
|
|
|
|
// DXC allows root buffers to have a stride of up to 16 bytes in the shader, which
|
|
// means encoding the byte offset into the first element here is wrong without
|
|
// knowing what the actual accessed stride is. Instead we only fetch the data from
|
|
// that offset onwards.
|
|
|
|
// Root buffers are typeless, try with the resource desc format
|
|
// The debugger code will handle DXGI_FORMAT_UNKNOWN
|
|
if(resDesc.Format != DXGI_FORMAT_UNKNOWN)
|
|
DXILDebug::FillViewFmtFromResourceFormat(resDesc.Format, srvData.resInfo.format);
|
|
|
|
srvData.resInfo.isRootDescriptor = true;
|
|
srvData.resInfo.firstElement = 0;
|
|
// root arguments have no bounds checking, so use the most conservative number of elements
|
|
srvData.resInfo.numElements = uint32_t(resDesc.Width - element.offset);
|
|
|
|
if(resDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
|
|
{
|
|
// Get the buffer stride from the shader metadata (for StructuredBuffer, RawBuffer)
|
|
uint32_t mdStride =
|
|
DXILDebug::GetSRVBufferStrideFromShaderMetadata(m_EntryPointInterface, slot);
|
|
if(mdStride != 0)
|
|
srvData.resInfo.format.stride = mdStride;
|
|
m_Device->GetDebugManager()->GetBufferData(pResource, element.offset, 0,
|
|
srvData.data);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
else if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE &&
|
|
element.type == eRootTable)
|
|
{
|
|
UINT prevTableOffset = 0;
|
|
WrappedID3D12DescriptorHeap *heap =
|
|
rm->GetCurrentAs<WrappedID3D12DescriptorHeap>(element.id);
|
|
|
|
size_t numRanges = param.ranges.size();
|
|
for(size_t r = 0; r < numRanges; ++r)
|
|
{
|
|
const D3D12_DESCRIPTOR_RANGE1 &range = param.ranges[r];
|
|
|
|
// For every range, check the number of descriptors so that we are accessing the
|
|
// correct data for append descriptor tables, even if the range type doesn't match
|
|
// what we need to fetch
|
|
UINT offset = range.OffsetInDescriptorsFromTableStart;
|
|
if(range.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
|
|
offset = prevTableOffset;
|
|
|
|
D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr;
|
|
desc += element.offset;
|
|
desc += offset;
|
|
|
|
UINT numDescriptors = range.NumDescriptors;
|
|
if(numDescriptors == UINT_MAX)
|
|
{
|
|
// Find out how many descriptors are left after
|
|
numDescriptors = heap->GetNumDescriptors() - offset - (UINT)element.offset;
|
|
|
|
// TODO: Should we look up the bind point in the D3D12 state to try to get
|
|
// a better guess at the number of descriptors?
|
|
}
|
|
|
|
prevTableOffset = offset + numDescriptors;
|
|
|
|
// Check if the range is for SRVs and the slot we want is contained
|
|
if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV &&
|
|
slot.shaderRegister >= range.BaseShaderRegister &&
|
|
slot.shaderRegister < range.BaseShaderRegister + numDescriptors &&
|
|
range.RegisterSpace == slot.registerSpace)
|
|
{
|
|
desc += slot.shaderRegister - range.BaseShaderRegister;
|
|
if(desc)
|
|
{
|
|
ResourceId srvId = desc->GetResResourceId();
|
|
ID3D12Resource *pResource = rm->GetCurrentAs<ID3D12Resource>(srvId);
|
|
if(pResource)
|
|
{
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = desc->GetSRV();
|
|
if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_UNKNOWN)
|
|
srvDesc = MakeSRVDesc(pResource->GetDesc());
|
|
|
|
if(srvDesc.Format != DXGI_FORMAT_UNKNOWN)
|
|
{
|
|
DXILDebug::FillViewFmtFromResourceFormat(srvDesc.Format, srvData.resInfo.format);
|
|
}
|
|
else
|
|
{
|
|
D3D12_RESOURCE_DESC resDesc = pResource->GetDesc();
|
|
if(resDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
|
|
srvData.resInfo.format.stride = srvDesc.Buffer.StructureByteStride;
|
|
}
|
|
|
|
if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_BUFFER)
|
|
{
|
|
srvData.resInfo.firstElement = (uint32_t)srvDesc.Buffer.FirstElement;
|
|
srvData.resInfo.numElements = srvDesc.Buffer.NumElements;
|
|
srvData.resInfo.isByteBuffer =
|
|
((srvDesc.Buffer.Flags & D3D12_BUFFER_SRV_FLAG_RAW) != 0) ? true : false;
|
|
// Get the buffer stride from the shader metadata (for StructuredBuffer, RawBuffer)
|
|
uint32_t mdStride =
|
|
DXILDebug::GetSRVBufferStrideFromShaderMetadata(m_EntryPointInterface, slot);
|
|
if(mdStride != 0)
|
|
srvData.resInfo.format.stride = mdStride;
|
|
|
|
m_Device->GetDebugManager()->GetBufferData(pResource, 0, 0, srvData.data);
|
|
}
|
|
|
|
// Textures are sampled via a pixel shader, so there's no need to copy their data
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RDCERR("Couldn't find root signature parameter corresponding to SRV %u in space %u",
|
|
slot.shaderRegister, slot.registerSpace);
|
|
return;
|
|
}
|
|
|
|
RDCERR("No root signature bound, couldn't identify SRV %u in space %u", slot.shaderRegister,
|
|
slot.registerSpace);
|
|
}
|
|
|
|
void D3D12APIWrapper::FetchUAV(const BindingSlot &slot)
|
|
{
|
|
// if the UAV might be dirty from side-effects from the action, replay back to right
|
|
// before it.
|
|
if(!m_DidReplay)
|
|
{
|
|
D3D12MarkerRegion region(m_Device->GetQueue()->GetReal(), "un-dirtying resources");
|
|
m_Device->ReplayLog(0, m_EventId, eReplay_WithoutDraw);
|
|
m_DidReplay = true;
|
|
}
|
|
|
|
const D3D12RenderState &rs = m_Device->GetQueue()->GetCommandData()->m_RenderState;
|
|
D3D12ResourceManager *rm = m_Device->GetResourceManager();
|
|
|
|
// Get the root signature
|
|
const D3D12RenderState::RootSignature *pRootSignature = NULL;
|
|
if(m_ShaderType == DXBC::ShaderType::Compute)
|
|
{
|
|
if(rs.compute.rootsig != ResourceId())
|
|
{
|
|
pRootSignature = &rs.compute;
|
|
}
|
|
}
|
|
else if(rs.graphics.rootsig != ResourceId())
|
|
{
|
|
pRootSignature = &rs.graphics;
|
|
}
|
|
|
|
DXILDebug::GlobalState::UAVData &uavData = m_GlobalState.uavs[slot];
|
|
|
|
if(pRootSignature)
|
|
{
|
|
WrappedID3D12RootSignature *pD3D12RootSig =
|
|
rm->GetCurrentAs<WrappedID3D12RootSignature>(pRootSignature->rootsig);
|
|
|
|
size_t numParams = RDCMIN(pD3D12RootSig->sig.Parameters.size(), pRootSignature->sigelems.size());
|
|
for(size_t i = 0; i < numParams; ++i)
|
|
{
|
|
const D3D12RootSignatureParameter ¶m = pD3D12RootSig->sig.Parameters[i];
|
|
const D3D12RenderState::SignatureElement &element = pRootSignature->sigelems[i];
|
|
if(IsShaderParameterVisible(m_ShaderType, param.ShaderVisibility))
|
|
{
|
|
if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_UAV && element.type == eRootUAV)
|
|
{
|
|
if(param.Descriptor.ShaderRegister == slot.shaderRegister &&
|
|
param.Descriptor.RegisterSpace == slot.registerSpace)
|
|
{
|
|
// Found the requested UAV
|
|
ID3D12Resource *pResource = rm->GetCurrentAs<ID3D12Resource>(element.id);
|
|
|
|
if(pResource)
|
|
{
|
|
D3D12_RESOURCE_DESC resDesc = pResource->GetDesc();
|
|
// DXC allows root buffers to have a stride of up to 16 bytes in the shader, which
|
|
// means encoding the byte offset into the first element here is wrong without
|
|
// knowing what the actual accessed stride is. Instead we only fetch the data from
|
|
// that offset onwards.
|
|
|
|
// Root buffers are typeless, try with the resource desc format
|
|
// The debugger code will handle DXGI_FORMAT_UNKNOWN
|
|
if(resDesc.Format != DXGI_FORMAT_UNKNOWN)
|
|
{
|
|
DXILDebug::FillViewFmtFromResourceFormat(resDesc.Format, uavData.resInfo.format);
|
|
}
|
|
|
|
uavData.resInfo.isRootDescriptor = true;
|
|
uavData.resInfo.firstElement = 0;
|
|
// root arguments have no bounds checking, use the most conservative number of elements
|
|
uavData.resInfo.numElements = uint32_t(resDesc.Width - element.offset);
|
|
|
|
if(resDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
|
|
{
|
|
// Get the buffer stride from the shader metadata (for StructuredBuffer, RawBuffer)
|
|
uint32_t mdStride =
|
|
DXILDebug::GetUAVBufferStrideFromShaderMetadata(m_EntryPointInterface, slot);
|
|
if(mdStride != 0)
|
|
uavData.resInfo.format.stride = mdStride;
|
|
m_Device->GetDebugManager()->GetBufferData(pResource, element.offset, 0,
|
|
uavData.data);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
else if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE &&
|
|
element.type == eRootTable)
|
|
{
|
|
UINT prevTableOffset = 0;
|
|
WrappedID3D12DescriptorHeap *heap =
|
|
rm->GetCurrentAs<WrappedID3D12DescriptorHeap>(element.id);
|
|
|
|
size_t numRanges = param.ranges.size();
|
|
for(size_t r = 0; r < numRanges; ++r)
|
|
{
|
|
const D3D12_DESCRIPTOR_RANGE1 &range = param.ranges[r];
|
|
|
|
// For every range, check the number of descriptors so that we are accessing the
|
|
// correct data for append descriptor tables, even if the range type doesn't match
|
|
// what we need to fetch
|
|
UINT offset = range.OffsetInDescriptorsFromTableStart;
|
|
if(range.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
|
|
offset = prevTableOffset;
|
|
|
|
D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr;
|
|
desc += element.offset;
|
|
desc += offset;
|
|
|
|
UINT numDescriptors = range.NumDescriptors;
|
|
if(numDescriptors == UINT_MAX)
|
|
{
|
|
// Find out how many descriptors are left after
|
|
numDescriptors = heap->GetNumDescriptors() - offset - (UINT)element.offset;
|
|
|
|
// TODO: Should we look up the bind point in the D3D12 state to try to get
|
|
// a better guess at the number of descriptors?
|
|
}
|
|
|
|
prevTableOffset = offset + numDescriptors;
|
|
|
|
// Check if the range is for UAVs and the slot we want is contained
|
|
if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV &&
|
|
slot.shaderRegister >= range.BaseShaderRegister &&
|
|
slot.shaderRegister < range.BaseShaderRegister + numDescriptors &&
|
|
range.RegisterSpace == slot.registerSpace)
|
|
{
|
|
desc += slot.shaderRegister - range.BaseShaderRegister;
|
|
if(desc)
|
|
{
|
|
ResourceId uavId = desc->GetResResourceId();
|
|
ID3D12Resource *pResource = rm->GetCurrentAs<ID3D12Resource>(uavId);
|
|
|
|
if(pResource)
|
|
{
|
|
// TODO: Need to fetch counter resource if applicable
|
|
|
|
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = desc->GetUAV();
|
|
|
|
if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_UNKNOWN)
|
|
uavDesc = MakeUAVDesc(pResource->GetDesc());
|
|
|
|
if(uavDesc.Format != DXGI_FORMAT_UNKNOWN)
|
|
{
|
|
DXILDebug::FillViewFmtFromResourceFormat(uavDesc.Format, uavData.resInfo.format);
|
|
}
|
|
|
|
if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_BUFFER)
|
|
{
|
|
uavData.resInfo.firstElement = (uint32_t)uavDesc.Buffer.FirstElement;
|
|
uavData.resInfo.numElements = uavDesc.Buffer.NumElements;
|
|
uavData.resInfo.isByteBuffer =
|
|
((uavDesc.Buffer.Flags & D3D12_BUFFER_UAV_FLAG_RAW) != 0) ? true : false;
|
|
// Get the buffer stride from the shader metadata (for StructuredBuffer, RawBuffer)
|
|
uint32_t mdStride =
|
|
DXILDebug::GetUAVBufferStrideFromShaderMetadata(m_EntryPointInterface, slot);
|
|
if(mdStride != 0)
|
|
uavData.resInfo.format.stride = mdStride;
|
|
|
|
m_Device->GetDebugManager()->GetBufferData(pResource, 0, 0, uavData.data);
|
|
}
|
|
else
|
|
{
|
|
uavData.tex = true;
|
|
m_Device->GetReplay()->GetTextureData(uavId, Subresource(),
|
|
GetTextureDataParams(), uavData.data);
|
|
|
|
D3D12_RESOURCE_DESC resDesc = pResource->GetDesc();
|
|
uavData.rowPitch = GetByteSize((int)resDesc.Width, 1, 1, uavDesc.Format, 0);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RDCERR("Couldn't find root signature parameter corresponding to UAV %u in space %u",
|
|
slot.shaderRegister, slot.registerSpace);
|
|
return;
|
|
}
|
|
|
|
RDCERR("No root signature bound, couldn't identify UAV %u in space %u", slot.shaderRegister,
|
|
slot.registerSpace);
|
|
}
|
|
|
|
bool D3D12APIWrapper::CalculateMathIntrinsic(DXIL::DXOp dxOp, const ShaderVariable &input,
|
|
ShaderVariable &output)
|
|
{
|
|
D3D12MarkerRegion region(m_Device->GetQueue()->GetReal(), "CalculateMathIntrinsic");
|
|
|
|
int mathOp;
|
|
switch(dxOp)
|
|
{
|
|
case DXOp::Cos: mathOp = DEBUG_SAMPLE_MATH_DXIL_COS; break;
|
|
case DXOp::Sin: mathOp = DEBUG_SAMPLE_MATH_DXIL_SIN; break;
|
|
case DXOp::Tan: mathOp = DEBUG_SAMPLE_MATH_DXIL_TAN; break;
|
|
case DXOp::Acos: mathOp = DEBUG_SAMPLE_MATH_DXIL_ACOS; break;
|
|
case DXOp::Asin: mathOp = DEBUG_SAMPLE_MATH_DXIL_ASIN; break;
|
|
case DXOp::Atan: mathOp = DEBUG_SAMPLE_MATH_DXIL_ATAN; break;
|
|
case DXOp::Hcos: mathOp = DEBUG_SAMPLE_MATH_DXIL_HCOS; break;
|
|
case DXOp::Hsin: mathOp = DEBUG_SAMPLE_MATH_DXIL_HSIN; break;
|
|
case DXOp::Htan: mathOp = DEBUG_SAMPLE_MATH_DXIL_HTAN; break;
|
|
case DXOp::Exp: mathOp = DEBUG_SAMPLE_MATH_DXIL_EXP; break;
|
|
case DXOp::Log: mathOp = DEBUG_SAMPLE_MATH_DXIL_LOG; break;
|
|
case DXOp::Sqrt: mathOp = DEBUG_SAMPLE_MATH_DXIL_SQRT; break;
|
|
case DXOp::Rsqrt: mathOp = DEBUG_SAMPLE_MATH_DXIL_RSQRT; break;
|
|
default:
|
|
// To support a new instruction, the shader created in
|
|
// D3D12DebugManager::CreateShaderDebugResources will need updating
|
|
RDCERR("Unsupported opcode for DXIL CalculateMathIntrinsic: %s %u", ToStr(dxOp).c_str(),
|
|
(uint)dxOp);
|
|
return false;
|
|
}
|
|
|
|
ShaderVariable ignored;
|
|
return D3D12ShaderDebug::CalculateMathIntrinsic(true, m_Device, mathOp, input, output, ignored);
|
|
}
|
|
|
|
bool D3D12APIWrapper::CalculateSampleGather(
|
|
DXIL::DXOp dxOp, SampleGatherResourceData resourceData, SampleGatherSamplerData samplerData,
|
|
const ShaderVariable &uv, const ShaderVariable &ddxCalc, const ShaderVariable &ddyCalc,
|
|
const int8_t texelOffsets[3], int multisampleIndex, float lodValue, float compareValue,
|
|
const uint8_t swizzle[4], GatherChannel gatherChannel, DXBC::ShaderType shaderType,
|
|
uint32_t instructionIdx, const char *opString, ShaderVariable &output)
|
|
{
|
|
int sampleOp;
|
|
switch(dxOp)
|
|
{
|
|
case DXOp::Sample: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE; break;
|
|
case DXOp::SampleBias: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_BIAS; break;
|
|
case DXOp::SampleLevel: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_LEVEL; break;
|
|
case DXOp::SampleGrad: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_GRAD; break;
|
|
case DXOp::SampleCmp: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP; break;
|
|
case DXOp::SampleCmpBias: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP_BIAS; break;
|
|
case DXOp::SampleCmpLevel: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL; break;
|
|
case DXOp::SampleCmpGrad: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP_GRAD; break;
|
|
case DXOp::SampleCmpLevelZero: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL_ZERO; break;
|
|
case DXOp::TextureGather: sampleOp = DEBUG_SAMPLE_TEX_GATHER4; break;
|
|
case DXOp::TextureGatherCmp: sampleOp = DEBUG_SAMPLE_TEX_GATHER4_CMP; break;
|
|
case DXOp::CalculateLOD: sampleOp = DEBUG_SAMPLE_TEX_LOD; break;
|
|
// In the shader DEBUG_SAMPLE_TEX_LOAD and DEBUG_SAMPLE_TEX_LOAD_MS behave equivalently
|
|
case DXOp::TextureLoad: sampleOp = DEBUG_SAMPLE_TEX_LOAD; break;
|
|
// TODO: consider these DXIL opcode operations
|
|
// DXOp::TextureGatherRaw
|
|
// TODO: consider these DXBC opcode operations
|
|
// DEBUG_SAMPLE_TEX_GATHER4_PARAM_OFFSET_CMP
|
|
default:
|
|
// To support a new instruction, the shader created in
|
|
// D3D12DebugManager::CreateShaderDebugResources will need updating
|
|
RDCERR("Unsupported instruction for CalculateSampleGather: %s %u", ToStr(dxOp).c_str(), dxOp);
|
|
return false;
|
|
}
|
|
|
|
return D3D12ShaderDebug::CalculateSampleGather(
|
|
true, m_Device, sampleOp, resourceData, samplerData, uv, ddxCalc, ddyCalc, texelOffsets,
|
|
multisampleIndex, lodValue, compareValue, swizzle, gatherChannel, shaderType, instructionIdx,
|
|
opString, output);
|
|
}
|
|
|
|
ShaderVariable D3D12APIWrapper::GetResourceInfo(DXIL::ResourceClass resClass,
|
|
const DXDebug::BindingSlot &slot, uint32_t mipLevel,
|
|
const DXBC::ShaderType shaderType, int &dim)
|
|
{
|
|
D3D12_DESCRIPTOR_RANGE_TYPE descType;
|
|
switch(resClass)
|
|
{
|
|
case DXIL::ResourceClass::SRV: descType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; break;
|
|
case DXIL::ResourceClass::UAV: descType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; break;
|
|
case DXIL::ResourceClass::CBuffer: descType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; break;
|
|
case DXIL::ResourceClass::Sampler: descType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; break;
|
|
default:
|
|
RDCERR("Unsupported resource class %s", ToStr(resClass).c_str());
|
|
return ShaderVariable();
|
|
}
|
|
return D3D12ShaderDebug::GetResourceInfo(m_Device, descType, slot, mipLevel, shaderType, dim, true);
|
|
}
|
|
|
|
ShaderVariable D3D12APIWrapper::GetSampleInfo(DXIL::ResourceClass resClass,
|
|
const DXDebug::BindingSlot &slot,
|
|
const DXBC::ShaderType shaderType, const char *opString)
|
|
{
|
|
D3D12_DESCRIPTOR_RANGE_TYPE descType;
|
|
switch(resClass)
|
|
{
|
|
case DXIL::ResourceClass::SRV: descType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; break;
|
|
case DXIL::ResourceClass::UAV: descType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; break;
|
|
case DXIL::ResourceClass::CBuffer: descType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; break;
|
|
case DXIL::ResourceClass::Sampler: descType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; break;
|
|
default:
|
|
RDCERR("Unsupported resource class %s", ToStr(resClass).c_str());
|
|
return ShaderVariable();
|
|
}
|
|
return D3D12ShaderDebug::GetSampleInfo(m_Device, descType, slot, shaderType, opString);
|
|
}
|
|
|
|
ShaderVariable D3D12APIWrapper::GetRenderTargetSampleInfo(const DXBC::ShaderType shaderType,
|
|
const char *opString)
|
|
{
|
|
return D3D12ShaderDebug::GetRenderTargetSampleInfo(m_Device, shaderType, opString);
|
|
}
|
|
|
|
ResourceReferenceInfo D3D12APIWrapper::GetResourceReferenceInfo(const DXDebug::BindingSlot &slot)
|
|
{
|
|
const HeapDescriptorType heapType = slot.heapType;
|
|
RDCASSERT(heapType != HeapDescriptorType::NoHeap);
|
|
const uint32_t descriptorIndex = slot.descriptorIndex;
|
|
D3D12Descriptor desc = D3D12ShaderDebug::FindDescriptor(m_Device, heapType, descriptorIndex);
|
|
|
|
D3D12ResourceManager *rm = m_Device->GetResourceManager();
|
|
|
|
ResourceReferenceInfo resRefInfo;
|
|
resRefInfo.binding.heapType = heapType;
|
|
resRefInfo.binding.descriptorIndex = descriptorIndex;
|
|
|
|
switch(desc.GetType())
|
|
{
|
|
case D3D12DescriptorType::CBV:
|
|
{
|
|
resRefInfo.resClass = DXIL::ResourceClass::CBuffer;
|
|
resRefInfo.category = DescriptorCategory::ConstantBlock;
|
|
resRefInfo.type = VarType::ConstantBlock;
|
|
}
|
|
case D3D12DescriptorType::SRV:
|
|
{
|
|
ResourceId srvId = desc.GetResResourceId();
|
|
ID3D12Resource *pResource = rm->GetCurrentAs<ID3D12Resource>(srvId);
|
|
if(pResource)
|
|
{
|
|
resRefInfo.resClass = DXIL::ResourceClass::SRV;
|
|
resRefInfo.category = DescriptorCategory::ReadOnlyResource;
|
|
resRefInfo.type = VarType::ReadOnlyResource;
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = desc.GetSRV();
|
|
if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_UNKNOWN)
|
|
srvDesc = MakeSRVDesc(pResource->GetDesc());
|
|
|
|
GlobalState::ViewFmt viewFmt;
|
|
if(srvDesc.Format != DXGI_FORMAT_UNKNOWN)
|
|
{
|
|
resRefInfo.srvData.dim =
|
|
(DXDebug::ResourceDimension)ConvertSRVResourceDimensionToResourceDimension(
|
|
srvDesc.ViewDimension);
|
|
|
|
DXILDebug::FillViewFmtFromResourceFormat(srvDesc.Format, viewFmt);
|
|
resRefInfo.srvData.compType =
|
|
(DXDebug::ResourceRetType)ConvertCompTypeToResourceRetType(viewFmt.compType);
|
|
|
|
D3D12_RESOURCE_DESC resDesc = pResource->GetDesc();
|
|
resRefInfo.srvData.sampleCount = resDesc.SampleDesc.Count;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RDCERR("Unknown SRV resource at Descriptor Index %s", descriptorIndex);
|
|
return ResourceReferenceInfo();
|
|
}
|
|
break;
|
|
}
|
|
case D3D12DescriptorType::UAV:
|
|
{
|
|
resRefInfo.resClass = DXIL::ResourceClass::UAV;
|
|
resRefInfo.category = DescriptorCategory::ReadWriteResource;
|
|
resRefInfo.type = VarType::ReadWriteResource;
|
|
break;
|
|
}
|
|
case D3D12DescriptorType::Sampler:
|
|
{
|
|
resRefInfo.resClass = DXIL::ResourceClass::Sampler;
|
|
resRefInfo.category = DescriptorCategory::Sampler;
|
|
resRefInfo.type = VarType::Sampler;
|
|
D3D12_SAMPLER_DESC2 samplerDesc = desc.GetSampler();
|
|
// Don't think SAMPLER_MODE_MONO is supported in D3D12 (set for filter mode D3D10_FILTER_TEXT_1BIT)
|
|
resRefInfo.samplerData.samplerMode =
|
|
(DXDebug::SamplerMode)ConvertSamplerFilterToSamplerMode(samplerDesc.Filter);
|
|
break;
|
|
}
|
|
default:
|
|
RDCERR("Unhandled Descriptor Type %s", ToStr(desc.GetType()).c_str());
|
|
return ResourceReferenceInfo();
|
|
}
|
|
return resRefInfo;
|
|
}
|
|
};
|