Format and resize callback
This commit is contained in:
parent
8b1aa63327
commit
09d92231e2
@ -10,6 +10,7 @@
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#define ACTIVE_VALIDATION_LAYER true
|
||||
#define MAX_FRAMES_IN_FLIGHT 2
|
||||
|
||||
class GLFWwindow;
|
||||
|
||||
@ -32,33 +33,34 @@ namespace deerith {
|
||||
|
||||
extern GraphicsConfig graphics_config;
|
||||
extern GLFWwindow* window;
|
||||
extern bool frame_buffer_resize;
|
||||
|
||||
// Vulkan Specific
|
||||
extern VkInstance instance;
|
||||
extern const std::vector<const char*> validation_layers;
|
||||
extern const std::vector<const char*> device_extensions;
|
||||
extern VkSurfaceKHR surface;
|
||||
extern VkPhysicalDevice physical_device;
|
||||
extern QueueFamilyIndices queue_family_indices;
|
||||
extern SwapChainSupportDetails swap_chain_support_details;
|
||||
extern const std::vector<const char*> device_extensions;
|
||||
extern VkDevice device;
|
||||
extern VkQueue graphics_queue;
|
||||
extern VkQueue pressent_queue;
|
||||
extern VkSurfaceKHR surface;
|
||||
extern VkSwapchainKHR swap_chain;
|
||||
extern std::vector<VkImage> swap_chain_images;
|
||||
extern VkFormat swap_chain_image_format;
|
||||
extern VkExtent2D swap_chain_extent;
|
||||
extern std::vector<VkImageView> swap_chain_image_views;
|
||||
extern VkPipelineLayout pipeline_layout;
|
||||
extern VkRenderPass render_pass;
|
||||
extern VkPipelineLayout pipeline_layout;
|
||||
extern VkPipeline graphics_pipeline;
|
||||
extern std::vector<VkFramebuffer> swap_chain_frame_buffers;
|
||||
extern VkCommandPool command_pool;
|
||||
extern VkCommandBuffer command_buffer;
|
||||
|
||||
extern VkSemaphore image_available_semaphore;
|
||||
extern VkSemaphore render_finished_semaphore;
|
||||
extern VkFence in_flight_fence;
|
||||
extern std::vector<VkCommandBuffer> command_buffers;
|
||||
extern std::vector<VkSemaphore> image_available_semaphores;
|
||||
extern std::vector<VkSemaphore> render_finished_semaphores;
|
||||
extern std::vector<VkFence> in_flight_fences;
|
||||
extern uint32_t current_frame;
|
||||
|
||||
void init_glfw();
|
||||
void shutdown_glfw();
|
||||
@ -69,7 +71,7 @@ namespace deerith {
|
||||
void create_vulkan_instance();
|
||||
void create_vulkan_validation_layer();
|
||||
void create_vulkan_surface();
|
||||
void create_vulkan_phisical_device();
|
||||
void pick_vulkan_phisical_device();
|
||||
void create_vulkan_logical_device();
|
||||
void create_vulkan_swap_chain();
|
||||
void create_vulkan_image_view();
|
||||
@ -79,6 +81,8 @@ namespace deerith {
|
||||
void create_vulkan_command_buffer();
|
||||
void create_vulkan_sync_objects();
|
||||
|
||||
void vulkan_clean_swap_chain();
|
||||
void vulkan_recreate_swap_chain();
|
||||
void vulkan_test_loop();
|
||||
|
||||
QueueFamilyIndices find_queue_families(VkPhysicalDevice device);
|
||||
|
||||
@ -3,15 +3,19 @@
|
||||
#include "detail/graphics.h"
|
||||
|
||||
namespace deerith {
|
||||
namespace graphics {
|
||||
void frame_buffer_resize_callback(GLFWwindow* window, int width, int height);
|
||||
}
|
||||
|
||||
void graphics::init_glfw() {
|
||||
deerith_graphics_trace("Initializing glfw");
|
||||
|
||||
glfwInit();
|
||||
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
|
||||
window = glfwCreateWindow(graphics_config.window_width, graphics_config.window_height, graphics_config.window_title, nullptr, nullptr);
|
||||
glfwSetFramebufferSizeCallback(window, frame_buffer_resize_callback);
|
||||
|
||||
if (!window) {
|
||||
deerith_graphics_error("failed to init glfw window");
|
||||
@ -24,4 +28,13 @@ namespace deerith {
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
void graphics::frame_buffer_resize_callback(GLFWwindow* window, int width, int height) {
|
||||
deerith_graphics_trace("called frame buffer resize");
|
||||
|
||||
graphics_config.window_height = height;
|
||||
graphics_config.window_width = width;
|
||||
|
||||
frame_buffer_resize = true;
|
||||
}
|
||||
} // namespace deerith
|
||||
@ -27,8 +27,10 @@ namespace deerith {
|
||||
VkPipeline graphics::graphics_pipeline;
|
||||
std::vector<VkFramebuffer> graphics::swap_chain_frame_buffers;
|
||||
VkCommandPool graphics::command_pool;
|
||||
VkCommandBuffer graphics::command_buffer;
|
||||
VkSemaphore graphics::image_available_semaphore;
|
||||
VkSemaphore graphics::render_finished_semaphore;
|
||||
VkFence graphics::in_flight_fence;
|
||||
std::vector<VkCommandBuffer> graphics::command_buffers;
|
||||
std::vector<VkSemaphore> graphics::image_available_semaphores;
|
||||
std::vector<VkSemaphore> graphics::render_finished_semaphores;
|
||||
std::vector<VkFence> graphics::in_flight_fences;
|
||||
uint32_t graphics::current_frame = 0;
|
||||
bool graphics::frame_buffer_resize = false;
|
||||
} // namespace deerith
|
||||
@ -7,7 +7,7 @@ namespace deerith {
|
||||
create_vulkan_validation_layer();
|
||||
create_vulkan_instance();
|
||||
create_vulkan_surface();
|
||||
create_vulkan_phisical_device();
|
||||
pick_vulkan_phisical_device();
|
||||
create_vulkan_logical_device();
|
||||
create_vulkan_swap_chain();
|
||||
create_vulkan_image_view();
|
||||
@ -20,25 +20,48 @@ namespace deerith {
|
||||
}
|
||||
|
||||
void graphics::shutdown_vulkan() {
|
||||
deerith_graphics_trace("Shutting Vulkan");
|
||||
|
||||
deerith_graphics_trace("Waiting for Vulkan device to finish");
|
||||
vkDeviceWaitIdle(device);
|
||||
vkDestroyCommandPool(device, command_pool, nullptr);
|
||||
for (auto framebuffer : swap_chain_frame_buffers) {
|
||||
vkDestroyFramebuffer(device, framebuffer, nullptr);
|
||||
|
||||
deerith_graphics_trace("Shutting Vulkan");
|
||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
vkDestroySemaphore(device, render_finished_semaphores[i], nullptr);
|
||||
vkDestroySemaphore(device, image_available_semaphores[i], nullptr);
|
||||
vkDestroyFence(device, in_flight_fences[i], nullptr);
|
||||
}
|
||||
|
||||
vkDestroyCommandPool(device, command_pool, nullptr);
|
||||
|
||||
vulkan_clean_swap_chain();
|
||||
|
||||
vkDestroyPipeline(device, graphics_pipeline, nullptr);
|
||||
vkDestroyRenderPass(device, render_pass, nullptr);
|
||||
vkDestroyPipelineLayout(device, pipeline_layout, nullptr);
|
||||
|
||||
for (auto image_view : swap_chain_image_views) {
|
||||
vkDestroyImageView(device, image_view, nullptr);
|
||||
}
|
||||
|
||||
vkDestroySwapchainKHR(device, swap_chain, nullptr);
|
||||
vkDestroySurfaceKHR(instance, surface, nullptr);
|
||||
vkDestroyDevice(device, nullptr);
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
}
|
||||
|
||||
void graphics::vulkan_clean_swap_chain() {
|
||||
for (auto framebuffer : swap_chain_frame_buffers) {
|
||||
vkDestroyFramebuffer(device, framebuffer, nullptr);
|
||||
}
|
||||
|
||||
for (auto imageView : swap_chain_image_views) {
|
||||
vkDestroyImageView(device, imageView, nullptr);
|
||||
}
|
||||
|
||||
vkDestroySwapchainKHR(device, swap_chain, nullptr);
|
||||
}
|
||||
|
||||
void graphics::vulkan_recreate_swap_chain() {
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
vulkan_clean_swap_chain();
|
||||
|
||||
create_vulkan_swap_chain();
|
||||
create_vulkan_image_view();
|
||||
create_vulkan_frame_buffer();
|
||||
}
|
||||
} // namespace deerith
|
||||
@ -17,7 +17,7 @@ namespace deerith {
|
||||
frame_buffer_info.layers = 1;
|
||||
|
||||
if (vkCreateFramebuffer(device, &frame_buffer_info, nullptr, &swap_chain_frame_buffers[i]) != VK_SUCCESS) {
|
||||
deerith_graphics_error("failed to create framebuffer!");
|
||||
deerith_graphics_error("failed to create frame_buffer!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,19 +8,19 @@ namespace deerith {
|
||||
bool check_device_extension_support(VkPhysicalDevice device);
|
||||
} // namespace graphics
|
||||
|
||||
void graphics::create_vulkan_phisical_device() {
|
||||
deerith_graphics_trace("Initializing Vulkan phisical device");
|
||||
void graphics::pick_vulkan_phisical_device() {
|
||||
deerith_graphics_trace("Choosing Vulkan phisical device");
|
||||
|
||||
uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
||||
uint32_t device_count = 0;
|
||||
vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
|
||||
|
||||
if (deviceCount == 0) {
|
||||
if (device_count == 0) {
|
||||
deerith_graphics_error("failed to find GPUs with Vulkan support!");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
||||
std::vector<VkPhysicalDevice> devices(device_count);
|
||||
vkEnumeratePhysicalDevices(instance, &device_count, devices.data());
|
||||
|
||||
for (const auto& device : devices) {
|
||||
if (is_device_suitable(device)) {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
namespace deerith {
|
||||
void graphics::create_vulkan_surface() {
|
||||
deerith_graphics_trace("Initializing Vulkan pressentation/surface");
|
||||
deerith_graphics_trace("Initializing Vulkan surface");
|
||||
|
||||
if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
|
||||
deerith_graphics_error("failed to create window surface!");
|
||||
|
||||
@ -13,13 +13,15 @@ namespace deerith {
|
||||
deerith_graphics_error("failed to create command pool!");
|
||||
}
|
||||
|
||||
command_buffers.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
VkCommandBufferAllocateInfo alloc_info{};
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
alloc_info.commandPool = command_pool;
|
||||
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
alloc_info.commandBufferCount = 1;
|
||||
alloc_info.commandBufferCount = MAX_FRAMES_IN_FLIGHT;
|
||||
|
||||
if (vkAllocateCommandBuffers(device, &alloc_info, &command_buffer) != VK_SUCCESS) {
|
||||
if (vkAllocateCommandBuffers(device, &alloc_info, command_buffers.data()) != VK_SUCCESS) {
|
||||
deerith_graphics_error("failed to allocate command buffers!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,22 +15,22 @@ namespace deerith {
|
||||
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VkAttachmentReference color_attachmentRef{};
|
||||
color_attachmentRef.attachment = 0;
|
||||
color_attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
VkAttachmentReference color_attachment_ref{};
|
||||
color_attachment_ref.attachment = 0;
|
||||
color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass{};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
VkSubpassDescription sub_pass{};
|
||||
sub_pass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &color_attachmentRef;
|
||||
sub_pass.colorAttachmentCount = 1;
|
||||
sub_pass.pColorAttachments = &color_attachment_ref;
|
||||
|
||||
VkRenderPassCreateInfo render_pass_info{};
|
||||
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
render_pass_info.attachmentCount = 1;
|
||||
render_pass_info.pAttachments = &color_attachment;
|
||||
render_pass_info.subpassCount = 1;
|
||||
render_pass_info.pSubpasses = &subpass;
|
||||
render_pass_info.pSubpasses = &sub_pass;
|
||||
|
||||
if (vkCreateRenderPass(device, &render_pass_info, nullptr, &render_pass) != VK_SUCCESS) {
|
||||
deerith_graphics_error("failed to create render pass!");
|
||||
|
||||
@ -13,6 +13,10 @@ namespace deerith {
|
||||
}
|
||||
|
||||
void graphics::create_vulkan_sync_objects() {
|
||||
image_available_semaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
render_finished_semaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
in_flight_fences.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
VkSemaphoreCreateInfo semaphoreInfo{};
|
||||
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
@ -20,41 +24,52 @@ namespace deerith {
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &image_available_semaphore) != VK_SUCCESS ||
|
||||
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &render_finished_semaphore) != VK_SUCCESS ||
|
||||
vkCreateFence(device, &fenceInfo, nullptr, &in_flight_fence) != VK_SUCCESS) {
|
||||
deerith_graphics_error("failed to create semaphores!");
|
||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &image_available_semaphores[i]) != VK_SUCCESS ||
|
||||
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &render_finished_semaphores[i]) != VK_SUCCESS ||
|
||||
vkCreateFence(device, &fenceInfo, nullptr, &in_flight_fences[i]) != VK_SUCCESS) {
|
||||
|
||||
deerith_graphics_error("failed to create synchronization objects for a frame!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void graphics::drawFrame() {
|
||||
vkWaitForFences(device, 1, &in_flight_fence, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(device, 1, &in_flight_fence);
|
||||
vkWaitForFences(device, 1, &in_flight_fences[current_frame], VK_TRUE, UINT64_MAX);
|
||||
|
||||
uint32_t image_index;
|
||||
vkAcquireNextImageKHR(device, swap_chain, UINT64_MAX, image_available_semaphore, VK_NULL_HANDLE, &image_index);
|
||||
VkResult result = vkAcquireNextImageKHR(device, swap_chain, UINT64_MAX, image_available_semaphores[current_frame], VK_NULL_HANDLE, &image_index);
|
||||
|
||||
vkResetCommandBuffer(command_buffer, 0);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
frame_buffer_resize = false;
|
||||
vulkan_recreate_swap_chain();
|
||||
return;
|
||||
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
|
||||
deerith_graphics_error("failed to acquire swap chain image!");
|
||||
}
|
||||
|
||||
record_command_buffer(command_buffer, image_index);
|
||||
vkResetFences(device, 1, &in_flight_fences[current_frame]);
|
||||
|
||||
vkResetCommandBuffer(command_buffers[current_frame], 0);
|
||||
record_command_buffer(command_buffers[current_frame], image_index);
|
||||
|
||||
VkSubmitInfo submit_info{};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
|
||||
VkSemaphore waitSemaphores[] = {image_available_semaphore};
|
||||
VkSemaphore waitSemaphores[] = {image_available_semaphores[current_frame]};
|
||||
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||
submit_info.waitSemaphoreCount = 1;
|
||||
submit_info.pWaitSemaphores = waitSemaphores;
|
||||
submit_info.pWaitDstStageMask = waitStages;
|
||||
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &command_buffer;
|
||||
submit_info.pCommandBuffers = &command_buffers[current_frame];
|
||||
|
||||
VkSemaphore signalSemaphores[] = {render_finished_semaphore};
|
||||
VkSemaphore signalSemaphores[] = {render_finished_semaphores[current_frame]};
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = signalSemaphores;
|
||||
|
||||
if (vkQueueSubmit(graphics_queue, 1, &submit_info, in_flight_fence) != VK_SUCCESS) {
|
||||
if (vkQueueSubmit(graphics_queue, 1, &submit_info, in_flight_fences[current_frame]) != VK_SUCCESS) {
|
||||
deerith_graphics_error("failed to submit draw command buffer!");
|
||||
}
|
||||
|
||||
@ -78,8 +93,17 @@ namespace deerith {
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = swapChains;
|
||||
presentInfo.pImageIndices = &image_index;
|
||||
presentInfo.pResults = nullptr; // Optional
|
||||
presentInfo.pResults = nullptr;
|
||||
|
||||
vkQueuePresentKHR(pressent_queue, &presentInfo);
|
||||
result = vkQueuePresentKHR(pressent_queue, &presentInfo);
|
||||
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || frame_buffer_resize) {
|
||||
vulkan_recreate_swap_chain();
|
||||
frame_buffer_resize = false;
|
||||
} else if (result != VK_SUCCESS) {
|
||||
deerith_graphics_error("failed to present swap chain image!");
|
||||
}
|
||||
|
||||
current_frame = (current_frame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
}
|
||||
} // namespace deerith
|
||||
@ -15,10 +15,10 @@ namespace deerith {
|
||||
SwapChainSupportDetails swap_chain_support = query_swap_chain_support(physical_device);
|
||||
|
||||
VkSurfaceFormatKHR surface_format = choose_swap_surface_format(swap_chain_support.formats);
|
||||
VkPresentModeKHR presentMode = choose_swap_present_mode(swap_chain_support.present_modes);
|
||||
VkPresentModeKHR present_mode = choose_swap_present_mode(swap_chain_support.present_modes);
|
||||
VkExtent2D extent = choose_swap_extent(swap_chain_support.capabilities);
|
||||
|
||||
uint32_t image_count = swap_chain_support.capabilities.minImageCount;
|
||||
uint32_t image_count = swap_chain_support.capabilities.minImageCount + 1;
|
||||
if (swap_chain_support.capabilities.maxImageCount > 0 && image_count > swap_chain_support.capabilities.maxImageCount) {
|
||||
image_count = swap_chain_support.capabilities.maxImageCount;
|
||||
}
|
||||
@ -48,7 +48,7 @@ namespace deerith {
|
||||
|
||||
create_info.preTransform = swap_chain_support.capabilities.currentTransform;
|
||||
create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
create_info.presentMode = presentMode;
|
||||
create_info.presentMode = present_mode;
|
||||
create_info.clipped = VK_TRUE;
|
||||
create_info.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@ int main() {
|
||||
graphics_config.window_title = "Deerith Studio";
|
||||
|
||||
deerith::graphics::init(graphics_config);
|
||||
|
||||
deerith::graphics::shutdown();
|
||||
|
||||
deerith::engine::shutdown();
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user