mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-22 21:55:52 +00:00
Add text-rendering support for in-application renderdoc overlay
This commit is contained in:
@@ -66,6 +66,8 @@ data/glsl/outline.frago \
|
||||
data/spv/blitvs.spvo \
|
||||
data/spv/checkerboardfs.spvo \
|
||||
data/spv/texdisplayfs.spvo \
|
||||
data/spv/textvs.spvo \
|
||||
data/spv/textfs.spvo \
|
||||
data/sourcecodepro.ttfo
|
||||
|
||||
.PHONY: all
|
||||
|
||||
@@ -50,5 +50,7 @@ DECLARE_EMBED(outline_frag);
|
||||
DECLARE_EMBED(blitvs_spv);
|
||||
DECLARE_EMBED(checkerboardfs_spv);
|
||||
DECLARE_EMBED(texdisplayfs_spv);
|
||||
DECLARE_EMBED(textvs_spv);
|
||||
DECLARE_EMBED(textfs_spv);
|
||||
|
||||
#undef DECLARE_EMBED
|
||||
|
||||
@@ -134,6 +134,8 @@ RESOURCE_sourcecodepro_ttf TYPE_EMBED "sourcecodepro.ttf"
|
||||
RESOURCE_blitvs_spv TYPE_EMBED "spv/blitvs.spv"
|
||||
RESOURCE_checkerboardfs_spv TYPE_EMBED "spv/checkerboardfs.spv"
|
||||
RESOURCE_texdisplayfs_spv TYPE_EMBED "spv/texdisplayfs.spv"
|
||||
RESOURCE_textvs_spv TYPE_EMBED "spv/textvs.spv"
|
||||
RESOURCE_textfs_spv TYPE_EMBED "spv/textfs.spv"
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#define RESOURCE_blitvs_spv 401
|
||||
#define RESOURCE_checkerboardfs_spv 402
|
||||
#define RESOURCE_texdisplayfs_spv 403
|
||||
#define RESOURCE_textvs_spv 404
|
||||
#define RESOURCE_textfs_spv 405
|
||||
|
||||
#if !defined(STRINGIZE)
|
||||
#define STRINGIZE2(a) #a
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
|
||||
#version 420 core
|
||||
|
||||
layout (binding = 3) uniform sampler2D tex0;
|
||||
layout (location = 0) out vec4 color_out;
|
||||
|
||||
in v2f
|
||||
{
|
||||
vec4 tex;
|
||||
vec2 glyphuv;
|
||||
} IN;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
float text = 0;
|
||||
|
||||
if(IN.glyphuv.x >= 0.0f && IN.glyphuv.x <= 1.0f &&
|
||||
IN.glyphuv.y >= 0.0f && IN.glyphuv.y <= 1.0f)
|
||||
{
|
||||
vec2 uv;
|
||||
uv.x = mix(IN.tex.x, IN.tex.z, IN.glyphuv.x);
|
||||
uv.y = mix(IN.tex.y, IN.tex.w, IN.glyphuv.y);
|
||||
text = texture(tex0, uv.xy).x;
|
||||
}
|
||||
|
||||
color_out = vec4(text.xxx, clamp(text + 0.5f, 0.0f, 1.0f));
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/******************************************************************************
|
||||
* 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.
|
||||
******************************************************************************/
|
||||
|
||||
#version 420 core
|
||||
|
||||
layout (binding = 0, std140) uniform fontuniforms
|
||||
{
|
||||
vec2 TextPosition;
|
||||
float txtpadding;
|
||||
float TextSize;
|
||||
|
||||
vec2 CharacterSize;
|
||||
vec2 FontScreenAspect;
|
||||
} general;
|
||||
|
||||
struct glyph
|
||||
{
|
||||
vec4 posdata;
|
||||
vec4 uvdata;
|
||||
};
|
||||
|
||||
layout (binding = 1, std140) uniform glyphdata
|
||||
{
|
||||
glyph data[127-32];
|
||||
} glyphs;
|
||||
|
||||
layout (binding = 2, std140) uniform stringdata
|
||||
{
|
||||
uvec4 chars[256];
|
||||
} str;
|
||||
|
||||
out gl_PerVertex
|
||||
{
|
||||
vec4 gl_Position;
|
||||
float gl_PointSize;
|
||||
float gl_ClipDistance[];
|
||||
};
|
||||
|
||||
out v2f
|
||||
{
|
||||
vec4 tex;
|
||||
vec2 glyphuv;
|
||||
} OUT;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// VKTODOMED temporarily drawing lists
|
||||
const vec3 verts[6] = vec3[6](vec3( 0.0, 0.0, 0.5),
|
||||
vec3( 1.0, 0.0, 0.5),
|
||||
vec3( 0.0, 1.0, 0.5),
|
||||
|
||||
vec3( 1.0, 0.0, 0.5),
|
||||
vec3( 0.0, 1.0, 0.5),
|
||||
vec3( 1.0, 1.0, 0.5));
|
||||
|
||||
vec3 pos = verts[gl_VertexID%6];
|
||||
uint strindex = (gl_VertexID/6);
|
||||
|
||||
vec2 charPos = vec2(strindex + pos.x + general.TextPosition.x, pos.y + general.TextPosition.y);
|
||||
|
||||
gl_Position = vec4(charPos.xy*2.0f*general.TextSize*general.FontScreenAspect.xy + vec2(-1, -1), 1, 1);
|
||||
|
||||
uint chars[20] = uint[20](0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19);
|
||||
|
||||
glyph G = glyphs.data[ str.chars[strindex].x ];
|
||||
|
||||
OUT.glyphuv.xy = (pos.xy - G.posdata.xy) * G.posdata.zw;
|
||||
OUT.tex = G.uvdata * general.CharacterSize.xyxy;
|
||||
|
||||
const vec3 cols[5] = vec3[5](vec3(0, 0, 0),
|
||||
vec3(1, 0, 0),
|
||||
vec3(0, 1, 0),
|
||||
vec3(0, 0, 1),
|
||||
vec3(1, 0, 1));
|
||||
}
|
||||
@@ -15,6 +15,7 @@ vk_core.o \
|
||||
vk_common.o \
|
||||
vk_manager.o \
|
||||
vk_resources.o \
|
||||
vk_debug.o \
|
||||
LoaderAndTools/layers/vk_layer_table.o \
|
||||
vk_replay.o \
|
||||
vk_info.o \
|
||||
@@ -24,6 +25,9 @@ DOBJDIR=../../.obj/data/spv
|
||||
DATA=blitvs.spvo \
|
||||
checkerboardfs.spvo \
|
||||
texdisplayfs.spvo \
|
||||
textvs.spvo \
|
||||
textfs.spvo \
|
||||
../sourcecodepro.ttfo
|
||||
|
||||
OBJDIR_DATA=$(addprefix $(DOBJDIR)/, $(DATA))
|
||||
|
||||
@@ -55,11 +59,13 @@ vk_info.o \
|
||||
vk_replay_linux.o \
|
||||
)
|
||||
|
||||
EXTRA_OBJECTS=../../.obj/3rdparty/stb/stb_impl.o ../../.obj/3rdparty/jpeg-compressor/jpge.o
|
||||
|
||||
rdoc_vulkan.a: $(STATIC_OBJECTS)
|
||||
ar rcs rdoc_vulkan.a $(STATIC_OBJECTS)
|
||||
|
||||
libVKLayerRenderdoc.so: $(OBJDIR_OBJECTS) $(OBJDIR_DATA) $(VULKAN_SDK_SRC)/build/layers/liblayer_utils.so
|
||||
/usr/bin/c++ -fPIC -std=c++11 -DVK_PROTOTYPES -Wpointer-arith -g -Wl,-Bsymbolic -shared -Wl,-soname,libVKLayerRenderdoc.so -o libVKLayerRenderdoc.so $(OBJDIR_OBJECTS) $(OBJDIR_DATA) ../../.obj/os/linux/linux_threading.o ../../.obj/os/linux/linux_stringio.o ../../.obj/os/linux/linux_network.o ../../.obj/os/os_specific.o ../../.obj/serialise/utf8printf.o ../../.obj/serialise/grisu2.o ../../.obj/core/core.o ../../.obj/core/remote_access.o ../../.obj/replay/capture_options.o ../../.obj/replay/type_helpers.o ../../.obj/serialise/serialiser.o ../../.obj/core/resource_manager.o ../../.obj/common/common.o $(VULKAN_SDK_SRC)/build/layers/liblayer_utils.so -Wl,-rpath,$(VULKAN_SDK_SRC)/build/layers -lpthread -lrt -ldl -lX11
|
||||
libVKLayerRenderdoc.so: $(OBJDIR_OBJECTS) $(EXTRA_OBJECTS) $(OBJDIR_DATA) $(VULKAN_SDK_SRC)/build/layers/liblayer_utils.so
|
||||
/usr/bin/c++ -fPIC -std=c++11 -DVK_PROTOTYPES -Wpointer-arith -g -Wl,-Bsymbolic -shared -Wl,-soname,libVKLayerRenderdoc.so -o libVKLayerRenderdoc.so $(OBJDIR_OBJECTS) $(EXTRA_OBJECTS) $(OBJDIR_DATA) ../../.obj/os/linux/linux_threading.o ../../.obj/os/linux/linux_stringio.o ../../.obj/os/linux/linux_network.o ../../.obj/os/os_specific.o ../../.obj/serialise/utf8printf.o ../../.obj/serialise/grisu2.o ../../.obj/core/core.o ../../.obj/core/remote_access.o ../../.obj/replay/capture_options.o ../../.obj/replay/type_helpers.o ../../.obj/serialise/serialiser.o ../../.obj/core/resource_manager.o ../../.obj/common/common.o $(VULKAN_SDK_SRC)/build/layers/liblayer_utils.so -Wl,-rpath,$(VULKAN_SDK_SRC)/build/layers -lpthread -lrt -ldl -lX11
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
||||
@@ -434,6 +434,8 @@ WrappedVulkan::~WrappedVulkan()
|
||||
|
||||
//if(it->second.rp != VK_NULL_HANDLE)
|
||||
//device_dispatch_table(GetDev())->DestroyRenderPass(GetDev(), it->second.rp);
|
||||
//if(it->second.vp != VK_NULL_HANDLE)
|
||||
//device_dispatch_table(GetDev())->DestroyDynamicViewportState(GetDev(), it->second.vp);
|
||||
}
|
||||
m_SwapChainInfo.clear();
|
||||
|
||||
@@ -6701,6 +6703,19 @@ VkResult WrappedVulkan::vkCreateSwapChainWSI(
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
{
|
||||
VkViewport vp = { 0.0f, 0.0f, (float)pCreateInfo->imageExtent.width, (float)pCreateInfo->imageExtent.height, 0.0f, 1.0f, };
|
||||
VkRect2D sc = { { 0, 0 }, { pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height } };
|
||||
|
||||
VkDynamicViewportStateCreateInfo vpInfo = {
|
||||
VK_STRUCTURE_TYPE_DYNAMIC_VIEWPORT_STATE_CREATE_INFO, NULL,
|
||||
1, &vp, &sc
|
||||
};
|
||||
|
||||
vkr = vt->CreateDynamicViewportState(device, &vpInfo, &swapInfo.vp);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
// serialise out the swap chain images
|
||||
{
|
||||
size_t swapChainImagesSize;
|
||||
@@ -6783,10 +6798,8 @@ VkResult WrappedVulkan::vkQueuePresentWSI(
|
||||
VkQueue queue,
|
||||
VkPresentInfoWSI* pPresentInfo)
|
||||
{
|
||||
VkResult ret = device_dispatch_table(queue)->QueuePresentWSI(queue, pPresentInfo);
|
||||
|
||||
if(ret != VK_SUCCESS || pPresentInfo->swapChainCount == 0)
|
||||
return ret;
|
||||
if(pPresentInfo->swapChainCount == 0)
|
||||
return VK_ERROR_INVALID_VALUE;
|
||||
|
||||
RenderDoc::Inst().SetCurrentDriver(RDC_Vulkan);
|
||||
|
||||
@@ -6808,6 +6821,9 @@ VkResult WrappedVulkan::vkQueuePresentWSI(
|
||||
const SwapInfo &swapInfo = m_SwapChainInfo[swapid];
|
||||
|
||||
VkImage backbuffer = swapInfo.images[pPresentInfo->imageIndices[0]].im;
|
||||
|
||||
// VKTODOLOW multiple windows/captures etc
|
||||
bool activeWindow = true; //RenderDoc::Inst().IsActiveWindow((ID3D11Device *)this, swapdesc.OutputWindow);
|
||||
|
||||
if(m_State == WRITING_IDLE)
|
||||
{
|
||||
@@ -6836,14 +6852,104 @@ VkResult WrappedVulkan::vkQueuePresentWSI(
|
||||
m_AvgFrametime /= double(m_FrameTimes.size());
|
||||
|
||||
m_FrameTimes.clear();
|
||||
}
|
||||
|
||||
uint32_t overlay = RenderDoc::Inst().GetOverlayBits();
|
||||
|
||||
if(overlay & eRENDERDOC_Overlay_Enabled)
|
||||
{
|
||||
VkRenderPass rp = swapInfo.rp;
|
||||
VkDynamicViewportState vp = swapInfo.vp;
|
||||
VkFramebuffer fb = swapInfo.images[pPresentInfo->imageIndices[0]].fb;
|
||||
|
||||
// VKTODOLOW only handling queue == GetQ()
|
||||
RDCASSERT(GetQ() == queue);
|
||||
|
||||
VkLayerDispatchTable *vt = device_dispatch_table(GetDev());
|
||||
|
||||
vt->QueueWaitIdle(GetQ());
|
||||
|
||||
TextPrintState textstate = { GetQ(), GetCmd(), rp, fb, vp, swapInfo.extent.width, swapInfo.extent.height };
|
||||
|
||||
if(activeWindow)
|
||||
{
|
||||
vector<RENDERDOC_InputButton> keys = RenderDoc::Inst().GetCaptureKeys();
|
||||
|
||||
string overlayText = "Vulkan. ";
|
||||
|
||||
for(size_t i=0; i < keys.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
overlayText += ", ";
|
||||
|
||||
overlayText += ToStr::Get(keys[i]);
|
||||
}
|
||||
|
||||
if(!keys.empty())
|
||||
overlayText += " to capture.";
|
||||
|
||||
if(overlay & eRENDERDOC_Overlay_FrameNumber)
|
||||
{
|
||||
overlayText += StringFormat::Fmt(" Frame: %d.", m_FrameCounter);
|
||||
}
|
||||
if(overlay & eRENDERDOC_Overlay_FrameRate)
|
||||
{
|
||||
overlayText += StringFormat::Fmt(" %.2lf ms (%.2lf .. %.2lf) (%.0lf FPS)",
|
||||
m_AvgFrametime, m_MinFrametime, m_MaxFrametime, 1000.0f/m_AvgFrametime);
|
||||
}
|
||||
|
||||
float y=0.0f;
|
||||
|
||||
if(!overlayText.empty())
|
||||
{
|
||||
GetDebugManager()->RenderText(textstate, 0.0f, y, overlayText.c_str());
|
||||
y += 1.0f;
|
||||
}
|
||||
|
||||
if(overlay & eRENDERDOC_Overlay_CaptureList)
|
||||
{
|
||||
GetDebugManager()->RenderText(textstate, 0.0f, y, "%d Captures saved.\n", (uint32_t)m_FrameRecord.size());
|
||||
y += 1.0f;
|
||||
|
||||
uint64_t now = Timing::GetUnixTimestamp();
|
||||
for(size_t i=0; i < m_FrameRecord.size(); i++)
|
||||
{
|
||||
if(now - m_FrameRecord[i].frameInfo.captureTime < 20)
|
||||
{
|
||||
GetDebugManager()->RenderText(textstate, 0.0f, y, "Captured frame %d.\n", m_FrameRecord[i].frameInfo.frameNumber);
|
||||
y += 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VKTODOLOW failed frames
|
||||
|
||||
RDCLOG("Frame: %d. F12/PrtScr to capture. %.2lf ms (%.2lf .. %.2lf) (%.0lf FPS)",
|
||||
m_FrameCounter, m_AvgFrametime, m_MinFrametime, m_MaxFrametime, 1000.0f/m_AvgFrametime);
|
||||
for(size_t i=0; i < m_FrameRecord.size(); i++)
|
||||
RDCLOG("Captured Frame %d. Multiple frame capture not supported.\n", m_FrameRecord[i].frameInfo.frameNumber);
|
||||
#if !defined(RELEASE)
|
||||
// RDCLOG("%llu chunks - %.2f MB", Chunk::NumLiveChunks(), float(Chunk::TotalMem())/1024.0f/1024.0f);
|
||||
GetDebugManager()->RenderText(textstate, 0.0f, y, "%llu chunks - %.2f MB", Chunk::NumLiveChunks(), float(Chunk::TotalMem())/1024.0f/1024.0f);
|
||||
y += 1.0f;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<RENDERDOC_InputButton> keys = RenderDoc::Inst().GetFocusKeys();
|
||||
|
||||
string str = "Vulkan. Inactive swapchain.";
|
||||
|
||||
for(size_t i=0; i < keys.size(); i++)
|
||||
{
|
||||
if(i == 0)
|
||||
str += " ";
|
||||
else
|
||||
str += ", ";
|
||||
|
||||
str += ToStr::Get(keys[i]);
|
||||
}
|
||||
|
||||
if(!keys.empty())
|
||||
str += " to cycle between swapchains";
|
||||
|
||||
GetDebugManager()->RenderText(textstate, 0.0f, 0.0f, str.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7182,6 +7288,7 @@ VkResult WrappedVulkan::vkQueuePresentWSI(
|
||||
|
||||
FetchFrameRecord record;
|
||||
record.frameInfo.frameNumber = m_FrameCounter+1;
|
||||
record.frameInfo.captureTime = Timing::GetUnixTimestamp();
|
||||
m_FrameRecord.push_back(record);
|
||||
|
||||
GetResourceManager()->ClearReferencedResources();
|
||||
@@ -7194,8 +7301,8 @@ VkResult WrappedVulkan::vkQueuePresentWSI(
|
||||
|
||||
RDCLOG("Starting capture, frame %u", m_FrameCounter);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
return device_dispatch_table(queue)->QueuePresentWSI(queue, pPresentInfo);
|
||||
}
|
||||
|
||||
bool WrappedVulkan::Prepare_InitialState(VkResource res)
|
||||
|
||||
@@ -339,6 +339,7 @@ private:
|
||||
int arraySize;
|
||||
|
||||
VkRenderPass rp;
|
||||
VkDynamicViewportState vp;
|
||||
|
||||
struct SwapImage
|
||||
{
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#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
|
||||
{
|
||||
@@ -51,6 +53,32 @@ struct displayuniforms
|
||||
Vec2f Padding;
|
||||
};
|
||||
|
||||
struct fontuniforms
|
||||
{
|
||||
Vec2f TextPosition;
|
||||
float txtpadding;
|
||||
float TextSize;
|
||||
|
||||
Vec2f CharacterSize;
|
||||
Vec2f FontScreenAspect;
|
||||
};
|
||||
|
||||
struct glyph
|
||||
{
|
||||
Vec4f posdata;
|
||||
Vec4f uvdata;
|
||||
};
|
||||
|
||||
struct glyphdata
|
||||
{
|
||||
glyph glyphs[127-32];
|
||||
};
|
||||
|
||||
struct stringdata
|
||||
{
|
||||
uint32_t str[256][4];
|
||||
};
|
||||
|
||||
void VulkanDebugManager::UBO::Create(WrappedVulkan *driver, VkDevice dev, VkDeviceSize size)
|
||||
{
|
||||
const VkLayerDispatchTable *vt = device_dispatch_table(dev);
|
||||
@@ -130,6 +158,8 @@ void VulkanDebugManager::UBO::Unmap(const VkLayerDispatchTable *vt, VkDevice dev
|
||||
|
||||
VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkImageView fakeBBView)
|
||||
{
|
||||
// VKTODOLOW needs tidy up - isn't scalable. Needs more classes like UBO above.
|
||||
|
||||
m_PipelineCache = VK_NULL_HANDLE;
|
||||
m_DescriptorPool = VK_NULL_HANDLE;
|
||||
m_DynamicCBStateWhite = VK_NULL_HANDLE;
|
||||
@@ -152,6 +182,17 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkIm
|
||||
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_Device = dev;
|
||||
|
||||
@@ -187,6 +228,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkIm
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
{
|
||||
// VKTODOLOW not sure if these stage flags VK_SHADER_STAGE_... work yet?
|
||||
VkDescriptorSetLayoutBinding layoutBinding[] = {
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, NULL, }
|
||||
};
|
||||
@@ -215,6 +257,23 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkIm
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
{
|
||||
VkDescriptorSetLayoutBinding layoutBinding[] = {
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, NULL, },
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, NULL, },
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 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(dev, &descsetLayoutInfo, &m_TextDescSetLayout);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
VkPipelineLayoutCreateInfo pipeLayoutInfo = {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, NULL,
|
||||
1, &m_TexDisplayDescSetLayout,
|
||||
@@ -229,6 +288,11 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkIm
|
||||
vkr = vt->CreatePipelineLayout(dev, &pipeLayoutInfo, &m_CheckerboardPipeLayout);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
pipeLayoutInfo.pSetLayouts = &m_TextDescSetLayout;
|
||||
|
||||
vkr = vt->CreatePipelineLayout(dev, &pipeLayoutInfo, &m_TextPipeLayout);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
VkDescriptorTypeCount descPoolTypes[] = {
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1024, },
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1024, },
|
||||
@@ -239,7 +303,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkIm
|
||||
ARRAY_COUNT(descPoolTypes), &descPoolTypes[0],
|
||||
};
|
||||
|
||||
vkr = vt->CreateDescriptorPool(dev, VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 2, &descpoolInfo, &m_DescriptorPool);
|
||||
vkr = vt->CreateDescriptorPool(dev, VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 3, &descpoolInfo, &m_DescriptorPool);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
uint32_t count;
|
||||
@@ -250,41 +314,21 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkIm
|
||||
vkr = vt->AllocDescriptorSets(dev, m_DescriptorPool, VK_DESCRIPTOR_SET_USAGE_STATIC, 1,
|
||||
&m_TexDisplayDescSetLayout, &m_TexDisplayDescSet, &count);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
vkr = vt->AllocDescriptorSets(dev, m_DescriptorPool, VK_DESCRIPTOR_SET_USAGE_STATIC, 1,
|
||||
&m_TextDescSetLayout, &m_TextDescSet, &count);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
m_CheckerboardUBO.Create(driver, dev, 128);
|
||||
m_TexDisplayUBO.Create(driver, dev, 128);
|
||||
|
||||
RDCCOMPILE_ASSERT(sizeof(displayuniforms) < 128, "tex display size");
|
||||
RDCCOMPILE_ASSERT(sizeof(displayuniforms) <= 128, "tex display size");
|
||||
|
||||
m_TextGeneralUBO.Create(driver, dev, 128);
|
||||
RDCCOMPILE_ASSERT(sizeof(fontuniforms) <= 128, "font uniforms size");
|
||||
|
||||
VkDescriptorInfo desc[3];
|
||||
RDCEraseEl(desc);
|
||||
|
||||
desc[0].bufferView = m_CheckerboardUBO.view;
|
||||
desc[1].bufferView = m_TexDisplayUBO.view;
|
||||
desc[2].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
desc[2].imageView = m_FakeBBImView;
|
||||
desc[2].sampler = m_LinearSampler;
|
||||
|
||||
VkWriteDescriptorSet writeSet[] = {
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
m_CheckerboardDescSet, 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &desc[0]
|
||||
},
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
m_TexDisplayDescSet, 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &desc[1]
|
||||
},
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
m_TexDisplayDescSet, 1, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &desc[2]
|
||||
},
|
||||
};
|
||||
|
||||
if(m_FakeBBImView != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = vt->UpdateDescriptorSets(dev, ARRAY_COUNT(writeSet), writeSet, 0, NULL);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
m_TextStringUBO.Create(driver, dev, 4096);
|
||||
RDCCOMPILE_ASSERT(sizeof(stringdata) <= 4096, "font uniforms size");
|
||||
|
||||
VkDynamicRasterStateCreateInfo rsInfo = {
|
||||
VK_STRUCTURE_TYPE_DYNAMIC_RASTER_STATE_CREATE_INFO, NULL,
|
||||
@@ -314,6 +358,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkIm
|
||||
GetEmbeddedResource(blitvs_spv),
|
||||
GetEmbeddedResource(checkerboardfs_spv),
|
||||
GetEmbeddedResource(texdisplayfs_spv),
|
||||
GetEmbeddedResource(textvs_spv),
|
||||
GetEmbeddedResource(textfs_spv),
|
||||
};
|
||||
|
||||
enum shaderIdx
|
||||
@@ -321,6 +367,8 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkIm
|
||||
BLITVS,
|
||||
CHECKERBOARDFS,
|
||||
TEXDISPLAYFS,
|
||||
TEXTVS,
|
||||
TEXTFS,
|
||||
};
|
||||
|
||||
VkShaderModule module[ARRAY_COUNT(shaderSources)];
|
||||
@@ -429,6 +477,16 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkIm
|
||||
vkr = vt->CreateGraphicsPipelines(dev, m_PipelineCache, 1, &pipeInfo, &m_TexDisplayBlendPipeline);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
|
||||
stages[0].shader = shader[TEXTVS];
|
||||
stages[1].shader = shader[TEXTFS];
|
||||
|
||||
pipeInfo.layout = m_TextPipeLayout;
|
||||
|
||||
vkr = vt->CreateGraphicsPipelines(dev, m_PipelineCache, 1, &pipeInfo, &m_TextPipeline);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
for(size_t i=0; i < ARRAY_COUNT(module); i++)
|
||||
{
|
||||
vkr = vt->DestroyShader(dev, shader[i]);
|
||||
@@ -437,6 +495,210 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkIm
|
||||
vkr = vt->DestroyShaderModule(dev, module[i]);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
{
|
||||
int width = FONT_TEX_WIDTH, height = FONT_TEX_HEIGHT;
|
||||
|
||||
VkImageCreateInfo imInfo = {
|
||||
/*.sType =*/ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
/*.pNext =*/ NULL,
|
||||
/*.imageType =*/ VK_IMAGE_TYPE_2D,
|
||||
/*.format =*/ VK_FORMAT_R8_UNORM,
|
||||
/*.extent =*/ { width, height, 1 },
|
||||
/*.mipLevels =*/ 1,
|
||||
/*.arraySize =*/ 1,
|
||||
/*.samples =*/ 1,
|
||||
/*.tiling =*/ VK_IMAGE_TILING_LINEAR,
|
||||
/*.usage =*/ VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
/*.flags =*/ 0,
|
||||
};
|
||||
|
||||
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(dev, &imInfo, &m_TextAtlas);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
VkMemoryRequirements mrq;
|
||||
vkr = vt->GetImageMemoryRequirements(dev, m_TextAtlas, &mrq);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
VkImageSubresource subr = { VK_IMAGE_ASPECT_COLOR, 0, 0 };
|
||||
VkSubresourceLayout layout = { 0 };
|
||||
vt->GetImageSubresourceLayout(dev, 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(dev, &allocInfo, &m_TextAtlasMem);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
vkr = vt->BindImageMemory(dev, m_TextAtlas, m_TextAtlasMem, 0);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
VkImageViewCreateInfo viewInfo = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, NULL,
|
||||
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, }
|
||||
};
|
||||
|
||||
// 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.
|
||||
VkResult vkr = vt->CreateImageView(dev, &viewInfo, &m_TextAtlasView);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
// need to transition image into valid state, then upload
|
||||
VkCmdBuffer cmd = driver->GetCmd();
|
||||
VkQueue q = driver->GetQ();
|
||||
|
||||
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->ResetCommandBuffer(cmd, 0);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
vkr = vt->BeginCommandBuffer(cmd, &beginInfo);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
VkImageMemoryBarrier trans = {
|
||||
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, NULL,
|
||||
0, 0, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
0, 0, m_TextAtlas,
|
||||
{ VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 1 } };
|
||||
|
||||
void *barrier = (void *)&trans;
|
||||
|
||||
vt->CmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, false, 1, &barrier);
|
||||
|
||||
vt->EndCommandBuffer(cmd);
|
||||
|
||||
vt->QueueSubmit(q, 1, &cmd, VK_NULL_HANDLE);
|
||||
|
||||
// VKTODOMED ideally all the commands from Bind to Flip would be recorded
|
||||
// into a single command buffer and we can just have several allocated
|
||||
// ring-buffer style
|
||||
vt->QueueWaitIdle(q);
|
||||
|
||||
byte *pData = NULL;
|
||||
vkr = vt->MapMemory(dev, 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;
|
||||
}
|
||||
|
||||
vkr = vt->UnmapMemory(dev, m_TextAtlasMem);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
m_TextGlyphUBO.Create(driver, dev, 4096);
|
||||
RDCCOMPILE_ASSERT(sizeof(Vec4f)*2*(numChars+1) < 4096, "font uniform size");
|
||||
|
||||
Vec4f *glyphData = (Vec4f *)m_TextGlyphUBO.Map(vt, dev);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
VkDescriptorInfo desc[7];
|
||||
RDCEraseEl(desc);
|
||||
|
||||
// checkerboard
|
||||
desc[0].bufferView = m_CheckerboardUBO.view;
|
||||
|
||||
// tex display
|
||||
desc[1].bufferView = m_TexDisplayUBO.view;
|
||||
desc[2].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
desc[2].imageView = m_FakeBBImView;
|
||||
desc[2].sampler = m_LinearSampler;
|
||||
|
||||
// text
|
||||
desc[3].bufferView = m_TextGeneralUBO.view;
|
||||
desc[4].bufferView = m_TextGlyphUBO.view;
|
||||
desc[5].bufferView = m_TextStringUBO.view;
|
||||
desc[6].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
desc[6].imageView = m_TextAtlasView;
|
||||
desc[6].sampler = m_LinearSampler;
|
||||
|
||||
VkWriteDescriptorSet writeSet[] = {
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
m_CheckerboardDescSet, 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &desc[0]
|
||||
},
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
m_TexDisplayDescSet, 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &desc[1]
|
||||
},
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
m_TextDescSet, 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &desc[3]
|
||||
},
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
m_TextDescSet, 1, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &desc[4]
|
||||
},
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
m_TextDescSet, 2, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &desc[5]
|
||||
},
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
m_TextDescSet, 3, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &desc[6]
|
||||
},
|
||||
// this one is last so that we can skip it if we don't have m_FakeBBImView
|
||||
{
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
m_TexDisplayDescSet, 1, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &desc[2]
|
||||
},
|
||||
};
|
||||
|
||||
uint32_t writeCount = (uint32_t)ARRAY_COUNT(writeSet);
|
||||
if(m_FakeBBImView == VK_NULL_HANDLE)
|
||||
writeCount--;
|
||||
|
||||
vkr = vt->UpdateDescriptorSets(dev, writeCount, writeSet, 0, NULL);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
VulkanDebugManager::~VulkanDebugManager()
|
||||
@@ -538,4 +800,129 @@ VulkanDebugManager::~VulkanDebugManager()
|
||||
|
||||
m_CheckerboardUBO.Destroy(vt, dev);
|
||||
m_TexDisplayUBO.Destroy(vt, dev);
|
||||
|
||||
if(m_TextDescSetLayout != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = vt->DestroyDescriptorSetLayout(dev, m_TextDescSetLayout);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
if(m_TextPipeLayout != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = vt->DestroyPipelineLayout(dev, m_TextPipeLayout);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
if(m_TextPipeline != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = vt->DestroyPipeline(dev, m_TextPipeline);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
m_TextGeneralUBO.Destroy(vt, dev);
|
||||
m_TextGlyphUBO.Destroy(vt, dev);
|
||||
m_TextStringUBO.Destroy(vt, dev);
|
||||
|
||||
if(m_TextAtlasView != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = vt->DestroyImageView(dev, m_TextAtlasView);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
if(m_TextAtlas != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = vt->DestroyImage(dev, m_TextAtlas);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
|
||||
if(m_TextAtlasMem != VK_NULL_HANDLE)
|
||||
{
|
||||
vkr = vt->FreeMemory(dev, m_TextAtlasMem);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
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 = device_dispatch_table(m_Device);
|
||||
|
||||
// VKTODOMED needs to be optimised to do all in one cmd buffer with
|
||||
// a start/stop pair of calls that map a UBO, then do each draw with
|
||||
// a push constant to tell it what the line should be.
|
||||
|
||||
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 = VK_SUCCESS;
|
||||
|
||||
fontuniforms *ubo = (fontuniforms *)m_TextGeneralUBO.Map(vt, m_Device);
|
||||
|
||||
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);
|
||||
|
||||
stringdata *stringData = (stringdata *)m_TextStringUBO.Map(vt, m_Device);
|
||||
|
||||
for(size_t i=0; i < strlen(text); i++)
|
||||
stringData->str[i][0] = uint32_t(text[i] - ' ');
|
||||
|
||||
m_TextStringUBO.Unmap(vt, m_Device);
|
||||
|
||||
vkr = vt->ResetCommandBuffer(textstate.cmd, 0);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
vkr = vt->BeginCommandBuffer(textstate.cmd, &beginInfo);
|
||||
RDCASSERT(vkr == VK_SUCCESS);
|
||||
|
||||
{
|
||||
VkClearValue clearval = {0};
|
||||
VkRenderPassBeginInfo rpbegin = {
|
||||
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, NULL,
|
||||
textstate.rp, textstate.fb,
|
||||
{ { 0, 0, }, { textstate.w, textstate.h} },
|
||||
1, &clearval,
|
||||
};
|
||||
vt->CmdBeginRenderPass(textstate.cmd, &rpbegin, VK_RENDER_PASS_CONTENTS_INLINE);
|
||||
|
||||
// VKTODOMED will need a way to disable blend for other things
|
||||
vt->CmdBindPipeline(textstate.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_TextPipeline);
|
||||
vt->CmdBindDescriptorSets(textstate.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_TextPipeLayout, 0, 1, &m_TextDescSet, 0, NULL);
|
||||
|
||||
vt->CmdBindDynamicViewportState(textstate.cmd, textstate.vp);
|
||||
vt->CmdBindDynamicRasterState(textstate.cmd, m_DynamicRSState);
|
||||
vt->CmdBindDynamicColorBlendState(textstate.cmd, m_DynamicCBStateWhite);
|
||||
vt->CmdBindDynamicDepthStencilState(textstate.cmd, m_DynamicDSStateDisabled);
|
||||
|
||||
// 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(textstate.cmd, 0, 6*(uint32_t)strlen(text), 0, 1);
|
||||
vt->CmdEndRenderPass(textstate.cmd);
|
||||
}
|
||||
|
||||
vt->EndCommandBuffer(textstate.cmd);
|
||||
|
||||
vt->QueueSubmit(textstate.q, 1, &textstate.cmd, VK_NULL_HANDLE);
|
||||
|
||||
vt->QueueWaitIdle(textstate.q);
|
||||
}
|
||||
@@ -30,11 +30,23 @@
|
||||
#include "replay/replay_driver.h"
|
||||
#include "core/core.h"
|
||||
|
||||
struct TextPrintState
|
||||
{
|
||||
VkQueue q;
|
||||
VkCmdBuffer cmd;
|
||||
VkRenderPass rp;
|
||||
VkFramebuffer fb;
|
||||
VkDynamicViewportState vp;
|
||||
int32_t w, h;
|
||||
};
|
||||
|
||||
class VulkanDebugManager
|
||||
{
|
||||
public:
|
||||
VulkanDebugManager(WrappedVulkan *driver, VkDevice dev, VkImageView fakeBBView);
|
||||
~VulkanDebugManager();
|
||||
|
||||
void RenderText(const TextPrintState &textstate, float x, float y, const char *fmt, ...);
|
||||
|
||||
struct UBO
|
||||
{
|
||||
@@ -71,11 +83,30 @@ class VulkanDebugManager
|
||||
VkDescriptorSet m_TexDisplayDescSet;
|
||||
VkPipeline m_TexDisplayPipeline, m_TexDisplayBlendPipeline;
|
||||
UBO m_TexDisplayUBO;
|
||||
|
||||
VkDescriptorSetLayout m_TextDescSetLayout;
|
||||
VkPipelineLayout m_TextPipeLayout;
|
||||
VkDescriptorSet m_TextDescSet;
|
||||
VkPipeline m_TextPipeline;
|
||||
UBO m_TextGeneralUBO;
|
||||
UBO m_TextGlyphUBO;
|
||||
UBO m_TextStringUBO;
|
||||
VkImage m_TextAtlas;
|
||||
VkDeviceMemory m_TextAtlasMem;
|
||||
VkImageView m_TextAtlasView;
|
||||
|
||||
private:
|
||||
void InitDebugData();
|
||||
void ShutdownDebugData();
|
||||
|
||||
void RenderTextInternal(const TextPrintState &textstate, float x, float y, const char *text);
|
||||
static const int FONT_TEX_WIDTH = 256;
|
||||
static const int FONT_TEX_HEIGHT = 128;
|
||||
|
||||
float m_FontCharAspect;
|
||||
float m_FontCharSize;
|
||||
|
||||
|
||||
WrappedVulkan *m_pDriver;
|
||||
|
||||
VkDevice m_Device;
|
||||
|
||||
@@ -397,9 +397,9 @@ VulkanReplay::VulkanReplay()
|
||||
m_BindDepth = false;
|
||||
}
|
||||
|
||||
VulkanDebugManager &VulkanReplay::GetDebugManager()
|
||||
VulkanDebugManager *VulkanReplay::GetDebugManager()
|
||||
{
|
||||
return *m_pDriver->GetDebugManager();
|
||||
return m_pDriver->GetDebugManager();
|
||||
}
|
||||
|
||||
void VulkanReplay::Shutdown()
|
||||
@@ -627,7 +627,7 @@ bool VulkanReplay::RenderTexture(TextureDisplay cfg)
|
||||
|
||||
// VKTODOHIGH once we stop doing DeviceWaitIdle/QueueWaitIdle all over, this
|
||||
// needs to be ring-buffered
|
||||
displayuniforms *data = (displayuniforms *)GetDebugManager().m_TexDisplayUBO.Map(vt, dev);
|
||||
displayuniforms *data = (displayuniforms *)GetDebugManager()->m_TexDisplayUBO.Map(vt, dev);
|
||||
|
||||
data->Padding = 0;
|
||||
|
||||
@@ -705,18 +705,18 @@ bool VulkanReplay::RenderTexture(TextureDisplay cfg)
|
||||
|
||||
data->RawOutput = cfg.rawoutput ? 1 : 0;
|
||||
|
||||
GetDebugManager().m_TexDisplayUBO.Unmap(vt, dev);
|
||||
GetDebugManager()->m_TexDisplayUBO.Unmap(vt, dev);
|
||||
|
||||
VkDescriptorInfo desc = {0};
|
||||
desc.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
desc.imageView = GetDebugManager().m_FakeBBImView;
|
||||
desc.sampler = GetDebugManager().m_PointSampler;
|
||||
desc.imageView = GetDebugManager()->m_FakeBBImView;
|
||||
desc.sampler = GetDebugManager()->m_PointSampler;
|
||||
if(cfg.mip == 0 && cfg.scale < 1.0f)
|
||||
desc.sampler = GetDebugManager().m_LinearSampler;
|
||||
desc.sampler = GetDebugManager()->m_LinearSampler;
|
||||
|
||||
VkWriteDescriptorSet writeSet = {
|
||||
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL,
|
||||
GetDebugManager().m_TexDisplayDescSet, 1, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &desc
|
||||
GetDebugManager()->m_TexDisplayDescSet, 1, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &desc
|
||||
};
|
||||
|
||||
VkResult vkr = vt->UpdateDescriptorSets(dev, 1, &writeSet, 0, NULL);
|
||||
@@ -752,13 +752,13 @@ bool VulkanReplay::RenderTexture(TextureDisplay cfg)
|
||||
vt->CmdBeginRenderPass(cmd, &rpbegin, VK_RENDER_PASS_CONTENTS_INLINE);
|
||||
|
||||
// VKTODOMED will need a way to disable blend for other things
|
||||
vt->CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cfg.rawoutput ? GetDebugManager().m_TexDisplayPipeline : GetDebugManager().m_TexDisplayBlendPipeline);
|
||||
vt->CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, GetDebugManager().m_TexDisplayPipeLayout, 0, 1, &GetDebugManager().m_TexDisplayDescSet, 0, NULL);
|
||||
vt->CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cfg.rawoutput ? GetDebugManager()->m_TexDisplayPipeline : GetDebugManager()->m_TexDisplayBlendPipeline);
|
||||
vt->CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, GetDebugManager()->m_TexDisplayPipeLayout, 0, 1, &GetDebugManager()->m_TexDisplayDescSet, 0, NULL);
|
||||
|
||||
vt->CmdBindDynamicViewportState(cmd, outw.fullVP);
|
||||
vt->CmdBindDynamicRasterState(cmd, GetDebugManager().m_DynamicRSState);
|
||||
vt->CmdBindDynamicColorBlendState(cmd, GetDebugManager().m_DynamicCBStateWhite);
|
||||
vt->CmdBindDynamicDepthStencilState(cmd, GetDebugManager().m_DynamicDSStateDisabled);
|
||||
vt->CmdBindDynamicRasterState(cmd, GetDebugManager()->m_DynamicRSState);
|
||||
vt->CmdBindDynamicColorBlendState(cmd, GetDebugManager()->m_DynamicCBStateWhite);
|
||||
vt->CmdBindDynamicDepthStencilState(cmd, GetDebugManager()->m_DynamicDSStateDisabled);
|
||||
|
||||
vt->CmdDraw(cmd, 0, 4, 0, 1);
|
||||
vt->CmdEndRenderPass(cmd);
|
||||
@@ -803,14 +803,14 @@ void VulkanReplay::RenderCheckerboard(Vec3f light, Vec3f dark)
|
||||
|
||||
// VKTODOHIGH once we stop doing DeviceWaitIdle/QueueWaitIdle all over, this
|
||||
// needs to be ring-buffered
|
||||
Vec4f *data = (Vec4f *)GetDebugManager().m_CheckerboardUBO.Map(vt, dev);
|
||||
Vec4f *data = (Vec4f *)GetDebugManager()->m_CheckerboardUBO.Map(vt, dev);
|
||||
data[0].x = light.x;
|
||||
data[0].y = light.y;
|
||||
data[0].z = light.z;
|
||||
data[1].x = dark.x;
|
||||
data[1].y = dark.y;
|
||||
data[1].z = dark.z;
|
||||
GetDebugManager().m_CheckerboardUBO.Unmap(vt, dev);
|
||||
GetDebugManager()->m_CheckerboardUBO.Unmap(vt, dev);
|
||||
|
||||
{
|
||||
VkClearValue clearval = {0};
|
||||
@@ -822,13 +822,13 @@ void VulkanReplay::RenderCheckerboard(Vec3f light, Vec3f dark)
|
||||
};
|
||||
vt->CmdBeginRenderPass(cmd, &rpbegin, VK_RENDER_PASS_CONTENTS_INLINE);
|
||||
|
||||
vt->CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, GetDebugManager().m_CheckerboardPipeline);
|
||||
vt->CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, GetDebugManager().m_CheckerboardPipeLayout, 0, 1, &GetDebugManager().m_CheckerboardDescSet, 0, NULL);
|
||||
vt->CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, GetDebugManager()->m_CheckerboardPipeline);
|
||||
vt->CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, GetDebugManager()->m_CheckerboardPipeLayout, 0, 1, &GetDebugManager()->m_CheckerboardDescSet, 0, NULL);
|
||||
|
||||
vt->CmdBindDynamicViewportState(cmd, outw.fullVP);
|
||||
vt->CmdBindDynamicRasterState(cmd, GetDebugManager().m_DynamicRSState);
|
||||
vt->CmdBindDynamicColorBlendState(cmd, GetDebugManager().m_DynamicCBStateWhite);
|
||||
vt->CmdBindDynamicDepthStencilState(cmd, GetDebugManager().m_DynamicDSStateDisabled);
|
||||
vt->CmdBindDynamicRasterState(cmd, GetDebugManager()->m_DynamicRSState);
|
||||
vt->CmdBindDynamicColorBlendState(cmd, GetDebugManager()->m_DynamicCBStateWhite);
|
||||
vt->CmdBindDynamicDepthStencilState(cmd, GetDebugManager()->m_DynamicDSStateDisabled);
|
||||
|
||||
vt->CmdDraw(cmd, 0, 4, 0, 1);
|
||||
vt->CmdEndRenderPass(cmd);
|
||||
|
||||
@@ -215,5 +215,5 @@ class VulkanReplay : public IReplayDriver
|
||||
|
||||
WrappedVulkan *m_pDriver;
|
||||
|
||||
VulkanDebugManager &GetDebugManager();
|
||||
VulkanDebugManager *GetDebugManager();
|
||||
};
|
||||
|
||||
@@ -363,6 +363,10 @@
|
||||
<None Include="data\spv\checkerboardfs.spv" />
|
||||
<None Include="data\spv\texdisplay.frag" />
|
||||
<None Include="data\spv\texdisplayfs.spv" />
|
||||
<None Include="data\spv\text.frag" />
|
||||
<None Include="data\spv\text.vert" />
|
||||
<None Include="data\spv\textfs.spv" />
|
||||
<None Include="data\spv\textvs.spv" />
|
||||
<None Include="os\win32\comexport.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -448,6 +448,18 @@
|
||||
<None Include="data\spv\checkerboardfs.spv">
|
||||
<Filter>Resources\spv</Filter>
|
||||
</None>
|
||||
<None Include="data\spv\text.frag">
|
||||
<Filter>Resources\spv</Filter>
|
||||
</None>
|
||||
<None Include="data\spv\text.vert">
|
||||
<Filter>Resources\spv</Filter>
|
||||
</None>
|
||||
<None Include="data\spv\textfs.spv">
|
||||
<Filter>Resources\spv</Filter>
|
||||
</None>
|
||||
<None Include="data\spv\textvs.spv">
|
||||
<Filter>Resources\spv</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="data\renderdoc.rc">
|
||||
|
||||
Reference in New Issue
Block a user