Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vulkan: Control secondary viewports format and present mode #8061

Draft
wants to merge 5 commits into
base: docking
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,009 changes: 826 additions & 183 deletions backends/imgui_impl_vulkan.cpp

Large diffs are not rendered by default.

81 changes: 73 additions & 8 deletions backends/imgui_impl_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,38 @@
#define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
#endif

#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
typedef VkPipelineRenderingCreateInfoKHR ImGui_ImplVulkan_PipelineRenderingInfo;
#else
typedef void ImGui_ImplVulkan_PipelineRenderingInfo;
#endif

enum ImGui_ImplVulkan_ColorCorrectionMethod : uint32_t
{
ImGui_ImplVulkan_ColorCorrection_None = 0, // Pass Through, no color correction
ImGui_ImplVulkan_ColorCorrection_Gamma = 1, // RGB gamma correction
ImGui_ImplVulkan_ColorCorrection_GammaAlpha = 2, // RGB Gamma correction + Alpha Gamma correction (with separate gamma factor)
};
struct ImGui_ImplVulkan_ColorCorrectionParameters
{
// Gamma, GammaAlpha: gamma exponent
float param1;
// Gamma, GammaAlpha: exposure multiplier
float param2;
// GammaAlpha: alpha channel gamma
float param3;
float param4;

static inline ImGui_ImplVulkan_ColorCorrectionParameters MakeGamma(float gamma, float exposure = 1.0f, float alpha_gamma = 1.0f)
{
ImGui_ImplVulkan_ColorCorrectionParameters res = {};
res.param1 = gamma;
res.param2 = exposure;
res.param3 = alpha_gamma;
return res;
}
};

// Initialization data, for ImGui_ImplVulkan_Init()
// - VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
// and must contain a pool size large enough to hold an ImGui VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor.
Expand All @@ -81,11 +113,13 @@ struct ImGui_ImplVulkan_InitInfo
uint32_t MinImageCount; // >= 2
uint32_t ImageCount; // >= MinImageCount
VkSampleCountFlagBits MSAASamples; // 0 defaults to VK_SAMPLE_COUNT_1_BIT

ImGui_ImplVulkan_ColorCorrectionMethod ColorCorrectionMethod;
ImGui_ImplVulkan_ColorCorrectionParameters ColorCorrectionParams;
// (Optional)
VkPipelineCache PipelineCache;
uint32_t Subpass;

bool UseStaticColorCorrectionsParams;
// (Optional) Dynamic Rendering
// Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3.
bool UseDynamicRendering;
Expand All @@ -100,10 +134,21 @@ struct ImGui_ImplVulkan_InitInfo
};

// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info);
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); // The main pipeline will be created if possible (RenderPass xor (UseDynamicRendering && PipelineRenderingCreateInfo->sType is correct))
struct ImGui_ImplVulkan_MainPipelineCreateInfo
{
VkRenderPass RenderPass = VK_NULL_HANDLE;
uint32_t Subpass = 0;
VkSampleCountFlagBits MSAASamples = {};
const ImGui_ImplVulkan_PipelineRenderingInfo * pDynamicRendering = nullptr;
ImGui_ImplVulkan_ColorCorrectionMethod ColorCorrectionMethod = {};
const ImGui_ImplVulkan_ColorCorrectionParameters * ColorCorrectionParams = nullptr;
};
IMGUI_IMPL_API void ImGui_ImplVulkan_ReCreateMainPipeline(ImGui_ImplVulkan_MainPipelineCreateInfo const& info);
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMainColorCorrectionParams(const ImGui_ImplVulkan_ColorCorrectionParameters& params);
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE, const ImGui_ImplVulkan_ColorCorrectionParameters * color_correction_params = nullptr);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture();
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
Expand All @@ -118,6 +163,19 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet de
// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr);

#define IMGUI_IMPL_VULKAN_SECONDARY_VIEWPORTS_CONTROL 1

struct ImGui_ImplVulkan_SecondaryViewportInfo
{
VkSurfaceFormatKHR SurfaceFormat = {};
const VkPresentModeKHR * PresentMode = nullptr; // Acts as an optional
ImGui_ImplVulkan_ColorCorrectionMethod ColorCorrectionMethod = {}; // Only applied if SurfaceFormat
const ImGui_ImplVulkan_ColorCorrectionParameters* ColorCorrectionParams = nullptr;
};

// Note: If the changes are accepted, they will take effect during the call to ImGui_ImplVulkan_RenderWindow(...) (when rendering secondary viewports)
IMGUI_IMPL_API void ImGui_ImplVulkan_RequestSecondaryViewportsChanges(ImGui_ImplVulkan_SecondaryViewportInfo const& info);

//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
Expand All @@ -138,11 +196,14 @@ struct ImGui_ImplVulkanH_Frame;
struct ImGui_ImplVulkanH_Window;

// Helpers
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
// To create the pipeline, ImGui_ImplVulkan_Init(...) must have been called before!
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count, bool create_pipeline = true);
IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator);
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
// Create the pipeline of wd
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateViewportPipeline(ImGui_ImplVulkanH_Window* wd, VkDevice device, const VkAllocationCallbacks* allocator);

