Files
renderdoc/renderdoc/driver/d3d12/d3d12_replay.cpp
T

1752 lines
58 KiB
C++

/******************************************************************************
* 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 "d3d12_replay.h"
#include "driver/dx/official/d3dcompiler.h"
#include "driver/dxgi/dxgi_common.h"
#include "d3d12_command_queue.h"
#include "d3d12_device.h"
#include "d3d12_resources.h"
template <class T>
T &resize_and_add(std::vector<T> &vec, size_t idx)
{
if(idx >= vec.size())
vec.resize(idx + 1);
return vec[idx];
}
D3D12Replay::D3D12Replay()
{
m_pDevice = NULL;
m_Proxy = false;
}
void D3D12Replay::Shutdown()
{
for(size_t i = 0; i < m_ProxyResources.size(); i++)
m_ProxyResources[i]->Release();
m_ProxyResources.clear();
PreDeviceShutdownCounters();
m_pDevice->Release();
D3D12Replay::PostDeviceShutdownCounters();
}
void D3D12Replay::ReadLogInitialisation()
{
m_pDevice->ReadLogInitialisation();
}
APIProperties D3D12Replay::GetAPIProperties()
{
APIProperties ret;
ret.pipelineType = eGraphicsAPI_D3D12;
ret.localRenderer = eGraphicsAPI_D3D12;
ret.degraded = false;
return ret;
}
void D3D12Replay::ReplayLog(uint32_t endEventID, ReplayLogType replayType)
{
m_pDevice->ReplayLog(0, endEventID, replayType);
}
vector<ResourceId> D3D12Replay::GetBuffers()
{
vector<ResourceId> ret;
for(auto it = WrappedID3D12Resource::GetList().begin();
it != WrappedID3D12Resource::GetList().end(); it++)
if(it->second->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
ret.push_back(it->first);
return ret;
}
vector<ResourceId> D3D12Replay::GetTextures()
{
vector<ResourceId> ret;
for(auto it = WrappedID3D12Resource::GetList().begin();
it != WrappedID3D12Resource::GetList().end(); it++)
{
if(it->second->GetDesc().Dimension != D3D12_RESOURCE_DIMENSION_BUFFER &&
m_pDevice->GetResourceManager()->GetOriginalID(it->first) != it->first)
ret.push_back(it->first);
}
return ret;
}
FetchBuffer D3D12Replay::GetBuffer(ResourceId id)
{
FetchBuffer ret;
ret.ID = m_pDevice->GetResourceManager()->GetOriginalID(id);
auto it = WrappedID3D12Resource::GetList().find(id);
if(it == WrappedID3D12Resource::GetList().end())
return ret;
D3D12_RESOURCE_DESC desc = it->second->GetDesc();
ret.customName = true;
string str = m_pDevice->GetResourceName(ret.ID);
if(str == "")
{
ret.customName = false;
str = StringFormat::Fmt("Buffer %llu", ret.ID);
}
ret.name = str;
ret.length = desc.Width;
ret.creationFlags = 0;
const std::vector<EventUsage> &usage = m_pDevice->GetQueue()->GetUsage(id);
for(size_t i = 0; i < usage.size(); i++)
{
if(usage[i].usage == eUsage_VS_RWResource || usage[i].usage == eUsage_HS_RWResource ||
usage[i].usage == eUsage_DS_RWResource || usage[i].usage == eUsage_GS_RWResource ||
usage[i].usage == eUsage_PS_RWResource || usage[i].usage == eUsage_CS_RWResource)
ret.creationFlags |= eBufferCreate_UAV;
else if(usage[i].usage == eUsage_VertexBuffer)
ret.creationFlags |= eBufferCreate_VB;
else if(usage[i].usage == eUsage_IndexBuffer)
ret.creationFlags |= eBufferCreate_IB;
else if(usage[i].usage == eUsage_Indirect)
ret.creationFlags |= eBufferCreate_Indirect;
}
if(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
ret.creationFlags |= eBufferCreate_UAV;
return ret;
}
FetchTexture D3D12Replay::GetTexture(ResourceId id)
{
FetchTexture ret;
ret.ID = m_pDevice->GetResourceManager()->GetOriginalID(id);
auto it = WrappedID3D12Resource::GetList().find(id);
if(it == WrappedID3D12Resource::GetList().end())
return ret;
D3D12_RESOURCE_DESC desc = it->second->GetDesc();
ret.format = MakeResourceFormat(desc.Format);
ret.dimension = desc.Dimension - D3D12_RESOURCE_DIMENSION_BUFFER;
ret.width = (uint32_t)desc.Width;
ret.height = desc.Height;
ret.depth = desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D ? desc.DepthOrArraySize : 1;
ret.arraysize = desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D ? desc.DepthOrArraySize : 1;
ret.mips = desc.MipLevels;
ret.msQual = desc.SampleDesc.Quality;
ret.msSamp = RDCMAX(1U, desc.SampleDesc.Count);
ret.byteSize = 0;
for(uint32_t i = 0; i < ret.mips; i++)
ret.byteSize += GetByteSize(ret.width, ret.height, ret.depth, desc.Format, i);
switch(ret.dimension)
{
case 1: ret.resType = ret.arraysize > 1 ? eResType_Texture1DArray : eResType_Texture1D; break;
case 2:
if(ret.msSamp > 1)
ret.resType = ret.arraysize > 1 ? eResType_Texture2DMSArray : eResType_Texture2DMS;
else
ret.resType = ret.arraysize > 1 ? eResType_Texture2DArray : eResType_Texture2D;
break;
case 3: ret.resType = eResType_Texture3D; break;
}
ret.cubemap = m_pDevice->IsCubemap(id);
ret.creationFlags = eTextureCreate_SRV;
if(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
ret.creationFlags |= eTextureCreate_RTV;
if(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)
ret.creationFlags |= eTextureCreate_DSV;
if(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
ret.creationFlags |= eTextureCreate_UAV;
if(ret.ID == m_pDevice->GetQueue()->GetBackbufferResourceID())
{
ret.format = MakeResourceFormat(GetTypedFormat(desc.Format, eCompType_UNorm));
ret.creationFlags |= eTextureCreate_SwapBuffer;
}
ret.customName = true;
string str = m_pDevice->GetResourceName(ret.ID);
if(str == "")
{
const char *suffix = "";
const char *ms = "";
if(ret.msSamp > 1)
ms = "MS";
if(ret.creationFlags & eTextureCreate_RTV)
suffix = " RTV";
if(ret.creationFlags & eTextureCreate_DSV)
suffix = " DSV";
ret.customName = false;
if(ret.arraysize > 1)
str = StringFormat::Fmt("Texture%uD%sArray%s %llu", ret.dimension, ms, suffix, ret.ID);
else
str = StringFormat::Fmt("Texture%uD%s%s %llu", ret.dimension, ms, suffix, ret.ID);
}
ret.name = str;
return ret;
}
ShaderReflection *D3D12Replay::GetShader(ResourceId shader, string entryPoint)
{
WrappedID3D12Shader *sh =
m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12Shader>(shader);
if(sh)
return &sh->GetDetails();
return NULL;
}
void D3D12Replay::FreeTargetResource(ResourceId id)
{
if(m_pDevice->GetResourceManager()->HasLiveResource(id))
{
ID3D12DeviceChild *resource = m_pDevice->GetResourceManager()->GetLiveResource(id);
SAFE_RELEASE(resource);
}
}
void D3D12Replay::FreeCustomShader(ResourceId id)
{
if(m_pDevice->GetResourceManager()->HasLiveResource(id))
{
ID3D12DeviceChild *resource = m_pDevice->GetResourceManager()->GetLiveResource(id);
SAFE_RELEASE(resource);
}
}
FetchFrameRecord D3D12Replay::GetFrameRecord()
{
return m_pDevice->GetFrameRecord();
}
ResourceId D3D12Replay::GetLiveID(ResourceId id)
{
return m_pDevice->GetResourceManager()->GetLiveID(id);
}
vector<EventUsage> D3D12Replay::GetUsage(ResourceId id)
{
return m_pDevice->GetQueue()->GetUsage(id);
}
void D3D12Replay::FillResourceView(D3D12PipelineState::ResourceView &view, D3D12Descriptor *desc)
{
D3D12ResourceManager *rm = m_pDevice->GetResourceManager();
if(desc->GetType() == D3D12Descriptor::TypeSampler || desc->GetType() == D3D12Descriptor::TypeCBV)
{
RDCERR("Invalid descriptors - expected a resource view");
return;
}
view.Resource = rm->GetOriginalID(GetResID(desc->nonsamp.resource));
if(view.Resource == ResourceId())
return;
D3D12_RESOURCE_DESC res = desc->nonsamp.resource->GetDesc();
{
DXGI_FORMAT fmt = DXGI_FORMAT_UNKNOWN;
if(desc->GetType() == D3D12Descriptor::TypeRTV)
fmt = desc->nonsamp.rtv.Format;
else if(desc->GetType() == D3D12Descriptor::TypeSRV)
fmt = desc->nonsamp.srv.Format;
else if(desc->GetType() == D3D12Descriptor::TypeUAV)
fmt = (DXGI_FORMAT)desc->nonsamp.uav.desc.Format;
if(fmt == DXGI_FORMAT_UNKNOWN)
fmt = res.Format;
view.ElementSize = fmt == DXGI_FORMAT_UNKNOWN ? 1 : GetByteSize(1, 1, 1, fmt, 0);
view.Format = MakeResourceFormat(fmt);
if(desc->GetType() == D3D12Descriptor::TypeRTV)
{
view.Type = ToStr::Get(desc->nonsamp.rtv.ViewDimension);
if(desc->nonsamp.rtv.ViewDimension == D3D12_RTV_DIMENSION_BUFFER)
{
view.FirstElement = desc->nonsamp.rtv.Buffer.FirstElement;
view.NumElements = desc->nonsamp.rtv.Buffer.NumElements;
}
else if(desc->nonsamp.rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE1D)
{
view.HighestMip = desc->nonsamp.rtv.Texture1D.MipSlice;
}
else if(desc->nonsamp.rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE1DARRAY)
{
view.ArraySize = desc->nonsamp.rtv.Texture1DArray.ArraySize;
view.FirstArraySlice = desc->nonsamp.rtv.Texture1DArray.FirstArraySlice;
view.HighestMip = desc->nonsamp.rtv.Texture1DArray.MipSlice;
}
else if(desc->nonsamp.rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2D)
{
view.HighestMip = desc->nonsamp.rtv.Texture2D.MipSlice;
}
else if(desc->nonsamp.rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2DARRAY)
{
view.ArraySize = desc->nonsamp.rtv.Texture2DArray.ArraySize;
view.FirstArraySlice = desc->nonsamp.rtv.Texture2DArray.FirstArraySlice;
view.HighestMip = desc->nonsamp.rtv.Texture2DArray.MipSlice;
}
else if(desc->nonsamp.rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2DMS)
{
}
else if(desc->nonsamp.rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY)
{
view.ArraySize = desc->nonsamp.rtv.Texture2DMSArray.ArraySize;
view.FirstArraySlice = desc->nonsamp.rtv.Texture2DArray.FirstArraySlice;
}
else if(desc->nonsamp.rtv.ViewDimension == D3D12_RTV_DIMENSION_TEXTURE3D)
{
view.ArraySize = desc->nonsamp.rtv.Texture3D.WSize;
view.FirstArraySlice = desc->nonsamp.rtv.Texture3D.FirstWSlice;
view.HighestMip = desc->nonsamp.rtv.Texture3D.MipSlice;
}
}
else if(desc->GetType() == D3D12Descriptor::TypeDSV)
{
view.Type = ToStr::Get(desc->nonsamp.dsv.ViewDimension);
if(desc->nonsamp.dsv.ViewDimension == D3D12_DSV_DIMENSION_TEXTURE1D)
{
view.HighestMip = desc->nonsamp.dsv.Texture1D.MipSlice;
}
else if(desc->nonsamp.dsv.ViewDimension == D3D12_DSV_DIMENSION_TEXTURE1DARRAY)
{
view.ArraySize = desc->nonsamp.dsv.Texture1DArray.ArraySize;
view.FirstArraySlice = desc->nonsamp.dsv.Texture1DArray.FirstArraySlice;
view.HighestMip = desc->nonsamp.dsv.Texture1DArray.MipSlice;
}
else if(desc->nonsamp.dsv.ViewDimension == D3D12_DSV_DIMENSION_TEXTURE2D)
{
view.HighestMip = desc->nonsamp.dsv.Texture2D.MipSlice;
}
else if(desc->nonsamp.dsv.ViewDimension == D3D12_DSV_DIMENSION_TEXTURE2DARRAY)
{
view.ArraySize = desc->nonsamp.dsv.Texture2DArray.ArraySize;
view.FirstArraySlice = desc->nonsamp.dsv.Texture2DArray.FirstArraySlice;
view.HighestMip = desc->nonsamp.dsv.Texture2DArray.MipSlice;
}
else if(desc->nonsamp.dsv.ViewDimension == D3D12_DSV_DIMENSION_TEXTURE2DMS)
{
}
else if(desc->nonsamp.dsv.ViewDimension == D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY)
{
view.ArraySize = desc->nonsamp.dsv.Texture2DMSArray.ArraySize;
view.FirstArraySlice = desc->nonsamp.dsv.Texture2DArray.FirstArraySlice;
}
}
else if(desc->GetType() == D3D12Descriptor::TypeSRV)
{
view.Type = ToStr::Get(desc->nonsamp.srv.ViewDimension);
view.swizzle[0] = (TextureSwizzle)D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(
0, desc->nonsamp.srv.Shader4ComponentMapping);
view.swizzle[1] = (TextureSwizzle)D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(
1, desc->nonsamp.srv.Shader4ComponentMapping);
view.swizzle[2] = (TextureSwizzle)D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(
2, desc->nonsamp.srv.Shader4ComponentMapping);
view.swizzle[3] = (TextureSwizzle)D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(
3, desc->nonsamp.srv.Shader4ComponentMapping);
if(desc->nonsamp.srv.ViewDimension == D3D12_SRV_DIMENSION_BUFFER)
{
view.FirstElement = desc->nonsamp.srv.Buffer.FirstElement;
view.NumElements = desc->nonsamp.srv.Buffer.NumElements;
view.BufferFlags = desc->nonsamp.srv.Buffer.Flags;
if(desc->nonsamp.srv.Buffer.StructureByteStride > 0)
view.ElementSize = desc->nonsamp.srv.Buffer.StructureByteStride;
}
else if(desc->nonsamp.srv.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE1D)
{
view.HighestMip = desc->nonsamp.srv.Texture1D.MostDetailedMip;
view.NumMipLevels = desc->nonsamp.srv.Texture1D.MipLevels;
view.MinLODClamp = desc->nonsamp.srv.Texture1D.ResourceMinLODClamp;
}
else if(desc->nonsamp.srv.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE1DARRAY)
{
view.ArraySize = desc->nonsamp.srv.Texture1DArray.ArraySize;
view.FirstArraySlice = desc->nonsamp.srv.Texture1DArray.FirstArraySlice;
view.HighestMip = desc->nonsamp.srv.Texture1DArray.MostDetailedMip;
view.NumMipLevels = desc->nonsamp.srv.Texture1DArray.MipLevels;
view.MinLODClamp = desc->nonsamp.srv.Texture1DArray.ResourceMinLODClamp;
}
else if(desc->nonsamp.srv.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D)
{
view.HighestMip = desc->nonsamp.srv.Texture2D.MostDetailedMip;
view.NumMipLevels = desc->nonsamp.srv.Texture2D.MipLevels;
view.MinLODClamp = desc->nonsamp.srv.Texture2D.ResourceMinLODClamp;
}
else if(desc->nonsamp.srv.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY)
{
view.ArraySize = desc->nonsamp.srv.Texture2DArray.ArraySize;
view.FirstArraySlice = desc->nonsamp.srv.Texture2DArray.FirstArraySlice;
view.HighestMip = desc->nonsamp.srv.Texture2DArray.MostDetailedMip;
view.NumMipLevels = desc->nonsamp.srv.Texture2DArray.MipLevels;
view.MinLODClamp = desc->nonsamp.srv.Texture2DArray.ResourceMinLODClamp;
}
else if(desc->nonsamp.srv.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS)
{
}
else if(desc->nonsamp.srv.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY)
{
view.ArraySize = desc->nonsamp.srv.Texture2DMSArray.ArraySize;
view.FirstArraySlice = desc->nonsamp.srv.Texture2DMSArray.FirstArraySlice;
}
else if(desc->nonsamp.srv.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE3D)
{
view.HighestMip = desc->nonsamp.srv.Texture3D.MostDetailedMip;
view.NumMipLevels = desc->nonsamp.srv.Texture3D.MipLevels;
view.MinLODClamp = desc->nonsamp.srv.Texture3D.ResourceMinLODClamp;
}
}
else if(desc->GetType() == D3D12Descriptor::TypeUAV)
{
D3D12_UNORDERED_ACCESS_VIEW_DESC uav = desc->nonsamp.uav.desc.AsDesc();
view.CounterResource = rm->GetOriginalID(GetResID(desc->nonsamp.uav.counterResource));
view.Type = ToStr::Get(uav.ViewDimension);
if(uav.ViewDimension == D3D12_UAV_DIMENSION_BUFFER)
{
view.FirstElement = uav.Buffer.FirstElement;
view.NumElements = uav.Buffer.NumElements;
view.BufferFlags = uav.Buffer.Flags;
if(uav.Buffer.StructureByteStride > 0)
view.ElementSize = uav.Buffer.StructureByteStride;
view.CounterByteOffset = uav.Buffer.CounterOffsetInBytes;
if(view.CounterResource != ResourceId())
{
vector<byte> counterVal;
m_pDevice->GetDebugManager()->GetBufferData(desc->nonsamp.uav.counterResource,
view.CounterByteOffset, 4, counterVal);
uint32_t *val = (uint32_t *)&counterVal[0];
view.BufferStructCount = *val;
}
}
else if(uav.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE1D)
{
view.HighestMip = uav.Texture1D.MipSlice;
}
else if(uav.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE1DARRAY)
{
view.ArraySize = uav.Texture1DArray.ArraySize;
view.FirstArraySlice = uav.Texture1DArray.FirstArraySlice;
view.HighestMip = uav.Texture1DArray.MipSlice;
}
else if(uav.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2D)
{
view.HighestMip = uav.Texture2D.MipSlice;
}
else if(uav.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY)
{
view.ArraySize = uav.Texture2DArray.ArraySize;
view.FirstArraySlice = uav.Texture2DArray.FirstArraySlice;
view.HighestMip = uav.Texture2DArray.MipSlice;
}
else if(uav.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE3D)
{
view.ArraySize = uav.Texture3D.WSize;
view.FirstArraySlice = uav.Texture3D.FirstWSlice;
view.HighestMip = uav.Texture3D.MipSlice;
}
}
}
}
void D3D12Replay::FillRegisterSpaces(
const D3D12RenderState::RootSignature &rootSig,
rdctype::array<D3D12PipelineState::ShaderStage::RegisterSpace> &dstSpaces,
D3D12_SHADER_VISIBILITY visibility)
{
D3D12ResourceManager *rm = m_pDevice->GetResourceManager();
WrappedID3D12RootSignature *sig =
m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12RootSignature>(rootSig.rootsig);
struct Space
{
vector<D3D12PipelineState::CBuffer> cbuffers;
vector<D3D12PipelineState::Sampler> samplers;
vector<D3D12PipelineState::ResourceView> srvs;
vector<D3D12PipelineState::ResourceView> uavs;
};
Space *spaces = new Space[sig->sig.numSpaces];
create_array_uninit(dstSpaces, sig->sig.numSpaces);
for(size_t rootEl = 0; rootEl < sig->sig.params.size(); rootEl++)
{
const D3D12RootSignatureParameter &p = sig->sig.params[rootEl];
if(p.ShaderVisibility != D3D12_SHADER_VISIBILITY_ALL && p.ShaderVisibility != visibility)
continue;
if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS)
{
D3D12PipelineState::CBuffer &cb =
resize_and_add(spaces[p.Constants.RegisterSpace].cbuffers, p.Constants.ShaderRegister);
cb.Immediate = true;
cb.RootElement = (uint32_t)rootEl;
cb.ByteSize = uint32_t(sizeof(uint32_t) * p.Constants.Num32BitValues);
if(rootEl < rootSig.sigelems.size())
{
const D3D12RenderState::SignatureElement &e = rootSig.sigelems[rootEl];
if(e.type == eRootConst)
create_array_init(cb.RootValues, RDCMIN(e.constants.size(), (size_t)cb.ByteSize),
&e.constants[0]);
}
if(cb.RootValues.count == 0)
create_array(cb.RootValues, p.Constants.Num32BitValues);
}
else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV)
{
D3D12PipelineState::CBuffer &cb =
resize_and_add(spaces[p.Descriptor.RegisterSpace].cbuffers, p.Descriptor.ShaderRegister);
cb.Immediate = true;
cb.RootElement = (uint32_t)rootEl;
if(rootEl < rootSig.sigelems.size())
{
const D3D12RenderState::SignatureElement &e = rootSig.sigelems[rootEl];
if(e.type == eRootCBV)
{
ID3D12Resource *res = rm->GetCurrentAs<ID3D12Resource>(e.id);
cb.Buffer = rm->GetOriginalID(e.id);
cb.Offset = e.offset;
cb.ByteSize = uint32_t(res->GetDesc().Width - cb.Offset);
}
}
}
else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_SRV)
{
D3D12PipelineState::ResourceView &view =
resize_and_add(spaces[p.Descriptor.RegisterSpace].srvs, p.Descriptor.ShaderRegister);
view.Immediate = true;
view.RootElement = (uint32_t)rootEl;
if(rootEl < rootSig.sigelems.size())
{
const D3D12RenderState::SignatureElement &e = rootSig.sigelems[rootEl];
if(e.type == eRootSRV)
{
ID3D12Resource *res = rm->GetCurrentAs<ID3D12Resource>(e.id);
// parameters from resource/view
view.Resource = rm->GetOriginalID(e.id);
view.Type = ToStr::Get(D3D12_SRV_DIMENSION_BUFFER);
view.Format = MakeResourceFormat(DXGI_FORMAT_R32_UINT);
view.ElementSize = sizeof(uint32_t);
view.FirstElement = e.offset / sizeof(uint32_t);
view.NumElements = uint32_t((res->GetDesc().Width - e.offset) / sizeof(uint32_t));
}
}
}
else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_UAV)
{
D3D12PipelineState::ResourceView &view =
resize_and_add(spaces[p.Descriptor.RegisterSpace].uavs, p.Descriptor.ShaderRegister);
view.Immediate = true;
view.RootElement = (uint32_t)rootEl;
if(rootEl < rootSig.sigelems.size())
{
const D3D12RenderState::SignatureElement &e = rootSig.sigelems[rootEl];
if(e.type == eRootUAV)
{
ID3D12Resource *res = rm->GetCurrentAs<ID3D12Resource>(e.id);
// parameters from resource/view
view.Resource = rm->GetOriginalID(e.id);
view.Type = ToStr::Get(D3D12_UAV_DIMENSION_BUFFER);
view.Format = MakeResourceFormat(DXGI_FORMAT_R32_UINT);
view.ElementSize = sizeof(uint32_t);
view.FirstElement = e.offset / sizeof(uint32_t);
view.NumElements = uint32_t((res->GetDesc().Width - e.offset) / sizeof(uint32_t));
}
}
}
else if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
{
const D3D12RenderState::SignatureElement *e = NULL;
WrappedID3D12DescriptorHeap *heap = NULL;
if(rootEl < rootSig.sigelems.size() && rootSig.sigelems[rootEl].type == eRootTable)
{
e = &rootSig.sigelems[rootEl];
heap = rm->GetCurrentAs<WrappedID3D12DescriptorHeap>(e->id);
}
UINT prevTableOffset = 0;
for(size_t r = 0; r < p.ranges.size(); r++)
{
const D3D12_DESCRIPTOR_RANGE1 &range = p.ranges[r];
UINT shaderReg = range.BaseShaderRegister;
UINT regSpace = range.RegisterSpace;
D3D12Descriptor *desc = NULL;
UINT offset = range.OffsetInDescriptorsFromTableStart;
if(range.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
offset = prevTableOffset;
if(heap)
{
desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr;
desc += e->offset;
desc += offset;
}
prevTableOffset = offset + range.NumDescriptors;
if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER)
{
UINT maxReg = shaderReg + range.NumDescriptors - 1;
if(maxReg >= spaces[regSpace].samplers.size())
spaces[regSpace].samplers.resize(maxReg + 1);
for(UINT i = 0; i < range.NumDescriptors; i++, shaderReg++)
{
D3D12PipelineState::Sampler &samp = spaces[regSpace].samplers[shaderReg];
samp.Immediate = false;
samp.RootElement = (uint32_t)rootEl;
samp.TableIndex = offset + i;
if(desc)
{
D3D12_SAMPLER_DESC &sampDesc = desc->samp.desc;
samp.AddressU = ToStr::Get(sampDesc.AddressU);
samp.AddressV = ToStr::Get(sampDesc.AddressV);
samp.AddressW = ToStr::Get(sampDesc.AddressW);
memcpy(samp.BorderColor, sampDesc.BorderColor, sizeof(FLOAT) * 4);
samp.Comparison = ToStr::Get(sampDesc.ComparisonFunc);
samp.Filter = ToStr::Get(sampDesc.Filter);
samp.MaxAniso = 0;
if(sampDesc.Filter == D3D12_FILTER_ANISOTROPIC ||
sampDesc.Filter == D3D12_FILTER_COMPARISON_ANISOTROPIC ||
sampDesc.Filter == D3D12_FILTER_MINIMUM_ANISOTROPIC ||
sampDesc.Filter == D3D12_FILTER_MAXIMUM_ANISOTROPIC)
samp.MaxAniso = sampDesc.MaxAnisotropy;
samp.MaxLOD = sampDesc.MaxLOD;
samp.MinLOD = sampDesc.MinLOD;
samp.MipLODBias = sampDesc.MipLODBias;
samp.UseComparison = (sampDesc.Filter >= D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT &&
sampDesc.Filter <= D3D12_FILTER_COMPARISON_ANISOTROPIC);
samp.UseBorder = (sampDesc.AddressU == D3D12_TEXTURE_ADDRESS_MODE_BORDER ||
sampDesc.AddressV == D3D12_TEXTURE_ADDRESS_MODE_BORDER ||
sampDesc.AddressW == D3D12_TEXTURE_ADDRESS_MODE_BORDER);
desc++;
}
}
}
else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV)
{
UINT maxReg = shaderReg + range.NumDescriptors - 1;
if(maxReg >= spaces[regSpace].cbuffers.size())
spaces[regSpace].cbuffers.resize(maxReg + 1);
for(UINT i = 0; i < range.NumDescriptors; i++, shaderReg++)
{
D3D12PipelineState::CBuffer &cb = spaces[regSpace].cbuffers[shaderReg];
cb.Immediate = false;
cb.RootElement = (uint32_t)rootEl;
cb.TableIndex = offset + i;
if(desc)
{
WrappedID3D12Resource::GetResIDFromAddr(desc->nonsamp.cbv.BufferLocation, cb.Buffer,
cb.Offset);
cb.Buffer = rm->GetOriginalID(cb.Buffer);
cb.ByteSize = desc->nonsamp.cbv.SizeInBytes;
desc++;
}
}
}
else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV)
{
UINT maxReg = shaderReg + range.NumDescriptors - 1;
if(maxReg >= spaces[regSpace].srvs.size())
spaces[regSpace].srvs.resize(maxReg + 1);
for(UINT i = 0; i < range.NumDescriptors; i++, shaderReg++)
{
D3D12PipelineState::ResourceView &view = spaces[regSpace].srvs[shaderReg];
view.Immediate = false;
view.RootElement = (uint32_t)rootEl;
view.TableIndex = offset + i;
if(desc)
{
FillResourceView(view, desc);
desc++;
}
}
}
else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV)
{
UINT maxReg = shaderReg + range.NumDescriptors - 1;
if(maxReg >= spaces[regSpace].uavs.size())
spaces[regSpace].uavs.resize(maxReg + 1);
for(UINT i = 0; i < range.NumDescriptors; i++, shaderReg++)
{
D3D12PipelineState::ResourceView &view = spaces[regSpace].uavs[shaderReg];
view.Immediate = false;
view.RootElement = (uint32_t)rootEl;
view.TableIndex = offset + i;
if(desc)
{
FillResourceView(view, desc);
desc++;
}
}
}
}
}
}
for(size_t i = 0; i < sig->sig.samplers.size(); i++)
{
D3D12_STATIC_SAMPLER_DESC &sampDesc = sig->sig.samplers[i];
if(sampDesc.ShaderVisibility != D3D12_SHADER_VISIBILITY_ALL &&
sampDesc.ShaderVisibility != visibility)
continue;
D3D12PipelineState::Sampler &samp =
resize_and_add(spaces[sampDesc.RegisterSpace].samplers, sampDesc.ShaderRegister);
samp.Immediate = true;
samp.RootElement = (uint32_t)i;
samp.AddressU = ToStr::Get(sampDesc.AddressU);
samp.AddressV = ToStr::Get(sampDesc.AddressV);
samp.AddressW = ToStr::Get(sampDesc.AddressW);
if(sampDesc.BorderColor == D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK)
{
samp.BorderColor[0] = 0.0f;
samp.BorderColor[1] = 0.0f;
samp.BorderColor[2] = 0.0f;
samp.BorderColor[3] = 0.0f;
}
else if(sampDesc.BorderColor == D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK)
{
samp.BorderColor[0] = 0.0f;
samp.BorderColor[1] = 0.0f;
samp.BorderColor[2] = 0.0f;
samp.BorderColor[3] = 1.0f;
}
else if(sampDesc.BorderColor == D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE)
{
samp.BorderColor[0] = 1.0f;
samp.BorderColor[1] = 1.0f;
samp.BorderColor[2] = 1.0f;
samp.BorderColor[3] = 1.0f;
}
else
{
RDCERR("Unexpected static border colour: %u", sampDesc.BorderColor);
}
samp.Comparison = ToStr::Get(sampDesc.ComparisonFunc);
samp.Filter = ToStr::Get(sampDesc.Filter);
samp.MaxAniso = 0;
if(sampDesc.Filter == D3D12_FILTER_ANISOTROPIC ||
sampDesc.Filter == D3D12_FILTER_COMPARISON_ANISOTROPIC ||
sampDesc.Filter == D3D12_FILTER_MINIMUM_ANISOTROPIC ||
sampDesc.Filter == D3D12_FILTER_MAXIMUM_ANISOTROPIC)
samp.MaxAniso = sampDesc.MaxAnisotropy;
samp.MaxLOD = sampDesc.MaxLOD;
samp.MinLOD = sampDesc.MinLOD;
samp.MipLODBias = sampDesc.MipLODBias;
samp.UseComparison = (sampDesc.Filter >= D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT &&
sampDesc.Filter <= D3D12_FILTER_COMPARISON_ANISOTROPIC);
samp.UseBorder = (sampDesc.AddressU == D3D12_TEXTURE_ADDRESS_MODE_BORDER ||
sampDesc.AddressV == D3D12_TEXTURE_ADDRESS_MODE_BORDER ||
sampDesc.AddressW == D3D12_TEXTURE_ADDRESS_MODE_BORDER);
}
for(uint32_t i = 0; i < sig->sig.numSpaces; i++)
{
dstSpaces[i].ConstantBuffers = spaces[i].cbuffers;
dstSpaces[i].Samplers = spaces[i].samplers;
dstSpaces[i].SRVs = spaces[i].srvs;
dstSpaces[i].UAVs = spaces[i].uavs;
}
SAFE_DELETE_ARRAY(spaces);
}
void D3D12Replay::MakePipelineState()
{
const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState;
D3D12PipelineState state;
/////////////////////////////////////////////////
// Input Assembler
/////////////////////////////////////////////////
D3D12ResourceManager *rm = m_pDevice->GetResourceManager();
state.pipeline = rm->GetOriginalID(rs.pipe);
state.customName = true;
string str = m_pDevice->GetResourceName(rs.pipe);
WrappedID3D12PipelineState *pipe = NULL;
if(rs.pipe != ResourceId())
pipe = rm->GetCurrentAs<WrappedID3D12PipelineState>(rs.pipe);
if(str == "")
{
state.customName = false;
if(pipe)
str = StringFormat::Fmt(pipe->IsGraphics() ? "Graphics Pipe %llu" : "Compute Pipe %llu",
state.pipeline);
else
str = "Unbound";
}
state.PipelineName = str;
if(pipe && pipe->IsGraphics())
{
const D3D12_INPUT_ELEMENT_DESC *inputEl = pipe->graphics->InputLayout.pInputElementDescs;
UINT numInput = pipe->graphics->InputLayout.NumElements;
create_array_uninit(state.m_IA.layouts, numInput);
for(UINT i = 0; i < numInput; i++)
{
D3D12PipelineState::InputAssembler::LayoutInput &l = state.m_IA.layouts[i];
l.ByteOffset = inputEl[i].AlignedByteOffset;
l.Format = MakeResourceFormat(inputEl[i].Format);
l.InputSlot = inputEl[i].InputSlot;
l.PerInstance = inputEl[i].InputSlotClass == D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
l.InstanceDataStepRate = inputEl[i].InstanceDataStepRate;
l.SemanticIndex = inputEl[i].SemanticIndex;
l.SemanticName = inputEl[i].SemanticName;
}
state.m_IA.indexStripCutValue = 0;
switch(pipe->graphics->IBStripCutValue)
{
case D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF: state.m_IA.indexStripCutValue = 0xFFFF; break;
case D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF:
state.m_IA.indexStripCutValue = 0xFFFFFFFF;
break;
default: break;
}
create_array_uninit(state.m_IA.vbuffers, rs.vbuffers.size());
for(size_t i = 0; i < rs.vbuffers.size(); i++)
{
D3D12PipelineState::InputAssembler::VertexBuffer &vb = state.m_IA.vbuffers[i];
vb.Buffer = rm->GetOriginalID(rs.vbuffers[i].buf);
vb.Offset = rs.vbuffers[i].offs;
vb.Size = rs.vbuffers[i].size;
vb.Stride = rs.vbuffers[i].stride;
}
state.m_IA.ibuffer.Buffer = rm->GetOriginalID(rs.ibuffer.buf);
state.m_IA.ibuffer.Offset = rs.ibuffer.offs;
state.m_IA.ibuffer.Size = rs.ibuffer.size;
}
/////////////////////////////////////////////////
// Shaders
/////////////////////////////////////////////////
if(pipe && pipe->IsCompute())
{
WrappedID3D12Shader *sh = (WrappedID3D12Shader *)pipe->compute->CS.pShaderBytecode;
state.m_CS.Shader = sh->GetResourceID();
state.m_CS.stage = eShaderStage_Compute;
state.m_CS.BindpointMapping = sh->GetMapping();
state.rootSig = rm->GetOriginalID(rs.compute.rootsig);
if(rs.compute.rootsig != ResourceId())
FillRegisterSpaces(rs.compute, state.m_CS.Spaces, D3D12_SHADER_VISIBILITY_ALL);
}
else if(pipe)
{
D3D12PipelineState::ShaderStage *dstArr[] = {&state.m_VS, &state.m_HS, &state.m_DS, &state.m_GS,
&state.m_PS};
D3D12_SHADER_BYTECODE *srcArr[] = {&pipe->graphics->VS, &pipe->graphics->HS, &pipe->graphics->DS,
&pipe->graphics->GS, &pipe->graphics->PS};
D3D12_SHADER_VISIBILITY visibility[] = {
D3D12_SHADER_VISIBILITY_VERTEX, D3D12_SHADER_VISIBILITY_HULL, D3D12_SHADER_VISIBILITY_DOMAIN,
D3D12_SHADER_VISIBILITY_GEOMETRY, D3D12_SHADER_VISIBILITY_PIXEL};
for(size_t stage = 0; stage < 5; stage++)
{
D3D12PipelineState::ShaderStage &dst = *dstArr[stage];
D3D12_SHADER_BYTECODE &src = *srcArr[stage];
dst.stage = (ShaderStageType)stage;
WrappedID3D12Shader *sh = (WrappedID3D12Shader *)src.pShaderBytecode;
if(sh)
{
dst.Shader = sh->GetResourceID();
dst.BindpointMapping = sh->GetMapping();
}
if(rs.graphics.rootsig != ResourceId())
FillRegisterSpaces(rs.graphics, dst.Spaces, visibility[stage]);
}
state.rootSig = rm->GetOriginalID(rs.graphics.rootsig);
}
if(pipe && pipe->IsGraphics())
{
/////////////////////////////////////////////////
// Stream Out
/////////////////////////////////////////////////
create_array_uninit(state.m_SO.Outputs, rs.streamouts.size());
for(size_t s = 0; s < rs.streamouts.size(); s++)
{
state.m_SO.Outputs[s].Buffer = rm->GetOriginalID(rs.streamouts[s].buf);
state.m_SO.Outputs[s].Offset = rs.streamouts[s].offs;
state.m_SO.Outputs[s].Size = rs.streamouts[s].size;
state.m_SO.Outputs[s].WrittenCountBuffer = rm->GetOriginalID(rs.streamouts[s].countbuf);
state.m_SO.Outputs[s].WrittenCountOffset = rs.streamouts[s].countoffs;
}
/////////////////////////////////////////////////
// Rasterizer
/////////////////////////////////////////////////
state.m_RS.SampleMask = pipe->graphics->SampleMask;
{
D3D12PipelineState::Rasterizer::RasterizerState &dst = state.m_RS.m_State;
D3D12_RASTERIZER_DESC &src = pipe->graphics->RasterizerState;
dst.AntialiasedLineEnable = src.AntialiasedLineEnable == TRUE;
dst.CullMode = eCull_None;
if(src.CullMode == D3D12_CULL_MODE_FRONT)
dst.CullMode = eCull_Front;
if(src.CullMode == D3D12_CULL_MODE_BACK)
dst.CullMode = eCull_Back;
dst.FillMode = eFill_Solid;
if(src.FillMode == D3D12_FILL_MODE_WIREFRAME)
dst.FillMode = eFill_Wireframe;
dst.DepthBias = src.DepthBias;
dst.DepthBiasClamp = src.DepthBiasClamp;
dst.DepthClip = src.DepthClipEnable == TRUE;
dst.FrontCCW = src.FrontCounterClockwise == TRUE;
dst.MultisampleEnable = src.MultisampleEnable == TRUE;
dst.SlopeScaledDepthBias = src.SlopeScaledDepthBias;
dst.ForcedSampleCount = src.ForcedSampleCount;
dst.ConservativeRasterization =
src.ConservativeRaster == D3D12_CONSERVATIVE_RASTERIZATION_MODE_ON;
}
create_array_uninit(state.m_RS.Scissors, rs.scissors.size());
for(size_t i = 0; i < rs.scissors.size(); i++)
state.m_RS.Scissors[i] = D3D12PipelineState::Rasterizer::Scissor(
rs.scissors[i].left, rs.scissors[i].top, rs.scissors[i].right, rs.scissors[i].bottom);
create_array_uninit(state.m_RS.Viewports, rs.views.size());
for(size_t i = 0; i < rs.views.size(); i++)
state.m_RS.Viewports[i] = D3D12PipelineState::Rasterizer::Viewport(
rs.views[i].TopLeftX, rs.views[i].TopLeftY, rs.views[i].Width, rs.views[i].Height,
rs.views[i].MinDepth, rs.views[i].MaxDepth);
/////////////////////////////////////////////////
// Output Merger
/////////////////////////////////////////////////
create_array(state.m_OM.RenderTargets, rs.rts.size());
for(size_t i = 0; i < rs.rts.size(); i++)
{
D3D12PipelineState::ResourceView &view = state.m_OM.RenderTargets[i];
PortableHandle h = rs.rtSingle ? rs.rts[0] : rs.rts[i];
if(h.heap != ResourceId())
{
D3D12Descriptor *desc = DescriptorFromPortableHandle(rm, h);
if(rs.rtSingle)
desc += i;
view.RootElement = (uint32_t)i;
view.Immediate = false;
FillResourceView(view, desc);
}
}
{
D3D12PipelineState::ResourceView &view = state.m_OM.DepthTarget;
if(rs.dsv.heap != ResourceId())
{
D3D12Descriptor *desc = DescriptorFromPortableHandle(rm, rs.dsv);
view.RootElement = 0;
view.Immediate = false;
FillResourceView(view, desc);
}
}
memcpy(state.m_OM.m_BlendState.BlendFactor, rs.blendFactor, sizeof(FLOAT) * 4);
{
D3D12_BLEND_DESC &src = pipe->graphics->BlendState;
state.m_OM.m_BlendState.AlphaToCoverage = src.AlphaToCoverageEnable == TRUE;
state.m_OM.m_BlendState.IndependentBlend = src.IndependentBlendEnable == TRUE;
create_array_uninit(state.m_OM.m_BlendState.Blends, 8);
for(size_t i = 0; i < 8; i++)
{
D3D12PipelineState::OutputMerger::BlendState::RTBlend &blend =
state.m_OM.m_BlendState.Blends[i];
blend.Enabled = src.RenderTarget[i].BlendEnable == TRUE;
blend.LogicEnabled = src.RenderTarget[i].LogicOpEnable == TRUE;
blend.LogicOp = ToStr::Get(src.RenderTarget[i].LogicOp);
blend.m_AlphaBlend.Source = ToStr::Get(src.RenderTarget[i].SrcBlendAlpha);
blend.m_AlphaBlend.Destination = ToStr::Get(src.RenderTarget[i].DestBlendAlpha);
blend.m_AlphaBlend.Operation = ToStr::Get(src.RenderTarget[i].BlendOpAlpha);
blend.m_Blend.Source = ToStr::Get(src.RenderTarget[i].SrcBlend);
blend.m_Blend.Destination = ToStr::Get(src.RenderTarget[i].DestBlend);
blend.m_Blend.Operation = ToStr::Get(src.RenderTarget[i].BlendOp);
blend.WriteMask = src.RenderTarget[i].RenderTargetWriteMask;
}
}
{
D3D12_DEPTH_STENCIL_DESC &src = pipe->graphics->DepthStencilState;
state.m_OM.m_State.DepthEnable = src.DepthEnable == TRUE;
state.m_OM.m_State.DepthFunc = ToStr::Get(src.DepthFunc);
state.m_OM.m_State.DepthWrites = src.DepthWriteMask == D3D12_DEPTH_WRITE_MASK_ALL;
state.m_OM.m_State.StencilEnable = src.StencilEnable == TRUE;
state.m_OM.m_State.StencilRef = rs.stencilRef;
state.m_OM.m_State.StencilReadMask = src.StencilReadMask;
state.m_OM.m_State.StencilWriteMask = src.StencilWriteMask;
state.m_OM.m_State.m_FrontFace.Func = ToStr::Get(src.FrontFace.StencilFunc);
state.m_OM.m_State.m_FrontFace.DepthFailOp = ToStr::Get(src.FrontFace.StencilDepthFailOp);
state.m_OM.m_State.m_FrontFace.PassOp = ToStr::Get(src.FrontFace.StencilPassOp);
state.m_OM.m_State.m_FrontFace.FailOp = ToStr::Get(src.FrontFace.StencilFailOp);
state.m_OM.m_State.m_BackFace.Func = ToStr::Get(src.BackFace.StencilFunc);
state.m_OM.m_State.m_BackFace.DepthFailOp = ToStr::Get(src.BackFace.StencilDepthFailOp);
state.m_OM.m_State.m_BackFace.PassOp = ToStr::Get(src.BackFace.StencilPassOp);
state.m_OM.m_State.m_BackFace.FailOp = ToStr::Get(src.BackFace.StencilFailOp);
}
}
// resource states
{
const map<ResourceId, SubresourceStateVector> &states = m_pDevice->GetSubresourceStates();
create_array_uninit(state.Resources, states.size());
size_t i = 0;
for(auto it = states.begin(); it != states.end(); ++it)
{
D3D12PipelineState::ResourceData &res = state.Resources[i];
res.id = rm->GetOriginalID(it->first);
create_array_uninit(res.states, it->second.size());
for(size_t l = 0; l < it->second.size(); l++)
res.states[l].name = ToStr::Get(it->second[l]);
i++;
}
}
m_PipelineState = state;
}
void D3D12Replay::RenderCheckerboard(Vec3f light, Vec3f dark)
{
m_pDevice->GetDebugManager()->RenderCheckerboard(light, dark);
}
void D3D12Replay::RenderHighlightBox(float w, float h, float scale)
{
m_pDevice->GetDebugManager()->RenderHighlightBox(w, h, scale);
}
bool D3D12Replay::RenderTexture(TextureDisplay cfg)
{
return m_pDevice->GetDebugManager()->RenderTexture(cfg, true);
}
void D3D12Replay::RenderMesh(uint32_t eventID, const vector<MeshFormat> &secondaryDraws,
const MeshDisplay &cfg)
{
return m_pDevice->GetDebugManager()->RenderMesh(eventID, secondaryDraws, cfg);
}
bool D3D12Replay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,
FormatComponentType typeHint, float *minval, float *maxval)
{
return m_pDevice->GetDebugManager()->GetMinMax(texid, sliceFace, mip, sample, typeHint, minval,
maxval);
}
bool D3D12Replay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,
FormatComponentType typeHint, float minval, float maxval,
bool channels[4], vector<uint32_t> &histogram)
{
return m_pDevice->GetDebugManager()->GetHistogram(texid, sliceFace, mip, sample, typeHint, minval,
maxval, channels, histogram);
}
ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FormatComponentType typeHint,
TextureDisplayOverlay overlay, uint32_t eventID,
const vector<uint32_t> &passEvents)
{
return m_pDevice->GetDebugManager()->RenderOverlay(texid, typeHint, overlay, eventID, passEvents);
}
bool D3D12Replay::IsRenderOutput(ResourceId id)
{
const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState;
id = m_pDevice->GetResourceManager()->GetLiveID(id);
for(size_t i = 0; i < rs.rts.size(); i++)
{
PortableHandle h = rs.rtSingle ? rs.rts[0] : rs.rts[i];
if(h.heap != ResourceId())
{
D3D12Descriptor *desc = DescriptorFromPortableHandle(m_pDevice->GetResourceManager(), h);
if(rs.rtSingle)
desc += i;
if(id == GetResID(desc->nonsamp.resource))
return true;
}
}
if(rs.dsv.heap != ResourceId())
{
D3D12Descriptor *desc = DescriptorFromPortableHandle(m_pDevice->GetResourceManager(), rs.dsv);
if(id == GetResID(desc->nonsamp.resource))
return true;
}
return false;
}
vector<uint32_t> D3D12Replay::GetPassEvents(uint32_t eventID)
{
vector<uint32_t> passEvents;
const FetchDrawcall *draw = m_pDevice->GetDrawcall(eventID);
if(!draw)
return passEvents;
// for D3D12 a pass == everything writing to the same RTs in a command list.
const FetchDrawcall *start = draw;
while(start)
{
// if we've come to the beginning of a list, break out of the loop, we've
// found the start.
if(start->flags & eDraw_BeginPass)
break;
// if we come to the END of a list, since we were iterating backwards that
// means we started outside of a list, so return empty set.
if(start->flags & eDraw_EndPass)
return passEvents;
// if we've come to the start of the log we were outside of a list
// to start with
if(start->previous == 0)
return passEvents;
// step back
const FetchDrawcall *prev = m_pDevice->GetDrawcall((uint32_t)start->previous);
// something went wrong, start->previous was non-zero but we didn't
// get a draw. Abort
if(!prev)
return passEvents;
// if the outputs changed, we're done
if(memcmp(start->outputs, prev->outputs, sizeof(start->outputs)) ||
start->depthOut != prev->depthOut)
break;
start = prev;
}
// store all the draw eventIDs up to the one specified at the start
while(start)
{
if(start == draw)
break;
// include pass boundaries, these will be filtered out later
// so we don't actually do anything (init postvs/draw overlay)
// but it's useful to have the first part of the pass as part
// of the list
if(start->flags & (eDraw_Drawcall | eDraw_PassBoundary))
passEvents.push_back(start->eventID);
start = m_pDevice->GetDrawcall((uint32_t)start->next);
}
return passEvents;
}
bool D3D12Replay::IsTextureSupported(const ResourceFormat &format)
{
return MakeDXGIFormat(format) != DXGI_FORMAT_UNKNOWN;
}
void D3D12Replay::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector<byte> &retData)
{
m_pDevice->GetDebugManager()->GetBufferData(buff, offset, len, retData);
}
void D3D12Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace,
uint32_t mip, uint32_t sample, FormatComponentType typeHint,
float pixel[4])
{
m_pDevice->GetDebugManager()->PickPixel(texture, x, y, sliceFace, mip, sample, typeHint, pixel);
}
void D3D12Replay::FillCBufferVariables(ResourceId shader, string entryPoint, uint32_t cbufSlot,
vector<ShaderVariable> &outvars, const vector<byte> &data)
{
if(shader == ResourceId())
return;
ID3D12DeviceChild *res = m_pDevice->GetResourceManager()->GetCurrentResource(shader);
if(!WrappedID3D12Shader::IsAlloc(res))
{
RDCERR("Shader ID %llu does not correspond to a known fake shader", shader);
return;
}
WrappedID3D12Shader *sh = (WrappedID3D12Shader *)res;
DXBC::DXBCFile *dxbc = sh->GetDXBC();
const ShaderBindpointMapping &bindMap = sh->GetMapping();
RDCASSERT(dxbc);
DXBC::CBuffer *cb = NULL;
uint32_t idx = 0;
for(size_t i = 0; i < dxbc->m_CBuffers.size(); i++)
{
if(dxbc->m_CBuffers[i].descriptor.type != DXBC::CBuffer::Descriptor::TYPE_CBUFFER)
continue;
if(idx == cbufSlot)
cb = &dxbc->m_CBuffers[i];
idx++;
}
if(cb && cbufSlot < (uint32_t)bindMap.ConstantBlocks.count)
{
// check if the data actually comes from root constants
const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState;
BindpointMap bind = bindMap.ConstantBlocks[cbufSlot];
WrappedID3D12RootSignature *sig = NULL;
const vector<D3D12RenderState::SignatureElement> *sigElems = NULL;
if(dxbc->m_Type == D3D11_ShaderType_Compute && rs.compute.rootsig != ResourceId())
{
sig = m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12RootSignature>(
rs.compute.rootsig);
sigElems = &rs.compute.sigelems;
}
else if(dxbc->m_Type != D3D11_ShaderType_Compute && rs.graphics.rootsig != ResourceId())
{
sig = m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12RootSignature>(
rs.graphics.rootsig);
sigElems = &rs.graphics.sigelems;
}
vector<byte> rootData;
for(size_t i = 0; sig && i < sig->sig.params.size(); i++)
{
const D3D12RootSignatureParameter &p = sig->sig.params[i];
if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS &&
p.Constants.RegisterSpace == (UINT)bind.bindset &&
p.Constants.ShaderRegister == (UINT)bind.bind)
{
size_t dstSize = sig->sig.params[i].Constants.Num32BitValues * sizeof(uint32_t);
rootData.resize(dstSize);
if(i < sigElems->size())
{
const D3D12RenderState::SignatureElement &el = (*sigElems)[i];
if(el.type == eRootConst)
{
byte *dst = &rootData[0];
const UINT *src = &el.constants[0];
size_t srcSize = el.constants.size() * sizeof(uint32_t);
memcpy(dst, src, RDCMIN(srcSize, dstSize));
}
}
}
}
m_pDevice->GetDebugManager()->FillCBufferVariables(cb->variables, outvars, false,
rootData.empty() ? data : rootData);
}
}
uint64_t D3D12Replay::MakeOutputWindow(WindowingSystem system, void *data, bool depth)
{
return m_pDevice->GetDebugManager()->MakeOutputWindow(system, data, depth);
}
void D3D12Replay::DestroyOutputWindow(uint64_t id)
{
m_pDevice->GetDebugManager()->DestroyOutputWindow(id);
}
bool D3D12Replay::CheckResizeOutputWindow(uint64_t id)
{
return m_pDevice->GetDebugManager()->CheckResizeOutputWindow(id);
}
void D3D12Replay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
{
m_pDevice->GetDebugManager()->GetOutputWindowDimensions(id, w, h);
}
void D3D12Replay::ClearOutputWindowColour(uint64_t id, float col[4])
{
m_pDevice->GetDebugManager()->ClearOutputWindowColour(id, col);
}
void D3D12Replay::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil)
{
m_pDevice->GetDebugManager()->ClearOutputWindowDepth(id, depth, stencil);
}
void D3D12Replay::BindOutputWindow(uint64_t id, bool depth)
{
m_pDevice->GetDebugManager()->BindOutputWindow(id, depth);
}
bool D3D12Replay::IsOutputWindowVisible(uint64_t id)
{
return m_pDevice->GetDebugManager()->IsOutputWindowVisible(id);
}
void D3D12Replay::FlipOutputWindow(uint64_t id)
{
m_pDevice->GetDebugManager()->FlipOutputWindow(id);
}
void D3D12Replay::InitCallstackResolver()
{
m_pDevice->GetMainSerialiser()->InitCallstackResolver();
}
bool D3D12Replay::HasCallstacks()
{
return m_pDevice->GetMainSerialiser()->HasCallstacks();
}
Callstack::StackResolver *D3D12Replay::GetCallstackResolver()
{
return m_pDevice->GetMainSerialiser()->GetCallstackResolver();
}
vector<DebugMessage> D3D12Replay::GetDebugMessages()
{
return m_pDevice->GetDebugMessages();
}
void D3D12Replay::BuildTargetShader(string source, string entry, const uint32_t compileFlags,
ShaderStageType type, ResourceId *id, string *errors)
{
m_pDevice->GetDebugManager()->BuildShader(source, entry, D3DCOMPILE_DEBUG | compileFlags, type,
id, errors);
}
void D3D12Replay::ReplaceResource(ResourceId from, ResourceId to)
{
D3D12ResourceManager *rm = m_pDevice->GetResourceManager();
// remove any previous replacement
RemoveReplacement(from);
if(rm->HasLiveResource(from))
{
ID3D12DeviceChild *resource = rm->GetLiveResource(from);
if(WrappedID3D12Shader::IsAlloc(resource))
{
WrappedID3D12Shader *sh = (WrappedID3D12Shader *)resource;
for(size_t i = 0; i < sh->m_Pipes.size(); i++)
{
WrappedID3D12PipelineState *pipe = sh->m_Pipes[i];
ResourceId id = rm->GetOriginalID(pipe->GetResourceID());
ID3D12PipelineState *replpipe = NULL;
D3D12_SHADER_BYTECODE shDesc = rm->GetLiveAs<WrappedID3D12Shader>(to)->GetDesc();
if(pipe->graphics)
{
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = *pipe->graphics;
D3D12_SHADER_BYTECODE *shaders[] = {
&desc.VS, &desc.HS, &desc.DS, &desc.GS, &desc.PS,
};
for(size_t s = 0; s < ARRAY_COUNT(shaders); s++)
{
if(shaders[s]->BytecodeLength > 0)
{
WrappedID3D12Shader *stage = (WrappedID3D12Shader *)shaders[s]->pShaderBytecode;
if(stage->GetResourceID() == from)
*shaders[s] = shDesc;
else
*shaders[s] = stage->GetDesc();
}
}
m_pDevice->CreateGraphicsPipelineState(&desc, __uuidof(ID3D12PipelineState),
(void **)&replpipe);
}
else
{
D3D12_COMPUTE_PIPELINE_STATE_DESC desc = *pipe->compute;
// replace the shader
desc.CS = shDesc;
m_pDevice->CreateComputePipelineState(&desc, __uuidof(ID3D12PipelineState),
(void **)&replpipe);
}
rm->ReplaceResource(id, GetResID(replpipe));
}
}
rm->ReplaceResource(from, to);
}
}
void D3D12Replay::RemoveReplacement(ResourceId id)
{
D3D12ResourceManager *rm = m_pDevice->GetResourceManager();
rm->RemoveReplacement(id);
if(rm->HasLiveResource(id))
{
ID3D12DeviceChild *resource = rm->GetLiveResource(id);
if(WrappedID3D12Shader::IsAlloc(resource))
{
WrappedID3D12Shader *sh = (WrappedID3D12Shader *)resource;
for(size_t i = 0; i < sh->m_Pipes.size(); i++)
{
WrappedID3D12PipelineState *pipe = sh->m_Pipes[i];
ResourceId pipeid = rm->GetOriginalID(pipe->GetResourceID());
rm->RemoveReplacement(pipeid);
}
}
}
}
byte *D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip,
const GetTextureDataParams &params, size_t &dataSize)
{
return m_pDevice->GetDebugManager()->GetTextureData(tex, arrayIdx, mip, params, dataSize);
}
#pragma region not yet implemented
void D3D12Replay::InitPostVSBuffers(uint32_t eventID)
{
}
void D3D12Replay::InitPostVSBuffers(const vector<uint32_t> &passEvents)
{
}
MeshFormat D3D12Replay::GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage)
{
return MeshFormat();
}
void D3D12Replay::BuildCustomShader(string source, string entry, const uint32_t compileFlags,
ShaderStageType type, ResourceId *id, string *errors)
{
}
vector<PixelModification> D3D12Replay::PixelHistory(vector<EventUsage> events, ResourceId target,
uint32_t x, uint32_t y, uint32_t slice,
uint32_t mip, uint32_t sampleIdx,
FormatComponentType typeHint)
{
return vector<PixelModification>();
}
ShaderDebugTrace D3D12Replay::DebugVertex(uint32_t eventID, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
{
return ShaderDebugTrace();
}
ShaderDebugTrace D3D12Replay::DebugPixel(uint32_t eventID, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
{
return ShaderDebugTrace();
}
ShaderDebugTrace D3D12Replay::DebugThread(uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3])
{
return ShaderDebugTrace();
}
uint32_t D3D12Replay::PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x, uint32_t y)
{
return ~0U;
}
ResourceId D3D12Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip,
uint32_t arrayIdx, uint32_t sampleIdx,
FormatComponentType typeHint)
{
return ResourceId();
}
ResourceId D3D12Replay::CreateProxyTexture(const FetchTexture &templateTex)
{
return ResourceId();
}
void D3D12Replay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data,
size_t dataSize)
{
}
ResourceId D3D12Replay::CreateProxyBuffer(const FetchBuffer &templateBuf)
{
return ResourceId();
}
void D3D12Replay::SetProxyBufferData(ResourceId bufid, byte *data, size_t dataSize)
{
}
#pragma endregion
extern "C" __declspec(dllexport) HRESULT
__cdecl RENDERDOC_CreateWrappedD3D12Device(IUnknown *pAdapter,
D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid,
void **ppDevice);
ID3DDevice *GetD3D12DeviceIfAlloc(IUnknown *dev);
ReplayCreateStatus D3D12_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
{
RDCDEBUG("Creating a D3D12 replay device");
WrappedIDXGISwapChain4::RegisterD3DDeviceCallback(GetD3D12DeviceIfAlloc);
HMODULE lib = NULL;
lib = LoadLibraryA("d3d12.dll");
if(lib == NULL)
{
RDCERR("Failed to load d3d12.dll");
return eReplayCreate_APIInitFailed;
}
lib = LoadLibraryA("dxgi.dll");
if(lib == NULL)
{
RDCERR("Failed to load dxgi.dll");
return eReplayCreate_APIInitFailed;
}
if(GetD3DCompiler() == NULL)
{
RDCERR("Failed to load d3dcompiler_??.dll");
return eReplayCreate_APIInitFailed;
}
D3D12InitParams initParams;
RDCDriver driverFileType = RDC_D3D12;
string driverName = "D3D12";
uint64_t machineIdent = 0;
if(logfile)
{
auto status = RenderDoc::Inst().FillInitParams(logfile, driverFileType, driverName,
machineIdent, (RDCInitParams *)&initParams);
if(status != eReplayCreate_Success)
return status;
}
// initParams.SerialiseVersion is guaranteed to be valid/supported since otherwise the
// FillInitParams (which calls D3D12InitParams::Serialise) would have failed above, so no need to
// check it here.
if(initParams.MinimumFeatureLevel < D3D_FEATURE_LEVEL_11_0)
initParams.MinimumFeatureLevel = D3D_FEATURE_LEVEL_11_0;
D3D12Replay::PreDeviceInitCounters();
ID3D12Device *dev = NULL;
HRESULT hr = RENDERDOC_CreateWrappedD3D12Device(NULL, initParams.MinimumFeatureLevel,
__uuidof(ID3D12Device), (void **)&dev);
if(FAILED(hr))
{
RDCERR("Couldn't create a d3d12 device :(.");
return eReplayCreate_APIHardwareUnsupported;
}
WrappedID3D12Device *wrappedDev = (WrappedID3D12Device *)dev;
if(logfile)
wrappedDev->SetLogFile(logfile);
wrappedDev->SetLogVersion(initParams.SerialiseVersion);
if(logfile && wrappedDev->GetMainSerialiser()->HasError())
{
SAFE_RELEASE(wrappedDev);
return eReplayCreate_FileIOFailed;
}
RDCLOG("Created device.");
D3D12Replay *replay = wrappedDev->GetReplay();
replay->SetProxy(logfile == NULL);
*driver = (IReplayDriver *)replay;
return eReplayCreate_Success;
}
static DriverRegistration D3D12DriverRegistration(RDC_D3D12, "D3D12", &D3D12_CreateReplayDevice);