mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-23 06:05:45 +00:00
Implement font rendering on D3D12 with simple ring buffer (needs tidied)
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include "maths/matrix.h"
|
||||
#include "maths/vec.h"
|
||||
#include "serialise/string_utils.h"
|
||||
#include "stb/stb_truetype.h"
|
||||
#include "d3d12_command_queue.h"
|
||||
#include "d3d12_device.h"
|
||||
|
||||
@@ -92,6 +93,9 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
|
||||
m_WrappedDevice = wrapper;
|
||||
m_WrappedDevice->InternalRef();
|
||||
|
||||
m_width = m_height = 1;
|
||||
m_BBFmtIdx = BGRA8_BACKBUFFER;
|
||||
|
||||
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.0f);
|
||||
|
||||
m_pFactory = NULL;
|
||||
@@ -177,45 +181,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
|
||||
samp.ptr += m_WrappedDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
m_WrappedDevice->CreateSampler(&sampDesc, samp);
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps;
|
||||
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProps.CreationNodeMask = 1;
|
||||
heapProps.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_RESOURCE_DESC cbDesc;
|
||||
cbDesc.Alignment = 0;
|
||||
cbDesc.DepthOrArraySize = 1;
|
||||
cbDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
cbDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
cbDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
cbDesc.Height = 1;
|
||||
cbDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
cbDesc.MipLevels = 1;
|
||||
cbDesc.SampleDesc.Count = 1;
|
||||
cbDesc.SampleDesc.Quality = 0;
|
||||
cbDesc.Width = sizeof(DebugVertexCBuffer);
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(
|
||||
&heapProps, D3D12_HEAP_FLAG_NONE, &cbDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&m_GenericVSCbuffer);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create m_GenericVSCbuffer! 0x%08x", hr);
|
||||
}
|
||||
|
||||
cbDesc.Width = sizeof(DebugPixelCBufferData);
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(
|
||||
&heapProps, D3D12_HEAP_FLAG_NONE, &cbDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&m_GenericPSCbuffer);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create m_GenericPSCbuffer! 0x%08x", hr);
|
||||
}
|
||||
m_GenericVSCbuffer = MakeCBuffer(sizeof(DebugVertexCBuffer));
|
||||
m_GenericPSCbuffer = MakeCBuffer(sizeof(DebugPixelCBufferData));
|
||||
|
||||
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.4f);
|
||||
|
||||
@@ -278,6 +245,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
|
||||
__uuidof(ID3D12RootSignature),
|
||||
(void **)&m_TexDisplayRootSig);
|
||||
|
||||
SAFE_RELEASE(root);
|
||||
|
||||
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.6f);
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc;
|
||||
@@ -360,6 +329,275 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
|
||||
|
||||
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.8f);
|
||||
|
||||
// font rendering
|
||||
{
|
||||
D3D12_HEAP_PROPERTIES uploadHeap;
|
||||
uploadHeap.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
uploadHeap.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
uploadHeap.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
uploadHeap.CreationNodeMask = 1;
|
||||
uploadHeap.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_HEAP_PROPERTIES defaultHeap = uploadHeap;
|
||||
defaultHeap.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
|
||||
const int width = FONT_TEX_WIDTH, height = FONT_TEX_HEIGHT;
|
||||
|
||||
D3D12_RESOURCE_DESC bufDesc;
|
||||
bufDesc.Alignment = 0;
|
||||
bufDesc.DepthOrArraySize = 1;
|
||||
bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
bufDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
bufDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
bufDesc.Height = 1;
|
||||
bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
bufDesc.MipLevels = 1;
|
||||
bufDesc.SampleDesc.Count = 1;
|
||||
bufDesc.SampleDesc.Quality = 0;
|
||||
bufDesc.Width = width * height;
|
||||
|
||||
ID3D12Resource *uploadBuf = NULL;
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(&uploadHeap, D3D12_HEAP_FLAG_NONE, &bufDesc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&uploadBuf);
|
||||
|
||||
if(FAILED(hr))
|
||||
RDCERR("Failed to create uploadBuf %08x", hr);
|
||||
|
||||
D3D12_RESOURCE_DESC texDesc;
|
||||
texDesc.Alignment = 0;
|
||||
texDesc.DepthOrArraySize = 1;
|
||||
texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
texDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
texDesc.Format = DXGI_FORMAT_R8_UNORM;
|
||||
texDesc.Height = height;
|
||||
texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||
texDesc.MipLevels = 1;
|
||||
texDesc.SampleDesc.Count = 1;
|
||||
texDesc.SampleDesc.Quality = 0;
|
||||
texDesc.Width = width;
|
||||
|
||||
hr = m_WrappedDevice->CreateCommittedResource(&defaultHeap, D3D12_HEAP_FLAG_NONE, &texDesc,
|
||||
D3D12_RESOURCE_STATE_COPY_DEST, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&m_Font.Tex);
|
||||
|
||||
if(FAILED(hr))
|
||||
RDCERR("Failed to create m_Font.Tex %08x", hr);
|
||||
|
||||
string font = GetEmbeddedResource(sourcecodepro_ttf);
|
||||
byte *ttfdata = (byte *)font.c_str();
|
||||
|
||||
const int firstChar = int(' ') + 1;
|
||||
const int lastChar = 127;
|
||||
const int numChars = lastChar - firstChar;
|
||||
|
||||
byte *buf = new byte[width * height];
|
||||
|
||||
const float pixelHeight = 20.0f;
|
||||
|
||||
stbtt_bakedchar chardata[numChars];
|
||||
stbtt_BakeFontBitmap(ttfdata, 0, pixelHeight, buf, width, height, firstChar, numChars, chardata);
|
||||
|
||||
m_Font.CharSize = pixelHeight;
|
||||
m_Font.CharAspect = chardata->xadvance / pixelHeight;
|
||||
|
||||
stbtt_fontinfo f = {0};
|
||||
stbtt_InitFont(&f, ttfdata, 0);
|
||||
|
||||
int ascent = 0;
|
||||
stbtt_GetFontVMetrics(&f, &ascent, NULL, NULL);
|
||||
|
||||
float maxheight = float(ascent) * stbtt_ScaleForPixelHeight(&f, pixelHeight);
|
||||
|
||||
FillBuffer(uploadBuf, buf, width * height);
|
||||
|
||||
delete[] buf;
|
||||
|
||||
ID3D12GraphicsCommandList *list = m_WrappedDevice->GetNewList();
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION dst, src;
|
||||
|
||||
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
dst.pResource = m_Font.Tex;
|
||||
dst.SubresourceIndex = 0;
|
||||
|
||||
src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
src.pResource = uploadBuf;
|
||||
src.PlacedFootprint.Offset = 0;
|
||||
src.PlacedFootprint.Footprint.Width = width;
|
||||
src.PlacedFootprint.Footprint.Height = height;
|
||||
src.PlacedFootprint.Footprint.Depth = 1;
|
||||
src.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8_UNORM;
|
||||
src.PlacedFootprint.Footprint.RowPitch = width;
|
||||
|
||||
RDCCOMPILE_ASSERT(
|
||||
(width / D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * D3D12_TEXTURE_DATA_PITCH_ALIGNMENT == width,
|
||||
"Width isn't aligned!");
|
||||
|
||||
list->CopyTextureRegion(&dst, 0, 0, 0, &src, NULL);
|
||||
|
||||
D3D12_RESOURCE_BARRIER barrier = {};
|
||||
barrier.Transition.pResource = m_Font.Tex;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
|
||||
list->ResourceBarrier(1, &barrier);
|
||||
|
||||
list->Close();
|
||||
|
||||
m_WrappedDevice->ExecuteLists();
|
||||
m_WrappedDevice->FlushLists();
|
||||
|
||||
SAFE_RELEASE(uploadBuf);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE srv;
|
||||
srv = cbvsrvHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
|
||||
// texture display uses the first few, move to font texture slow
|
||||
srv.ptr +=
|
||||
FONT_SRV *
|
||||
m_WrappedDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
|
||||
m_WrappedDevice->CreateShaderResourceView(m_Font.Tex, NULL, srv);
|
||||
|
||||
Vec4f glyphData[2 * (numChars + 1)];
|
||||
|
||||
m_Font.GlyphData = MakeCBuffer(sizeof(glyphData));
|
||||
|
||||
for(int i = 0; i < numChars; i++)
|
||||
{
|
||||
stbtt_bakedchar *b = chardata + i;
|
||||
|
||||
float x = b->xoff;
|
||||
float y = b->yoff + maxheight;
|
||||
|
||||
glyphData[(i + 1) * 2 + 0] =
|
||||
Vec4f(x / b->xadvance, y / pixelHeight, b->xadvance / float(b->x1 - b->x0),
|
||||
pixelHeight / float(b->y1 - b->y0));
|
||||
glyphData[(i + 1) * 2 + 1] = Vec4f(b->x0, b->y0, b->x1, b->y1);
|
||||
}
|
||||
|
||||
FillBuffer(m_Font.GlyphData, &glyphData, sizeof(glyphData));
|
||||
|
||||
for(size_t i = 0; i < ARRAY_COUNT(m_Font.Constants); i++)
|
||||
m_Font.Constants[i] = MakeCBuffer(sizeof(FontCBuffer));
|
||||
m_Font.CharBuffer = MakeCBuffer(FONT_BUFFER_CHARS * sizeof(uint32_t) * 4);
|
||||
|
||||
m_Font.ConstRingIdx = 0;
|
||||
|
||||
rootSig.clear();
|
||||
|
||||
D3D12_ROOT_PARAMETER param = {};
|
||||
|
||||
// m_Font.Constants
|
||||
param.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
|
||||
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
||||
param.Descriptor.ShaderRegister = 0;
|
||||
|
||||
rootSig.push_back(param);
|
||||
|
||||
// m_Font.GlyphData
|
||||
param.Descriptor.ShaderRegister = 1;
|
||||
rootSig.push_back(param);
|
||||
|
||||
// CharBuffer
|
||||
param.Descriptor.ShaderRegister = 2;
|
||||
rootSig.push_back(param);
|
||||
|
||||
D3D12_DESCRIPTOR_RANGE srvrange = {};
|
||||
srvrange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
srvrange.BaseShaderRegister = 0;
|
||||
srvrange.NumDescriptors = 1;
|
||||
srvrange.OffsetInDescriptorsFromTableStart = FONT_SRV;
|
||||
|
||||
param.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
param.DescriptorTable.NumDescriptorRanges = 1;
|
||||
param.DescriptorTable.pDescriptorRanges = &srvrange;
|
||||
|
||||
// font SRV
|
||||
rootSig.push_back(param);
|
||||
|
||||
D3D12_DESCRIPTOR_RANGE samplerrange = {};
|
||||
samplerrange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
|
||||
samplerrange.BaseShaderRegister = 0;
|
||||
samplerrange.NumDescriptors = 2;
|
||||
samplerrange.OffsetInDescriptorsFromTableStart = 0;
|
||||
|
||||
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
param.DescriptorTable.NumDescriptorRanges = 1;
|
||||
param.DescriptorTable.pDescriptorRanges = &samplerrange;
|
||||
|
||||
// samplers
|
||||
rootSig.push_back(param);
|
||||
|
||||
ID3DBlob *root = MakeRootSig(rootSig);
|
||||
|
||||
RDCASSERT(root);
|
||||
|
||||
hr = m_WrappedDevice->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(),
|
||||
__uuidof(ID3D12RootSignature),
|
||||
(void **)&m_Font.RootSig);
|
||||
|
||||
SAFE_RELEASE(root);
|
||||
|
||||
string fullhlsl = "";
|
||||
{
|
||||
string debugShaderCBuf = GetEmbeddedResource(debugcbuffers_h);
|
||||
string textShaderHLSL = GetEmbeddedResource(debugtext_hlsl);
|
||||
|
||||
fullhlsl = debugShaderCBuf + textShaderHLSL;
|
||||
}
|
||||
|
||||
ID3DBlob *TextVS = NULL;
|
||||
ID3DBlob *TextPS = NULL;
|
||||
|
||||
GetShaderBlob(fullhlsl.c_str(), "RENDERDOC_TextVS", D3DCOMPILE_WARNINGS_ARE_ERRORS, "vs_5_0",
|
||||
&TextVS);
|
||||
GetShaderBlob(fullhlsl.c_str(), "RENDERDOC_TextPS", D3DCOMPILE_WARNINGS_ARE_ERRORS, "ps_5_0",
|
||||
&TextPS);
|
||||
|
||||
RDCASSERT(TextVS);
|
||||
RDCASSERT(TextPS);
|
||||
|
||||
pipeDesc.BlendState.RenderTarget[0].BlendEnable = TRUE;
|
||||
|
||||
pipeDesc.VS.BytecodeLength = TextVS->GetBufferSize();
|
||||
pipeDesc.VS.pShaderBytecode = TextVS->GetBufferPointer();
|
||||
pipeDesc.PS.BytecodeLength = TextPS->GetBufferSize();
|
||||
pipeDesc.PS.pShaderBytecode = TextPS->GetBufferPointer();
|
||||
|
||||
pipeDesc.pRootSignature = m_Font.RootSig;
|
||||
|
||||
pipeDesc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
|
||||
hr = m_WrappedDevice->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState),
|
||||
(void **)&m_Font.Pipe[BGRA8_BACKBUFFER]);
|
||||
|
||||
if(FAILED(hr))
|
||||
RDCERR("Couldn't create BGRA8 m_Font.Pipe! 0x%08x", hr);
|
||||
|
||||
pipeDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
hr = m_WrappedDevice->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState),
|
||||
(void **)&m_Font.Pipe[RGBA8_BACKBUFFER]);
|
||||
|
||||
if(FAILED(hr))
|
||||
RDCERR("Couldn't create RGBA8 m_Font.Pipe! 0x%08x", hr);
|
||||
|
||||
pipeDesc.RTVFormats[0] = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
|
||||
hr = m_WrappedDevice->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState),
|
||||
(void **)&m_Font.Pipe[RGBA16_BACKBUFFER]);
|
||||
|
||||
if(FAILED(hr))
|
||||
RDCERR("Couldn't create RGBA16 m_Font.Pipe! 0x%08x", hr);
|
||||
|
||||
SAFE_RELEASE(TextVS);
|
||||
SAFE_RELEASE(TextPS);
|
||||
}
|
||||
|
||||
RenderDoc::Inst().SetProgress(DebugManagerInit, 1.0f);
|
||||
|
||||
m_CacheShaders = false;
|
||||
@@ -517,6 +755,44 @@ ID3DBlob *D3D12DebugManager::MakeRootSig(const vector<D3D12_ROOT_PARAMETER> &roo
|
||||
return ret;
|
||||
}
|
||||
|
||||
ID3D12Resource *D3D12DebugManager::MakeCBuffer(UINT64 size)
|
||||
{
|
||||
ID3D12Resource *ret;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps;
|
||||
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProps.CreationNodeMask = 1;
|
||||
heapProps.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_RESOURCE_DESC cbDesc;
|
||||
cbDesc.Alignment = 0;
|
||||
cbDesc.DepthOrArraySize = 1;
|
||||
cbDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
cbDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
cbDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
cbDesc.Height = 1;
|
||||
cbDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
cbDesc.MipLevels = 1;
|
||||
cbDesc.SampleDesc.Count = 1;
|
||||
cbDesc.SampleDesc.Quality = 0;
|
||||
cbDesc.Width = size;
|
||||
|
||||
HRESULT hr = m_WrappedDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &cbDesc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&ret);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create cbuffer size %llu! 0x%08x", size, hr);
|
||||
SAFE_RELEASE(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void D3D12DebugManager::OutputWindow::MakeRTV(bool multisampled)
|
||||
{
|
||||
SAFE_RELEASE(col);
|
||||
@@ -787,7 +1063,7 @@ void D3D12DebugManager::BindOutputWindow(uint64_t id, bool depth)
|
||||
if(outw.bb[0] == NULL)
|
||||
return;
|
||||
|
||||
SetOutputDimensions(outw.width, outw.height);
|
||||
SetOutputDimensions(outw.width, outw.height, DXGI_FORMAT_UNKNOWN);
|
||||
}
|
||||
|
||||
bool D3D12DebugManager::IsOutputWindowVisible(uint64_t id)
|
||||
@@ -850,7 +1126,7 @@ void D3D12DebugManager::FlipOutputWindow(uint64_t id)
|
||||
outw.bbIdx %= 2;
|
||||
}
|
||||
|
||||
void D3D12DebugManager::FillCBuffer(ID3D12Resource *buf, void *data, size_t size)
|
||||
void D3D12DebugManager::FillBuffer(ID3D12Resource *buf, void *data, size_t size)
|
||||
{
|
||||
void *ptr = NULL;
|
||||
HRESULT hr = buf->Map(0, NULL, &ptr);
|
||||
@@ -866,6 +1142,23 @@ void D3D12DebugManager::FillCBuffer(ID3D12Resource *buf, void *data, size_t size
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE D3D12DebugManager::AllocRTV()
|
||||
{
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtv = rtvHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
rtv.ptr += SIZE_T(m_OutputWindowID) *
|
||||
m_WrappedDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
|
||||
m_OutputWindowID++;
|
||||
|
||||
return rtv;
|
||||
}
|
||||
|
||||
void D3D12DebugManager::FreeRTV(D3D12_CPU_DESCRIPTOR_HANDLE handle)
|
||||
{
|
||||
// do nothing for now but could recycle/free-list/etc RTVs
|
||||
D3D12NOTIMP("Not freeing RTV's - will run out");
|
||||
}
|
||||
|
||||
void D3D12DebugManager::RenderCheckerboard(Vec3f light, Vec3f dark)
|
||||
{
|
||||
DebugVertexCBuffer vertexData;
|
||||
@@ -888,8 +1181,8 @@ void D3D12DebugManager::RenderCheckerboard(Vec3f light, Vec3f dark)
|
||||
pixelData.Channels = Vec4f(light.x, light.y, light.z, 0.0f);
|
||||
pixelData.WireframeColour = dark;
|
||||
|
||||
FillCBuffer(m_GenericVSCbuffer, &vertexData, sizeof(DebugVertexCBuffer));
|
||||
FillCBuffer(m_GenericPSCbuffer, &pixelData, sizeof(DebugPixelCBufferData));
|
||||
FillBuffer(m_GenericVSCbuffer, &vertexData, sizeof(DebugVertexCBuffer));
|
||||
FillBuffer(m_GenericPSCbuffer, &pixelData, sizeof(DebugPixelCBufferData));
|
||||
|
||||
OutputWindow &outw = m_OutputWindows[m_CurrentOutputWindow];
|
||||
|
||||
@@ -931,6 +1224,115 @@ void D3D12DebugManager::RenderCheckerboard(Vec3f light, Vec3f dark)
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12DebugManager::RenderText(ID3D12GraphicsCommandList *list, float x, float y,
|
||||
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);
|
||||
|
||||
RenderTextInternal(list, x, y, tmpBuf);
|
||||
}
|
||||
|
||||
void D3D12DebugManager::RenderTextInternal(ID3D12GraphicsCommandList *list, float x, float y,
|
||||
const char *text)
|
||||
{
|
||||
if(char *t = strchr((char *)text, '\n'))
|
||||
{
|
||||
*t = 0;
|
||||
RenderTextInternal(list, x, y, text);
|
||||
RenderTextInternal(list, x, y + 1.0f, t + 1);
|
||||
*t = '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
if(strlen(text) == 0)
|
||||
return;
|
||||
|
||||
RDCASSERT(strlen(text) < FONT_MAX_CHARS);
|
||||
|
||||
FontCBuffer data;
|
||||
|
||||
data.TextPosition.x = x;
|
||||
data.TextPosition.y = y;
|
||||
|
||||
data.FontScreenAspect.x = 1.0f / float(GetWidth());
|
||||
data.FontScreenAspect.y = 1.0f / float(GetHeight());
|
||||
|
||||
data.TextSize = m_Font.CharSize;
|
||||
data.FontScreenAspect.x *= m_Font.CharAspect;
|
||||
|
||||
data.CharacterSize.x = 1.0f / float(FONT_TEX_WIDTH);
|
||||
data.CharacterSize.y = 1.0f / float(FONT_TEX_HEIGHT);
|
||||
|
||||
FillBuffer(m_Font.Constants[m_Font.ConstRingIdx], &data, sizeof(FontCBuffer));
|
||||
|
||||
size_t chars = strlen(text);
|
||||
|
||||
size_t charOffset = m_Font.CharOffset;
|
||||
|
||||
if(m_Font.CharOffset + chars >= FONT_BUFFER_CHARS)
|
||||
charOffset = 0;
|
||||
|
||||
m_Font.CharOffset = charOffset + chars;
|
||||
|
||||
unsigned long *texs = NULL;
|
||||
HRESULT hr = m_Font.CharBuffer->Map(0, NULL, (void **)&texs);
|
||||
|
||||
if(FAILED(hr) || texs == NULL)
|
||||
{
|
||||
RDCERR("Failed to map charbuffer %08x", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
texs += charOffset * 4;
|
||||
|
||||
for(size_t i = 0; i < strlen(text); i++)
|
||||
texs[i * 4] = (text[i] - ' ');
|
||||
|
||||
m_Font.CharBuffer->Unmap(0, NULL);
|
||||
|
||||
{
|
||||
list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
|
||||
D3D12_VIEWPORT view;
|
||||
view.TopLeftX = 0;
|
||||
view.TopLeftY = 0;
|
||||
view.Width = (float)GetWidth();
|
||||
view.Height = (float)GetHeight();
|
||||
view.MinDepth = 0.0f;
|
||||
view.MaxDepth = 1.0f;
|
||||
list->RSSetViewports(1, &view);
|
||||
|
||||
D3D12_RECT scissor = {0, 0, GetWidth(), GetHeight()};
|
||||
list->RSSetScissorRects(1, &scissor);
|
||||
|
||||
list->SetPipelineState(m_Font.Pipe[m_BBFmtIdx]);
|
||||
list->SetGraphicsRootSignature(m_Font.RootSig);
|
||||
|
||||
// Set the descriptor heap containing the texture srv
|
||||
ID3D12DescriptorHeap *heaps[] = {cbvsrvHeap, samplerHeap};
|
||||
list->SetDescriptorHeaps(2, heaps);
|
||||
|
||||
list->SetGraphicsRootConstantBufferView(
|
||||
0, m_Font.Constants[m_Font.ConstRingIdx]->GetGPUVirtualAddress());
|
||||
list->SetGraphicsRootConstantBufferView(1, m_Font.GlyphData->GetGPUVirtualAddress());
|
||||
list->SetGraphicsRootConstantBufferView(
|
||||
2, m_Font.CharBuffer->GetGPUVirtualAddress() + charOffset * sizeof(Vec4f));
|
||||
list->SetGraphicsRootDescriptorTable(3, cbvsrvHeap->GetGPUDescriptorHandleForHeapStart());
|
||||
list->SetGraphicsRootDescriptorTable(4, samplerHeap->GetGPUDescriptorHandleForHeapStart());
|
||||
|
||||
list->DrawInstanced(4, (uint32_t)strlen(text), 0, 0);
|
||||
}
|
||||
|
||||
m_Font.ConstRingIdx++;
|
||||
m_Font.ConstRingIdx %= ARRAY_COUNT(m_Font.Constants);
|
||||
}
|
||||
|
||||
bool D3D12DebugManager::RenderTexture(TextureDisplay cfg, bool blendAlpha)
|
||||
{
|
||||
DebugVertexCBuffer vertexData;
|
||||
@@ -1113,8 +1515,8 @@ bool D3D12DebugManager::RenderTexture(TextureDisplay cfg, bool blendAlpha)
|
||||
|
||||
m_WrappedDevice->CreateShaderResourceView(resource, &srvDesc, srv);
|
||||
|
||||
FillCBuffer(m_GenericVSCbuffer, &vertexData, sizeof(DebugVertexCBuffer));
|
||||
FillCBuffer(m_GenericPSCbuffer, &pixelData, sizeof(DebugPixelCBufferData));
|
||||
FillBuffer(m_GenericVSCbuffer, &vertexData, sizeof(DebugVertexCBuffer));
|
||||
FillBuffer(m_GenericPSCbuffer, &pixelData, sizeof(DebugPixelCBufferData));
|
||||
|
||||
// transition resource to D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
|
||||
const vector<D3D12_RESOURCE_STATES> &states =
|
||||
|
||||
@@ -36,6 +36,7 @@ class D3D12DebugManager
|
||||
{
|
||||
public:
|
||||
D3D12DebugManager(WrappedID3D12Device *wrapper);
|
||||
|
||||
~D3D12DebugManager();
|
||||
|
||||
uint64_t MakeOutputWindow(WindowingSystem system, void *data, bool depth);
|
||||
@@ -48,16 +49,28 @@ public:
|
||||
bool IsOutputWindowVisible(uint64_t id);
|
||||
void FlipOutputWindow(uint64_t id);
|
||||
|
||||
void SetOutputDimensions(int w, int h)
|
||||
void SetOutputDimensions(int w, int h, DXGI_FORMAT fmt)
|
||||
{
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
|
||||
if(fmt == DXGI_FORMAT_B8G8R8A8_UNORM)
|
||||
m_BBFmtIdx = BGRA8_BACKBUFFER;
|
||||
else if(fmt == DXGI_FORMAT_R16G16B16A16_FLOAT)
|
||||
m_BBFmtIdx = RGBA16_BACKBUFFER;
|
||||
else
|
||||
m_BBFmtIdx = RGBA8_BACKBUFFER;
|
||||
}
|
||||
int GetWidth() { return m_width; }
|
||||
int GetHeight() { return m_height; }
|
||||
void RenderText(ID3D12GraphicsCommandList *list, float x, float y, const char *textfmt, ...);
|
||||
|
||||
void RenderCheckerboard(Vec3f light, Vec3f dark);
|
||||
bool RenderTexture(TextureDisplay cfg, bool blendAlpha);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE AllocRTV();
|
||||
void FreeRTV(D3D12_CPU_DESCRIPTOR_HANDLE handle);
|
||||
|
||||
private:
|
||||
struct OutputWindow
|
||||
{
|
||||
@@ -78,7 +91,57 @@ private:
|
||||
int width, height;
|
||||
};
|
||||
|
||||
void FillCBuffer(ID3D12Resource *buf, void *data, size_t size);
|
||||
ID3D12Resource *MakeCBuffer(UINT64 size);
|
||||
void FillBuffer(ID3D12Resource *buf, void *data, size_t size);
|
||||
|
||||
static const int FONT_TEX_WIDTH = 256;
|
||||
static const int FONT_TEX_HEIGHT = 128;
|
||||
static const int FONT_MAX_CHARS = 256;
|
||||
|
||||
// how much character space is in the ring buffer
|
||||
static const int FONT_BUFFER_CHARS = 8192;
|
||||
|
||||
// index in SRV heap
|
||||
static const int FONT_SRV = 128;
|
||||
|
||||
// indices for the pipelines, for the three possible backbuffer formats
|
||||
enum
|
||||
{
|
||||
BGRA8_BACKBUFFER = 0,
|
||||
RGBA8_BACKBUFFER,
|
||||
RGBA16_BACKBUFFER,
|
||||
FMTNUM_BACKBUFFER,
|
||||
} m_BBFmtIdx;
|
||||
|
||||
struct FontData
|
||||
{
|
||||
FontData() { RDCEraseMem(this, sizeof(FontData)); }
|
||||
~FontData()
|
||||
{
|
||||
SAFE_RELEASE(Tex);
|
||||
SAFE_RELEASE(RootSig);
|
||||
SAFE_RELEASE(GlyphData);
|
||||
SAFE_RELEASE(CharBuffer);
|
||||
|
||||
for(size_t i = 0; i < ARRAY_COUNT(Constants); i++)
|
||||
SAFE_RELEASE(Constants[i]);
|
||||
for(int i = 0; i < ARRAY_COUNT(Pipe); i++)
|
||||
SAFE_RELEASE(Pipe[i]);
|
||||
}
|
||||
|
||||
ID3D12Resource *Tex;
|
||||
ID3D12PipelineState *Pipe[FMTNUM_BACKBUFFER];
|
||||
ID3D12RootSignature *RootSig;
|
||||
ID3D12Resource *Constants[20];
|
||||
ID3D12Resource *GlyphData;
|
||||
ID3D12Resource *CharBuffer;
|
||||
|
||||
size_t CharOffset;
|
||||
size_t ConstRingIdx;
|
||||
|
||||
float CharAspect;
|
||||
float CharSize;
|
||||
} m_Font;
|
||||
|
||||
ID3D12DescriptorHeap *cbvsrvHeap;
|
||||
ID3D12DescriptorHeap *samplerHeap;
|
||||
@@ -101,6 +164,8 @@ private:
|
||||
bool m_ShaderCacheDirty, m_CacheShaders;
|
||||
map<uint32_t, ID3DBlob *> m_ShaderCache;
|
||||
|
||||
void RenderTextInternal(ID3D12GraphicsCommandList *list, float x, float y, const char *text);
|
||||
|
||||
string GetShaderBlob(const char *source, const char *entry, const uint32_t compileFlags,
|
||||
const char *profile, ID3DBlob **srcblob);
|
||||
ID3DBlob *MakeRootSig(const vector<D3D12_ROOT_PARAMETER> &rootSig);
|
||||
|
||||
@@ -514,7 +514,12 @@ void WrappedID3D12Device::ReleaseSwapchainResources(WrappedIDXGISwapChain3 *swap
|
||||
|
||||
auto it = m_SwapChains.find(swap);
|
||||
if(it != m_SwapChains.end())
|
||||
{
|
||||
for(int i = 0; i < swap->GetNumBackbuffers(); i++)
|
||||
GetDebugManager()->FreeRTV(it->second.rtvs[i]);
|
||||
|
||||
m_SwapChains.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
bool WrappedID3D12Device::Serialise_WrapSwapchainBuffer(WrappedIDXGISwapChain3 *swap,
|
||||
@@ -623,7 +628,7 @@ IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(WrappedIDXGISwapChain3 *swap,
|
||||
}
|
||||
}
|
||||
|
||||
if(buffer == 0 && m_State >= WRITING)
|
||||
if(m_State >= WRITING)
|
||||
{
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtv = {};
|
||||
|
||||
@@ -633,8 +638,9 @@ IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(WrappedIDXGISwapChain3 *swap,
|
||||
rtvDesc.Texture2D.MipSlice = 0;
|
||||
rtvDesc.Texture2D.PlaneSlice = 0;
|
||||
|
||||
D3D12NOTIMP("Creating RTV for rendering to back buffer");
|
||||
// m_pDevice->CreateRenderTargetView(Unwrap(pRes), &rtvDesc, rtv);
|
||||
rtv = GetDebugManager()->AllocRTV();
|
||||
|
||||
CreateRenderTargetView(pRes, NULL, rtv);
|
||||
|
||||
m_SwapChains[swap].rtvs[buffer] = rtv;
|
||||
|
||||
@@ -689,8 +695,6 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain3 *swap, UINT SyncInte
|
||||
m_TotalTime += m_FrameTimes.back();
|
||||
m_FrameTimer.Restart();
|
||||
|
||||
bool doprint = false;
|
||||
|
||||
// update every second
|
||||
if(m_TotalTime > 1000.0)
|
||||
{
|
||||
@@ -700,8 +704,6 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain3 *swap, UINT SyncInte
|
||||
|
||||
m_TotalTime = 0.0;
|
||||
|
||||
doprint = true;
|
||||
|
||||
for(size_t i = 0; i < m_FrameTimes.size(); i++)
|
||||
{
|
||||
m_AvgFrametime += m_FrameTimes[i];
|
||||
@@ -720,6 +722,26 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain3 *swap, UINT SyncInte
|
||||
|
||||
if(overlay & eRENDERDOC_Overlay_Enabled)
|
||||
{
|
||||
SwapPresentInfo &swapInfo = m_SwapChains[swap];
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtv = swapInfo.rtvs[swapInfo.lastPresentedBuffer];
|
||||
|
||||
GetDebugManager()->SetOutputDimensions(swapdesc.BufferDesc.Width, swapdesc.BufferDesc.Height,
|
||||
swapdesc.BufferDesc.Format);
|
||||
|
||||
ID3D12GraphicsCommandList *list = GetNewList();
|
||||
|
||||
// buffer will be in common for presentation, transition to render target
|
||||
D3D12_RESOURCE_BARRIER barrier = {};
|
||||
barrier.Transition.pResource =
|
||||
(ID3D12Resource *)swap->GetBackbuffers()[swapInfo.lastPresentedBuffer];
|
||||
barrier.Transition.Subresource = 0;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
|
||||
list->ResourceBarrier(1, &barrier);
|
||||
|
||||
list->OMSetRenderTargets(1, &rtv, FALSE, NULL);
|
||||
|
||||
if(activeWindow)
|
||||
{
|
||||
vector<RENDERDOC_InputButton> keys = RenderDoc::Inst().GetCaptureKeys();
|
||||
@@ -763,15 +785,14 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain3 *swap, UINT SyncInte
|
||||
|
||||
if(!overlayText.empty())
|
||||
{
|
||||
if(doprint)
|
||||
RDCLOG(overlayText.c_str());
|
||||
GetDebugManager()->RenderText(list, 0.0f, y, overlayText.c_str());
|
||||
y += 1.0f;
|
||||
}
|
||||
|
||||
if(overlay & eRENDERDOC_Overlay_CaptureList)
|
||||
{
|
||||
if(doprint)
|
||||
RDCLOG("%d Captures saved.", (uint32_t)m_CapturedFrames.size());
|
||||
GetDebugManager()->RenderText(list, 0.0f, y, "%d Captures saved.",
|
||||
(uint32_t)m_CapturedFrames.size());
|
||||
y += 1.0f;
|
||||
|
||||
uint64_t now = Timing::GetUnixTimestamp();
|
||||
@@ -779,17 +800,16 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain3 *swap, UINT SyncInte
|
||||
{
|
||||
if(now - m_CapturedFrames[i].captureTime < 20)
|
||||
{
|
||||
if(doprint)
|
||||
RDCLOG("Captured frame %d.", m_CapturedFrames[i].frameNumber);
|
||||
GetDebugManager()->RenderText(list, 0.0f, y, "Captured frame %d.",
|
||||
m_CapturedFrames[i].frameNumber);
|
||||
y += 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(RELEASE)
|
||||
if(doprint)
|
||||
RDCLOG("%llu chunks - %.2f MB", Chunk::NumLiveChunks(),
|
||||
float(Chunk::TotalMem()) / 1024.0f / 1024.0f);
|
||||
GetDebugManager()->RenderText(list, 0.0f, y, "%llu chunks - %.2f MB", Chunk::NumLiveChunks(),
|
||||
float(Chunk::TotalMem()) / 1024.0f / 1024.0f);
|
||||
y += 1.0f;
|
||||
#endif
|
||||
}
|
||||
@@ -812,9 +832,16 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain3 *swap, UINT SyncInte
|
||||
if(!keys.empty())
|
||||
str += " to cycle between swapchains";
|
||||
|
||||
if(doprint)
|
||||
RDCLOG(str.c_str());
|
||||
GetDebugManager()->RenderText(list, 0.0f, 0.0f, str.c_str());
|
||||
}
|
||||
|
||||
// transition backbuffer back again
|
||||
std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter);
|
||||
list->ResourceBarrier(1, &barrier);
|
||||
|
||||
list->Close();
|
||||
|
||||
ExecuteLists();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user