1
0
Fork 0

Vulkan ImGui full

tmp
May B. 2020-10-18 17:34:27 +02:00
parent c7da6fbcc0
commit d323668ab4
27 changed files with 365 additions and 899 deletions

24
TODO.md
View File

@ -2,11 +2,9 @@
## Hello screen again
- [~] Extract OpenGL
- Rename Passes/Programs as Pipelines
- [~] Minimal Vulkan
- [ ] ImGui
- [ ] Config (yaml)
- [x] Extract OpenGL
- [x] Minimal Vulkan
- [x] ImGui
## Hello other
@ -16,6 +14,11 @@
- [ ] Encryption
- [x] Embedded
- [x] Standalone
- [ ] VK
- [ ] Pipeline recreate
- [ ] Pipeline cache
- [ ] Reuse descriptors
- [ ] Secondary buffers
## Hello world
@ -26,6 +29,7 @@
- [~] Occlusion Culling
- [ ] Iterator ray
- [ ] Cast from chunk center
- [ ] Transparency
## Hello darkness
@ -44,14 +48,18 @@
- https://imgur.com/a/bh2iy
- https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png
- [ ] Galaxy
- [ ] Dynamic SIMD libs
- [ ] FastNoiseSIMD / HastyNoise double precision
- [ ] Octree
- SIMD
- [ ] Dynamic SIMD libs
- [ ] FastNoiseSIMD / HastyNoise double precision
- [ ] https://github.com/Auburn/FastNoise2/releases
- [ ] Cross plateforme encoding
- [ ] Config (yaml)
- [ ] HDR
- https://www.youtube.com/watch?v=iikdcAA7cww
- Toon shading
- Eye adaptation
- [ ] Correct sRGB conversions
- [ ] Post processing
- https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing
- Bloom
@ -59,5 +67,3 @@
- [ ] Deferred
- [ ] Cascaded shadow maps
- [ ] Ray Tracing
- [ ] Transparency
- [ ] https://github.com/Auburn/FastNoise2/releases

View File

@ -78,7 +78,6 @@ static VkDeviceSize g_BufferMemoryAlignment = 256;
static VkPipelineCreateFlags g_PipelineCreateFlags = 0x00;
static VkDescriptorSetLayout g_DescriptorSetLayout = VK_NULL_HANDLE;
static VkPipelineLayout g_PipelineLayout = VK_NULL_HANDLE;
static VkDescriptorSet g_DescriptorSet = VK_NULL_HANDLE;
static VkPipeline g_Pipeline = VK_NULL_HANDLE;
// Font data
@ -179,36 +178,38 @@ 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);
fColor = pow(In.Color * texture(sTexture, In.UV.st), vec4(vec3(2.2), 1));
}
*/
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
0x07230203,0x00010000,0x00080008,0x00000022,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,0x0004002b,0x00000006,0x0000001e,
0x400ccccd,0x0004002b,0x00000006,0x0000001f,0x3f800000,0x0007002c,0x00000007,0x00000020,
0x0000001e,0x0000001e,0x0000001e,0x0000001f,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,0x0007000c,0x00000007,0x00000021,0x00000001,0x0000001a,
0x0000001d,0x00000020,0x0003003e,0x00000009,0x00000021,0x000100fd,0x00010038
};
//-----------------------------------------------------------------------------
@ -268,11 +269,9 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory
static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkCommandBuffer command_buffer, ImGui_ImplVulkanH_FrameRenderBuffers* rb, int fb_width, int fb_height)
{
// Bind pipeline and descriptor sets:
// Bind pipeline:
{
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_Pipeline);
VkDescriptorSet desc_set[1] = { g_DescriptorSet };
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL);
}
// Bind Vertex And Index Buffer:
@ -384,6 +383,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
// (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;
// Avoid rebinding textures
ImTextureID currentTexture = nullptr;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
@ -424,6 +425,13 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
scissor.extent.height = (uint32_t)(clip_rect.w - clip_rect.y);
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
// Bind descriptorset with font or user texture
if (pcmd->TextureId != currentTexture) {
VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId };
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL);
currentTexture = pcmd->TextureId;
}
// Draw
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
}
@ -490,20 +498,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
check_vk_result(err);
}
// Update the Descriptor Set:
{
VkDescriptorImageInfo desc_image[1] = {};
desc_image[0].sampler = g_FontSampler;
desc_image[0].imageView = g_FontView;
desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_desc[0].dstSet = g_DescriptorSet;
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
VkDescriptorSet font_descriptor_set = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture({g_FontSampler, g_FontView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL});
// Create the Upload Buffer:
{
@ -581,7 +576,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
}
// Store our identifier
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontImage;
io.Fonts->TexID = (ImTextureID)font_descriptor_set;
return true;
}
@ -628,12 +623,10 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
if (!g_DescriptorSetLayout)
{
VkSampler sampler[1] = {g_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;
@ -642,17 +635,6 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
check_vk_result(err);
}
// Create Descriptor Set:
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);
check_vk_result(err);
}
if (!g_PipelineLayout)
{
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
@ -1224,3 +1206,35 @@ void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVul
buffers->Index = 0;
buffers->Count = 0;
}
ImTextureID ImGui_ImplVulkan_AddTexture(VkDescriptorImageInfo imageInfo){
VkResult err;
//TODO: hash imageInfo and cache
ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkDescriptorSet descriptor_set;
// Create Descriptor Set:
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &g_DescriptorSetLayout;
err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set);
check_vk_result(err);
}
// Update the Descriptor Set:
{
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_desc[0].dstSet = descriptor_set;
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = &imageInfo;
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
return (ImTextureID)descriptor_set;
}

