Files
renderdoc/renderdoc/driver/d3d11/d3d11_debug.cpp
T
baldurk 89e90f8c36 Replace mip selection with sample idx when viewing Tex2DMS. Refs #79
* Also for float/unorm texture add an additional "resolved" option that
  just does an unweighted average of all samples, which is the behaviour
  from before (assuming that's what ResolveSubresource does).
2014-08-29 01:54:14 +01:00

4785 lines
138 KiB
C++

/******************************************************************************
* The MIT License (MIT)
*
* 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_manager.h"
#include "d3d11_context.h"
#include "d3d11_debug.h"
#include "shaders/dxbc_debug.h"
#include "maths/matrix.h"
#include "maths/camera.h"
#include "data/resource.h"
#include "common/string_utils.h"
#include "driver/d3d11/d3d11_resources.h"
#include "d3d11_renderstate.h"
#include <d3dcompiler.h>
// used for serialising out ms textures - converts typeless to uint typed where possible,
// or float/unorm if necessary. Only typeless formats are converted.
DXGI_FORMAT GetTypedFormatUIntPreferred(DXGI_FORMAT f)
{
switch(f)
{
case DXGI_FORMAT_R32G32B32A32_TYPELESS:
return DXGI_FORMAT_R32G32B32A32_UINT;
case DXGI_FORMAT_R32G32B32_TYPELESS:
return DXGI_FORMAT_R32G32B32_UINT;
case DXGI_FORMAT_R16G16B16A16_TYPELESS:
return DXGI_FORMAT_R16G16B16A16_UINT;
case DXGI_FORMAT_R32G32_TYPELESS:
return DXGI_FORMAT_R32G32_UINT;
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
return DXGI_FORMAT_R10G10B10A2_UINT;
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
return DXGI_FORMAT_R8G8B8A8_UINT;
case DXGI_FORMAT_R16G16_TYPELESS:
return DXGI_FORMAT_R16G16_UINT;
case DXGI_FORMAT_R32_TYPELESS:
return DXGI_FORMAT_R32_UINT;
case DXGI_FORMAT_R8G8_TYPELESS:
return DXGI_FORMAT_R8G8_UINT;
case DXGI_FORMAT_R16_TYPELESS:
return DXGI_FORMAT_R16_UINT;
case DXGI_FORMAT_R8_TYPELESS:
return DXGI_FORMAT_R8_UINT;
case DXGI_FORMAT_BC1_TYPELESS:
return DXGI_FORMAT_BC1_UNORM;
case DXGI_FORMAT_BC2_TYPELESS:
return DXGI_FORMAT_BC2_UNORM;
case DXGI_FORMAT_BC3_TYPELESS:
return DXGI_FORMAT_BC3_UNORM;
case DXGI_FORMAT_BC4_TYPELESS:
return DXGI_FORMAT_BC4_UNORM;
case DXGI_FORMAT_BC5_TYPELESS:
return DXGI_FORMAT_BC5_UNORM;
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
case DXGI_FORMAT_B8G8R8X8_TYPELESS:
return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;
case DXGI_FORMAT_BC6H_TYPELESS:
return DXGI_FORMAT_BC6H_UF16;
case DXGI_FORMAT_BC7_TYPELESS:
return DXGI_FORMAT_BC7_UNORM;
default:
break;
}
return f;
}
D3D11DebugManager::D3D11DebugManager(WrappedID3D11Device *wrapper)
{
if(RenderDoc::Inst().GetCrashHandler())
RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(D3D11DebugManager));
m_pDevice = wrapper->GetReal();
m_pDevice->GetImmediateContext(&m_pImmediateContext);
m_ResourceManager = wrapper->GetResourceManager();
m_OutputWindowID = 1;
m_WrappedDevice = wrapper;
ID3D11DeviceContext *ctx = NULL;
m_WrappedDevice->GetImmediateContext(&ctx);
m_WrappedDevice->InternalRef();
m_WrappedContext = (WrappedID3D11DeviceContext *)ctx;
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.0f);
m_pFactory = NULL;
HRESULT hr = S_OK;
IDXGIDevice *pDXGIDevice;
hr = m_WrappedDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&pDXGIDevice);
if(FAILED(hr))
{
RDCERR("Couldn't get DXGI device from D3D device");
}
else
{
IDXGIAdapter *pDXGIAdapter;
hr = pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&pDXGIAdapter);
if(FAILED(hr))
{
RDCERR("Couldn't get DXGI adapter from DXGI device");
SAFE_RELEASE(pDXGIDevice);
}
else
{
hr = pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&m_pFactory);
SAFE_RELEASE(pDXGIDevice);
SAFE_RELEASE(pDXGIAdapter);
if(FAILED(hr))
{
RDCERR("Couldn't get DXGI factory from DXGI adapter");
}
}
}
wstring shadercache = FileIO::GetAppFolderFilename(L"shaders.cache");
m_ShaderCacheDirty = true;
FILE *f = FileIO::fopen(shadercache.c_str(), L"rb");
if(f)
{
FileIO::fseek64(f, 0, SEEK_END);
uint64_t cachelen = FileIO::ftell64(f);
FileIO::fseek64(f, 0, SEEK_SET);
if(cachelen < 8)
{
RDCERR("Invalid shader cache");
m_ShaderCacheDirty = true;
}
else
{
byte *cache = new byte[(size_t)cachelen];
FileIO::fread(cache, 1, (size_t)cachelen, f);
uint32_t *header = (uint32_t *)cache;
uint32_t version = header[0];
if(version != m_ShaderCacheVersion)
{
RDCDEBUG("Out of date or invalid shader cache version: %d", version);
m_ShaderCacheDirty = true;
}
else
{
uint32_t numentries = header[1];
byte *ptr = cache+sizeof(uint32_t)*2;
int64_t bufsize = (int64_t)cachelen-sizeof(uint32_t)*2;
HMODULE d3dcompiler = GetD3DCompiler();
if(d3dcompiler == NULL)
{
RDCFATAL("Can't get handle to d3dcompiler_??.dll");
}
typedef HRESULT (WINAPI *pD3DCreateBlob)(SIZE_T Size, ID3DBlob** ppBlob);
pD3DCreateBlob blobCreate = (pD3DCreateBlob)GetProcAddress(d3dcompiler, "D3DCreateBlob");
if(blobCreate == NULL)
{
RDCFATAL("Can't get D3DCreateBlob from d3dcompiler_??.dll");
}
m_ShaderCacheDirty = false;
for(uint32_t i=0; i < numentries; i++)
{
if(bufsize < sizeof(uint32_t))
{
RDCERR("Invalid shader cache");
m_ShaderCacheDirty = true;
break;
}
uint32_t hash = *(uint32_t *)ptr; ptr += sizeof(uint32_t); bufsize -= sizeof(uint32_t);
if(bufsize < sizeof(uint32_t))
{
RDCERR("Invalid shader cache");
m_ShaderCacheDirty = true;
break;
}
uint32_t len = *(uint32_t *)ptr; ptr += sizeof(uint32_t); bufsize -= sizeof(uint32_t);
if(bufsize < len)
{
RDCERR("Invalid shader cache");
m_ShaderCacheDirty = true;
break;
}
byte *data = ptr; ptr += len; bufsize -= len;
ID3DBlob *blob = NULL;
HRESULT hr = blobCreate((SIZE_T)len, &blob);
if(FAILED(hr))
{
RDCERR("Couldn't create blob of size %d from shadercache: %08x", len, hr);
m_ShaderCacheDirty = true;
}
memcpy(blob->GetBufferPointer(), data, len);
m_ShaderCache[hash] = blob;
}
if(bufsize != 0)
{
RDCERR("Invalid shader cache");
m_ShaderCacheDirty = true;
}
RDCDEBUG("Successfully loaded %d shaders from shader cache", m_ShaderCache.size());
}
delete[] cache;
}
fclose(f);
}
m_CacheShaders = true;
InitStreamOut();
InitDebugRendering();
InitFontRendering();
m_CacheShaders = false;
RenderDoc::Inst().SetProgress(DebugManagerInit, 1.0f);
}
D3D11DebugManager::~D3D11DebugManager()
{
if(m_ShaderCacheDirty)
{
wstring shadercache = FileIO::GetAppFolderFilename(L"shaders.cache");
FILE *f = FileIO::fopen(shadercache.c_str(), L"wb");
if(f)
{
uint32_t version = m_ShaderCacheVersion;
FileIO::fwrite(&version, 1, sizeof(version), f);
uint32_t numentries = (uint32_t)m_ShaderCache.size();
FileIO::fwrite(&numentries, 1, sizeof(numentries), f);
auto it = m_ShaderCache.begin();
for(uint32_t i=0; i < numentries; i++)
{
uint32_t hash = it->first;
uint32_t len = (uint32_t)it->second->GetBufferSize();
FileIO::fwrite(&hash, 1, sizeof(hash), f);
FileIO::fwrite(&len, 1, sizeof(len), f);
FileIO::fwrite(it->second->GetBufferPointer(), 1, len, f);
it->second->Release();
++it;
}
RDCDEBUG("Successfully wrote %d shaders to shader cache", m_ShaderCache.size());
fclose(f);
}
else
{
RDCERR("Error opening shader cache for write");
}
}
ShutdownFontRendering();
ShutdownStreamOut();
if(m_OverlayResourceId != ResourceId())
SAFE_RELEASE(m_OverlayRenderTex);
SAFE_RELEASE(m_CustomShaderRTV);
if(m_CustomShaderResourceId != ResourceId())
SAFE_RELEASE(m_CustomShaderTex);
SAFE_RELEASE(m_pFactory);
while(!m_ShaderItemCache.empty())
{
CacheElem &elem = m_ShaderItemCache.back();
elem.Release();
m_ShaderItemCache.pop_back();
}
for(auto it=m_PostVSData.begin(); it != m_PostVSData.end(); ++it)
{
SAFE_RELEASE(it->second.vsout.buf);
SAFE_RELEASE(it->second.gsout.buf);
}
m_PostVSData.clear();
SAFE_RELEASE(m_WrappedContext);
m_WrappedDevice->InternalRelease();
SAFE_RELEASE(m_pImmediateContext);
if(RenderDoc::Inst().GetCrashHandler())
RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this);
}
//////////////////////////////////////////////////////
// debug/replay functions
static uint32_t strhash(const char *str, uint32_t seed = 5381)
{
if(str == NULL) return seed;
uint32_t hash = seed;
int c = *str;
str++;
while(c)
{
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
c = *str;
str++;
}
return hash;
}
string D3D11DebugManager::GetShaderBlob(const char *source, const char *entry, const uint32_t compileFlags, const char *profile, ID3DBlob **srcblob)
{
uint32_t hash = strhash(source);
hash = strhash(entry, hash);
hash = strhash(profile, hash);
hash ^= compileFlags;
if(m_ShaderCache.find(hash) != m_ShaderCache.end())
{
*srcblob = m_ShaderCache[hash];
(*srcblob)->AddRef();
return "";
}
HRESULT hr = S_OK;
ID3DBlob *byteBlob = NULL;
ID3DBlob *errBlob = NULL;
HMODULE d3dcompiler = GetD3DCompiler();
if(d3dcompiler == NULL)
{
RDCFATAL("Can't get handle to d3dcompiler_??.dll");
}
pD3DCompile compileFunc = (pD3DCompile)GetProcAddress(d3dcompiler, "D3DCompile");
if(compileFunc == NULL)
{
RDCFATAL("Can't get D3DCompile from d3dcompiler_??.dll");
}
uint32_t flags = compileFlags & ~D3DCOMPILE_NO_PRESHADER;
hr = compileFunc(source, strlen(source), entry, NULL, NULL, entry, profile,
flags, 0, &byteBlob, &errBlob);
string errors = "";
if(errBlob)
{
errors = (char *)errBlob->GetBufferPointer();
string logerror = errors;
if(logerror.length() > 1024)
logerror = logerror.substr(0, 1024) + "...";
RDCWARN("Shader compile error in '%hs':\n%hs", entry, logerror.c_str());
SAFE_RELEASE(errBlob);
if(FAILED(hr))
{
SAFE_RELEASE(byteBlob);
return errors;
}
}
void *bytecode = byteBlob->GetBufferPointer();
size_t bytecodeLen = byteBlob->GetBufferSize();
if(m_CacheShaders)
{
m_ShaderCache[hash] = byteBlob;
byteBlob->AddRef();
m_ShaderCacheDirty = true;
}
SAFE_RELEASE(errBlob);
*srcblob = byteBlob;
return errors;
}
ID3D11VertexShader *D3D11DebugManager::MakeVShader(const char *source, const char *entry, const char *profile,
int numInputDescs, D3D11_INPUT_ELEMENT_DESC *inputs, ID3D11InputLayout **ret,
vector<byte> *blob)
{
ID3DBlob *byteBlob = NULL;
if(GetShaderBlob(source, entry, D3DCOMPILE_WARNINGS_ARE_ERRORS, profile, &byteBlob) != "")
{
RDCERR("Couldn't get shader blob for %hs", entry);
return NULL;
}
void *bytecode = byteBlob->GetBufferPointer();
size_t bytecodeLen = byteBlob->GetBufferSize();
ID3D11VertexShader *ps = NULL;
HRESULT hr = m_pDevice->CreateVertexShader(bytecode, bytecodeLen, NULL, &ps);
if(FAILED(hr))
{
RDCERR("Couldn't create vertex shader for %hs %08x", entry, hr);
SAFE_RELEASE(byteBlob);
return NULL;
}
if(numInputDescs)
{
hr = m_pDevice->CreateInputLayout(inputs, numInputDescs, bytecode, bytecodeLen, ret);
if(FAILED(hr))
{
RDCERR("Couldn't create input layout for %hs %08x", entry, hr);
}
}
if(blob)
{
blob->resize(bytecodeLen);
memcpy(&(*blob)[0], bytecode, bytecodeLen);
}
SAFE_RELEASE(byteBlob);
return ps;
}
ID3D11GeometryShader *D3D11DebugManager::MakeGShader(const char *source, const char *entry, const char *profile)
{
ID3DBlob *byteBlob = NULL;
if(GetShaderBlob(source, entry, D3DCOMPILE_WARNINGS_ARE_ERRORS, profile, &byteBlob) != "")
{
return NULL;
}
void *bytecode = byteBlob->GetBufferPointer();
size_t bytecodeLen = byteBlob->GetBufferSize();
ID3D11GeometryShader *gs = NULL;
HRESULT hr = m_pDevice->CreateGeometryShader(bytecode, bytecodeLen, NULL, &gs);
SAFE_RELEASE(byteBlob);
if(FAILED(hr))
{
RDCERR("Couldn't create geometry shader for %hs %08x", entry, hr);
return NULL;
}
return gs;
}
ID3D11PixelShader *D3D11DebugManager::MakePShader(const char *source, const char *entry, const char *profile)
{
ID3DBlob *byteBlob = NULL;
if(GetShaderBlob(source, entry, D3DCOMPILE_WARNINGS_ARE_ERRORS, profile, &byteBlob) != "")
{
return NULL;
}
void *bytecode = byteBlob->GetBufferPointer();
size_t bytecodeLen = byteBlob->GetBufferSize();
ID3D11PixelShader *ps = NULL;
HRESULT hr = m_pDevice->CreatePixelShader(bytecode, bytecodeLen, NULL, &ps);
SAFE_RELEASE(byteBlob);
if(FAILED(hr))
{
RDCERR("Couldn't create pixel shader for %hs %08x", entry, hr);
return NULL;
}
return ps;
}
ID3D11ComputeShader *D3D11DebugManager::MakeCShader(const char *source, const char *entry, const char *profile)
{
ID3DBlob *byteBlob = NULL;
if(GetShaderBlob(source, entry, D3DCOMPILE_WARNINGS_ARE_ERRORS, profile, &byteBlob) != "")
{
return NULL;
}
void *bytecode = byteBlob->GetBufferPointer();
size_t bytecodeLen = byteBlob->GetBufferSize();
ID3D11ComputeShader *cs = NULL;
HRESULT hr = m_pDevice->CreateComputeShader(bytecode, bytecodeLen, NULL, &cs);
SAFE_RELEASE(byteBlob);
if(FAILED(hr))
{
RDCERR("Couldn't create compute shader for %hs %08x", entry, hr);
return NULL;
}
return cs;
}
void D3D11DebugManager::BuildShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors)
{
if(id == NULL || errors == NULL)
{
if(id) *id = ResourceId();
return;
}
char *profile = NULL;
switch(type)
{
case eShaderStage_Vertex: profile = "vs_5_0"; break;
case eShaderStage_Hull: profile = "hs_5_0"; break;
case eShaderStage_Domain: profile = "ds_5_0"; break;
case eShaderStage_Geometry: profile = "gs_5_0"; break;
case eShaderStage_Pixel: profile = "ps_5_0"; break;
case eShaderStage_Compute: profile = "cs_5_0"; break;
default: RDCERR("Unexpected type in BuildShader!"); *id = ResourceId(); return;
}
ID3DBlob *blob = NULL;
*errors = GetShaderBlob(source.c_str(), entry.c_str(), compileFlags, profile, &blob);
if(blob == NULL)
{
*id = ResourceId();
return;
}
switch(type)
{
case eShaderStage_Vertex:
{
ID3D11VertexShader *sh = NULL;
m_WrappedDevice->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh);
SAFE_RELEASE(blob);
*id = ((WrappedID3D11Shader<ID3D11VertexShader> *)sh)->GetResourceID();
return;
}
case eShaderStage_Hull:
{
ID3D11HullShader *sh = NULL;
m_WrappedDevice->CreateHullShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh);
SAFE_RELEASE(blob);
*id = ((WrappedID3D11Shader<ID3D11HullShader> *)sh)->GetResourceID();
return;
}
case eShaderStage_Domain:
{
ID3D11DomainShader *sh = NULL;
m_WrappedDevice->CreateDomainShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh);
SAFE_RELEASE(blob);
*id = ((WrappedID3D11Shader<ID3D11DomainShader> *)sh)->GetResourceID();
return;
}
case eShaderStage_Geometry:
{
ID3D11GeometryShader *sh = NULL;
m_WrappedDevice->CreateGeometryShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh);
SAFE_RELEASE(blob);
*id = ((WrappedID3D11Shader<ID3D11GeometryShader> *)sh)->GetResourceID();
return;
}
case eShaderStage_Pixel:
{
ID3D11PixelShader *sh = NULL;
m_WrappedDevice->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh);
SAFE_RELEASE(blob);
*id = ((WrappedID3D11Shader<ID3D11PixelShader> *)sh)->GetResourceID();
return;
}
case eShaderStage_Compute:
{
ID3D11ComputeShader *sh = NULL;
m_WrappedDevice->CreateComputeShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &sh);
SAFE_RELEASE(blob);
*id = ((WrappedID3D11Shader<ID3D11ComputeShader> *)sh)->GetResourceID();
return;
}
default:
break;
}
SAFE_RELEASE(blob);
RDCERR("Unexpected type in BuildShader!");
*id = ResourceId();
}
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 %08x", hr);
return NULL;
}
return ret;
}
void D3D11DebugManager::FillCBuffer(ID3D11Buffer *buf, float *data, size_t size)
{
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT hr = m_pImmediateContext->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Can't fill cbuffer %08x", hr);
}
else
{
memcpy(mapped.pData, data, size);
m_pImmediateContext->Unmap(buf, 0);
}
}
ID3D11Buffer *D3D11DebugManager::MakeCBuffer(float *data, size_t size)
{
int idx = m_DebugRender.publicCBufIdx;
FillCBuffer(m_DebugRender.PublicCBuffers[idx], data, size);
m_DebugRender.publicCBufIdx = (m_DebugRender.publicCBufIdx+1)%ARRAY_COUNT(m_DebugRender.PublicCBuffers);
return m_DebugRender.PublicCBuffers[idx];
}
#include "data/hlsl/debugcbuffers.h"
bool D3D11DebugManager::InitDebugRendering()
{
HRESULT hr = S_OK;
m_CustomShaderTex = NULL;
m_CustomShaderRTV = NULL;
m_CustomShaderResourceId = ResourceId();
m_OverlayRenderTex = NULL;
m_OverlayResourceId = ResourceId();
m_DebugRender.GenericVSCBuffer = MakeCBuffer(sizeof(DebugVertexCBuffer));
m_DebugRender.GenericGSCBuffer = MakeCBuffer(sizeof(DebugGeometryCBuffer));
m_DebugRender.GenericPSCBuffer = MakeCBuffer(sizeof(DebugPixelCBufferData));
for(int i=0; i < ARRAY_COUNT(m_DebugRender.PublicCBuffers); i++)
m_DebugRender.PublicCBuffers[i] = MakeCBuffer(sizeof(float)*4 * 100);
m_DebugRender.publicCBufIdx = 0;
string displayhlsl = GetEmbeddedResource(debugcbuffers_h);
displayhlsl += GetEmbeddedResource(debugcommon_hlsl);
displayhlsl += GetEmbeddedResource(debugdisplay_hlsl);
D3D11_INPUT_ELEMENT_DESC inputDesc;
inputDesc.SemanticName = "POSITION";
inputDesc.SemanticIndex = 0;
inputDesc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
inputDesc.InputSlot = 0;
inputDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
inputDesc.AlignedByteOffset = 0;
inputDesc.InstanceDataStepRate = 0;
vector<byte> bytecode;
m_DebugRender.GenericVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_DebugVS", "vs_4_0", 1, &inputDesc, &m_DebugRender.GenericLayout);
m_DebugRender.TexDisplayPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_TexDisplayPS", "ps_5_0");
m_DebugRender.WireframeVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_WireframeVS", "vs_4_0");
m_DebugRender.MeshVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_MeshVS", "vs_4_0", 0, NULL, NULL, &bytecode);
m_DebugRender.MeshGS = MakeGShader(displayhlsl.c_str(), "RENDERDOC_MeshGS", "gs_4_0");
m_DebugRender.MeshPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_MeshPS", "ps_4_0");
m_DebugRender.MeshVSBytecode = new byte[bytecode.size()];
m_DebugRender.MeshVSBytelen = (uint32_t)bytecode.size();
memcpy(m_DebugRender.MeshVSBytecode, &bytecode[0], bytecode.size());
inputDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
m_DebugRender.WireframeHomogVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_WireframeHomogVS", "vs_4_0", 1, &inputDesc, &m_DebugRender.GenericHomogLayout);
m_DebugRender.WireframePS = MakePShader(displayhlsl.c_str(), "RENDERDOC_WireframePS", "ps_4_0");
m_DebugRender.FullscreenVS = MakeVShader(displayhlsl.c_str(), "RENDERDOC_FullscreenVS", "vs_4_0");
m_DebugRender.OverlayPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_OverlayPS", "ps_4_0");
m_DebugRender.CheckerboardPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_CheckerboardPS", "ps_4_0");
m_DebugRender.QuadOverdrawPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_QuadOverdrawPS", "ps_5_0");
m_DebugRender.QOResolvePS = MakePShader(displayhlsl.c_str(), "RENDERDOC_QOResolvePS", "ps_5_0");
m_DebugRender.PixelHistoryUnusedCS = MakeCShader(displayhlsl.c_str(), "RENDERDOC_PixelHistoryUnused", "cs_5_0");
m_DebugRender.PixelHistoryDepthCopyCS = MakeCShader(displayhlsl.c_str(), "RENDERDOC_PixelHistoryCopyDepthStencil", "cs_5_0");
m_DebugRender.PrimitiveIDPS = MakePShader(displayhlsl.c_str(), "RENDERDOC_PrimitiveIDPS", "ps_5_0");
string multisamplehlsl = GetEmbeddedResource(multisample_hlsl);
m_DebugRender.CopyMSToArrayPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_CopyMSToArray", "ps_5_0");
m_DebugRender.CopyArrayToMSPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_CopyArrayToMS", "ps_5_0");
m_DebugRender.FloatCopyMSToArrayPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_FloatCopyMSToArray", "ps_5_0");
m_DebugRender.FloatCopyArrayToMSPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_FloatCopyArrayToMS", "ps_5_0");
m_DebugRender.DepthCopyMSToArrayPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_DepthCopyMSToArray", "ps_5_0");
m_DebugRender.DepthCopyArrayToMSPS = MakePShader(multisamplehlsl.c_str(), "RENDERDOC_DepthCopyArrayToMS", "ps_5_0");
string histogramhlsl = GetEmbeddedResource(debugcbuffers_h);
histogramhlsl += GetEmbeddedResource(debugcommon_hlsl);
histogramhlsl += GetEmbeddedResource(histogram_hlsl);
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.1f);
if(RenderDoc::Inst().IsReplayApp())
{
for(int t=eTexType_1D; t < eTexType_Max; t++)
{
// float, uint, sint
for(int i=0; i < 3; i++)
{
string hlsl = string("#define SHADER_RESTYPE ") + ToStr::Get(t) + "\n";
hlsl += string("#define UINT_TEX ") + (i == 1 ? "1" : "0") + "\n";
hlsl += string("#define SINT_TEX ") + (i == 2 ? "1" : "0") + "\n";
hlsl += histogramhlsl;
m_DebugRender.TileMinMaxCS[t][i] = MakeCShader(hlsl.c_str(), "RENDERDOC_TileMinMaxCS", "cs_5_0");
m_DebugRender.HistogramCS[t][i] = MakeCShader(hlsl.c_str(), "RENDERDOC_HistogramCS", "cs_5_0");
if(t == 1)
m_DebugRender.ResultMinMaxCS[i] = MakeCShader(hlsl.c_str(), "RENDERDOC_ResultMinMaxCS", "cs_5_0");
RenderDoc::Inst().SetProgress(DebugManagerInit, (float(i + 3.0f*t)/float(2.0f + 3.0f*(eTexType_Max-1)))*0.7f+0.1f);
}
}
}
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.8f);
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_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 = m_pDevice->CreateBlendState(&blendDesc, &m_DebugRender.BlendState);
if(FAILED(hr))
{
RDCERR("Failed to create default blendstate %08x", hr);
}
blendDesc.RenderTarget[0].BlendEnable = FALSE;
blendDesc.RenderTarget[0].RenderTargetWriteMask = 0;
hr = m_pDevice->CreateBlendState(&blendDesc, &m_DebugRender.NopBlendState);
if(FAILED(hr))
{
RDCERR("Failed to create nop blendstate %08x", hr);
}
D3D11_RASTERIZER_DESC rastDesc;
RDCEraseEl(rastDesc);
rastDesc.CullMode = D3D11_CULL_NONE;
rastDesc.FillMode = D3D11_FILL_SOLID;
rastDesc.DepthBias = 0;
hr = m_pDevice->CreateRasterizerState(&rastDesc, &m_DebugRender.RastState);
if(FAILED(hr))
{
RDCERR("Failed to create default rasterizer state %08x", hr);
}
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 = m_pDevice->CreateSamplerState(&sampDesc, &m_DebugRender.LinearSampState);
if(FAILED(hr))
{
RDCERR("Failed to create linear sampler state %08x", hr);
}
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
hr = m_pDevice->CreateSamplerState(&sampDesc, &m_DebugRender.PointSampState);
if(FAILED(hr))
{
RDCERR("Failed to create point sampler state %08x", hr);
}
{
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 = m_pDevice->CreateDepthStencilState(&desc, &m_DebugRender.NoDepthState);
if(FAILED(hr))
{
RDCERR("Failed to create no-depth depthstencilstate %08x", hr);
}
desc.DepthEnable = TRUE;
desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
hr = m_pDevice->CreateDepthStencilState(&desc, &m_DebugRender.LEqualDepthState);
if(FAILED(hr))
{
RDCERR("Failed to create less-equal depthstencilstate %08x", hr);
}
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
desc.StencilEnable = TRUE;
hr = m_pDevice->CreateDepthStencilState(&desc, &m_DebugRender.AllPassDepthState);
if(FAILED(hr))
{
RDCERR("Failed to create always pass depthstencilstate %08x", hr);
}
desc.DepthEnable = FALSE;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
desc.StencilReadMask = desc.StencilWriteMask = 0;
desc.StencilEnable = FALSE;
hr = m_pDevice->CreateDepthStencilState(&desc, &m_DebugRender.NopDepthState);
if(FAILED(hr))
{
RDCERR("Failed to create nop depthstencilstate %08x", hr);
}
desc.StencilReadMask = desc.StencilWriteMask = 0xff;
desc.StencilEnable = TRUE;
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 = m_pDevice->CreateDepthStencilState(&desc, &m_DebugRender.AllPassIncrDepthState);
if(FAILED(hr))
{
RDCERR("Failed to create always pass stencil increment depthstencilstate %08x", hr);
}
desc.DepthEnable = TRUE;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc.BackFace.StencilFunc = D3D11_COMPARISON_EQUAL;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL;
hr = m_pDevice->CreateDepthStencilState(&desc, &m_DebugRender.StencIncrEqDepthState);
if(FAILED(hr))
{
RDCERR("Failed to create always pass stencil increment depthstencilstate %08x", hr);
}
}
{
D3D11_SUBRESOURCE_DATA initialPos;
float *buf = new float[(2 + FONT_MAX_CHARS*4) *3];
// tri strip with degenerates to split characters:
//
// 0--24--68--..
// | /|| /|| /
// |/ ||/ ||/
// 1--35--79--..
buf[0] = 0.0f;
buf[1] = 0.0f;
buf[2] = 0.0f;
buf[3] = 0.0f;
buf[4] = -1.0f;
buf[5] = 0.0f;
for(int i=1; i <= FONT_MAX_CHARS; i++)
{
buf[i*12 - 6 + 0] = 1.0f;
buf[i*12 - 6 + 1] = 0.0f;
buf[i*12 - 6 + 2] = float(i-1);
buf[i*12 - 6 + 3] = 1.0f;
buf[i*12 - 6 + 4] = -1.0f;
buf[i*12 - 6 + 5] = float(i-1);
buf[i*12 + 0 + 0] = 0.0f;
buf[i*12 + 0 + 1] = 0.0f;
buf[i*12 + 0 + 2] = float(i);
buf[i*12 + 0 + 3] = 0.0f;
buf[i*12 + 0 + 4] = -1.0f;
buf[i*12 + 0 + 5] = float(i);
}
initialPos.pSysMem = buf;
initialPos.SysMemPitch = initialPos.SysMemSlicePitch = 0;
D3D11_BUFFER_DESC bufDesc;
bufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufDesc.Usage = D3D11_USAGE_DEFAULT;
bufDesc.ByteWidth = (2 + FONT_MAX_CHARS*4) *3*sizeof(float);
bufDesc.CPUAccessFlags = 0;
bufDesc.MiscFlags = 0;
hr = m_pDevice->CreateBuffer(&bufDesc, &initialPos, &m_DebugRender.PosBuffer);
if(FAILED(hr))
{
RDCERR("Failed to create font pos buffer %08x", hr);
}
delete[] buf;
}
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.9f);
{
float data[] = {
0.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f,
};
D3D11_SUBRESOURCE_DATA initialPos;
initialPos.pSysMem = data;
initialPos.SysMemPitch = initialPos.SysMemSlicePitch = 0;
D3D11_BUFFER_DESC bufDesc;
bufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufDesc.Usage = D3D11_USAGE_IMMUTABLE;
bufDesc.ByteWidth = sizeof(data);
bufDesc.CPUAccessFlags = 0;
bufDesc.MiscFlags = 0;
hr = m_pDevice->CreateBuffer(&bufDesc, &initialPos, &m_DebugRender.OutlineStripVB);
if(FAILED(hr))
{
RDCERR("Failed to create outline strip buffer %08x", hr);
}
}
{
D3D11_TEXTURE2D_DESC desc;
ID3D11Texture2D *pickTex = NULL;
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 = m_pDevice->CreateTexture2D(&desc, NULL, &pickTex);
if(FAILED(hr))
{
RDCERR("Failed to create pick tex %08x", hr);
}
else
{
hr = m_pDevice->CreateRenderTargetView(pickTex, NULL, &m_DebugRender.PickPixelRT);
if(FAILED(hr))
{
RDCERR("Failed to create pick rt %08x", hr);
}
SAFE_RELEASE(pickTex);
}
}
{
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 = m_pDevice->CreateTexture2D(&desc, NULL, &m_DebugRender.PickPixelStageTex);
if(FAILED(hr))
{
RDCERR("Failed to create pick stage tex %08x", hr);
}
}
{
D3D11_BUFFER_DESC bDesc;
const uint32_t maxTexDim = 16384;
const uint32_t blockPixSize = HGRAM_TILES_PER_BLOCK*HGRAM_PIXELS_PER_TILE;
const uint32_t maxBlocksNeeded = (maxTexDim*maxTexDim)/(blockPixSize*blockPixSize);
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 = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.tileResultBuff);
if(FAILED(hr))
{
RDCERR("Failed to create tile result buffer %08x", hr);
}
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
srvDesc.Buffer.ElementOffset = 0;
srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.ElementWidth = 4*sizeof(float);
srvDesc.Buffer.NumElements = bDesc.ByteWidth/srvDesc.Buffer.ElementWidth;
hr = m_pDevice->CreateShaderResourceView(m_DebugRender.tileResultBuff, &srvDesc, &m_DebugRender.tileResultSRV[0]);
if(FAILED(hr))
RDCERR("Failed to create tile result SRV 0 %08x", hr);
srvDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
hr = m_pDevice->CreateShaderResourceView(m_DebugRender.tileResultBuff, &srvDesc, &m_DebugRender.tileResultSRV[1]);
if(FAILED(hr))
RDCERR("Failed to create tile result SRV 1 %08x", hr);
srvDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT;
hr = m_pDevice->CreateShaderResourceView(m_DebugRender.tileResultBuff, &srvDesc, &m_DebugRender.tileResultSRV[2]);
if(FAILED(hr))
RDCERR("Failed to create tile result SRV 2 %08x", hr);
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 = m_pDevice->CreateUnorderedAccessView(m_DebugRender.tileResultBuff, &uavDesc, &m_DebugRender.tileResultUAV[0]);
if(FAILED(hr))
RDCERR("Failed to create tile result UAV 0 %08x", hr);
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.tileResultBuff, &uavDesc, &m_DebugRender.tileResultUAV[1]);
if(FAILED(hr))
RDCERR("Failed to create tile result UAV 1 %08x", hr);
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT;
hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.tileResultBuff, &uavDesc, &m_DebugRender.tileResultUAV[2]);
if(FAILED(hr))
RDCERR("Failed to create tile result UAV 2 %08x", hr);
uavDesc.Format = DXGI_FORMAT_R32_UINT;
uavDesc.Buffer.NumElements = HGRAM_NUM_BUCKETS;
bDesc.ByteWidth = uavDesc.Buffer.NumElements*sizeof(int);
hr = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.histogramBuff);
if(FAILED(hr))
RDCERR("Failed to create histogram buff %08x", hr);
hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.histogramBuff, &uavDesc, &m_DebugRender.histogramUAV);
if(FAILED(hr))
RDCERR("Failed to create histogram UAV %08x", hr);
bDesc.BindFlags = 0;
bDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
bDesc.Usage = D3D11_USAGE_STAGING;
hr = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.histogramStageBuff);
if(FAILED(hr))
RDCERR("Failed to create histogram stage buff %08x", hr);
bDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
bDesc.CPUAccessFlags = 0;
bDesc.ByteWidth = 2*4*sizeof(float);
bDesc.Usage = D3D11_USAGE_DEFAULT;
hr = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.resultBuff);
if(FAILED(hr))
RDCERR("Failed to create result buff %08x", hr);
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
uavDesc.Buffer.NumElements = 2;
hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.resultBuff, &uavDesc, &m_DebugRender.resultUAV[0]);
if(FAILED(hr))
RDCERR("Failed to create result UAV 0 %08x", hr);
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.resultBuff, &uavDesc, &m_DebugRender.resultUAV[1]);
if(FAILED(hr))
RDCERR("Failed to create result UAV 1 %08x", hr);
uavDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT;
hr = m_pDevice->CreateUnorderedAccessView(m_DebugRender.resultBuff, &uavDesc, &m_DebugRender.resultUAV[2]);
if(FAILED(hr))
RDCERR("Failed to create result UAV 2 %08x", hr);
bDesc.BindFlags = 0;
bDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
bDesc.Usage = D3D11_USAGE_STAGING;
hr = m_pDevice->CreateBuffer(&bDesc, NULL, &m_DebugRender.resultStageBuff);
if(FAILED(hr))
RDCERR("Failed to create result stage buff %08x", hr);
}
{
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, &m_DebugRender.StageBuffer);
if(FAILED(hr))
RDCERR("Failed to create map staging buffer %08x", hr);
}
return true;
}
void D3D11DebugManager::ShutdownFontRendering()
{
}
void D3D11DebugManager::ShutdownStreamOut()
{
SAFE_RELEASE(m_SOBuffer);
SAFE_RELEASE(m_SOStatsQuery);
SAFE_RELEASE(m_SOStagingBuffer);
SAFE_RELEASE(m_WireframeHelpersRS);
SAFE_RELEASE(m_WireframeHelpersBS);
SAFE_RELEASE(m_SolidHelpersRS);
SAFE_RELEASE(m_MeshDisplayLayout);
SAFE_RELEASE(m_FrustumHelper);
SAFE_RELEASE(m_AxisHelper);
SAFE_RELEASE(m_TriHighlightHelper);
}
bool D3D11DebugManager::InitStreamOut()
{
m_MeshDisplayLayout = NULL;
m_MeshDisplayNULLVB = 0;
m_PrevMeshInputLayout = NULL;
D3D11_BUFFER_DESC bufferDesc =
{
m_SOBufferSize,
D3D11_USAGE_DEFAULT,
D3D11_BIND_STREAM_OUTPUT,
0,
0,
0
};
HRESULT hr = S_OK;
hr = m_pDevice->CreateBuffer( &bufferDesc, NULL, &m_SOBuffer );
if(FAILED(hr)) RDCERR("Failed to create m_SOBuffer %08x", hr);
bufferDesc.Usage = D3D11_USAGE_STAGING;
bufferDesc.BindFlags = 0;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
hr = m_pDevice->CreateBuffer( &bufferDesc, NULL, &m_SOStagingBuffer );
if(FAILED(hr)) RDCERR("Failed to create m_SOStagingBuffer %08x", hr);
D3D11_QUERY_DESC qdesc;
qdesc.MiscFlags = 0;
qdesc.Query = D3D11_QUERY_SO_STATISTICS;
hr = m_pDevice->CreateQuery(&qdesc, &m_SOStatsQuery);
if(FAILED(hr)) RDCERR("Failed to create m_SOStatsQuery %08x", hr);
D3D11_RASTERIZER_DESC desc;
{
desc.AntialiasedLineEnable = TRUE;
desc.DepthBias = 0;
desc.DepthBiasClamp = 0.0f;
desc.DepthClipEnable = FALSE;
desc.FrontCounterClockwise = FALSE;
desc.MultisampleEnable = FALSE;
desc.ScissorEnable = FALSE;
desc.SlopeScaledDepthBias = 0.0f;
desc.FillMode = D3D11_FILL_WIREFRAME;
desc.CullMode = D3D11_CULL_NONE;
hr = m_pDevice->CreateRasterizerState(&desc, &m_WireframeHelpersRS);
if(FAILED(hr)) RDCERR("Failed to create m_WireframeHelpersRS %08x", hr);
desc.FrontCounterClockwise = TRUE;
desc.CullMode = D3D11_CULL_FRONT;
hr = m_pDevice->CreateRasterizerState(&desc, &m_WireframeHelpersCullCCWRS);
if(FAILED(hr)) RDCERR("Failed to create m_WireframeHelpersCullCCWRS %08x", hr);
desc.FrontCounterClockwise = FALSE;
desc.CullMode = D3D11_CULL_FRONT;
hr = m_pDevice->CreateRasterizerState(&desc, &m_WireframeHelpersCullCWRS);
if(FAILED(hr)) RDCERR("Failed to create m_WireframeHelpersCullCCWRS %08x", hr);
}
{
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 = m_pDevice->CreateBlendState(&desc, &m_WireframeHelpersBS);
if(FAILED(hr)) RDCERR("Failed to create m_WireframeHelpersRS %08x", hr);
}
{
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
hr = m_pDevice->CreateRasterizerState(&desc, &m_SolidHelpersRS);
if(FAILED(hr)) RDCERR("Failed to create m_SolidHelpersRS %08x", hr);
}
{
Vec3f axisVB[6] =
{
Vec3f(0.0f, 0.0f, 0.0f),
Vec3f(1.0f, 0.0f, 0.0f),
Vec3f(0.0f, 0.0f, 0.0f),
Vec3f(0.0f, 1.0f, 0.0f),
Vec3f(0.0f, 0.0f, 0.0f),
Vec3f(0.0f, 0.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 = m_pDevice->CreateBuffer(&bdesc, &data, &m_AxisHelper);
if(FAILED(hr)) RDCERR("Failed to create m_AxisHelper %08x", hr);
}
{
Vec3f TLN = Vec3f(-1.0f, 1.0f, 0.0f); // TopLeftNear, etc...
Vec3f TRN = Vec3f( 1.0f, 1.0f, 0.0f);
Vec3f BLN = Vec3f(-1.0f, -1.0f, 0.0f);
Vec3f BRN = Vec3f( 1.0f, -1.0f, 0.0f);
Vec3f TLF = Vec3f(-1.0f, 1.0f, 1.0f);
Vec3f TRF = Vec3f( 1.0f, 1.0f, 1.0f);
Vec3f BLF = Vec3f(-1.0f, -1.0f, 1.0f);
Vec3f BRF = Vec3f( 1.0f, -1.0f, 1.0f);
// 12 frustum lines => 24 verts
Vec3f 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 = m_pDevice->CreateBuffer(&bdesc, &data, &m_FrustumHelper);
if(FAILED(hr))
RDCERR("Failed to create m_FrustumHelper %08x", hr);
}
{
D3D11_BUFFER_DESC bdesc;
bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bdesc.ByteWidth = sizeof(Vec4f)*4;
bdesc.MiscFlags = 0;
bdesc.Usage = D3D11_USAGE_DYNAMIC;
hr = m_pDevice->CreateBuffer(&bdesc, NULL, &m_TriHighlightHelper);
if(FAILED(hr))
RDCERR("Failed to create m_TriHighlightHelper %08x", hr);
}
return true;
}
bool D3D11DebugManager::InitFontRendering()
{
D3D11_TEXTURE2D_DESC desc;
RDCEraseEl(desc);
int width = FONT_TEX_WIDTH, height = FONT_TEX_HEIGHT;
desc.ArraySize = 1;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.Width = width;
desc.Height = height;
{
int h=height>>1;
desc.MipLevels = 1;
while(h >= 8)
{
desc.MipLevels++;
h >>= 1;
}
}
desc.MiscFlags = 0;
desc.SampleDesc.Quality = 0;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
D3D11_SUBRESOURCE_DATA *initialData = new D3D11_SUBRESOURCE_DATA[desc.MipLevels];
/////////////////////////////////////////////////////////////////////
BITMAPINFOHEADER bih;
RDCEraseEl(bih);
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = width;
bih.biHeight = height;
bih.biPlanes = 1;
bih.biBitCount = 32;
bih.biCompression = BI_RGB;
byte **buffers = new byte *[desc.MipLevels];
HDC pDC = GetDC(NULL);
HDC MemDC = CreateCompatibleDC(pDC);
SetBkColor(MemDC, RGB(0, 0, 0));
SetTextColor(MemDC, RGB(255, 255, 255));
HBITMAP *bmps = new HBITMAP[desc.MipLevels];
for(UINT i=0; i < desc.MipLevels; i++)
{
int w = width>>i;
int h = height>>i;
bih.biWidth = w;
bih.biHeight = h;
HFONT font = CreateFont(h,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, FIXED_PITCH,TEXT("Consolas"));
bmps[i] = CreateCompatibleBitmap(pDC, w, h);
SelectObject(MemDC, bmps[i]);
SelectObject(MemDC, font);
char str[2] = {0, 0};
for(int s=0; s < 127-' '-1; s++)
{
str[0] = (char)(' '+s+1);
TextOutA(MemDC, int(s*h*0.75), -1, str, 1);
}
byte *buf = buffers[i] = new byte[w*h*4];
GetDIBits(MemDC, bmps[i], 0, h, buf, (BITMAPINFO *)&bih, DIB_RGB_COLORS);
DeleteObject(font);
// flip it right side up
byte *tmpRow = new byte[w*4];
for(int j=0; j < h/2; j++)
{
int x = h-j-1;
memcpy(tmpRow, &buf[j*w*4], w*4);
memcpy(&buf[j*w*4], &buf[x*w*4], w*4);
memcpy(&buf[x*w*4], tmpRow, w*4);
}
delete[] tmpRow;
/////////////////////////////////////////////////////////////////////
initialData[i].pSysMem = buffers[i];
initialData[i].SysMemPitch = w*4;
initialData[i].SysMemSlicePitch = w*h*4;
}
ID3D11Texture2D *debugTex;
HRESULT hr = S_OK;
hr = m_pDevice->CreateTexture2D(&desc, initialData, &debugTex);
if(FAILED(hr))
RDCERR("Failed to create debugTex %08x", hr);
delete[] initialData;
hr = m_pDevice->CreateShaderResourceView(debugTex, NULL, &m_Font.Tex);
if(FAILED(hr))
RDCERR("Failed to create m_Font.Tex %08x", hr);
SAFE_RELEASE(debugTex);
for(UINT i=0; i < desc.MipLevels; i++)
{
SAFE_DELETE_ARRAY(buffers[i]);
DeleteObject(bmps[i]);
}
SAFE_DELETE_ARRAY(buffers);
SAFE_DELETE_ARRAY(bmps);
DeleteDC(pDC);
DeleteDC(MemDC);
{
HRESULT hr = S_OK;
m_Font.CBuffer = MakeCBuffer(sizeof(FontCBuffer));
D3D11_BUFFER_DESC bufDesc;
bufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufDesc.MiscFlags = 0;
bufDesc.Usage = D3D11_USAGE_DYNAMIC;
bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bufDesc.ByteWidth = 2+FONT_MAX_CHARS*4*4;
hr = m_pDevice->CreateBuffer(&bufDesc, NULL, &m_Font.CharBuffer);
if(FAILED(hr))
RDCERR("Failed to create m_Font.CharBuffer %08x", hr);
string fullhlsl = "";
{
string textShaderHLSL = GetEmbeddedResource(debugtext_hlsl);
string debugShaderCBuf = GetEmbeddedResource(debugcbuffers_h);
fullhlsl = debugShaderCBuf + textShaderHLSL;
}
D3D11_INPUT_ELEMENT_DESC inputDescs[2];
inputDescs[0].SemanticName = "POSITION";
inputDescs[0].SemanticIndex = 0;
inputDescs[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
inputDescs[0].InputSlot = 0;
inputDescs[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
inputDescs[0].AlignedByteOffset = 0;
inputDescs[0].InstanceDataStepRate = 0;
inputDescs[1].SemanticName = "TEXCOORD";
inputDescs[1].SemanticIndex = 0;
inputDescs[1].Format = DXGI_FORMAT_R32_UINT;
inputDescs[1].InputSlot = 1;
inputDescs[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
inputDescs[1].AlignedByteOffset = 0;
inputDescs[1].InstanceDataStepRate = 0;
m_Font.VS = MakeVShader(fullhlsl.c_str(), "RENDERDOC_TextVS", "vs_4_0", 2, inputDescs, &m_Font.Layout);
m_Font.PS = MakePShader(fullhlsl.c_str(), "RENDERDOC_TextPS", "ps_4_0");
}
return true;
}
void D3D11DebugManager::OutputWindow::MakeRTV()
{
ID3D11Texture2D *texture = NULL;
HRESULT hr = swap->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&texture);
if(FAILED(hr))
{
RDCERR("Failed to get swap chain buffer, HRESULT: 0x%08x", hr);
SAFE_RELEASE(texture);
return;
}
hr = dev->CreateRenderTargetView(texture, NULL, &rtv);
SAFE_RELEASE(texture);
if(FAILED(hr))
{
RDCERR("Failed to create RTV for swap chain buffer, HRESULT: 0x%08x", hr);
SAFE_RELEASE(swap);
return;
}
}
void D3D11DebugManager::OutputWindow::MakeDSV()
{
ID3D11Texture2D *texture = NULL;
HRESULT hr = swap->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&texture);
if(FAILED(hr))
{
RDCERR("Failed to get swap chain buffer, HRESULT: 0x%08x", hr);
SAFE_RELEASE(texture);
return;
}
D3D11_TEXTURE2D_DESC texDesc;
texture->GetDesc(&texDesc);
SAFE_RELEASE(texture);
texDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
texDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
hr = dev->CreateTexture2D(&texDesc, NULL, &texture);
if(FAILED(hr))
{
RDCERR("Failed to create DSV texture for main output, HRESULT: 0x%08x", hr);
SAFE_RELEASE(swap);
SAFE_RELEASE(rtv);
return;
}
hr = dev->CreateDepthStencilView(texture, NULL, &dsv);
SAFE_RELEASE(texture);
if(FAILED(hr))
{
RDCERR("Failed to create DSV for main output, HRESULT: 0x%08x", hr);
SAFE_RELEASE(swap);
SAFE_RELEASE(rtv);
return;
}
}
uint64_t D3D11DebugManager::MakeOutputWindow(void *w, bool depth)
{
OutputWindow outw;
outw.wnd = (HWND)w;
outw.dev = m_WrappedDevice;
DXGI_SWAP_CHAIN_DESC swapDesc;
RDCEraseEl(swapDesc);
RECT rect;GetClientRect(outw.wnd, &rect);
swapDesc.BufferCount = 2;
swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
outw.width = swapDesc.BufferDesc.Width = rect.right-rect.left;
outw.height = swapDesc.BufferDesc.Height = rect.bottom-rect.top;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.SampleDesc.Count = 1;
swapDesc.SampleDesc.Quality = 0;
swapDesc.OutputWindow = outw.wnd;
swapDesc.Windowed = TRUE;
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapDesc.Flags = 0;
HRESULT hr = S_OK;
hr = m_pFactory->CreateSwapChain(m_WrappedDevice, &swapDesc, &outw.swap);
if(FAILED(hr))
{
RDCERR("Failed to create swap chain for HWND, HRESULT: 0x%08x", hr);
return 0;
}
outw.MakeRTV();
outw.dsv = NULL;
if(depth) outw.MakeDSV();
uint64_t id = m_OutputWindowID++;
m_OutputWindows[id] = outw;
return id;
}
void D3D11DebugManager::DestroyOutputWindow(uint64_t id)
{
auto it = m_OutputWindows.find(id);
if(id == 0 || it == m_OutputWindows.end())
return;
OutputWindow &outw = it->second;
SAFE_RELEASE(outw.swap);
SAFE_RELEASE(outw.rtv);
SAFE_RELEASE(outw.dsv);
m_OutputWindows.erase(it);
}
bool D3D11DebugManager::CheckResizeOutputWindow(uint64_t id)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return false;
OutputWindow &outw = m_OutputWindows[id];
if(outw.wnd == NULL || outw.swap == NULL)
return false;
RECT rect;GetClientRect(outw.wnd, &rect);
long w = rect.right-rect.left;
long h = rect.bottom-rect.top;
if(w != outw.width || h != outw.height)
{
outw.width = w;
outw.height = h;
m_WrappedContext->OMSetRenderTargets(0, 0, 0);
if(outw.width > 0 && outw.height > 0)
{
SAFE_RELEASE(outw.rtv);
SAFE_RELEASE(outw.dsv);
DXGI_SWAP_CHAIN_DESC desc;
outw.swap->GetDesc(&desc);
HRESULT hr = outw.swap->ResizeBuffers(desc.BufferCount, outw.width, outw.height, desc.BufferDesc.Format, desc.Flags);
if(FAILED(hr))
{
RDCERR("Failed to resize swap chain, HRESULT: 0x%08x", hr);
return true;
}
outw.MakeRTV();
outw.MakeDSV();
}
return true;
}
return false;
}
void D3D11DebugManager::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return;
w = m_OutputWindows[id].width;
h = m_OutputWindows[id].height;
}
void D3D11DebugManager::ClearOutputWindowColour(uint64_t id, float col[4])
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return;
m_WrappedContext->ClearRenderTargetView(m_OutputWindows[id].rtv, col);
}
void D3D11DebugManager::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return;
if(m_OutputWindows[id].dsv)
m_WrappedContext->ClearDepthStencilView(m_OutputWindows[id].dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, depth, stencil);
}
void D3D11DebugManager::BindOutputWindow(uint64_t id, bool depth)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return;
m_WrappedContext->OMSetRenderTargets(1, &m_OutputWindows[id].rtv, depth && m_OutputWindows[id].dsv ? m_OutputWindows[id].dsv : NULL);
D3D11_VIEWPORT viewport = { 0, 0, (float)m_OutputWindows[id].width, (float)m_OutputWindows[id].height, 0.0f, 1.0f };
m_WrappedContext->RSSetViewports(1, &viewport);
SetOutputDimensions(m_OutputWindows[id].width, m_OutputWindows[id].height);
}
bool D3D11DebugManager::IsOutputWindowVisible(uint64_t id)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return false;
return (IsWindowVisible(m_OutputWindows[id].wnd) == TRUE);
}
void D3D11DebugManager::FlipOutputWindow(uint64_t id)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return;
if(m_OutputWindows[id].swap)
m_OutputWindows[id].swap->Present(0, 0);
}
uint32_t D3D11DebugManager::GetStructCount(ID3D11UnorderedAccessView *uav)
{
m_pImmediateContext->CopyStructureCount(m_DebugRender.StageBuffer, 0, UNWRAP(WrappedID3D11UnorderedAccessView, uav));
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT hr = m_pImmediateContext->Map(m_DebugRender.StageBuffer, 0, D3D11_MAP_READ, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Failed to Map %08x", hr);
return ~0U;
}
uint32_t ret = *((uint32_t *)mapped.pData);
m_pImmediateContext->Unmap(m_DebugRender.StageBuffer, 0);
return ret;
}
bool D3D11DebugManager::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, float minval, float maxval, bool channels[4], vector<uint32_t> &histogram)
{
if(minval >= maxval) return false;
TextureShaderDetails details = GetShaderDetails(texid, true);
if(details.texFmt == DXGI_FORMAT_UNKNOWN)
return false;
D3D11RenderStateTracker tracker(m_WrappedContext);
HistogramCBufferData cdata;
cdata.HistogramTextureResolution.x = (float)RDCMAX(details.texWidth>>mip, 1U);
cdata.HistogramTextureResolution.y = (float)RDCMAX(details.texHeight>>mip, 1U);
cdata.HistogramTextureResolution.z = (float)RDCMAX(details.texDepth>>mip, 1U);
cdata.HistogramSlice = (float)sliceFace;
cdata.HistogramMip = mip;
cdata.HistogramSample = (int)RDCCLAMP(sample, 0U, details.sampleCount-1);
if(sample == ~0U) cdata.HistogramSample = -int(details.sampleCount);
cdata.HistogramMin = minval;
cdata.HistogramMax = maxval;
cdata.HistogramChannels = 0;
if(channels[0]) cdata.HistogramChannels |= 0x1;
if(channels[1]) cdata.HistogramChannels |= 0x2;
if(channels[2]) cdata.HistogramChannels |= 0x4;
if(channels[3]) cdata.HistogramChannels |= 0x8;
cdata.HistogramFlags = 0;
int srvOffset = 0;
int intIdx = 0;
if(IsUIntFormat(details.texFmt))
{
cdata.HistogramFlags |= TEXDISPLAY_UINT_TEX;
srvOffset = 10;
intIdx = 1;
}
if(IsIntFormat(details.texFmt))
{
cdata.HistogramFlags |= TEXDISPLAY_SINT_TEX;
srvOffset = 20;
intIdx = 2;
}
if(details.texType == eTexType_3D)
cdata.HistogramSlice = float(sliceFace)/float(details.texDepth);
ID3D11Buffer *cbuf = MakeCBuffer((float *)&cdata, sizeof(cdata));
UINT zeroes[] = { 0, 0, 0, 0 };
m_pImmediateContext->ClearUnorderedAccessViewUint(m_DebugRender.histogramUAV, zeroes);
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, NULL, 0, 0, NULL, NULL);
ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = { 0 };
UINT UAV_keepcounts[D3D11_PS_CS_UAV_REGISTER_COUNT] = { (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1 };
uavs[0] = m_DebugRender.histogramUAV;
m_pImmediateContext->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, uavs, UAV_keepcounts);
m_pImmediateContext->CSSetConstantBuffers(0, 1, &cbuf);
m_pImmediateContext->CSSetShaderResources(srvOffset, eTexType_Max, details.srv);
ID3D11SamplerState *samps[] = { m_DebugRender.PointSampState, m_DebugRender.LinearSampState };
m_pImmediateContext->CSSetSamplers(0, 2, samps);
m_pImmediateContext->CSSetShader(m_DebugRender.HistogramCS[details.texType][intIdx], NULL, 0);
int tilesX = (int)ceil(cdata.HistogramTextureResolution.x/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE));
int tilesY = (int)ceil(cdata.HistogramTextureResolution.y/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE));
m_pImmediateContext->Dispatch(tilesX, tilesY, 1);
m_pImmediateContext->CopyResource(m_DebugRender.histogramStageBuff, m_DebugRender.histogramBuff);
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT hr = m_pImmediateContext->Map(m_DebugRender.histogramStageBuff, 0, D3D11_MAP_READ, 0, &mapped);
histogram.clear();
histogram.resize(HGRAM_NUM_BUCKETS);
if(FAILED(hr))
{
RDCERR("Can't map histogram stage buff %08x", hr);
}
else
{
memcpy(&histogram[0], mapped.pData, sizeof(uint32_t)*HGRAM_NUM_BUCKETS);
m_pImmediateContext->Unmap(m_DebugRender.histogramStageBuff, 0);
}
return true;
}
bool D3D11DebugManager::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, float *minval, float *maxval)
{
TextureShaderDetails details = GetShaderDetails(texid, true);
if(details.texFmt == DXGI_FORMAT_UNKNOWN)
return false;
D3D11RenderStateTracker tracker(m_WrappedContext);
HistogramCBufferData cdata;
cdata.HistogramTextureResolution.x = (float)RDCMAX(details.texWidth>>mip, 1U);
cdata.HistogramTextureResolution.y = (float)RDCMAX(details.texHeight>>mip, 1U);
cdata.HistogramTextureResolution.z = (float)RDCMAX(details.texDepth>>mip, 1U);
cdata.HistogramSlice = (float)sliceFace;
cdata.HistogramMip = mip;
cdata.HistogramSample = (int)RDCCLAMP(sample, 0U, details.sampleCount-1);
if(sample == ~0U) cdata.HistogramSample = -int(details.sampleCount);
cdata.HistogramMin = 0.0f;
cdata.HistogramMax = 1.0f;
cdata.HistogramChannels = 0xf;
cdata.HistogramFlags = 0;
int srvOffset = 0;
int intIdx = 0;
DXGI_FORMAT fmt = GetTypedFormat(details.texFmt);
if(IsUIntFormat(fmt))
{
cdata.HistogramFlags |= TEXDISPLAY_UINT_TEX;
srvOffset = 10;
intIdx = 1;
}
if(IsIntFormat(fmt))
{
cdata.HistogramFlags |= TEXDISPLAY_SINT_TEX;
srvOffset = 20;
intIdx = 2;
}
if(details.texType == eTexType_3D)
cdata.HistogramSlice = float(sliceFace)/float(details.texDepth);
ID3D11Buffer *cbuf = MakeCBuffer((float *)&cdata, sizeof(cdata));
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, NULL, 0, 0, NULL, NULL);
m_pImmediateContext->CSSetConstantBuffers(0, 1, &cbuf);
ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = { NULL };
uavs[intIdx] = m_DebugRender.tileResultUAV[intIdx];
m_pImmediateContext->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, uavs, NULL);
m_pImmediateContext->CSSetShaderResources(srvOffset, eTexType_Max, details.srv);
ID3D11SamplerState *samps[] = { m_DebugRender.PointSampState, m_DebugRender.LinearSampState };
m_pImmediateContext->CSSetSamplers(0, 2, samps);
m_pImmediateContext->CSSetShader(m_DebugRender.TileMinMaxCS[details.texType][intIdx], NULL, 0);
int blocksX = (int)ceil(cdata.HistogramTextureResolution.x/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE));
int blocksY = (int)ceil(cdata.HistogramTextureResolution.y/float(HGRAM_PIXELS_PER_TILE*HGRAM_PIXELS_PER_TILE));
m_pImmediateContext->Dispatch(blocksX, blocksY, 1);
m_pImmediateContext->CSSetUnorderedAccessViews(intIdx, 1, &m_DebugRender.resultUAV[intIdx], NULL);
m_pImmediateContext->CSSetShaderResources(intIdx, 1, &m_DebugRender.tileResultSRV[intIdx]);
m_pImmediateContext->CSSetShader(m_DebugRender.ResultMinMaxCS[intIdx], NULL, 0);
m_pImmediateContext->Dispatch(1, 1, 1);
m_pImmediateContext->CopyResource(m_DebugRender.resultStageBuff, m_DebugRender.resultBuff);
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT hr = m_pImmediateContext->Map(m_DebugRender.resultStageBuff, 0, D3D11_MAP_READ, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Failed to map minmax results buffer %08x", hr);
}
else
{
Vec4f *minmax = (Vec4f *)mapped.pData;
minval[0] = minmax[0].x;
minval[1] = minmax[0].y;
minval[2] = minmax[0].z;
minval[3] = minmax[0].w;
maxval[0] = minmax[1].x;
maxval[1] = minmax[1].y;
maxval[2] = minmax[1].z;
maxval[3] = minmax[1].w;
m_pImmediateContext->Unmap(m_DebugRender.resultStageBuff, 0);
}
/*
// debugging - copy out tile results
const uint32_t maxTexDim = 16384;
const uint32_t blockPixSize = HGRAM_TILES_PER_BLOCK*HGRAM_PIXELS_PER_TILE;
const uint32_t maxBlocksNeeded = (maxTexDim*maxTexDim)/(blockPixSize*blockPixSize);
D3D11_BUFFER_DESC bdesc;
bdesc.BindFlags = 0;
bdesc.Usage = D3D11_USAGE_STAGING;
bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
bdesc.MiscFlags = 0;
bdesc.StructureByteStride = 0;
bdesc.ByteWidth = 2*4*sizeof(float)*HGRAM_TILES_PER_BLOCK*HGRAM_TILES_PER_BLOCK*maxBlocksNeeded;
ID3D11Buffer *test = NULL;
m_pDevice->CreateBuffer(&bdesc, NULL, &test);
m_pImmediateContext->CopyResource(test, m_DebugRender.tileResultBuff);
m_pImmediateContext->Map(test, 0, D3D11_MAP_READ, 0, &mapped);
m_pImmediateContext->Unmap(test, 0);
SAFE_RELEASE(test);
*/
return true;
}
vector<byte> D3D11DebugManager::GetBufferData(ResourceId buff, uint32_t offset, uint32_t len)
{
auto it = WrappedID3D11Buffer::m_BufferList.find(buff);
if(it == WrappedID3D11Buffer::m_BufferList.end())
return vector<byte>();
ID3D11Buffer *buffer = it->second.m_Buffer;
RDCASSERT(buffer);
return GetBufferData(buffer, offset, len);
}
vector<byte> D3D11DebugManager::GetBufferData(ID3D11Buffer *buffer, uint32_t offset, uint32_t len)
{
D3D11_MAPPED_SUBRESOURCE mapped;
if(buffer == NULL)
return vector<byte>();
D3D11_BUFFER_DESC desc;
buffer->GetDesc(&desc);
if(len > 0 && offset+len > desc.ByteWidth)
{
RDCWARN("Attempting to read off the end of the array. Will be clamped");
len = RDCMIN(len, desc.ByteWidth-offset);
}
else if(len == 0)
{
len = desc.ByteWidth;
}
uint32_t outOffs = 0;
vector<byte> ret;
ret.resize(len);
D3D11_BOX box;
box.top = 0;
box.bottom = 1;
box.front = 0;
box.back = 1;
ID3D11Buffer *src = UNWRAP(WrappedID3D11Buffer, buffer);
while(len > 0)
{
uint32_t chunkSize = RDCMIN(len, STAGE_BUFFER_BYTE_SIZE);
if(desc.StructureByteStride > 0)
chunkSize -= (chunkSize % desc.StructureByteStride);
box.left = RDCMIN(offset + outOffs, desc.ByteWidth);
box.right = RDCMIN(offset + outOffs + chunkSize, desc.ByteWidth);
if(box.right-box.left == 0)
break;
m_pImmediateContext->CopySubresourceRegion(m_DebugRender.StageBuffer, 0, 0, 0, 0, src, 0, &box);
HRESULT hr = m_pImmediateContext->Map(m_DebugRender.StageBuffer, 0, D3D11_MAP_READ, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Failed to map bufferdata buffer %08x", hr);
return ret;
}
else
{
memcpy(&ret[outOffs], mapped.pData, RDCMIN(len, STAGE_BUFFER_BYTE_SIZE));
m_pImmediateContext->Unmap(m_DebugRender.StageBuffer, 0);
}
outOffs += chunkSize;
len -= chunkSize;
}
return ret;
}
void D3D11DebugManager::CopyArrayToTex2DMS(ID3D11Texture2D *destMS, ID3D11Texture2D *srcArray)
{
D3D11RenderStateTracker tracker(m_WrappedContext);
// copy to textures with right bind flags for operation
D3D11_TEXTURE2D_DESC descArr;
srcArray->GetDesc(&descArr);
D3D11_TEXTURE2D_DESC descMS;
destMS->GetDesc(&descMS);
bool depth = IsDepthFormat(descMS.Format);
ID3D11Texture2D *rtvResource = NULL;
ID3D11Texture2D *srvResource = NULL;
D3D11_TEXTURE2D_DESC rtvResDesc = descMS;
D3D11_TEXTURE2D_DESC srvResDesc = descArr;
rtvResDesc.BindFlags = depth ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET;
srvResDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
if(depth)
{
rtvResDesc.Format = GetTypelessFormat(rtvResDesc.Format);
srvResDesc.Format = GetTypelessFormat(srvResDesc.Format);
}
rtvResDesc.Usage = D3D11_USAGE_DEFAULT;
srvResDesc.Usage = D3D11_USAGE_DEFAULT;
rtvResDesc.CPUAccessFlags = 0;
srvResDesc.CPUAccessFlags = 0;
HRESULT hr = S_OK;
hr = m_pDevice->CreateTexture2D(&rtvResDesc, NULL, &rtvResource);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
hr = m_pDevice->CreateTexture2D(&srvResDesc, NULL, &srvResource);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
m_pImmediateContext->CopyResource(srvResource, srcArray);
ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = { NULL };
UINT uavCounts[D3D11_PS_CS_UAV_REGISTER_COUNT] = { (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1 };
m_pImmediateContext->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, uavs, uavCounts);
m_pImmediateContext->VSSetShader(m_DebugRender.FullscreenVS, NULL, 0);
m_pImmediateContext->PSSetShader(depth ? m_DebugRender.DepthCopyArrayToMSPS : m_DebugRender.CopyArrayToMSPS, NULL, 0);
m_pImmediateContext->HSSetShader(NULL, NULL, 0);
m_pImmediateContext->DSSetShader(NULL, NULL, 0);
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
D3D11_VIEWPORT view = { 0.0f, 0.0f, (float)descArr.Width, (float)descArr.Height, 0.0f, 1.0f };
m_pImmediateContext->RSSetState(m_DebugRender.RastState);
m_pImmediateContext->RSSetViewports(1, &view);
m_pImmediateContext->IASetInputLayout(NULL);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
float blendFactor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
m_pImmediateContext->OMSetBlendState(NULL, blendFactor, ~0U);
if(depth)
{
D3D11_DEPTH_STENCIL_DESC dsDesc;
ID3D11DepthStencilState *dsState = NULL;
RDCEraseEl(dsDesc);
dsDesc.DepthEnable = TRUE;
dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.StencilEnable = FALSE;
dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp = dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp = dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff;
m_pDevice->CreateDepthStencilState(&dsDesc, &dsState);
m_pImmediateContext->OMSetDepthStencilState(dsState, 0);
SAFE_RELEASE(dsState);
}
ID3D11DepthStencilView *dsvMS = NULL;
ID3D11RenderTargetView *rtvMS = NULL;
ID3D11ShaderResourceView *srvArray = NULL;
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
rtvDesc.Format = depth ? GetUIntTypedFormat(descMS.Format) : GetTypedFormatUIntPreferred(descMS.Format);
rtvDesc.Texture2DMSArray.ArraySize = descMS.ArraySize;
rtvDesc.Texture2DMSArray.FirstArraySlice = 0;
D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
dsvDesc.Flags = 0;
dsvDesc.Format = GetDepthTypedFormat(descMS.Format);
dsvDesc.Texture2DMSArray.ArraySize = descMS.ArraySize;
dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
srvDesc.Format = depth ? GetUIntTypedFormat(descArr.Format) : GetTypedFormatUIntPreferred(descArr.Format);
srvDesc.Texture2DArray.ArraySize = descArr.ArraySize;
srvDesc.Texture2DArray.FirstArraySlice = 0;
srvDesc.Texture2DArray.MipLevels = descArr.MipLevels;
srvDesc.Texture2DArray.MostDetailedMip = 0;
bool stencil = false;
DXGI_FORMAT stencilFormat = DXGI_FORMAT_UNKNOWN;
if(depth)
{
switch(descArr.Format)
{
case DXGI_FORMAT_D32_FLOAT:
case DXGI_FORMAT_R32_FLOAT:
case DXGI_FORMAT_R32_TYPELESS:
srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
break;
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
case DXGI_FORMAT_R32G8X24_TYPELESS:
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
stencilFormat = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
stencil = true;
break;
case DXGI_FORMAT_D24_UNORM_S8_UINT:
case DXGI_FORMAT_R24G8_TYPELESS:
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
stencilFormat = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
stencil = true;
break;
case DXGI_FORMAT_D16_UNORM:
case DXGI_FORMAT_R16_TYPELESS:
srvDesc.Format = DXGI_FORMAT_R16_FLOAT;
break;
}
}
hr = m_pDevice->CreateShaderResourceView(srvResource, &srvDesc, &srvArray);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
ID3D11ShaderResourceView *srvs[8] = { NULL };
srvs[0] = srvArray;
m_pImmediateContext->PSSetShaderResources(0, D3D11_PS_CS_UAV_REGISTER_COUNT, srvs);
// loop over every array slice in MS texture
for(UINT slice=0; slice < descMS.ArraySize; slice++)
{
uint32_t cdata[4] = { descMS.SampleDesc.Count, 1000, 0, slice};
ID3D11Buffer *cbuf = MakeCBuffer((float *)cdata, sizeof(cdata));
m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf);
rtvDesc.Texture2DMSArray.FirstArraySlice = slice;
rtvDesc.Texture2DMSArray.ArraySize = 1;
dsvDesc.Texture2DMSArray.FirstArraySlice = slice;
dsvDesc.Texture2DMSArray.ArraySize = 1;
if(depth)
hr = m_pDevice->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvMS);
else
hr = m_pDevice->CreateRenderTargetView(rtvResource, &rtvDesc, &rtvMS);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
if(depth)
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvMS, 0, 0, NULL, NULL);
else
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &rtvMS, NULL, 0, 0, NULL, NULL);
m_pImmediateContext->Draw(3, 0);
SAFE_RELEASE(rtvMS);
SAFE_RELEASE(dsvMS);
}
SAFE_RELEASE(srvArray);
if(stencil)
{
srvDesc.Format = stencilFormat;
hr = m_pDevice->CreateShaderResourceView(srvResource, &srvDesc, &srvArray);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
m_pImmediateContext->PSSetShaderResources(1, 1, &srvArray);
D3D11_DEPTH_STENCIL_DESC dsDesc;
ID3D11DepthStencilState *dsState = NULL;
RDCEraseEl(dsDesc);
dsDesc.DepthEnable = FALSE;
dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dsDesc.StencilEnable = TRUE;
dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp = dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp = dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff;
dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH;
dsvDesc.Texture2DArray.ArraySize = 1;
m_pDevice->CreateDepthStencilState(&dsDesc, &dsState);
// loop over every array slice in MS texture
for(UINT slice=0; slice < descMS.ArraySize; slice++)
{
dsvDesc.Texture2DMSArray.FirstArraySlice = slice;
hr = m_pDevice->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvMS);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvMS, 0, 0, NULL, NULL);
// loop over every stencil value (zzzzzz, no shader stencil read/write)
for(UINT stencil=0; stencil < 256; stencil++)
{
uint32_t cdata[4] = { descMS.SampleDesc.Count, stencil, 0, slice};
ID3D11Buffer *cbuf = MakeCBuffer((float *)cdata, sizeof(cdata));
m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf);
m_pImmediateContext->OMSetDepthStencilState(dsState, stencil);
m_pImmediateContext->Draw(3, 0);
}
SAFE_RELEASE(dsvMS);
}
SAFE_RELEASE(dsState);
}
m_pImmediateContext->CopyResource(destMS, rtvResource);
SAFE_RELEASE(rtvResource);
SAFE_RELEASE(srvResource);
}
void D3D11DebugManager::CopyTex2DMSToArray(ID3D11Texture2D *destArray, ID3D11Texture2D *srcMS)
{
D3D11RenderStateTracker tracker(m_WrappedContext);
// copy to textures with right bind flags for operation
D3D11_TEXTURE2D_DESC descMS;
srcMS->GetDesc(&descMS);
D3D11_TEXTURE2D_DESC descArr;
destArray->GetDesc(&descArr);
ID3D11Texture2D *rtvResource = NULL;
ID3D11Texture2D *srvResource = NULL;
D3D11_TEXTURE2D_DESC rtvResDesc = descArr;
D3D11_TEXTURE2D_DESC srvResDesc = descMS;
bool depth = IsDepthFormat(descMS.Format);
rtvResDesc.BindFlags = depth ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET;
srvResDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
if(depth)
{
rtvResDesc.Format = GetTypelessFormat(rtvResDesc.Format);
srvResDesc.Format = GetTypelessFormat(srvResDesc.Format);
}
rtvResDesc.Usage = D3D11_USAGE_DEFAULT;
srvResDesc.Usage = D3D11_USAGE_DEFAULT;
rtvResDesc.CPUAccessFlags = 0;
srvResDesc.CPUAccessFlags = 0;
HRESULT hr = S_OK;
hr = m_pDevice->CreateTexture2D(&rtvResDesc, NULL, &rtvResource);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
hr = m_pDevice->CreateTexture2D(&srvResDesc, NULL, &srvResource);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
m_pImmediateContext->CopyResource(srvResource, srcMS);
ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = { NULL };
UINT uavCounts[D3D11_PS_CS_UAV_REGISTER_COUNT] = { (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1 };
m_pImmediateContext->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, uavs, uavCounts);
m_pImmediateContext->VSSetShader(m_DebugRender.FullscreenVS, NULL, 0);
m_pImmediateContext->PSSetShader(depth ? m_DebugRender.DepthCopyMSToArrayPS : m_DebugRender.CopyMSToArrayPS, NULL, 0);
m_pImmediateContext->IASetInputLayout(NULL);
float blendFactor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
m_pImmediateContext->OMSetBlendState(NULL, blendFactor, ~0U);
if(depth)
{
D3D11_DEPTH_STENCIL_DESC dsDesc;
ID3D11DepthStencilState *dsState = NULL;
RDCEraseEl(dsDesc);
dsDesc.DepthEnable = TRUE;
dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.StencilEnable = FALSE;
dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp = dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp = dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff;
m_pDevice->CreateDepthStencilState(&dsDesc, &dsState);
m_pImmediateContext->OMSetDepthStencilState(dsState, 0);
SAFE_RELEASE(dsState);
}
ID3D11RenderTargetView *rtvArray = NULL;
ID3D11DepthStencilView *dsvArray = NULL;
ID3D11ShaderResourceView *srvMS = NULL;
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
rtvDesc.Format = depth ? GetUIntTypedFormat(descArr.Format) : GetTypedFormatUIntPreferred(descArr.Format);
rtvDesc.Texture2DArray.FirstArraySlice = 0;
rtvDesc.Texture2DArray.ArraySize = 1;
rtvDesc.Texture2DArray.MipSlice = 0;
D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
dsvDesc.Format = GetDepthTypedFormat(descArr.Format);
dsvDesc.Flags = 0;
dsvDesc.Texture2DArray.FirstArraySlice = 0;
dsvDesc.Texture2DArray.ArraySize = 1;
dsvDesc.Texture2DArray.MipSlice = 0;
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
srvDesc.Format = depth ? GetUIntTypedFormat(descMS.Format) : GetTypedFormatUIntPreferred(descMS.Format);
srvDesc.Texture2DMSArray.ArraySize = descMS.ArraySize;
srvDesc.Texture2DMSArray.FirstArraySlice = 0;
bool stencil = false;
DXGI_FORMAT stencilFormat = DXGI_FORMAT_UNKNOWN;
if(depth)
{
switch(descMS.Format)
{
case DXGI_FORMAT_D32_FLOAT:
case DXGI_FORMAT_R32_FLOAT:
case DXGI_FORMAT_R32_TYPELESS:
srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
break;
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
case DXGI_FORMAT_R32G8X24_TYPELESS:
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
stencilFormat = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
stencil = true;
break;
case DXGI_FORMAT_D24_UNORM_S8_UINT:
case DXGI_FORMAT_R24G8_TYPELESS:
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
stencilFormat = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
stencil = true;
break;
case DXGI_FORMAT_D16_UNORM:
case DXGI_FORMAT_R16_TYPELESS:
srvDesc.Format = DXGI_FORMAT_R16_FLOAT;
break;
}
}
hr = m_pDevice->CreateShaderResourceView(srvResource, &srvDesc, &srvMS);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
ID3D11ShaderResourceView *srvs[8] = { NULL };
int srvIndex = 0;
for(int i=0; i < 8; i++)
if(descMS.SampleDesc.Count == UINT(1<<i))
srvIndex = i;
srvs[srvIndex] = srvMS;
m_pImmediateContext->PSSetShaderResources(0, D3D11_PS_CS_UAV_REGISTER_COUNT, srvs);
// loop over every array slice in MS texture
for(UINT slice=0; slice < descMS.ArraySize; slice++)
{
// loop over every multi sample
for(UINT sample=0; sample < descMS.SampleDesc.Count; sample++)
{
uint32_t cdata[4] = { descMS.SampleDesc.Count, 1000, sample, slice};
ID3D11Buffer *cbuf = MakeCBuffer((float *)cdata, sizeof(cdata));
m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf);
rtvDesc.Texture2DArray.FirstArraySlice = slice*descMS.SampleDesc.Count + sample;
dsvDesc.Texture2DArray.FirstArraySlice = slice*descMS.SampleDesc.Count + sample;
if(depth)
hr = m_pDevice->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvArray);
else
hr = m_pDevice->CreateRenderTargetView(rtvResource, &rtvDesc, &rtvArray);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
if(depth)
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvArray, 0, 0, NULL, NULL);
else
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &rtvArray, NULL, 0, 0, NULL, NULL);
m_pImmediateContext->Draw(3, 0);
SAFE_RELEASE(rtvArray);
SAFE_RELEASE(dsvArray);
}
}
SAFE_RELEASE(srvMS);
if(stencil)
{
srvDesc.Format = stencilFormat;
hr = m_pDevice->CreateShaderResourceView(srvResource, &srvDesc, &srvMS);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
m_pImmediateContext->PSSetShaderResources(10+srvIndex, 1, &srvMS);
D3D11_DEPTH_STENCIL_DESC dsDesc;
ID3D11DepthStencilState *dsState = NULL;
RDCEraseEl(dsDesc);
dsDesc.DepthEnable = FALSE;
dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
dsDesc.StencilEnable = TRUE;
dsDesc.BackFace.StencilFailOp = dsDesc.BackFace.StencilPassOp = dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.FrontFace.StencilFailOp = dsDesc.FrontFace.StencilPassOp = dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dsDesc.StencilReadMask = dsDesc.StencilWriteMask = 0xff;
dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH;
dsvDesc.Texture2DArray.ArraySize = 1;
m_pDevice->CreateDepthStencilState(&dsDesc, &dsState);
// loop over every array slice in MS texture
for(UINT slice=0; slice < descMS.ArraySize; slice++)
{
// loop over every multi sample
for(UINT sample=0; sample < descMS.SampleDesc.Count; sample++)
{
dsvDesc.Texture2DArray.FirstArraySlice = slice*descMS.SampleDesc.Count + sample;
hr = m_pDevice->CreateDepthStencilView(rtvResource, &dsvDesc, &dsvArray);
if(FAILED(hr))
{
RDCERR("0x%08x", hr);
return;
}
m_pImmediateContext->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, dsvArray, 0, 0, NULL, NULL);
// loop over every stencil value (zzzzzz, no shader stencil read/write)
for(UINT stencil=0; stencil < 256; stencil++)
{
uint32_t cdata[4] = { descMS.SampleDesc.Count, stencil, sample, slice};
ID3D11Buffer *cbuf = MakeCBuffer((float *)cdata, sizeof(cdata));
m_pImmediateContext->PSSetConstantBuffers(0, 1, &cbuf);
m_pImmediateContext->OMSetDepthStencilState(dsState, stencil);
m_pImmediateContext->Draw(3, 0);
}
SAFE_RELEASE(dsvArray);
}
}
SAFE_RELEASE(dsState);
}
m_pImmediateContext->CopyResource(destArray, rtvResource);
SAFE_RELEASE(rtvResource);
SAFE_RELEASE(srvResource);
}
D3D11DebugManager::CacheElem &D3D11DebugManager::GetCachedElem(ResourceId id, bool raw)
{
for(auto it=m_ShaderItemCache.begin(); it != m_ShaderItemCache.end(); ++it)
{
if(it->id == id && it->raw == raw)
return *it;
}
if(m_ShaderItemCache.size() >= NUM_CACHED_SRVS)
{
CacheElem &elem = m_ShaderItemCache.back();
elem.Release();
m_ShaderItemCache.pop_back();
}
m_ShaderItemCache.push_front(CacheElem(id, raw));
return m_ShaderItemCache.front();
}
D3D11DebugManager::TextureShaderDetails D3D11DebugManager::GetShaderDetails(ResourceId id, bool rawOutput)
{
TextureShaderDetails details;
HRESULT hr = S_OK;
bool foundResource = false;
CacheElem &cache = GetCachedElem(id, rawOutput);
bool msaaDepth = false;
bool cube = false;
DXGI_FORMAT srvFormat = DXGI_FORMAT_UNKNOWN;
if(WrappedID3D11Texture1D::m_TextureList.find(id) != WrappedID3D11Texture1D::m_TextureList.end())
{
WrappedID3D11Texture1D *wrapTex1D = (WrappedID3D11Texture1D *)WrappedID3D11Texture1D::m_TextureList[id].m_Texture;
TextureDisplayType mode = WrappedID3D11Texture1D::m_TextureList[id].m_Type;
foundResource = true;
details.texType = eTexType_1D;
if(mode == TEXDISPLAY_DEPTH_TARGET)
details.texType = eTexType_Depth;
D3D11_TEXTURE1D_DESC desc1d = {0};
wrapTex1D->GetDesc(&desc1d);
details.texFmt = desc1d.Format;
details.texWidth = desc1d.Width;
details.texHeight = 1;
details.texDepth = 1;
details.texArraySize = desc1d.ArraySize;
details.texMips = desc1d.MipLevels;
srvFormat = GetTypedFormat(details.texFmt);
details.srvResource = wrapTex1D->GetReal();
if(mode == TEXDISPLAY_INDIRECT_VIEW ||
mode == TEXDISPLAY_DEPTH_TARGET)
{
D3D11_TEXTURE1D_DESC desc = desc1d;
desc.CPUAccessFlags = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
if(mode == TEXDISPLAY_DEPTH_TARGET)
desc.Format = GetTypelessFormat(desc.Format);
if(!cache.created)
{
ID3D11Texture1D *tmp = NULL;
hr = m_pDevice->CreateTexture1D(&desc, NULL, &tmp);
if(FAILED(hr))
{
RDCERR("Failed to create temporary Texture1D %08x", hr);
}
cache.srvResource = tmp;
}
details.previewCopy = cache.srvResource;
m_pImmediateContext->CopyResource(details.previewCopy, details.srvResource);
details.srvResource = details.previewCopy;
}
}
else if(WrappedID3D11Texture2D::m_TextureList.find(id) != WrappedID3D11Texture2D::m_TextureList.end())
{
WrappedID3D11Texture2D *wrapTex2D = (WrappedID3D11Texture2D *)WrappedID3D11Texture2D::m_TextureList[id].m_Texture;
TextureDisplayType mode = WrappedID3D11Texture2D::m_TextureList[id].m_Type;
foundResource = true;
details.texType = eTexType_2D;
D3D11_TEXTURE2D_DESC desc2d = {0};
wrapTex2D->GetDesc(&desc2d);
if(desc2d.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE)
cube = true;
details.texFmt = desc2d.Format;
details.texWidth = desc2d.Width;
details.texHeight = desc2d.Height;
details.texDepth = 1;
details.texArraySize = desc2d.ArraySize;
details.texMips = desc2d.MipLevels;
details.sampleCount = RDCMAX(1U, desc2d.SampleDesc.Count);
details.sampleQuality = desc2d.SampleDesc.Quality;
if(desc2d.SampleDesc.Count > 1 || desc2d.SampleDesc.Quality > 0)
{
details.texType = eTexType_2DMS;
}
if(mode == TEXDISPLAY_DEPTH_TARGET || IsDepthFormat(details.texFmt))
{
details.texType = eTexType_Depth;
details.texFmt = GetTypedFormat(details.texFmt);
}
// backbuffer is always interpreted as SRGB data regardless of format specified:
// http://msdn.microsoft.com/en-us/library/windows/desktop/hh972627(v=vs.85).aspx
//
// "The app must always place sRGB data into back buffers with integer-valued formats
// to present the sRGB data to the screen, even if the data doesn't have this format
// modifier in its format name."
//
// This essentially corrects for us always declaring an SRGB render target for our
// output displays, as any app with a non-SRGB backbuffer would be incorrectly converted
// unless we read out SRGB here.
//
// However when picking a pixel we want the actual value stored, not the corrected perceptual
// value so for raw output we don't do this. This does my head in, it really does.
if(wrapTex2D->m_RealDescriptor)
{
if(rawOutput)
details.texFmt = wrapTex2D->m_RealDescriptor->Format;
else
details.texFmt = GetSRGBFormat(wrapTex2D->m_RealDescriptor->Format);
}
srvFormat = GetTypedFormat(details.texFmt);
details.srvResource = wrapTex2D->GetReal();
if(mode == TEXDISPLAY_INDIRECT_VIEW ||
mode == TEXDISPLAY_DEPTH_TARGET ||
desc2d.SampleDesc.Count > 1 || desc2d.SampleDesc.Quality > 0)
{
D3D11_TEXTURE2D_DESC desc = desc2d;
desc.CPUAccessFlags = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
if(mode == TEXDISPLAY_DEPTH_TARGET)
{
desc.Format = GetTypelessFormat(desc.Format);
}
else
{
desc.Format = srvFormat;
}
if(!cache.created)
{
ID3D11Texture2D *tmp = NULL;
hr = m_pDevice->CreateTexture2D(&desc, NULL, &tmp);
if(FAILED(hr))
{
RDCERR("Failed to create temporary Texture2D %08x", hr);
}
cache.srvResource = tmp;
}
details.previewCopy = cache.srvResource;
if((desc2d.SampleDesc.Count > 1 || desc2d.SampleDesc.Quality > 0) && mode == TEXDISPLAY_DEPTH_TARGET)
msaaDepth = true;
m_pImmediateContext->CopyResource(details.previewCopy, details.srvResource);
details.srvResource = details.previewCopy;
}
}
else if(WrappedID3D11Texture3D::m_TextureList.find(id) != WrappedID3D11Texture3D::m_TextureList.end())
{
WrappedID3D11Texture3D *wrapTex3D = (WrappedID3D11Texture3D *)WrappedID3D11Texture3D::m_TextureList[id].m_Texture;
TextureDisplayType mode = WrappedID3D11Texture3D::m_TextureList[id].m_Type;
foundResource = true;
details.texType = eTexType_3D;
D3D11_TEXTURE3D_DESC desc3d = {0};
wrapTex3D->GetDesc(&desc3d);
details.texFmt = desc3d.Format;
details.texWidth = desc3d.Width;
details.texHeight = desc3d.Height;
details.texDepth = desc3d.Depth;
details.texArraySize = 1;
details.texMips = desc3d.MipLevels;
srvFormat = GetTypedFormat(details.texFmt);
details.srvResource = wrapTex3D->GetReal();
if(mode == TEXDISPLAY_INDIRECT_VIEW)
{
D3D11_TEXTURE3D_DESC desc = desc3d;
desc.CPUAccessFlags = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
if(IsUIntFormat(srvFormat) || IsIntFormat(srvFormat))
desc.Format = GetTypelessFormat(desc.Format);
if(!cache.created)
{
ID3D11Texture3D *tmp = NULL;
hr = m_pDevice->CreateTexture3D(&desc, NULL, &tmp);
if(FAILED(hr))
{
RDCERR("Failed to create temporary Texture3D %08x", hr);
}
cache.srvResource = tmp;
}
details.previewCopy = cache.srvResource;
m_pImmediateContext->CopyResource(details.previewCopy, details.srvResource);
details.srvResource = details.previewCopy;
}
}
if(!foundResource)
{
RDCERR("bad texture trying to be displayed");
return TextureShaderDetails();
}
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc[eTexType_Max];
srvDesc[eTexType_1D].ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
srvDesc[eTexType_1D].Texture1DArray.ArraySize = details.texArraySize;
srvDesc[eTexType_1D].Texture1DArray.FirstArraySlice = 0;
srvDesc[eTexType_1D].Texture1DArray.MipLevels = details.texMips;
srvDesc[eTexType_1D].Texture1DArray.MostDetailedMip = 0;
srvDesc[eTexType_2D].ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
srvDesc[eTexType_2D].Texture2DArray.ArraySize = details.texArraySize;
srvDesc[eTexType_2D].Texture2DArray.FirstArraySlice = 0;
srvDesc[eTexType_2D].Texture2DArray.MipLevels = details.texMips;
srvDesc[eTexType_2D].Texture2DArray.MostDetailedMip = 0;
srvDesc[eTexType_2DMS].ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
srvDesc[eTexType_2DMS].Texture2DMSArray.ArraySize = details.texArraySize;
srvDesc[eTexType_2DMS].Texture2DMSArray.FirstArraySlice = 0;
srvDesc[eTexType_Stencil] = srvDesc[eTexType_Depth] = srvDesc[eTexType_2D];
srvDesc[eTexType_3D].ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
srvDesc[eTexType_3D].Texture3D.MipLevels = details.texMips;
srvDesc[eTexType_3D].Texture3D.MostDetailedMip = 0;
srvDesc[eTexType_Cube].ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
srvDesc[eTexType_Cube].TextureCubeArray.First2DArrayFace = 0;
srvDesc[eTexType_Cube].TextureCubeArray.MipLevels = details.texMips;
srvDesc[eTexType_Cube].TextureCubeArray.MostDetailedMip = 0;
srvDesc[eTexType_Cube].TextureCubeArray.NumCubes = RDCMAX(1U, details.texArraySize/6);
for(int i=0; i < eTexType_Max; i++)
srvDesc[i].Format = srvFormat;
if(details.texType == eTexType_Depth)
{
switch(details.texFmt)
{
case DXGI_FORMAT_R32G8X24_TYPELESS:
case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
{
srvDesc[eTexType_Depth].Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
srvDesc[eTexType_Stencil].Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
break;
}
case DXGI_FORMAT_R32_FLOAT:
case DXGI_FORMAT_R32_TYPELESS:
case DXGI_FORMAT_D32_FLOAT:
{
srvDesc[eTexType_Depth].Format = DXGI_FORMAT_R32_FLOAT;
srvDesc[eTexType_Stencil].Format = DXGI_FORMAT_UNKNOWN;
break;
}
case DXGI_FORMAT_R24G8_TYPELESS:
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
case DXGI_FORMAT_D24_UNORM_S8_UINT:
{
srvDesc[eTexType_Depth].Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
srvDesc[eTexType_Stencil].Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
break;
}
case DXGI_FORMAT_R16_FLOAT:
case DXGI_FORMAT_R16_TYPELESS:
case DXGI_FORMAT_D16_UNORM:
case DXGI_FORMAT_R16_UINT:
{
srvDesc[eTexType_Depth].Format = DXGI_FORMAT_R16_UNORM;
srvDesc[eTexType_Stencil].Format = DXGI_FORMAT_UNKNOWN;
break;
}
default:
break;
}
}
if(msaaDepth)
{
srvDesc[eTexType_Stencil].ViewDimension = srvDesc[eTexType_Depth].ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
srvDesc[eTexType_Depth].Texture2DMSArray.ArraySize = srvDesc[eTexType_2D].Texture2DArray.ArraySize;
srvDesc[eTexType_Stencil].Texture2DMSArray.ArraySize = srvDesc[eTexType_2D].Texture2DArray.ArraySize;
srvDesc[eTexType_Depth].Texture2DMSArray.FirstArraySlice = srvDesc[eTexType_2D].Texture2DArray.FirstArraySlice;
srvDesc[eTexType_Stencil].Texture2DMSArray.FirstArraySlice = srvDesc[eTexType_2D].Texture2DArray.FirstArraySlice;
}
if(!cache.created)
{
hr = m_pDevice->CreateShaderResourceView(details.srvResource, &srvDesc[details.texType], &cache.srv[0]);
if(FAILED(hr))
RDCERR("Failed to create cache SRV 0, type %d %08x", details.texType, hr);
}
details.srv[details.texType] = cache.srv[0];
if(details.texType == eTexType_Depth && srvDesc[eTexType_Stencil].Format != DXGI_FORMAT_UNKNOWN)
{
if(!cache.created)
{
hr = m_pDevice->CreateShaderResourceView(details.srvResource, &srvDesc[eTexType_Stencil], &cache.srv[1]);
if(FAILED(hr))
RDCERR("Failed to create cache SRV 1, type %d %08x", details.texType, hr);
}
details.srv[eTexType_Stencil] = cache.srv[1];
details.texType = eTexType_Stencil;
}
if(msaaDepth)
{
if(details.texType == eTexType_Depth)
details.texType = eTexType_DepthMS;
if(details.texType == eTexType_Stencil)
details.texType = eTexType_StencilMS;
details.srv[eTexType_Depth] = NULL;
details.srv[eTexType_Stencil] = NULL;
details.srv[eTexType_DepthMS] = cache.srv[0];
details.srv[eTexType_StencilMS] = cache.srv[1];
}
if((details.texType == eTexType_2D ||
details.texType == eTexType_Depth ||
details.texType == eTexType_Stencil)
&& cube)
{
if(!cache.created)
{
hr = m_pDevice->CreateShaderResourceView(details.srvResource, &srvDesc[eTexType_Cube], &cache.srv[2]);
if(FAILED(hr))
RDCERR("Failed to create cache SRV 2 %08x", hr);
}
details.srv[eTexType_Cube] = cache.srv[2];
}
cache.created = true;
return details;
}
void D3D11DebugManager::RenderText(float x, float y, float size, const char *textfmt, ...)
{
static char tmpBuf[4096];
va_list args;
va_start(args, textfmt);
StringFormat::vsnprintf( tmpBuf, 4095, textfmt, args );
tmpBuf[4095] = '\0';
va_end(args);
// normalize size to 720 (and scale respectively)
// invert y co-ordinates for convenience
RenderTextInternal(x, -y, size*(720.0f/float(GetHeight())), tmpBuf);
}
void D3D11DebugManager::RenderTextInternal(float x, float y, float size, const char *text)
{
if(char *t = strchr((char *)text, '\n'))
{
*t = 0;
RenderTextInternal(x, y, size, text);
RenderTextInternal(x, y-18.0f, size, t+1);
*t = '\n';
return;
}
if(strlen(text) == 0)
return;
RDCASSERT(strlen(text) < FONT_MAX_CHARS);
FontCBuffer data;
data.TextPosition.x = x*(2.0f/float(GetWidth()));
data.TextPosition.y = y*(2.0f/float(GetHeight()));
data.FontScreenAspect.x = (float(GetHeight())/float(GetWidth()))*0.5f; // 0.5 = character width / character height
data.FontScreenAspect.y = 1.0f;
data.CharacterSize.x = 0.5f*(float(FONT_TEX_HEIGHT)/float(FONT_TEX_WIDTH));
data.CharacterSize.y = 1.0f;
data.TextSize = size*0.05f; // default arbitrary font size
data.CharacterOffsetX = 0.75f*(float(FONT_TEX_HEIGHT)/float(FONT_TEX_WIDTH));
D3D11_MAPPED_SUBRESOURCE mapped;
FillCBuffer(m_Font.CBuffer, (float *)&data, sizeof(FontCBuffer));
HRESULT hr = m_pImmediateContext->Map(m_Font.CharBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Failed to map charbuffer %08x", hr);
return;
}
unsigned long *texs = (unsigned long *)mapped.pData;
for(size_t i=0; i < strlen(text); i++)
{
texs[i*4 + 0] = text[i] - ' ';
texs[i*4 + 1] = text[i] - ' ';
texs[i*4 + 2] = text[i] - ' ';
texs[i*4 + 3] = text[i] - ' ';
}
m_pImmediateContext->Unmap(m_Font.CharBuffer, 0);
ID3D11Buffer *bufs[2] = { m_DebugRender.PosBuffer, m_Font.CharBuffer };
UINT strides[2] = { 3*sizeof(float), sizeof(long) };
UINT offsets[2] = { 0, 0 };
// can't just clear state because we need to keep things like render targets.
{
m_pImmediateContext->IASetInputLayout(m_Font.Layout);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
m_pImmediateContext->IASetVertexBuffers(0, 2, bufs, strides, offsets);
m_pImmediateContext->VSSetShader(m_Font.VS, NULL, 0);
m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_Font.CBuffer);
m_pImmediateContext->HSSetShader(NULL, NULL, 0);
m_pImmediateContext->DSSetShader(NULL, NULL, 0);
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
m_pImmediateContext->RSSetState(m_DebugRender.RastState);
D3D11_VIEWPORT view;
view.TopLeftX = 0;
view.TopLeftY = 0;
view.Width = (float)GetWidth();
view.Height = (float)GetHeight();
view.MinDepth = 0.0f;
view.MaxDepth = 1.0f;
m_pImmediateContext->RSSetViewports(1, &view);
m_pImmediateContext->PSSetShader(m_Font.PS, NULL, 0);
m_pImmediateContext->PSSetShaderResources(0, 1, &m_Font.Tex);
ID3D11SamplerState *samps[] = { m_DebugRender.PointSampState, m_DebugRender.LinearSampState };
m_pImmediateContext->PSSetSamplers(0, 2, samps);
float factor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
m_pImmediateContext->OMSetBlendState(m_DebugRender.BlendState, factor, 0xffffffff);
m_pImmediateContext->Draw((uint32_t)strlen(text)*4, 0);
}
}
bool D3D11DebugManager::RenderTexture(TextureDisplay cfg)
{
DebugVertexCBuffer vertexData;
DebugPixelCBufferData pixelData;
float x = cfg.offx;
float y = cfg.offy;
vertexData.Position.x = x*(2.0f/float(GetWidth()));
vertexData.Position.y = -y*(2.0f/float(GetHeight()));
vertexData.ScreenAspect.x = (float(GetHeight())/float(GetWidth())); // 0.5 = character width / character height
vertexData.ScreenAspect.y = 1.0f;
vertexData.TextureResolution.x = 1.0f/vertexData.ScreenAspect.x;
vertexData.TextureResolution.y = 1.0f;
if(cfg.rangemax <= cfg.rangemin) cfg.rangemax += 0.00001f;
pixelData.Channels.x = cfg.Red ? 1.0f : 0.0f;
pixelData.Channels.y = cfg.Green ? 1.0f : 0.0f;
pixelData.Channels.z = cfg.Blue ? 1.0f : 0.0f;
pixelData.Channels.w = cfg.Alpha ? 1.0f : 0.0f;
pixelData.RangeMinimum = cfg.rangemin;
pixelData.InverseRangeSize = 1.0f/(cfg.rangemax-cfg.rangemin);
pixelData.WireframeColour.x = cfg.HDRMul;
pixelData.RawOutput = cfg.rawoutput ? 1 : 0;
pixelData.FlipY = cfg.FlipY ? 1 : 0;
TextureShaderDetails details = GetShaderDetails(cfg.texid, cfg.rawoutput ? true : false);
static int sampIdx = 0;
pixelData.SampleIdx = (int)RDCCLAMP(cfg.sampleIdx, 0U, details.sampleCount-1);
// hacky resolve
if(cfg.sampleIdx == ~0U)
pixelData.SampleIdx = -int(details.sampleCount);
if(details.texFmt == DXGI_FORMAT_UNKNOWN)
return false;
D3D11RenderStateTracker tracker(m_WrappedContext);
if(details.texFmt == DXGI_FORMAT_A8_UNORM && cfg.scale <= 0.0f)
{
pixelData.Channels.x = pixelData.Channels.y = pixelData.Channels.z = 0.0f;
pixelData.Channels.w = 1.0f;
}
float tex_x = float(details.texWidth);
float tex_y = float(details.texType == eTexType_1D ? 100 : details.texHeight);
vertexData.TextureResolution.x *= tex_x/float(GetWidth());
vertexData.TextureResolution.y *= tex_y/float(GetHeight());
pixelData.TextureResolutionPS.x = float(RDCMAX(1U,details.texWidth>>cfg.mip));
pixelData.TextureResolutionPS.y = float(RDCMAX(1U,details.texHeight>>cfg.mip));
pixelData.TextureResolutionPS.z = float(RDCMAX(1U,details.texDepth>>cfg.mip));
if(details.texArraySize > 1 && details.texType != eTexType_3D)
pixelData.TextureResolutionPS.z = float(details.texArraySize);
vertexData.Scale = cfg.scale;
pixelData.ScalePS = cfg.scale;
if(cfg.scale <= 0.0f)
{
float xscale = float(GetWidth())/tex_x;
float yscale = float(GetHeight())/tex_y;
vertexData.Scale = RDCMIN(xscale, yscale);
if(yscale > xscale)
{
vertexData.Position.x = 0;
vertexData.Position.y = tex_y*vertexData.Scale/float(GetHeight()) - 1.0f;
}
else
{
vertexData.Position.y = 0;
vertexData.Position.x = 1.0f - tex_x*vertexData.Scale/float(GetWidth());
}
}
ID3D11PixelShader *customPS = NULL;
ID3D11Buffer *customBuff = NULL;
if(cfg.CustomShader != ResourceId())
{
auto it = WrappedShader::m_ShaderList.find(cfg.CustomShader);
if(it != WrappedShader::m_ShaderList.end())
{
auto dxbc = it->second.m_DXBCFile;
RDCASSERT(dxbc);
RDCASSERT(dxbc->m_Type == D3D11_SHVER_PIXEL_SHADER);
WrappedID3D11Shader<ID3D11PixelShader> *wrapped = (WrappedID3D11Shader<ID3D11PixelShader> *)m_WrappedDevice->GetResourceManager()->GetLiveResource(cfg.CustomShader);
customPS = wrapped->GetReal();
for(size_t i=0; i < dxbc->m_CBuffers.size(); i++)
{
const DXBC::CBuffer &cbuf = dxbc->m_CBuffers[i];
if(cbuf.name == "$Globals")
{
float *cbufData = new float[cbuf.descriptor.byteSize/sizeof(float) + 1];
byte *byteData = (byte *)cbufData;
for(size_t v=0; v < cbuf.variables.size(); v++)
{
const DXBC::CBufferVariable &var = cbuf.variables[v];
if(var.name == "RENDERDOC_TexDim")
{
if(var.type.descriptor.rows == 1 &&
var.type.descriptor.cols == 4 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
{
uint32_t *d = (uint32_t *)(byteData + var.descriptor.offset);
d[0] = details.texWidth;
d[1] = details.texHeight;
d[2] = details.texType == D3D11DebugManager::eTexType_3D ? details.texDepth : details.texArraySize;
d[3] = details.texMips;
}
else
{
RDCWARN("Custom shader: Variable recognised but type wrong, expected uint4: %hs", var.name.c_str());
}
}
else if(var.name == "RENDERDOC_SelectedMip")
{
if(var.type.descriptor.rows == 1 &&
var.type.descriptor.cols == 1 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
{
uint32_t *d = (uint32_t *)(byteData + var.descriptor.offset);
d[0] = cfg.mip;
}
else
{
RDCWARN("Custom shader: Variable recognised but type wrong, expected uint: %hs", var.name.c_str());
}
}
else if(var.name == "RENDERDOC_TextureType")
{
if(var.type.descriptor.rows == 1 &&
var.type.descriptor.cols == 1 &&
var.type.descriptor.type == DXBC::VARTYPE_UINT)
{
uint32_t *d = (uint32_t *)(byteData + var.descriptor.offset);
d[0] = details.texType;
}
else
{
RDCWARN("Custom shader: Variable recognised but type wrong, expected uint: %hs", var.name.c_str());
}
}
else
{
RDCWARN("Custom shader: Variable not recognised: %hs", var.name.c_str());
}
}
customBuff = MakeCBuffer(cbufData, cbuf.descriptor.byteSize);
}
}
}
}
vertexData.Scale *= 2.0f; // viewport is -1 -> 1
pixelData.MipLevel = (float)cfg.mip;
ID3D11Buffer *bufs[2] = { m_DebugRender.PosBuffer, m_Font.CharBuffer };
UINT stride = 3*sizeof(float);
UINT offset = 0;
pixelData.OutputDisplayFormat = RESTYPE_TEX2D;
pixelData.Slice = float(RDCCLAMP(cfg.sliceFace, 0U, details.texArraySize-1));
if(details.texType == eTexType_3D)
{
pixelData.OutputDisplayFormat = RESTYPE_TEX3D;
pixelData.Slice = float(cfg.sliceFace)/float(details.texDepth);
}
else if(details.texType == eTexType_1D)
{
pixelData.OutputDisplayFormat = RESTYPE_TEX1D;
}
else if(details.texType == eTexType_Depth)
{
pixelData.OutputDisplayFormat = RESTYPE_DEPTH;
}
else if(details.texType == eTexType_Stencil)
{
pixelData.OutputDisplayFormat = RESTYPE_DEPTH_STENCIL;
}
else if(details.texType == eTexType_DepthMS)
{
pixelData.OutputDisplayFormat = RESTYPE_DEPTH_MS;
}
else if(details.texType == eTexType_StencilMS)
{
pixelData.OutputDisplayFormat = RESTYPE_DEPTH_STENCIL_MS;
}
else if(details.texType == eTexType_2DMS)
{
pixelData.OutputDisplayFormat = RESTYPE_TEX2D_MS;
}
if(cfg.overlay == eTexOverlay_NaN)
{
pixelData.OutputDisplayFormat |= TEXDISPLAY_NANS;
}
if(cfg.overlay == eTexOverlay_Clipping)
{
pixelData.OutputDisplayFormat |= TEXDISPLAY_CLIPPING;
}
int srvOffset = 0;
if(IsUIntFormat(details.texFmt))
{
pixelData.OutputDisplayFormat |= TEXDISPLAY_UINT_TEX;
srvOffset = 10;
}
if(IsIntFormat(details.texFmt))
{
pixelData.OutputDisplayFormat |= TEXDISPLAY_SINT_TEX;
srvOffset = 20;
}
if(!IsSRGBFormat(details.texFmt) && cfg.linearDisplayAsGamma)
{
pixelData.OutputDisplayFormat |= TEXDISPLAY_GAMMA_CURVE;
}
FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer));
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
// can't just clear state because we need to keep things like render targets.
{
m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
m_pImmediateContext->IASetVertexBuffers(0, 1, &m_DebugRender.PosBuffer, &stride, &offset);
m_pImmediateContext->VSSetShader(m_DebugRender.GenericVS, NULL, 0);
m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer);
m_pImmediateContext->HSSetShader(NULL, NULL, 0);
m_pImmediateContext->DSSetShader(NULL, NULL, 0);
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
m_pImmediateContext->RSSetState(m_DebugRender.RastState);
if(customPS == NULL)
{
m_pImmediateContext->PSSetShader(m_DebugRender.TexDisplayPS, NULL, 0);
m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer);
}
else
{
m_pImmediateContext->PSSetShader(customPS, NULL, 0);
m_pImmediateContext->PSSetConstantBuffers(0, 1, &customBuff);
}
ID3D11UnorderedAccessView *NullUAVs[D3D11_PS_CS_UAV_REGISTER_COUNT] = { 0 };
UINT UAV_keepcounts[D3D11_PS_CS_UAV_REGISTER_COUNT] = { (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1, (UINT)-1 };
m_pImmediateContext->CSSetUnorderedAccessViews(0, D3D11_PS_CS_UAV_REGISTER_COUNT, NullUAVs, UAV_keepcounts);
m_pImmediateContext->PSSetShaderResources(srvOffset, eTexType_Max, details.srv);
ID3D11SamplerState *samps[] = { m_DebugRender.PointSampState, m_DebugRender.LinearSampState };
m_pImmediateContext->PSSetSamplers(0, 2, samps);
float factor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
if(cfg.rawoutput)
m_pImmediateContext->OMSetBlendState(NULL, factor, 0xffffffff);
else
m_pImmediateContext->OMSetBlendState(m_DebugRender.BlendState, factor, 0xffffffff);
m_pImmediateContext->Draw(4, 0);
}
return true;
}
void D3D11DebugManager::RenderHighlightBox(float w, float h, float scale)
{
UINT stride = 3*sizeof(float);
UINT offs = 0;
D3D11RenderStateTracker tracker(m_WrappedContext);
float overlayConsts[] = { 1.0f, 1.0f, 1.0f, 1.0f };
ID3D11Buffer *vconst = NULL;
ID3D11Buffer *pconst = NULL;
pconst = MakeCBuffer(overlayConsts, sizeof(overlayConsts));
const float xpixdim = 2.0f/w;
const float ypixdim = 2.0f/h;
const float xdim = scale*xpixdim;
const float ydim = scale*ypixdim;
DebugVertexCBuffer vertCBuffer;
RDCEraseEl(vertCBuffer);
vertCBuffer.Scale = 1.0f;
vertCBuffer.ScreenAspect.x = vertCBuffer.ScreenAspect.y = 1.0f;
vertCBuffer.Position.x = 1.0f;
vertCBuffer.Position.y = -1.0f;
vertCBuffer.TextureResolution.x = xdim;
vertCBuffer.TextureResolution.y = ydim;
vconst = MakeCBuffer((float *)&vertCBuffer, sizeof(vertCBuffer));
m_pImmediateContext->HSSetShader(NULL, NULL, 0);
m_pImmediateContext->DSSetShader(NULL, NULL, 0);
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
m_pImmediateContext->RSSetState(m_DebugRender.RastState);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP);
m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout);
m_pImmediateContext->IASetVertexBuffers(0, 1, &m_DebugRender.OutlineStripVB, &stride, &offs);
m_pImmediateContext->VSSetShader(m_DebugRender.GenericVS, NULL, 0);
m_pImmediateContext->PSSetShader(m_DebugRender.OverlayPS, NULL, 0);
m_pImmediateContext->OMSetBlendState(NULL, NULL, 0xffffffff);
m_pImmediateContext->PSSetConstantBuffers(1, 1, &pconst);
m_pImmediateContext->VSSetConstantBuffers(0, 1, &vconst);
m_pImmediateContext->Draw(5, 0);
vertCBuffer.Position.x = 1.0f-xpixdim;
vertCBuffer.Position.y = -1.0f+ypixdim;
vertCBuffer.TextureResolution.x = xdim+xpixdim*2;
vertCBuffer.TextureResolution.y = ydim+ypixdim*2;
overlayConsts[0] = overlayConsts[1] = overlayConsts[2] = 0.0f;
vconst = MakeCBuffer((float *)&vertCBuffer, sizeof(vertCBuffer));
pconst = MakeCBuffer(overlayConsts, sizeof(overlayConsts));
m_pImmediateContext->VSSetConstantBuffers(0, 1, &vconst);
m_pImmediateContext->PSSetConstantBuffers(1, 1, &pconst);
m_pImmediateContext->Draw(5, 0);
}
void D3D11DebugManager::RenderCheckerboard(Vec3f light, Vec3f dark)
{
DebugVertexCBuffer vertexData;
D3D11RenderStateTracker tracker(m_WrappedContext);
vertexData.Scale = 2.0f;
vertexData.Position.x = vertexData.Position.y = 0;
vertexData.ScreenAspect.x = 1.0f;
vertexData.ScreenAspect.y = 1.0f;
vertexData.TextureResolution.x = 1.0f;
vertexData.TextureResolution.y = 1.0f;
FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer));
DebugPixelCBufferData pixelData;
pixelData.Channels = Vec4f(light.x, light.y, light.z, 0.0f);
pixelData.WireframeColour = dark;
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
UINT stride = 3*sizeof(float);
UINT offset = 0;
// can't just clear state because we need to keep things like render targets.
{
m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
m_pImmediateContext->IASetVertexBuffers(0, 1, &m_DebugRender.PosBuffer, &stride, &offset);
m_pImmediateContext->VSSetShader(m_DebugRender.GenericVS, NULL, 0);
m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer);
m_pImmediateContext->HSSetShader(NULL, NULL, 0);
m_pImmediateContext->DSSetShader(NULL, NULL, 0);
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
m_pImmediateContext->RSSetState(m_DebugRender.RastState);
m_pImmediateContext->PSSetShader(m_DebugRender.CheckerboardPS, NULL, 0);
m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer);
float factor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
m_pImmediateContext->OMSetBlendState(NULL, factor, 0xffffffff);
m_pImmediateContext->Draw(4, 0);
}
}
PostVSData D3D11DebugManager::GetPostVSBuffers(uint32_t frameID, uint32_t eventID)
{
auto idx = std::make_pair(frameID, eventID);
if(m_PostVSData.find(idx) != m_PostVSData.end())
return m_PostVSData[idx];
RDCWARN("Post VS Buffers not initialised!");
PostVSData empty;
RDCEraseEl(empty);
return empty;
}
PostVSMeshData D3D11DebugManager::GetPostVSBuffers(uint32_t frameID, uint32_t eventID, MeshDataStage stage)
{
PostVSMeshData ret;
PostVSData postvs = GetPostVSBuffers(frameID, eventID);
PostVSData::StageData s = postvs.GetStage(stage);
ret.numVerts = s.numVerts;
ret.topo = (PrimitiveTopology)s.topo;
if(s.buf != NULL)
ret.buf = GetBufferData(s.buf, 0, 0);
else
RDCWARN("No buffer for this stage!");
return ret;
}
void D3D11DebugManager::InitPostVSBuffers(uint32_t frameID, uint32_t eventID)
{
auto idx = std::make_pair(frameID, eventID);
if(m_PostVSData.find(idx) != m_PostVSData.end())
return;
D3D11RenderStateTracker tracker(m_WrappedContext);
ID3D11VertexShader *vs = NULL;
m_pImmediateContext->VSGetShader(&vs, NULL, NULL);
ID3D11GeometryShader *gs = NULL;
m_pImmediateContext->GSGetShader(&gs, NULL, NULL);
ID3D11HullShader *hs = NULL;
m_pImmediateContext->HSGetShader(&hs, NULL, NULL);
ID3D11DomainShader *ds = NULL;
m_pImmediateContext->DSGetShader(&ds, NULL, NULL);
if(vs) vs->Release();
if(gs) gs->Release();
if(hs) hs->Release();
if(ds) ds->Release();
if(!vs)
return;
D3D11_PRIMITIVE_TOPOLOGY topo;
m_pImmediateContext->IAGetPrimitiveTopology(&topo);
WrappedID3D11Shader<ID3D11VertexShader> *wrappedVS = (WrappedID3D11Shader<ID3D11VertexShader> *)m_WrappedDevice->GetResourceManager()->GetWrapper(vs);
if(!wrappedVS)
{
RDCERR("Couldn't find wrapped vertex shader!");
return;
}
DXBC::DXBCFile *dxbcVS = wrappedVS->GetDXBC();
RDCASSERT(dxbcVS);
DXBC::DXBCFile *dxbcGS = NULL;
if(gs)
{
WrappedID3D11Shader<ID3D11GeometryShader> *wrappedGS = (WrappedID3D11Shader<ID3D11GeometryShader> *)m_WrappedDevice->GetResourceManager()->GetWrapper(gs);
if(!wrappedGS)
{
RDCERR("Couldn't find wrapped geometry shader!");
return;
}
dxbcGS = wrappedGS->GetDXBC();
RDCASSERT(dxbcGS);
}
DXBC::DXBCFile *dxbcDS = NULL;
if(ds)
{
WrappedID3D11Shader<ID3D11DomainShader> *wrappedDS = (WrappedID3D11Shader<ID3D11DomainShader> *)m_WrappedDevice->GetResourceManager()->GetWrapper(ds);
if(!wrappedDS)
{
RDCERR("Couldn't find wrapped domain shader!");
return;
}
dxbcDS = wrappedDS->GetDXBC();
RDCASSERT(dxbcDS);
}
vector<D3D11_SO_DECLARATION_ENTRY> sodecls;
UINT stride = 0;
UINT posoffset = ~0U;
int numPosComponents = 0;
ID3D11GeometryShader *streamoutGS = NULL;
if(!dxbcVS->m_OutputSig.empty())
{
for(size_t i=0; i < dxbcVS->m_OutputSig.size(); i++)
{
SigParameter &sign = dxbcVS->m_OutputSig[i];
D3D11_SO_DECLARATION_ENTRY decl;
decl.Stream = 0;
decl.OutputSlot = 0;
decl.SemanticName = sign.semanticName.elems;
decl.SemanticIndex = sign.semanticIndex;
decl.StartComponent = 0;
decl.ComponentCount = sign.compCount&0xff;
string a = strupper(string(decl.SemanticName));
if(a.find("POSITION") != string::npos)
{
// force to 4 components, as we need it, and store its offset
if(a.find("SV_POSITION") != string::npos)
decl.ComponentCount = 4;
numPosComponents = decl.ComponentCount;
posoffset = stride;
}
stride += decl.ComponentCount * sizeof(float);
sodecls.push_back(decl);
}
HRESULT hr = m_pDevice->CreateGeometryShaderWithStreamOutput(
(void *)&dxbcVS->m_ShaderBlob[0],
dxbcVS->m_ShaderBlob.size(),
&sodecls[0],
(UINT)sodecls.size(),
&stride,
1,
D3D11_SO_NO_RASTERIZED_STREAM,
NULL,
&streamoutGS);
if(FAILED(hr))
{
RDCERR("Failed to create Geometry Shader + SO %08x", hr);
return;
}
m_pImmediateContext->GSSetShader(streamoutGS, NULL, 0);
m_pImmediateContext->HSSetShader(NULL, NULL, 0);
m_pImmediateContext->DSSetShader(NULL, NULL, 0);
SAFE_RELEASE(streamoutGS);
UINT offset = 0;
m_pImmediateContext->SOSetTargets( 1, &m_SOBuffer, &offset );
m_pImmediateContext->Begin(m_SOStatsQuery);
m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw);
m_pImmediateContext->End(m_SOStatsQuery);
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
m_pImmediateContext->SOSetTargets(0, NULL, NULL);
D3D11_QUERY_DATA_SO_STATISTICS numPrims;
m_pImmediateContext->CopyResource(m_SOStagingBuffer, m_SOBuffer);
do
{
hr = m_pImmediateContext->GetData(m_SOStatsQuery, &numPrims, sizeof(D3D11_QUERY_DATA_SO_STATISTICS ), 0);
} while(hr == S_FALSE);
if(numPrims.NumPrimitivesWritten == 0)
{
m_PostVSData[idx] = PostVSData();
return;
}
D3D11_MAPPED_SUBRESOURCE mapped;
hr = m_pImmediateContext->Map(m_SOStagingBuffer, 0, D3D11_MAP_READ, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Failed to map sobuffer %08x", hr);
return;
}
D3D11_BUFFER_DESC bufferDesc =
{
stride * (uint32_t)numPrims.NumPrimitivesWritten*3,
D3D11_USAGE_IMMUTABLE,
D3D11_BIND_VERTEX_BUFFER,
0,
0,
0
};
if(bufferDesc.ByteWidth >= m_SOBufferSize)
{
RDCERR("Generated output data too large: %08x", bufferDesc.ByteWidth);
m_pImmediateContext->Unmap(m_SOStagingBuffer, 0);
return;
}
ID3D11Buffer *vsoutBuffer = NULL;
// we need to map this data into memory for read anyway, might as well make this VB
// immutable while we're at it.
D3D11_SUBRESOURCE_DATA initialData;
initialData.pSysMem = mapped.pData;
initialData.SysMemPitch = bufferDesc.ByteWidth;
initialData.SysMemSlicePitch = bufferDesc.ByteWidth;
hr = m_WrappedDevice->CreateBuffer( &bufferDesc, &initialData, &vsoutBuffer );
if(FAILED(hr))
{
RDCERR("Failed to create postvs pos buffer %08x", hr);
m_pImmediateContext->Unmap(m_SOStagingBuffer, 0);
return;
}
byte *byteData = (byte *)mapped.pData;
float nearp = 0.0f;
float farp = 0.0f;
Vec4f *pos0 = (Vec4f *)(byteData + posoffset);
for(UINT64 i=1; numPosComponents == 4 && i < numPrims.NumPrimitivesWritten; i++)
{
//////////////////////////////////////////////////////////////////////////////////
// derive near/far, assuming a standard perspective matrix
//
// the transformation from from pre-projection {Z,W} to post-projection {Z,W}
// is linear. So we can say Zpost = Zpre*m + c . Here we assume Wpre = 1
// and we know Wpost = Zpre from the perspective matrix.
// we can then see from the perspective matrix that
// m = F/(F-N)
// c = -(F*N)/(F-N)
//
// with re-arranging and substitution, we then get:
// N = -c/m
// F = c/(1-m)
//
// so if we can derive m and c then we can determine N and F. We can do this with
// two points, and we pick them reasonably distinct on z to reduce floating-point
// error
Vec4f *pos = (Vec4f *)(byteData + posoffset + i*stride);
if(fabs(pos->w - pos0->w) > 0.01f)
{
Vec2f A(pos0->w, pos0->z);
Vec2f B(pos->w, pos->z);
float m = (B.y-A.y)/(B.x-A.x);
float c = B.y - B.x*m;
if(m == 1.0f) continue;
nearp = -c/m;
farp = c/(1-m);
break;
}
}
m_pImmediateContext->Unmap(m_SOStagingBuffer, 0);
m_PostVSData[idx].vsin.topo = topo;
m_PostVSData[idx].vsout.buf = vsoutBuffer;
m_PostVSData[idx].vsout.posOffset = posoffset;
m_PostVSData[idx].vsout.vertStride = stride;
m_PostVSData[idx].vsout.numPrims = (uint32_t)numPrims.NumPrimitivesWritten;
m_PostVSData[idx].vsout.nearPlane = nearp;
m_PostVSData[idx].vsout.farPlane = farp;
m_PostVSData[idx].vsout.topo = topo;
}
else
{
// empty vertex output signature
m_PostVSData[idx].vsin.topo = topo;
m_PostVSData[idx].vsout.buf = NULL;
m_PostVSData[idx].vsout.posOffset = ~0U;
m_PostVSData[idx].vsout.vertStride = 0;
m_PostVSData[idx].vsout.numPrims = 0;
m_PostVSData[idx].vsout.nearPlane = 0.0f;
m_PostVSData[idx].vsout.farPlane = 0.0f;
m_PostVSData[idx].vsout.topo = topo;
}
// streamout expands strips unfortunately
if(topo == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP)
m_PostVSData[idx].vsout.topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
else if(topo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP)
m_PostVSData[idx].vsout.topo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
else if(topo == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ)
m_PostVSData[idx].vsout.topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ;
else if(topo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ)
m_PostVSData[idx].vsout.topo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
switch(m_PostVSData[idx].vsout.topo)
{
case D3D11_PRIMITIVE_TOPOLOGY_POINTLIST:
m_PostVSData[idx].vsout.numVerts = m_PostVSData[idx].vsout.numPrims; break;
case D3D11_PRIMITIVE_TOPOLOGY_LINELIST:
m_PostVSData[idx].vsout.numVerts = m_PostVSData[idx].vsout.numPrims*2; break;
default:
case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST:
m_PostVSData[idx].vsout.numVerts = m_PostVSData[idx].vsout.numPrims*3; break;
}
if(dxbcGS || dxbcDS)
{
stride = 0;
posoffset = ~0U;
numPosComponents = 0;
DXBC::DXBCFile *lastShader = dxbcGS;
if(dxbcDS) lastShader = dxbcDS;
sodecls.clear();
for(size_t i=0; i < lastShader->m_OutputSig.size(); i++)
{
SigParameter &sign = lastShader->m_OutputSig[i];
D3D11_SO_DECLARATION_ENTRY decl;
// for now, skip streams that aren't stream 0
if(sign.stream != 0)
continue;
decl.Stream = 0;
decl.OutputSlot = 0;
decl.SemanticName = sign.semanticName.elems;
decl.SemanticIndex = sign.semanticIndex;
decl.StartComponent = 0;
decl.ComponentCount = sign.compCount&0xff;
string a = strupper(string(decl.SemanticName));
// force to 4 components, as we need it, and store its offset
if(a.find("POSITION") != string::npos)
{
// force to 4 components, as we need it, and store its offset
if(a.find("SV_POSITION") != string::npos)
decl.ComponentCount = 4;
numPosComponents = decl.ComponentCount;
posoffset = stride;
}
stride += decl.ComponentCount * sizeof(float);
sodecls.push_back(decl);
}
streamoutGS = NULL;
HRESULT hr = m_pDevice->CreateGeometryShaderWithStreamOutput(
(void *)&lastShader->m_ShaderBlob[0],
lastShader->m_ShaderBlob.size(),
&sodecls[0],
(UINT)sodecls.size(),
&stride,
1,
D3D11_SO_NO_RASTERIZED_STREAM,
NULL,
&streamoutGS);
if(FAILED(hr))
{
RDCERR("Failed to create Geometry Shader + SO %08x", hr);
return;
}
m_pImmediateContext->GSSetShader(streamoutGS, NULL, 0);
m_pImmediateContext->HSSetShader(hs, NULL, 0);
m_pImmediateContext->DSSetShader(ds, NULL, 0);
SAFE_RELEASE(streamoutGS);
UINT offset = 0;
m_pImmediateContext->SOSetTargets( 1, &m_SOBuffer, &offset );
m_pImmediateContext->Begin(m_SOStatsQuery);
m_WrappedDevice->ReplayLog(frameID, 0, eventID, eReplay_OnlyDraw);
m_pImmediateContext->End(m_SOStatsQuery);
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
m_pImmediateContext->SOSetTargets(0, NULL, NULL);
D3D11_QUERY_DATA_SO_STATISTICS numPrims;
m_pImmediateContext->CopyResource(m_SOStagingBuffer, m_SOBuffer);
do
{
hr = m_pImmediateContext->GetData(m_SOStatsQuery, &numPrims, sizeof(D3D11_QUERY_DATA_SO_STATISTICS ), 0);
} while(hr == S_FALSE);
if(numPrims.NumPrimitivesWritten == 0)
{
return;
}
D3D11_MAPPED_SUBRESOURCE mapped;
hr = m_pImmediateContext->Map(m_SOStagingBuffer, 0, D3D11_MAP_READ, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Failed to map sobuffer %08x", hr);
return;
}
D3D11_BUFFER_DESC bufferDesc =
{
stride * (uint32_t)numPrims.NumPrimitivesWritten*3,
D3D11_USAGE_IMMUTABLE,
D3D11_BIND_VERTEX_BUFFER,
0,
0,
0
};
if(bufferDesc.ByteWidth >= m_SOBufferSize)
{
RDCERR("Generated output data too large: %08x", bufferDesc.ByteWidth);
m_pImmediateContext->Unmap(m_SOStagingBuffer, 0);
return;
}
ID3D11Buffer *gsoutBuffer = NULL;
// we need to map this data into memory for read anyway, might as well make this VB
// immutable while we're at it.
D3D11_SUBRESOURCE_DATA initialData;
initialData.pSysMem = mapped.pData;
initialData.SysMemPitch = bufferDesc.ByteWidth;
initialData.SysMemSlicePitch = bufferDesc.ByteWidth;
hr = m_WrappedDevice->CreateBuffer( &bufferDesc, &initialData, &gsoutBuffer );
if(FAILED(hr))
{
RDCERR("Failed to create postvs pos buffer %08x", hr);
m_pImmediateContext->Unmap(m_SOStagingBuffer, 0);
return;
}
byte *byteData = (byte *)mapped.pData;
float nearp = 0.0f;
float farp = 0.0f;
Vec4f *pos0 = (Vec4f *)(byteData + posoffset);
for(UINT64 i=1; numPosComponents == 4 && i < numPrims.NumPrimitivesWritten; i++)
{
//////////////////////////////////////////////////////////////////////////////////
// derive near/far, assuming a standard perspective matrix
//
// the transformation from from pre-projection {Z,W} to post-projection {Z,W}
// is linear. So we can say Zpost = Zpre*m + c . Here we assume Wpre = 1
// and we know Wpost = Zpre from the perspective matrix.
// we can then see from the perspective matrix that
// m = F/(F-N)
// c = -(F*N)/(F-N)
//
// with re-arranging and substitution, we then get:
// N = -c/m
// F = c/(1-m)
//
// so if we can derive m and c then we can determine N and F. We can do this with
// two points, and we pick them reasonably distinct on z to reduce floating-point
// error
Vec4f *pos = (Vec4f *)(byteData + posoffset + i*stride);
if(fabs(pos->w - pos0->w) > 0.01f)
{
Vec2f A(pos0->w, pos0->z);
Vec2f B(pos->w, pos->z);
float m = (B.y-A.y)/(B.x-A.x);
float c = B.y - B.x*m;
if(m == 1.0f) continue;
nearp = -c/m;
farp = c/(1-m);
break;
}
}
m_pImmediateContext->Unmap(m_SOStagingBuffer, 0);
m_PostVSData[idx].gsout.buf = gsoutBuffer;
m_PostVSData[idx].gsout.posOffset = posoffset;
m_PostVSData[idx].gsout.vertStride = stride;
m_PostVSData[idx].gsout.numPrims = (uint32_t)numPrims.NumPrimitivesWritten;
m_PostVSData[idx].gsout.nearPlane = nearp;
m_PostVSData[idx].gsout.farPlane = farp;
D3D11_PRIMITIVE_TOPOLOGY topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
if(lastShader == dxbcGS)
{
for(size_t i=0; i < dxbcGS->m_Declarations.size(); i++)
{
if(dxbcGS->m_Declarations[i].declaration == DXBC::OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY)
{
topo = (D3D11_PRIMITIVE_TOPOLOGY)dxbcGS->m_Declarations[i].outTopology; // enums match
break;
}
}
}
else if(lastShader == dxbcDS)
{
for(size_t i=0; i < dxbcDS->m_Declarations.size(); i++)
{
if(dxbcDS->m_Declarations[i].declaration == DXBC::OPCODE_DCL_TESS_DOMAIN)
{
if(dxbcDS->m_Declarations[i].domain == DXBC::DOMAIN_ISOLINE)
topo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
else
topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
break;
}
}
}
m_PostVSData[idx].gsout.topo = topo;
// streamout expands strips unfortunately
if(topo == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP)
m_PostVSData[idx].gsout.topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
else if(topo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP)
m_PostVSData[idx].gsout.topo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
else if(topo == D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ)
m_PostVSData[idx].gsout.topo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ;
else if(topo == D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ)
m_PostVSData[idx].gsout.topo = D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
switch(m_PostVSData[idx].gsout.topo)
{
case D3D11_PRIMITIVE_TOPOLOGY_POINTLIST:
m_PostVSData[idx].gsout.numVerts = m_PostVSData[idx].gsout.numPrims; break;
case D3D11_PRIMITIVE_TOPOLOGY_LINELIST:
m_PostVSData[idx].gsout.numVerts = m_PostVSData[idx].gsout.numPrims*2; break;
default:
case D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST:
m_PostVSData[idx].gsout.numVerts = m_PostVSData[idx].gsout.numPrims*3; break;
}
}
}
void D3D11DebugManager::RenderMesh(uint32_t frameID, const vector<uint32_t> &events, MeshDisplay cfg)
{
DebugVertexCBuffer vertexData;
D3D11PipelineState pipeState = m_WrappedDevice->GetReplay()->GetD3D11PipelineState();
D3D11RenderState *curRS = m_WrappedDevice->GetImmediateContext()->GetCurrentPipelineState();
float aspect = 1.0f;
// guess the output aspect ratio, for mesh calculation
if(pipeState.m_OM.DepthTarget.Resource != ResourceId())
{
FetchTexture desc = m_WrappedDevice->GetReplay()->GetTexture(m_ResourceManager->GetLiveID(pipeState.m_OM.DepthTarget.Resource));
aspect = float(desc.width)/float(desc.height);
}
else
{
for(int32_t i=0; i < pipeState.m_OM.RenderTargets.count; i++)
{
if(pipeState.m_OM.RenderTargets[i].Resource != ResourceId())
{
FetchTexture desc = m_WrappedDevice->GetReplay()->GetTexture(m_ResourceManager->GetLiveID(pipeState.m_OM.RenderTargets[i].Resource));
aspect = float(desc.width)/float(desc.height);
break;
}
}
}
Matrix4f projMat = Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, float(GetWidth())/float(GetHeight()));
Camera cam;
if(cfg.arcballCamera)
cam.Arcball(cfg.cameraPos.x, Vec3f(cfg.cameraRot.x, cfg.cameraRot.y, cfg.cameraRot.z));
else
cam.fpsLook(Vec3f(cfg.cameraPos.x, cfg.cameraPos.y, cfg.cameraPos.z), Vec3f(cfg.cameraRot.x, cfg.cameraRot.y, cfg.cameraRot.z));
Matrix4f camMat = cam.GetMatrix();
Matrix4f guessProjInv;
vertexData.ModelViewProj = projMat.Mul(camMat);
vertexData.SpriteSize = Vec2f();
DebugPixelCBufferData pixelData;
pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID;
pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 0.0f);
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer);
m_pImmediateContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0);
m_pImmediateContext->HSSetShader(NULL, NULL, 0);
m_pImmediateContext->DSSetShader(NULL, NULL, 0);
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
m_pImmediateContext->OMSetDepthStencilState(NULL, 0);
m_pImmediateContext->OMSetBlendState(m_WireframeHelpersBS, NULL, 0xffffffff);
// don't cull in wireframe mesh display
/*
if(pipeState.m_RS.m_State.CullMode != eCull_None && pipeState.m_RS.m_State.FrontCCW)
m_pImmediateContext->RSSetState(m_WireframeHelpersCullCWRS);
else if(pipeState.m_RS.m_State.CullMode != eCull_None && !pipeState.m_RS.m_State.FrontCCW)
m_pImmediateContext->RSSetState(m_WireframeHelpersCullCCWRS);
else
*/
m_pImmediateContext->RSSetState(m_WireframeHelpersRS);
if((cfg.type != eMeshDataStage_VSIn && pipeState.m_HS.Shader == ResourceId()) ||
(cfg.type == eMeshDataStage_GSOut && pipeState.m_HS.Shader != ResourceId()))
{
float nearp = 0.1f;
float farp = 1000.0f;
for(size_t i=0; i < events.size(); i++)
{
PostVSData data = GetPostVSBuffers(frameID, events[i]);
const PostVSData::StageData &stage = data.GetStage(cfg.type);
if(stage.buf && stage.nearPlane != stage.farPlane)
{
nearp = stage.nearPlane;
farp = stage.farPlane;
break;
}
}
// the derivation of the projection matrix might not be right (hell, it could be an
// orthographic projection). But it'll be close enough likely.
Matrix4f guessProj = Matrix4f::Perspective(cfg.fov,
cfg.nearPlane > -FLT_MAX ? cfg.nearPlane : nearp,
cfg.farPlane > -FLT_MAX ? cfg.farPlane : farp,
cfg.aspect > 0.0f ? cfg.aspect : aspect);
if(cfg.ortho)
{
guessProj = Matrix4f::Orthographic(cfg.nearPlane > -FLT_MAX ? cfg.nearPlane : nearp,
cfg.farPlane > -FLT_MAX ? cfg.farPlane : farp);
}
guessProjInv = guessProj.Inverse();
vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer));
m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer);
m_pImmediateContext->VSSetShader(m_DebugRender.WireframeHomogVS, NULL, 0);
m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer);
m_pImmediateContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0);
{
m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericHomogLayout);
if(events.size() > 1)
{
pixelData.WireframeColour = Vec3f(cfg.prevMeshColour.x, cfg.prevMeshColour.y, cfg.prevMeshColour.z);
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
}
for(size_t i=0; i < events.size()-1; i++)
{
PostVSData data = GetPostVSBuffers(frameID, events[i]);
const PostVSData::StageData &stage = data.GetStage(cfg.type);
if(stage.buf)
{
if(stage.topo < D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ)
{
m_pImmediateContext->IASetPrimitiveTopology(stage.topo);
ID3D11Buffer *buf = UNWRAP(WrappedID3D11Buffer, stage.buf);
m_pImmediateContext->IASetVertexBuffers(0, 1, &buf, (UINT *)&stage.vertStride, (UINT *)&stage.posOffset);
m_pImmediateContext->Draw(stage.numVerts, 0);
}
}
}
pixelData.WireframeColour = Vec3f(cfg.currentMeshColour.x, cfg.currentMeshColour.y, cfg.currentMeshColour.z);
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
PostVSData data = GetPostVSBuffers(frameID, events.back());
const PostVSData::StageData &stage = data.GetStage(cfg.type);
if(stage.buf)
{
if(stage.topo < D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ)
{
m_pImmediateContext->IASetPrimitiveTopology(stage.topo);
ID3D11Buffer *buf = UNWRAP(WrappedID3D11Buffer, stage.buf);
m_pImmediateContext->IASetVertexBuffers(0, 1, &buf, (UINT *)&stage.vertStride, (UINT *)&stage.posOffset);
m_pImmediateContext->Draw(stage.numVerts, 0);
}
}
}
}
else
{
FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer));
m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer);
m_pImmediateContext->VSSetShader(m_DebugRender.MeshVS, NULL, 0);
m_pImmediateContext->PSSetShader(m_DebugRender.MeshPS, NULL, 0);
if(m_PrevMeshInputLayout != curRS->IA.Layout)
{
SAFE_RELEASE(m_MeshDisplayLayout);
m_PrevMeshInputLayout = curRS->IA.Layout;
const vector<D3D11_INPUT_ELEMENT_DESC> curLayout = m_WrappedDevice->GetLayoutDesc(curRS->IA.Layout);
vector<D3D11_INPUT_ELEMENT_DESC> layoutdesc;
byte elems = 0;
int buffers[3] = {0,0,0};
for(size_t i=0; i < curLayout.size(); i++)
{
const D3D11_INPUT_ELEMENT_DESC &layout = curLayout[i];
if((!_stricmp(layout.SemanticName, "POSITION") || !_stricmp(layout.SemanticName, "SV_Position")) &&
layout.SemanticIndex == 0) // need to get name from input config
{
D3D11_INPUT_ELEMENT_DESC el = layout;
el.SemanticName = "pos"; // these are the known values since they match WireframeVS
el.SemanticIndex = 0;
layoutdesc.push_back(el);
buffers[0] = layout.InputSlot;
elems |= 0x1;
}
else if(!_stricmp(layout.SemanticName, "TEXCOORD") && layout.SemanticIndex == 0)
{
D3D11_INPUT_ELEMENT_DESC el = layout;
el.SemanticName = "tex"; // these are the known values since they match WireframeVS
el.SemanticIndex = 0;
layoutdesc.push_back(el);
buffers[1] = layout.InputSlot;
elems |= 0x2;
}
else if(!_stricmp(layout.SemanticName, "COLOR") && layout.SemanticIndex == 0)
{
D3D11_INPUT_ELEMENT_DESC el = layout;
el.SemanticName = "col"; // these are the known values since they match WireframeVS
el.SemanticIndex = 0;
layoutdesc.push_back(el);
buffers[2] = layout.InputSlot;
elems |= 0x4;
}
}
for(m_MeshDisplayNULLVB = 0; m_MeshDisplayNULLVB < 4; m_MeshDisplayNULLVB++)
{
bool used = false;
for(int i=0; i < 3; i++)
{
if(elems & (1<<i) && buffers[i] == m_MeshDisplayNULLVB)
{
used = true;
break;
}
}
if(!used)
break;
}
if((elems & 0x1) == 0)
{
RDCWARN("No position element!");
return;
}
if((elems & 0x2) == 0)
{
D3D11_INPUT_ELEMENT_DESC el;
el.SemanticName = "tex"; // these are the known values since they match WireframeVS
el.SemanticIndex = 0;
el.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
el.AlignedByteOffset = 0;
el.InputSlot = m_MeshDisplayNULLVB;
el.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
el.InstanceDataStepRate = 0;
layoutdesc.push_back(el);
}
if((elems & 0x4) == 0)
{
D3D11_INPUT_ELEMENT_DESC el;
el.SemanticName = "col"; // these are the known values since they match WireframeVS
el.SemanticIndex = 0;
el.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
el.AlignedByteOffset = 0;
el.InputSlot = m_MeshDisplayNULLVB;
el.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
el.InstanceDataStepRate = 0;
layoutdesc.push_back(el);
}
RDCASSERT(layoutdesc.size() == 3);
if(layoutdesc.size() != 3)
return;
HRESULT hr = m_pDevice->CreateInputLayout(&layoutdesc[0], 3, m_DebugRender.MeshVSBytecode, m_DebugRender.MeshVSBytelen, &m_MeshDisplayLayout);
if(FAILED(hr))
{
RDCERR("Failed to create rendermesh input layout %08x", hr);
return;
}
}
if(m_MeshDisplayLayout == NULL)
{
RDCWARN("Couldn't get a mesh display layout");
return;
}
m_pImmediateContext->IASetInputLayout(m_MeshDisplayLayout);
ID3D11Buffer *vb = NULL;
UINT dummy = 4;
m_pImmediateContext->IASetVertexBuffers(m_MeshDisplayNULLVB, 1, &vb, &dummy, &dummy);
// draw solid shaded mode
if(cfg.solidShadeMode != eShade_None)
{
m_pImmediateContext->RSSetState(m_DebugRender.RastState);
pixelData.OutputDisplayFormat = (int)cfg.solidShadeMode;
pixelData.WireframeColour = Vec3f(0.8f, 0.8f, 0.0f);
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer);
if(cfg.solidShadeMode == eShade_Lit)
{
DebugGeometryCBuffer geomData;
geomData.InvProj = projMat.Inverse();
FillCBuffer(m_DebugRender.GenericGSCBuffer, (float *)&geomData, sizeof(DebugGeometryCBuffer));
m_pImmediateContext->GSSetConstantBuffers(0, 1, &m_DebugRender.GenericGSCBuffer);
m_pImmediateContext->GSSetShader(m_DebugRender.MeshGS, NULL, 0);
}
m_WrappedDevice->ReplayLog(frameID, 0, events[0], eReplay_OnlyDraw);
if(cfg.solidShadeMode == eShade_Lit)
m_pImmediateContext->GSSetShader(NULL, NULL, 0);
}
// draw wireframe mode
if(cfg.solidShadeMode == eShade_None || cfg.wireframeDraw)
{
m_pImmediateContext->RSSetState(m_WireframeHelpersRS);
m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.LEqualDepthState, 0);
pixelData.OutputDisplayFormat = MESHDISPLAY_SOLID;
pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 0.0f);
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer);
m_WrappedDevice->ReplayLog(frameID, 0, events[0], eReplay_OnlyDraw);
}
}
m_pImmediateContext->RSSetState(m_WireframeHelpersRS);
// set up state for drawing helpers
{
vertexData.ModelViewProj = projMat.Mul(camMat);
FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer));
m_pImmediateContext->RSSetState(m_SolidHelpersRS);
m_pImmediateContext->OMSetDepthStencilState(m_DebugRender.NoDepthState, 0);
m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_DebugRender.GenericVSCBuffer);
m_pImmediateContext->VSSetShader(m_DebugRender.WireframeVS, NULL, 0);
m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer);
m_pImmediateContext->PSSetShader(m_DebugRender.WireframePS, NULL, 0);
}
// axis markers
if(cfg.type == eMeshDataStage_VSIn ||
(cfg.type == eMeshDataStage_VSOut && pipeState.m_HS.Shader != ResourceId()))
{
m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_DebugRender.GenericPSCBuffer);
UINT strides[] = { sizeof(Vec3f) };
UINT offsets[] = { 0 };
m_pImmediateContext->IASetVertexBuffers(0, 1, &m_AxisHelper, strides, offsets);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout);
pixelData.WireframeColour = Vec3f(1.0f, 0.0f, 0.0f);
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
m_pImmediateContext->Draw(2, 0);
pixelData.WireframeColour = Vec3f(0.0f, 1.0f, 0.0f);
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
m_pImmediateContext->Draw(2, 2);
pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 1.0f);
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
m_pImmediateContext->Draw(2, 4);
}
if(cfg.showVerts)
{
// if data is from post transform, it will be in clipspace
if((cfg.type != eMeshDataStage_VSIn && pipeState.m_HS.Shader == ResourceId()) ||
(cfg.type == eMeshDataStage_GSOut && pipeState.m_HS.Shader != ResourceId()))
{
vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
m_pImmediateContext->VSSetShader(m_DebugRender.WireframeHomogVS, NULL, 0);
m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericHomogLayout);
}
else
{
vertexData.ModelViewProj = projMat.Mul(camMat);
m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout);
}
FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer));
pixelData.WireframeColour = Vec3f(1.0f, 0.0f, 0.0f);
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT hr = S_OK;
hr = m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Failde to map m_TriHighlightHelper %08x", hr);
return;
}
memcpy(mapped.pData, cfg.hilightVerts, sizeof(Vec4f)*3);
m_pImmediateContext->Unmap(m_TriHighlightHelper, 0);
UINT strides[] = { sizeof(Vec4f) };
UINT offsets[] = { 0 };
m_pImmediateContext->IASetVertexBuffers(0, 1, &m_TriHighlightHelper, (UINT *)&strides, (UINT *)&offsets);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_pImmediateContext->Draw(3, 0);
FloatVector vertSprite[4] = {
cfg.hilightVerts[0],
cfg.hilightVerts[0],
cfg.hilightVerts[0],
cfg.hilightVerts[0]
};
hr = m_pImmediateContext->Map(m_TriHighlightHelper, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
if(FAILED(hr))
{
RDCERR("Failde to map m_TriHighlightHelper %08x", hr);
return;
}
memcpy(mapped.pData, vertSprite, sizeof(vertSprite));
m_pImmediateContext->Unmap(m_TriHighlightHelper, 0);
float scale = 800.0f/float(GetHeight());
float asp = float(GetWidth())/float(GetHeight());
pixelData.WireframeColour = Vec3f(0.0f, 0.0f, 1.0f);
vertexData.SpriteSize = Vec2f(scale/asp, scale);
FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer));
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
m_pImmediateContext->Draw(4, 0);
if(cfg.type != eMeshDataStage_VSIn)
m_pImmediateContext->VSSetShader(m_DebugRender.WireframeVS, NULL, 0);
}
// 'fake' helper frustum
if((cfg.type != eMeshDataStage_VSIn && pipeState.m_HS.Shader == ResourceId()) ||
(cfg.type == eMeshDataStage_GSOut && pipeState.m_HS.Shader != ResourceId()))
{
UINT strides[] = { sizeof(Vec3f) };
UINT offsets[] = { 0 };
vertexData.SpriteSize = Vec2f();
vertexData.ModelViewProj = projMat.Mul(camMat.Mul(guessProjInv));
FillCBuffer(m_DebugRender.GenericVSCBuffer, (float *)&vertexData, sizeof(DebugVertexCBuffer));
m_pImmediateContext->IASetVertexBuffers(0, 1, &m_FrustumHelper, (UINT *)&strides, (UINT *)&offsets);
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
m_pImmediateContext->IASetInputLayout(m_DebugRender.GenericLayout);
pixelData.WireframeColour = Vec3f(0.5f, 0.5f, 0.5f);
FillCBuffer(m_DebugRender.GenericPSCBuffer, (float *)&pixelData, sizeof(DebugPixelCBufferData));
m_pImmediateContext->Draw(24, 0);
}
}