mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-23 14:25:37 +00:00
685 lines
37 KiB
C++
685 lines
37 KiB
C++
// dear imgui: Renderer Backend for Vulkan
|
|
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
|
|
|
// Implemented features:
|
|
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
|
// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
|
|
|
|
// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
|
|
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
|
|
// To build this on 32-bit systems and support texture changes:
|
|
// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in our .vcxproj files)
|
|
// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
|
|
// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
|
|
// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in our batch files)
|
|
|
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
|
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
|
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
|
|
|
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
|
|
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
|
|
|
// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
|
|
// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
|
|
// You will use those if you want to use this rendering backend in your engine/app.
|
|
// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
|
|
// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
|
|
// Read comments in imgui_impl_vulkan.h.
|
|
|
|
// CHANGELOG
|
|
// (minor and older changes stripped away, please see git history for details)
|
|
// 2021-10-15: Vulkan: Call vkCmdSetScissor() at the end of render a full-viewport to reduce likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame.
|
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
|
// 2021-03-22: Vulkan: Fix mapped memory validation error when buffer sizes are not multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize.
|
|
// 2021-02-18: Vulkan: Change blending equation to preserve alpha in output buffer.
|
|
// 2021-01-27: Vulkan: Added support for custom function load and IMGUI_IMPL_VULKAN_NO_PROTOTYPES by using ImGui_ImplVulkan_LoadFunctions().
|
|
// 2020-11-11: Vulkan: Added support for specifying which subpass to reference during VkPipeline creation.
|
|
// 2020-09-07: Vulkan: Added VkPipeline parameter to ImGui_ImplVulkan_RenderDrawData (default to one passed to ImGui_ImplVulkan_Init).
|
|
// 2020-05-04: Vulkan: Fixed crash if initial frame has no vertices.
|
|
// 2020-04-26: Vulkan: Fixed edge case where render callbacks wouldn't be called if the ImDrawData didn't have vertices.
|
|
// 2019-08-01: Vulkan: Added support for specifying multisample count. Set ImGui_ImplVulkan_InitInfo::MSAASamples to one of the VkSampleCountFlagBits values to use, default is non-multisampled as before.
|
|
// 2019-05-29: Vulkan: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
|
// 2019-04-30: Vulkan: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
|
// 2019-04-04: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
|
|
// 2019-04-04: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
|
|
// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
|
|
// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
|
|
// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.
|
|
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
|
// 2018-08-25: Vulkan: Fixed mishandled VkSurfaceCapabilitiesKHR::maxImageCount=0 case.
|
|
// 2018-06-22: Inverted the parameters to ImGui_ImplVulkan_RenderDrawData() to be consistent with other backends.
|
|
// 2018-06-08: Misc: Extracted imgui_impl_vulkan.cpp/.h away from the old combined GLFW+Vulkan example.
|
|
// 2018-06-08: Vulkan: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
|
// 2018-03-03: Vulkan: Various refactor, created a couple of ImGui_ImplVulkanH_XXX helper that the example can use and that viewport support will use.
|
|
// 2018-03-01: Vulkan: Renamed ImGui_ImplVulkan_Init_Info to ImGui_ImplVulkan_InitInfo and fields to match more closely Vulkan terminology.
|
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback, ImGui_ImplVulkan_Render() calls ImGui_ImplVulkan_RenderDrawData() itself.
|
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
|
// 2017-05-15: Vulkan: Fix scissor offset being negative. Fix new Vulkan validation warnings. Set required depth member for buffer image copy.
|
|
// 2016-11-13: Vulkan: Fix validation layer warnings and errors and redeclare gl_PerVertex.
|
|
// 2016-10-18: Vulkan: Add location decorators & change to use structs as in/out in glsl, update embedded spv (produced with glslangValidator -x). Null the released resources.
|
|
// 2016-08-27: Vulkan: Fix Vulkan example for use when a depth buffer is active.
|
|
|
|
#include "imgui_impl_vulkan.h"
|
|
|
|
#include "common/vulkan/builders.h"
|
|
#include "common/vulkan/context.h"
|
|
#include "common/vulkan/texture.h"
|
|
#include "common/vulkan/stream_buffer.h"
|
|
#include "common/vulkan/util.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
// Visual Studio warnings
|
|
#ifdef _MSC_VER
|
|
#pragma warning (disable: 4127) // condition expression is constant
|
|
#endif
|
|
|
|
// If we're doing more than this... wtf?
|
|
static constexpr u32 VERTEX_BUFFER_SIZE = 8 * 1024 * 1024;
|
|
static constexpr u32 INDEX_BUFFER_SIZE = 4 * 1024 * 1024;
|
|
|
|
// Vulkan data
|
|
struct ImGui_ImplVulkan_Data
|
|
{
|
|
VkRenderPass RenderPass = VK_NULL_HANDLE;
|
|
VkPipelineCreateFlags PipelineCreateFlags = 0;
|
|
VkDescriptorSetLayout DescriptorSetLayout = VK_NULL_HANDLE;
|
|
VkPipelineLayout PipelineLayout = VK_NULL_HANDLE;
|
|
VkPipeline Pipeline = VK_NULL_HANDLE;
|
|
VkShaderModule ShaderModuleVert = VK_NULL_HANDLE;
|
|
VkShaderModule ShaderModuleFrag = VK_NULL_HANDLE;
|
|
|
|
VkSampler FontSampler = VK_NULL_HANDLE;
|
|
|
|
Vulkan::StreamBuffer VertexStreamBuffer;
|
|
Vulkan::StreamBuffer IndexStreamBuffer;
|
|
Vulkan::Texture FontTexture;
|
|
};
|
|
|
|
// Forward Declarations
|
|
static bool ImGui_ImplVulkan_CreateDeviceObjects();
|
|
static void ImGui_ImplVulkan_DestroyDeviceObjects();
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SHADERS
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// glsl_shader.vert, compiled with:
|
|
// # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
|
|
/*
|
|
#version 450 core
|
|
layout(location = 0) in vec2 aPos;
|
|
layout(location = 1) in vec2 aUV;
|
|
layout(location = 2) in vec4 aColor;
|
|
layout(push_constant) uniform uPushConstant { vec2 uScale; vec2 uTranslate; } pc;
|
|
|
|
out gl_PerVertex { vec4 gl_Position; };
|
|
layout(location = 0) out struct { vec4 Color; vec2 UV; } Out;
|
|
|
|
void main()
|
|
{
|
|
Out.Color = aColor;
|
|
Out.UV = aUV;
|
|
gl_Position = vec4(aPos * pc.uScale + pc.uTranslate, 0, 1);
|
|
}
|
|
*/
|
|
static uint32_t __glsl_shader_vert_spv[] =
|
|
{
|
|
0x07230203,0x00010000,0x00080001,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b,
|
|
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
|
|
0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015,
|
|
0x0000001b,0x0000001c,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
|
|
0x00000000,0x00030005,0x00000009,0x00000000,0x00050006,0x00000009,0x00000000,0x6f6c6f43,
|
|
0x00000072,0x00040006,0x00000009,0x00000001,0x00005655,0x00030005,0x0000000b,0x0074754f,
|
|
0x00040005,0x0000000f,0x6c6f4361,0x0000726f,0x00030005,0x00000015,0x00565561,0x00060005,
|
|
0x00000019,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000019,0x00000000,
|
|
0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000001b,0x00000000,0x00040005,0x0000001c,
|
|
0x736f5061,0x00000000,0x00060005,0x0000001e,0x73755075,0x6e6f4368,0x6e617473,0x00000074,
|
|
0x00050006,0x0000001e,0x00000000,0x61635375,0x0000656c,0x00060006,0x0000001e,0x00000001,
|
|
0x61725475,0x616c736e,0x00006574,0x00030005,0x00000020,0x00006370,0x00040047,0x0000000b,
|
|
0x0000001e,0x00000000,0x00040047,0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015,
|
|
0x0000001e,0x00000001,0x00050048,0x00000019,0x00000000,0x0000000b,0x00000000,0x00030047,
|
|
0x00000019,0x00000002,0x00040047,0x0000001c,0x0000001e,0x00000000,0x00050048,0x0000001e,
|
|
0x00000000,0x00000023,0x00000000,0x00050048,0x0000001e,0x00000001,0x00000023,0x00000008,
|
|
0x00030047,0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,
|
|
0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040017,
|
|
0x00000008,0x00000006,0x00000002,0x0004001e,0x00000009,0x00000007,0x00000008,0x00040020,
|
|
0x0000000a,0x00000003,0x00000009,0x0004003b,0x0000000a,0x0000000b,0x00000003,0x00040015,
|
|
0x0000000c,0x00000020,0x00000001,0x0004002b,0x0000000c,0x0000000d,0x00000000,0x00040020,
|
|
0x0000000e,0x00000001,0x00000007,0x0004003b,0x0000000e,0x0000000f,0x00000001,0x00040020,
|
|
0x00000011,0x00000003,0x00000007,0x0004002b,0x0000000c,0x00000013,0x00000001,0x00040020,
|
|
0x00000014,0x00000001,0x00000008,0x0004003b,0x00000014,0x00000015,0x00000001,0x00040020,
|
|
0x00000017,0x00000003,0x00000008,0x0003001e,0x00000019,0x00000007,0x00040020,0x0000001a,
|
|
0x00000003,0x00000019,0x0004003b,0x0000001a,0x0000001b,0x00000003,0x0004003b,0x00000014,
|
|
0x0000001c,0x00000001,0x0004001e,0x0000001e,0x00000008,0x00000008,0x00040020,0x0000001f,
|
|
0x00000009,0x0000001e,0x0004003b,0x0000001f,0x00000020,0x00000009,0x00040020,0x00000021,
|
|
0x00000009,0x00000008,0x0004002b,0x00000006,0x00000028,0x00000000,0x0004002b,0x00000006,
|
|
0x00000029,0x3f800000,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,
|
|
0x00000005,0x0004003d,0x00000007,0x00000010,0x0000000f,0x00050041,0x00000011,0x00000012,
|
|
0x0000000b,0x0000000d,0x0003003e,0x00000012,0x00000010,0x0004003d,0x00000008,0x00000016,
|
|
0x00000015,0x00050041,0x00000017,0x00000018,0x0000000b,0x00000013,0x0003003e,0x00000018,
|
|
0x00000016,0x0004003d,0x00000008,0x0000001d,0x0000001c,0x00050041,0x00000021,0x00000022,
|
|
0x00000020,0x0000000d,0x0004003d,0x00000008,0x00000023,0x00000022,0x00050085,0x00000008,
|
|
0x00000024,0x0000001d,0x00000023,0x00050041,0x00000021,0x00000025,0x00000020,0x00000013,
|
|
0x0004003d,0x00000008,0x00000026,0x00000025,0x00050081,0x00000008,0x00000027,0x00000024,
|
|
0x00000026,0x00050051,0x00000006,0x0000002a,0x00000027,0x00000000,0x00050051,0x00000006,
|
|
0x0000002b,0x00000027,0x00000001,0x00070050,0x00000007,0x0000002c,0x0000002a,0x0000002b,
|
|
0x00000028,0x00000029,0x00050041,0x00000011,0x0000002d,0x0000001b,0x0000000d,0x0003003e,
|
|
0x0000002d,0x0000002c,0x000100fd,0x00010038
|
|
};
|
|
|
|
// glsl_shader.frag, compiled with:
|
|
// # glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag
|
|
/*
|
|
#version 450 core
|
|
layout(location = 0) out vec4 fColor;
|
|
layout(set=0, binding=0) uniform sampler2D sTexture;
|
|
layout(location = 0) in struct { vec4 Color; vec2 UV; } In;
|
|
void main()
|
|
{
|
|
fColor = In.Color * texture(sTexture, In.UV.st);
|
|
}
|
|
*/
|
|
static uint32_t __glsl_shader_frag_spv[] =
|
|
{
|
|
0x07230203,0x00010000,0x00080001,0x0000001e,0x00000000,0x00020011,0x00000001,0x0006000b,
|
|
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
|
|
0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010,
|
|
0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
|
|
0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000,
|
|
0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001,
|
|
0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000016,0x78655473,0x65727574,
|
|
0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e,
|
|
0x00000000,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021,
|
|
0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,
|
|
0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003,
|
|
0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,0x00000006,
|
|
0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,0x00000001,
|
|
0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,0x00000020,
|
|
0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,0x00000001,
|
|
0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,
|
|
0x00000001,0x00000000,0x0003001b,0x00000014,0x00000013,0x00040020,0x00000015,0x00000000,
|
|
0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x0004002b,0x0000000e,0x00000018,
|
|
0x00000001,0x00040020,0x00000019,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004,
|
|
0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d,
|
|
0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000014,0x00000017,
|
|
0x00000016,0x00050041,0x00000019,0x0000001a,0x0000000d,0x00000018,0x0004003d,0x0000000a,
|
|
0x0000001b,0x0000001a,0x00050057,0x00000007,0x0000001c,0x00000017,0x0000001b,0x00050085,
|
|
0x00000007,0x0000001d,0x00000012,0x0000001c,0x0003003e,0x00000009,0x0000001d,0x000100fd,
|
|
0x00010038
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// FUNCTIONS
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
|
// FIXME: multi-context support is not tested and probably dysfunctional in this backend.
|
|
static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_GetBackendData()
|
|
{
|
|
return ImGui::GetCurrentContext() ? (ImGui_ImplVulkan_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
|
}
|
|
|
|
static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline pipeline, VkCommandBuffer command_buffer, int fb_width, int fb_height)
|
|
{
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
|
|
// Bind pipeline:
|
|
{
|
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
|
}
|
|
|
|
// Bind Vertex And Index Buffer:
|
|
if (draw_data->TotalVtxCount > 0)
|
|
{
|
|
VkBuffer vertex_buffers[1] = { bd->VertexStreamBuffer.GetBuffer() };
|
|
VkDeviceSize vertex_offset[1] = { bd->VertexStreamBuffer.GetCurrentOffset() };
|
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
|
|
vkCmdBindIndexBuffer(command_buffer, bd->IndexStreamBuffer.GetBuffer(), bd->IndexStreamBuffer.GetCurrentOffset(), sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
|
|
}
|
|
|
|
// Setup viewport:
|
|
{
|
|
VkViewport viewport;
|
|
viewport.x = 0;
|
|
viewport.y = 0;
|
|
viewport.width = (float)fb_width;
|
|
viewport.height = (float)fb_height;
|
|
viewport.minDepth = 0.0f;
|
|
viewport.maxDepth = 1.0f;
|
|
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
|
}
|
|
|
|
// Setup scale and translation:
|
|
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
|
{
|
|
float scale[2];
|
|
scale[0] = 2.0f / draw_data->DisplaySize.x;
|
|
scale[1] = 2.0f / draw_data->DisplaySize.y;
|
|
float translate[2];
|
|
translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0];
|
|
translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1];
|
|
vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale);
|
|
vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate);
|
|
}
|
|
}
|
|
|
|
// Render function
|
|
void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data)
|
|
{
|
|
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
|
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
|
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
|
if (fb_width <= 0 || fb_height <= 0)
|
|
return;
|
|
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
if (draw_data->TotalVtxCount > 0)
|
|
{
|
|
// Create or resize the vertex/index buffers
|
|
const u32 vertex_size = static_cast<u32>(draw_data->TotalVtxCount) * static_cast<u32>(sizeof(ImDrawVert));
|
|
const u32 index_size = static_cast<u32>(draw_data->TotalIdxCount) * static_cast<u32>(sizeof(ImDrawIdx));
|
|
if (!bd->VertexStreamBuffer.ReserveMemory(vertex_size, static_cast<u32>(sizeof(ImDrawVert))) ||
|
|
!bd->IndexStreamBuffer.ReserveMemory(index_size, static_cast<u32>(sizeof(ImDrawIdx))))
|
|
{
|
|
// this is annoying, because we can't restart the render pass...
|
|
return;
|
|
}
|
|
|
|
// Upload vertex/index data into a single contiguous GPU buffer
|
|
ImDrawVert* vtx_dst = (ImDrawVert*)bd->VertexStreamBuffer.GetCurrentHostPointer();
|
|
ImDrawIdx* idx_dst = (ImDrawIdx*)bd->IndexStreamBuffer.GetCurrentHostPointer();
|
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
|
{
|
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
|
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, static_cast<u32>(cmd_list->VtxBuffer.Size) * static_cast<u32>(sizeof(ImDrawVert)));
|
|
memcpy(idx_dst, cmd_list->IdxBuffer.Data, static_cast<u32>(cmd_list->IdxBuffer.Size) * static_cast<u32>(sizeof(ImDrawIdx)));
|
|
vtx_dst += static_cast<u32>(cmd_list->VtxBuffer.Size);
|
|
idx_dst += static_cast<u32>(cmd_list->IdxBuffer.Size);
|
|
}
|
|
|
|
// Setup desired Vulkan state (must come before buffer commit)
|
|
ImGui_ImplVulkan_SetupRenderState(draw_data, bd->Pipeline, g_vulkan_context->GetCurrentCommandBuffer(), fb_width, fb_height);
|
|
bd->VertexStreamBuffer.CommitMemory(vertex_size);
|
|
bd->IndexStreamBuffer.CommitMemory(index_size);
|
|
}
|
|
|
|
// Will project scissor/clipping rectangles into framebuffer space
|
|
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
|
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
|
|
|
// Render command lists
|
|
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
|
int global_vtx_offset = 0;
|
|
int global_idx_offset = 0;
|
|
const Vulkan::Texture* last_texture = nullptr;
|
|
VkCommandBuffer command_buffer = g_vulkan_context->GetCurrentCommandBuffer();
|
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
|
{
|
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
|
{
|
|
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
|
if (pcmd->UserCallback != NULL)
|
|
{
|
|
// User callback, registered via ImDrawList::AddCallback()
|
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
|
ImGui_ImplVulkan_SetupRenderState(draw_data, bd->Pipeline, command_buffer, fb_width, fb_height);
|
|
else
|
|
pcmd->UserCallback(cmd_list, pcmd);
|
|
}
|
|
else
|
|
{
|
|
// Project scissor/clipping rectangles into framebuffer space
|
|
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
|
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
|
|
|
// Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds
|
|
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
|
|
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
|
|
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
|
|
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
|
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
|
continue;
|
|
|
|
// Apply scissor/clipping rectangle
|
|
VkRect2D scissor;
|
|
scissor.offset.x = (int32_t)(clip_min.x);
|
|
scissor.offset.y = (int32_t)(clip_min.y);
|
|
scissor.extent.width = (uint32_t)(clip_max.x - clip_min.x);
|
|
scissor.extent.height = (uint32_t)(clip_max.y - clip_min.y);
|
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
|
|
|
// Bind DescriptorSet with font or user texture
|
|
const Vulkan::Texture* tex = (const Vulkan::Texture*)pcmd->TextureId;
|
|
if (tex && last_texture != tex)
|
|
{
|
|
// if we can't get a descriptor set, we'll we're in trouble, since we can't restart the render pass from here.
|
|
VkDescriptorSet ds = g_vulkan_context->AllocateDescriptorSet(bd->DescriptorSetLayout);
|
|
if (ds == VK_NULL_HANDLE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Vulkan::DescriptorSetUpdateBuilder dsb;
|
|
dsb.AddCombinedImageSamplerDescriptorWrite(ds, 0, tex->GetView(), bd->FontSampler);
|
|
dsb.Update(g_vulkan_context->GetDevice());
|
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &ds, 0, nullptr);
|
|
last_texture = tex;
|
|
}
|
|
|
|
// Draw
|
|
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
|
|
}
|
|
}
|
|
global_idx_offset += cmd_list->IdxBuffer.Size;
|
|
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
|
}
|
|
|
|
// Note: at this point both vkCmdSetViewport() and vkCmdSetScissor() have been called.
|
|
// Our last values will leak into user/application rendering IF:
|
|
// - Your app uses a pipeline with VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR dynamic state
|
|
// - And you forgot to call vkCmdSetViewport() and vkCmdSetScissor() yourself to explicitely set that state.
|
|
// If you use VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR you are responsible for setting the values before rendering.
|
|
// In theory we should aim to backup/restore those values but I am not sure this is possible.
|
|
// We perform a call to vkCmdSetScissor() to set back a full viewport which is likely to fix things for 99% users but technically this is not perfect. (See github #4644)
|
|
VkRect2D scissor = { { 0, 0 }, { (uint32_t)fb_width, (uint32_t)fb_height } };
|
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
|
}
|
|
|
|
bool ImGui_ImplVulkan_CreateFontsTexture()
|
|
{
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
|
|
unsigned char* pixels;
|
|
int width, height;
|
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
|
|
|
if (bd->FontTexture.GetWidth() != static_cast<u32>(width) || bd->FontTexture.GetHeight() != static_cast<u32>(height))
|
|
{
|
|
if (!bd->FontTexture.Create(width, height, 1, 1, VK_FORMAT_R8G8B8A8_UNORM,
|
|
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
|
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Store our identifier
|
|
bd->FontTexture.Update(0, 0, width, height, 0, 0, pixels, sizeof(u32) * width);
|
|
io.Fonts->SetTexID((ImTextureID)&bd->FontTexture);
|
|
return true;
|
|
}
|
|
|
|
static bool ImGui_ImplVulkan_CreateShaderModules(VkDevice device)
|
|
{
|
|
// Create the shader modules
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
if (bd->ShaderModuleVert == VK_NULL_HANDLE)
|
|
{
|
|
VkShaderModuleCreateInfo vert_info = {};
|
|
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
vert_info.codeSize = sizeof(__glsl_shader_vert_spv);
|
|
vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;
|
|
VkResult err = vkCreateShaderModule(device, &vert_info, nullptr, &bd->ShaderModuleVert);
|
|
if (err != VK_SUCCESS)
|
|
return false;
|
|
}
|
|
if (bd->ShaderModuleFrag == VK_NULL_HANDLE)
|
|
{
|
|
VkShaderModuleCreateInfo frag_info = {};
|
|
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
|
|
frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
|
|
VkResult err = vkCreateShaderModule(device, &frag_info, nullptr, &bd->ShaderModuleFrag);
|
|
if (err != VK_SUCCESS)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool ImGui_ImplVulkan_CreateFontSampler(VkDevice device)
|
|
{
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
if (bd->FontSampler)
|
|
return true;
|
|
|
|
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
|
|
VkSamplerCreateInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
info.magFilter = VK_FILTER_LINEAR;
|
|
info.minFilter = VK_FILTER_LINEAR;
|
|
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
info.minLod = -1000;
|
|
info.maxLod = 1000;
|
|
info.maxAnisotropy = 1.0f;
|
|
VkResult err = vkCreateSampler(device, &info, nullptr, &bd->FontSampler);
|
|
return (err == VK_SUCCESS);
|
|
}
|
|
|
|
static bool ImGui_ImplVulkan_CreateDescriptorSetLayout(VkDevice device)
|
|
{
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
if (bd->DescriptorSetLayout)
|
|
return true;
|
|
|
|
if (!ImGui_ImplVulkan_CreateFontSampler(device))
|
|
return false;
|
|
|
|
VkSampler sampler[1] = { bd->FontSampler };
|
|
VkDescriptorSetLayoutBinding binding[1] = {};
|
|
binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
binding[0].descriptorCount = 1;
|
|
binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
binding[0].pImmutableSamplers = sampler;
|
|
VkDescriptorSetLayoutCreateInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
|
info.bindingCount = 1;
|
|
info.pBindings = binding;
|
|
VkResult err = vkCreateDescriptorSetLayout(device, &info, nullptr, &bd->DescriptorSetLayout);
|
|
return (err == VK_SUCCESS);
|
|
}
|
|
|
|
static bool ImGui_ImplVulkan_CreatePipelineLayout(VkDevice device)
|
|
{
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
if (bd->PipelineLayout)
|
|
return true;
|
|
|
|
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
|
|
ImGui_ImplVulkan_CreateDescriptorSetLayout(device);
|
|
VkPushConstantRange push_constants[1] = {};
|
|
push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
|
push_constants[0].offset = sizeof(float) * 0;
|
|
push_constants[0].size = sizeof(float) * 4;
|
|
VkDescriptorSetLayout set_layout[1] = { bd->DescriptorSetLayout };
|
|
VkPipelineLayoutCreateInfo layout_info = {};
|
|
layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
layout_info.setLayoutCount = 1;
|
|
layout_info.pSetLayouts = set_layout;
|
|
layout_info.pushConstantRangeCount = 1;
|
|
layout_info.pPushConstantRanges = push_constants;
|
|
VkResult err = vkCreatePipelineLayout(device, &layout_info, nullptr, &bd->PipelineLayout);
|
|
return (err == VK_SUCCESS);
|
|
}
|
|
|
|
static bool ImGui_ImplVulkan_CreatePipeline(VkDevice device, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkPipeline* pipeline)
|
|
{
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
if (!ImGui_ImplVulkan_CreateShaderModules(device))
|
|
return false;
|
|
|
|
VkPipelineShaderStageCreateInfo stage[2] = {};
|
|
stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
|
stage[0].module = bd->ShaderModuleVert;
|
|
stage[0].pName = "main";
|
|
stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
stage[1].module = bd->ShaderModuleFrag;
|
|
stage[1].pName = "main";
|
|
|
|
VkVertexInputBindingDescription binding_desc[1] = {};
|
|
binding_desc[0].stride = sizeof(ImDrawVert);
|
|
binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
|
|
|
VkVertexInputAttributeDescription attribute_desc[3] = {};
|
|
attribute_desc[0].location = 0;
|
|
attribute_desc[0].binding = binding_desc[0].binding;
|
|
attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT;
|
|
attribute_desc[0].offset = IM_OFFSETOF(ImDrawVert, pos);
|
|
attribute_desc[1].location = 1;
|
|
attribute_desc[1].binding = binding_desc[0].binding;
|
|
attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT;
|
|
attribute_desc[1].offset = IM_OFFSETOF(ImDrawVert, uv);
|
|
attribute_desc[2].location = 2;
|
|
attribute_desc[2].binding = binding_desc[0].binding;
|
|
attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM;
|
|
attribute_desc[2].offset = IM_OFFSETOF(ImDrawVert, col);
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertex_info = {};
|
|
vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
vertex_info.vertexBindingDescriptionCount = 1;
|
|
vertex_info.pVertexBindingDescriptions = binding_desc;
|
|
vertex_info.vertexAttributeDescriptionCount = 3;
|
|
vertex_info.pVertexAttributeDescriptions = attribute_desc;
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo ia_info = {};
|
|
ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
|
ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
|
|
VkPipelineViewportStateCreateInfo viewport_info = {};
|
|
viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
|
viewport_info.viewportCount = 1;
|
|
viewport_info.scissorCount = 1;
|
|
|
|
VkPipelineRasterizationStateCreateInfo raster_info = {};
|
|
raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
|
raster_info.polygonMode = VK_POLYGON_MODE_FILL;
|
|
raster_info.cullMode = VK_CULL_MODE_NONE;
|
|
raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
|
raster_info.lineWidth = 1.0f;
|
|
|
|
VkPipelineMultisampleStateCreateInfo ms_info = {};
|
|
ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
|
ms_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
VkPipelineColorBlendAttachmentState color_attachment[1] = {};
|
|
color_attachment[0].blendEnable = VK_TRUE;
|
|
color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD;
|
|
color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD;
|
|
color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
|
|
VkPipelineDepthStencilStateCreateInfo depth_info = {};
|
|
depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
|
|
|
VkPipelineColorBlendStateCreateInfo blend_info = {};
|
|
blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
blend_info.attachmentCount = 1;
|
|
blend_info.pAttachments = color_attachment;
|
|
|
|
VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
|
VkPipelineDynamicStateCreateInfo dynamic_state = {};
|
|
dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
|
dynamic_state.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states);
|
|
dynamic_state.pDynamicStates = dynamic_states;
|
|
|
|
if (!ImGui_ImplVulkan_CreatePipelineLayout(device))
|
|
return false;
|
|
|
|
VkGraphicsPipelineCreateInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
|
info.flags = bd->PipelineCreateFlags;
|
|
info.stageCount = 2;
|
|
info.pStages = stage;
|
|
info.pVertexInputState = &vertex_info;
|
|
info.pInputAssemblyState = &ia_info;
|
|
info.pViewportState = &viewport_info;
|
|
info.pRasterizationState = &raster_info;
|
|
info.pMultisampleState = &ms_info;
|
|
info.pDepthStencilState = &depth_info;
|
|
info.pColorBlendState = &blend_info;
|
|
info.pDynamicState = &dynamic_state;
|
|
info.layout = bd->PipelineLayout;
|
|
info.renderPass = renderPass;
|
|
info.subpass = 0;
|
|
VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, nullptr, pipeline);
|
|
return (err == VK_SUCCESS);
|
|
}
|
|
|
|
bool ImGui_ImplVulkan_CreateDeviceObjects()
|
|
{
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
|
|
if (!bd->VertexStreamBuffer.Create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VERTEX_BUFFER_SIZE) ||
|
|
!bd->IndexStreamBuffer.Create(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, INDEX_BUFFER_SIZE))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!ImGui_ImplVulkan_CreatePipeline(g_vulkan_context->GetDevice(), VK_NULL_HANDLE, bd->RenderPass, &bd->Pipeline))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ImGui_ImplVulkan_DestroyDeviceObjects()
|
|
{
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
|
|
bd->VertexStreamBuffer.Destroy(false);
|
|
bd->IndexStreamBuffer.Destroy(false);
|
|
bd->FontTexture.Destroy(false);
|
|
|
|
if (bd->ShaderModuleVert) { vkDestroyShaderModule(g_vulkan_context->GetDevice(), bd->ShaderModuleVert, nullptr); bd->ShaderModuleVert = VK_NULL_HANDLE; }
|
|
if (bd->ShaderModuleFrag) { vkDestroyShaderModule(g_vulkan_context->GetDevice(), bd->ShaderModuleFrag, nullptr); bd->ShaderModuleFrag = VK_NULL_HANDLE; }
|
|
if (bd->FontSampler) { vkDestroySampler(g_vulkan_context->GetDevice(), bd->FontSampler, nullptr); bd->FontSampler = VK_NULL_HANDLE; }
|
|
if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(g_vulkan_context->GetDevice(), bd->DescriptorSetLayout, nullptr); bd->DescriptorSetLayout = VK_NULL_HANDLE; }
|
|
if (bd->PipelineLayout) { vkDestroyPipelineLayout(g_vulkan_context->GetDevice(), bd->PipelineLayout, nullptr); bd->PipelineLayout = VK_NULL_HANDLE; }
|
|
if (bd->Pipeline) { vkDestroyPipeline(g_vulkan_context->GetDevice(), bd->Pipeline, nullptr); bd->Pipeline = VK_NULL_HANDLE; }
|
|
}
|
|
|
|
bool ImGui_ImplVulkan_Init(VkRenderPass render_pass)
|
|
{
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
|
|
|
// Setup backend capabilities flags
|
|
ImGui_ImplVulkan_Data* bd = IM_NEW(ImGui_ImplVulkan_Data)();
|
|
io.BackendRendererUserData = (void*)bd;
|
|
io.BackendRendererName = "imgui_impl_vulkan";
|
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
|
|
|
IM_ASSERT(render_pass != VK_NULL_HANDLE);
|
|
|
|
bd->RenderPass = render_pass;
|
|
|
|
return ImGui_ImplVulkan_CreateDeviceObjects();
|
|
}
|
|
|
|
void ImGui_ImplVulkan_Shutdown()
|
|
{
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
|
|
ImGui_ImplVulkan_DestroyDeviceObjects();
|
|
io.BackendRendererName = NULL;
|
|
io.BackendRendererUserData = NULL;
|
|
IM_DELETE(bd);
|
|
}
|