View File

@ -22,7 +22,7 @@
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#include <vulkan/vulkan.h>
#include <volk.h>
// Initialization data, for ImGui_ImplVulkan_Init()
// [Please zero-clear before use!]
@ -50,7 +50,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, V
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
IMGUI_IMPL_API ImTextureID ImGui_ImplVulkan_AddTexture(VkDescriptorImageInfo imageInfo);
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers

View File

@ -1,3 +0,0 @@
#!/bin/bash
glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag
glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert

View File

@ -1,14 +0,0 @@
#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);
}

View File

@ -1,25 +0,0 @@
#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);
}

View File

@ -1,214 +0,0 @@
// dear imgui: standalone example application for GLFW + OpenGL 3, using programmable pipeline
// If you are new to dear imgui, see examples/README.txt and documentation at the top of imgui.cpp.
// (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.)
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include <stdio.h>
// About Desktop OpenGL function loaders:
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
#include <GL/gl3w.h> // Initialize with gl3wInit()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
#include <GL/glew.h> // Initialize with glewInit()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
#include <glad/glad.h> // Initialize with gladLoadGL()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
#include <glad/gl.h> // Initialize with gladLoadGL(...) or gladLoaderLoadGL()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#include <glbinding/Binding.h> // Initialize with glbinding::Binding::initialize()
#include <glbinding/gl/gl.h>
using namespace gl;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#include <glbinding/glbinding.h>// Initialize with glbinding::initialize()
#include <glbinding/gl/gl.h>
using namespace gl;
#else
#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
#endif
// Include glfw3.h after our OpenGL definitions
#include <GLFW/glfw3.h>
// [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers.
// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma.
// Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio.
#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#pragma comment(lib, "legacy_stdio_definitions")
#endif
static void glfw_error_callback(int error, const char* description)
{
fprintf(stderr, "Glfw Error %d: %s\n", error, description);
}
int main(int, char**)
{
// Setup window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
// Decide GL+GLSL versions
#if __APPLE__
// GL 3.2 + GLSL 150
const char* glsl_version = "#version 150";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
#else
// GL 3.0 + GLSL 130
const char* glsl_version = "#version 130";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only
#endif
// Create window with graphics context
GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+OpenGL3 example", NULL, NULL);
if (window == NULL)
return 1;
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // Enable vsync
// Initialize OpenGL loader
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
bool err = gl3wInit() != 0;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
bool err = glewInit() != GLEW_OK;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
bool err = gladLoadGL() == 0;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
bool err = gladLoadGL(glfwGetProcAddress) == 0; // glad2 recommend using the windowing library loader instead of the (optionally) bundled one.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
bool err = false;
glbinding::Binding::initialize();
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
bool err = false;
glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)glfwGetProcAddress(name); });
#else
bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization.
#endif
if (err)
{
fprintf(stderr, "Failed to initialize OpenGL loader!\n");
return 1;
}
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init(glsl_version);
// 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.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'docs/FONTS.md' for more instructions and details.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//io.Fonts->AddFontDefault();
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f);
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
//IM_ASSERT(font != NULL);
// Our state
bool show_demo_window = true;
bool show_another_window = false;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// Main loop
while (!glfwWindowShouldClose(window))
{
// Poll and handle events (inputs, window resize, etc.)
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
glfwPollEvents();
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
{
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::End();
}
// 3. Show another simple window.
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
ImGui::Text("Hello from another window!");
if (ImGui::Button("Close Me"))
show_another_window = false;
ImGui::End();
}
// Rendering
ImGui::Render();
int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
}
// Cleanup
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}

View File

