Files
renderdoc/renderdoc/driver/d3d11/d3d11_debug.cpp
T

1728 lines
53 KiB
C++

/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2019-2021 Baldur Karlsson
* Copyright (c) 2014 Crytek
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "d3d11_debug.h"
#include "common/shader_cache.h"
#include "data/resource.h"
#include "maths/formatpacking.h"
#include "maths/matrix.h"
#include "d3d11_context.h"
#include "d3d11_manager.h"
#include "d3d11_renderstate.h"
#include "d3d11_replay.h"
#include "d3d11_resources.h"
#include "d3d11_shader_cache.h"
#include "data/hlsl/hlsl_cbuffers.h"
static void InternalRef(ID3D11DeviceChild *child)
{
if(child)
{
// we don't want any of our internal resources to show up as external references but we do
// certainly want to keep them alive.
// To solve this, we add an internal refcount and remove the implicit external refcount.
// Removing the external refcount means the device will also have no refcount so it will still
// be destroyed at the same time regardless of these objects. The internal ref will keep them
// alive even if the user doesn't have any pointers to them and they aren't bound anywhere.
// Effectively you can think of this as the same as if they were bound to some unknown undefined
// pipeline slot
IntAddRef(child);
child->Release();
}
}
D3D11DebugManager::D3D11DebugManager(WrappedID3D11Device *wrapper)
{
if(RenderDoc::Inst().GetCrashHandler())
RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(D3D11DebugManager));
m_pDevice = wrapper;
m_pImmediateContext = wrapper->GetImmediateContext();
m_pDevice->GetShaderCache()->SetCaching(true);
// create things needed both during capture and replay
InitCommonResources();
// now do replay-only initialisation
if(RenderDoc::Inst().IsReplayApp())
InitReplayResources();
m_pDevice->GetShaderCache()->SetCaching(false);
}
D3D11DebugManager::~D3D11DebugManager()
{
ShutdownResources();
while(!m_ShaderItemCache.empty())
{
CacheElem &elem = m_ShaderItemCache.back();
elem.Release();
m_ShaderItemCache.pop_back();
}
if(RenderDoc::Inst().GetCrashHandler())
RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this);
}
//////////////////////////////////////////////////////
// debug/replay functions
ID3D11Buffer *D3D11DebugManager::MakeCBuffer(UINT size)
{
D3D11_BUFFER_DESC bufDesc;
bufDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bufDesc.Usage = D3D11_USAGE_DYNAMIC;
bufDesc.ByteWidth = size;
bufDesc.StructureByteStride = 0;
bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bufDesc.MiscFlags = 0;
ID3D11Buffer *ret = NULL;
HRESULT hr = m_pDevice->CreateBuffer(&bufDesc, NULL, &ret);
if(FAILED(hr))
{
RDCERR("Failed to create CBuffer HRESULT: %s", ToStr(hr).c_str());
return NULL;
}
return ret;
}
void D3D11DebugManager::FillCBuffer(ID3D11Buffer *buf, const void *data, size_t size)
{
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT hr = m_pImmediateContext->GetReal()->Map(UNWRAP(WrappedID3D11Buffer, buf), 0,
D3D11_MAP_WRITE_DISCARD, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Can't fill cbuffer HRESULT: %s", ToStr(hr).c_str());
}
else
{
memcpy(mapped.pData, data, size);
m_pImmediateContext->GetReal()->Unmap(UNWRAP(WrappedID3D11Buffer, buf), 0);
}
}
ID3D11Buffer *D3D11DebugManager::MakeCBuffer(const void *data, size_t size)
{
int idx = publicCBufIdx;
RDCASSERT(size <= PublicCBufferSize, size, PublicCBufferSize);
FillCBuffer(PublicCBuffers[idx], data, RDCMIN(size, PublicCBufferSize));
publicCBufIdx = (publicCBufIdx + 1) % ARRAY_COUNT(PublicCBuffers);
return PublicCBuffers[idx];
}
void D3D11DebugManager::InitCommonResources()
{
D3D11ShaderCache *shaderCache = m_pDevice->GetShaderCache();
D3D11ResourceManager *rm = m_pDevice->GetResourceManager();
rdcstr multisamplehlsl = GetEmbeddedResource(multisample_hlsl);
rdcstr hlsl = GetEmbeddedResource(misc_hlsl);
if(m_pDevice->GetFeatureLevel() >= D3D_FEATURE_LEVEL_11_0)
{
CopyMSToArrayPS =
shaderCache->MakePShader(multisamplehlsl.c_str(), "RENDERDOC_CopyMSToArray", "ps_5_0");
InternalRef(CopyMSToArrayPS);
CopyArrayToMSPS =
shaderCache->MakePShader(multisamplehlsl.c_str(), "RENDERDOC_CopyArrayToMS", "ps_5_0");
InternalRef(CopyArrayToMSPS);
FloatCopyMSToArrayPS =
shaderCache->MakePShader(multisamplehlsl.c_str(), "RENDERDOC_FloatCopyMSToArray", "ps_5_0");
InternalRef(FloatCopyMSToArrayPS);
FloatCopyArrayToMSPS =
shaderCache->MakePShader(multisamplehlsl.c_str(), "RENDERDOC_FloatCopyArrayToMS", "ps_5_0");
InternalRef(FloatCopyArrayToMSPS);
DepthCopyMSToArrayPS =
shaderCache->MakePShader(multisamplehlsl.c_str(), "RENDERDOC_DepthCopyMSToArray", "ps_5_0");
InternalRef(DepthCopyMSToArrayPS);
DepthCopyArrayToMSPS =
shaderCache->MakePShader(multisamplehlsl.c_str(), "RENDERDOC_DepthCopyArrayToMS", "ps_5_0");
InternalRef(DepthCopyArrayToMSPS);
MSArrayCopyVS = shaderCache->MakeVShader(hlsl.c_str(), "RENDERDOC_FullscreenVS", "vs_4_0");
InternalRef(MSArrayCopyVS);
}
else
{
RDCWARN("Device feature level below 11_0, MSAA <-> Array copies will not be supported.");
CopyMSToArrayPS = NULL;
CopyArrayToMSPS = NULL;
FloatCopyMSToArrayPS = NULL;
FloatCopyArrayToMSPS = NULL;
DepthCopyMSToArrayPS = NULL;
DepthCopyArrayToMSPS = NULL;
}
// mark created resources as internal during capture so they aren't included in capture files.
rm->SetInternalResource(CopyMSToArrayPS);
rm->SetInternalResource(CopyArrayToMSPS);
rm->SetInternalResource(FloatCopyMSToArrayPS);
rm->SetInternalResource(FloatCopyArrayToMSPS);
rm->SetInternalResource(DepthCopyMSToArrayPS);
rm->SetInternalResource(DepthCopyArrayToMSPS);
rm->SetInternalResource(MSArrayCopyVS);
for(int i = 0; i < ARRAY_COUNT(PublicCBuffers); i++)
{
PublicCBuffers[i] = MakeCBuffer(PublicCBufferSize);
InternalRef(PublicCBuffers[i]);
rm->SetInternalResource(PublicCBuffers[i]);
}
publicCBufIdx = 0;
}
void D3D11DebugManager::InitReplayResources()
{
D3D11ShaderCache *shaderCache = m_pDevice->GetShaderCache();
HRESULT hr = S_OK;
{
rdcstr hlsl = GetEmbeddedResource(pixelhistory_hlsl);
PixelHistoryUnusedCS =
shaderCache->MakeCShader(hlsl.c_str(), "RENDERDOC_PixelHistoryUnused", "cs_5_0");
PixelHistoryCopyCS =
shaderCache->MakeCShader(hlsl.c_str(), "RENDERDOC_PixelHistoryCopyPixel", "cs_5_0");
}
RDCCOMPILE_ASSERT(eTexType_1D == RESTYPE_TEX1D, "Tex type enum doesn't match shader defines");
RDCCOMPILE_ASSERT(eTexType_2D == RESTYPE_TEX2D, "Tex type enum doesn't match shader defines");
RDCCOMPILE_ASSERT(eTexType_3D == RESTYPE_TEX3D, "Tex type enum doesn't match shader defines");
RDCCOMPILE_ASSERT(eTexType_Depth == RESTYPE_DEPTH, "Tex type enum doesn't match shader defines");
RDCCOMPILE_ASSERT(eTexType_Stencil == RESTYPE_DEPTH_STENCIL,
"Tex type enum doesn't match shader defines");
RDCCOMPILE_ASSERT(eTexType_DepthMS == RESTYPE_DEPTH_MS,
"Tex type enum doesn't match shader defines");
RDCCOMPILE_ASSERT(eTexType_StencilMS == RESTYPE_DEPTH_STENCIL_MS,
"Tex type enum doesn't match shader defines");
RDCCOMPILE_ASSERT(eTexType_2DMS == RESTYPE_TEX2D_MS,
"Tex type enum doesn't match shader defines");
{
D3D11_BUFFER_DESC desc;
desc.StructureByteStride = 0;
desc.ByteWidth = STAGE_BUFFER_BYTE_SIZE;
desc.BindFlags = 0;
desc.MiscFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE_STAGING;
hr = m_pDevice->CreateBuffer(&desc, NULL, &StageBuffer);
if(FAILED(hr))
RDCERR("Failed to create map staging buffer HRESULT: %s", ToStr(hr).c_str());
}
{
D3D11_TEXTURE2D_DESC desc = {};
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_D16_UNORM;
desc.Width = 1;
desc.Height = 1;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
ID3D11Texture2D *dummyTex = NULL;
hr = m_pDevice->CreateTexture2D(&desc, NULL, &dummyTex);
if(FAILED(hr))
{
RDCERR("Failed to create dummy predicate tex HRESULT: %s", ToStr(hr).c_str());
}
else
{
hr = m_pDevice->CreateDepthStencilView(dummyTex, NULL, &PredicateDSV);
if(FAILED(hr))
{
RDCERR("Failed to predicate DSV HRESULT: %s", ToStr(hr).c_str());
}
}
SAFE_RELEASE(dummyTex);
}
{
rdcstr hlsl = GetEmbeddedResource(misc_hlsl);
m_DiscardVS = shaderCache->MakeVShader(hlsl.c_str(), "RENDERDOC_FullscreenVS", "vs_4_0");
m_DiscardPS = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_DiscardPS", "ps_4_0");
ResourceFormat fmt;
fmt.type = ResourceFormatType::Regular;
fmt.compType = CompType::Float;
fmt.compByteWidth = 4;
fmt.compCount = 1;
m_DiscardBytes = GetDiscardPattern(DiscardType::DiscardCall, fmt);
D3D11_DEPTH_STENCIL_DESC desc;
desc.BackFace.StencilFailOp = desc.BackFace.StencilPassOp = desc.BackFace.StencilDepthFailOp =
D3D11_STENCIL_OP_REPLACE;
desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilPassOp =
desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.DepthEnable = TRUE;
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc.StencilReadMask = desc.StencilWriteMask = 0xff;
desc.StencilEnable = TRUE;
hr = m_pDevice->CreateDepthStencilState(&desc, &m_DiscardDepthState);
if(FAILED(hr))
RDCERR("Failed to create m_DiscardDepthState HRESULT: %s", ToStr(hr).c_str());
D3D11_RASTERIZER_DESC rastDesc;
RDCEraseEl(rastDesc);
rastDesc.CullMode = D3D11_CULL_NONE;
rastDesc.FillMode = D3D11_FILL_SOLID;
rastDesc.DepthClipEnable = FALSE;
rastDesc.ScissorEnable = TRUE;
hr = m_pDevice->CreateRasterizerState(&rastDesc, &m_DiscardRasterState);
if(FAILED(hr))
RDCERR("Failed to create m_DiscardRasterState HRESULT: %s", ToStr(hr).c_str());
}
}
void D3D11DebugManager::ShutdownResources()
{
SAFE_RELEASE(StageBuffer);
SAFE_RELEASE(PredicateDSV);
// the objects we added with an internal ref, because they're used during capture, should also be
// released with an internal ref.
SAFE_INTRELEASE(CopyMSToArrayPS);
SAFE_INTRELEASE(CopyArrayToMSPS);
SAFE_INTRELEASE(FloatCopyMSToArrayPS);
SAFE_INTRELEASE(FloatCopyArrayToMSPS);
SAFE_INTRELEASE(DepthCopyMSToArrayPS);
SAFE_INTRELEASE(DepthCopyArrayToMSPS);
SAFE_INTRELEASE(MSArrayCopyVS);
SAFE_RELEASE(PixelHistoryUnusedCS);
SAFE_RELEASE(PixelHistoryCopyCS);
for(auto it = m_DiscardPatterns.begin(); it != m_DiscardPatterns.end(); it++)
if(it->second)
it->second->Release();
SAFE_RELEASE(m_DiscardVS);
SAFE_RELEASE(m_DiscardPS);
SAFE_RELEASE(m_DiscardDepthState);
SAFE_RELEASE(m_DiscardRasterState);
for(int i = 0; i < ARRAY_COUNT(PublicCBuffers); i++)
{
SAFE_INTRELEASE(PublicCBuffers[i]);
}
}
void D3D11DebugManager::FillWithDiscardPattern(DiscardType type, ID3D11Resource *res, UINT slice,
UINT mip, const D3D11_RECT *pRect, UINT NumRects)
{
D3D11MarkerRegion region(StringFormat::Fmt("FillWithDiscardPattern %s slice %u mip %u",
ToStr(GetIDForDeviceChild(res)).c_str(), slice, mip));
D3D11_RECT all = {0, 0, 65536, 65536};
if(NumRects == 0)
{
NumRects = 1;
pRect = &all;
}
if(WrappedID3D11Buffer::IsAlloc(res))
{
D3D11MarkerRegion::Set("Buffer");
WrappedID3D11Buffer *buf = (WrappedID3D11Buffer *)res;
D3D11_BUFFER_DESC desc = {};
buf->GetDesc(&desc);
uint32_t value = 0xD15CAD3D;
for(UINT r = 0; r < NumRects; r++)
{
UINT size = RDCMIN(UINT(pRect[r].right - pRect[r].left), desc.ByteWidth);
if(desc.Usage == D3D11_USAGE_DYNAMIC || desc.Usage == D3D11_USAGE_STAGING)
{
// dynamic buffers can always be mapped
// staging buffers can be read-only, at which point we can't write to them
if(desc.CPUAccessFlags & D3D11_CPU_ACCESS_WRITE)
{
D3D11_MAPPED_SUBRESOURCE mapped = {};
m_pImmediateContext->Map(res, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
byte *dst = (byte *)mapped.pData;
dst += pRect[r].left;
for(size_t i = 0; i < size; i++)
{
memcpy(dst, &value, RDCMIN(sizeof(uint32_t), size - i));
dst += sizeof(uint32_t);
}
m_pImmediateContext->Unmap(res, 0);
}
}
else if(desc.Usage == D3D11_USAGE_DEFAULT)
{
bytebuf pattern;
pattern.resize(AlignUp4(size));
for(size_t i = 0; i < pattern.size(); i += 4)
memcpy(&pattern[i], &value, sizeof(uint32_t));
// default buffers can be updated
D3D11_BOX box = {};
box.bottom = box.back = 1;
box.left = pRect[r].left;
box.right = box.left + size;
m_pImmediateContext->UpdateSubresource(res, 0, &box, pattern.data(), size, size);
}
// IMMUTABLE is the other option, which we can't do anything with
}
}
else
{
DiscardPatternKey key = {};
UINT numMips = 1;
UINT width = 1, height = 1, depth = 1;
// for textures we create a template texture with the same format and properties then do
// repeated copies
if(WrappedID3D11Texture1D::IsAlloc(res))
{
WrappedID3D11Texture1D *tex = (WrappedID3D11Texture1D *)res;
D3D11_TEXTURE1D_DESC desc = {};
tex->GetDesc(&desc);
key.dim = 1;
key.fmt = desc.Format;
numMips = desc.MipLevels;
width = desc.Width;
}
else if(WrappedID3D11Texture2D1::IsAlloc(res))
{
WrappedID3D11Texture2D1 *tex = (WrappedID3D11Texture2D1 *)res;
D3D11_TEXTURE2D_DESC desc = {};
tex->GetDesc(&desc);
key.dim = 2;
key.fmt = desc.Format;
key.samp = desc.SampleDesc;
numMips = desc.MipLevels;
width = desc.Width;
height = desc.Height;
}
else if(WrappedID3D11Texture3D1::IsAlloc(res))
{
WrappedID3D11Texture3D1 *tex = (WrappedID3D11Texture3D1 *)res;
D3D11_TEXTURE3D_DESC desc = {};
tex->GetDesc(&desc);
key.dim = 3;
key.fmt = desc.Format;
numMips = desc.MipLevels;
width = desc.Width;
height = desc.Height;
depth = desc.Depth;
}
UINT subresource = slice * numMips + mip;
if(key.dim == 3)
subresource = mip;
// depth-stencil resources can't be sub-copied, so we need to render to them
if(IsDepthFormat(key.fmt) || key.samp.Count > 1)
{
D3D11MarkerRegion::Set("Depth texture");
D3D11RenderStateTracker tracker(m_pImmediateContext);
m_pImmediateContext->ClearState();
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_pImmediateContext->OMSetDepthStencilState(m_DiscardDepthState, 0);
m_pImmediateContext->VSSetShader(m_DiscardVS, NULL, 0);
m_pImmediateContext->PSSetShader(m_DiscardPS, NULL, 0);
m_pImmediateContext->RSSetState(m_DiscardRasterState);
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
rtvDesc.Format = GetFloatTypedFormat(key.fmt);
D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.Flags = 0;
dsvDesc.Format = GetDepthTypedFormat(key.fmt);
if(key.samp.Count > 1)
{
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
dsvDesc.Texture2DMSArray.ArraySize = 1;
dsvDesc.Texture2DMSArray.FirstArraySlice = slice;
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
rtvDesc.Texture2DMSArray.ArraySize = 1;
rtvDesc.Texture2DMSArray.FirstArraySlice = slice;
}
else if(key.dim == 1)
{
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1DARRAY;
dsvDesc.Texture1DArray.ArraySize = 1;
dsvDesc.Texture1DArray.FirstArraySlice = slice;
dsvDesc.Texture1DArray.MipSlice = mip;
}
else if(key.dim == 2)
{
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
dsvDesc.Texture2DArray.ArraySize = 1;
dsvDesc.Texture2DArray.FirstArraySlice = slice;
dsvDesc.Texture2DArray.MipSlice = mip;
}
ID3D11RenderTargetView *rtv = NULL;
ID3D11DepthStencilView *dsv = NULL;
if(IsDepthFormat(key.fmt))
m_pDevice->CreateDepthStencilView(res, &dsvDesc, &dsv);
else
m_pDevice->CreateRenderTargetView(res, &rtvDesc, &rtv);
m_pImmediateContext->OMSetRenderTargets(1, &rtv, dsv);
ID3D11Buffer *cbuf = MakeCBuffer(m_DiscardBytes.data(), m_DiscardBytes.size());
m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf);
D3D11_VIEWPORT viewport = {0, 0, (float)width, (float)height, 0.0f, 1.0f};
m_pImmediateContext->RSSetViewports(1, &viewport);
for(UINT r = 0; r < NumRects; r++)
{
m_pImmediateContext->RSSetScissorRects(1, pRect + r);
if(dsv)
{
uint32_t pass = 1;
cbuf = MakeCBuffer(&pass, sizeof(pass));
m_pImmediateContext->PSSetConstantBuffers(1, 1, &cbuf);
m_pImmediateContext->Draw(3, 0);
m_pImmediateContext->OMSetDepthStencilState(m_DiscardDepthState, 0xff);
pass = 2;
cbuf = MakeCBuffer(&pass, sizeof(pass));
m_pImmediateContext->PSSetConstantBuffers(1, 1, &cbuf);
m_pImmediateContext->Draw(3, 0);
}
else
{
uint32_t pass = 0;
cbuf = MakeCBuffer(&pass, sizeof(pass));
m_pImmediateContext->PSSetConstantBuffers(1, 1, &cbuf);
m_pImmediateContext->Draw(3, 0);
}
}
SAFE_RELEASE(rtv);
SAFE_RELEASE(dsv);
}
else
{
ID3D11Resource *patternRes = m_DiscardPatterns[key];
if(patternRes == NULL)
{
bytebuf pattern = GetDiscardPattern(type, MakeResourceFormat(key.fmt));
if(key.dim == 1)
{
D3D11_TEXTURE1D_DESC desc;
desc.ArraySize = 1;
desc.Format = key.fmt;
desc.Width = DiscardPatternWidth;
desc.MipLevels = 1;
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.CPUAccessFlags = 0;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA data = {};
data.pSysMem = pattern.data();
data.SysMemSlicePitch = data.SysMemPitch = GetRowPitch(desc.Width, desc.Format, 0);
ID3D11Texture1D *tex = NULL;
HRESULT hr = m_pDevice->CreateTexture1D(&desc, &data, &tex);
if(FAILED(hr))
{
RDCERR("Failed to create discard texture for %s HRESULT: %s", ToStr(key.fmt).c_str(),
ToStr(hr).c_str());
return;
}
m_DiscardPatterns[key] = patternRes = tex;
}
else if(key.dim == 2)
{
D3D11_TEXTURE2D_DESC desc;
desc.ArraySize = 1;
desc.Format = key.fmt;
desc.Width = DiscardPatternWidth;
desc.Height = DiscardPatternHeight;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.CPUAccessFlags = 0;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA data = {};
data.pSysMem = pattern.data();
data.SysMemPitch = GetRowPitch(desc.Width, desc.Format, 0);
data.SysMemSlicePitch = data.SysMemPitch * desc.Height;
ID3D11Texture2D *tex = NULL;
HRESULT hr = m_pDevice->CreateTexture2D(&desc, &data, &tex);
if(FAILED(hr))
{
RDCERR("Failed to create discard texture for %s HRESULT: %s", ToStr(key.fmt).c_str(),
ToStr(hr).c_str());
return;
}
m_DiscardPatterns[key] = patternRes = tex;
}
else
{
D3D11_TEXTURE3D_DESC desc;
desc.Format = key.fmt;
desc.Width = DiscardPatternWidth;
desc.Height = DiscardPatternHeight;
desc.Depth = 1;
desc.MipLevels = 1;
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.CPUAccessFlags = 0;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA data = {};
data.pSysMem = pattern.data();
data.SysMemPitch = GetRowPitch(desc.Width, desc.Format, 0);
data.SysMemSlicePitch = data.SysMemPitch * desc.Height;
ID3D11Texture3D *tex = NULL;
HRESULT hr = m_pDevice->CreateTexture3D(&desc, &data, &tex);
if(FAILED(hr))
{
RDCERR("Failed to create discard texture for %s HRESULT: %s", ToStr(key.fmt).c_str(),
ToStr(hr).c_str());
return;
}
m_DiscardPatterns[key] = patternRes = tex;
}
}
if(!patternRes)
return;
UINT z = 0;
if(key.dim == 3)
z = slice;
for(UINT r = 0; r < NumRects; r++)
{
D3D11_RECT rect = pRect[r];
UINT rectWidth = RDCMIN((UINT)rect.right, RDCMAX(1U, width >> mip));
UINT rectHeight = RDCMIN((UINT)rect.bottom, RDCMAX(1U, height >> mip));
for(UINT y = rect.top; y < rectHeight; y += DiscardPatternHeight)
{
for(UINT x = rect.left; x < rectWidth; x += DiscardPatternWidth)
{
D3D11_BOX box = {
0,
0,
0,
RDCMIN(DiscardPatternWidth, uint32_t(rectWidth - x)),
RDCMIN(DiscardPatternHeight, uint32_t(rectHeight - y)),
1,
};
m_pImmediateContext->CopySubresourceRegion(res, subresource, x, y, z, patternRes, 0,
&box);
}
}
}
}
}
}
void D3D11DebugManager::FillWithDiscardPattern(DiscardType type, ID3D11Resource *res,
UINT subresource, const D3D11_RECT *pRect,
UINT NumRects)
{
if(WrappedID3D11Texture1D::IsAlloc(res))
{
WrappedID3D11Texture1D *tex = (WrappedID3D11Texture1D *)res;
D3D11_TEXTURE1D_DESC desc = {};
tex->GetDesc(&desc);
// subresource uniquely identifies a slice and mip
FillWithDiscardPattern(type, res, subresource / desc.MipLevels, subresource % desc.MipLevels,
pRect, NumRects);
}
else if(WrappedID3D11Texture2D1::IsAlloc(res))
{
WrappedID3D11Texture2D1 *tex = (WrappedID3D11Texture2D1 *)res;
D3D11_TEXTURE2D_DESC desc = {};
tex->GetDesc(&desc);
// subresource uniquely identifies a slice and mip
FillWithDiscardPattern(type, res, subresource / desc.MipLevels, subresource % desc.MipLevels,
pRect, NumRects);
}
else if(WrappedID3D11Texture3D1::IsAlloc(res))
{
WrappedID3D11Texture3D1 *tex = (WrappedID3D11Texture3D1 *)res;
D3D11_TEXTURE3D_DESC desc = {};
tex->GetDesc(&desc);
// fill all slices in this mip
for(UINT z = 0; z < RDCMAX(1U, desc.Depth >> subresource); z++)
FillWithDiscardPattern(type, res, z, subresource, pRect, NumRects);
}
else if(WrappedID3D11Buffer::IsAlloc(res))
{
// buffer
FillWithDiscardPattern(type, res, 0, 0, pRect, NumRects);
}
else
{
RDCERR("Unknown resource type being discarded");
return;
}
}
void D3D11DebugManager::FillWithDiscardPattern(DiscardType type, ID3D11View *view,
const D3D11_RECT *pRect, UINT NumRects)
{
D3D11MarkerRegion region(StringFormat::Fmt("FillWithDiscardPattern view %s",
ToStr(GetIDForDeviceChild(view)).c_str()));
ResourceRange range = ResourceRange::Null;
if(WrappedID3D11ShaderResourceView1::IsAlloc(view))
{
range = ResourceRange((WrappedID3D11ShaderResourceView1 *)view);
}
else if(WrappedID3D11UnorderedAccessView1::IsAlloc(view))
{
range = ResourceRange((WrappedID3D11UnorderedAccessView1 *)view);
}
else if(WrappedID3D11RenderTargetView1::IsAlloc(view))
{
range = ResourceRange((WrappedID3D11RenderTargetView1 *)view);
}
else if(WrappedID3D11DepthStencilView::IsAlloc(view))
{
range = ResourceRange((WrappedID3D11DepthStencilView *)view);
}
else
{
RDCERR("Unknown view type being discarded");
return;
}
ID3D11Resource *res = range.GetResource();
UINT numMips = 1;
bool tex3D = false;
// check for wrapped types first as they will be most common and don't
// require a virtual call
if(WrappedID3D11Texture1D::IsAlloc(res))
{
D3D11_TEXTURE1D_DESC desc = {};
((WrappedID3D11Texture1D *)res)->GetDesc(&desc);
numMips = desc.MipLevels;
}
else if(WrappedID3D11Texture2D1::IsAlloc(res))
{
D3D11_TEXTURE2D_DESC desc = {};
((WrappedID3D11Texture2D1 *)res)->GetDesc(&desc);
numMips = desc.MipLevels;
}
else if(WrappedID3D11Texture3D1::IsAlloc(res))
{
D3D11_TEXTURE3D_DESC desc = {};
((WrappedID3D11Texture3D1 *)res)->GetDesc(&desc);
numMips = desc.MipLevels;
tex3D = true;
}
else if(WrappedID3D11Buffer::IsAlloc(res))
{
// nothing to do, just pass
}
else
{
RDCERR("View of unknown resource type being discarded");
return;
}
rdcarray<D3D11_RECT> rects;
rects.assign(pRect, NumRects);
// DiscardView1 on D3D11 only allows rects to be specified with DSVs and RTVs which should only
// target one mip.
if(NumRects > 0)
RDCASSERTMSG("Rects shouldn't be specified when we have multiple mips",
range.GetMinMip() == range.GetMaxMip(), range.GetMinMip(), range.GetMaxMip(),
NumRects);
for(UINT slice = range.GetMinSlice(); slice <= range.GetMaxSlice(); slice++)
for(UINT mip = range.GetMinMip(); mip <= range.GetMaxMip(); mip++)
FillWithDiscardPattern(type, res, slice, mip, pRect, NumRects);
}
uint32_t D3D11DebugManager::GetStructCount(ID3D11UnorderedAccessView *uav)
{
m_pImmediateContext->CopyStructureCount(StageBuffer, 0, uav);
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT hr = m_pImmediateContext->Map(StageBuffer, 0, D3D11_MAP_READ, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Failed to Map HRESULT: %s", ToStr(hr).c_str());
return ~0U;
}
uint32_t ret = *((uint32_t *)mapped.pData);
m_pImmediateContext->Unmap(StageBuffer, 0);
return ret;
}
void D3D11DebugManager::GetBufferData(ID3D11Buffer *buffer, uint64_t offset, uint64_t length,
bytebuf &ret)
{
D3D11_MAPPED_SUBRESOURCE mapped;
if(buffer == NULL)
return;
RDCASSERT(offset < 0xffffffff);
RDCASSERT(length <= 0xffffffff || length == ~0ULL);
uint32_t offs = (uint32_t)offset;
uint32_t len = (uint32_t)length;
D3D11_BUFFER_DESC desc;
buffer->GetDesc(&desc);
if(offs >= desc.ByteWidth)
{
// can't read past the end of the buffer, return empty
return;
}
if(len == 0 || len > desc.ByteWidth)
{
len = desc.ByteWidth - offs;
}
if(len > 0 && offs + len > desc.ByteWidth)
{
RDCWARN("Attempting to read off the end of the buffer (%llu %llu). Will be clamped (%u)",
offset, length, desc.ByteWidth);
len = RDCMIN(len, desc.ByteWidth - offs);
}
uint32_t outOffs = 0;
ret.resize(len);
D3D11_BOX box;
box.top = 0;
box.bottom = 1;
box.front = 0;
box.back = 1;
while(len > 0)
{
uint32_t chunkSize = RDCMIN(len, STAGE_BUFFER_BYTE_SIZE);
if(desc.StructureByteStride > 0)
chunkSize -= (chunkSize % desc.StructureByteStride);
box.left = RDCMIN(offs + outOffs, desc.ByteWidth);
box.right = RDCMIN(offs + outOffs + chunkSize, desc.ByteWidth);
if(box.right - box.left == 0)
break;
m_pImmediateContext->GetReal()->CopySubresourceRegion(
UNWRAP(WrappedID3D11Buffer, StageBuffer), 0, 0, 0, 0, UNWRAP(WrappedID3D11Buffer, buffer),
0, &box);
HRESULT hr = m_pImmediateContext->GetReal()->Map(UNWRAP(WrappedID3D11Buffer, StageBuffer), 0,
D3D11_MAP_READ, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Failed to map bufferdata buffer HRESULT: %s", ToStr(hr).c_str());
return;
}
else
{
memcpy(&ret[outOffs], mapped.pData, RDCMIN(len, STAGE_BUFFER_BYTE_SIZE));
m_pImmediateContext->GetReal()->Unmap(UNWRAP(WrappedID3D11Buffer, StageBuffer), 0);
}
outOffs += chunkSize;
len -= chunkSize;
}
}
void D3D11DebugManager::RenderForPredicate()
{
// just somehow draw a quad that renders some pixels to fill the predicate with TRUE
m_pImmediateContext->ClearState();
D3D11_VIEWPORT viewport = {0, 0, 1, 1, 0.0f, 1.0f};
m_pImmediateContext->RSSetViewports(1, &viewport);
m_pImmediateContext->VSSetShader(MSArrayCopyVS, NULL, 0);
m_pImmediateContext->PSSetShader(NULL, NULL, 0);
m_pImmediateContext->OMSetRenderTargets(0, NULL, PredicateDSV);
m_pImmediateContext->Draw(3, 0);
}
ResourceId D3D11DebugManager::AddCounterUAVBuffer(ID3D11UnorderedAccessView *uav)
{
ResourceId ret = ResourceIDGen::GetNewUniqueID();
m_CounterBufferToUAV[ret] = uav;
m_UAVToCounterBuffer[uav] = ret;
return ret;
}
void D3D11Replay::GeneralMisc::Init(WrappedID3D11Device *device)
{
D3D11ShaderCache *shaderCache = device->GetShaderCache();
HRESULT hr = S_OK;
D3D11_RASTERIZER_DESC rastDesc;
RDCEraseEl(rastDesc);
rastDesc.CullMode = D3D11_CULL_NONE;
rastDesc.FillMode = D3D11_FILL_SOLID;
rastDesc.DepthBias = 0;
hr = device->CreateRasterizerState(&rastDesc, &RasterState);
if(FAILED(hr))
RDCERR("Failed to create default rasterizer state HRESULT: %s", ToStr(hr).c_str());
rastDesc.ScissorEnable = TRUE;
hr = device->CreateRasterizerState(&rastDesc, &RasterScissorState);
if(FAILED(hr))
RDCERR("Failed to create scissoring rasterizer state HRESULT: %s", ToStr(hr).c_str());
{
rdcstr hlsl = GetEmbeddedResource(misc_hlsl);
FullscreenVS = shaderCache->MakeVShader(hlsl.c_str(), "RENDERDOC_FullscreenVS", "vs_4_0");
FixedColPS = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_FixedColPS", "ps_4_0");
CheckerboardPS = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_CheckerboardPS", "ps_4_0");
}
}
void D3D11Replay::GeneralMisc::Release()
{
SAFE_RELEASE(RasterState);
SAFE_RELEASE(RasterScissorState);
SAFE_RELEASE(FullscreenVS);
SAFE_RELEASE(CheckerboardPS);
SAFE_RELEASE(FixedColPS);
}
void D3D11Replay::TextureRendering::Init(WrappedID3D11Device *device)
{
D3D11ShaderCache *shaderCache = device->GetShaderCache();
HRESULT hr = S_OK;
{
rdcstr hlsl = GetEmbeddedResource(texdisplay_hlsl);
TexDisplayVS = shaderCache->MakeVShader(hlsl.c_str(), "RENDERDOC_TexDisplayVS", "vs_4_0");
TexDisplayPS = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_TexDisplayPS", "ps_5_0");
}
{
rdcstr hlsl = GetEmbeddedResource(texremap_hlsl);
TexRemapPS[0] = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_TexRemapFloat", "ps_5_0");
TexRemapPS[1] = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_TexRemapUInt", "ps_5_0");
TexRemapPS[2] = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_TexRemapSInt", "ps_5_0");
}
{
D3D11_BLEND_DESC blendDesc;
RDCEraseEl(blendDesc);
blendDesc.AlphaToCoverageEnable = FALSE;
blendDesc.IndependentBlendEnable = FALSE;
blendDesc.RenderTarget[0].BlendEnable = TRUE;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
hr = device->CreateBlendState(&blendDesc, &BlendState);
if(FAILED(hr))
{
RDCERR("Failed to create default blendstate HRESULT: %s", ToStr(hr).c_str());
}
}
{
D3D11_SAMPLER_DESC sampDesc;
RDCEraseEl(sampDesc);
sampDesc.AddressU = sampDesc.AddressV = sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
sampDesc.MaxAnisotropy = 1;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = FLT_MAX;
sampDesc.MipLODBias = 0.0f;
hr = device->CreateSamplerState(&sampDesc, &LinearSampState);
if(FAILED(hr))
{
RDCERR("Failed to create linear sampler state HRESULT: %s", ToStr(hr).c_str());
}
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
hr = device->CreateSamplerState(&sampDesc, &PointSampState);
if(FAILED(hr))
{
RDCERR("Failed to create point sampler state HRESULT: %s", ToStr(hr).c_str());
}
}
}
void D3D11Replay::TextureRendering::Release()
{
SAFE_RELEASE(PointSampState);
SAFE_RELEASE(LinearSampState);
SAFE_RELEASE(BlendState);
SAFE_RELEASE(TexDisplayVS);
SAFE_RELEASE(TexDisplayPS);
for(int i = 0; i < 3; i++)
SAFE_RELEASE(TexRemapPS[i]);
}
void D3D11Replay::OverlayRendering::Init(WrappedID3D11Device *device)
{
D3D11ShaderCache *shaderCache = device->GetShaderCache();
{
rdcstr hlsl = GetEmbeddedResource(misc_hlsl);
FullscreenVS = shaderCache->MakeVShader(hlsl.c_str(), "RENDERDOC_FullscreenVS", "vs_4_0");
hlsl = GetEmbeddedResource(quadoverdraw_hlsl);
QuadOverdrawPS = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_QuadOverdrawPS", "ps_5_0");
QOResolvePS = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_QOResolvePS", "ps_5_0");
}
{
rdcstr meshhlsl = GetEmbeddedResource(mesh_hlsl);
TriangleSizeGS =
shaderCache->MakeGShader(meshhlsl.c_str(), "RENDERDOC_TriangleSizeGS", "gs_4_0");
TriangleSizePS =
shaderCache->MakePShader(meshhlsl.c_str(), "RENDERDOC_TriangleSizePS", "ps_4_0");
}
}
void D3D11Replay::OverlayRendering::Release()
{
SAFE_RELEASE(FullscreenVS);
SAFE_RELEASE(QuadOverdrawPS);
SAFE_RELEASE(QOResolvePS);
SAFE_RELEASE(TriangleSizeGS);
SAFE_RELEASE(TriangleSizePS);
SAFE_RELEASE(Texture);
}
void D3D11Replay::MeshRendering::Init(WrappedID3D11Device *device)
{
D3D11ShaderCache *shaderCache = device->GetShaderCache();
HRESULT hr = S_OK;
{
D3D11_DEPTH_STENCIL_DESC desc;
desc.BackFace.StencilFailOp = desc.BackFace.StencilPassOp = desc.BackFace.StencilDepthFailOp =
D3D11_STENCIL_OP_KEEP;
desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilPassOp =
desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.DepthEnable = FALSE;
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
desc.StencilEnable = FALSE;
desc.StencilReadMask = desc.StencilWriteMask = 0xff;
hr = device->CreateDepthStencilState(&desc, &NoDepthState);
if(FAILED(hr))
{
RDCERR("Failed to create no-depth depthstencilstate HRESULT: %s", ToStr(hr).c_str());
}
desc.DepthEnable = TRUE;
desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
hr = device->CreateDepthStencilState(&desc, &LessEqualDepthState);
}
{
D3D11_RASTERIZER_DESC desc;
desc.AntialiasedLineEnable = TRUE;
desc.DepthBias = 0;
desc.DepthBiasClamp = 0.0f;
desc.DepthClipEnable = FALSE;
desc.FrontCounterClockwise = FALSE;
desc.MultisampleEnable = TRUE;
desc.ScissorEnable = FALSE;
desc.SlopeScaledDepthBias = 0.0f;
desc.FillMode = D3D11_FILL_WIREFRAME;
desc.CullMode = D3D11_CULL_NONE;
hr = device->CreateRasterizerState(&desc, &WireframeRasterState);
if(FAILED(hr))
RDCERR("Failed to create m_WireframeHelpersRS HRESULT: %s", ToStr(hr).c_str());
desc.FrontCounterClockwise = FALSE;
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
hr = device->CreateRasterizerState(&desc, &SolidRasterState);
if(FAILED(hr))
RDCERR("Failed to create m_SolidHelpersRS HRESULT: %s", ToStr(hr).c_str());
}
{
D3D11_BLEND_DESC desc;
RDCEraseEl(desc);
desc.AlphaToCoverageEnable = TRUE;
desc.IndependentBlendEnable = FALSE;
desc.RenderTarget[0].BlendEnable = TRUE;
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].RenderTargetWriteMask = 0xf;
hr = device->CreateBlendState(&desc, &WireframeHelpersBS);
if(FAILED(hr))
RDCERR("Failed to create m_WireframeHelpersRS HRESULT: %s", ToStr(hr).c_str());
}
{
// these elements are just for signature matching sake, so we don't need correct offsets/slots
D3D11_INPUT_ELEMENT_DESC inputDescSecondary[2] = {
{"pos", 0, DXGI_FORMAT_R32G32B32A32_FLOAT}, {"sec", 0, DXGI_FORMAT_R8G8B8A8_UNORM},
};
rdcstr meshhlsl = GetEmbeddedResource(mesh_hlsl);
rdcarray<byte> bytecode;
MeshVS = shaderCache->MakeVShader(meshhlsl.c_str(), "RENDERDOC_MeshVS", "vs_4_0", 2,
inputDescSecondary, &GenericLayout, &bytecode);
MeshGS = shaderCache->MakeGShader(meshhlsl.c_str(), "RENDERDOC_MeshGS", "gs_4_0");
MeshPS = shaderCache->MakePShader(meshhlsl.c_str(), "RENDERDOC_MeshPS", "ps_4_0");
MeshVSBytecode = new byte[bytecode.size()];
MeshVSBytelen = (uint32_t)bytecode.size();
memcpy(MeshVSBytecode, &bytecode[0], bytecode.size());
}
{
Vec4f TLN = Vec4f(-1.0f, 1.0f, 0.0f, 1.0f); // TopLeftNear, etc...
Vec4f TRN = Vec4f(1.0f, 1.0f, 0.0f, 1.0f);
Vec4f BLN = Vec4f(-1.0f, -1.0f, 0.0f, 1.0f);
Vec4f BRN = Vec4f(1.0f, -1.0f, 0.0f, 1.0f);
Vec4f TLF = Vec4f(-1.0f, 1.0f, 1.0f, 1.0f);
Vec4f TRF = Vec4f(1.0f, 1.0f, 1.0f, 1.0f);
Vec4f BLF = Vec4f(-1.0f, -1.0f, 1.0f, 1.0f);
Vec4f BRF = Vec4f(1.0f, -1.0f, 1.0f, 1.0f);
// 12 frustum lines => 24 verts
Vec4f axisVB[24] = {
TLN, TRN, TRN, BRN, BRN, BLN, BLN, TLN,
TLN, TLF, TRN, TRF, BLN, BLF, BRN, BRF,
TLF, TRF, TRF, BRF, BRF, BLF, BLF, TLF,
};
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = axisVB;
data.SysMemPitch = data.SysMemSlicePitch = 0;
D3D11_BUFFER_DESC bdesc;
bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bdesc.CPUAccessFlags = 0;
bdesc.ByteWidth = sizeof(axisVB);
bdesc.MiscFlags = 0;
bdesc.Usage = D3D11_USAGE_IMMUTABLE;
hr = device->CreateBuffer(&bdesc, &data, &FrustumHelper);
if(FAILED(hr))
RDCERR("Failed to create m_FrustumHelper HRESULT: %s", ToStr(hr).c_str());
}
{
Vec4f axisVB[6] = {
Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f),
Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec4f(0.0f, 0.0f, 0.0f, 1.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f),
};
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = axisVB;
data.SysMemPitch = data.SysMemSlicePitch = 0;
D3D11_BUFFER_DESC bdesc;
bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bdesc.CPUAccessFlags = 0;
bdesc.ByteWidth = sizeof(axisVB);
bdesc.MiscFlags = 0;
bdesc.Usage = D3D11_USAGE_IMMUTABLE;
hr = device->CreateBuffer(&bdesc, &data, &AxisHelper);
if(FAILED(hr))
RDCERR("Failed to create m_AxisHelper HRESULT: %s", ToStr(hr).c_str());
}
{
D3D11_BUFFER_DESC bdesc;
bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bdesc.ByteWidth = sizeof(Vec4f) * 24;
bdesc.MiscFlags = 0;
bdesc.Usage = D3D11_USAGE_DYNAMIC;
hr = device->CreateBuffer(&bdesc, NULL, &TriHighlightHelper);
if(FAILED(hr))
RDCERR("Failed to create m_TriHighlightHelper HRESULT: %s", ToStr(hr).c_str());
}
}
void D3D11Replay::MeshRendering::Release()
{
SAFE_RELEASE(MeshLayout);
SAFE_RELEASE(GenericLayout);
SAFE_RELEASE(NoDepthState);
SAFE_RELEASE(LessEqualDepthState);
SAFE_RELEASE(MeshVS);
SAFE_RELEASE(MeshGS);
SAFE_RELEASE(MeshPS);
SAFE_DELETE_ARRAY(MeshVSBytecode);
SAFE_RELEASE(WireframeRasterState);
SAFE_RELEASE(WireframeHelpersBS);
SAFE_RELEASE(SolidRasterState);
SAFE_RELEASE(FrustumHelper);
SAFE_RELEASE(AxisHelper);
SAFE_RELEASE(TriHighlightHelper);
}
void D3D11Replay::VertexPicking::Init(WrappedID3D11Device *device)
{
D3D11ShaderCache *shaderCache = device->GetShaderCache();
HRESULT hr = S_OK;
rdcstr meshhlsl = GetEmbeddedResource(mesh_hlsl);
MeshPickCS = shaderCache->MakeCShader(meshhlsl.c_str(), "RENDERDOC_MeshPickCS", "cs_5_0");
D3D11_BUFFER_DESC bDesc;
bDesc.ByteWidth = sizeof(Vec4f) * MaxMeshPicks;
bDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
bDesc.CPUAccessFlags = 0;
bDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
bDesc.StructureByteStride = sizeof(Vec4f);
bDesc.Usage = D3D11_USAGE_DEFAULT;
hr = device->CreateBuffer(&bDesc, NULL, &PickResultBuf);
if(FAILED(hr))
RDCERR("Failed to create mesh pick result buff HRESULT: %s", ToStr(hr).c_str());
D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.NumElements = MaxMeshPicks;
uavDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_APPEND;
hr = device->CreateUnorderedAccessView(PickResultBuf, &uavDesc, &PickResultUAV);
if(FAILED(hr))
RDCERR("Failed to create mesh pick result UAV HRESULT: %s", ToStr(hr).c_str());
// created/sized on demand
PickIBBuf = PickVBBuf = NULL;
PickIBSRV = PickVBSRV = NULL;
PickIBSize = PickVBSize = 0;
}
void D3D11Replay::VertexPicking::Release()
{
SAFE_RELEASE(MeshPickCS);
SAFE_RELEASE(PickIBBuf);
SAFE_RELEASE(PickVBBuf);
SAFE_RELEASE(PickIBSRV);
SAFE_RELEASE(PickVBSRV);
SAFE_RELEASE(PickResultBuf);
SAFE_RELEASE(PickResultUAV);
}
void D3D11Replay::PixelPicking::Init(WrappedID3D11Device *device)
{
HRESULT hr = S_OK;
{
D3D11_TEXTURE2D_DESC desc;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.Width = 100;
desc.Height = 100;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.CPUAccessFlags = 0;
desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
desc.MiscFlags = 0;
hr = device->CreateTexture2D(&desc, NULL, &Texture);
if(FAILED(hr))
{
RDCERR("Failed to create pick tex HRESULT: %s", ToStr(hr).c_str());
}
if(Texture)
{
hr = device->CreateRenderTargetView(Texture, NULL, &RTV);
if(FAILED(hr))
{
RDCERR("Failed to create pick rt HRESULT: %s", ToStr(hr).c_str());
}
}
}
{
D3D11_TEXTURE2D_DESC desc;
RDCEraseEl(desc);
desc.ArraySize = 1;
desc.MipLevels = 1;
desc.Width = 1;
desc.Height = 1;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_STAGING;
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
hr = device->CreateTexture2D(&desc, NULL, &StageTexture);
if(FAILED(hr))
{
RDCERR("Failed to create pick stage tex HRESULT: %s", ToStr(hr).c_str());
}
}
}
void D3D11Replay::PixelPicking::Release()
{
SAFE_RELEASE(Texture);
SAFE_RELEASE(RTV);
SAFE_RELEASE(StageTexture);
}
void D3D11Replay::HistogramMinMax::Init(WrappedID3D11Device *device)
{
D3D11ShaderCache *shaderCache = device->GetShaderCache();
HRESULT hr = S_OK;
const uint32_t maxTexDim = 16384;
const uint32_t blockPixSize = HGRAM_PIXELS_PER_TILE * HGRAM_TILES_PER_BLOCK;
const uint32_t maxBlocksNeeded = (maxTexDim * maxTexDim) / (blockPixSize * blockPixSize);
D3D11_BUFFER_DESC bDesc;
bDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
bDesc.ByteWidth =
2 * 4 * sizeof(float) * HGRAM_TILES_PER_BLOCK * HGRAM_TILES_PER_BLOCK * maxBlocksNeeded;
bDesc.CPUAccessFlags = 0;
bDesc.MiscFlags = 0;
bDesc.StructureByteStride = 0;
bDesc.Usage = D3D11_USAGE_DEFAULT;
hr = device->CreateBuffer(&bDesc, NULL, &TileResultBuff);
if(FAILED(hr))
{
RDCERR("Failed to create tile result buffer HRESULT: %s", ToStr(hr).c_str());
}
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.NumElements = bDesc.ByteWidth / sizeof(Vec4f);
hr = device->CreateShaderResourceView(TileResultBuff, &srvDesc, &TileResultSRV[0]);
if(FAILED(hr))
RDCERR("Failed to create tile result SRV 0 HRESULT: %s", ToStr(hr).c_str());
srvDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
hr = device->CreateShaderResourceView(TileResultBuff, &srvDesc, &TileResultSRV[1]);
if(FAILED(hr))
RDCERR("Failed to create tile result SRV 1 HRESULT: %s", ToStr(hr).c_str());
srvDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT;
hr = device->CreateShaderResourceView(TileResultBuff, &srvDesc, &TileResultSRV[2]);
if(FAILED(hr))
RDCERR("Failed to create tile result SRV 2 HRESULT: %s", ToStr(hr).c_str());
D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.Flags = 0;
uavDesc.Buffer.NumElements = srvDesc.Buffer.NumElements;
hr = device->CreateUnorderedAccessView(TileResultBuff, &uavDesc, &TileResultUAV[0]);
if(FAILED(hr))
RDCERR("Failed to create tile result UAV 0 HRESULT: %s", ToStr(hr).c_str());
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
hr = device->CreateUnorderedAccessView(TileResultBuff, &uavDesc, &TileResultUAV[1]);
if(FAILED(hr))
RDCERR("Failed to create tile result UAV 1 HRESULT: %s", ToStr(hr).c_str());
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT;
hr = device->CreateUnorderedAccessView(TileResultBuff, &uavDesc, &TileResultUAV[2]);
if(FAILED(hr))
RDCERR("Failed to create tile result UAV 2 HRESULT: %s", ToStr(hr).c_str());
uavDesc.Format = DXGI_FORMAT_R32_UINT;
uavDesc.Buffer.NumElements = HGRAM_NUM_BUCKETS;
bDesc.ByteWidth = uavDesc.Buffer.NumElements * sizeof(int);
hr = device->CreateBuffer(&bDesc, NULL, &ResultBuff);
if(FAILED(hr))
RDCERR("Failed to create histogram buff HRESULT: %s", ToStr(hr).c_str());
hr = device->CreateUnorderedAccessView(ResultBuff, &uavDesc, &HistogramUAV);
if(FAILED(hr))
RDCERR("Failed to create histogram UAV HRESULT: %s", ToStr(hr).c_str());
bDesc.BindFlags = 0;
bDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
bDesc.Usage = D3D11_USAGE_STAGING;
hr = device->CreateBuffer(&bDesc, NULL, &ResultStageBuff);
if(FAILED(hr))
RDCERR("Failed to create histogram stage buff HRESULT: %s", ToStr(hr).c_str());
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
uavDesc.Buffer.NumElements = 2;
hr = device->CreateUnorderedAccessView(ResultBuff, &uavDesc, &ResultUAV[0]);
if(FAILED(hr))
RDCERR("Failed to create result UAV 0 HRESULT: %s", ToStr(hr).c_str());
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
hr = device->CreateUnorderedAccessView(ResultBuff, &uavDesc, &ResultUAV[1]);
if(FAILED(hr))
RDCERR("Failed to create result UAV 1 HRESULT: %s", ToStr(hr).c_str());
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT;
hr = device->CreateUnorderedAccessView(ResultBuff, &uavDesc, &ResultUAV[2]);
if(FAILED(hr))
RDCERR("Failed to create result UAV 2 HRESULT: %s", ToStr(hr).c_str());
rdcstr histogramhlsl = GetEmbeddedResource(histogram_hlsl);
for(int t = eTexType_1D; t < eTexType_Max; t++)
{
if(t == eTexType_Unused)
continue;
// float, uint, sint
for(int i = 0; i < 3; i++)
{
rdcstr hlsl = rdcstr("#define SHADER_RESTYPE ") + ToStr(t) + "\n";
hlsl += rdcstr("#define SHADER_BASETYPE ") + ToStr(i) + "\n";
hlsl += histogramhlsl;
TileMinMaxCS[t][i] =
shaderCache->MakeCShader(hlsl.c_str(), "RENDERDOC_TileMinMaxCS", "cs_5_0");
HistogramCS[t][i] = shaderCache->MakeCShader(hlsl.c_str(), "RENDERDOC_HistogramCS", "cs_5_0");
if(t == 1)
ResultMinMaxCS[i] =
shaderCache->MakeCShader(hlsl.c_str(), "RENDERDOC_ResultMinMaxCS", "cs_5_0");
}
}
}
void D3D11Replay::HistogramMinMax::Release()
{
SAFE_RELEASE(TileResultBuff);
SAFE_RELEASE(ResultBuff);
SAFE_RELEASE(ResultStageBuff);
for(int i = 0; i < 3; i++)
{
SAFE_RELEASE(TileResultUAV[i]);
SAFE_RELEASE(ResultUAV[i]);
SAFE_RELEASE(TileResultSRV[i]);
}
for(int i = 0; i < ARRAY_COUNT(TileMinMaxCS); i++)
{
for(int j = 0; j < 3; j++)
{
SAFE_RELEASE(TileMinMaxCS[i][j]);
SAFE_RELEASE(HistogramCS[i][j]);
if(i == 0)
SAFE_RELEASE(ResultMinMaxCS[j]);
}
}
SAFE_RELEASE(HistogramUAV);
}
void D3D11Replay::PixelHistory::Init(WrappedID3D11Device *device)
{
D3D11ShaderCache *shaderCache = device->GetShaderCache();
HRESULT hr = S_OK;
{
D3D11_BLEND_DESC blendDesc = {};
blendDesc.AlphaToCoverageEnable = FALSE;
blendDesc.IndependentBlendEnable = FALSE;
blendDesc.RenderTarget[0].BlendEnable = FALSE;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].RenderTargetWriteMask = 0;
hr = device->CreateBlendState(&blendDesc, &NopBlendState);
}
{
D3D11_DEPTH_STENCIL_DESC desc;
desc.BackFace.StencilFailOp = desc.BackFace.StencilPassOp = desc.BackFace.StencilDepthFailOp =
D3D11_STENCIL_OP_KEEP;
desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilPassOp =
desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.DepthEnable = FALSE;
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
desc.StencilReadMask = desc.StencilWriteMask = 0;
desc.StencilEnable = FALSE;
hr = device->CreateDepthStencilState(&desc, &NopDepthState);
if(FAILED(hr))
{
RDCERR("Failed to create nop depthstencilstate HRESULT: %s", ToStr(hr).c_str());
}
desc.DepthEnable = TRUE;
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc.StencilEnable = TRUE;
desc.StencilReadMask = desc.StencilWriteMask = 0xff;
hr = device->CreateDepthStencilState(&desc, &AllPassDepthState);
if(FAILED(hr))
RDCERR("Failed to create always pass depthstencilstate HRESULT: %s", ToStr(hr).c_str());
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
desc.DepthEnable = FALSE;
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
desc.BackFace.StencilFailOp = desc.BackFace.StencilPassOp = desc.BackFace.StencilDepthFailOp =
D3D11_STENCIL_OP_INCR_SAT;
desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilPassOp =
desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR_SAT;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
hr = device->CreateDepthStencilState(&desc, &AllPassIncrDepthState);
if(FAILED(hr))
{
RDCERR("Failed to create always pass stencil increment depthstencilstate HRESULT: %s",
ToStr(hr).c_str());
}
desc.DepthEnable = TRUE;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc.BackFace.StencilFunc = D3D11_COMPARISON_EQUAL;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL;
hr = device->CreateDepthStencilState(&desc, &StencIncrEqDepthState);
if(FAILED(hr))
{
RDCERR("Failed to create always pass stencil increment depthstencilstate HRESULT: %s",
ToStr(hr).c_str());
}
}
{
rdcstr hlsl = GetEmbeddedResource(pixelhistory_hlsl);
PrimitiveIDPS = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_PrimitiveIDPS", "ps_5_0");
}
}
void D3D11Replay::PixelHistory::Release()
{
SAFE_RELEASE(NopBlendState);
SAFE_RELEASE(NopDepthState);
SAFE_RELEASE(AllPassDepthState);
SAFE_RELEASE(AllPassIncrDepthState);
SAFE_RELEASE(StencIncrEqDepthState);
SAFE_RELEASE(PrimitiveIDPS);
}