mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-17 15:30:51 +00:00
11ce77e8cd
* Make each UBO N times larger, and map subsets of them in ring-buffer fashion. Use dynamic offsets to specify the right subset.
1211 lines
36 KiB
C++
1211 lines
36 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2015 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 "vk_debug.h"
|
|
#include "vk_core.h"
|
|
|
|
#include "stb/stb_truetype.h"
|
|
|
|
// VKTODOMED should share this between shader and C++ - need #include support in glslang
|
|
struct displayuniforms
|
|
{
|
|
Vec2f Position;
|
|
float Scale;
|
|
float HDRMul;
|
|
|
|
Vec4f Channels;
|
|
|
|
float RangeMinimum;
|
|
float InverseRangeSize;
|
|
float MipLevel;
|
|
int FlipY;
|
|
|
|
Vec3f TextureResolutionPS;
|
|
int OutputDisplayFormat;
|
|
|
|
Vec2f OutputRes;
|
|
int RawOutput;
|
|
float Slice;
|
|
|
|
int SampleIdx;
|
|
int NumSamples;
|
|
Vec2f Padding;
|
|
};
|
|
|
|
struct fontuniforms
|
|
{
|
|
Vec2f TextPosition;
|
|
float txtpadding;
|
|
float TextSize;
|
|
|
|
Vec2f CharacterSize;
|
|
Vec2f FontScreenAspect;
|
|
};
|
|
|
|
struct genericuniforms
|
|
{
|
|
Vec4f Offset;
|
|
Vec4f Scale;
|
|
Vec4f Color;
|
|
};
|
|
|
|
struct glyph
|
|
{
|
|
Vec4f posdata;
|
|
Vec4f uvdata;
|
|
};
|
|
|
|
struct glyphdata
|
|
{
|
|
glyph glyphs[127-32];
|
|
};
|
|
|
|
struct stringdata
|
|
{
|
|
uint32_t str[256][4];
|
|
};
|
|
|
|
void VulkanDebugManager::GPUBuffer::Create(WrappedVulkan *driver, VkDevice dev, VkDeviceSize size, uint32_t ringSize, uint32_t flags)
|
|
{
|
|
const VkLayerDispatchTable *vt = ObjDisp(dev);
|
|
|
|
sz = size;
|
|
// offset must be 256-aligned, so ensure we have at least ringSize
|
|
// copies accounting for that
|
|
totalsize = ringSize == 1 ? size : AlignUp(size, 256ULL)*ringSize;
|
|
curoffset = 0;
|
|
|
|
VkBufferCreateInfo bufInfo = {
|
|
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL,
|
|
totalsize, 0, 0,
|
|
VK_SHARING_MODE_EXCLUSIVE, 0, NULL,
|
|
};
|
|
|
|
bufInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SOURCE_BIT;
|
|
bufInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT;
|
|
bufInfo.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
|
|
|
VkResult vkr = vt->CreateBuffer(Unwrap(dev), &bufInfo, &buf);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), buf);
|
|
|
|
VkMemoryRequirements mrq;
|
|
vkr = vt->GetBufferMemoryRequirements(Unwrap(dev), Unwrap(buf), &mrq);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
// VKTODOMED maybe don't require host visible, and do map & copy?
|
|
VkMemoryAllocInfo allocInfo = {
|
|
VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, NULL,
|
|
mrq.size,
|
|
(flags & eGPUBufferReadback)
|
|
? driver->GetReadbackMemoryIndex(mrq.memoryTypeBits)
|
|
: driver->GetUploadMemoryIndex(mrq.memoryTypeBits),
|
|
};
|
|
|
|
vkr = vt->AllocMemory(Unwrap(dev), &allocInfo, &mem);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), mem);
|
|
|
|
vkr = vt->BindBufferMemory(Unwrap(dev), Unwrap(buf), Unwrap(mem), 0);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
}
|
|
|
|
void VulkanDebugManager::GPUBuffer::FillDescriptor(VkDescriptorInfo &desc)
|
|
{
|
|
desc.bufferInfo.buffer = Unwrap(buf);
|
|
desc.bufferInfo.offset = 0;
|
|
desc.bufferInfo.range = sz;
|
|
}
|
|
|
|
void VulkanDebugManager::GPUBuffer::Destroy(const VkLayerDispatchTable *vt, VkDevice dev)
|
|
{
|
|
VkResult vkr = VK_SUCCESS;
|
|
|
|
if(buf != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyBuffer(Unwrap(dev), Unwrap(buf));
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
VKMGR()->ReleaseWrappedResource(buf);
|
|
buf = VK_NULL_HANDLE;
|
|
}
|
|
|
|
if(mem != VK_NULL_HANDLE)
|
|
{
|
|
vt->FreeMemory(Unwrap(dev), Unwrap(mem));
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
VKMGR()->ReleaseWrappedResource(mem);
|
|
mem = VK_NULL_HANDLE;
|
|
}
|
|
}
|
|
|
|
void *VulkanDebugManager::GPUBuffer::Map(const VkLayerDispatchTable *vt, VkDevice dev, uint32_t *bindoffset, VkDeviceSize usedsize)
|
|
{
|
|
VkDeviceSize offset = bindoffset ? curoffset : 0;
|
|
VkDeviceSize size = usedsize > 0 ? usedsize : sz;
|
|
|
|
// wrap around the ring, assuming the ring is large enough
|
|
// that this memory is now free
|
|
if(offset + size > totalsize)
|
|
offset = 0;
|
|
RDCASSERT(offset + size <= totalsize);
|
|
|
|
// offset must be 256-aligned
|
|
curoffset = AlignUp(offset+size, 256ULL);
|
|
|
|
if(bindoffset) *bindoffset = (uint32_t)offset;
|
|
|
|
void *ptr = NULL;
|
|
VkResult vkr = vt->MapMemory(Unwrap(dev), Unwrap(mem), offset, size, 0, (void **)&ptr);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
return ptr;
|
|
}
|
|
|
|
void VulkanDebugManager::GPUBuffer::Unmap(const VkLayerDispatchTable *vt, VkDevice dev)
|
|
{
|
|
vt->UnmapMemory(Unwrap(dev), Unwrap(mem));
|
|
}
|
|
|
|
VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev)
|
|
{
|
|
// VKTODOLOW needs tidy up - isn't scalable. Needs more classes like UBO above.
|
|
|
|
m_DescriptorPool = VK_NULL_HANDLE;
|
|
m_LinearSampler = VK_NULL_HANDLE;
|
|
m_PointSampler = VK_NULL_HANDLE;
|
|
|
|
m_CheckerboardDescSetLayout = VK_NULL_HANDLE;
|
|
m_CheckerboardPipeLayout = VK_NULL_HANDLE;
|
|
m_CheckerboardDescSet = VK_NULL_HANDLE;
|
|
m_CheckerboardPipeline = VK_NULL_HANDLE;
|
|
RDCEraseEl(m_CheckerboardUBO);
|
|
|
|
m_TexDisplayDescSetLayout = VK_NULL_HANDLE;
|
|
m_TexDisplayPipeLayout = VK_NULL_HANDLE;
|
|
m_TexDisplayDescSet = VK_NULL_HANDLE;
|
|
m_TexDisplayPipeline = VK_NULL_HANDLE;
|
|
m_TexDisplayBlendPipeline = VK_NULL_HANDLE;
|
|
RDCEraseEl(m_TexDisplayUBO);
|
|
|
|
m_TextDescSetLayout = VK_NULL_HANDLE;
|
|
m_TextPipeLayout = VK_NULL_HANDLE;
|
|
m_TextDescSet = VK_NULL_HANDLE;
|
|
m_TextPipeline = VK_NULL_HANDLE;
|
|
RDCEraseEl(m_TextGeneralUBO);
|
|
RDCEraseEl(m_TextGlyphUBO);
|
|
RDCEraseEl(m_TextStringUBO);
|
|
m_TextAtlas = VK_NULL_HANDLE;
|
|
m_TextAtlasMem = VK_NULL_HANDLE;
|
|
m_TextAtlasView = VK_NULL_HANDLE;
|
|
|
|
m_GenericDescSetLayout = VK_NULL_HANDLE;
|
|
m_GenericPipeLayout = VK_NULL_HANDLE;
|
|
m_GenericDescSet = VK_NULL_HANDLE;
|
|
m_GenericPipeline = VK_NULL_HANDLE;
|
|
|
|
m_Device = dev;
|
|
|
|
const VkLayerDispatchTable *vt = ObjDisp(dev);
|
|
|
|
VkResult vkr = VK_SUCCESS;
|
|
|
|
VkSamplerCreateInfo sampInfo = {
|
|
VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, NULL,
|
|
VK_TEX_FILTER_LINEAR, VK_TEX_FILTER_LINEAR,
|
|
VK_TEX_MIPMAP_MODE_LINEAR,
|
|
VK_TEX_ADDRESS_MODE_CLAMP, VK_TEX_ADDRESS_MODE_CLAMP, VK_TEX_ADDRESS_MODE_CLAMP,
|
|
0.0f, // lod bias
|
|
1.0f, // max aniso
|
|
false, VK_COMPARE_OP_NEVER,
|
|
0.0f, 128.0f, // min/max lod
|
|
VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
|
|
false, // unnormalized
|
|
};
|
|
|
|
vkr = vt->CreateSampler(Unwrap(dev), &sampInfo, &m_LinearSampler);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_LinearSampler);
|
|
|
|
sampInfo.minFilter = VK_TEX_FILTER_NEAREST;
|
|
sampInfo.magFilter = VK_TEX_FILTER_NEAREST;
|
|
sampInfo.mipMode = VK_TEX_MIPMAP_MODE_NEAREST;
|
|
|
|
vkr = vt->CreateSampler(Unwrap(dev), &sampInfo, &m_PointSampler);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_PointSampler);
|
|
|
|
{
|
|
// VKTODOLOW not sure if these stage flags VK_SHADER_STAGE_... work yet?
|
|
VkDescriptorSetLayoutBinding layoutBinding[] = {
|
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, NULL, }
|
|
};
|
|
|
|
VkDescriptorSetLayoutCreateInfo descsetLayoutInfo = {
|
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL,
|
|
ARRAY_COUNT(layoutBinding), &layoutBinding[0],
|
|
};
|
|
|
|
vkr = vt->CreateDescriptorSetLayout(Unwrap(dev), &descsetLayoutInfo, &m_CheckerboardDescSetLayout);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_CheckerboardDescSetLayout);
|
|
|
|
// identical layout
|
|
vkr = vt->CreateDescriptorSetLayout(Unwrap(dev), &descsetLayoutInfo, &m_GenericDescSetLayout);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_GenericDescSetLayout);
|
|
}
|
|
|
|
{
|
|
VkDescriptorSetLayoutBinding layoutBinding[] = {
|
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, NULL, },
|
|
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, NULL, }
|
|
};
|
|
|
|
VkDescriptorSetLayoutCreateInfo descsetLayoutInfo = {
|
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL,
|
|
ARRAY_COUNT(layoutBinding), &layoutBinding[0],
|
|
};
|
|
|
|
vkr = vt->CreateDescriptorSetLayout(Unwrap(dev), &descsetLayoutInfo, &m_TexDisplayDescSetLayout);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TexDisplayDescSetLayout);
|
|
}
|
|
|
|
{
|
|
VkDescriptorSetLayoutBinding layoutBinding[] = {
|
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, NULL, },
|
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, NULL, },
|
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, NULL, },
|
|
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, NULL, }
|
|
};
|
|
|
|
VkDescriptorSetLayoutCreateInfo descsetLayoutInfo = {
|
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, NULL,
|
|
ARRAY_COUNT(layoutBinding), &layoutBinding[0],
|
|
};
|
|
|
|
vkr = vt->CreateDescriptorSetLayout(Unwrap(dev), &descsetLayoutInfo, &m_TextDescSetLayout);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TextDescSetLayout);
|
|
}
|
|
|
|
VkPipelineLayoutCreateInfo pipeLayoutInfo = {
|
|
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, NULL,
|
|
1, UnwrapPtr(m_TexDisplayDescSetLayout),
|
|
0, NULL, // push constant ranges
|
|
};
|
|
|
|
vkr = vt->CreatePipelineLayout(Unwrap(dev), &pipeLayoutInfo, &m_TexDisplayPipeLayout);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TexDisplayPipeLayout);
|
|
|
|
pipeLayoutInfo.pSetLayouts = UnwrapPtr(m_CheckerboardDescSetLayout);
|
|
|
|
vkr = vt->CreatePipelineLayout(Unwrap(dev), &pipeLayoutInfo, &m_CheckerboardPipeLayout);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_CheckerboardPipeLayout);
|
|
|
|
pipeLayoutInfo.pSetLayouts = UnwrapPtr(m_TextDescSetLayout);
|
|
|
|
vkr = vt->CreatePipelineLayout(Unwrap(dev), &pipeLayoutInfo, &m_TextPipeLayout);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TextPipeLayout);
|
|
|
|
pipeLayoutInfo.pSetLayouts = UnwrapPtr(m_GenericDescSetLayout);
|
|
|
|
vkr = vt->CreatePipelineLayout(Unwrap(dev), &pipeLayoutInfo, &m_GenericPipeLayout);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_GenericPipeLayout);
|
|
|
|
VkDescriptorTypeCount descPoolTypes[] = {
|
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1024, },
|
|
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1024, },
|
|
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1024, },
|
|
};
|
|
|
|
VkDescriptorPoolCreateInfo descpoolInfo = {
|
|
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, NULL,
|
|
VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 4,
|
|
ARRAY_COUNT(descPoolTypes), &descPoolTypes[0],
|
|
};
|
|
|
|
vkr = vt->CreateDescriptorPool(Unwrap(dev), &descpoolInfo, &m_DescriptorPool);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_DescriptorPool);
|
|
|
|
vkr = vt->AllocDescriptorSets(Unwrap(dev), Unwrap(m_DescriptorPool), VK_DESCRIPTOR_SET_USAGE_STATIC, 1,
|
|
UnwrapPtr(m_CheckerboardDescSetLayout), &m_CheckerboardDescSet);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_CheckerboardDescSet);
|
|
|
|
vkr = vt->AllocDescriptorSets(Unwrap(dev), Unwrap(m_DescriptorPool), VK_DESCRIPTOR_SET_USAGE_STATIC, 1,
|
|
UnwrapPtr(m_TexDisplayDescSetLayout), &m_TexDisplayDescSet);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TexDisplayDescSet);
|
|
|
|
vkr = vt->AllocDescriptorSets(Unwrap(dev), Unwrap(m_DescriptorPool), VK_DESCRIPTOR_SET_USAGE_STATIC, 1,
|
|
UnwrapPtr(m_TextDescSetLayout), &m_TextDescSet);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TextDescSet);
|
|
|
|
vkr = vt->AllocDescriptorSets(Unwrap(dev), Unwrap(m_DescriptorPool), VK_DESCRIPTOR_SET_USAGE_STATIC, 1,
|
|
UnwrapPtr(m_GenericDescSetLayout), &m_GenericDescSet);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_GenericDescSet);
|
|
|
|
m_GenericUBO.Create(driver, dev, 128, 10, 0);
|
|
RDCCOMPILE_ASSERT(sizeof(genericuniforms) <= 128, "outline strip VBO size");
|
|
|
|
{
|
|
float data[] = {
|
|
0.0f, 0.0f, 0.0f, 1.0f,
|
|
1.0f, 0.0f, 0.0f, 1.0f,
|
|
|
|
1.0f, 0.0f, 0.0f, 1.0f,
|
|
1.0f, 1.0f, 0.0f, 1.0f,
|
|
|
|
1.0f, 1.0f, 0.0f, 1.0f,
|
|
0.0f, 1.0f, 0.0f, 1.0f,
|
|
|
|
0.0f, 1.0f, 0.0f, 1.0f,
|
|
0.0f, -0.1f, 0.0f, 1.0f,
|
|
};
|
|
|
|
m_OutlineStripVBO.Create(driver, dev, 128, 1, 0); // doesn't need to be ring buffered
|
|
RDCCOMPILE_ASSERT(sizeof(data) <= 128, "outline strip VBO size");
|
|
|
|
float *mapped = (float *)m_OutlineStripVBO.Map(vt, dev, NULL);
|
|
|
|
memcpy(mapped, data, sizeof(data));
|
|
|
|
m_OutlineStripVBO.Unmap(vt, dev);
|
|
}
|
|
|
|
m_CheckerboardUBO.Create(driver, dev, 128, 10, 0);
|
|
m_TexDisplayUBO.Create(driver, dev, 128, 10, 0);
|
|
|
|
RDCCOMPILE_ASSERT(sizeof(displayuniforms) <= 128, "tex display size");
|
|
|
|
m_TextGeneralUBO.Create(driver, dev, 128, 100, 0); // make the ring conservatively large to handle many lines of text * several frames
|
|
RDCCOMPILE_ASSERT(sizeof(fontuniforms) <= 128, "font uniforms size");
|
|
|
|
m_TextStringUBO.Create(driver, dev, 4096, 10, 0); // we only use a subset of the [256] array needed for each line, so this ring can be smaller
|
|
RDCCOMPILE_ASSERT(sizeof(stringdata) <= 4096, "font uniforms size");
|
|
|
|
string shaderSources[] = {
|
|
GetEmbeddedResource(blitvs_spv),
|
|
GetEmbeddedResource(checkerboardfs_spv),
|
|
GetEmbeddedResource(texdisplayfs_spv),
|
|
GetEmbeddedResource(textvs_spv),
|
|
GetEmbeddedResource(textfs_spv),
|
|
GetEmbeddedResource(genericvs_spv),
|
|
GetEmbeddedResource(genericfs_spv),
|
|
};
|
|
|
|
bool vtxShader[] = {
|
|
true,
|
|
false,
|
|
false,
|
|
true,
|
|
false,
|
|
true,
|
|
false,
|
|
};
|
|
|
|
enum shaderIdx
|
|
{
|
|
BLITVS,
|
|
CHECKERBOARDFS,
|
|
TEXDISPLAYFS,
|
|
TEXTVS,
|
|
TEXTFS,
|
|
GENERICVS,
|
|
GENERICFS,
|
|
};
|
|
|
|
VkShaderModule module[ARRAY_COUNT(shaderSources)];
|
|
VkShader shader[ARRAY_COUNT(shaderSources)];
|
|
|
|
for(size_t i=0; i < ARRAY_COUNT(module); i++)
|
|
{
|
|
VkShaderModuleCreateInfo modinfo = {
|
|
VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, NULL,
|
|
shaderSources[i].size(), (void *)&shaderSources[i][0], 0,
|
|
};
|
|
|
|
vkr = vt->CreateShaderModule(Unwrap(dev), &modinfo, &module[i]);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), module[i]);
|
|
|
|
VkShaderCreateInfo shadinfo = {
|
|
VK_STRUCTURE_TYPE_SHADER_CREATE_INFO, NULL,
|
|
Unwrap(module[i]), "main", 0,
|
|
vtxShader[i] ? VK_SHADER_STAGE_VERTEX : VK_SHADER_STAGE_FRAGMENT,
|
|
};
|
|
|
|
vkr = vt->CreateShader(Unwrap(dev), &shadinfo, &shader[i]);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), shader[i]);
|
|
}
|
|
|
|
VkPipelineShaderStageCreateInfo stages[2] = {
|
|
{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, VK_SHADER_STAGE_VERTEX, VK_NULL_HANDLE, NULL },
|
|
{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, NULL, VK_SHADER_STAGE_FRAGMENT, VK_NULL_HANDLE, NULL },
|
|
};
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo ia = {
|
|
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, NULL,
|
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, false,
|
|
};
|
|
|
|
VkRect2D scissor = { { 0, 0 }, { 4096, 4096 } };
|
|
|
|
VkPipelineViewportStateCreateInfo vp = {
|
|
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, NULL,
|
|
1, NULL,
|
|
1, &scissor
|
|
};
|
|
|
|
VkPipelineRasterStateCreateInfo rs = {
|
|
VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO, NULL,
|
|
true, false, VK_FILL_MODE_SOLID, VK_CULL_MODE_NONE, VK_FRONT_FACE_CW,
|
|
false, 0.0f, 0.0f, 0.0f, 1.0f,
|
|
};
|
|
|
|
VkPipelineMultisampleStateCreateInfo msaa = {
|
|
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, NULL,
|
|
1, false, 0.0f, NULL,
|
|
};
|
|
|
|
VkPipelineDepthStencilStateCreateInfo ds = {
|
|
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, NULL,
|
|
false, false, VK_COMPARE_OP_ALWAYS, false, false,
|
|
{ VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0, 0, 0 },
|
|
{ VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0, 0, 0 },
|
|
0.0f, 1.0f,
|
|
};
|
|
|
|
VkPipelineColorBlendAttachmentState attState = {
|
|
false,
|
|
VK_BLEND_ONE, VK_BLEND_ZERO, VK_BLEND_OP_ADD,
|
|
VK_BLEND_ONE, VK_BLEND_ZERO, VK_BLEND_OP_ADD,
|
|
0xf,
|
|
};
|
|
|
|
VkPipelineColorBlendStateCreateInfo cb = {
|
|
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, NULL,
|
|
false, false, false, VK_LOGIC_OP_NOOP,
|
|
1, &attState,
|
|
{ 1.0f, 1.0f, 1.0f, 1.0f }
|
|
};
|
|
|
|
VkDynamicState dynstates[] = { VK_DYNAMIC_STATE_VIEWPORT };
|
|
|
|
VkPipelineDynamicStateCreateInfo dyn = {
|
|
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, NULL,
|
|
ARRAY_COUNT(dynstates), dynstates,
|
|
};
|
|
|
|
VkGraphicsPipelineCreateInfo pipeInfo = {
|
|
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, NULL,
|
|
2, stages,
|
|
NULL, // vertex input
|
|
&ia,
|
|
NULL, // tess
|
|
&vp,
|
|
&rs,
|
|
&msaa,
|
|
&ds,
|
|
&cb,
|
|
&dyn,
|
|
0, // flags
|
|
Unwrap(m_CheckerboardPipeLayout),
|
|
VK_NULL_HANDLE, // render pass
|
|
0, // sub pass
|
|
VK_NULL_HANDLE, // base pipeline handle
|
|
0, // base pipeline index
|
|
};
|
|
|
|
stages[0].shader = Unwrap(shader[BLITVS]);
|
|
stages[1].shader = Unwrap(shader[CHECKERBOARDFS]);
|
|
|
|
vkr = vt->CreateGraphicsPipelines(Unwrap(dev), VK_NULL_HANDLE, 1, &pipeInfo, &m_CheckerboardPipeline);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_CheckerboardPipeline);
|
|
|
|
stages[0].shader = Unwrap(shader[BLITVS]);
|
|
stages[1].shader = Unwrap(shader[TEXDISPLAYFS]);
|
|
|
|
pipeInfo.layout = Unwrap(m_TexDisplayPipeLayout);
|
|
|
|
vkr = vt->CreateGraphicsPipelines(Unwrap(dev), VK_NULL_HANDLE, 1, &pipeInfo, &m_TexDisplayPipeline);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TexDisplayPipeline);
|
|
|
|
attState.blendEnable = true;
|
|
attState.srcBlendColor = VK_BLEND_SRC_ALPHA;
|
|
attState.destBlendColor = VK_BLEND_ONE_MINUS_SRC_ALPHA;
|
|
|
|
vkr = vt->CreateGraphicsPipelines(Unwrap(dev), VK_NULL_HANDLE, 1, &pipeInfo, &m_TexDisplayBlendPipeline);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TexDisplayBlendPipeline);
|
|
|
|
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
|
|
stages[0].shader = Unwrap(shader[TEXTVS]);
|
|
stages[1].shader = Unwrap(shader[TEXTFS]);
|
|
|
|
pipeInfo.layout = Unwrap(m_TextPipeLayout);
|
|
|
|
vkr = vt->CreateGraphicsPipelines(Unwrap(dev), VK_NULL_HANDLE, 1, &pipeInfo, &m_TextPipeline);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TextPipeline);
|
|
|
|
ia.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
|
|
attState.blendEnable = false;
|
|
|
|
VkVertexInputBindingDescription vertexBind = {
|
|
0, sizeof(Vec4f), VK_VERTEX_INPUT_STEP_RATE_VERTEX,
|
|
};
|
|
|
|
VkVertexInputAttributeDescription vertexAttr = {
|
|
0, 0, VK_FORMAT_R32G32B32A32_SFLOAT, 0,
|
|
};
|
|
|
|
VkPipelineVertexInputStateCreateInfo vi = {
|
|
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, NULL,
|
|
1, &vertexBind,
|
|
1, &vertexAttr,
|
|
};
|
|
|
|
pipeInfo.pVertexInputState = &vi;
|
|
|
|
stages[0].shader = Unwrap(shader[GENERICVS]);
|
|
stages[1].shader = Unwrap(shader[GENERICFS]);
|
|
|
|
pipeInfo.layout = Unwrap(m_GenericPipeLayout);
|
|
|
|
vkr = vt->CreateGraphicsPipelines(Unwrap(dev), VK_NULL_HANDLE, 1, &pipeInfo, &m_GenericPipeline);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_GenericPipeline);
|
|
|
|
for(size_t i=0; i < ARRAY_COUNT(module); i++)
|
|
{
|
|
vt->DestroyShader(Unwrap(dev), Unwrap(shader[i]));
|
|
VKMGR()->ReleaseWrappedResource(shader[i]);
|
|
|
|
vt->DestroyShaderModule(Unwrap(dev), Unwrap(module[i]));
|
|
VKMGR()->ReleaseWrappedResource(module[i]);
|
|
}
|
|
|
|
VkCmdBuffer cmd = driver->GetNextCmd();
|
|
|
|
VkCmdBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, NULL, VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT };
|
|
|
|
vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
{
|
|
int width = FONT_TEX_WIDTH, height = FONT_TEX_HEIGHT;
|
|
|
|
VkImageCreateInfo imInfo = {
|
|
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, NULL,
|
|
VK_IMAGE_TYPE_2D, VK_FORMAT_R8_UNORM,
|
|
{ width, height, 1 }, 1, 1, 1,
|
|
VK_IMAGE_TILING_LINEAR,
|
|
VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
0,
|
|
VK_SHARING_MODE_EXCLUSIVE,
|
|
0, NULL,
|
|
VK_IMAGE_LAYOUT_PREINITIALIZED,
|
|
};
|
|
|
|
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];
|
|
int ret = stbtt_BakeFontBitmap(ttfdata, 0, pixelHeight, buf, width, height, firstChar, numChars, chardata);
|
|
|
|
m_FontCharSize = pixelHeight;
|
|
m_FontCharAspect = 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);
|
|
|
|
// create and fill image
|
|
{
|
|
vkr = vt->CreateImage(Unwrap(dev), &imInfo, &m_TextAtlas);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TextAtlas);
|
|
|
|
VkMemoryRequirements mrq;
|
|
vkr = vt->GetImageMemoryRequirements(Unwrap(dev), Unwrap(m_TextAtlas), &mrq);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkImageSubresource subr = { VK_IMAGE_ASPECT_COLOR, 0, 0 };
|
|
VkSubresourceLayout layout = { 0 };
|
|
vt->GetImageSubresourceLayout(Unwrap(dev), Unwrap(m_TextAtlas), &subr, &layout);
|
|
|
|
// allocate readback memory
|
|
VkMemoryAllocInfo allocInfo = {
|
|
VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, NULL,
|
|
mrq.size, driver->GetUploadMemoryIndex(mrq.memoryTypeBits),
|
|
};
|
|
|
|
vkr = vt->AllocMemory(Unwrap(dev), &allocInfo, &m_TextAtlasMem);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TextAtlasMem);
|
|
|
|
vkr = vt->BindImageMemory(Unwrap(dev), Unwrap(m_TextAtlas), Unwrap(m_TextAtlasMem), 0);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkImageViewCreateInfo viewInfo = {
|
|
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, NULL,
|
|
Unwrap(m_TextAtlas), VK_IMAGE_VIEW_TYPE_2D,
|
|
imInfo.format,
|
|
{ VK_CHANNEL_SWIZZLE_R, VK_CHANNEL_SWIZZLE_G, VK_CHANNEL_SWIZZLE_B, VK_CHANNEL_SWIZZLE_A },
|
|
{ VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 1, },
|
|
0,
|
|
};
|
|
|
|
vkr = vt->CreateImageView(Unwrap(dev), &viewInfo, &m_TextAtlasView);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_TextAtlasView);
|
|
|
|
// need to transition image into valid state, then upload
|
|
|
|
VkImageMemoryBarrier trans = {
|
|
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, NULL,
|
|
0, 0,
|
|
VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
|
Unwrap(m_TextAtlas),
|
|
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } };
|
|
|
|
void *barrier = (void *)&trans;
|
|
|
|
vt->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, &barrier);
|
|
|
|
byte *pData = NULL;
|
|
vkr = vt->MapMemory(Unwrap(dev), Unwrap(m_TextAtlasMem), 0, 0, 0, (void **)&pData);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
RDCASSERT(pData != NULL);
|
|
|
|
for(int32_t row = 0; row < height; row++)
|
|
{
|
|
memcpy(pData, buf, width);
|
|
pData += layout.rowPitch;
|
|
buf += width;
|
|
}
|
|
|
|
vt->UnmapMemory(Unwrap(dev), Unwrap(m_TextAtlasMem));
|
|
}
|
|
|
|
m_TextGlyphUBO.Create(driver, dev, 4096, 1, 0); // doesn't need to be ring'd, as it's static
|
|
RDCCOMPILE_ASSERT(sizeof(Vec4f)*2*(numChars+1) < 4096, "font uniform size");
|
|
|
|
Vec4f *glyphData = (Vec4f *)m_TextGlyphUBO.Map(vt, dev, NULL);
|
|
|
|
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);
|
|
}
|
|
|
|
m_TextGlyphUBO.Unmap(vt, dev);
|
|
}
|
|
|
|
// pick pixel data
|
|
{
|
|
// create image
|
|
|
|
VkImageCreateInfo imInfo = {
|
|
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, NULL,
|
|
VK_IMAGE_TYPE_2D, VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
{ 1, 1, 1 }, 1, 1, 1,
|
|
VK_IMAGE_TILING_OPTIMAL,
|
|
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT,
|
|
0,
|
|
VK_SHARING_MODE_EXCLUSIVE,
|
|
0, NULL,
|
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
|
};
|
|
|
|
vkr = vt->CreateImage(Unwrap(dev), &imInfo, &m_PickPixelImage);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_PickPixelImage);
|
|
|
|
VkMemoryRequirements mrq;
|
|
vkr = vt->GetImageMemoryRequirements(Unwrap(dev), Unwrap(m_PickPixelImage), &mrq);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkImageSubresource subr = { VK_IMAGE_ASPECT_COLOR, 0, 0 };
|
|
VkSubresourceLayout layout = { 0 };
|
|
vt->GetImageSubresourceLayout(Unwrap(dev), Unwrap(m_PickPixelImage), &subr, &layout);
|
|
|
|
// allocate readback memory
|
|
VkMemoryAllocInfo allocInfo = {
|
|
VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO, NULL,
|
|
mrq.size, driver->GetGPULocalMemoryIndex(mrq.memoryTypeBits),
|
|
};
|
|
|
|
vkr = vt->AllocMemory(Unwrap(dev), &allocInfo, &m_PickPixelImageMem);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_PickPixelImageMem);
|
|
|
|
vkr = vt->BindImageMemory(Unwrap(dev), Unwrap(m_PickPixelImage), Unwrap(m_PickPixelImageMem), 0);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkImageViewCreateInfo viewInfo = {
|
|
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, NULL,
|
|
Unwrap(m_PickPixelImage), VK_IMAGE_VIEW_TYPE_2D,
|
|
VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
{ VK_CHANNEL_SWIZZLE_R, VK_CHANNEL_SWIZZLE_G, VK_CHANNEL_SWIZZLE_B, VK_CHANNEL_SWIZZLE_A },
|
|
{ VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 1, },
|
|
0,
|
|
};
|
|
|
|
// VKTODOMED used for texture display, but eventually will have to be created on the fly
|
|
// for whichever image we're viewing (and cached), not specifically created here.
|
|
vkr = vt->CreateImageView(Unwrap(dev), &viewInfo, &m_PickPixelImageView);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_PickPixelImageView);
|
|
|
|
// need to transition image into valid state
|
|
|
|
VkImageMemoryBarrier trans = {
|
|
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, NULL,
|
|
0, 0,
|
|
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
|
Unwrap(m_PickPixelImage),
|
|
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
|
|
};
|
|
|
|
void *barrier = (void *)&trans;
|
|
|
|
vt->CmdPipelineBarrier(Unwrap(cmd), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, &barrier);
|
|
|
|
// create render pass
|
|
VkAttachmentDescription attDesc = {
|
|
VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION, NULL,
|
|
VK_FORMAT_R32G32B32A32_SFLOAT, 1,
|
|
VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
|
|
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
|
};
|
|
|
|
VkAttachmentReference attRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
|
|
|
|
VkSubpassDescription sub = {
|
|
VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION, NULL,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS, 0,
|
|
0, NULL, // inputs
|
|
1, &attRef, // color
|
|
NULL, // resolve
|
|
{ VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED }, // depth-stencil
|
|
0, NULL, // preserve
|
|
};
|
|
|
|
VkRenderPassCreateInfo rpinfo = {
|
|
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, NULL,
|
|
1, &attDesc,
|
|
1, &sub,
|
|
0, NULL, // dependencies
|
|
};
|
|
|
|
vkr = vt->CreateRenderPass(Unwrap(dev), &rpinfo, &m_PickPixelRP);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_PickPixelRP);
|
|
|
|
// create framebuffer
|
|
VkFramebufferCreateInfo fbinfo = {
|
|
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, NULL,
|
|
Unwrap(m_PickPixelRP),
|
|
1, UnwrapPtr(m_PickPixelImageView),
|
|
1, 1, 1,
|
|
};
|
|
|
|
vkr = vt->CreateFramebuffer(Unwrap(dev), &fbinfo, &m_PickPixelFB);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VKMGR()->WrapResource(Unwrap(dev), m_PickPixelFB);
|
|
|
|
// since we always sync for readback, doesn't need to be ring'd
|
|
m_PickPixelReadbackBuffer.Create(driver, dev, sizeof(float)*4, 1, GPUBuffer::eGPUBufferReadback);
|
|
}
|
|
|
|
VkDescriptorInfo desc[7];
|
|
RDCEraseEl(desc);
|
|
|
|
// checkerboard
|
|
m_CheckerboardUBO.FillDescriptor(desc[0]);
|
|
|
|
// tex display
|
|
m_TexDisplayUBO.FillDescriptor(desc[1]);
|
|
// image descriptor is updated right before rendering
|
|
|
|
// text
|
|
m_TextGeneralUBO.FillDescriptor(desc[2]);
|
|
m_TextGlyphUBO.FillDescriptor(desc[3]);
|
|
m_TextStringUBO.FillDescriptor(desc[4]);
|
|
desc[5].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
|
desc[5].imageView = Unwrap(m_TextAtlasView);
|
|
desc[5].sampler = Unwrap(m_LinearSampler);
|
|
|
|
// generic
|
|
m_GenericUBO.FillDescriptor(desc[6]);
|
|
|
|
VkWriteDescriptorSet writeSet[] = {
|
|
{
|
|
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
|
Unwrap(m_CheckerboardDescSet), 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &desc[0]
|
|
},
|
|
{
|
|
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
|
Unwrap(m_TexDisplayDescSet), 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &desc[1]
|
|
},
|
|
{
|
|
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
|
Unwrap(m_TextDescSet), 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &desc[2]
|
|
},
|
|
{
|
|
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
|
Unwrap(m_TextDescSet), 1, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &desc[3]
|
|
},
|
|
{
|
|
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
|
Unwrap(m_TextDescSet), 2, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &desc[4]
|
|
},
|
|
{
|
|
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
|
Unwrap(m_TextDescSet), 3, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &desc[5]
|
|
},
|
|
{
|
|
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
|
Unwrap(m_GenericDescSet), 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, &desc[6]
|
|
},
|
|
};
|
|
|
|
vt->UpdateDescriptorSets(Unwrap(dev), ARRAY_COUNT(writeSet), writeSet, 0, NULL);
|
|
|
|
vt->EndCommandBuffer(Unwrap(cmd));
|
|
driver->SubmitCmds();
|
|
}
|
|
|
|
VulkanDebugManager::~VulkanDebugManager()
|
|
{
|
|
VkDevice dev = m_Device;
|
|
const VkLayerDispatchTable *vt = ObjDisp(dev);
|
|
|
|
VkResult vkr = VK_SUCCESS;
|
|
|
|
if(m_DescriptorPool != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyDescriptorPool(Unwrap(dev), Unwrap(m_DescriptorPool));
|
|
VKMGR()->ReleaseWrappedResource(m_DescriptorPool);
|
|
}
|
|
|
|
if(m_LinearSampler != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroySampler(Unwrap(dev), Unwrap(m_LinearSampler));
|
|
VKMGR()->ReleaseWrappedResource(m_LinearSampler);
|
|
}
|
|
|
|
if(m_PointSampler != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroySampler(Unwrap(dev), Unwrap(m_PointSampler));
|
|
VKMGR()->ReleaseWrappedResource(m_PointSampler);
|
|
}
|
|
|
|
if(m_CheckerboardDescSetLayout != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyDescriptorSetLayout(Unwrap(dev), Unwrap(m_CheckerboardDescSetLayout));
|
|
VKMGR()->ReleaseWrappedResource(m_CheckerboardDescSetLayout);
|
|
}
|
|
|
|
if(m_CheckerboardPipeLayout != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyPipelineLayout(Unwrap(dev), Unwrap(m_CheckerboardPipeLayout));
|
|
VKMGR()->ReleaseWrappedResource(m_CheckerboardPipeLayout);
|
|
}
|
|
|
|
if(m_CheckerboardPipeline != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyPipeline(Unwrap(dev), Unwrap(m_CheckerboardPipeline));
|
|
VKMGR()->ReleaseWrappedResource(m_CheckerboardPipeline);
|
|
}
|
|
|
|
if(m_TexDisplayDescSetLayout != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyDescriptorSetLayout(Unwrap(dev), Unwrap(m_TexDisplayDescSetLayout));
|
|
VKMGR()->ReleaseWrappedResource(m_TexDisplayDescSetLayout);
|
|
}
|
|
|
|
if(m_TexDisplayPipeLayout != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyPipelineLayout(Unwrap(dev), Unwrap(m_TexDisplayPipeLayout));
|
|
VKMGR()->ReleaseWrappedResource(m_TexDisplayPipeLayout);
|
|
}
|
|
|
|
if(m_TexDisplayPipeline != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyPipeline(Unwrap(dev), Unwrap(m_TexDisplayPipeline));
|
|
VKMGR()->ReleaseWrappedResource(m_TexDisplayPipeline);
|
|
}
|
|
|
|
if(m_TexDisplayBlendPipeline != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyPipeline(Unwrap(dev), Unwrap(m_TexDisplayBlendPipeline));
|
|
VKMGR()->ReleaseWrappedResource(m_TexDisplayBlendPipeline);
|
|
}
|
|
|
|
m_CheckerboardUBO.Destroy(vt, dev);
|
|
m_TexDisplayUBO.Destroy(vt, dev);
|
|
|
|
m_PickPixelReadbackBuffer.Destroy(vt, dev);
|
|
|
|
if(m_PickPixelFB != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyFramebuffer(Unwrap(dev), Unwrap(m_PickPixelFB));
|
|
VKMGR()->ReleaseWrappedResource(m_PickPixelFB);
|
|
}
|
|
|
|
if(m_PickPixelRP != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyRenderPass(Unwrap(dev), Unwrap(m_PickPixelRP));
|
|
VKMGR()->ReleaseWrappedResource(m_PickPixelRP);
|
|
}
|
|
|
|
if(m_PickPixelImageView != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyImageView(Unwrap(dev), Unwrap(m_PickPixelImageView));
|
|
VKMGR()->ReleaseWrappedResource(m_PickPixelImageView);
|
|
}
|
|
|
|
if(m_PickPixelImage != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyImage(Unwrap(dev), Unwrap(m_PickPixelImage));
|
|
VKMGR()->ReleaseWrappedResource(m_PickPixelImage);
|
|
}
|
|
|
|
if(m_PickPixelImageMem != VK_NULL_HANDLE)
|
|
{
|
|
vt->FreeMemory(Unwrap(dev), Unwrap(m_PickPixelImageMem));
|
|
VKMGR()->ReleaseWrappedResource(m_PickPixelImageMem);
|
|
}
|
|
|
|
if(m_TextDescSetLayout != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyDescriptorSetLayout(Unwrap(dev), Unwrap(m_TextDescSetLayout));
|
|
VKMGR()->ReleaseWrappedResource(m_TextDescSetLayout);
|
|
}
|
|
|
|
if(m_TextPipeLayout != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyPipelineLayout(Unwrap(dev), Unwrap(m_TextPipeLayout));
|
|
VKMGR()->ReleaseWrappedResource(m_TextPipeLayout);
|
|
}
|
|
|
|
if(m_TextPipeline != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyPipeline(Unwrap(dev), Unwrap(m_TextPipeline));
|
|
VKMGR()->ReleaseWrappedResource(m_TextPipeline);
|
|
}
|
|
|
|
m_TextGeneralUBO.Destroy(vt, dev);
|
|
m_TextGlyphUBO.Destroy(vt, dev);
|
|
m_TextStringUBO.Destroy(vt, dev);
|
|
|
|
if(m_TextAtlasView != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyImageView(Unwrap(dev), Unwrap(m_TextAtlasView));
|
|
VKMGR()->ReleaseWrappedResource(m_TextAtlasView);
|
|
}
|
|
|
|
if(m_TextAtlas != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyImage(Unwrap(dev), Unwrap(m_TextAtlas));
|
|
VKMGR()->ReleaseWrappedResource(m_TextAtlas);
|
|
}
|
|
|
|
if(m_TextAtlasMem != VK_NULL_HANDLE)
|
|
{
|
|
vt->FreeMemory(Unwrap(dev), Unwrap(m_TextAtlasMem));
|
|
VKMGR()->ReleaseWrappedResource(m_TextAtlasMem);
|
|
}
|
|
|
|
if(m_GenericDescSetLayout != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyDescriptorSetLayout(Unwrap(dev), Unwrap(m_GenericDescSetLayout));
|
|
VKMGR()->ReleaseWrappedResource(m_GenericDescSetLayout);
|
|
}
|
|
|
|
if(m_GenericPipeLayout != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyPipelineLayout(Unwrap(dev), Unwrap(m_GenericPipeLayout));
|
|
VKMGR()->ReleaseWrappedResource(m_GenericPipeLayout);
|
|
}
|
|
|
|
if(m_GenericPipeline != VK_NULL_HANDLE)
|
|
{
|
|
vt->DestroyPipeline(Unwrap(dev), Unwrap(m_GenericPipeline));
|
|
VKMGR()->ReleaseWrappedResource(m_GenericPipeline);
|
|
}
|
|
|
|
m_OutlineStripVBO.Destroy(vt, dev);
|
|
m_GenericUBO.Destroy(vt, dev);
|
|
}
|
|
|
|
void VulkanDebugManager::BeginText(const TextPrintState &textstate)
|
|
{
|
|
const VkLayerDispatchTable *vt = ObjDisp(textstate.cmd);
|
|
|
|
VkCmdBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO, NULL, VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT | VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT };
|
|
|
|
VkResult vkr = vt->BeginCommandBuffer(Unwrap(textstate.cmd), &beginInfo);
|
|
RDCASSERT(vkr == VK_SUCCESS);
|
|
|
|
VkClearValue clearval = {0};
|
|
VkRenderPassBeginInfo rpbegin = {
|
|
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, NULL,
|
|
Unwrap(textstate.rp), Unwrap(textstate.fb),
|
|
{ { 0, 0, }, { textstate.w, textstate.h} },
|
|
1, &clearval,
|
|
};
|
|
vt->CmdBeginRenderPass(Unwrap(textstate.cmd), &rpbegin, VK_RENDER_PASS_CONTENTS_INLINE);
|
|
|
|
vt->CmdBindPipeline(Unwrap(textstate.cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(m_TextPipeline));
|
|
|
|
VkViewport viewport = { 0.0f, 0.0f, (float)textstate.w, (float)textstate.h, 0.0f, 1.0f };
|
|
vt->CmdSetViewport(Unwrap(textstate.cmd), 1, &viewport);
|
|
}
|
|
|
|
void VulkanDebugManager::RenderText(const TextPrintState &textstate, 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(textstate, x, y, tmpBuf);
|
|
}
|
|
|
|
void VulkanDebugManager::RenderTextInternal(const TextPrintState &textstate, float x, float y, const char *text)
|
|
{
|
|
const VkLayerDispatchTable *vt = ObjDisp(textstate.cmd);
|
|
|
|
VkResult vkr = VK_SUCCESS;
|
|
|
|
uint32_t offsets[2] = { 0 };
|
|
|
|
fontuniforms *ubo = (fontuniforms *)m_TextGeneralUBO.Map(vt, m_Device, &offsets[0]);
|
|
|
|
ubo->TextPosition.x = x;
|
|
ubo->TextPosition.y = y;
|
|
|
|
ubo->FontScreenAspect.x = 1.0f/float(textstate.w);
|
|
ubo->FontScreenAspect.y = 1.0f/float(textstate.h);
|
|
|
|
ubo->TextSize = m_FontCharSize;
|
|
ubo->FontScreenAspect.x *= m_FontCharAspect;
|
|
|
|
ubo->CharacterSize.x = 1.0f/float(FONT_TEX_WIDTH);
|
|
ubo->CharacterSize.y = 1.0f/float(FONT_TEX_HEIGHT);
|
|
|
|
m_TextGeneralUBO.Unmap(vt, m_Device);
|
|
|
|
// only map enough for our string
|
|
stringdata *stringData = (stringdata *)m_TextStringUBO.Map(vt, m_Device, &offsets[1], strlen(text)*sizeof(Vec4f));
|
|
|
|
for(size_t i=0; i < strlen(text); i++)
|
|
stringData->str[i][0] = uint32_t(text[i] - ' ');
|
|
|
|
m_TextStringUBO.Unmap(vt, m_Device);
|
|
|
|
vt->CmdBindDescriptorSets(Unwrap(textstate.cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, Unwrap(m_TextPipeLayout), 0, 1, UnwrapPtr(m_TextDescSet), 2, offsets);
|
|
|
|
// VKTODOMED strip + instance ID doesn't seem to work atm? instance ID comes through 0
|
|
// for now, do lists, but want to change back
|
|
vt->CmdDraw(Unwrap(textstate.cmd), 6*(uint32_t)strlen(text), 1, 0, 0);
|
|
}
|
|
|
|
void VulkanDebugManager::EndText(const TextPrintState &textstate)
|
|
{
|
|
ObjDisp(textstate.cmd)->CmdEndRenderPass(Unwrap(textstate.cmd));
|
|
ObjDisp(textstate.cmd)->EndCommandBuffer(Unwrap(textstate.cmd));
|
|
}
|