@ -1,536 +0,0 @@
// dear imgui: standalone example application for Glfw + Vulkan
// If you are new to dear imgui, see examples/README.txt and documentation at the top of imgui.cpp.
// 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 back-end in your engine/app.
// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
// the back-end itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
// Read comments in imgui_impl_vulkan.h.
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_vulkan.h"
#include <stdio.h> // printf, fprintf
#include <stdlib.h> // abort
#define GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vulkan/vulkan.h>
// [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers.
// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma.
// Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio.
#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#pragma comment(lib, "legacy_stdio_definitions")
#endif
//#define IMGUI_UNLIMITED_FRAME_RATE
#ifdef _DEBUG
#define IMGUI_VULKAN_DEBUG_REPORT
#endif
static VkAllocationCallbacks* g_Allocator = NULL;
static VkInstance g_Instance = VK_NULL_HANDLE;
static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
static VkDevice g_Device = VK_NULL_HANDLE;
static uint32_t g_QueueFamily = (uint32_t)-1;
static VkQueue g_Queue = VK_NULL_HANDLE;
static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE;
static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
static ImGui_ImplVulkanH_Window g_MainWindowData;
static int g_MinImageCount = 2;
static bool g_SwapChainRebuild = false;
static int g_SwapChainResizeWidth = 0;
static int g_SwapChainResizeHeight = 0;
static void check_vk_result(VkResult err)
{
if (err == 0)
return;
fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err);
if (err < 0)
abort();
}
#ifdef IMGUI_VULKAN_DEBUG_REPORT
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData)
{
(void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments
fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage);
return VK_FALSE;
}
#endif // IMGUI_VULKAN_DEBUG_REPORT
static void SetupVulkan(const char** extensions, uint32_t extensions_count)
{
VkResult err;
// Create Vulkan Instance
{
VkInstanceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.enabledExtensionCount = extensions_count;
create_info.ppEnabledExtensionNames = extensions;
#ifdef IMGUI_VULKAN_DEBUG_REPORT
// Enabling multiple validation layers grouped as LunarG standard validation
const char* layers[] = { "VK_LAYER_LUNARG_standard_validation" };
create_info.enabledLayerCount = 1;
create_info.ppEnabledLayerNames = layers;
// Enable debug report extension (we need additional storage, so we duplicate the user array to add our new extension to it)
const char** extensions_ext = (const char**)malloc(sizeof(const char*) * (extensions_count + 1));
memcpy(extensions_ext, extensions, extensions_count * sizeof(const char*));
extensions_ext[extensions_count] = "VK_EXT_debug_report";
create_info.enabledExtensionCount = extensions_count + 1;
create_info.ppEnabledExtensionNames = extensions_ext;
// Create Vulkan Instance
err = vkCreateInstance(&create_info, g_Allocator, &g_Instance);
check_vk_result(err);
free(extensions_ext);
// Get the function pointer (required for any extensions)
auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT");
IM_ASSERT(vkCreateDebugReportCallbackEXT != NULL);
// Setup the debug report callback
VkDebugReportCallbackCreateInfoEXT debug_report_ci = {};
debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
debug_report_ci.pfnCallback = debug_report;
debug_report_ci.pUserData = NULL;
err = vkCreateDebugReportCallbackEXT(g_Instance, &debug_report_ci, g_Allocator, &g_DebugReport);
check_vk_result(err);
#else
// Create Vulkan Instance without any debug feature
err = vkCreateInstance(&create_info, g_Allocator, &g_Instance);
check_vk_result(err);
IM_UNUSED(g_DebugReport);
#endif
}
// Select GPU
{
uint32_t gpu_count;
err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, NULL);
check_vk_result(err);
IM_ASSERT(gpu_count > 0);
VkPhysicalDevice* gpus = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * gpu_count);
err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus);
check_vk_result(err);
// If a number >1 of GPUs got reported, you should find the best fit GPU for your purpose
// e.g. VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU if available, or with the greatest memory available, etc.
// for sake of simplicity we'll just take the first one, assuming it has a graphics queue family.
g_PhysicalDevice = gpus[0];
free(gpus);
}
// Select graphics queue family
{
uint32_t count;
vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, NULL);
VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count);
vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, queues);
for (uint32_t i = 0; i < count; i++)
if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
{
g_QueueFamily = i;
break;
}
free(queues);
IM_ASSERT(g_QueueFamily != (uint32_t)-1);
}
// Create Logical Device (with 1 queue)
{
int device_extension_count = 1;
const char* device_extensions[] = { "VK_KHR_swapchain" };
const float queue_priority[] = { 1.0f };
VkDeviceQueueCreateInfo queue_info[1] = {};
queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info[0].queueFamilyIndex = g_QueueFamily;
queue_info[0].queueCount = 1;
queue_info[0].pQueuePriorities = queue_priority;
VkDeviceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]);
create_info.pQueueCreateInfos = queue_info;
create_info.enabledExtensionCount = device_extension_count;
create_info.ppEnabledExtensionNames = device_extensions;
err = vkCreateDevice(g_PhysicalDevice, &create_info, g_Allocator, &g_Device);
check_vk_result(err);
vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &g_Queue);
}
// Create Descriptor Pool
{
VkDescriptorPoolSize pool_sizes[] =
{
{ VK_DESCRIPTOR_TYPE_SAMPLER, 1000 },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 },
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 },
{ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 }
};
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes);
pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes);
pool_info.pPoolSizes = pool_sizes;
err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool);
check_vk_result(err);
}
}
// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
// Your real engine/app may not use them.
static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height)
{
wd->Surface = surface;
// Check for WSI support
VkBool32 res;
vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, wd->Surface, &res);
if (res != VK_TRUE)
{
fprintf(stderr, "Error no WSI support on physical device 0\n");
exit(-1);
}
// Select Surface Format
const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace);
// Select Present Mode
#ifdef IMGUI_UNLIMITED_FRAME_RATE
VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
#else
VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR };
#endif
wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(g_PhysicalDevice, wd->Surface, &present_modes[0], IM_ARRAYSIZE(present_modes));
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// 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);
}
static void CleanupVulkan()
{
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef IMGUI_VULKAN_DEBUG_REPORT
// Remove the debug report callback
auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT");
vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator);
#endif // IMGUI_VULKAN_DEBUG_REPORT
vkDestroyDevice(g_Device, g_Allocator);
vkDestroyInstance(g_Instance, g_Allocator);
}
static void CleanupVulkanWindow()
{
ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator);
}
static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data)
{
VkResult err;
VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore;
VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex);
check_vk_result(err);
ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex];
{
err = vkWaitForFences(g_Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX); // wait indefinitely instead of periodically checking
check_vk_result(err);
err = vkResetFences(g_Device, 1, &fd->Fence);
check_vk_result(err);
}
{
err = vkResetCommandPool(g_Device, fd->CommandPool, 0);
check_vk_result(err);
VkCommandBufferBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
err = vkBeginCommandBuffer(fd->CommandBuffer, &info);
check_vk_result(err);
}
{
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
info.pClearValues = &wd->ClearValue;
vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
// Record dear imgui primitives into command buffer
ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer);
// Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer);
{
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &image_acquired_semaphore;
info.pWaitDstStageMask = &wait_stage;
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
err = vkQueueSubmit(g_Queue, 1, &info, fd->Fence);
check_vk_result(err);
}
}
static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &render_complete_semaphore;
info.swapchainCount = 1;
info.pSwapchains = &wd->Swapchain;
info.pImageIndices = &wd->FrameIndex;
VkResult err = vkQueuePresentKHR(g_Queue, &info);
check_vk_result(err);
wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->ImageCount; // Now we can use the next set of semaphores
}
static void glfw_error_callback(int error, const char* description)
{
fprintf(stderr, "Glfw Error %d: %s\n", error, description);
}
static void glfw_resize_callback(GLFWwindow*, int w, int h)
{
g_SwapChainRebuild = true;
g_SwapChainResizeWidth = w;
g_SwapChainResizeHeight = h;
}
int main(int, char**)
{
// Setup GLFW window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return 1;
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+Vulkan example", NULL, NULL);
// Setup Vulkan
if (!glfwVulkanSupported())
{
printf("GLFW: Vulkan Not Supported\n");
return 1;
}
uint32_t extensions_count = 0;
const char** extensions = glfwGetRequiredInstanceExtensions(&extensions_count);
SetupVulkan(extensions, extensions_count);
// Create Window Surface
VkSurfaceKHR surface;
VkResult err = glfwCreateWindowSurface(g_Instance, window, g_Allocator, &surface);
check_vk_result(err);
// Create Framebuffers
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glfwSetFramebufferSizeCallback(window, glfw_resize_callback);
ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
SetupVulkanWindow(wd, surface, w, h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForVulkan(window, true);
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = g_Instance;
init_info.PhysicalDevice = g_PhysicalDevice;
init_info.Device = g_Device;
init_info.QueueFamily = g_QueueFamily;
init_info.Queue = g_Queue;
init_info.PipelineCache = g_PipelineCache;
init_info.DescriptorPool = g_DescriptorPool;
init_info.Allocator = g_Allocator;
init_info.MinImageCount = g_MinImageCount;
init_info.ImageCount = wd->ImageCount;
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);
// 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.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'docs/FONTS.md' for more instructions and details.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//io.Fonts->AddFontDefault();
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f);
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
//IM_ASSERT(font != NULL);
// Upload Fonts
{
// Use any command queue
VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool;
VkCommandBuffer command_buffer = wd->Frames[wd->FrameIndex].CommandBuffer;
err = vkResetCommandPool(g_Device, command_pool, 0);
check_vk_result(err);
VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
err = vkBeginCommandBuffer(command_buffer, &begin_info);
check_vk_result(err);
ImGui_ImplVulkan_CreateFontsTexture(command_buffer);
VkSubmitInfo end_info = {};
end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
end_info.commandBufferCount = 1;
end_info.pCommandBuffers = &command_buffer;
err = vkEndCommandBuffer(command_buffer);
check_vk_result(err);
err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE);
check_vk_result(err);
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
ImGui_ImplVulkan_DestroyFontUploadObjects();
}
// Our state
bool show_demo_window = true;
bool show_another_window = false;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// Main loop
while (!glfwWindowShouldClose(window))
{
// Poll and handle events (inputs, window resize, etc.)
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
glfwPollEvents();
// Resize swap chain?
if (g_SwapChainRebuild && g_SwapChainResizeWidth > 0 && g_SwapChainResizeHeight > 0)
{
g_SwapChainRebuild = false;
ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, g_SwapChainResizeWidth, g_SwapChainResizeHeight, g_MinImageCount);
g_MainWindowData.FrameIndex = 0;
}
// Start the Dear ImGui frame
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
{
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::End();
}
// 3. Show another simple window.
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
ImGui::Text("Hello from another window!");
if (ImGui::Button("Close Me"))
show_another_window = false;
ImGui::End();
}
// Rendering
ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData();
const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f);
if (!is_minimized)
{
memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float));
FrameRender(wd, draw_data);
FramePresent(wd);
}
}
// Cleanup
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
CleanupVulkanWindow();
CleanupVulkan();
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}