// Helper structure to hold the data needed by one rendering frame
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
Expand All @@ -152,6 +213,7 @@ struct ImGui_ImplVulkanH_Frame
VkCommandPool CommandPool;
VkCommandBuffer CommandBuffer;
VkFence Fence;

VkImage Backbuffer;
VkImageView BackbufferView;
VkFramebuffer Framebuffer;
Expand All @@ -173,9 +235,8 @@ struct ImGui_ImplVulkanH_Window
VkSurfaceKHR Surface;
VkSurfaceFormatKHR SurfaceFormat;
VkPresentModeKHR PresentMode;
VkRenderPass RenderPass;
bool UseDynamicRendering;
bool ClearEnable;
VkRenderPass RenderPass; // Ownedship determined by OwnsRenderPass
VkPipeline Pipeline; // Owned by this
VkClearValue ClearValue;
uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
Expand All @@ -184,11 +245,15 @@ struct ImGui_ImplVulkanH_Window
ImGui_ImplVulkanH_Frame* Frames;
ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;

bool RenderPassClear;
bool UseDynamicRendering;
bool UseStaticColorCorrectionParams;
bool OwnsRenderPass;

ImGui_ImplVulkanH_Window()
{
memset((void*)this, 0, sizeof(*this));
PresentMode = (VkPresentModeKHR)~0; // Ensure we get an error if user doesn't set this.
ClearEnable = true;
}
};

Expand Down
3 changes: 2 additions & 1 deletion backends/vulkan/generate_spv.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
## -V: create SPIR-V binary
## -x: save binary output as text-based 32-bit hexadecimal numbers
## -o: output file
glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag
glslangValidator -V -x -DUSE_SPEC_CONSTANT_PARAMS=1 -o glsl_shader_static.frag.u32 glsl_shader.frag
glslangValidator -V -x -DUSE_SPEC_CONSTANT_PARAMS=0 -o glsl_shader_dynamic.frag.u32 glsl_shader.frag
glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
41 changes: 41 additions & 0 deletions backends/vulkan/glsl_shader.frag
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
#version 450 core

#ifndef USE_SPEC_CONSTANT_PARAMS
#define USE_SPEC_CONSTANT_PARAMS 0
#endif

layout(location = 0) out vec4 fColor;

layout(set=0, binding=0) uniform sampler2D sTexture;
Expand All @@ -8,7 +13,43 @@ layout(location = 0) in struct {
vec2 UV;
} In;

layout(constant_id = 0) const int color_correction_method = 0;
#if USE_SPEC_CONSTANT_PARAMS
layout(constant_id = 1) const float color_correction_param1 = 1.0f;
layout(constant_id = 2) const float color_correction_param2 = 1.0f;
layout(constant_id = 3) const float color_correction_param3 = 1.0f;
layout(constant_id = 4) const float color_correction_param4 = 1.0f;
#else
layout(push_constant) uniform uPushConstant {
layout(offset = 16 + 4 * 0) float color_correction_param1;
layout(offset = 16 + 4 * 1) float color_correction_param2;
layout(offset = 16 + 4 * 2) float color_correction_param3;
layout(offset = 16 + 4 * 3) float color_correction_param4;
};
#endif

vec4 ApplyColorCorrection(vec4 src)
{
vec4 res = src;
if(color_correction_method == 1 || color_correction_method == 2)
{
const float gamma = color_correction_param1;
const float exposure = color_correction_param2;
res.rgb = exposure * pow(src.rgb, gamma.xxx);
if(color_correction_method == 2)
{
const float alpha_gamma = color_correction_param3;
res.a = pow(src.a, alpha_gamma);
}
}
return res;
}

void main()
{
fColor = In.Color * texture(sTexture, In.UV.st);
if(color_correction_method != 0)
{
fColor = ApplyColorCorrection(fColor);
}
}
5 changes: 4 additions & 1 deletion examples/example_glfw_vulkan/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ static void SetupVulkan(ImVector<const char*> instance_extensions)
static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height)
{
wd->Surface = surface;
wd->RenderPassClear = true;

// Check for WSI support
VkBool32 res;
Expand All @@ -278,7 +279,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface

// Create SwapChain, RenderPass, Framebuffer, etc.
IM_ASSERT(g_MinImageCount >= 2);
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, false);
}

static void CleanupVulkan()
Expand Down Expand Up @@ -465,6 +466,8 @@ int main(int, char**)
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info);

ImGui_ImplVulkanH_CreateViewportPipeline(wd, g_Device, g_Allocator);

// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
Expand Down
5 changes: 4 additions & 1 deletion examples/example_sdl2_vulkan/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ static void SetupVulkan(ImVector<const char*> instance_extensions)
static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height)
{
wd->Surface = surface;
wd->RenderPassClear = true;

// Check for WSI support
VkBool32 res;
Expand All @@ -266,7 +267,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface

// Create SwapChain, RenderPass, Framebuffer, etc.
IM_ASSERT(g_MinImageCount >= 2);
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount);
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, false);
}

static void CleanupVulkan()
Expand Down Expand Up @@ -465,6 +466,8 @@ int main(int, char**)
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info);

ImGui_ImplVulkanH_CreateViewportPipeline(wd, g_Device, g_Allocator);

// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
Expand Down