mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-05 06:11:05 +00:00
* This reduces code complexity and divergence between the backends, as well as prevents internal resources in captures from being included when 'Ref All Resources' is enabled.
568 lines
18 KiB
C++
568 lines
18 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2018 Baldur Karlsson
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#include "d3d12_rendertext.h"
|
|
#include "driver/dx/official/d3dcompiler.h"
|
|
#include "maths/matrix.h"
|
|
#include "maths/vec.h"
|
|
#include "stb/stb_truetype.h"
|
|
#include "d3d12_device.h"
|
|
#include "d3d12_shader_cache.h"
|
|
|
|
#include "data/hlsl/debugcbuffers.h"
|
|
|
|
D3D12TextRenderer::D3D12TextRenderer(WrappedID3D12Device *wrapper)
|
|
{
|
|
D3D12ResourceManager *rm = wrapper->GetResourceManager();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
D3D12_DESCRIPTOR_HEAP_DESC desc;
|
|
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
|
desc.NodeMask = 1;
|
|
desc.NumDescriptors = 1;
|
|
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
|
|
|
hr = wrapper->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)&descHeap);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
RDCERR("Couldn't create font descriptor heap! HRESULT: %s", ToStr(hr).c_str());
|
|
}
|
|
|
|
rm->SetInternalResource(descHeap);
|
|
|
|
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 = wrapper->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 HRESULT: %s", ToStr(hr).c_str());
|
|
|
|
rm->SetInternalResource(uploadBuf);
|
|
|
|
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 = wrapper->CreateCommittedResource(&defaultHeap, D3D12_HEAP_FLAG_NONE, &texDesc,
|
|
D3D12_RESOURCE_STATE_COPY_DEST, NULL,
|
|
__uuidof(ID3D12Resource), (void **)&Tex);
|
|
|
|
Tex->SetName(L"FontTex");
|
|
|
|
if(FAILED(hr))
|
|
RDCERR("Failed to create FontTex HRESULT: %s", ToStr(hr).c_str());
|
|
|
|
rm->SetInternalResource(Tex);
|
|
|
|
std::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);
|
|
|
|
CharSize = pixelHeight;
|
|
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);
|
|
|
|
{
|
|
D3D12_RANGE range = {0, width * height};
|
|
byte *ptr = NULL;
|
|
hr = uploadBuf->Map(0, &range, (void **)&ptr);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
RDCERR("Can't fill font tex upload buffer HRESULT: %s", ToStr(hr).c_str());
|
|
}
|
|
else
|
|
{
|
|
memcpy(ptr, buf, width * height);
|
|
uploadBuf->Unmap(0, &range);
|
|
}
|
|
}
|
|
|
|
delete[] buf;
|
|
|
|
ID3D12GraphicsCommandList *list = wrapper->GetNewList();
|
|
|
|
D3D12_TEXTURE_COPY_LOCATION dst, src;
|
|
|
|
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
|
dst.pResource = 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 = Tex;
|
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
|
|
|
list->ResourceBarrier(1, &barrier);
|
|
|
|
list->Close();
|
|
|
|
wrapper->ExecuteLists();
|
|
wrapper->FlushLists();
|
|
|
|
SAFE_RELEASE(uploadBuf);
|
|
|
|
D3D12_CPU_DESCRIPTOR_HANDLE srv = descHeap->GetCPUDescriptorHandleForHeapStart();
|
|
|
|
wrapper->CreateShaderResourceView(Tex, NULL, srv);
|
|
|
|
Vec4f glyphData[2 * (numChars + 1)];
|
|
|
|
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(glyphData);
|
|
hr = wrapper->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &cbDesc,
|
|
D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
|
__uuidof(ID3D12Resource), (void **)&GlyphData);
|
|
|
|
if(FAILED(hr))
|
|
RDCERR("Couldn't create GlyphData cbuffer! %s", ToStr(hr).c_str());
|
|
|
|
rm->SetInternalResource(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);
|
|
}
|
|
|
|
{
|
|
D3D12_RANGE range = {0, sizeof(glyphData)};
|
|
byte *ptr = NULL;
|
|
hr = GlyphData->Map(0, &range, (void **)&ptr);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
RDCERR("Can't fill glyph data buffer HRESULT: %s", ToStr(hr).c_str());
|
|
}
|
|
else
|
|
{
|
|
memcpy(ptr, &glyphData, sizeof(glyphData));
|
|
GlyphData->Unmap(0, &range);
|
|
}
|
|
}
|
|
|
|
const UINT fontDataSize = 256;
|
|
RDCCOMPILE_ASSERT(sizeof(FontCBuffer) < fontDataSize, "FontCBuffer is larger - need to align up");
|
|
|
|
cbDesc.Width = fontDataSize * ConstRingSize;
|
|
hr = wrapper->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &cbDesc,
|
|
D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
|
__uuidof(ID3D12Resource), (void **)&Constants);
|
|
|
|
if(FAILED(hr))
|
|
RDCERR("Couldn't create Constants cbuffer! %s", ToStr(hr).c_str());
|
|
|
|
rm->SetInternalResource(Constants);
|
|
|
|
cbDesc.Width = FONT_BUFFER_CHARS * sizeof(uint32_t) * 4;
|
|
hr = wrapper->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &cbDesc,
|
|
D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
|
__uuidof(ID3D12Resource), (void **)&CharBuffer);
|
|
|
|
if(FAILED(hr))
|
|
RDCERR("Couldn't create CharBuffer cbuffer! %s", ToStr(hr).c_str());
|
|
|
|
rm->SetInternalResource(CharBuffer);
|
|
|
|
ConstRingIdx = 0;
|
|
|
|
std::vector<D3D12_ROOT_PARAMETER1> rootSig;
|
|
D3D12_ROOT_PARAMETER1 param = {};
|
|
|
|
// Constants
|
|
param.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
|
|
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
|
param.Descriptor.ShaderRegister = 0;
|
|
param.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE;
|
|
|
|
rootSig.push_back(param);
|
|
|
|
// GlyphData
|
|
param.Descriptor.ShaderRegister = 1;
|
|
rootSig.push_back(param);
|
|
|
|
// CharBuffer
|
|
param.Descriptor.ShaderRegister = 2;
|
|
rootSig.push_back(param);
|
|
|
|
D3D12_DESCRIPTOR_RANGE1 srvrange = {};
|
|
srvrange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
|
srvrange.BaseShaderRegister = 0;
|
|
srvrange.NumDescriptors = 1;
|
|
srvrange.OffsetInDescriptorsFromTableStart = 0;
|
|
|
|
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);
|
|
|
|
D3D12ShaderCache *shaderCache = wrapper->GetShaderCache();
|
|
|
|
const D3D12_STATIC_SAMPLER_DESC samplers[2] = {
|
|
// point
|
|
{
|
|
D3D12_FILTER_MIN_MAG_MIP_POINT, D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
|
|
D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, 0.0f, 1,
|
|
D3D12_COMPARISON_FUNC_ALWAYS, D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK, 0.0f, FLT_MAX, 0, 0,
|
|
D3D12_SHADER_VISIBILITY_PIXEL,
|
|
},
|
|
|
|
// linear
|
|
{
|
|
D3D12_FILTER_MIN_MAG_MIP_LINEAR, D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
|
|
D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, 0.0f, 1,
|
|
D3D12_COMPARISON_FUNC_ALWAYS, D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK, 0.0f, FLT_MAX, 1, 0,
|
|
D3D12_SHADER_VISIBILITY_PIXEL,
|
|
},
|
|
};
|
|
|
|
ID3DBlob *root = shaderCache->MakeRootSig(rootSig, D3D12_ROOT_SIGNATURE_FLAG_NONE, 2, samplers);
|
|
|
|
RDCASSERT(root);
|
|
|
|
hr = wrapper->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(),
|
|
__uuidof(ID3D12RootSignature), (void **)&RootSig);
|
|
|
|
if(FAILED(hr))
|
|
RDCERR("Couldn't create RootSig! %s", ToStr(hr).c_str());
|
|
|
|
rm->SetInternalResource(RootSig);
|
|
|
|
SAFE_RELEASE(root);
|
|
|
|
std::string fullhlsl = "";
|
|
{
|
|
std::string debugShaderCBuf = GetEmbeddedResource(debugcbuffers_h);
|
|
std::string textShaderHLSL = GetEmbeddedResource(debugtext_hlsl);
|
|
|
|
fullhlsl = debugShaderCBuf + textShaderHLSL;
|
|
}
|
|
|
|
ID3DBlob *TextVS = NULL;
|
|
ID3DBlob *TextPS = NULL;
|
|
|
|
shaderCache->GetShaderBlob(fullhlsl.c_str(), "RENDERDOC_TextVS", D3DCOMPILE_WARNINGS_ARE_ERRORS,
|
|
"vs_5_0", &TextVS);
|
|
shaderCache->GetShaderBlob(fullhlsl.c_str(), "RENDERDOC_TextPS", D3DCOMPILE_WARNINGS_ARE_ERRORS,
|
|
"ps_5_0", &TextPS);
|
|
|
|
RDCASSERT(TextVS);
|
|
RDCASSERT(TextPS);
|
|
|
|
D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc;
|
|
RDCEraseEl(pipeDesc);
|
|
|
|
pipeDesc.pRootSignature = RootSig;
|
|
pipeDesc.VS.BytecodeLength = TextVS->GetBufferSize();
|
|
pipeDesc.VS.pShaderBytecode = TextVS->GetBufferPointer();
|
|
pipeDesc.PS.BytecodeLength = TextPS->GetBufferSize();
|
|
pipeDesc.PS.pShaderBytecode = TextPS->GetBufferPointer();
|
|
pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
|
pipeDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
|
|
pipeDesc.SampleMask = 0xFFFFFFFF;
|
|
pipeDesc.SampleDesc.Count = 1;
|
|
pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
|
|
pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
|
pipeDesc.NumRenderTargets = 1;
|
|
pipeDesc.DSVFormat = DXGI_FORMAT_UNKNOWN;
|
|
pipeDesc.BlendState.RenderTarget[0].BlendEnable = TRUE;
|
|
pipeDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
|
|
pipeDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
|
|
pipeDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
|
|
pipeDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA;
|
|
pipeDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
|
|
pipeDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
|
pipeDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
|
|
|
pipeDesc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
|
|
hr = wrapper->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState),
|
|
(void **)&Pipe[BGRA8_BACKBUFFER]);
|
|
|
|
if(FAILED(hr))
|
|
RDCERR("Couldn't create BGRA8 Pipe! HRESULT: %s", ToStr(hr).c_str());
|
|
|
|
rm->SetInternalResource(Pipe[BGRA8_BACKBUFFER]);
|
|
|
|
pipeDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
|
|
hr = wrapper->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState),
|
|
(void **)&Pipe[RGBA8_BACKBUFFER]);
|
|
|
|
if(FAILED(hr))
|
|
RDCERR("Couldn't create RGBA8 Pipe! HRESULT: %s", ToStr(hr).c_str());
|
|
|
|
rm->SetInternalResource(Pipe[RGBA8_BACKBUFFER]);
|
|
|
|
pipeDesc.RTVFormats[0] = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
|
|
|
hr = wrapper->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState),
|
|
(void **)&Pipe[RGBA16_BACKBUFFER]);
|
|
|
|
if(FAILED(hr))
|
|
RDCERR("Couldn't create RGBA16 Pipe! HRESULT: %s", ToStr(hr).c_str());
|
|
|
|
rm->SetInternalResource(Pipe[RGBA16_BACKBUFFER]);
|
|
|
|
SAFE_RELEASE(TextVS);
|
|
SAFE_RELEASE(TextPS);
|
|
}
|
|
|
|
D3D12TextRenderer::~D3D12TextRenderer()
|
|
{
|
|
SAFE_RELEASE(Tex);
|
|
for(ID3D12PipelineState *pipe : Pipe)
|
|
SAFE_RELEASE(pipe);
|
|
SAFE_RELEASE(RootSig);
|
|
SAFE_RELEASE(Constants);
|
|
SAFE_RELEASE(GlyphData);
|
|
SAFE_RELEASE(CharBuffer);
|
|
SAFE_RELEASE(descHeap);
|
|
}
|
|
|
|
void D3D12TextRenderer::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 D3D12TextRenderer::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 = CharSize;
|
|
data.FontScreenAspect.x *= CharAspect;
|
|
|
|
data.CharacterSize.x = 1.0f / float(FONT_TEX_WIDTH);
|
|
data.CharacterSize.y = 1.0f / float(FONT_TEX_HEIGHT);
|
|
|
|
// Is 256 byte alignment on buffer offsets is just fixed, or device-specific?
|
|
const UINT constantAlignment = 256;
|
|
|
|
// won't read anything, empty range
|
|
D3D12_RANGE range = {0, 0};
|
|
byte *ptr = NULL;
|
|
HRESULT hr = Constants->Map(0, &range, (void **)&ptr);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
RDCERR("Can't fill cbuffer HRESULT: %s", ToStr(hr).c_str());
|
|
}
|
|
else
|
|
{
|
|
memcpy(ptr + ConstRingIdx * constantAlignment, &data, sizeof(FontCBuffer));
|
|
range.Begin = ConstRingIdx * constantAlignment;
|
|
range.End = range.Begin + sizeof(FontCBuffer);
|
|
Constants->Unmap(0, &range);
|
|
}
|
|
|
|
size_t chars = strlen(text);
|
|
|
|
size_t charOffset = CharOffset;
|
|
|
|
if(CharOffset + chars >= FONT_BUFFER_CHARS)
|
|
charOffset = 0;
|
|
|
|
CharOffset = charOffset + chars;
|
|
|
|
CharOffset = AlignUp(CharOffset, constantAlignment / sizeof(Vec4f));
|
|
|
|
unsigned long *texs = NULL;
|
|
hr = CharBuffer->Map(0, NULL, (void **)&texs);
|
|
|
|
if(FAILED(hr) || texs == NULL)
|
|
{
|
|
RDCERR("Failed to map charbuffer HRESULT: %s", ToStr(hr).c_str());
|
|
return;
|
|
}
|
|
|
|
texs += charOffset * 4;
|
|
|
|
for(size_t i = 0; i < strlen(text); i++)
|
|
texs[i * 4] = (text[i] - ' ');
|
|
|
|
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(Pipe[m_BBFmtIdx]);
|
|
list->SetGraphicsRootSignature(RootSig);
|
|
|
|
// Set the descriptor heap containing the texture srv
|
|
list->SetDescriptorHeaps(1, &descHeap);
|
|
|
|
list->SetGraphicsRootConstantBufferView(
|
|
0, Constants->GetGPUVirtualAddress() + ConstRingIdx * constantAlignment);
|
|
list->SetGraphicsRootConstantBufferView(1, GlyphData->GetGPUVirtualAddress());
|
|
list->SetGraphicsRootConstantBufferView(
|
|
2, CharBuffer->GetGPUVirtualAddress() + charOffset * sizeof(Vec4f));
|
|
list->SetGraphicsRootDescriptorTable(3, descHeap->GetGPUDescriptorHandleForHeapStart());
|
|
|
|
list->DrawInstanced(4, (uint32_t)strlen(text), 0, 0);
|
|
}
|
|
|
|
ConstRingIdx++;
|
|
ConstRingIdx %= ConstRingSize;
|
|
}
|