View File

@ -13,15 +13,16 @@ Client::Client(config::client::options& options): options(options) { }
Client::~Client() { }
void Client::run(server_handle* const localHandle) {
if (!render::Load(window, options.preferVulkan, options.renderer, options.window.samples))
if (!render::Load(window, options.preferVulkan, options.renderer, options.window.getSamples()))
return;
window.setTargetFPS(options.window.targetFPS);
window.setFullscreen(options.window.fullscreen);
InputMap inputs(window.getPtr());
Controllable player(window.getPtr(), inputs, options.control);
Camera camera(&player, options.camera);
state.position = player.position;
auto pipeline = render::Renderer::Get();
pipeline->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2));
@ -55,7 +56,7 @@ void Client::run(server_handle* const localHandle) {
}
camera.update();
pipeline->lookFrom(camera);
pipeline->LightInvDir = glm::vec3(glm::rotate(glm::mat4(1), deltaTime * .5f, glm::vec3(1, .5, .1)) * glm::vec4(pipeline->LightInvDir, 0));
pipeline->LightInvDir = glm::vec3(glm::rotate(glm::mat4(1), deltaTime * .1f, glm::vec3(1, .5, .1)) * glm::vec4(pipeline->LightInvDir, 0));
{
const auto ray_result = world->raycast(camera.getRay() * options.voxel_density);
@ -113,7 +114,7 @@ void Client::run(server_handle* const localHandle) {
player.setOptions(options.control);
}
if(actions && render::UI::Actions::FillMode) {
//TODO: pipeline->setFillMode(options.renderer.wireframe);
pipeline->setFillMode(options.renderer.wireframe);
}
}
{ // Rendering
@ -184,7 +185,6 @@ void Client::run(server_handle* const localHandle) {
options.contouring = state.contouring->getOptions();
world.reset();
render::UI::Unload();
render::Renderer::Unload();
window.destroy();
}

View File

@ -43,7 +43,6 @@ bool Window::create(const CreateInfo &opt) {
break;
case CreateInfo::Client::Type::VK:
LOG_W("WIP client type");
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
break;

View File

@ -29,7 +29,7 @@ public:
assert(config["enabled"]);
window.targetFPS = config["window"]["target_fps"].value_or(window.targetFPS);
window.samples = config["window"]["samples"].value_or(window.samples);
window.sampling = config["window"]["sampling"].value_or(window.sampling);
window.fullscreen = config["window"]["fullscreen"].value_or(window.fullscreen);
renderer.inFlightFrames = config["window"]["parallel_frames"].value_or(renderer.inFlightFrames);
@ -96,7 +96,7 @@ public:
config.insert_or_assign("enabled", true);
config.insert_or_assign("window", toml::table({
{"target_fps", window.targetFPS},
{"samples", window.samples},
{"sampling", window.sampling},
{"fullscreen", window.fullscreen},
{"parallel_frames", renderer.inFlightFrames}
}));
@ -181,8 +181,10 @@ public:
struct {
int targetFPS = 60;
int samples = -1;
int sampling = -1;
bool fullscreen = false;
constexpr int getSamples() const { return sampling > 0 ? (1 << (sampling - 1)) : sampling; }
} window;
bool preferVulkan = true;

View File

@ -86,6 +86,7 @@ public:
virtual void setClearColor(glm::vec4) = 0;
virtual void reloadShaders(const passOptions &) = 0;
virtual void reloadTextures(const std::string &, float mipMapLOD, float anisotropy) = 0;
virtual void setFillMode(bool wireframe) = 0;
virtual void loadUI(Window&) = 0;

View File

@ -52,14 +52,24 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons
if (options.debugMenu.render) {
ImGui::Begin("Debug: Render", &options.debugMenu.render, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::Text("Tris: %ld (%ld models)", reports.tris_count, reports.models_count);
ImGui::Separator();
ImGui::Checkbox("Overlay", &options.overlay.visible);
{
ImGui::Combo("Driver", (int*)&options.preferVulkan, "OpenGL\0Vulkan\0");
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Prefer Vulkan over OpenGL if available (requires restart)");
auto samples = std::to_string(options.window.getSamples()) + "x";
ImGui::SliderInt("MSAA", &options.window.sampling, -1, 7, options.window.sampling > 0 ? samples.c_str() :
(options.window.sampling < 0 ? "System default" : "Minimun"));
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Anti-aliasing (requires restart).\nActual value may be smaller than requested");
ImGui::Separator();
}
if (ImGui::SliderInt("FPS", &options.window.targetFPS, Window::MIN_FPS-1, Window::MAX_FPS+1, options.window.targetFPS > Window::MIN_FPS ? (options.window.targetFPS < Window::MAX_FPS ? "%d" : "UNLIMITED") : "VSYNC")){
actions |= Actions::FPS;
}
ImGui::Text("Sampling %d (requires restart)", options.window.samples);
if (ImGui::Checkbox("Fullscreen", &options.window.fullscreen)){
actions |= Actions::FullScreen;
}
@ -106,8 +116,9 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons
actions |= Actions::FillMode;
}
ImGui::Text("Textures '%s'", options.renderer.textures.c_str()); // MAYBE: select
std::string anisotropy = std::to_string(options.renderer.getAnisotropy()) + "x";
if (ImGui::SliderInt("Quality", &options.renderer.textureQuality, 0, 200, "%d%%") |
ImGui::SliderInt("Sharpness", &options.renderer.textureSharpness, 0, 8)) {
ImGui::SliderInt("Sharpness", &options.renderer.textureSharpness, 0, 8, anisotropy.c_str())) {
actions |= Actions::RendererTextures;
}
if(ImGui::IsItemHovered())

View File

@ -29,9 +29,11 @@ Renderer::Renderer(const renderOptions& options):
FogColor = glm::vec3(options.clear_color.x, options.clear_color.y, options.clear_color.z);
loadTextures(options.textures, options.getMipmapLodBias(), options.getAnisotropy());
setFillMode(options.wireframe);
}
Renderer::~Renderer() {
render::UI::Unload();
unloadTextures();
glDeleteVertexArrays(1, &VertexArrayID);
}
@ -172,3 +174,7 @@ void Renderer::setClearColor(glm::vec4 c) {
FogColor = c;
glClearColor(c.r, c.g, c.b, c.a);
}
void Renderer::setFillMode(bool wireframe) {
glPolygonMode(GL_FRONT_AND_BACK, wireframe ? GL_LINE : GL_FILL);
}

View File

@ -55,6 +55,7 @@ public:
void lookFrom(const Camera&) override;
void reloadShaders(const pass::VoxelProgram::options &) override;
void reloadTextures(const std::string &, float mipMapLOD, float anisotropy) override;
void setFillMode(bool wireframe) override;
void loadUI(Window &) override;

View File

@ -175,6 +175,11 @@ void submitCmd(VkCommandBuffer buffer, VkQueue queue) {
vkQueueWaitIdle(queue); //MAYBE: use fences
vkResetCommandBuffer(buffer, 0);
}
void Allocator::transfer(std::function<void(VkCommandBuffer)> call) {
beginCmd(transferBuffer);
call(transferBuffer);
submitCmd(transferBuffer, transferQueue);
}
void Allocator::copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size) {
beginCmd(transferBuffer);

View File

@ -6,6 +6,7 @@
#include <cassert>
#include <vector>
#include <optional>
#include <functional>
namespace render::vk {
@ -32,6 +33,7 @@ public:
memory::ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags, bool optimalTiling = false);
bool deallocate(const memory::area&);
void transfer(std::function<void(VkCommandBuffer)>);
void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size);
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels, uint32_t arrayLayers);
void copyBufferToImage(VkBuffer src, VkImage dst, uint32_t width, uint32_t height, uint32_t mipLevels = 1, uint32_t arrayLayer = 0);

View File

@ -113,6 +113,23 @@ void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeli
}
}
uiFramebuffers.resize(views.size());
for (size_t i = 0; i < views.size(); i++) {
VkFramebufferCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass = pipe.getUIRenderPass();
info.attachmentCount = 1;
info.pAttachments = &views[i];
info.width = extent.width;
info.height = extent.height;
info.layers = 1;
if (vkCreateFramebuffer(device, &info, ALLOC, &uiFramebuffers[i]) != VK_SUCCESS) {
FATAL("Failed to create ui framebuffer!");
}
}
{ // Uniform buffers
std::vector<Buffer::requirement> requirements;
requirements.resize(framebuffers.size(), Buffer::requirement(sizeof(VoxelUBO), Buffer::Usage::UNIFORM));
@ -253,6 +270,9 @@ void CommandCenter::free() {
for (size_t i = 0; i < framebuffers.size(); i++) {
vkDestroyFramebuffer(device, framebuffers[i], ALLOC);
}
for (size_t i = 0; i < uiFramebuffers.size(); i++) {
vkDestroyFramebuffer(device, uiFramebuffers[i], ALLOC);
}
freed = true;
}
@ -277,7 +297,7 @@ void CommandCenter::startRecording(uint32_t idx, VkRenderPass renderPass, VkExte
if (!idx) {
TracyVkCollect(tracyCtx, graphicsBuffers[idx]);
}
TracyVkZone(tracyCtx, graphicsBuffers[idx], "Render");
TracyVkZone(tracyCtx, graphicsBuffers[idx], "Begin");
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = renderPass;
@ -336,9 +356,24 @@ void CommandCenter::recordPostprocess(uint32_t idx, const Subpass& skyPass, bool
vkCmdDraw(graphicsBuffers[idx], skyCubeBuffer->size, 1, 0, 0);
}
vkCmdEndRenderPass(graphicsBuffers[idx]);
TracyVkZone(tracyCtx, graphicsBuffers[idx], "Swap");
}
void CommandCenter::recordUI(uint32_t idx, VkRenderPass uiPass, VkExtent2D extent, const std::function<void(VkCommandBuffer)>& call) {
TracyVkZone(tracyCtx, graphicsBuffers[idx], "UI");
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = uiPass;
info.framebuffer = uiFramebuffers[idx];
info.renderArea.extent = extent;
info.clearValueCount = 1;
VkClearValue clearValue{};
clearValue.color = {0.f, 0.f, 0.f, 1.f};
info.pClearValues = &clearValue;
vkCmdBeginRenderPass(graphicsBuffers[idx], &info, VK_SUBPASS_CONTENTS_INLINE);
call(graphicsBuffers[idx]);
vkCmdEndRenderPass(graphicsBuffers[idx]);
}
void CommandCenter::submitGraphics(uint32_t idx, VkSemaphore waitSemaphore, VkSemaphore signalSemaphore, VkFence submittedFence) {
assert(!freed);

View File

@ -2,6 +2,7 @@
#include "forward.hpp"
#include <vector>
#include <functional>
#include <glm/mat4x4.hpp>
#include "api/Buffers.hpp"
#include "api/Images.hpp"
@ -29,17 +30,19 @@ public:
void startIndicPass(uint32_t idx, const Subpass&);
size_t recordIndicator(uint32_t idx, const Subpass&, glm::mat4 model);
void recordPostprocess(uint32_t idx, const Subpass&, bool skybox);
void recordUI(uint32_t idx, VkRenderPass uiPass, VkExtent2D, const std::function<void(VkCommandBuffer)> &);
void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence);
void loadAtlases(const std::string &texturePath, int anisotropy, float lodBias);
void allocate(const std::vector<VkImageView>&, const Pipeline&, VkPhysicalDevice, VkExtent2D);
void free();
private:
void loadAtlases(const std::string &texturePath, int anisotropy, float lodBias);
VkDevice device;
std::vector<VkFramebuffer> framebuffers;
std::vector<VkFramebuffer> uiFramebuffers;
VkFormat colorFormat;
VkSampleCountFlagBits colorSamples;

View File

@ -23,8 +23,8 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = hasSamples ?
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
// NOTE: UI RenderPass do VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
VkAttachmentReference colorAttachmentRef{};
colorAttachmentRef.attachment = 0; //TODO: layouts bind
@ -52,7 +52,8 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
// NOTE: UI RenderPass do VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
VkAttachmentReference colorAttachmentResolveRef{};
colorAttachmentResolveRef.attachment = 2;
@ -126,6 +127,46 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
FATAL("Failed to create render pass!");
}
}
{ // UI Render pass
VkAttachmentDescription attachment = {};
attachment.format = info.getSurfaceFormat().format;
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference color_attachment = {};
color_attachment.attachment = 0;
color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_attachment;
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0; // or VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkRenderPassCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
info.attachmentCount = 1;
info.pAttachments = &attachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;
info.dependencyCount = 1;
info.pDependencies = &dependency;
if (vkCreateRenderPass(device, &info, nullptr, &uiRenderPass) != VK_SUCCESS) {
FATAL("Failed to create UI render pass!");
}
}
//MAYBE: use sets (ubo, (samplers, passInfos))
//MAYBE: reuse sub UBO
{ // Voxel descriptor
@ -310,7 +351,7 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = options.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
rasterizer.polygonMode = options.wireframe && info.features.fillModeNonSolid ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
@ -519,6 +560,8 @@ Pipeline::~Pipeline() {
vkDestroyPipelineLayout(device, pass.layout, ALLOC);
};
vkDestroyRenderPass(device, uiRenderPass, ALLOC);
destroy(worldPass);
destroy(indicPass);
destroy(skyPass);

View File

@ -28,6 +28,8 @@ public:
constexpr VkDescriptorSetLayout getSkyDescriptorSet() const { return skyDescriptorSet; }
constexpr const Subpass& getSkyPass() const { return skyPass; }
constexpr VkRenderPass getUIRenderPass() const { return uiRenderPass; }
private:
VkDevice device;
@ -40,5 +42,7 @@ private:
Subpass worldPass;
Subpass indicPass;
Subpass skyPass;
VkRenderPass uiRenderPass;
};
}

View File

@ -12,6 +12,7 @@
#include <string.h>
#include <algorithm>
#include <set>
#include <Tracy.hpp>
using namespace render::vk;
@ -81,6 +82,7 @@ Renderer::~Renderer() {
vkDeviceWaitIdle(device);
const auto imageCount = swapChain->getImageViews().size();
destroySwapChain();
render::UI::Unload();
for(size_t i = 0; i < renderFinishedSemaphores.size(); i++) {
vkDestroyFence(device, inFlightFences[i], ALLOC);
@ -111,6 +113,8 @@ void Renderer::recreateSwapChain() {
swapChain = std::make_unique<SwapChain>(device, getInfos());
pipeline = std::make_unique<Pipeline>(device, getInfos(), options);
commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().device, getInfos().swapDetails.capabilities.currentExtent);
dynamic_cast<UI*>(UI::Get())->setImageCount(swapChain->getImageViews().size());
}
void Renderer::destroySwapChain() {
commandCenter->free();
@ -333,6 +337,12 @@ bool Renderer::Load(Window& window, const renderOptions& opt, int samples) {
if (infos.features.samplerAnisotropy)
score += 1000;
if (infos.features.sampleRateShading)
score += 1500;
if (infos.features.fillModeNonSolid)
score += 100;
//TODO: check others limits
if (!infos.queueIndices.isComplete())
@ -377,6 +387,7 @@ bool Renderer::Load(Window& window, const renderOptions& opt, int samples) {
deviceFeatures.geometryShader = physicalInfo.features.geometryShader;
deviceFeatures.samplerAnisotropy = physicalInfo.features.samplerAnisotropy;
deviceFeatures.sampleRateShading = physicalInfo.features.sampleRateShading;
deviceFeatures.fillModeNonSolid = physicalInfo.features.fillModeNonSolid;
std::vector<const char*> extensions(requiredExtensions);
extensions.insert(extensions.end(), physicalInfo.optionalExtensions.begin(), physicalInfo.optionalExtensions.end());
@ -404,6 +415,12 @@ bool Renderer::Load(Window& window, const renderOptions& opt, int samples) {
LodModel::MakeDefault();
return true;
}
Renderer::UICtx Renderer::getUICtx() const {
auto queueFamily = physicalInfo->queueIndices.graphicsFamily.value();
VkQueue queue;
vkGetDeviceQueue(device, queueFamily, 0, &queue);
return {instance, physicalInfo->device, device, queueFamily, queue, (uint32_t)swapChain->getImageViews().size(), pipeline->getUIRenderPass()};
}
void Renderer::loadUI(Window& w) {
UI::Load(w);
@ -411,6 +428,7 @@ void Renderer::loadUI(Window& w) {
void Renderer::beginFrame() {
assert(currentImage == UINT32_MAX);
ZoneScopedN("VkWaitForFrame");
if (auto newImage = swapChain->acquireNextImage(imageAvailableSemaphores[currentFrame], inFlightFences[currentFrame])) {
currentImage = newImage.value();
@ -467,7 +485,10 @@ std::function<size_t(glm::mat4)> Renderer::beginIndicatorPass() {
void Renderer::postProcess() {
commandCenter->recordPostprocess(currentImage, pipeline->getSkyPass(), options.skybox);
}
void Renderer::recordUI(std::function<void(VkCommandBuffer)> call) {
return commandCenter->recordUI(currentImage, pipeline->getUIRenderPass(),
getInfos().swapDetails.capabilities.currentExtent, call);
}
void Renderer::endFrame() {
commandCenter->submitGraphics(currentImage, imageAvailableSemaphores[currentFrame],
renderFinishedSemaphores[currentFrame], inFlightFences[currentFrame]);
@ -485,13 +506,20 @@ void Renderer::swapBuffer(Window&) {
vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
}
void Renderer::reloadShaders(const passOptions&) {
/*WorldPass = std::make_unique<pass::WorldProgram>(options);
EntityPass = std::make_unique<pass::EntityProgram>(options);*/
void Renderer::reloadShaders(const passOptions& opt) {
options.voxel = opt;
recreateSwapChain();
}
void Renderer::reloadTextures(const std::string&, float, float) {
/*unloadTextures();
loadTextures(texturePath, mipMapLOD, anisotropy);*/
void Renderer::reloadTextures(const std::string& textures, float mipmap, float anisotropy) {
vkDeviceWaitIdle(device);
commandCenter->free();
commandCenter->loadAtlases(textures, anisotropy, mipmap);
commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().device,
getInfos().swapDetails.capabilities.currentExtent);
}
void Renderer::setFillMode(bool wireframe) {
options.wireframe = wireframe;
recreateSwapChain();
}
void Renderer::lookFrom(const Camera& camera) {

View File

@ -24,6 +24,7 @@ public:
std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> beginEntityPass() override;
std::function<size_t(glm::mat4)> beginIndicatorPass() override;
void postProcess() override;
void recordUI(std::function<void(VkCommandBuffer)>);
void endFrame() override;
void swapBuffer(Window &) override;
@ -33,8 +34,19 @@ public:
void lookFrom(const Camera &) override;
void reloadShaders(const passOptions &) override;
void reloadTextures(const std::string &, float mipMapLOD, float anisotropy) override;
void setFillMode(bool wireframe) override;
Allocator* getAllocator() const { return allocator.get(); }
struct UICtx {
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkDevice device;
uint32_t queueFamily;
VkQueue queue;
uint32_t imageCount;
VkRenderPass renderPass;
};
UICtx getUICtx() const;
void setResized() { framebufferResized = true; }

View File

@ -1,28 +1,103 @@
#include "UI.hpp"
#include "../../Window.hpp"
#include <GL/gl3w.h>
#include "Renderer.hpp"
#include "Allocator.hpp"
#include <imgui_impl_glfw.h>
#include <imgui_impl_vulkan.h>
#include "../../../core/utils/logger.hpp"
using namespace render::vk;
static void imgui_check_vk_result(VkResult err) {
if (err == 0)
return;
if (err < 0) {
FATAL("VK ImGui error " << err);
} else {
LOG_W("VK ImGui error " << err);
}
}
UI::UI(GLFWwindow *window): render::UI() {
auto ctx = Renderer::Get()->getUICtx();
device = ctx.device;
{ // Descriptor pool
std::array<VkDescriptorPoolSize, 11> poolSizes{};
poolSizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLER;
poolSizes[0].descriptorCount = 1000;
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSizes[1].descriptorCount = 1000;
poolSizes[2].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
poolSizes[2].descriptorCount = 1000;
poolSizes[3].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
poolSizes[3].descriptorCount = 1000;
poolSizes[4].type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
poolSizes[4].descriptorCount = 1000;
poolSizes[5].type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
poolSizes[5].descriptorCount = 1000;
poolSizes[6].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSizes[6].descriptorCount = 1000;
poolSizes[7].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
poolSizes[7].descriptorCount = 1000;
poolSizes[8].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
poolSizes[8].descriptorCount = 1000;
poolSizes[9].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
poolSizes[9].descriptorCount = 1000;
poolSizes[10].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
poolSizes[10].descriptorCount = 1000;
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = poolSizes.size();
poolInfo.pPoolSizes = poolSizes.data();
poolInfo.maxSets = 1000 * poolSizes.size();
poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
FATAL("Failed to create UI descriptor pool!");
}
}
// Setup Platform/Renderer bindings
/*ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 130");
aim = Texture::CreatePtr("ui/Aim", false);*/
ImGui_ImplGlfw_InitForVulkan(window, true);
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = ctx.instance;
init_info.PhysicalDevice = ctx.physicalDevice;
init_info.Device = ctx.device;
init_info.QueueFamily = ctx.queueFamily;
init_info.Queue = ctx.queue;
init_info.PipelineCache = VK_NULL_HANDLE;
init_info.DescriptorPool = descriptorPool;
init_info.Allocator = nullptr;
init_info.MinImageCount = ctx.imageCount;
init_info.ImageCount = ctx.imageCount;
init_info.CheckVkResultFn = imgui_check_vk_result;
ImGui_ImplVulkan_Init(&init_info, ctx.renderPass);
Allocator::GetDefault()->transfer(ImGui_ImplVulkan_CreateFontsTexture);
aimTexture = Texture::LoadFromFile("content/textures/ui/Aim.dds", {false, false, Texture::Wrap::MIRRORED_REPEAT, 0, false});
aimHandle = (intptr_t)ImGui_ImplVulkan_AddTexture(aimTexture->getDescriptor());
}
UI::~UI() {
/*ImGui_ImplGlfw_Shutdown();
ImGui_ImplOpenGL3_Shutdown();*/
ImGui_ImplVulkan_Shutdown();
ImGui_ImplGlfw_Shutdown();
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
}
void UI::setImageCount(uint32_t count) {
ImGui_ImplVulkan_SetMinImageCount(count);
}
UI::Actions UI::draw(config::client::options &o, state::state &s, const state::reports &r) {
/*ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();*/
return UI::Actions::None; //render::UI::draw(o, s, r, aim);
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
return render::UI::draw(o, s, r, aimHandle);
}
void UI::render() {
//ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
Renderer::Get()->recordUI([](VkCommandBuffer buffer){
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), buffer);
});
}
void UI::Load(Window& w) {

View File

@ -1,6 +1,8 @@
#pragma once
#include "../UI.hpp"
#include "forward.hpp"
#include "api/Images.hpp"
struct GLFWwindow;
class Window;
@ -18,7 +20,13 @@ public:
Actions draw(config::client::options &, state::state &, const state::reports &) override;
void render() override;
void setImageCount(uint32_t);
private:
intptr_t aim;
VkDevice device;
std::unique_ptr<Texture> aimTexture;
intptr_t aimHandle;
VkDescriptorPool descriptorPool;
};
}

View File

@ -82,6 +82,7 @@ void DistantUniverse::pullNetwork(voxel_pos pos) {
switch (type) {
case server_packet_type::CAPABILITIES: {
PacketReader(packet).read(serverDistance);
emit(world::action::Move(pos));
break;
}

View File

@ -25,6 +25,8 @@ LocalUniverse::~LocalUniverse() {
void LocalUniverse::update(voxel_pos pos, float) {
const auto cur_chunk = glm::divide(pos);
const auto chunkChange = cur_chunk != last_chunk;
if (last_chunk.x == INT_MAX)
emit(world::action::Move(pos));
last_chunk = cur_chunk;
if(chunkChange) {