From 2d47bc8f27f3f2088bc9e985203e23fc6a5f513f Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sun, 2 Sep 2018 17:35:41 -0400 Subject: [PATCH 01/30] Delete IDE files and fix compiling --- .idea/engine.iml | 2 -- .idea/misc.xml | 4 ---- .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ CMakeLists.txt | 2 +- src/engine/main.c | 2 ++ 6 files changed, 3 insertions(+), 21 deletions(-) delete mode 100644 .idea/engine.iml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/engine.iml b/.idea/engine.iml deleted file mode 100644 index f08604b..0000000 --- a/.idea/engine.iml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 79b3c94..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 4de3850..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 996d53a..0fcb96c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,7 +68,7 @@ add_executable(engine ${SOURCE_FILES}) add_dependencies(engine localduktape localglad) # GL, GLFW, DL, M -target_link_libraries(engine dl m glfw GL) +target_link_libraries(engine dl m glfw GL vulkan) # STANDARDS set_property(TARGET engine PROPERTY C_STANDARD 99) diff --git a/src/engine/main.c b/src/engine/main.c index a92ceb5..cc12593 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -1,4 +1,6 @@ +#define GLFW_INCLUDE_VULKAN + #include "lib/glad/glad.h" #include #include "src/engine/scripting/callbacks.h" From ab52063ae283283e4f6611ba239aa010f1782728 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sun, 2 Sep 2018 17:36:30 -0400 Subject: [PATCH 02/30] Add gitignore file to project --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f9e3f1c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea +cmake-build-debug/ +lib/duktape/ +lib/glad/ + From 7d2d03bc7d055e41965ccd094fc2a1e1acd694cb Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sun, 2 Sep 2018 19:52:36 -0400 Subject: [PATCH 03/30] Begin loading vulkan components and modules --- CMakeLists.txt | 2 +- src/engine/graphics/vulkan.c | 56 ++++++++++++++++++++++++++++++++++++ src/engine/graphics/vulkan.h | 27 +++++++++++++++++ src/engine/main.c | 55 +++++++++++++++++------------------ 4 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 src/engine/graphics/vulkan.c create mode 100644 src/engine/graphics/vulkan.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fcb96c..1cfe8d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,7 @@ set(SOURCE_FILES src/engine/graphics/shader.c src/engine/graphics/shader.h src/engine/graphics/texture.c src/engine/graphics/texture.h lib/stb/stb_image.h src/engine/graphics/style.c src/engine/graphics/style.h - lib/linmath/linmath.h src/engine/scripting/callbacks.c src/engine/scripting/callbacks.h src/engine/graphics/screen.c src/engine/graphics/screen.h) + lib/linmath/linmath.h src/engine/scripting/callbacks.c src/engine/scripting/callbacks.h src/engine/graphics/screen.c src/engine/graphics/screen.h src/engine/graphics/vulkan.c src/engine/graphics/vulkan.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan.c b/src/engine/graphics/vulkan.c new file mode 100644 index 0000000..a4caba6 --- /dev/null +++ b/src/engine/graphics/vulkan.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include "vulkan.h" + +glfw_state glfw; +vulkan_state vulkan; + +/* + * Provide vulkan with some context for our application + */ +VkApplicationInfo definition = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "Solid Snake", + .applicationVersion = VK_MAKE_VERSION(0, 0, 1), + .pEngineName = "Solid Engine", + .engineVersion = VK_MAKE_VERSION(0, 0, 1), + .apiVersion = VK_API_VERSION_1_0 +}; + + +VkResult create_vulkan_application_interface() { + VkInstanceCreateInfo creation_request = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &definition + }; + creation_request.enabledExtensionCount = glfw.num_extensions; + creation_request.ppEnabledExtensionNames = glfw.extensions; + creation_request.enabledLayerCount = 0; + + return vkCreateInstance(&creation_request, NULL, &vulkan.instance); +} + +void init_glfw() { + glfw.extensions = glfwGetRequiredInstanceExtensions(&glfw.num_extensions); +} + +bool init_vulkan() { + init_glfw(); + + // Load properties + if (vkEnumerateInstanceExtensionProperties(NULL, &vulkan.num_properties, vulkan.properties) != VK_SUCCESS) { + printf("Failed to get extension properties\n"); + return false; + } + + if (create_vulkan_application_interface() != VK_SUCCESS) { + printf("Failed to initialize vulkan instance\n"); + return false; + } + + printf("Vulkan Initialized"); + printf("Loaded Vulkan Extensions: %u\n", vulkan.num_properties); + + return true; +} diff --git a/src/engine/graphics/vulkan.h b/src/engine/graphics/vulkan.h new file mode 100644 index 0000000..03ee012 --- /dev/null +++ b/src/engine/graphics/vulkan.h @@ -0,0 +1,27 @@ + +#ifndef ENGINE_VULKAN_H +#define ENGINE_VULKAN_H + +#include +#include + +typedef struct { + uint32_t num_extensions; + const char **extensions; +} glfw_state; + +typedef struct { + VkExtensionProperties *properties; + uint32_t num_properties; + + VkInstance instance; +} vulkan_state; + + +/** + * Initialize Vulkan + * @return + */ +bool init_vulkan(); + +#endif diff --git a/src/engine/main.c b/src/engine/main.c index cc12593..430d518 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -3,24 +3,25 @@ #include "lib/glad/glad.h" #include +#include "src/engine/graphics/vulkan.h" #include "src/engine/scripting/callbacks.h" #include "src/engine/scripting/script.h" #define SCREEN_W 400 #define SCREEN_H 400 -void update() -{ - static double start = 0; + + +void update() { + static double start = 0; const double current_time = glfwGetTime(); - const double delta = current_time - start; + const double delta = current_time - start; start = current_time; game.update(delta); } -void draw() -{ +void draw() { glClear(GL_COLOR_BUFFER_BIT); { game.draw(); @@ -29,8 +30,7 @@ void draw() } -void init() -{ +void init() { if (!init_interface()) { printf("Failed to load scripting context\n"); exit(1); @@ -48,45 +48,44 @@ void init() int main() { - glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - GLFWwindow* window = glfwCreateWindow(SCREEN_W, SCREEN_H, "Solid Engine", NULL, NULL); + // Disable loading OpenGL and use GLFW for loading APIs + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - if (!window) - { + GLFWwindow *window = glfwCreateWindow(SCREEN_W, SCREEN_H, "Solid Engine", NULL, NULL); + + if (!window) { printf("Failed to create window!\n"); glfwTerminate(); return 1; } + glfwMakeContextCurrent(window); - if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) - { - printf("Failed to load open GL api\n"); + + if (!init_vulkan()) { + printf("Failed to initialize graphics layer\n"); return 1; } + //init(); // Init our code. - // Screen is black - glClearColor(0.0, 0.0, 0.0, 0.0); - - init(); // Init our code. + //REGISTER_GLFW_CALLBACKS(); - REGISTER_GLFW_CALLBACKS(); - while (!glfwWindowShouldClose(window)) - { - update(); - draw(); + while (!glfwWindowShouldClose(window)) { + //update(); + //draw(); - glfwSwapBuffers(window); + //glfwSwapBuffers(window); glfwPollEvents(); } + + glfwDestroyWindow(window); + glfwTerminate(); return 0; From 6502622e1d1930733bfe175f200abb107c5af6a6 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sun, 2 Sep 2018 20:30:42 -0400 Subject: [PATCH 04/30] Enable validation layers and print errors if the layers are not enabled --- src/engine/graphics/vulkan.c | 58 +++++++++++++++++++++++++++++++++--- src/engine/graphics/vulkan.h | 5 ++++ src/engine/main.c | 2 ++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/engine/graphics/vulkan.c b/src/engine/graphics/vulkan.c index a4caba6..6d12525 100644 --- a/src/engine/graphics/vulkan.c +++ b/src/engine/graphics/vulkan.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include "vulkan.h" glfw_state glfw; @@ -18,6 +20,33 @@ VkApplicationInfo definition = { .apiVersion = VK_API_VERSION_1_0 }; +#define NUM_WANTED_VALIDATION_LAYERS ((uint32_t) 2) +const char *wanted_validation_layers[NUM_WANTED_VALIDATION_LAYERS] = { + "VK_LAYER_LUNARG_core_validation", + "VK_LAYER_LUNARG_standard_validation" + +}; + +/** + * Check to make sure all of our desired validation layers can be provided by vulkan + * @return + */ +bool has_all_wanted_validation_layers() +{ + for (uint32_t wanted_layer_index = 0; wanted_layer_index < NUM_WANTED_VALIDATION_LAYERS; wanted_layer_index++) { + bool found = false; + + for (uint32_t existing_layer_index = 0; !found && existing_layer_index < vulkan.num_layer_properties; existing_layer_index++) { + found = strcmp(wanted_validation_layers[wanted_layer_index], vulkan.layer_properties[existing_layer_index].layerName) == 0; + } + + if (!found) { + return false; + } + } + + return true; +} VkResult create_vulkan_application_interface() { VkInstanceCreateInfo creation_request = { @@ -26,7 +55,8 @@ VkResult create_vulkan_application_interface() { }; creation_request.enabledExtensionCount = glfw.num_extensions; creation_request.ppEnabledExtensionNames = glfw.extensions; - creation_request.enabledLayerCount = 0; + creation_request.ppEnabledLayerNames = wanted_validation_layers; + creation_request.enabledLayerCount = NUM_WANTED_VALIDATION_LAYERS; return vkCreateInstance(&creation_request, NULL, &vulkan.instance); } @@ -38,19 +68,39 @@ void init_glfw() { bool init_vulkan() { init_glfw(); - // Load properties - if (vkEnumerateInstanceExtensionProperties(NULL, &vulkan.num_properties, vulkan.properties) != VK_SUCCESS) { + if (vkEnumerateInstanceExtensionProperties(NULL, &vulkan.num_properties, vulkan.properties) != VK_SUCCESS) { printf("Failed to get extension properties\n"); return false; } + vkEnumerateInstanceLayerProperties(&vulkan.num_layer_properties, NULL); + vulkan.layer_properties = malloc(sizeof(VkLayerProperties) * vulkan.num_layer_properties); + if (vkEnumerateInstanceLayerProperties(&vulkan.num_layer_properties, vulkan.layer_properties) != VK_SUCCESS) { + printf("Failed to get extension properties\n"); + return false; + } + + if (!has_all_wanted_validation_layers()) { + printf("Vulkan does not provide all requested validation layers!\n"); + return false; + } + if (create_vulkan_application_interface() != VK_SUCCESS) { printf("Failed to initialize vulkan instance\n"); return false; } - printf("Vulkan Initialized"); + printf("Vulkan Initialized\n"); printf("Loaded Vulkan Extensions: %u\n", vulkan.num_properties); + printf("Loaded Vulkan Instance Layers: %u\n", vulkan.num_layer_properties); + + for (uint32_t i = 0; i < vulkan.num_layer_properties; i++) { + printf("\t%d - %s (%d)\n", i, vulkan.layer_properties[i].layerName, vulkan.layer_properties[i].specVersion); + } return true; } + +void cleanup_vulkan() { + vkDestroyInstance(vulkan.instance, NULL); +} diff --git a/src/engine/graphics/vulkan.h b/src/engine/graphics/vulkan.h index 03ee012..7da0c40 100644 --- a/src/engine/graphics/vulkan.h +++ b/src/engine/graphics/vulkan.h @@ -14,6 +14,9 @@ typedef struct { VkExtensionProperties *properties; uint32_t num_properties; + VkLayerProperties *layer_properties; + uint32_t num_layer_properties; + VkInstance instance; } vulkan_state; @@ -24,4 +27,6 @@ typedef struct { */ bool init_vulkan(); +void cleanup_vulkan(); + #endif diff --git a/src/engine/main.c b/src/engine/main.c index 430d518..45a37be 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -84,6 +84,8 @@ int main() { glfwPollEvents(); } + cleanup_vulkan(); + glfwDestroyWindow(window); glfwTerminate(); From b83ebd62bd30fe8743c519ba44598a7fd140d5f3 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Mon, 3 Sep 2018 09:56:10 -0400 Subject: [PATCH 05/30] Create and teardown vulkan debugging objects --- CMakeLists.txt | 5 +- src/engine/graphics/vulkan.c | 67 +++++++++++++++++-- src/engine/graphics/vulkan.h | 4 ++ .../graphics/wrappers/vulkan_debugging.h | 52 ++++++++++++++ 4 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 src/engine/graphics/wrappers/vulkan_debugging.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cfe8d0..33bdbc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,10 @@ set(SOURCE_FILES src/engine/graphics/shader.c src/engine/graphics/shader.h src/engine/graphics/texture.c src/engine/graphics/texture.h lib/stb/stb_image.h src/engine/graphics/style.c src/engine/graphics/style.h - lib/linmath/linmath.h src/engine/scripting/callbacks.c src/engine/scripting/callbacks.h src/engine/graphics/screen.c src/engine/graphics/screen.h src/engine/graphics/vulkan.c src/engine/graphics/vulkan.h) + lib/linmath/linmath.h + src/engine/scripting/callbacks.c src/engine/scripting/callbacks.h + src/engine/graphics/screen.c src/engine/graphics/screen.h + src/engine/graphics/vulkan.c src/engine/graphics/vulkan.h src/engine/graphics/wrappers/vulkan_debugging.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan.c b/src/engine/graphics/vulkan.c index 6d12525..b017366 100644 --- a/src/engine/graphics/vulkan.c +++ b/src/engine/graphics/vulkan.c @@ -4,6 +4,7 @@ #include #include #include "vulkan.h" +#include "wrappers/vulkan_debugging.h" glfw_state glfw; vulkan_state vulkan; @@ -27,17 +28,57 @@ const char *wanted_validation_layers[NUM_WANTED_VALIDATION_LAYERS] = { }; + +static VKAPI_ATTR VkBool32 VKAPI_CALL on_vulkan_validation_failure( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT *data, + void *user_date +) { + // Ignore lack of usage + ((void) severity); + ((void) type); + ((void) data); + ((void) user_date); + + printf("validation layer: %s\n", data->pMessage); + + return VK_FALSE; +} + +void init_debug_callback() { + VkDebugUtilsMessengerCreateInfoEXT creation_request = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = on_vulkan_validation_failure, + .pUserData = NULL // Optional + }; + + wrap_vulkan_create_debug_utils_messenger_ext( + vulkan.instance, + &creation_request, + NULL, + &vulkan.debug_utils_messenger_callback + ); +} + + /** * Check to make sure all of our desired validation layers can be provided by vulkan * @return */ -bool has_all_wanted_validation_layers() -{ +bool has_all_wanted_validation_layers() { for (uint32_t wanted_layer_index = 0; wanted_layer_index < NUM_WANTED_VALIDATION_LAYERS; wanted_layer_index++) { bool found = false; - for (uint32_t existing_layer_index = 0; !found && existing_layer_index < vulkan.num_layer_properties; existing_layer_index++) { - found = strcmp(wanted_validation_layers[wanted_layer_index], vulkan.layer_properties[existing_layer_index].layerName) == 0; + // Search array of available layers + for (uint32_t i = 0; !found && i < vulkan.num_layer_properties; i++) { + found = strcmp(wanted_validation_layers[wanted_layer_index], vulkan.layer_properties[i].layerName) == 0; } if (!found) { @@ -55,9 +96,12 @@ VkResult create_vulkan_application_interface() { }; creation_request.enabledExtensionCount = glfw.num_extensions; creation_request.ppEnabledExtensionNames = glfw.extensions; + creation_request.ppEnabledLayerNames = wanted_validation_layers; creation_request.enabledLayerCount = NUM_WANTED_VALIDATION_LAYERS; + creation_request.ppEnabledExtensionNames = vulkan.required_extensions; + creation_request.enabledExtensionCount = vulkan.num_required_extensions; return vkCreateInstance(&creation_request, NULL, &vulkan.instance); } @@ -65,6 +109,15 @@ void init_glfw() { glfw.extensions = glfwGetRequiredInstanceExtensions(&glfw.num_extensions); } +void init_list_of_required_extensions() { + vulkan.num_required_extensions = glfw.num_extensions + 1; + vulkan.required_extensions = malloc(sizeof(char *) * vulkan.num_required_extensions); + for (size_t i = 0; i < vulkan.num_required_extensions - 1; i++) { + vulkan.required_extensions[i] = glfw.extensions[i]; + } + vulkan.required_extensions[vulkan.num_required_extensions - 1] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; +} + bool init_vulkan() { init_glfw(); @@ -85,16 +138,19 @@ bool init_vulkan() { return false; } + init_list_of_required_extensions(); + if (create_vulkan_application_interface() != VK_SUCCESS) { printf("Failed to initialize vulkan instance\n"); return false; } + init_debug_callback(); + printf("Vulkan Initialized\n"); printf("Loaded Vulkan Extensions: %u\n", vulkan.num_properties); printf("Loaded Vulkan Instance Layers: %u\n", vulkan.num_layer_properties); - for (uint32_t i = 0; i < vulkan.num_layer_properties; i++) { printf("\t%d - %s (%d)\n", i, vulkan.layer_properties[i].layerName, vulkan.layer_properties[i].specVersion); } @@ -102,5 +158,6 @@ bool init_vulkan() { } void cleanup_vulkan() { + wrap_vulkan_destroy_debug_utils_messenger_ext(vulkan.instance, vulkan.debug_utils_messenger_callback, NULL); vkDestroyInstance(vulkan.instance, NULL); } diff --git a/src/engine/graphics/vulkan.h b/src/engine/graphics/vulkan.h index 7da0c40..80af657 100644 --- a/src/engine/graphics/vulkan.h +++ b/src/engine/graphics/vulkan.h @@ -18,6 +18,10 @@ typedef struct { uint32_t num_layer_properties; VkInstance instance; + VkDebugUtilsMessengerEXT debug_utils_messenger_callback; + + const char ** required_extensions; + uint32_t num_required_extensions; } vulkan_state; diff --git a/src/engine/graphics/wrappers/vulkan_debugging.h b/src/engine/graphics/wrappers/vulkan_debugging.h new file mode 100644 index 0000000..dbd3358 --- /dev/null +++ b/src/engine/graphics/wrappers/vulkan_debugging.h @@ -0,0 +1,52 @@ +#ifndef ENGINE_VULKAN_DEBUGGING_H +#define ENGINE_VULKAN_DEBUGGING_H + +#include + +/** + * Wrapper for vkCreateDebugUtilsMessengerEXT extension function + * @param instance + * @param pCreateInfo + * @param pAllocator + * @param pCallback + * @return + */ +static inline VkResult wrap_vulkan_create_debug_utils_messenger_ext( + VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugUtilsMessengerEXT *pCallback +) { + const PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr( + instance, + "vkCreateDebugUtilsMessengerEXT" + ); + if (func != NULL) { + return func(instance, pCreateInfo, pAllocator, pCallback); + } else { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } +} + +/** + * Wrapper around vkDestroyDebugUtilsMessengerEXT + * @param instance + * @param callback + * @param pAllocator + */ +static inline void wrap_vulkan_destroy_debug_utils_messenger_ext( + VkInstance instance, + VkDebugUtilsMessengerEXT callback, + const VkAllocationCallbacks *pAllocator +) { + PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr( + instance, + "vkDestroyDebugUtilsMessengerEXT" + ); + if (func != NULL) { + func(instance, callback, pAllocator); + } +} + + +#endif From feb9fb00e999ee1066db29fca4f822eea8e70a57 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Mon, 3 Sep 2018 10:07:07 -0400 Subject: [PATCH 06/30] Find a device to use. --- src/engine/graphics/vulkan.c | 52 +++++++++++++++++++++++++++++++++--- src/engine/graphics/vulkan.h | 2 ++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/engine/graphics/vulkan.c b/src/engine/graphics/vulkan.c index b017366..df2d0be 100644 --- a/src/engine/graphics/vulkan.c +++ b/src/engine/graphics/vulkan.c @@ -7,7 +7,9 @@ #include "wrappers/vulkan_debugging.h" glfw_state glfw; -vulkan_state vulkan; +vulkan_state vulkan = { + .physicalDevice = VK_NULL_HANDLE +}; /* * Provide vulkan with some context for our application @@ -105,9 +107,6 @@ VkResult create_vulkan_application_interface() { return vkCreateInstance(&creation_request, NULL, &vulkan.instance); } -void init_glfw() { - glfw.extensions = glfwGetRequiredInstanceExtensions(&glfw.num_extensions); -} void init_list_of_required_extensions() { vulkan.num_required_extensions = glfw.num_extensions + 1; @@ -118,6 +117,46 @@ void init_list_of_required_extensions() { vulkan.required_extensions[vulkan.num_required_extensions - 1] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; } + +bool is_suitable_physical_device(VkPhysicalDevice device) { + VkPhysicalDeviceProperties properties; + VkPhysicalDeviceFeatures features; + vkGetPhysicalDeviceProperties(device, &properties); + vkGetPhysicalDeviceFeatures(device, &features); + + return properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && features.geometryShader; +} + +bool pick_physical_device() { + uint32_t num_devices = 0; + if (vkEnumeratePhysicalDevices(vulkan.instance, &num_devices, NULL) != VK_SUCCESS) { + return false; + } + + VkPhysicalDevice *devices = malloc(sizeof(VkPhysicalDevice) * num_devices); + if (vkEnumeratePhysicalDevices(vulkan.instance, &num_devices, devices) != VK_SUCCESS) { + free(devices); + return false; + } + + bool found = false; + for (uint32_t i = 0; i < num_devices; i++) { + if (is_suitable_physical_device(devices[i])) { + vulkan.physicalDevice = devices[i]; + found = true; + break; + } + } + + free(devices); + + return found; +} + +void init_glfw() { + glfw.extensions = glfwGetRequiredInstanceExtensions(&glfw.num_extensions); +} + bool init_vulkan() { init_glfw(); @@ -147,6 +186,11 @@ bool init_vulkan() { init_debug_callback(); + if (!pick_physical_device()) { + printf("Failed to pick a suitable graphics device\n"); + return false; + } + printf("Vulkan Initialized\n"); printf("Loaded Vulkan Extensions: %u\n", vulkan.num_properties); diff --git a/src/engine/graphics/vulkan.h b/src/engine/graphics/vulkan.h index 80af657..e413d56 100644 --- a/src/engine/graphics/vulkan.h +++ b/src/engine/graphics/vulkan.h @@ -22,6 +22,8 @@ typedef struct { const char ** required_extensions; uint32_t num_required_extensions; + + VkPhysicalDevice physicalDevice; } vulkan_state; From bc23c0ad60fd3ad70af955c44243cd68040d3e65 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Mon, 3 Sep 2018 11:07:39 -0400 Subject: [PATCH 07/30] Move vulkan into it's own folder --- CMakeLists.txt | 2 +- src/engine/graphics/vulkan.c | 207 -------------------------- src/engine/graphics/vulkan.h | 38 ----- src/engine/graphics/vulkan/config.c | 52 +++++++ src/engine/graphics/vulkan/config.h | 10 ++ src/engine/graphics/vulkan/debug.c | 80 ++++++++++ src/engine/graphics/vulkan/debug.h | 24 +++ src/engine/graphics/vulkan/query.c | 55 +++++++ src/engine/graphics/vulkan/query.h | 14 ++ src/engine/graphics/vulkan/vulkan.c | 82 ++++++++++ src/engine/graphics/vulkan/vulkan.h | 70 +++++++++ src/engine/graphics/vulkan/wrappers.h | 51 +++++++ src/engine/main.c | 5 +- 13 files changed, 441 insertions(+), 249 deletions(-) delete mode 100644 src/engine/graphics/vulkan.c delete mode 100644 src/engine/graphics/vulkan.h create mode 100644 src/engine/graphics/vulkan/config.c create mode 100644 src/engine/graphics/vulkan/config.h create mode 100644 src/engine/graphics/vulkan/debug.c create mode 100644 src/engine/graphics/vulkan/debug.h create mode 100644 src/engine/graphics/vulkan/query.c create mode 100644 src/engine/graphics/vulkan/query.h create mode 100644 src/engine/graphics/vulkan/vulkan.c create mode 100644 src/engine/graphics/vulkan/vulkan.h create mode 100644 src/engine/graphics/vulkan/wrappers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 33bdbc3..89ccf07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,7 @@ set(SOURCE_FILES lib/linmath/linmath.h src/engine/scripting/callbacks.c src/engine/scripting/callbacks.h src/engine/graphics/screen.c src/engine/graphics/screen.h - src/engine/graphics/vulkan.c src/engine/graphics/vulkan.h src/engine/graphics/wrappers/vulkan_debugging.h) + src/engine/graphics/wrappers/vulkan_debugging.h src/engine/graphics/vulkan/vulkan.c src/engine/graphics/vulkan/vulkan.h src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan.c b/src/engine/graphics/vulkan.c deleted file mode 100644 index df2d0be..0000000 --- a/src/engine/graphics/vulkan.c +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include -#include -#include -#include -#include "vulkan.h" -#include "wrappers/vulkan_debugging.h" - -glfw_state glfw; -vulkan_state vulkan = { - .physicalDevice = VK_NULL_HANDLE -}; - -/* - * Provide vulkan with some context for our application - */ -VkApplicationInfo definition = { - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pApplicationName = "Solid Snake", - .applicationVersion = VK_MAKE_VERSION(0, 0, 1), - .pEngineName = "Solid Engine", - .engineVersion = VK_MAKE_VERSION(0, 0, 1), - .apiVersion = VK_API_VERSION_1_0 -}; - -#define NUM_WANTED_VALIDATION_LAYERS ((uint32_t) 2) -const char *wanted_validation_layers[NUM_WANTED_VALIDATION_LAYERS] = { - "VK_LAYER_LUNARG_core_validation", - "VK_LAYER_LUNARG_standard_validation" - -}; - - -static VKAPI_ATTR VkBool32 VKAPI_CALL on_vulkan_validation_failure( - VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkDebugUtilsMessengerCallbackDataEXT *data, - void *user_date -) { - // Ignore lack of usage - ((void) severity); - ((void) type); - ((void) data); - ((void) user_date); - - printf("validation layer: %s\n", data->pMessage); - - return VK_FALSE; -} - -void init_debug_callback() { - VkDebugUtilsMessengerCreateInfoEXT creation_request = { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, - .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, - .pfnUserCallback = on_vulkan_validation_failure, - .pUserData = NULL // Optional - }; - - wrap_vulkan_create_debug_utils_messenger_ext( - vulkan.instance, - &creation_request, - NULL, - &vulkan.debug_utils_messenger_callback - ); -} - - -/** - * Check to make sure all of our desired validation layers can be provided by vulkan - * @return - */ -bool has_all_wanted_validation_layers() { - for (uint32_t wanted_layer_index = 0; wanted_layer_index < NUM_WANTED_VALIDATION_LAYERS; wanted_layer_index++) { - bool found = false; - - // Search array of available layers - for (uint32_t i = 0; !found && i < vulkan.num_layer_properties; i++) { - found = strcmp(wanted_validation_layers[wanted_layer_index], vulkan.layer_properties[i].layerName) == 0; - } - - if (!found) { - return false; - } - } - - return true; -} - -VkResult create_vulkan_application_interface() { - VkInstanceCreateInfo creation_request = { - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - .pApplicationInfo = &definition - }; - creation_request.enabledExtensionCount = glfw.num_extensions; - creation_request.ppEnabledExtensionNames = glfw.extensions; - - creation_request.ppEnabledLayerNames = wanted_validation_layers; - creation_request.enabledLayerCount = NUM_WANTED_VALIDATION_LAYERS; - - creation_request.ppEnabledExtensionNames = vulkan.required_extensions; - creation_request.enabledExtensionCount = vulkan.num_required_extensions; - return vkCreateInstance(&creation_request, NULL, &vulkan.instance); -} - - -void init_list_of_required_extensions() { - vulkan.num_required_extensions = glfw.num_extensions + 1; - vulkan.required_extensions = malloc(sizeof(char *) * vulkan.num_required_extensions); - for (size_t i = 0; i < vulkan.num_required_extensions - 1; i++) { - vulkan.required_extensions[i] = glfw.extensions[i]; - } - vulkan.required_extensions[vulkan.num_required_extensions - 1] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; -} - - -bool is_suitable_physical_device(VkPhysicalDevice device) { - VkPhysicalDeviceProperties properties; - VkPhysicalDeviceFeatures features; - vkGetPhysicalDeviceProperties(device, &properties); - vkGetPhysicalDeviceFeatures(device, &features); - - return properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && features.geometryShader; -} - -bool pick_physical_device() { - uint32_t num_devices = 0; - if (vkEnumeratePhysicalDevices(vulkan.instance, &num_devices, NULL) != VK_SUCCESS) { - return false; - } - - VkPhysicalDevice *devices = malloc(sizeof(VkPhysicalDevice) * num_devices); - if (vkEnumeratePhysicalDevices(vulkan.instance, &num_devices, devices) != VK_SUCCESS) { - free(devices); - return false; - } - - bool found = false; - for (uint32_t i = 0; i < num_devices; i++) { - if (is_suitable_physical_device(devices[i])) { - vulkan.physicalDevice = devices[i]; - found = true; - break; - } - } - - free(devices); - - return found; -} - -void init_glfw() { - glfw.extensions = glfwGetRequiredInstanceExtensions(&glfw.num_extensions); -} - -bool init_vulkan() { - init_glfw(); - - if (vkEnumerateInstanceExtensionProperties(NULL, &vulkan.num_properties, vulkan.properties) != VK_SUCCESS) { - printf("Failed to get extension properties\n"); - return false; - } - - vkEnumerateInstanceLayerProperties(&vulkan.num_layer_properties, NULL); - vulkan.layer_properties = malloc(sizeof(VkLayerProperties) * vulkan.num_layer_properties); - if (vkEnumerateInstanceLayerProperties(&vulkan.num_layer_properties, vulkan.layer_properties) != VK_SUCCESS) { - printf("Failed to get extension properties\n"); - return false; - } - - if (!has_all_wanted_validation_layers()) { - printf("Vulkan does not provide all requested validation layers!\n"); - return false; - } - - init_list_of_required_extensions(); - - if (create_vulkan_application_interface() != VK_SUCCESS) { - printf("Failed to initialize vulkan instance\n"); - return false; - } - - init_debug_callback(); - - if (!pick_physical_device()) { - printf("Failed to pick a suitable graphics device\n"); - return false; - } - - printf("Vulkan Initialized\n"); - printf("Loaded Vulkan Extensions: %u\n", vulkan.num_properties); - - printf("Loaded Vulkan Instance Layers: %u\n", vulkan.num_layer_properties); - for (uint32_t i = 0; i < vulkan.num_layer_properties; i++) { - printf("\t%d - %s (%d)\n", i, vulkan.layer_properties[i].layerName, vulkan.layer_properties[i].specVersion); - } - return true; -} - -void cleanup_vulkan() { - wrap_vulkan_destroy_debug_utils_messenger_ext(vulkan.instance, vulkan.debug_utils_messenger_callback, NULL); - vkDestroyInstance(vulkan.instance, NULL); -} diff --git a/src/engine/graphics/vulkan.h b/src/engine/graphics/vulkan.h deleted file mode 100644 index e413d56..0000000 --- a/src/engine/graphics/vulkan.h +++ /dev/null @@ -1,38 +0,0 @@ - -#ifndef ENGINE_VULKAN_H -#define ENGINE_VULKAN_H - -#include -#include - -typedef struct { - uint32_t num_extensions; - const char **extensions; -} glfw_state; - -typedef struct { - VkExtensionProperties *properties; - uint32_t num_properties; - - VkLayerProperties *layer_properties; - uint32_t num_layer_properties; - - VkInstance instance; - VkDebugUtilsMessengerEXT debug_utils_messenger_callback; - - const char ** required_extensions; - uint32_t num_required_extensions; - - VkPhysicalDevice physicalDevice; -} vulkan_state; - - -/** - * Initialize Vulkan - * @return - */ -bool init_vulkan(); - -void cleanup_vulkan(); - -#endif diff --git a/src/engine/graphics/vulkan/config.c b/src/engine/graphics/vulkan/config.c new file mode 100644 index 0000000..2a5356b --- /dev/null +++ b/src/engine/graphics/vulkan/config.c @@ -0,0 +1,52 @@ +#include +#include "config.h" +#include "vulkan.h" +#include "debug.h" + + +bool vulkan_config_physical_device_is_suitable(VkPhysicalDevice device) { + VkPhysicalDeviceProperties properties; + VkPhysicalDeviceFeatures features; + vkGetPhysicalDeviceProperties(device, &properties); + vkGetPhysicalDeviceFeatures(device, &features); + + return properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && features.geometryShader; +} + +VkPhysicalDevice vulkan_config_pick_physical_device(vulkan *v) { + if (vkEnumeratePhysicalDevices(v->instance, &v->devices.num_devices, NULL) != VK_SUCCESS) { + return VK_NULL_HANDLE; + } + + v->devices.devices = malloc(sizeof(VkPhysicalDevice) * v->devices.num_devices); + if (vkEnumeratePhysicalDevices(v->instance, &v->devices.num_devices, v->devices.devices) != VK_SUCCESS) { + return VK_NULL_HANDLE; + } + + for (uint32_t i = 0; i < v->devices.num_devices; i++) { + if (vulkan_config_physical_device_is_suitable(v->devices.devices[i])) { + return v->devices.devices[i]; + } + } + + return VK_NULL_HANDLE; +} + + +bool vulkan_config_init(vulkan *v) +{ + // Request all GLFW extensions to be loaded up + v->required_configuration.num_extensions = v->g.num_extensions + 1; + v->required_configuration.extensions = malloc(sizeof(char *) * v->required_configuration.num_extensions); + for (size_t i = 0; i < v->g.num_extensions; i++) { + v->required_configuration.extensions[i] = v->g.extensions[i]; + } + + // Requrest for debugging extensions to be loaded up + v->required_configuration.extensions[v->g.num_extensions] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; + + // request all validation layers + v->required_configuration.num_layers = vulkan_debug_num_validation_layers(); + v->required_configuration.layers = vulkan_debug_validation_layers(); + return true; +} diff --git a/src/engine/graphics/vulkan/config.h b/src/engine/graphics/vulkan/config.h new file mode 100644 index 0000000..270d423 --- /dev/null +++ b/src/engine/graphics/vulkan/config.h @@ -0,0 +1,10 @@ +#ifndef ENGINE_CONFIG_H +#define ENGINE_CONFIG_H + +#include "vulkan.h" +#include + +VkPhysicalDevice vulkan_config_pick_physical_device(vulkan *v); +bool vulkan_config_init(vulkan *v); + +#endif diff --git a/src/engine/graphics/vulkan/debug.c b/src/engine/graphics/vulkan/debug.c new file mode 100644 index 0000000..60b0d9a --- /dev/null +++ b/src/engine/graphics/vulkan/debug.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include "vulkan.h" +#include "wrappers.h" + + +#define NUM_WANTED_VALIDATION_LAYERS ((uint32_t) 2) +const char *wanted_validation_layers[NUM_WANTED_VALIDATION_LAYERS] = { + "VK_LAYER_LUNARG_core_validation", + "VK_LAYER_LUNARG_standard_validation" + +}; + + +static VKAPI_ATTR VkBool32 VKAPI_CALL on_error( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT *data, + void *user_date +) { + // Ignore lack of usage + ((void) severity); + ((void) type); + ((void) data); + ((void) user_date); + + printf("Validation Message: %s\n", data->pMessage); + + return VK_FALSE; +} + + +uint32_t vulkan_debug_num_validation_layers() { + return NUM_WANTED_VALIDATION_LAYERS; +} + +const char **vulkan_debug_validation_layers() { + return wanted_validation_layers; +} + + +void vulkan_debug_init(vulkan *v) { + VkDebugUtilsMessengerCreateInfoEXT creation_request = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = on_error, + .pUserData = NULL // Optional + }; + + wrap_vulkan_create_debug_utils_messenger_ext( + v->instance, + &creation_request, + NULL, + &v->debugging.debug_utils_messenger_callback + ); +} + +bool vulkan_debug_has_all_wanted_validation_layers(vulkan *v) { + + for (uint32_t wanted_layer_index = 0; wanted_layer_index < NUM_WANTED_VALIDATION_LAYERS; wanted_layer_index++) { + bool found = false; + + // Search array of available layers + for (uint32_t i = 0; !found && i < v->layers.num_properties; i++) { + found = strcmp(wanted_validation_layers[wanted_layer_index], v->layers.properties[i].layerName) == 0; + } + + if (!found) { + return false; + } + } + + return true; +} diff --git a/src/engine/graphics/vulkan/debug.h b/src/engine/graphics/vulkan/debug.h new file mode 100644 index 0000000..5a691e6 --- /dev/null +++ b/src/engine/graphics/vulkan/debug.h @@ -0,0 +1,24 @@ +#ifndef ENGINE_HDEBUG_H +#define ENGINE_HDEBUG_H + +#include +#include "vulkan.h" + +/** + * Check if all validation layers can be provided by vulkan on this system + * @param v + * @return + */ +bool vulkan_debug_has_all_wanted_validation_layers(vulkan *v); + +/** + * Set debugger callbacks into vulkan instance + * @param v + */ +void vulkan_debug_init(vulkan *v); + +uint32_t vulkan_debug_num_validation_layers(); + +const char **vulkan_debug_validation_layers(); + +#endif diff --git a/src/engine/graphics/vulkan/query.c b/src/engine/graphics/vulkan/query.c new file mode 100644 index 0000000..f1e5a65 --- /dev/null +++ b/src/engine/graphics/vulkan/query.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include "query.h" + + +/** + * Load hardware and rendering information from GLFW + */ +bool glfw_query(vulkan *v) { + v->g.extensions = glfwGetRequiredInstanceExtensions(&v->g.num_extensions); + return true; +} + +/** + * Load available extensions from vulkan + * @return + */ +bool vulkan_query_extensions(vulkan *v) { + if (vkEnumerateInstanceExtensionProperties(NULL, &v->extensions.num_properties, NULL) != VK_SUCCESS) { + return false; + } + + v->extensions.properties = malloc(sizeof(VkExtensionProperties) * v->extensions.num_properties); + + return vkEnumerateInstanceExtensionProperties(NULL, &v->extensions.num_properties, v->extensions.properties) == + VK_SUCCESS; +} + +bool vulkan_query_layers(vulkan *v) { + if (vkEnumerateInstanceLayerProperties(&v->layers.num_properties, NULL) != VK_SUCCESS) { + return false; + } + + v->layers.properties = malloc(sizeof(VkLayerProperties) * v->layers.num_properties); + + if (vkEnumerateInstanceLayerProperties(&v->layers.num_properties, v->layers.properties) != VK_SUCCESS) { + printf("Failed to get extension properties\n"); + return false; + } + + return true; +} + + +/** + * Query all hardware on the system + * @return + */ +bool vulkan_hardware_query(vulkan *v) { + return + glfw_query(v) && + vulkan_query_extensions(v) && + vulkan_query_layers(v); +} diff --git a/src/engine/graphics/vulkan/query.h b/src/engine/graphics/vulkan/query.h new file mode 100644 index 0000000..82e0d36 --- /dev/null +++ b/src/engine/graphics/vulkan/query.h @@ -0,0 +1,14 @@ +#ifndef ENGINE_HQUERY_H +#define ENGINE_HQUERY_H + +#include +#include + +/** + * Query all hardware from vulkan system + * @param v + * @return + */ +bool vulkan_hardware_query(vulkan *v); + +#endif diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c new file mode 100644 index 0000000..eec4f29 --- /dev/null +++ b/src/engine/graphics/vulkan/vulkan.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include "query.h" +#include "vulkan.h" +#include "config.h" +#include "debug.h" + +vulkan v = { + .definition = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "Solid Snake", + .applicationVersion = VK_MAKE_VERSION(0, 0, 1), + .pEngineName = "Solid Engine", + .engineVersion = VK_MAKE_VERSION(0, 0, 1), + .apiVersion = VK_API_VERSION_1_0 + }, + .devices.selected_device = VK_NULL_HANDLE +}; + + +VkResult vulkan_create_instance() { + VkInstanceCreateInfo creation_request = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &v.definition + }; + + creation_request.ppEnabledLayerNames = v.required_configuration.layers; + creation_request.enabledLayerCount = v.required_configuration.num_layers; + + creation_request.ppEnabledExtensionNames = v.required_configuration.extensions; + creation_request.enabledExtensionCount = v.required_configuration.num_extensions; + + return vkCreateInstance(&creation_request, NULL, &v.instance); +} + +void vulkan_info_print() { + printf("Vulkan Initialized\n"); + + printf("Loaded Vulkan Extensions: %u\n", v.extensions.num_properties); + for (uint32_t i = 0; i < v.extensions.num_properties; i++) { + printf("\t%d - %s (%d)\n", i, v.extensions.properties[i].extensionName, v.extensions.properties[i].specVersion); + } + + printf("Loaded Vulkan Instance Layers: %u\n", v.layers.num_properties); + for (uint32_t i = 0; i < v.layers.num_properties; i++) { + printf("\t%d - %s (%d)\n", i, v.layers.properties[i].layerName, v.layers.properties[i].specVersion); + } +} + + +bool vulkan_init() { + // Find hardware info + if (!vulkan_hardware_query(&v)) { + printf("Failed to query vulkan hardware!\n"); + return false; + } + + // Choose extensions and layers to use + vulkan_config_init(&v); + + // Create vulkan instance + if (vulkan_create_instance() != VK_SUCCESS) { + printf("Failed to create vulkan instance\n"); + return false; + } + + // Start the debugger + vulkan_debug_init(&v); + + // Select a device + if ((v.devices.selected_device = vulkan_config_pick_physical_device(&v)) == VK_NULL_HANDLE) { + printf("Failed to find suitable device!\n"); + return false; + } + + // Info to prove we have loaded everything + vulkan_info_print(); + + return true; +} diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h new file mode 100644 index 0000000..b5c50b7 --- /dev/null +++ b/src/engine/graphics/vulkan/vulkan.h @@ -0,0 +1,70 @@ +#ifndef ENGINE_VGMODULE_H +#define ENGINE_VGMODULE_H + +#include +#include + +typedef struct { + uint32_t num_extensions; + const char **extensions; +} glfw; + + +typedef struct { + VkDebugUtilsMessengerEXT debug_utils_messenger_callback; +} vulkan_debugging; + + +typedef struct { + + /** + * Info about available devices + */ + VkPhysicalDevice *devices; + uint32_t num_devices; + + /** + * The device we are currently rendering to + */ + VkPhysicalDevice selected_device; +} vulkan_devices; + +typedef struct { + VkExtensionProperties *properties; + uint32_t num_properties; +} vulkan_extensions; + +typedef struct { + VkLayerProperties *properties; + uint32_t num_properties; + + const char **layers; + uint32_t num_layers; +} vulkan_layers; + +typedef struct { + uint32_t num_extensions; + const char **extensions; + uint32_t num_layers; + const char **layers; +} vulkan_required_configuration; + +typedef struct { + VkApplicationInfo definition; + + glfw g; + VkInstance instance; + + vulkan_layers layers; + vulkan_extensions extensions; + vulkan_debugging debugging; + vulkan_devices devices; + + vulkan_required_configuration required_configuration; +} vulkan; + + +bool vulkan_init(); + + +#endif diff --git a/src/engine/graphics/vulkan/wrappers.h b/src/engine/graphics/vulkan/wrappers.h new file mode 100644 index 0000000..0011ad2 --- /dev/null +++ b/src/engine/graphics/vulkan/wrappers.h @@ -0,0 +1,51 @@ +#ifndef ENGINE_WRAPPERS_H +#define ENGINE_WRAPPERS_H + +#include + +/** + * Wrapper for vkCreateDebugUtilsMessengerEXT extension function + * @param instance + * @param pCreateInfo + * @param pAllocator + * @param pCallback + * @return + */ +static inline VkResult wrap_vulkan_create_debug_utils_messenger_ext( + VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugUtilsMessengerEXT *pCallback +) { + const PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr( + instance, + "vkCreateDebugUtilsMessengerEXT" + ); + if (func != NULL) { + return func(instance, pCreateInfo, pAllocator, pCallback); + } else { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } +} + +/** + * Wrapper around vkDestroyDebugUtilsMessengerEXT + * @param instance + * @param callback + * @param pAllocator + */ +static inline void wrap_vulkan_destroy_debug_utils_messenger_ext( + VkInstance instance, + VkDebugUtilsMessengerEXT callback, + const VkAllocationCallbacks *pAllocator +) { + PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr( + instance, + "vkDestroyDebugUtilsMessengerEXT" + ); + if (func != NULL) { + func(instance, callback, pAllocator); + } +} + +#endif diff --git a/src/engine/main.c b/src/engine/main.c index 45a37be..270b771 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -3,7 +3,7 @@ #include "lib/glad/glad.h" #include -#include "src/engine/graphics/vulkan.h" +#include #include "src/engine/scripting/callbacks.h" #include "src/engine/scripting/script.h" @@ -66,7 +66,7 @@ int main() { glfwMakeContextCurrent(window); - if (!init_vulkan()) { + if (!vulkan_init()) { printf("Failed to initialize graphics layer\n"); return 1; } @@ -84,7 +84,6 @@ int main() { glfwPollEvents(); } - cleanup_vulkan(); glfwDestroyWindow(window); From 0bdbcbbf21e3428adcd583dde737511f2fad63a0 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Mon, 3 Sep 2018 11:08:04 -0400 Subject: [PATCH 08/30] Delete old wrapper file --- .../graphics/wrappers/vulkan_debugging.h | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 src/engine/graphics/wrappers/vulkan_debugging.h diff --git a/src/engine/graphics/wrappers/vulkan_debugging.h b/src/engine/graphics/wrappers/vulkan_debugging.h deleted file mode 100644 index dbd3358..0000000 --- a/src/engine/graphics/wrappers/vulkan_debugging.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef ENGINE_VULKAN_DEBUGGING_H -#define ENGINE_VULKAN_DEBUGGING_H - -#include - -/** - * Wrapper for vkCreateDebugUtilsMessengerEXT extension function - * @param instance - * @param pCreateInfo - * @param pAllocator - * @param pCallback - * @return - */ -static inline VkResult wrap_vulkan_create_debug_utils_messenger_ext( - VkInstance instance, - const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkDebugUtilsMessengerEXT *pCallback -) { - const PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr( - instance, - "vkCreateDebugUtilsMessengerEXT" - ); - if (func != NULL) { - return func(instance, pCreateInfo, pAllocator, pCallback); - } else { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } -} - -/** - * Wrapper around vkDestroyDebugUtilsMessengerEXT - * @param instance - * @param callback - * @param pAllocator - */ -static inline void wrap_vulkan_destroy_debug_utils_messenger_ext( - VkInstance instance, - VkDebugUtilsMessengerEXT callback, - const VkAllocationCallbacks *pAllocator -) { - PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr( - instance, - "vkDestroyDebugUtilsMessengerEXT" - ); - if (func != NULL) { - func(instance, callback, pAllocator); - } -} - - -#endif From 15e30e1e9828b3f36c9ade16da1f334c0dc6f1ef Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 8 Sep 2018 00:33:01 -0400 Subject: [PATCH 09/30] Clean up CMakeLists.txt --- CMakeLists.txt | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89ccf07..323b16b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,23 +1,22 @@ cmake_minimum_required(VERSION 3.5) project(engine) -find_package( PythonInterp 2.7 REQUIRED ) +find_package(PythonInterp 2.7 REQUIRED) include(CheckCCompilerFlag) # Source: https://stackoverflow.com/a/33266748/1127064 function(enable_c_compiler_flag_if_supported flag) string(FIND "${CMAKE_C_FLAGS}" "${flag}" flag_already_set) - if(flag_already_set EQUAL -1) + if (flag_already_set EQUAL -1) check_c_compiler_flag("${flag}" flag_supported) - if(flag_supported) + if (flag_supported) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}" PARENT_SCOPE) - endif() + endif () unset(flag_supported CACHE) - endif() + endif () endfunction() - # VENDOR DUKTAPE set(VENDOR_DUKTAPE_SOURCES ${CMAKE_SOURCE_DIR}/lib/duktape/duktape.c ${CMAKE_SOURCE_DIR}/lib/duktape/duktape.h ${CMAKE_SOURCE_DIR}/lib/duktape/duk_config.h ${CMAKE_SOURCE_DIR}/lib/duktape/duk_source_meta.json) add_custom_command( @@ -31,14 +30,14 @@ add_custom_target(localduktape set(VENDOR_GLAD_SOURCES ${CMAKE_SOURCE_DIR}/lib/glad/glad.c ${CMAKE_SOURCE_DIR}/lib/glad/glad.h) add_custom_command( - OUTPUT ${VENDOR_GLAD_SOURCES} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/vendor/glad/ - PRE_BUILD - COMMAND ${PYTHON_EXECUTABLE} -m glad --generator c --out-path ${CMAKE_SOURCE_DIR}/lib/glad/ --spec gl --omit-khrplatform --local-files + OUTPUT ${VENDOR_GLAD_SOURCES} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/vendor/glad/ + PRE_BUILD + COMMAND ${PYTHON_EXECUTABLE} -m glad --generator c --out-path ${CMAKE_SOURCE_DIR}/lib/glad/ --spec gl --omit-khrplatform --local-files ) add_custom_target(localglad - ALL - DEPENDS ${VENDOR_GLAD_SOURCES}) + ALL + DEPENDS ${VENDOR_GLAD_SOURCES}) # lib/glad/glad.c @@ -46,7 +45,7 @@ add_custom_target(localglad # ALL SOURCES set(SOURCE_FILES - ${VENDOR_GLAD_SOURCES} ${VENDOR_DUKTAPE_SOURCES} + ${VENDOR_GLAD_SOURCES} ${VENDOR_DUKTAPE_SOURCES} src/engine/main.c src/engine/scripting/interface.c src/engine/scripting/interface.h src/engine/scripting/script.h @@ -59,10 +58,14 @@ set(SOURCE_FILES lib/linmath/linmath.h src/engine/scripting/callbacks.c src/engine/scripting/callbacks.h src/engine/graphics/screen.c src/engine/graphics/screen.h - src/engine/graphics/wrappers/vulkan_debugging.h src/engine/graphics/vulkan/vulkan.c src/engine/graphics/vulkan/vulkan.h src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h) -set(CMAKE_INCLUDE_CURRENT_DIR ON) + src/engine/graphics/vulkan/vulkan.c src/engine/graphics/vulkan/vulkan.h + src/engine/graphics/vulkan/wrappers.h + src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h + src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h + src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h) +set(CMAKE_INCLUDE_CURRENT_DIR ON) add_executable(engine ${SOURCE_FILES}) From f72bbc0425f935b1ff2031bd043207a7d6638e04 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 8 Sep 2018 01:17:32 -0400 Subject: [PATCH 10/30] Setup the first queue --- CMakeLists.txt | 2 +- src/engine/graphics/vulkan/queues.c | 73 +++++++++++++++++++++++++++++ src/engine/graphics/vulkan/queues.h | 9 ++++ src/engine/graphics/vulkan/vulkan.c | 9 ++++ src/engine/graphics/vulkan/vulkan.h | 11 +++++ 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/engine/graphics/vulkan/queues.c create mode 100644 src/engine/graphics/vulkan/queues.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 323b16b..e74596e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,7 @@ set(SOURCE_FILES src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h - src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h) + src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan/queues.c b/src/engine/graphics/vulkan/queues.c new file mode 100644 index 0000000..218611a --- /dev/null +++ b/src/engine/graphics/vulkan/queues.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include "queues.h" +#include "vulkan.h" + +VkResult vulkan_queues_init_queue_family(vulkan *v, VkPhysicalDevice device, uint32_t queue, float priority) { + VkDeviceQueueCreateInfo queue_create_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = queue, + .queueCount = 1, + .pQueuePriorities = &priority + }; + + VkPhysicalDeviceFeatures device_features; + memset(&device_features, 0, sizeof(VkPhysicalDeviceFeatures)); + + VkDeviceCreateInfo request = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pQueueCreateInfos = &queue_create_info, + .queueCreateInfoCount = 1, + .pEnabledFeatures = &device_features, + + // No device extensions enabled for now. We will enable swapchain later + .enabledExtensionCount = 0, + + // Validation Layers + .enabledLayerCount = v->required_configuration.num_layers, + .ppEnabledLayerNames = v->required_configuration.layers + }; + + return vkCreateDevice(device, &request, NULL, &v->devices.logical_device); +} + +void vulkan_queues_cleanup(vulkan *v) { + vkDestroyDevice(v->devices.logical_device, NULL); +} + +bool vulkan_queues_init(vulkan *v) { + VkPhysicalDevice device = v->devices.selected_device; + + // Find properties + vkGetPhysicalDeviceQueueFamilyProperties(device, &v->queues.num_properties, NULL); + v->queues.properties = malloc(sizeof(VkQueueFamilyProperties) * v->queues.num_properties); + vkGetPhysicalDeviceQueueFamilyProperties(device, &v->queues.num_properties, v->queues.properties); + + + v->queues.main_rendering_queue_id = UINT32_MAX; + + for (uint32_t i = 0; i < v->queues.num_properties; i++) { + VkQueueFamilyProperties *properties = &v->queues.properties[i]; + + // Find graphics queue + if (properties->queueFlags & VK_QUEUE_GRAPHICS_BIT) { + v->queues.main_rendering_queue_id = i; + break; + } + } + + if (v->queues.main_rendering_queue_id == UINT32_MAX) { + return false; + } + + if (vulkan_queues_init_queue_family(v, v->devices.selected_device, v->queues.main_rendering_queue_id, 1.0f) != VK_SUCCESS) { + printf("Failed to initialize queue family\n"); + return false; + } + + // Load instance into vulkan structure + vkGetDeviceQueue(v->devices.logical_device, v->queues.main_rendering_queue_id, 0, &v->queues.rendering); + + return true; +} diff --git a/src/engine/graphics/vulkan/queues.h b/src/engine/graphics/vulkan/queues.h new file mode 100644 index 0000000..6b25e94 --- /dev/null +++ b/src/engine/graphics/vulkan/queues.h @@ -0,0 +1,9 @@ +#ifndef ENGINE_QUEUES_H +#define ENGINE_QUEUES_H + +#include "vulkan.h" + +void vulkan_queues_cleanup(vulkan *v); +bool vulkan_queues_init(vulkan *v); + +#endif diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index eec4f29..0ab240f 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -6,6 +6,7 @@ #include "vulkan.h" #include "config.h" #include "debug.h" +#include "queues.h" vulkan v = { .definition = { @@ -47,6 +48,8 @@ void vulkan_info_print() { for (uint32_t i = 0; i < v.layers.num_properties; i++) { printf("\t%d - %s (%d)\n", i, v.layers.properties[i].layerName, v.layers.properties[i].specVersion); } + + printf("Using %u as the main graphics queue\n", v.queues.main_rendering_queue_id); } @@ -75,6 +78,12 @@ bool vulkan_init() { return false; } + // Find a queue with graphics pipeline support + if (!vulkan_queues_init(&v)) { + printf("Could not find graphics bit in chosen device!\n"); + return false; + } + // Info to prove we have loaded everything vulkan_info_print(); diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h index b5c50b7..fffe0cd 100644 --- a/src/engine/graphics/vulkan/vulkan.h +++ b/src/engine/graphics/vulkan/vulkan.h @@ -27,6 +27,7 @@ typedef struct { * The device we are currently rendering to */ VkPhysicalDevice selected_device; + VkDevice logical_device; } vulkan_devices; typedef struct { @@ -42,6 +43,15 @@ typedef struct { uint32_t num_layers; } vulkan_layers; + +typedef struct { + uint32_t num_properties; + VkQueueFamilyProperties *properties; + + uint32_t main_rendering_queue_id; + VkQueue rendering; +} vulkan_queues; + typedef struct { uint32_t num_extensions; const char **extensions; @@ -59,6 +69,7 @@ typedef struct { vulkan_extensions extensions; vulkan_debugging debugging; vulkan_devices devices; + vulkan_queues queues; vulkan_required_configuration required_configuration; } vulkan; From a7597216b7d373476370ea0205522c15f44a3a13 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 8 Sep 2018 02:04:38 -0400 Subject: [PATCH 11/30] Begin surface creation and initialization of multiple queues --- CMakeLists.txt | 2 +- src/engine/graphics/vulkan/queues.c | 91 +++++++++++++++++++++------- src/engine/graphics/vulkan/surface.c | 5 ++ src/engine/graphics/vulkan/surface.h | 8 +++ src/engine/graphics/vulkan/vulkan.c | 23 +++++++ src/engine/graphics/vulkan/vulkan.h | 10 ++- src/engine/graphics/vulkan/window.c | 43 +++++++++++++ src/engine/graphics/vulkan/window.h | 19 ++++++ src/engine/main.c | 31 ++-------- 9 files changed, 182 insertions(+), 50 deletions(-) create mode 100644 src/engine/graphics/vulkan/surface.c create mode 100644 src/engine/graphics/vulkan/surface.h create mode 100644 src/engine/graphics/vulkan/window.c create mode 100644 src/engine/graphics/vulkan/window.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e74596e..d6f22aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,7 @@ set(SOURCE_FILES src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h - src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h) + src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan/queues.c b/src/engine/graphics/vulkan/queues.c index 218611a..3947383 100644 --- a/src/engine/graphics/vulkan/queues.c +++ b/src/engine/graphics/vulkan/queues.c @@ -4,12 +4,53 @@ #include "queues.h" #include "vulkan.h" -VkResult vulkan_queues_init_queue_family(vulkan *v, VkPhysicalDevice device, uint32_t queue, float priority) { - VkDeviceQueueCreateInfo queue_create_info = { - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .queueFamilyIndex = queue, - .queueCount = 1, - .pQueuePriorities = &priority +typedef bool (*vulkan_queues_selection_criteria_t)(vulkan *v, VkPhysicalDevice device, uint32_t i, + VkQueueFamilyProperties *properties); + + +bool +vulkan_queues_selection_filter_is_presentable(vulkan *v, VkPhysicalDevice device, uint32_t i, + VkQueueFamilyProperties *properties) { + ((void) properties); + VkBool32 presentable = false; + vkGetPhysicalDeviceSurfaceSupportKHR(device, i, v->surface, &presentable); + return (bool) presentable; +} + +bool +vulkan_queues_selection_filter_is_graphics_queue(vulkan *v, VkPhysicalDevice device, uint32_t i, + VkQueueFamilyProperties *properties) { + + ((void) v); + ((void) device); + ((void) i); + return (bool) properties->queueFlags & VK_QUEUE_GRAPHICS_BIT; +} + +VkResult vulkan_queues_init_queue_family(vulkan *v, VkPhysicalDevice device, float priority) { + + + uint32_t num_queue_creations = 2; + + // We don't need to double create the same queue. + // TODO: Hack. Make this handle a dynamic number of queues + if (v->queues.main_presentation_queue_id == v->queues.main_rendering_queue_id) { + num_queue_creations = 1; + } + + VkDeviceQueueCreateInfo queue_creations[] = { + { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = v->queues.main_rendering_queue_id, + .queueCount = 1, + .pQueuePriorities = &priority + }, + { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = v->queues.main_presentation_queue_id, + .queueCount = 1, + .pQueuePriorities = &priority + }, }; VkPhysicalDeviceFeatures device_features; @@ -17,8 +58,8 @@ VkResult vulkan_queues_init_queue_family(vulkan *v, VkPhysicalDevice device, uin VkDeviceCreateInfo request = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pQueueCreateInfos = &queue_create_info, - .queueCreateInfoCount = 1, + .pQueueCreateInfos = queue_creations, + .queueCreateInfoCount = num_queue_creations, .pEnabledFeatures = &device_features, // No device extensions enabled for now. We will enable swapchain later @@ -32,6 +73,18 @@ VkResult vulkan_queues_init_queue_family(vulkan *v, VkPhysicalDevice device, uin return vkCreateDevice(device, &request, NULL, &v->devices.logical_device); } + +uint32_t vulkan_queues_find_appropriate_queue(vulkan *v, vulkan_queues_selection_criteria_t filter) { + for (uint32_t i = 0; i < v->queues.num_properties; i++) { + VkQueueFamilyProperties *properties = &v->queues.properties[i]; + + if (filter(v, v->devices.selected_device, i, properties)) { + return i; + } + } + return UINT32_MAX; +} + void vulkan_queues_cleanup(vulkan *v) { vkDestroyDevice(v->devices.logical_device, NULL); } @@ -45,29 +98,25 @@ bool vulkan_queues_init(vulkan *v) { vkGetPhysicalDeviceQueueFamilyProperties(device, &v->queues.num_properties, v->queues.properties); - v->queues.main_rendering_queue_id = UINT32_MAX; - - for (uint32_t i = 0; i < v->queues.num_properties; i++) { - VkQueueFamilyProperties *properties = &v->queues.properties[i]; + v->queues.main_rendering_queue_id = vulkan_queues_find_appropriate_queue(v, + vulkan_queues_selection_filter_is_graphics_queue); + v->queues.main_presentation_queue_id = vulkan_queues_find_appropriate_queue(v, + vulkan_queues_selection_filter_is_presentable); - // Find graphics queue - if (properties->queueFlags & VK_QUEUE_GRAPHICS_BIT) { - v->queues.main_rendering_queue_id = i; - break; - } - } - - if (v->queues.main_rendering_queue_id == UINT32_MAX) { + if (v->queues.main_rendering_queue_id == UINT32_MAX || v->queues.main_presentation_queue_id == UINT32_MAX) { return false; } - if (vulkan_queues_init_queue_family(v, v->devices.selected_device, v->queues.main_rendering_queue_id, 1.0f) != VK_SUCCESS) { + + if (vulkan_queues_init_queue_family(v, v->devices.selected_device, 1.0f) != VK_SUCCESS) { printf("Failed to initialize queue family\n"); return false; } + // Load instance into vulkan structure vkGetDeviceQueue(v->devices.logical_device, v->queues.main_rendering_queue_id, 0, &v->queues.rendering); + vkGetDeviceQueue(v->devices.logical_device, v->queues.main_presentation_queue_id, 0, &v->queues.presenting); return true; } diff --git a/src/engine/graphics/vulkan/surface.c b/src/engine/graphics/vulkan/surface.c new file mode 100644 index 0000000..b7db906 --- /dev/null +++ b/src/engine/graphics/vulkan/surface.c @@ -0,0 +1,5 @@ +#include "surface.h" + +bool vulkan_surface_init(vulkan *v) { + return glfwCreateWindowSurface(v->instance, v->g.window, NULL, &v->surface) == VK_SUCCESS; +} \ No newline at end of file diff --git a/src/engine/graphics/vulkan/surface.h b/src/engine/graphics/vulkan/surface.h new file mode 100644 index 0000000..e396fdd --- /dev/null +++ b/src/engine/graphics/vulkan/surface.h @@ -0,0 +1,8 @@ +#ifndef ENGINE_SURFACE_H +#define ENGINE_SURFACE_H + +#include "vulkan.h" + +bool vulkan_surface_init(vulkan *v); + +#endif diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index 0ab240f..8e3b53b 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -7,6 +7,8 @@ #include "config.h" #include "debug.h" #include "queues.h" +#include "window.h" +#include "surface.h" vulkan v = { .definition = { @@ -54,6 +56,12 @@ void vulkan_info_print() { bool vulkan_init() { + + if (!vulkan_window_init(&v)) { + printf("Failed to create window!\n"); + return false; + } + // Find hardware info if (!vulkan_hardware_query(&v)) { printf("Failed to query vulkan hardware!\n"); @@ -78,6 +86,12 @@ bool vulkan_init() { return false; } + // Make drawable surface + if (!vulkan_surface_init(&v)) { + printf("Failed to create drawing surface\n"); + return false; + } + // Find a queue with graphics pipeline support if (!vulkan_queues_init(&v)) { printf("Could not find graphics bit in chosen device!\n"); @@ -89,3 +103,12 @@ bool vulkan_init() { return true; } + + +void vulkan_update() { + vulkan_window_update(); +} + +void vulkan_cleanup() { + vulkan_window_cleanup(); +} diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h index fffe0cd..e1e488c 100644 --- a/src/engine/graphics/vulkan/vulkan.h +++ b/src/engine/graphics/vulkan/vulkan.h @@ -1,12 +1,16 @@ #ifndef ENGINE_VGMODULE_H #define ENGINE_VGMODULE_H +#define GLFW_INCLUDE_VULKAN 1 + +#include #include #include typedef struct { uint32_t num_extensions; const char **extensions; + GLFWwindow *window; } glfw; @@ -49,7 +53,9 @@ typedef struct { VkQueueFamilyProperties *properties; uint32_t main_rendering_queue_id; + uint32_t main_presentation_queue_id; VkQueue rendering; + VkQueue presenting; } vulkan_queues; typedef struct { @@ -64,6 +70,7 @@ typedef struct { glfw g; VkInstance instance; + VkSurfaceKHR surface; vulkan_layers layers; vulkan_extensions extensions; @@ -76,6 +83,7 @@ typedef struct { bool vulkan_init(); - +void vulkan_update(); +void vulkan_cleanup(); #endif diff --git a/src/engine/graphics/vulkan/window.c b/src/engine/graphics/vulkan/window.c new file mode 100644 index 0000000..22bef15 --- /dev/null +++ b/src/engine/graphics/vulkan/window.c @@ -0,0 +1,43 @@ +#include "window.h" + +#include +#include + +GLFWwindow *window; + +bool vulkan_window_init(vulkan *v) { + glfwInit(); + + // Disable loading OpenGL and use GLFW for loading APIs + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + + window = v->g.window = glfwCreateWindow(SCREEN_W, SCREEN_H, "Solid Engine", NULL, NULL); + + if (!v->g.window) { + printf("Failed to create window!\n"); + glfwTerminate(); + return false; + } + + + glfwMakeContextCurrent(v->g.window); + + return true; +} + +void vulkan_window_update() { + glfwPollEvents(); +} + +void vulkan_window_cleanup() { + glfwDestroyWindow(window); + glfwTerminate(); +} + +bool vulkan_window_is_close_requested() { + if (!window) { + return true; + } + return (bool) glfwWindowShouldClose(window); +} diff --git a/src/engine/graphics/vulkan/window.h b/src/engine/graphics/vulkan/window.h new file mode 100644 index 0000000..f578150 --- /dev/null +++ b/src/engine/graphics/vulkan/window.h @@ -0,0 +1,19 @@ +#ifndef ENGINE_WINDOW_H +#define ENGINE_WINDOW_H + + +#include +#include "vulkan.h" + +#define SCREEN_W 400 +#define SCREEN_H 400 + +bool vulkan_window_init(vulkan *v); + +bool vulkan_window_is_close_requested(); + +void vulkan_window_update(); + +void vulkan_window_cleanup(); + +#endif diff --git a/src/engine/main.c b/src/engine/main.c index 270b771..448e991 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -1,9 +1,9 @@ -#define GLFW_INCLUDE_VULKAN #include "lib/glad/glad.h" #include #include +#include #include "src/engine/scripting/callbacks.h" #include "src/engine/scripting/script.h" @@ -46,26 +46,6 @@ void init() { int main() { - - - glfwInit(); - - // Disable loading OpenGL and use GLFW for loading APIs - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - - GLFWwindow *window = glfwCreateWindow(SCREEN_W, SCREEN_H, "Solid Engine", NULL, NULL); - - if (!window) { - printf("Failed to create window!\n"); - glfwTerminate(); - return 1; - } - - - glfwMakeContextCurrent(window); - - if (!vulkan_init()) { printf("Failed to initialize graphics layer\n"); return 1; @@ -76,18 +56,15 @@ int main() { //REGISTER_GLFW_CALLBACKS(); - while (!glfwWindowShouldClose(window)) { + while (!vulkan_window_is_close_requested()) { //update(); //draw(); //glfwSwapBuffers(window); - glfwPollEvents(); + vulkan_update(); } - - glfwDestroyWindow(window); - - glfwTerminate(); + vulkan_cleanup(); return 0; } From fb596e4255d958736785ed95220e0433e9986929 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 8 Sep 2018 11:23:39 -0400 Subject: [PATCH 12/30] Create the first swapchain --- CMakeLists.txt | 2 +- src/engine/graphics/vulkan/config.c | 28 ++++- src/engine/graphics/vulkan/queues.c | 17 ++- src/engine/graphics/vulkan/swapchain.c | 142 +++++++++++++++++++++++++ src/engine/graphics/vulkan/swapchain.h | 8 ++ src/engine/graphics/vulkan/vulkan.c | 5 + src/engine/graphics/vulkan/vulkan.h | 17 +++ 7 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 src/engine/graphics/vulkan/swapchain.c create mode 100644 src/engine/graphics/vulkan/swapchain.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d6f22aa..f940936 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,7 @@ set(SOURCE_FILES src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h - src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h) + src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan/config.c b/src/engine/graphics/vulkan/config.c index 2a5356b..31f71ed 100644 --- a/src/engine/graphics/vulkan/config.c +++ b/src/engine/graphics/vulkan/config.c @@ -3,13 +3,33 @@ #include "vulkan.h" #include "debug.h" +#define NUM_LOGICAL_EXTENSIONS 1 +const char *logical_extensions[NUM_LOGICAL_EXTENSIONS] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME +}; + bool vulkan_config_physical_device_is_suitable(VkPhysicalDevice device) { + static char *extensions = NULL; + static uint32_t num_extensions = 0; + static uint32_t current_num_extensions = 0; + VkPhysicalDeviceProperties properties; VkPhysicalDeviceFeatures features; vkGetPhysicalDeviceProperties(device, &properties); vkGetPhysicalDeviceFeatures(device, &features); +// vkEnumerateDeviceExtensionProperties(device, NULL, ¤t_num_extensions, NULL); +// +// if (extensions) { +// if (current_num_extensions > num_extensions) { +// +// } +// } else { +// extensions = malloc(sizeof(char*) * current_num_extensions); +// num_extensions = current_num_extensions; +// } + return properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && features.geometryShader; } @@ -33,8 +53,7 @@ VkPhysicalDevice vulkan_config_pick_physical_device(vulkan *v) { } -bool vulkan_config_init(vulkan *v) -{ +bool vulkan_config_init(vulkan *v) { // Request all GLFW extensions to be loaded up v->required_configuration.num_extensions = v->g.num_extensions + 1; v->required_configuration.extensions = malloc(sizeof(char *) * v->required_configuration.num_extensions); @@ -48,5 +67,10 @@ bool vulkan_config_init(vulkan *v) // request all validation layers v->required_configuration.num_layers = vulkan_debug_num_validation_layers(); v->required_configuration.layers = vulkan_debug_validation_layers(); + + + v->required_configuration.num_logical_extensions = NUM_LOGICAL_EXTENSIONS; + v->required_configuration.logical_extensions = logical_extensions; + return true; } diff --git a/src/engine/graphics/vulkan/queues.c b/src/engine/graphics/vulkan/queues.c index 3947383..ad2e8cc 100644 --- a/src/engine/graphics/vulkan/queues.c +++ b/src/engine/graphics/vulkan/queues.c @@ -30,12 +30,17 @@ vulkan_queues_selection_filter_is_graphics_queue(vulkan *v, VkPhysicalDevice dev VkResult vulkan_queues_init_queue_family(vulkan *v, VkPhysicalDevice device, float priority) { - uint32_t num_queue_creations = 2; + v->queues.num_queue_families = 2; // We don't need to double create the same queue. // TODO: Hack. Make this handle a dynamic number of queues if (v->queues.main_presentation_queue_id == v->queues.main_rendering_queue_id) { - num_queue_creations = 1; + v->queues.num_queue_families = 1; + v->queues.queue_families[0] = v->queues.main_presentation_queue_id; + } else { + v->queues.num_queue_families = 2; + v->queues.queue_families[0] = v->queues.main_presentation_queue_id; + v->queues.queue_families[1] = v->queues.main_rendering_queue_id; } VkDeviceQueueCreateInfo queue_creations[] = { @@ -59,17 +64,19 @@ VkResult vulkan_queues_init_queue_family(vulkan *v, VkPhysicalDevice device, flo VkDeviceCreateInfo request = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pQueueCreateInfos = queue_creations, - .queueCreateInfoCount = num_queue_creations, + .queueCreateInfoCount = v->queues.num_queue_families, .pEnabledFeatures = &device_features, - // No device extensions enabled for now. We will enable swapchain later - .enabledExtensionCount = 0, + // Device extensions + .enabledExtensionCount = v->required_configuration.num_logical_extensions, + .ppEnabledExtensionNames = v->required_configuration.logical_extensions, // Validation Layers .enabledLayerCount = v->required_configuration.num_layers, .ppEnabledLayerNames = v->required_configuration.layers }; + return vkCreateDevice(device, &request, NULL, &v->devices.logical_device); } diff --git a/src/engine/graphics/vulkan/swapchain.c b/src/engine/graphics/vulkan/swapchain.c new file mode 100644 index 0000000..315df31 --- /dev/null +++ b/src/engine/graphics/vulkan/swapchain.c @@ -0,0 +1,142 @@ +#include +#include "swapchain.h" +#include "window.h" + +VkSurfaceFormatKHR vulkan_swapchain_select_format(vulkan *v) { + VkSurfaceFormatKHR best_format = { + .format = VK_FORMAT_B8G8R8A8_UNORM, + .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + }; + + if (v->swapchain.formats[0].format == VK_FORMAT_UNDEFINED) { + return best_format; + } else { + for (uint32_t i = 0; i < v->swapchain.num_formats; i++) { + VkSurfaceFormatKHR found_format = v->swapchain.formats[i]; + if (found_format.format == best_format.format && found_format.colorSpace == best_format.colorSpace) { + return found_format; + } + } + } + + return v->swapchain.formats[0]; +} + +VkPresentModeKHR vulkan_swapchain_select_presentation_mode(vulkan *v) { + VkPresentModeKHR mode_order[] = { + VK_PRESENT_MODE_MAILBOX_KHR, + VK_PRESENT_MODE_IMMEDIATE_KHR, + VK_PRESENT_MODE_FIFO_KHR + }; + + for (uint32_t mode_order_idx = 0; sizeof(mode_order) / sizeof(VkPresentModeKHR); mode_order_idx++) { + for (uint32_t i = 0; i < v->swapchain.num_modes; i++) { + if (v->swapchain.modes[i] == mode_order[mode_order_idx]) { + return v->swapchain.modes[i]; + } + } + } + + return VK_PRESENT_MODE_FIFO_KHR; +} + +VkExtent2D vulkan_swapchain_choose_extent(vulkan *v) { + if (v->swapchain.capabilities.currentExtent.width != UINT32_MAX) { + return v->swapchain.capabilities.currentExtent; + } + + VkExtent2D minimum = v->swapchain.capabilities.minImageExtent; + VkExtent2D maximum = v->swapchain.capabilities.maxImageExtent; + + VkExtent2D extent = { + SCREEN_W, SCREEN_H + }; + + + // Clamp width and height between minimum and maximum + if (minimum.width > extent.width) { + extent.width = minimum.width; + } + if (maximum.width < extent.width) { + extent.width = maximum.width; + } + + + if (minimum.height > extent.height) { + extent.height = minimum.height; + } + if (maximum.height < extent.height) { + extent.height = maximum.height; + } + + return extent; +} + +uint32_t vulkan_swapchain_choose_image_count(vulkan *v) { + uint32_t count = v->swapchain.capabilities.minImageCount + 1; + if (v->swapchain.capabilities.maxImageCount > 0 && v->swapchain.capabilities.maxImageCount < count) { + count = v->swapchain.capabilities.maxImageCount; + } + return count; +} + +VkResult vulkan_swapchain_create(vulkan *v) { + VkSurfaceFormatKHR format = vulkan_swapchain_select_format(v); + VkSwapchainCreateInfoKHR request = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .surface = v->surface, + .minImageCount = vulkan_swapchain_choose_image_count(v), + .imageFormat = format.format, + .imageColorSpace = format.colorSpace, + .imageExtent = vulkan_swapchain_choose_extent(v), + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = NULL, + + .preTransform = v->swapchain.capabilities.currentTransform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + + .presentMode = vulkan_swapchain_select_presentation_mode(v), + .clipped = VK_TRUE, + + .oldSwapchain = VK_NULL_HANDLE + }; + + if (v->queues.main_presentation_queue_id != v->queues.main_rendering_queue_id) { + request.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + request.queueFamilyIndexCount = v->queues.num_queue_families; + request.pQueueFamilyIndices = v->queues.queue_families; + } + + return vkCreateSwapchainKHR(v->devices.logical_device, &request, NULL, &v->swapchain.swapchain); +} + +bool vulkan_swapchain_init(vulkan *v) { + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(v->devices.selected_device, v->surface, &v->swapchain.capabilities); + vkGetPhysicalDeviceSurfaceFormatsKHR(v->devices.selected_device, v->surface, &v->swapchain.num_formats, NULL); + vkGetPhysicalDeviceSurfacePresentModesKHR(v->devices.selected_device, v->surface, &v->swapchain.num_modes, NULL); + + v->swapchain.formats = malloc(sizeof(VkSurfaceFormatKHR) * v->swapchain.num_formats); + v->swapchain.modes = malloc(sizeof(VkPresentModeKHR) * v->swapchain.num_modes); + + vkGetPhysicalDeviceSurfaceFormatsKHR(v->devices.selected_device, v->surface, &v->swapchain.num_formats, + v->swapchain.formats); + vkGetPhysicalDeviceSurfacePresentModesKHR(v->devices.selected_device, v->surface, &v->swapchain.num_modes, + v->swapchain.modes); + + + if (!v->swapchain.num_modes || !v->swapchain.num_formats) { + printf("Could not find a supported swapchain mode or format\n"); + return false; + } + + if (vulkan_swapchain_create(v) != VK_SUCCESS) { + printf("Failed to create swapchain instance from configuration\n"); + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/engine/graphics/vulkan/swapchain.h b/src/engine/graphics/vulkan/swapchain.h new file mode 100644 index 0000000..d1946cd --- /dev/null +++ b/src/engine/graphics/vulkan/swapchain.h @@ -0,0 +1,8 @@ +#ifndef ENGINE_SWAPCHAIN_H +#define ENGINE_SWAPCHAIN_H + +#include "vulkan.h" + +bool vulkan_swapchain_init(vulkan *v); + +#endif diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index 8e3b53b..191a373 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -9,6 +9,7 @@ #include "queues.h" #include "window.h" #include "surface.h" +#include "swapchain.h" vulkan v = { .definition = { @@ -98,6 +99,10 @@ bool vulkan_init() { return false; } + if (!vulkan_swapchain_init(&v)) { + return false; + } + // Info to prove we have loaded everything vulkan_info_print(); diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h index e1e488c..51da582 100644 --- a/src/engine/graphics/vulkan/vulkan.h +++ b/src/engine/graphics/vulkan/vulkan.h @@ -52,6 +52,9 @@ typedef struct { uint32_t num_properties; VkQueueFamilyProperties *properties; + uint32_t num_queue_families; + uint32_t queue_families[2]; + uint32_t main_rendering_queue_id; uint32_t main_presentation_queue_id; VkQueue rendering; @@ -61,10 +64,23 @@ typedef struct { typedef struct { uint32_t num_extensions; const char **extensions; + uint32_t num_logical_extensions; + const char **logical_extensions; uint32_t num_layers; const char **layers; } vulkan_required_configuration; +typedef struct { + VkSwapchainKHR swapchain; + VkSurfaceCapabilitiesKHR capabilities; + + VkSurfaceFormatKHR *formats; + uint32_t num_formats; + + VkPresentModeKHR *modes; + uint32_t num_modes; +} vulkan_swapchain; + typedef struct { VkApplicationInfo definition; @@ -77,6 +93,7 @@ typedef struct { vulkan_debugging debugging; vulkan_devices devices; vulkan_queues queues; + vulkan_swapchain swapchain; vulkan_required_configuration required_configuration; } vulkan; From d230a330cdf477583198810ca0d7275a0a9a1cf7 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 8 Sep 2018 12:42:07 -0400 Subject: [PATCH 13/30] Make views of all images from the swapchain --- src/engine/graphics/vulkan/config.c | 15 ------- src/engine/graphics/vulkan/swapchain.c | 58 ++++++++++++++++++++++++-- src/engine/graphics/vulkan/vulkan.h | 7 ++++ 3 files changed, 61 insertions(+), 19 deletions(-) diff --git a/src/engine/graphics/vulkan/config.c b/src/engine/graphics/vulkan/config.c index 31f71ed..3f5fce8 100644 --- a/src/engine/graphics/vulkan/config.c +++ b/src/engine/graphics/vulkan/config.c @@ -10,26 +10,11 @@ const char *logical_extensions[NUM_LOGICAL_EXTENSIONS] = { bool vulkan_config_physical_device_is_suitable(VkPhysicalDevice device) { - static char *extensions = NULL; - static uint32_t num_extensions = 0; - static uint32_t current_num_extensions = 0; - VkPhysicalDeviceProperties properties; VkPhysicalDeviceFeatures features; vkGetPhysicalDeviceProperties(device, &properties); vkGetPhysicalDeviceFeatures(device, &features); -// vkEnumerateDeviceExtensionProperties(device, NULL, ¤t_num_extensions, NULL); -// -// if (extensions) { -// if (current_num_extensions > num_extensions) { -// -// } -// } else { -// extensions = malloc(sizeof(char*) * current_num_extensions); -// num_extensions = current_num_extensions; -// } - return properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && features.geometryShader; } diff --git a/src/engine/graphics/vulkan/swapchain.c b/src/engine/graphics/vulkan/swapchain.c index 315df31..d2a7436 100644 --- a/src/engine/graphics/vulkan/swapchain.c +++ b/src/engine/graphics/vulkan/swapchain.c @@ -81,14 +81,16 @@ uint32_t vulkan_swapchain_choose_image_count(vulkan *v) { } VkResult vulkan_swapchain_create(vulkan *v) { - VkSurfaceFormatKHR format = vulkan_swapchain_select_format(v); + v->swapchain.format = vulkan_swapchain_select_format(v); + v->swapchain.extent = vulkan_swapchain_choose_extent(v); + VkSwapchainCreateInfoKHR request = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .surface = v->surface, .minImageCount = vulkan_swapchain_choose_image_count(v), - .imageFormat = format.format, - .imageColorSpace = format.colorSpace, - .imageExtent = vulkan_swapchain_choose_extent(v), + .imageFormat = v->swapchain.format.format, + .imageColorSpace = v->swapchain.format.colorSpace, + .imageExtent = v->swapchain.extent, .imageArrayLayers = 1, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, @@ -114,6 +116,44 @@ VkResult vulkan_swapchain_create(vulkan *v) { return vkCreateSwapchainKHR(v->devices.logical_device, &request, NULL, &v->swapchain.swapchain); } +VkResult vulkan_swapchan_get_images(vulkan *v) { + + vkGetSwapchainImagesKHR(v->devices.logical_device, v->swapchain.swapchain, &v->swapchain.num_images, NULL); + v->swapchain.images = malloc(sizeof(VkImage) * v->swapchain.num_images); + return vkGetSwapchainImagesKHR(v->devices.logical_device, v->swapchain.swapchain, &v->swapchain.num_images, + v->swapchain.images); +} + +bool vulkan_swapchain_make_image_views(vulkan *v) { + v->swapchain.image_views = malloc(sizeof(VkImageView) * v->swapchain.num_images); + for (uint32_t i = 0; i < v->swapchain.num_images; i++) { + VkImageViewCreateInfo request = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = v->swapchain.images[i], + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = v->swapchain.format.format, + .components = { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + } + }; + + if (vkCreateImageView(v->devices.logical_device, &request, NULL, &v->swapchain.image_views[i]) != VK_SUCCESS) { + return false; + } + } + return true; +} + bool vulkan_swapchain_init(vulkan *v) { vkGetPhysicalDeviceSurfaceCapabilitiesKHR(v->devices.selected_device, v->surface, &v->swapchain.capabilities); vkGetPhysicalDeviceSurfaceFormatsKHR(v->devices.selected_device, v->surface, &v->swapchain.num_formats, NULL); @@ -138,5 +178,15 @@ bool vulkan_swapchain_init(vulkan *v) { return false; } + if (vulkan_swapchan_get_images(v) != VK_SUCCESS) { + printf("Failed to load images out of swapchain\n"); + return false; + } + + if (!vulkan_swapchain_make_image_views(v)) { + printf("Failed to make image views\n"); + return false; + } + return true; } \ No newline at end of file diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h index 51da582..3b4f779 100644 --- a/src/engine/graphics/vulkan/vulkan.h +++ b/src/engine/graphics/vulkan/vulkan.h @@ -71,7 +71,14 @@ typedef struct { } vulkan_required_configuration; typedef struct { + VkSurfaceFormatKHR format; + VkExtent2D extent; VkSwapchainKHR swapchain; + + VkImage *images; + VkImageView *image_views; + uint32_t num_images; + VkSurfaceCapabilitiesKHR capabilities; VkSurfaceFormatKHR *formats; From da9e03bcb8cbd6fcb40c3bf5384ca69837e4f572 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 8 Sep 2018 14:29:34 -0400 Subject: [PATCH 14/30] Add a glsl shader compiler into the project --- .gitmodules | 15 ++++++++++++ CMakeLists.txt | 36 ++++++++++++++++++++++++++--- README.md | 2 +- src/engine/graphics/vulkan/shader.c | 13 +++++++++++ src/engine/graphics/vulkan/shader.h | 8 +++++++ src/engine/graphics/vulkan/vulkan.c | 3 +++ tools/glslang | 1 + tools/googletest | 1 + tools/shaderc | 1 + tools/spirv-headers | 1 + tools/spirv-tools | 1 + 11 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 src/engine/graphics/vulkan/shader.c create mode 100644 src/engine/graphics/vulkan/shader.h create mode 160000 tools/glslang create mode 160000 tools/googletest create mode 160000 tools/shaderc create mode 160000 tools/spirv-headers create mode 160000 tools/spirv-tools diff --git a/.gitmodules b/.gitmodules index c56acc8..c45618c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,18 @@ path = vendor/glad url = git@github.com:Dav1dde/glad.git branch = master +[submodule "tools/shaderc"] + path = tools/shaderc + url = git@github.com:google/shaderc.git +[submodule "tools/googletest"] + path = tools/googletest + url = git@github.com:google/googletest.git +[submodule "tools/glslang"] + path = tools/glslang + url = git@github.com:google/glslang.git +[submodule "tools/spirv-tools"] + path = tools/spirv-tools + url = git@github.com:KhronosGroup/SPIRV-Tools.git +[submodule "tools/spirv-headers"] + path = tools/spirv-headers + url = git@github.com:KhronosGroup/SPIRV-Headers.git diff --git a/CMakeLists.txt b/CMakeLists.txt index f940936..a8bb6cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ project(engine) find_package(PythonInterp 2.7 REQUIRED) include(CheckCCompilerFlag) +include(ExternalProject) # Source: https://stackoverflow.com/a/33266748/1127064 function(enable_c_compiler_flag_if_supported flag) @@ -17,6 +18,33 @@ function(enable_c_compiler_flag_if_supported flag) endfunction() +# Build shaderc library for compiling glsl shaders +set(SHADERC_SYMLINKS + ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/glslang + ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/googletest + ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/spirv-headers + ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/spirv-tools) +add_custom_command( + OUTPUT ${SHADERC_SYMLINKS} + COMMAND ln -s ${CMAKE_SOURCE_DIR}/tools/glslang ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/glslang + COMMAND ln -s ${CMAKE_SOURCE_DIR}/tools/googletest ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/googletest + COMMAND ln -s ${CMAKE_SOURCE_DIR}/tools/spirv-headers ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/spirv-headers + COMMAND ln -s ${CMAKE_SOURCE_DIR}/tools/spirv-tools ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/spirv-tools +) +add_custom_target(shadercsymlinktarget + ALL + DEPENDS ${SHADERC_SYMLINKS}) +ExternalProject_Add(localshaderc + DEPENDS shadercsymlinktarget + PREFIX lib/shaderc + SOURCE_DIR ${CMAKE_SOURCE_DIR}/tools/shaderc/ + CONFIGURE_COMMAND cmake -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/lib/shaderc/ -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR}/tools/shaderc + BUILD_COMMAND make -j4 + INSTALL_COMMAND make install + ) +link_directories(${CMAKE_BINARY_DIR}/lib/shaderc/lib/) +include_directories(${CMAKE_BINARY_DIR}/lib/shaderc/include/shaderc) + # VENDOR DUKTAPE set(VENDOR_DUKTAPE_SOURCES ${CMAKE_SOURCE_DIR}/lib/duktape/duktape.c ${CMAKE_SOURCE_DIR}/lib/duktape/duktape.h ${CMAKE_SOURCE_DIR}/lib/duktape/duk_config.h ${CMAKE_SOURCE_DIR}/lib/duktape/duk_source_meta.json) add_custom_command( @@ -63,7 +91,7 @@ set(SOURCE_FILES src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h - src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h) + src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -71,10 +99,12 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_executable(engine ${SOURCE_FILES}) # VENDOR DUKTAPE -add_dependencies(engine localduktape localglad) +add_dependencies(engine localduktape localglad localshaderc) # GL, GLFW, DL, M -target_link_libraries(engine dl m glfw GL vulkan) +target_link_libraries(engine + dl m glfw GL vulkan + shaderc_combined stdc++ pthread) # STANDARDS set_property(TARGET engine PROPERTY C_STANDARD 99) diff --git a/README.md b/README.md index a8f1857..301f757 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ git pull --recursive-submodules | dl | N/A | Dynamically load libraries | | m | N/A | Standard math library | | GLFW3 | libglfw3-dev | GLFW 3 headers | -| GL | GPU drivers, N/A | OpenGL headers and libs | | Python 2 | python2 | Python 2 to build duktape | +| Ninja | ninja-build | Used by google's shaderc | ## Used Libraries diff --git a/src/engine/graphics/vulkan/shader.c b/src/engine/graphics/vulkan/shader.c new file mode 100644 index 0000000..16a0cc0 --- /dev/null +++ b/src/engine/graphics/vulkan/shader.c @@ -0,0 +1,13 @@ +#include "shader.h" + +shaderc_compiler_t compiler; + +void vulkan_shader_compiler_init() +{ + compiler = shaderc_compiler_initialize(); +} + +void vulkan_shader_init() +{ + vulkan_shader_compiler_init(); +} diff --git a/src/engine/graphics/vulkan/shader.h b/src/engine/graphics/vulkan/shader.h new file mode 100644 index 0000000..45f817d --- /dev/null +++ b/src/engine/graphics/vulkan/shader.h @@ -0,0 +1,8 @@ +#ifndef ENGINE_SHADER_H +#define ENGINE_SHADER_H + +#include + +void vulkan_shader_init(); + +#endif diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index 191a373..fad20de 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -10,6 +10,7 @@ #include "window.h" #include "surface.h" #include "swapchain.h" +#include "shader.h" vulkan v = { .definition = { @@ -103,6 +104,8 @@ bool vulkan_init() { return false; } + vulkan_shader_init(); + // Info to prove we have loaded everything vulkan_info_print(); diff --git a/tools/glslang b/tools/glslang new file mode 160000 index 0000000..1ca0f8e --- /dev/null +++ b/tools/glslang @@ -0,0 +1 @@ +Subproject commit 1ca0f8e8eb00b1a16286a9d46c150ffbf7a24aef diff --git a/tools/googletest b/tools/googletest new file mode 160000 index 0000000..34d5d22 --- /dev/null +++ b/tools/googletest @@ -0,0 +1 @@ +Subproject commit 34d5d22b6441fd7d91898a48097a18e29d137ace diff --git a/tools/shaderc b/tools/shaderc new file mode 160000 index 0000000..30af9f9 --- /dev/null +++ b/tools/shaderc @@ -0,0 +1 @@ +Subproject commit 30af9f9899aefd018669e81a5b8e605d14d40431 diff --git a/tools/spirv-headers b/tools/spirv-headers new file mode 160000 index 0000000..dcf23bd --- /dev/null +++ b/tools/spirv-headers @@ -0,0 +1 @@ +Subproject commit dcf23bdabacc3c54b83b1f9367e7a8adb27f8d87 diff --git a/tools/spirv-tools b/tools/spirv-tools new file mode 160000 index 0000000..40a6854 --- /dev/null +++ b/tools/spirv-tools @@ -0,0 +1 @@ +Subproject commit 40a68547dcda8b97d467a1d8264f626c63b50a60 From b1eaada67b1b4d4d3f8da1edeba3b09ed6e155ea Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 8 Sep 2018 14:32:46 -0400 Subject: [PATCH 15/30] Move from tools into libs folder --- .gitmodules | 10 +++++----- CMakeLists.txt | 20 ++++++++++---------- {tools => lib}/glslang | 0 {tools => lib}/googletest | 0 {tools => lib}/shaderc | 0 {tools => lib}/spirv-headers | 0 {tools => lib}/spirv-tools | 0 7 files changed, 15 insertions(+), 15 deletions(-) rename {tools => lib}/glslang (100%) rename {tools => lib}/googletest (100%) rename {tools => lib}/shaderc (100%) rename {tools => lib}/spirv-headers (100%) rename {tools => lib}/spirv-tools (100%) diff --git a/.gitmodules b/.gitmodules index c45618c..7cd924b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,17 +6,17 @@ url = git@github.com:Dav1dde/glad.git branch = master [submodule "tools/shaderc"] - path = tools/shaderc + path = lib/shaderc url = git@github.com:google/shaderc.git [submodule "tools/googletest"] - path = tools/googletest + path = lib/googletest url = git@github.com:google/googletest.git [submodule "tools/glslang"] - path = tools/glslang + path = lib/glslang url = git@github.com:google/glslang.git [submodule "tools/spirv-tools"] - path = tools/spirv-tools + path = lib/spirv-tools url = git@github.com:KhronosGroup/SPIRV-Tools.git [submodule "tools/spirv-headers"] - path = tools/spirv-headers + path = lib/spirv-headers url = git@github.com:KhronosGroup/SPIRV-Headers.git diff --git a/CMakeLists.txt b/CMakeLists.txt index a8bb6cc..1368270 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,16 +20,16 @@ endfunction() # Build shaderc library for compiling glsl shaders set(SHADERC_SYMLINKS - ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/glslang - ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/googletest - ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/spirv-headers - ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/spirv-tools) + ${CMAKE_SOURCE_DIR}/lib/shaderc/third_party/glslang + ${CMAKE_SOURCE_DIR}/lib/shaderc/third_party/googletest + ${CMAKE_SOURCE_DIR}/lib/shaderc/third_party/spirv-headers + ${CMAKE_SOURCE_DIR}/lib/shaderc/third_party/spirv-tools) add_custom_command( OUTPUT ${SHADERC_SYMLINKS} - COMMAND ln -s ${CMAKE_SOURCE_DIR}/tools/glslang ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/glslang - COMMAND ln -s ${CMAKE_SOURCE_DIR}/tools/googletest ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/googletest - COMMAND ln -s ${CMAKE_SOURCE_DIR}/tools/spirv-headers ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/spirv-headers - COMMAND ln -s ${CMAKE_SOURCE_DIR}/tools/spirv-tools ${CMAKE_SOURCE_DIR}/tools/shaderc/third_party/spirv-tools + COMMAND ln -s ${CMAKE_SOURCE_DIR}/lib/glslang ${CMAKE_SOURCE_DIR}/lib/shaderc/third_party/glslang + COMMAND ln -s ${CMAKE_SOURCE_DIR}/lib/googletest ${CMAKE_SOURCE_DIR}/lib/shaderc/third_party/googletest + COMMAND ln -s ${CMAKE_SOURCE_DIR}/lib/spirv-headers ${CMAKE_SOURCE_DIR}/lib/shaderc/third_party/spirv-headers + COMMAND ln -s ${CMAKE_SOURCE_DIR}/lib/spirv-tools ${CMAKE_SOURCE_DIR}/lib/shaderc/third_party/spirv-tools ) add_custom_target(shadercsymlinktarget ALL @@ -37,8 +37,8 @@ add_custom_target(shadercsymlinktarget ExternalProject_Add(localshaderc DEPENDS shadercsymlinktarget PREFIX lib/shaderc - SOURCE_DIR ${CMAKE_SOURCE_DIR}/tools/shaderc/ - CONFIGURE_COMMAND cmake -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/lib/shaderc/ -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR}/tools/shaderc + SOURCE_DIR ${CMAKE_SOURCE_DIR}/lib/shaderc/ + CONFIGURE_COMMAND cmake -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/lib/shaderc/ -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR}/lib/shaderc BUILD_COMMAND make -j4 INSTALL_COMMAND make install ) diff --git a/tools/glslang b/lib/glslang similarity index 100% rename from tools/glslang rename to lib/glslang diff --git a/tools/googletest b/lib/googletest similarity index 100% rename from tools/googletest rename to lib/googletest diff --git a/tools/shaderc b/lib/shaderc similarity index 100% rename from tools/shaderc rename to lib/shaderc diff --git a/tools/spirv-headers b/lib/spirv-headers similarity index 100% rename from tools/spirv-headers rename to lib/spirv-headers diff --git a/tools/spirv-tools b/lib/spirv-tools similarity index 100% rename from tools/spirv-tools rename to lib/spirv-tools From 146d3f11939425227174369e341df30c41385261 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 8 Sep 2018 15:05:28 -0400 Subject: [PATCH 16/30] Get a shader compiling during runtime --- CMakeLists.txt | 2 +- src/engine/graphics/vulkan/shader.c | 27 +++++++++++++++++++++++---- src/engine/graphics/vulkan/shader.h | 6 +++--- src/engine/graphics/vulkan/surface.c | 2 +- src/game/assets/shaders/apple.frag | 2 +- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1368270..c24786d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ ExternalProject_Add(localshaderc INSTALL_COMMAND make install ) link_directories(${CMAKE_BINARY_DIR}/lib/shaderc/lib/) -include_directories(${CMAKE_BINARY_DIR}/lib/shaderc/include/shaderc) +include_directories(${CMAKE_BINARY_DIR}/lib/shaderc/include) # VENDOR DUKTAPE set(VENDOR_DUKTAPE_SOURCES ${CMAKE_SOURCE_DIR}/lib/duktape/duktape.c ${CMAKE_SOURCE_DIR}/lib/duktape/duktape.h ${CMAKE_SOURCE_DIR}/lib/duktape/duk_config.h ${CMAKE_SOURCE_DIR}/lib/duktape/duk_source_meta.json) diff --git a/src/engine/graphics/vulkan/shader.c b/src/engine/graphics/vulkan/shader.c index 16a0cc0..041b5ec 100644 --- a/src/engine/graphics/vulkan/shader.c +++ b/src/engine/graphics/vulkan/shader.c @@ -1,13 +1,32 @@ +#include +#include #include "shader.h" shaderc_compiler_t compiler; -void vulkan_shader_compiler_init() -{ +void vulkan_shader_compiler_init() { compiler = shaderc_compiler_initialize(); } -void vulkan_shader_init() -{ + + +void vulkan_shader_init() { vulkan_shader_compiler_init(); + + char * source = read_file("assets/shaders/apple.frag"); + printf("%s\n", source); + shaderc_compilation_result_t result = shaderc_compile_into_spv( + compiler, + source, strlen(source), + shaderc_fragment_shader, + "apple.frag", + "main", + NULL + ); + shaderc_compilation_status status = shaderc_result_get_compilation_status(result); + printf("Shader compiling status: %d\n", status); + if (status != shaderc_compilation_status_success) { + printf("Failed to compile shader: %s\n", shaderc_result_get_error_message(result)); + } + shaderc_result_release(result); } diff --git a/src/engine/graphics/vulkan/shader.h b/src/engine/graphics/vulkan/shader.h index 45f817d..2a93042 100644 --- a/src/engine/graphics/vulkan/shader.h +++ b/src/engine/graphics/vulkan/shader.h @@ -1,7 +1,7 @@ -#ifndef ENGINE_SHADER_H -#define ENGINE_SHADER_H +#ifndef ENGINE_VULKAN_SHADER_H +#define ENGINE_VULKAN_SHADER_H -#include +#include void vulkan_shader_init(); diff --git a/src/engine/graphics/vulkan/surface.c b/src/engine/graphics/vulkan/surface.c index b7db906..c778844 100644 --- a/src/engine/graphics/vulkan/surface.c +++ b/src/engine/graphics/vulkan/surface.c @@ -2,4 +2,4 @@ bool vulkan_surface_init(vulkan *v) { return glfwCreateWindowSurface(v->instance, v->g.window, NULL, &v->surface) == VK_SUCCESS; -} \ No newline at end of file +} diff --git a/src/game/assets/shaders/apple.frag b/src/game/assets/shaders/apple.frag index b14776a..305745c 100644 --- a/src/game/assets/shaders/apple.frag +++ b/src/game/assets/shaders/apple.frag @@ -1,6 +1,6 @@ #version 330 core -out vec4 FragColor; +layout(location = 0) out vec4 FragColor; void main() { From 4c34c7b8ec9c1cc591c06d74c42884821e415c70 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 15 Sep 2018 15:38:53 -0400 Subject: [PATCH 17/30] Implement pipeline creation --- CMakeLists.txt | 2 +- src/engine/graphics/vulkan/pipeline.c | 236 ++++++++++++++++++++++++++ src/engine/graphics/vulkan/pipeline.h | 9 + src/engine/graphics/vulkan/shader.c | 130 ++++++++++++-- src/engine/graphics/vulkan/shader.h | 7 +- src/engine/graphics/vulkan/vulkan.c | 12 +- src/engine/graphics/vulkan/vulkan.h | 16 +- src/engine/graphics/vulkan/window.c | 15 +- src/engine/graphics/vulkan/window.h | 4 + src/game/assets/shaders/vt.frag | 8 + src/game/assets/shaders/vt.vert | 16 ++ 11 files changed, 432 insertions(+), 23 deletions(-) create mode 100644 src/engine/graphics/vulkan/pipeline.c create mode 100644 src/engine/graphics/vulkan/pipeline.h create mode 100644 src/game/assets/shaders/vt.frag create mode 100644 src/game/assets/shaders/vt.vert diff --git a/CMakeLists.txt b/CMakeLists.txt index c24786d..aac6ee9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ set(SOURCE_FILES src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h - src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h) + src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan/pipeline.c b/src/engine/graphics/vulkan/pipeline.c new file mode 100644 index 0000000..1118266 --- /dev/null +++ b/src/engine/graphics/vulkan/pipeline.c @@ -0,0 +1,236 @@ +#include +#include +#include "pipeline.h" +#include "window.h" +#include "shader.h" + + +static VkPipelineVertexInputStateCreateInfo vertext_input_state_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 0, + .pVertexBindingDescriptions = NULL, + .vertexAttributeDescriptionCount = 0, + .pVertexAttributeDescriptions = NULL +}; + + +static VkPipelineInputAssemblyStateCreateInfo input_assembly_state_create_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = VK_FALSE +}; + +static VkViewport viewport = { + .x = 0.0f, + .y = 0.0f, + .width = 0, // This will be configured later in the code + .height = 0, // This will be configured later in the code + .minDepth = 0.0f, + .maxDepth = 1.0f +}; + +static VkRect2D scissor = { + .offset = {0, 0}, + .extent = { + .height = 0, + .width = 0 + } // This will be configured later in the code +}; + +static VkPipelineViewportStateCreateInfo viewport_state_creation_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .pViewports = &viewport, + .scissorCount = 1, + .pScissors = &scissor +}; + +static VkPipelineRasterizationStateCreateInfo rasterizer = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .lineWidth = 1.0f, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + + + .depthBiasEnable = VK_FALSE, + .depthBiasConstantFactor = 0.0f, + .depthBiasClamp = 0.0f, + .depthBiasSlopeFactor = 0.0f, +}; + +static VkPipelineMultisampleStateCreateInfo multisampling = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .sampleShadingEnable = VK_FALSE, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .minSampleShading = 1.0f, + .pSampleMask = NULL, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE +}; + +static VkPipelineColorBlendAttachmentState color_blending_attachment_state = { + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT, + .blendEnable = VK_FALSE, + .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, + .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD, +}; + +static VkPipelineColorBlendStateCreateInfo color_blending = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = 1, + .pAttachments = &color_blending_attachment_state, + .blendConstants = { + 0.0f, + 0.0f, + 0.0f, + 0.0f + } +}; + +const VkDynamicState dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_LINE_WIDTH, +}; + +static VkPipelineDynamicStateCreateInfo dynamic_state_create_info = { + .sType= VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = 2, + .pDynamicStates = dynamic_states +}; + +bool vulkan_pipeline_render_pass_init(vulkan *v) { + VkAttachmentDescription color_attachment = { + .samples = VK_SAMPLE_COUNT_1_BIT, + .format = v->swapchain.format.format, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR + }; + VkAttachmentReference reference = { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; + VkSubpassDescription subpass = { + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + + .colorAttachmentCount = 1, + .pColorAttachments = &reference, + }; + + VkRenderPassCreateInfo render_pass_info = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + + .attachmentCount = 1, + .pAttachments = &color_attachment, + + .subpassCount = 1, + .pSubpasses = &subpass + }; + + + return vkCreateRenderPass( + v->devices.logical_device, + &render_pass_info, + NULL, + &v->pipelines.render_pass + ) == VK_SUCCESS; +} + +bool vulkan_pipeline_layout_init(vulkan *v) { + VkPipelineLayoutCreateInfo request = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = 0, + .pSetLayouts = NULL, + .pushConstantRangeCount = 0, + .pPushConstantRanges = NULL, + }; + + return vkCreatePipelineLayout(v->devices.logical_device, &request, NULL, &v->pipelines.layout) == VK_SUCCESS; +} + +bool vulkan_pipeline_graphics_init(vulkan *v) { + VkPipelineShaderStageCreateInfo stages[2]; + + if (!vulkan_shader_pipeline_shader_stage_get(VULKAN_SHADER_VERTEX_TEST, &stages[0])) { + return false; + } + + if (!vulkan_shader_pipeline_shader_stage_get(VULKAN_SHADER_FRAGMENT_TEST, &stages[1])) { + return false; + } + + VkGraphicsPipelineCreateInfo graphics_pipeline_create_info = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = 2, + .pStages = stages, + + .pVertexInputState = &vertext_input_state_create_info, + .pInputAssemblyState = &input_assembly_state_create_info, + .pViewportState = &viewport_state_creation_info, + .pRasterizationState = &rasterizer, + .pMultisampleState = &multisampling, + .pDepthStencilState = NULL, // Optional + .pColorBlendState = &color_blending, + .pDynamicState = NULL, // &dynamic_state_create_info, // Optional + + + .layout = v->pipelines.layout, + + .renderPass = v->pipelines.render_pass, + .subpass = 0, + + + .basePipelineHandle = VK_NULL_HANDLE, + //.basePipelineIndex = -1, + }; + + return vkCreateGraphicsPipelines( + v->devices.logical_device, + VK_NULL_HANDLE, + 1, + &graphics_pipeline_create_info, + NULL, + &v->pipelines.graphics + ) == VK_SUCCESS; +} + +bool vulkan_pipeline_init(vulkan *v) { + + // configure viewport size + viewport.width = vulkan_window_width_get(); + viewport.height = vulkan_window_height_get(); + + // configure swapchain extent + scissor.extent = v->swapchain.extent; + + + if (!vulkan_pipeline_layout_init(v)) { + printf("Failed to create pipeline layout\n"); + return false; + } + + if (!vulkan_pipeline_render_pass_init(v)) { + printf("Failed to initialize render pass\n"); + return false; + } + + if (!vulkan_pipeline_graphics_init(v)) { + printf("Failed to initialize graphics pipeline\n"); + return false; + } + + return true; +} diff --git a/src/engine/graphics/vulkan/pipeline.h b/src/engine/graphics/vulkan/pipeline.h new file mode 100644 index 0000000..7bf002d --- /dev/null +++ b/src/engine/graphics/vulkan/pipeline.h @@ -0,0 +1,9 @@ +#ifndef ENGINE_PIPELINE_H +#define ENGINE_PIPELINE_H + +#include +#include "vulkan.h" + +bool vulkan_pipeline_init(vulkan *v); + +#endif diff --git a/src/engine/graphics/vulkan/shader.c b/src/engine/graphics/vulkan/shader.c index 041b5ec..8981d58 100644 --- a/src/engine/graphics/vulkan/shader.c +++ b/src/engine/graphics/vulkan/shader.c @@ -2,31 +2,131 @@ #include #include "shader.h" +typedef struct { + char *file_name; + char *source; + const uint32_t *binary; + + VkPipelineShaderStageCreateInfo stage_info; + VkShaderModule module; + shaderc_compilation_result_t result; +} shader_data; + + +llist *compiled; shaderc_compiler_t compiler; void vulkan_shader_compiler_init() { compiler = shaderc_compiler_initialize(); } +static inline bool vulkan_shader_shaderc_kind_to_stage_bit(shaderc_shader_kind kind, VkShaderStageFlagBits *bits) { + if (kind == shaderc_glsl_vertex_shader) { + *bits = VK_SHADER_STAGE_VERTEX_BIT; + return true; + } + if (kind == shaderc_glsl_fragment_shader) { + *bits = VK_SHADER_STAGE_FRAGMENT_BIT; + return true; + } -void vulkan_shader_init() { - vulkan_shader_compiler_init(); + if (kind == shaderc_glsl_geometry_shader) { + *bits = VK_SHADER_STAGE_GEOMETRY_BIT; + return true; + } + + printf("Compiled unknown shaderc type\n"); + return false; +} - char * source = read_file("assets/shaders/apple.frag"); - printf("%s\n", source); - shaderc_compilation_result_t result = shaderc_compile_into_spv( +bool vulkan_shader_compile(vulkan *v, char *file_name, shaderc_shader_kind kind) { + shader_data *resource = malloc(sizeof(shader_data)); + resource->file_name = strdup(file_name); + resource->source = read_file(file_name); + resource->result = shaderc_compile_into_spv( compiler, - source, strlen(source), - shaderc_fragment_shader, - "apple.frag", - "main", - NULL + resource->source, strlen(resource->source), + kind, + file_name, + "main", // TODO: Configurable shaders? + NULL // TODO: Add preprocessor directives ); - shaderc_compilation_status status = shaderc_result_get_compilation_status(result); - printf("Shader compiling status: %d\n", status); - if (status != shaderc_compilation_status_success) { - printf("Failed to compile shader: %s\n", shaderc_result_get_error_message(result)); + + + // Was the compile successful? + if (shaderc_result_get_compilation_status(resource->result) != shaderc_compilation_status_success) { + printf("Failed to compile shader (%s): %s\n", file_name, shaderc_result_get_error_message(resource->result)); + return false; + } + + const char *binary = shaderc_result_get_bytes(resource->result); + resource->binary = (const uint32_t *) binary; + + VkShaderModuleCreateInfo request = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = shaderc_result_get_length(resource->result), + .pCode = resource->binary, + .pNext = NULL + }; + + if (vkCreateShaderModule(v->devices.logical_device, &request, NULL, &resource->module) != VK_SUCCESS) { + printf("Could not allocate shader on GPU: %s\n", file_name); + return false; + } + + + // Create pipeline stage info for vulkan configuration down the line + resource->stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + resource->stage_info.pName = "main"; + resource->stage_info.module = resource->module; + resource->stage_info.pNext = NULL; + resource->stage_info.pSpecializationInfo = NULL; + resource->stage_info.flags = 0; + + if (!vulkan_shader_shaderc_kind_to_stage_bit(kind, &resource->stage_info.stage)) { + return false; + } + + // Track shader + llist_add(&compiled, file_name, resource, sizeof(shader_data)); + + return true; +} + + +bool vulkan_shader_compile_all(vulkan *v) { + // TODO: Detect and load all shaders + return vulkan_shader_compile(v, VULKAN_SHADER_FRAGMENT_TEST, shaderc_fragment_shader) && + vulkan_shader_compile(v, VULKAN_SHADER_VERTEX_TEST, shaderc_glsl_vertex_shader); +} + +bool vulkan_shader_module_get(char *shader_file_name, VkShaderModule *module) { + shader_data *data = llist_get(&compiled, shader_file_name); + if (data) { + *module = data->module; + return true; } - shaderc_result_release(result); + return NULL; +} + +bool vulkan_shader_pipeline_shader_stage_get(char *shader_file_name, VkPipelineShaderStageCreateInfo *request) { + shader_data *data = llist_get(&compiled, shader_file_name); + if (data) { + *request = data->stage_info; + return true; + } + return NULL; +} + +bool vulkan_shader_init(vulkan *v) { + // Init the compiler library + vulkan_shader_compiler_init(); + + // Compile all of the shaders into SPIR-V Bytecode + if (!vulkan_shader_compile_all(v)) { + return false; + } + + return true; } diff --git a/src/engine/graphics/vulkan/shader.h b/src/engine/graphics/vulkan/shader.h index 2a93042..685e9c3 100644 --- a/src/engine/graphics/vulkan/shader.h +++ b/src/engine/graphics/vulkan/shader.h @@ -2,7 +2,12 @@ #define ENGINE_VULKAN_SHADER_H #include +#include "vulkan.h" -void vulkan_shader_init(); +#define VULKAN_SHADER_FRAGMENT_TEST "assets/shaders/vt.frag" +#define VULKAN_SHADER_VERTEX_TEST "assets/shaders/vt.vert" + +bool vulkan_shader_pipeline_shader_stage_get(char *shader_file_name, VkPipelineShaderStageCreateInfo *request); +bool vulkan_shader_init(vulkan *v); #endif diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index fad20de..f0f6aac 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -11,6 +11,7 @@ #include "surface.h" #include "swapchain.h" #include "shader.h" +#include "pipeline.h" vulkan v = { .definition = { @@ -104,7 +105,13 @@ bool vulkan_init() { return false; } - vulkan_shader_init(); + if (!vulkan_shader_init(&v)) { + return false; + } + + if (!vulkan_pipeline_init(&v)) { + return false; + } // Info to prove we have loaded everything vulkan_info_print(); @@ -112,6 +119,9 @@ bool vulkan_init() { return true; } +void vulkan_render() { + +} void vulkan_update() { vulkan_window_update(); diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h index 3b4f779..8d5bcb7 100644 --- a/src/engine/graphics/vulkan/vulkan.h +++ b/src/engine/graphics/vulkan/vulkan.h @@ -20,7 +20,6 @@ typedef struct { typedef struct { - /** * Info about available devices */ @@ -31,7 +30,7 @@ typedef struct { * The device we are currently rendering to */ VkPhysicalDevice selected_device; - VkDevice logical_device; + VkDevice logical_device; } vulkan_devices; typedef struct { @@ -52,7 +51,7 @@ typedef struct { uint32_t num_properties; VkQueueFamilyProperties *properties; - uint32_t num_queue_families; + uint32_t num_queue_families; uint32_t queue_families[2]; uint32_t main_rendering_queue_id; @@ -84,10 +83,16 @@ typedef struct { VkSurfaceFormatKHR *formats; uint32_t num_formats; - VkPresentModeKHR *modes; + VkPresentModeKHR *modes; uint32_t num_modes; } vulkan_swapchain; +typedef struct { + VkRenderPass render_pass; + VkPipelineLayout layout; + VkPipeline graphics; +} vulkan_pipelines; + typedef struct { VkApplicationInfo definition; @@ -101,13 +106,16 @@ typedef struct { vulkan_devices devices; vulkan_queues queues; vulkan_swapchain swapchain; + vulkan_pipelines pipelines; vulkan_required_configuration required_configuration; } vulkan; bool vulkan_init(); + void vulkan_update(); + void vulkan_cleanup(); #endif diff --git a/src/engine/graphics/vulkan/window.c b/src/engine/graphics/vulkan/window.c index 22bef15..56e74a1 100644 --- a/src/engine/graphics/vulkan/window.c +++ b/src/engine/graphics/vulkan/window.c @@ -12,7 +12,12 @@ bool vulkan_window_init(vulkan *v) { glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - window = v->g.window = glfwCreateWindow(SCREEN_W, SCREEN_H, "Solid Engine", NULL, NULL); + window = v->g.window = glfwCreateWindow( + vulkan_window_width_get(), vulkan_window_height_get(), + "Solid Engine", + NULL, + NULL + ); if (!v->g.window) { printf("Failed to create window!\n"); @@ -26,6 +31,14 @@ bool vulkan_window_init(vulkan *v) { return true; } +int vulkan_window_width_get() { + return SCREEN_W; +} + +int vulkan_window_height_get() { + return SCREEN_H; +} + void vulkan_window_update() { glfwPollEvents(); } diff --git a/src/engine/graphics/vulkan/window.h b/src/engine/graphics/vulkan/window.h index f578150..49c1614 100644 --- a/src/engine/graphics/vulkan/window.h +++ b/src/engine/graphics/vulkan/window.h @@ -16,4 +16,8 @@ void vulkan_window_update(); void vulkan_window_cleanup(); +int vulkan_window_width_get(); + +int vulkan_window_height_get(); + #endif diff --git a/src/game/assets/shaders/vt.frag b/src/game/assets/shaders/vt.frag new file mode 100644 index 0000000..7718cbd --- /dev/null +++ b/src/game/assets/shaders/vt.frag @@ -0,0 +1,8 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(1.0, 0.0, 0.0, 1.0); +} diff --git a/src/game/assets/shaders/vt.vert b/src/game/assets/shaders/vt.vert new file mode 100644 index 0000000..29474b2 --- /dev/null +++ b/src/game/assets/shaders/vt.vert @@ -0,0 +1,16 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +out gl_PerVertex { + vec4 gl_Position; +}; + +vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); +} \ No newline at end of file From 561da2f6e0055460d9bc00e6a1c46a4f7d3adfdf Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 15 Sep 2018 16:28:34 -0400 Subject: [PATCH 18/30] Enable recording on command buffers and start rendering fixed polygon sizes. --- CMakeLists.txt | 2 +- src/engine/graphics/vulkan/commandpool.c | 109 +++++++++++++++++++++++ src/engine/graphics/vulkan/commandpool.h | 8 ++ src/engine/graphics/vulkan/framebuffer.c | 33 +++++++ src/engine/graphics/vulkan/framebuffer.h | 10 +++ src/engine/graphics/vulkan/vulkan.c | 10 +++ src/engine/graphics/vulkan/vulkan.h | 3 + 7 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/engine/graphics/vulkan/commandpool.c create mode 100644 src/engine/graphics/vulkan/commandpool.h create mode 100644 src/engine/graphics/vulkan/framebuffer.c create mode 100644 src/engine/graphics/vulkan/framebuffer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index aac6ee9..baf0bbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ set(SOURCE_FILES src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h - src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h) + src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h src/engine/graphics/vulkan/framebuffer.c src/engine/graphics/vulkan/framebuffer.h src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan/commandpool.c b/src/engine/graphics/vulkan/commandpool.c new file mode 100644 index 0000000..ab72d9c --- /dev/null +++ b/src/engine/graphics/vulkan/commandpool.c @@ -0,0 +1,109 @@ +#include +#include +#include "commandpool.h" + +VkCommandBuffer *command_buffer; + +bool vulkan_command_pool_buffer_init(vulkan *v) { + command_buffer = malloc(sizeof(VkCommandBuffer) * v->swapchain.num_images); + VkCommandBufferAllocateInfo allocation_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = v->command_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = (uint32_t) v->swapchain.num_images + }; + + + if (vkAllocateCommandBuffers(v->devices.logical_device, &allocation_info, command_buffer) != VK_SUCCESS) { + printf("Failed to allocate command buffer for pool\n"); + return false; + } + + return true; +} + +bool vulkan_command_pool_buffer_recording_start(vulkan *v) { + for (size_t i = 0; i < v->swapchain.num_images; i++) { + VkCommandBufferBeginInfo command_buffer_begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, + .pInheritanceInfo = NULL + }; + + if (vkBeginCommandBuffer(command_buffer[i], &command_buffer_begin_info) != VK_SUCCESS) { + printf("Failed to start recording on command buffer %zu\n", i); + return false; + } + } + + return true; +} + + +bool vulkan_command_pool_render_pass_begin(vulkan *v) { + for (size_t i = 0; i < v->swapchain.num_images; i++) { + VkClearValue clear_color = { + .color.float32 = { + 0, 0, 0, 0 + } + }; + VkRenderPassBeginInfo render_pass_info = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = v->pipelines.render_pass, + .framebuffer = v->swapchain.frame_buffers[i], + .renderArea = { + .offset = {0, 0}, + .extent = v->swapchain.extent + }, + .clearValueCount = 1, + .pClearValues = &clear_color, + }; + + { + vkCmdBeginRenderPass(command_buffer[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); + { + vkCmdBindPipeline(command_buffer[i], VK_PIPELINE_BIND_POINT_GRAPHICS, v->pipelines.graphics); + + vkCmdDraw(command_buffer[i], 3, 1, 0, 0); + + } + vkCmdEndRenderPass(command_buffer[i]); + + + if (vkEndCommandBuffer(command_buffer[i]) != VK_SUCCESS) { + printf("Failed to end command buffer sequence when sending render job to %zu\n", i); + return false; + } + } + } + + return true; +} + +bool vulkan_command_pool_init(vulkan *v) { + VkCommandPoolCreateInfo poolInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = 0, + .queueFamilyIndex = v->queues.main_rendering_queue_id + }; + + + if (vkCreateCommandPool(v->devices.logical_device, &poolInfo, NULL, &v->command_pool) != VK_SUCCESS) { + printf("Failed to initialize command pool\n"); + return false; + } + + if (!vulkan_command_pool_buffer_init(v)) { + return false; + } + + if (!vulkan_command_pool_buffer_recording_start(v)) { + return false; + } + + if (!vulkan_command_pool_render_pass_begin(v)) { + return false; + } + + return true; +} diff --git a/src/engine/graphics/vulkan/commandpool.h b/src/engine/graphics/vulkan/commandpool.h new file mode 100644 index 0000000..35358bf --- /dev/null +++ b/src/engine/graphics/vulkan/commandpool.h @@ -0,0 +1,8 @@ +#ifndef ENGINE_CPOOL_H +#define ENGINE_CPOOL_H + +#include "vulkan.h" + +bool vulkan_command_pool_init(vulkan *v); + +#endif diff --git a/src/engine/graphics/vulkan/framebuffer.c b/src/engine/graphics/vulkan/framebuffer.c new file mode 100644 index 0000000..010b067 --- /dev/null +++ b/src/engine/graphics/vulkan/framebuffer.c @@ -0,0 +1,33 @@ +#include +#include "framebuffer.h" + +bool vulkan_framebuffer_init(vulkan *v) { + v->swapchain.frame_buffers = malloc(sizeof(VkFramebuffer) * v->swapchain.num_images); + + VkFramebufferCreateInfo framebuffer_create_info = { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .renderPass = v->pipelines.render_pass, + .attachmentCount = 1, + .pAttachments = NULL, // configured later + .width = v->swapchain.extent.width, + .height = v->swapchain.extent.height, + .layers = 1 + }; + + for (size_t i = 0; i < v->swapchain.num_images; i++) { + framebuffer_create_info.pAttachments = &v->swapchain.image_views[i]; + VkResult creation_result = vkCreateFramebuffer( + v->devices.logical_device, + &framebuffer_create_info, + NULL, + &v->swapchain.frame_buffers[i] + ); + + if (creation_result != VK_SUCCESS) { + printf("Failed to create vulkan framebuffer for swapchain image %zu\n", i); + return false; + } + } + + return true; +} diff --git a/src/engine/graphics/vulkan/framebuffer.h b/src/engine/graphics/vulkan/framebuffer.h new file mode 100644 index 0000000..f72e6bb --- /dev/null +++ b/src/engine/graphics/vulkan/framebuffer.h @@ -0,0 +1,10 @@ +#ifndef ENGINE_FRAMEBUFFER_H +#define ENGINE_FRAMEBUFFER_H + +#include +#include "vulkan.h" + +bool vulkan_framebuffer_init(vulkan *v); + +#endif + diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index f0f6aac..a12060f 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -12,6 +12,8 @@ #include "swapchain.h" #include "shader.h" #include "pipeline.h" +#include "framebuffer.h" +#include "commandpool.h" vulkan v = { .definition = { @@ -113,6 +115,14 @@ bool vulkan_init() { return false; } + if (!vulkan_framebuffer_init(&v)) { + return false; + } + + if (!vulkan_command_pool_init(&v)) { + return false; + } + // Info to prove we have loaded everything vulkan_info_print(); diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h index 8d5bcb7..f708713 100644 --- a/src/engine/graphics/vulkan/vulkan.h +++ b/src/engine/graphics/vulkan/vulkan.h @@ -85,6 +85,8 @@ typedef struct { VkPresentModeKHR *modes; uint32_t num_modes; + + VkFramebuffer *frame_buffers; } vulkan_swapchain; typedef struct { @@ -99,6 +101,7 @@ typedef struct { glfw g; VkInstance instance; VkSurfaceKHR surface; + VkCommandPool command_pool; vulkan_layers layers; vulkan_extensions extensions; From c260012e28b1358fdc367b50df79fc65b873121b Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 15 Sep 2018 16:55:43 -0400 Subject: [PATCH 19/30] Implement locking, depend on gpu provided subpasses, and command pool First triangle! --- CMakeLists.txt | 2 +- src/engine/graphics/vulkan/commandpool.c | 5 ++ src/engine/graphics/vulkan/commandpool.h | 1 + src/engine/graphics/vulkan/locking.c | 25 +++++++++ src/engine/graphics/vulkan/locking.h | 12 ++++ src/engine/graphics/vulkan/pipeline.c | 17 +++++- src/engine/graphics/vulkan/vulkan.c | 71 ++++++++++++++++++++++++ src/engine/graphics/vulkan/vulkan.h | 2 + src/engine/main.c | 1 + 9 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 src/engine/graphics/vulkan/locking.c create mode 100644 src/engine/graphics/vulkan/locking.h diff --git a/CMakeLists.txt b/CMakeLists.txt index baf0bbc..70c462d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ set(SOURCE_FILES src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h - src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h src/engine/graphics/vulkan/framebuffer.c src/engine/graphics/vulkan/framebuffer.h src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h) + src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h src/engine/graphics/vulkan/framebuffer.c src/engine/graphics/vulkan/framebuffer.h src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan/commandpool.c b/src/engine/graphics/vulkan/commandpool.c index ab72d9c..9c87dbb 100644 --- a/src/engine/graphics/vulkan/commandpool.c +++ b/src/engine/graphics/vulkan/commandpool.c @@ -4,6 +4,11 @@ VkCommandBuffer *command_buffer; +VkCommandBuffer *vulkan_command_pool_get(size_t pool_index) { + // TODO: Bounds checking + return &command_buffer[pool_index]; +} + bool vulkan_command_pool_buffer_init(vulkan *v) { command_buffer = malloc(sizeof(VkCommandBuffer) * v->swapchain.num_images); VkCommandBufferAllocateInfo allocation_info = { diff --git a/src/engine/graphics/vulkan/commandpool.h b/src/engine/graphics/vulkan/commandpool.h index 35358bf..2be6c76 100644 --- a/src/engine/graphics/vulkan/commandpool.h +++ b/src/engine/graphics/vulkan/commandpool.h @@ -4,5 +4,6 @@ #include "vulkan.h" bool vulkan_command_pool_init(vulkan *v); +VkCommandBuffer *vulkan_command_pool_get(size_t pool_index); #endif diff --git a/src/engine/graphics/vulkan/locking.c b/src/engine/graphics/vulkan/locking.c new file mode 100644 index 0000000..f42502f --- /dev/null +++ b/src/engine/graphics/vulkan/locking.c @@ -0,0 +1,25 @@ +#include "locking.h" + + +VkSemaphoreCreateInfo semaphore_create_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .flags = 0, + .pNext = NULL +}; + +VkSemaphore frame_buffer_image_available; +VkSemaphore rendering_finished; + +bool vulkan_locking_init(vulkan *v) { + VkDevice device = v->devices.logical_device; + return vkCreateSemaphore(device, &semaphore_create_info, NULL, &frame_buffer_image_available) == VK_SUCCESS && + vkCreateSemaphore(device, &semaphore_create_info, NULL, &rendering_finished) == VK_SUCCESS; +} + +VkSemaphore vulkan_locking_semphore_get_frame_buffer_image_available() { + return frame_buffer_image_available; +} + +VkSemaphore vulkan_locking_semphore_get_rendering_finished() { + return rendering_finished; +} diff --git a/src/engine/graphics/vulkan/locking.h b/src/engine/graphics/vulkan/locking.h new file mode 100644 index 0000000..d7a8fd5 --- /dev/null +++ b/src/engine/graphics/vulkan/locking.h @@ -0,0 +1,12 @@ +#ifndef ENGINE_LOCKING_H +#define ENGINE_LOCKING_H + +#include "vulkan.h" + + +bool vulkan_locking_init(vulkan *v); +VkSemaphore vulkan_locking_semphore_get_frame_buffer_image_available(); +VkSemaphore vulkan_locking_semphore_get_rendering_finished(); + +#endif + diff --git a/src/engine/graphics/vulkan/pipeline.c b/src/engine/graphics/vulkan/pipeline.c index 1118266..e1e5390 100644 --- a/src/engine/graphics/vulkan/pipeline.c +++ b/src/engine/graphics/vulkan/pipeline.c @@ -109,6 +109,17 @@ static VkPipelineDynamicStateCreateInfo dynamic_state_create_info = { }; bool vulkan_pipeline_render_pass_init(vulkan *v) { + + + VkSubpassDependency dependency = { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = 0, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT + }; + VkAttachmentDescription color_attachment = { .samples = VK_SAMPLE_COUNT_1_BIT, .format = v->swapchain.format.format, @@ -137,7 +148,10 @@ bool vulkan_pipeline_render_pass_init(vulkan *v) { .pAttachments = &color_attachment, .subpassCount = 1, - .pSubpasses = &subpass + .pSubpasses = &subpass, + + .dependencyCount = 1, + .pDependencies = &dependency }; @@ -172,6 +186,7 @@ bool vulkan_pipeline_graphics_init(vulkan *v) { return false; } + VkGraphicsPipelineCreateInfo graphics_pipeline_create_info = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .stageCount = 2, diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index a12060f..d00873d 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -14,6 +14,7 @@ #include "pipeline.h" #include "framebuffer.h" #include "commandpool.h" +#include "locking.h" vulkan v = { .definition = { @@ -111,6 +112,12 @@ bool vulkan_init() { return false; } + + if (!vulkan_locking_init(&v)) { + printf("Could not create locks\n"); + return false; + } + if (!vulkan_pipeline_init(&v)) { return false; } @@ -130,7 +137,71 @@ bool vulkan_init() { } void vulkan_render() { + uint32_t image_index; + vkAcquireNextImageKHR( + v.devices.logical_device, + v.swapchain.swapchain, + UINT64_MAX, + vulkan_locking_semphore_get_frame_buffer_image_available(), + VK_NULL_HANDLE, + &image_index + ); + + // Render starting configuration + VkSemaphore waiting_semaphores[] = { + vulkan_locking_semphore_get_frame_buffer_image_available() + }; + VkPipelineStageFlags stages[] = { + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + }; + + // Render ending configuration + VkSemaphore signaling_semaphores[] = { + vulkan_locking_semphore_get_rendering_finished() + }; + + + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = 1, + .pWaitSemaphores = waiting_semaphores, + .pWaitDstStageMask = stages, + + + // Link the command buffer to the render stage + .commandBufferCount = 1, + .pCommandBuffers = vulkan_command_pool_get(image_index), + + + // After rendering signal these semphores + .signalSemaphoreCount = 1, + .pSignalSemaphores = signaling_semaphores + }; + + // Submitting render job + if (vkQueueSubmit(v.queues.rendering, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { + printf("Failed to render!\n"); + } + + // Submitting presenting job + VkSwapchainKHR subscribing_swapchains[] = { + v.swapchain.swapchain + }; + + VkPresentInfoKHR present_info = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + // Subscribe + .waitSemaphoreCount = 1, + .pWaitSemaphores = signaling_semaphores, + + .swapchainCount = 1, + .pSwapchains = subscribing_swapchains, + .pImageIndices = &image_index, + + .pResults = NULL + }; + vkQueuePresentKHR(v.queues.presenting, &present_info); } void vulkan_update() { diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h index f708713..b71ec8e 100644 --- a/src/engine/graphics/vulkan/vulkan.h +++ b/src/engine/graphics/vulkan/vulkan.h @@ -119,6 +119,8 @@ bool vulkan_init(); void vulkan_update(); +void vulkan_render(); + void vulkan_cleanup(); #endif diff --git a/src/engine/main.c b/src/engine/main.c index 448e991..1841633 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -62,6 +62,7 @@ int main() { //glfwSwapBuffers(window); vulkan_update(); + vulkan_render(); } vulkan_cleanup(); From 36779935b4a54564cf9bda65c127656a3137b6af Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 15 Sep 2018 22:35:33 -0400 Subject: [PATCH 20/30] Implement base dictionary type --- CMakeLists.txt | 2 +- src/engine/main.c | 1 + src/engine/util/dict.c | 64 +++++++++++++++++++++++++++++ src/engine/util/dict.h | 64 +++++++++++++++++++++++++++++ src/engine/util/hashing/crc.c | 73 +++++++++++++++++++++++++++++++++ src/engine/util/hashing/crc.h | 18 +++++++++ src/engine/util/llist.c | 76 ++++++++++++++++++++++++++++------- src/engine/util/llist.h | 17 ++++++-- 8 files changed, 297 insertions(+), 18 deletions(-) create mode 100644 src/engine/util/dict.c create mode 100644 src/engine/util/dict.h create mode 100644 src/engine/util/hashing/crc.c create mode 100644 src/engine/util/hashing/crc.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 70c462d..c66e485 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ set(SOURCE_FILES src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h - src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h src/engine/graphics/vulkan/framebuffer.c src/engine/graphics/vulkan/framebuffer.h src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h) + src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h src/engine/graphics/vulkan/framebuffer.c src/engine/graphics/vulkan/framebuffer.h src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h src/engine/util/dict.c src/engine/util/dict.h src/engine/util/hashing/crc.c src/engine/util/hashing/crc.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/main.c b/src/engine/main.c index 1841633..32c2219 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "src/engine/scripting/callbacks.h" #include "src/engine/scripting/script.h" diff --git a/src/engine/util/dict.c b/src/engine/util/dict.c new file mode 100644 index 0000000..3d278a3 --- /dev/null +++ b/src/engine/util/dict.c @@ -0,0 +1,64 @@ +#include "dict.h" +#include +#include + +#include +#include + +typedef size_t bucket_index_t; + +/** + * Find the bucket index for this hash map + * @param d - Dictionary object + * @param name - Name of the pair + * @param length - Length of the name + * @return + */ +static inline bucket_index_t dict_bucket_for(dict *d, const char *const name, const size_t length) { + const uint_fast32_t hash = hashing_crc32_make(name, length); + const size_t num_buckets = d->num_buckets; + return (bucket_index_t) (hash % num_buckets); +} + +static inline bool dict_bucket_empty(dict *d, bucket_index_t i) { + return llist_empty(&d->buckets[i]); +} + + +dict *dict_init(size_t num_buckets) { + const size_t size_of_buckets = sizeof(llist *) * num_buckets; + dict *d = malloc(sizeof(dict) + size_of_buckets); + d->num_buckets = num_buckets; + memset(d->buckets, 0, size_of_buckets); + return d; +} + +bool dict_get(dict *d, const char *const name, void **value, size_t *length) { + const size_t len_name = strlen(name); + bucket_index_t index = dict_bucket_for(d, name, len_name); + + if (dict_bucket_empty(d, index)) { + return false; + } + + return llist_retrive(&d->buckets[index], name, value, length); +} + +bool dict_get_string(dict *d, const char *const name, char **value) { + return dict_get(d, name, (void **) value, NULL); +} + +bool dict_has(dict *d, const char *const name) { + return dict_get(d, name, NULL, NULL); +} + +void dict_set(dict *d, const char *const name, void *value, size_t length) { + const size_t len_name = strlen(name); + bucket_index_t index = dict_bucket_for(d, name, len_name); + llist_add(&d->buckets[index], name, value, length); +} + +void dict_set_string(dict *d, const char *const name, char *value) { + dict_set(d, name, value, strlen(value)); +} + diff --git a/src/engine/util/dict.h b/src/engine/util/dict.h new file mode 100644 index 0000000..ba12505 --- /dev/null +++ b/src/engine/util/dict.h @@ -0,0 +1,64 @@ +#ifndef ENGINE_UTIL_DICT_H +#define ENGINE_UTIL_DICT_H + +#include + +#define DICT_DEFAULT_NUM_BUCKETS 256 + +#define dict_new() dict_init(DICT_DEFAULT_NUM_BUCKETS) + +typedef struct { + size_t num_buckets; + llist *buckets[]; +} dict; + +dict *dict_init(size_t num_buckets); + +/** + * Get a value from the dictionary + * + * @param d + * @param name + * @param value + * @param length + * @return + */ +bool dict_get(dict *d, const char *name, void **value, size_t *length); + + +/** + * Check to see if a dictionary has a KV pair + * @param d + * @param name + * @return + */ +bool dict_has(dict *d, const char *name); + +/** + * Set a dictionary KV pair + * @param d + * @param name + * @param value + * @param length + */ +void dict_set(dict *d, const char *name, void *value, size_t length); + +/** + * Set a KV pair of strings + * @param d + * @param name + * @param value + */ +void dict_set_string(dict *d, const char *name, char *value); + + +/** + * Get a string from a K + * @param d + * @param name + * @param value + * @return + */ +bool dict_get_string(dict *d, const char *name, char **value); + +#endif diff --git a/src/engine/util/hashing/crc.c b/src/engine/util/hashing/crc.c new file mode 100644 index 0000000..60726eb --- /dev/null +++ b/src/engine/util/hashing/crc.c @@ -0,0 +1,73 @@ +#include "crc.h" + + +/** + * CRC32 magic table. Copied from the person who copied from the person who copied from the person (ad infinum) + * https://referencesource.microsoft.com/#System/sys/System/IO/compression/Crc32Helper.cs,3b31978c7d7f7246,references + */ +uint_fast32_t table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +}; + +uint_fast32_t hashing_crc32_make(const char *const data, size_t length) { + uint_fast32_t hash = 0xffffffff; + + for (size_t i = 0; i < length; i++) { + const size_t table_lookup_index = (hash ^ data[i]) & 0xff; + const uint_fast32_t table_value = table[table_lookup_index]; + hash = (hash >> 8) ^ table_value; + } + + return hash; +} diff --git a/src/engine/util/hashing/crc.h b/src/engine/util/hashing/crc.h new file mode 100644 index 0000000..1a4260a --- /dev/null +++ b/src/engine/util/hashing/crc.h @@ -0,0 +1,18 @@ +#ifndef ENGINE_UTIL_HASHING_CRC_H +#define ENGINE_UTIL_HASHING_CRC_H + +#include +#include + + +/** + * Hash a string using CRC32. + * Algorithm from https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm + * + * @param data Pointer to data + * @param length The size of the data block + * @return Hash of the data + */ +uint_fast32_t hashing_crc32_make(const char *data, size_t length); + +#endif diff --git a/src/engine/util/llist.c b/src/engine/util/llist.c index a6e1f9d..86eae9e 100644 --- a/src/engine/util/llist.c +++ b/src/engine/util/llist.c @@ -7,25 +7,44 @@ #include #include -void *llist_get(llist **head, const char * const name) -{ - llist const * tmp = *head; - while (tmp) - { +llist *llist_get_internal(llist **head, const char *const name) { + llist *tmp = *head; + while (tmp) { if (strcmp(name, tmp->name) == 0) - return tmp->value; + return tmp; tmp = tmp->next; } return NULL; } -bool llist_has(llist **head, const char * const name) -{ +void *llist_get(llist **head, const char *const name) { + llist const *tmp = llist_get_internal(head, name); + if (tmp) { + return tmp->value; + } + return NULL; +} + +bool llist_retrive(llist **head, const char *const name, void **value, size_t *length) { + llist const *tmp = llist_get_internal(head, name); + if (tmp) { + if (length) { + *length = tmp->length; + } + if (value) { + *value = tmp->value; + } + return true; + } + return false; +} + + +bool llist_has(llist **head, const char *const name) { return llist_get(head, name) != NULL; } -void llist_add(llist **head, const char * const name, const void * const value, size_t size) -{ +void llist_add(llist **head, const char *const name, const void *const value, size_t size) { // Allocate llist *next = malloc(sizeof(llist)); @@ -33,6 +52,13 @@ void llist_add(llist **head, const char * const name, const void * const value, next->value = malloc(size); next->name = strdup(name); next->next = *head; + next->length = size; + next->last = NULL; + + // Set last value + if (*head) { + (*head)->last = next; + } // Copy data into container memcpy(next->value, value, size); @@ -40,10 +66,32 @@ void llist_add(llist **head, const char * const name, const void * const value, *head = next; } -void llist_free(llist **head) -{ - while (*head) - { +void llist_remove(llist **head, const char *const name) { + llist *item = llist_get_internal(head, name); + + if (!item) { + return; + } + + if (item->last) { + item->last->next = item->next; + } + + if (item->next) { + item->next->last = item->last; + } + + free(item->value); + free(item->name); + free(item); +} + +bool llist_empty(llist **head) { + return *head == NULL; +} + +void llist_free(llist **head) { + while (*head) { llist *curr = *head; llist *next = curr->next; free(curr->name); diff --git a/src/engine/util/llist.h b/src/engine/util/llist.h index 1f09bb7..c45a617 100644 --- a/src/engine/util/llist.h +++ b/src/engine/util/llist.h @@ -9,15 +9,26 @@ #include struct llist_t { + struct llist_t *last; struct llist_t *next; char *name; void *value; + size_t length; }; typedef struct llist_t llist; -void *llist_get(llist **head, const char * const name); -bool llist_has(llist **head, const char * const name); -void llist_add(llist **head, const char * const name, const void * const value, size_t size); +void *llist_get(llist **head, const char *const name); + +bool llist_retrive(llist **head, const char *const name, void **value, size_t *length); + +bool llist_has(llist **head, const char *const name); + +void llist_add(llist **head, const char *const name, const void *const value, size_t size); + +void llist_remove(llist **head, const char *const name); + +bool llist_empty(llist **head); + void llist_free(llist **head); #endif //ENGINE_LLIST_H From f7194b5aa736951aa9f1f7c2172e45eed8ce62be Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sat, 15 Sep 2018 22:38:39 -0400 Subject: [PATCH 21/30] Organize CMakeLists file --- CMakeLists.txt | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c66e485..cf54888 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,10 +75,18 @@ add_custom_target(localglad set(SOURCE_FILES ${VENDOR_GLAD_SOURCES} ${VENDOR_DUKTAPE_SOURCES} src/engine/main.c + + # Scripting src/engine/scripting/interface.c src/engine/scripting/interface.h src/engine/scripting/script.h + + # Utilities src/engine/util/llist.c src/engine/util/llist.h src/engine/util/files.c src/engine/util/files.h + src/engine/util/dict.c src/engine/util/dict.h + src/engine/util/hashing/crc.c src/engine/util/hashing/crc.h + + # Engine source src/engine/graphics/quadmesh.c src/engine/graphics/quadmesh.h src/engine/graphics/shader.c src/engine/graphics/shader.h src/engine/graphics/texture.c src/engine/graphics/texture.h lib/stb/stb_image.h @@ -87,11 +95,21 @@ set(SOURCE_FILES src/engine/scripting/callbacks.c src/engine/scripting/callbacks.h src/engine/graphics/screen.c src/engine/graphics/screen.h + # Vulkan src/engine/graphics/vulkan/vulkan.c src/engine/graphics/vulkan/vulkan.h src/engine/graphics/vulkan/wrappers.h src/engine/graphics/vulkan/query.c src/engine/graphics/vulkan/query.h src/engine/graphics/vulkan/debug.c src/engine/graphics/vulkan/debug.h - src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h src/engine/graphics/vulkan/framebuffer.c src/engine/graphics/vulkan/framebuffer.h src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h src/engine/util/dict.c src/engine/util/dict.h src/engine/util/hashing/crc.c src/engine/util/hashing/crc.h) + src/engine/graphics/vulkan/config.c src/engine/graphics/vulkan/config.h + src/engine/graphics/vulkan/queues.c src/engine/graphics/vulkan/queues.h + src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h + src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h + src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h + src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h + src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h + src/engine/graphics/vulkan/framebuffer.c src/engine/graphics/vulkan/framebuffer.h + src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h + src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) From 9837bca0bfda9d21ee557711ed5ba1f968a59468 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Tue, 18 Sep 2018 22:09:56 -0400 Subject: [PATCH 22/30] Implement geometry shader into the engine. --- CMakeLists.txt | 19 ++++++----- src/engine/graphics/vulkan/pipeline.c | 14 +++++--- src/engine/graphics/vulkan/queues.c | 3 ++ src/engine/graphics/vulkan/shader.c | 3 +- src/engine/graphics/vulkan/shader.h | 1 + src/game/assets/shaders/vt.geom | 47 +++++++++++++++++++++++++++ src/game/assets/shaders/vt.vert | 14 ++++---- 7 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 src/game/assets/shaders/vt.geom diff --git a/CMakeLists.txt b/CMakeLists.txt index cf54888..8d64938 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,10 +114,20 @@ set(SOURCE_FILES set(CMAKE_INCLUDE_CURRENT_DIR ON) + + +# COPY SOURCE OF GAME INTO BUILD DIR +add_custom_target( + game_client_code + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/src/game/ + ${CMAKE_CURRENT_BINARY_DIR}/) + + add_executable(engine ${SOURCE_FILES}) # VENDOR DUKTAPE -add_dependencies(engine localduktape localglad localshaderc) +add_dependencies(engine localduktape localglad localshaderc game_client_code) # GL, GLFW, DL, M target_link_libraries(engine @@ -129,10 +139,3 @@ set_property(TARGET engine PROPERTY C_STANDARD 99) enable_c_compiler_flag_if_supported("-Wall") enable_c_compiler_flag_if_supported("-Wextra") enable_c_compiler_flag_if_supported("-pedantic") - -# COPY SOURCE OF GAME INTO BUILD DIR -add_custom_command( - TARGET engine POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/src/game/ - ${CMAKE_CURRENT_BINARY_DIR}/) diff --git a/src/engine/graphics/vulkan/pipeline.c b/src/engine/graphics/vulkan/pipeline.c index e1e5390..c5a62a6 100644 --- a/src/engine/graphics/vulkan/pipeline.c +++ b/src/engine/graphics/vulkan/pipeline.c @@ -16,7 +16,7 @@ static VkPipelineVertexInputStateCreateInfo vertext_input_state_create_info = { static VkPipelineInputAssemblyStateCreateInfo input_assembly_state_create_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, .primitiveRestartEnable = VK_FALSE }; @@ -176,20 +176,26 @@ bool vulkan_pipeline_layout_init(vulkan *v) { } bool vulkan_pipeline_graphics_init(vulkan *v) { - VkPipelineShaderStageCreateInfo stages[2]; + +#define NUM_SHADER_STAGES 3 + VkPipelineShaderStageCreateInfo stages[NUM_SHADER_STAGES]; if (!vulkan_shader_pipeline_shader_stage_get(VULKAN_SHADER_VERTEX_TEST, &stages[0])) { return false; } - if (!vulkan_shader_pipeline_shader_stage_get(VULKAN_SHADER_FRAGMENT_TEST, &stages[1])) { + if (!vulkan_shader_pipeline_shader_stage_get(VULKAN_SHADER_GEOMETRY_TEST, &stages[1])) { + return false; + } + + if (!vulkan_shader_pipeline_shader_stage_get(VULKAN_SHADER_FRAGMENT_TEST, &stages[2])) { return false; } VkGraphicsPipelineCreateInfo graphics_pipeline_create_info = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .stageCount = 2, + .stageCount = NUM_SHADER_STAGES, .pStages = stages, .pVertexInputState = &vertext_input_state_create_info, diff --git a/src/engine/graphics/vulkan/queues.c b/src/engine/graphics/vulkan/queues.c index ad2e8cc..94b6162 100644 --- a/src/engine/graphics/vulkan/queues.c +++ b/src/engine/graphics/vulkan/queues.c @@ -61,6 +61,9 @@ VkResult vulkan_queues_init_queue_family(vulkan *v, VkPhysicalDevice device, flo VkPhysicalDeviceFeatures device_features; memset(&device_features, 0, sizeof(VkPhysicalDeviceFeatures)); + // Geometry shaders enabled. TODO: Refactor + device_features.geometryShader = VK_TRUE; + VkDeviceCreateInfo request = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pQueueCreateInfos = queue_creations, diff --git a/src/engine/graphics/vulkan/shader.c b/src/engine/graphics/vulkan/shader.c index 8981d58..ebdf86a 100644 --- a/src/engine/graphics/vulkan/shader.c +++ b/src/engine/graphics/vulkan/shader.c @@ -98,7 +98,8 @@ bool vulkan_shader_compile(vulkan *v, char *file_name, shaderc_shader_kind kind) bool vulkan_shader_compile_all(vulkan *v) { // TODO: Detect and load all shaders return vulkan_shader_compile(v, VULKAN_SHADER_FRAGMENT_TEST, shaderc_fragment_shader) && - vulkan_shader_compile(v, VULKAN_SHADER_VERTEX_TEST, shaderc_glsl_vertex_shader); + vulkan_shader_compile(v, VULKAN_SHADER_VERTEX_TEST, shaderc_glsl_vertex_shader) && + vulkan_shader_compile(v, VULKAN_SHADER_GEOMETRY_TEST, shaderc_glsl_geometry_shader); } bool vulkan_shader_module_get(char *shader_file_name, VkShaderModule *module) { diff --git a/src/engine/graphics/vulkan/shader.h b/src/engine/graphics/vulkan/shader.h index 685e9c3..33143dc 100644 --- a/src/engine/graphics/vulkan/shader.h +++ b/src/engine/graphics/vulkan/shader.h @@ -6,6 +6,7 @@ #define VULKAN_SHADER_FRAGMENT_TEST "assets/shaders/vt.frag" #define VULKAN_SHADER_VERTEX_TEST "assets/shaders/vt.vert" +#define VULKAN_SHADER_GEOMETRY_TEST "assets/shaders/vt.geom" bool vulkan_shader_pipeline_shader_stage_get(char *shader_file_name, VkPipelineShaderStageCreateInfo *request); bool vulkan_shader_init(vulkan *v); diff --git a/src/game/assets/shaders/vt.geom b/src/game/assets/shaders/vt.geom new file mode 100644 index 0000000..3e39d10 --- /dev/null +++ b/src/game/assets/shaders/vt.geom @@ -0,0 +1,47 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + + +// Terrible but only resource: https://www.khronos.org/opengl/wiki/Geometry_Shader +layout (points) in; +layout (triangle_strip, max_vertices = 3) out; + +out gl_PerVertex { + vec4 gl_Position; +}; + +float triangle_radius = 0.5f; + +vec4 triangle_first(vec4 triangle_center_position) { + return triangle_center_position + vec4(0.0f, -triangle_radius, 0.0f, 0.0f); +} + +vec4 triangle_second(vec4 triangle_center_position) { + return triangle_center_position + vec4(triangle_radius, triangle_radius, 0.0f, 0.0f); +} + +vec4 triangle_third(vec4 triangle_center_position) { + return triangle_center_position + vec4(-triangle_radius, triangle_radius, 0.0f, 0.0f); +} + + +void main(void) +{ + + for(int i = 0; i < gl_in.length(); i++) + { + { + gl_Position = triangle_first(gl_in[i].gl_Position); + EmitVertex(); + + gl_Position = triangle_second(gl_in[i].gl_Position); + EmitVertex(); + + gl_Position = triangle_third(gl_in[i].gl_Position); + EmitVertex(); + } + EndPrimitive(); + } +} \ No newline at end of file diff --git a/src/game/assets/shaders/vt.vert b/src/game/assets/shaders/vt.vert index 29474b2..1542456 100644 --- a/src/game/assets/shaders/vt.vert +++ b/src/game/assets/shaders/vt.vert @@ -5,12 +5,14 @@ out gl_PerVertex { vec4 gl_Position; }; -vec2 positions[3] = vec2[]( - vec2(0.0, -0.5), - vec2(0.5, 0.5), - vec2(-0.5, 0.5) -); +//vec2 positions[3] = vec2[]( +// vec2(0.0, -0.5), +// vec2(0.5, 0.5), +// vec2(-0.5, 0.5) +//); + +vec2 triangle_center_pos = vec2(0, 0); void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + gl_Position = vec4(triangle_center_pos, 0.0, 1.0); } \ No newline at end of file From d1c1f564ec17c34373b315be1ef80a31b0b86c18 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Wed, 19 Sep 2018 23:18:34 -0400 Subject: [PATCH 23/30] Send a vertex buffer to the GPU and use it as the position of our triangle. --- CMakeLists.txt | 4 +- src/engine/graphics/vulkan/commandpool.c | 14 +++- src/engine/graphics/vulkan/commandpool.h | 2 +- src/engine/graphics/vulkan/memory.c | 73 +++++++++++++++++++ src/engine/graphics/vulkan/memory.h | 26 +++++++ src/engine/graphics/vulkan/pipeline.c | 30 ++++++-- .../graphics/vulkan/{ => shaders}/shader.c | 0 .../graphics/vulkan/{ => shaders}/shader.h | 6 +- src/engine/graphics/vulkan/shaders/vbuffer.c | 47 ++++++++++++ src/engine/graphics/vulkan/shaders/vbuffer.h | 23 ++++++ src/engine/graphics/vulkan/vulkan.c | 33 ++++++++- src/engine/graphics/vulkan/window.c | 13 ++++ src/engine/graphics/vulkan/window.h | 5 ++ src/engine/util/bits.h | 7 ++ src/game/assets/shaders/vt.vert | 2 +- 15 files changed, 267 insertions(+), 18 deletions(-) create mode 100644 src/engine/graphics/vulkan/memory.c create mode 100644 src/engine/graphics/vulkan/memory.h rename src/engine/graphics/vulkan/{ => shaders}/shader.c (100%) rename src/engine/graphics/vulkan/{ => shaders}/shader.h (74%) create mode 100644 src/engine/graphics/vulkan/shaders/vbuffer.c create mode 100644 src/engine/graphics/vulkan/shaders/vbuffer.h create mode 100644 src/engine/util/bits.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d64938..cbe339f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,11 +105,11 @@ set(SOURCE_FILES src/engine/graphics/vulkan/surface.c src/engine/graphics/vulkan/surface.h src/engine/graphics/vulkan/window.c src/engine/graphics/vulkan/window.h src/engine/graphics/vulkan/swapchain.c src/engine/graphics/vulkan/swapchain.h - src/engine/graphics/vulkan/shader.c src/engine/graphics/vulkan/shader.h + src/engine/graphics/vulkan/shaders/shader.c src/engine/graphics/vulkan/shaders/shader.h src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h src/engine/graphics/vulkan/framebuffer.c src/engine/graphics/vulkan/framebuffer.h src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h - src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h) + src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h src/engine/graphics/vulkan/shaders/vbuffer.c src/engine/graphics/vulkan/shaders/vbuffer.h src/engine/graphics/vulkan/memory.c src/engine/graphics/vulkan/memory.h src/engine/util/bits.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan/commandpool.c b/src/engine/graphics/vulkan/commandpool.c index 9c87dbb..9e4943e 100644 --- a/src/engine/graphics/vulkan/commandpool.c +++ b/src/engine/graphics/vulkan/commandpool.c @@ -1,5 +1,6 @@ #include #include +#include #include "commandpool.h" VkCommandBuffer *command_buffer; @@ -45,7 +46,7 @@ bool vulkan_command_pool_buffer_recording_start(vulkan *v) { } -bool vulkan_command_pool_render_pass_begin(vulkan *v) { +bool vulkan_command_pool_render_pass_begin(vulkan *v, vbuffer *buffer) { for (size_t i = 0; i < v->swapchain.num_images; i++) { VkClearValue clear_color = { .color.float32 = { @@ -69,7 +70,12 @@ bool vulkan_command_pool_render_pass_begin(vulkan *v) { { vkCmdBindPipeline(command_buffer[i], VK_PIPELINE_BIND_POINT_GRAPHICS, v->pipelines.graphics); - vkCmdDraw(command_buffer[i], 3, 1, 0, 0); + // TODO: How the fuck to I get this buffer data into here?! + VkBuffer vertexBuffers[] = {buffer->buffer}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(command_buffer[i], 0, 1, vertexBuffers, offsets); + + vkCmdDraw(command_buffer[i], (uint32_t) buffer->num_elements, 1, 0, 0); } vkCmdEndRenderPass(command_buffer[i]); @@ -85,7 +91,7 @@ bool vulkan_command_pool_render_pass_begin(vulkan *v) { return true; } -bool vulkan_command_pool_init(vulkan *v) { +bool vulkan_command_pool_init(vulkan *v, vbuffer *buffer) { VkCommandPoolCreateInfo poolInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .flags = 0, @@ -106,7 +112,7 @@ bool vulkan_command_pool_init(vulkan *v) { return false; } - if (!vulkan_command_pool_render_pass_begin(v)) { + if (!vulkan_command_pool_render_pass_begin(v, buffer)) { return false; } diff --git a/src/engine/graphics/vulkan/commandpool.h b/src/engine/graphics/vulkan/commandpool.h index 2be6c76..2277ae1 100644 --- a/src/engine/graphics/vulkan/commandpool.h +++ b/src/engine/graphics/vulkan/commandpool.h @@ -3,7 +3,7 @@ #include "vulkan.h" -bool vulkan_command_pool_init(vulkan *v); +bool vulkan_command_pool_init(vulkan *v, vbuffer *buffer); VkCommandBuffer *vulkan_command_pool_get(size_t pool_index); #endif diff --git a/src/engine/graphics/vulkan/memory.c b/src/engine/graphics/vulkan/memory.c new file mode 100644 index 0000000..f836116 --- /dev/null +++ b/src/engine/graphics/vulkan/memory.c @@ -0,0 +1,73 @@ +#include +#include "memory.h" + +vulkan_device_memory_info info; + +static inline bool vulkan_memory_properties_has_all_desired_features( + const VkMemoryPropertyFlags available, + const VkMemoryPropertyFlags desired +) { + return IS_EVERY_BIT_SET(available, desired); +} + +uint32_t vulkan_memory_type_find(uint32_t memory_type_mask, VkMemoryPropertyFlags properties) { + for (uint32_t i = 0; i < info.properties.memoryTypeCount; i++) { + const VkMemoryPropertyFlags memory_type_properties = info.properties.memoryTypes[i].propertyFlags; + + if (!IS_BIT_SET(memory_type_mask, i)) { + continue; + } + + if (!vulkan_memory_properties_has_all_desired_features(memory_type_properties, properties)) { + continue; + } + + return i; + } + + return UINT32_MAX; +} + +// TODO: Implement memory mapping, flushing mapped memory, and invalidating mapped memory caches. +// TODO: Move memory mapping out of vbuffer.c/h + +bool vulkan_memory_allocate( + const vulkan *const v, + const uint32_t memory_type_mask, + const VkMemoryPropertyFlags properties, + const uint32_t size, + VkDeviceMemory *const memory +) { + + // If you don't store the memory address we refuse to allocate anything + if (!memory) { + return false; + } + + // Memory index that supports our variable filter flags + uint32_t memory_type_index = vulkan_memory_type_find(memory_type_mask, properties); + + if (memory_type_index == UINT32_MAX) { + return false; + } + + VkMemoryAllocateInfo memory_allocation_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = size, + .memoryTypeIndex = memory_type_index + }; + + return vkAllocateMemory(v->devices.logical_device, &memory_allocation_info, NULL, memory) == VK_SUCCESS; +} + +void vukan_memory_free( + const vulkan *const v, + VkDeviceMemory memory +) { + vkFreeMemory(v->devices.logical_device, memory, NULL); +} + +bool vulkan_memory_init(vulkan *v) { + vkGetPhysicalDeviceMemoryProperties(v->devices.selected_device, &info.properties); + return true; +} diff --git a/src/engine/graphics/vulkan/memory.h b/src/engine/graphics/vulkan/memory.h new file mode 100644 index 0000000..8df2110 --- /dev/null +++ b/src/engine/graphics/vulkan/memory.h @@ -0,0 +1,26 @@ +#ifndef ENGINE_MEMORY_H +#define ENGINE_MEMORY_H + +#include +#include "vulkan.h" + +typedef struct { + VkPhysicalDeviceMemoryProperties properties; +} vulkan_device_memory_info; + +bool vulkan_memory_allocate( + const vulkan *v, + uint32_t memory_type_mask, + VkMemoryPropertyFlags properties, + uint32_t size, + VkDeviceMemory *memory +); + +void vukan_memory_free( + const vulkan *v, + VkDeviceMemory memory +); + +bool vulkan_memory_init(vulkan *v); + +#endif diff --git a/src/engine/graphics/vulkan/pipeline.c b/src/engine/graphics/vulkan/pipeline.c index c5a62a6..29f941f 100644 --- a/src/engine/graphics/vulkan/pipeline.c +++ b/src/engine/graphics/vulkan/pipeline.c @@ -1,16 +1,36 @@ #include #include +#include #include "pipeline.h" #include "window.h" -#include "shader.h" +#include "src/engine/graphics/vulkan/shaders/shader.h" +#define NUM_VERTEX_INPUT_BINDING_ATTRIBUTE_DESCRIPTIONS 1 +static VkVertexInputAttributeDescription vertex_input_binding_attrbute_descriptions[NUM_VERTEX_INPUT_BINDING_ATTRIBUTE_DESCRIPTIONS] = { + { + .binding = 0, + .offset = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .location = 0 + } +}; + +#define NUM_VERTEX_INPUT_BINDING_DESCRIPTIONS 1 +static VkVertexInputBindingDescription vertex_input_binding_description[NUM_VERTEX_INPUT_BINDING_DESCRIPTIONS] = { + { + .binding = 0, + .stride = sizeof(vec2), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX + } +}; + static VkPipelineVertexInputStateCreateInfo vertext_input_state_create_info = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .vertexBindingDescriptionCount = 0, - .pVertexBindingDescriptions = NULL, - .vertexAttributeDescriptionCount = 0, - .pVertexAttributeDescriptions = NULL + .vertexBindingDescriptionCount = NUM_VERTEX_INPUT_BINDING_DESCRIPTIONS, + .pVertexBindingDescriptions = vertex_input_binding_description, + .vertexAttributeDescriptionCount = NUM_VERTEX_INPUT_BINDING_ATTRIBUTE_DESCRIPTIONS, + .pVertexAttributeDescriptions = vertex_input_binding_attrbute_descriptions }; diff --git a/src/engine/graphics/vulkan/shader.c b/src/engine/graphics/vulkan/shaders/shader.c similarity index 100% rename from src/engine/graphics/vulkan/shader.c rename to src/engine/graphics/vulkan/shaders/shader.c diff --git a/src/engine/graphics/vulkan/shader.h b/src/engine/graphics/vulkan/shaders/shader.h similarity index 74% rename from src/engine/graphics/vulkan/shader.h rename to src/engine/graphics/vulkan/shaders/shader.h index 33143dc..dd2bba0 100644 --- a/src/engine/graphics/vulkan/shader.h +++ b/src/engine/graphics/vulkan/shaders/shader.h @@ -1,8 +1,8 @@ -#ifndef ENGINE_VULKAN_SHADER_H -#define ENGINE_VULKAN_SHADER_H +#ifndef ENGINE_VULKAN_SHADERS_SHADER_H +#define ENGINE_VULKAN_SHADERS_SHADER_H #include -#include "vulkan.h" +#include "src/engine/graphics/vulkan/vulkan.h" #define VULKAN_SHADER_FRAGMENT_TEST "assets/shaders/vt.frag" #define VULKAN_SHADER_VERTEX_TEST "assets/shaders/vt.vert" diff --git a/src/engine/graphics/vulkan/shaders/vbuffer.c b/src/engine/graphics/vulkan/shaders/vbuffer.c new file mode 100644 index 0000000..4cf43b3 --- /dev/null +++ b/src/engine/graphics/vulkan/shaders/vbuffer.c @@ -0,0 +1,47 @@ +#include +#include +#include "vbuffer.h" + +const VkMemoryPropertyFlags vbuffer_memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + +bool vulkan_vbuffer_allocate(vulkan *v, vbuffer *buffer, uint32_t element_size, uint32_t num_elements, + bool map_memory_region) { + const uint32_t size = element_size * num_elements; + + // Clear out old vbuffer + memset(buffer, 0, sizeof(vbuffer)); + + // Engine metadata + buffer->element_size = element_size; + buffer->num_elements = num_elements; + + // Set up buffer dimension info + buffer->info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer->info.size = size; + buffer->info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + buffer->info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if (vkCreateBuffer(v->devices.logical_device, &buffer->info, NULL, &buffer->buffer) != VK_SUCCESS) { + return false; + } + + vkGetBufferMemoryRequirements(v->devices.logical_device, buffer->buffer, &buffer->required_memory); + + if (!vulkan_memory_allocate(v, buffer->required_memory.memoryTypeBits, vbuffer_memory_properties, size, &buffer->memory)) { + return false; + } + + // Bind the memory to the new buffer + if (vkBindBufferMemory(v->devices.logical_device, buffer->buffer, buffer->memory, 0) != VK_SUCCESS) { + return false; + } + + if (map_memory_region) { + // Map memory location into trapped page (I guess?) + if (vkMapMemory(v->devices.logical_device, buffer->memory, 0, buffer->info.size, 0, &buffer->mapped_memory) != VK_SUCCESS) { + return false; + } + } + + return true; +} diff --git a/src/engine/graphics/vulkan/shaders/vbuffer.h b/src/engine/graphics/vulkan/shaders/vbuffer.h new file mode 100644 index 0000000..ea45d62 --- /dev/null +++ b/src/engine/graphics/vulkan/shaders/vbuffer.h @@ -0,0 +1,23 @@ +#ifndef ENGINE_GRAPHICS_VULKAN_SHADERS_VBUFFER_H +#define ENGINE_GRAPHICS_VULKAN_SHADERS_VBUFFER_H + + +#include +#include +#include + +typedef struct { + VkBufferCreateInfo info; + VkBuffer buffer; + VkMemoryRequirements required_memory; + VkDeviceMemory memory; + size_t element_size; + size_t num_elements; + void *mapped_memory; +} vbuffer; + + +bool vulkan_vbuffer_allocate(vulkan *v, vbuffer *buffer, uint32_t element_size, uint32_t num_elements, + bool map_memory_region); + +#endif diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index d00873d..bfec9de 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include #include "query.h" #include "vulkan.h" #include "config.h" @@ -10,11 +13,12 @@ #include "window.h" #include "surface.h" #include "swapchain.h" -#include "shader.h" +#include "src/engine/graphics/vulkan/shaders/shader.h" #include "pipeline.h" #include "framebuffer.h" #include "commandpool.h" #include "locking.h" +#include "memory.h" vulkan v = { .definition = { @@ -28,6 +32,8 @@ vulkan v = { .devices.selected_device = VK_NULL_HANDLE }; +vec2 triangle_center_position; +vbuffer triangle_position_buffer; VkResult vulkan_create_instance() { VkInstanceCreateInfo creation_request = { @@ -126,7 +132,20 @@ bool vulkan_init() { return false; } - if (!vulkan_command_pool_init(&v)) { + if (!vulkan_memory_init(&v)) { + printf("Failed to init memory\n"); + return false; + } + + // TODO: Do not allocate this here. This is game state logic + if (!vulkan_vbuffer_allocate(&v, &triangle_position_buffer, sizeof(vec2), 1, true)) { + printf("Failed allocate buffer\n"); + return false; + } + + // TODO: We should NOT be passing the triangle position buffer in like this + if (!vulkan_command_pool_init(&v, &triangle_position_buffer)) { + printf("Failed to init command pool\n"); return false; } @@ -137,6 +156,16 @@ bool vulkan_init() { } void vulkan_render() { + + /** + * set triangle position + */ + triangle_center_position[0] = (cursor_x - (vulkan_window_width_get() / 2.0f)) / vulkan_window_width_get(); + triangle_center_position[1] = (cursor_y - (vulkan_window_height_get() / 2.0f)) / vulkan_window_height_get(); + + // send to gpu via memory mapped region + memcpy(triangle_position_buffer.mapped_memory, &triangle_center_position, sizeof(vec2) * 1); + uint32_t image_index; vkAcquireNextImageKHR( v.devices.logical_device, diff --git a/src/engine/graphics/vulkan/window.c b/src/engine/graphics/vulkan/window.c index 56e74a1..a391099 100644 --- a/src/engine/graphics/vulkan/window.c +++ b/src/engine/graphics/vulkan/window.c @@ -5,6 +5,17 @@ GLFWwindow *window; +volatile float cursor_x; +volatile float cursor_y; + +void vulkan_on_mouse_move(GLFWwindow *window, double x, double y) +{ + (void) window; + cursor_x = (float) x; + cursor_y = (float) y; +} + + bool vulkan_window_init(vulkan *v) { glfwInit(); @@ -25,6 +36,8 @@ bool vulkan_window_init(vulkan *v) { return false; } + // TODO: Move into it's own location + glfwSetCursorPosCallback(v->g.window, vulkan_on_mouse_move); glfwMakeContextCurrent(v->g.window); diff --git a/src/engine/graphics/vulkan/window.h b/src/engine/graphics/vulkan/window.h index 49c1614..ec179c3 100644 --- a/src/engine/graphics/vulkan/window.h +++ b/src/engine/graphics/vulkan/window.h @@ -8,6 +8,11 @@ #define SCREEN_W 400 #define SCREEN_H 400 +// this shouldn't be the way this is done +extern volatile float cursor_x; +extern volatile float cursor_y; + + bool vulkan_window_init(vulkan *v); bool vulkan_window_is_close_requested(); diff --git a/src/engine/util/bits.h b/src/engine/util/bits.h new file mode 100644 index 0000000..e86e9b8 --- /dev/null +++ b/src/engine/util/bits.h @@ -0,0 +1,7 @@ +#ifndef ENGINE_UTIL_BITS_H +#define ENGINE_UTIL_BITS_H + +#define IS_BIT_SET(number, index) (number & (1 << index)) +#define IS_EVERY_BIT_SET(number, mask) ((number & mask) == mask) + +#endif diff --git a/src/game/assets/shaders/vt.vert b/src/game/assets/shaders/vt.vert index 1542456..cd651a7 100644 --- a/src/game/assets/shaders/vt.vert +++ b/src/game/assets/shaders/vt.vert @@ -11,7 +11,7 @@ out gl_PerVertex { // vec2(-0.5, 0.5) //); -vec2 triangle_center_pos = vec2(0, 0); +layout(location = 0) in vec2 triangle_center_pos; void main() { gl_Position = vec4(triangle_center_pos, 0.0, 1.0); From f18a9aa6c2c267083a82278daaef6f372ff594fc Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sun, 23 Sep 2018 10:56:54 -0400 Subject: [PATCH 24/30] Reformat code and improve the layout of the shader compilation --- src/engine/graphics/vulkan/pipeline.c | 386 ++++++++++---------- src/engine/graphics/vulkan/shaders/shader.c | 228 ++++++------ src/engine/graphics/vulkan/shaders/shader.h | 45 ++- src/engine/util/dict.c | 4 +- src/engine/util/dict.h | 2 +- src/engine/util/files.c | 102 +++--- src/engine/util/files.h | 8 + 7 files changed, 417 insertions(+), 358 deletions(-) diff --git a/src/engine/graphics/vulkan/pipeline.c b/src/engine/graphics/vulkan/pipeline.c index 29f941f..77567cc 100644 --- a/src/engine/graphics/vulkan/pipeline.c +++ b/src/engine/graphics/vulkan/pipeline.c @@ -8,270 +8,270 @@ #define NUM_VERTEX_INPUT_BINDING_ATTRIBUTE_DESCRIPTIONS 1 static VkVertexInputAttributeDescription vertex_input_binding_attrbute_descriptions[NUM_VERTEX_INPUT_BINDING_ATTRIBUTE_DESCRIPTIONS] = { - { - .binding = 0, - .offset = 0, - .format = VK_FORMAT_R32G32_SFLOAT, - .location = 0 - } + { + .binding = 0, + .offset = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .location = 0 + } }; #define NUM_VERTEX_INPUT_BINDING_DESCRIPTIONS 1 static VkVertexInputBindingDescription vertex_input_binding_description[NUM_VERTEX_INPUT_BINDING_DESCRIPTIONS] = { - { - .binding = 0, - .stride = sizeof(vec2), - .inputRate = VK_VERTEX_INPUT_RATE_VERTEX - } + { + .binding = 0, + .stride = sizeof(vec2), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX + } }; static VkPipelineVertexInputStateCreateInfo vertext_input_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .vertexBindingDescriptionCount = NUM_VERTEX_INPUT_BINDING_DESCRIPTIONS, - .pVertexBindingDescriptions = vertex_input_binding_description, - .vertexAttributeDescriptionCount = NUM_VERTEX_INPUT_BINDING_ATTRIBUTE_DESCRIPTIONS, - .pVertexAttributeDescriptions = vertex_input_binding_attrbute_descriptions + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = NUM_VERTEX_INPUT_BINDING_DESCRIPTIONS, + .pVertexBindingDescriptions = vertex_input_binding_description, + .vertexAttributeDescriptionCount = NUM_VERTEX_INPUT_BINDING_ATTRIBUTE_DESCRIPTIONS, + .pVertexAttributeDescriptions = vertex_input_binding_attrbute_descriptions }; static VkPipelineInputAssemblyStateCreateInfo input_assembly_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, - .primitiveRestartEnable = VK_FALSE + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, + .primitiveRestartEnable = VK_FALSE }; static VkViewport viewport = { - .x = 0.0f, - .y = 0.0f, - .width = 0, // This will be configured later in the code - .height = 0, // This will be configured later in the code - .minDepth = 0.0f, - .maxDepth = 1.0f + .x = 0.0f, + .y = 0.0f, + .width = 0, // This will be configured later in the code + .height = 0, // This will be configured later in the code + .minDepth = 0.0f, + .maxDepth = 1.0f }; static VkRect2D scissor = { - .offset = {0, 0}, - .extent = { - .height = 0, - .width = 0 - } // This will be configured later in the code + .offset = {0, 0}, + .extent = { + .height = 0, + .width = 0 + } // This will be configured later in the code }; static VkPipelineViewportStateCreateInfo viewport_state_creation_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .viewportCount = 1, - .pViewports = &viewport, - .scissorCount = 1, - .pScissors = &scissor + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .pViewports = &viewport, + .scissorCount = 1, + .pScissors = &scissor }; static VkPipelineRasterizationStateCreateInfo rasterizer = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - .depthClampEnable = VK_FALSE, - .rasterizerDiscardEnable = VK_FALSE, - .polygonMode = VK_POLYGON_MODE_FILL, - .lineWidth = 1.0f, - .cullMode = VK_CULL_MODE_BACK_BIT, - .frontFace = VK_FRONT_FACE_CLOCKWISE, - - - .depthBiasEnable = VK_FALSE, - .depthBiasConstantFactor = 0.0f, - .depthBiasClamp = 0.0f, - .depthBiasSlopeFactor = 0.0f, + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .lineWidth = 1.0f, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + + + .depthBiasEnable = VK_FALSE, + .depthBiasConstantFactor = 0.0f, + .depthBiasClamp = 0.0f, + .depthBiasSlopeFactor = 0.0f, }; static VkPipelineMultisampleStateCreateInfo multisampling = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - .sampleShadingEnable = VK_FALSE, - .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, - .minSampleShading = 1.0f, - .pSampleMask = NULL, - .alphaToCoverageEnable = VK_FALSE, - .alphaToOneEnable = VK_FALSE + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .sampleShadingEnable = VK_FALSE, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .minSampleShading = 1.0f, + .pSampleMask = NULL, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE }; static VkPipelineColorBlendAttachmentState color_blending_attachment_state = { - .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | - VK_COLOR_COMPONENT_A_BIT, - .blendEnable = VK_FALSE, - .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, - .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, - .colorBlendOp = VK_BLEND_OP_ADD, - .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, - .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, - .alphaBlendOp = VK_BLEND_OP_ADD, + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT, + .blendEnable = VK_FALSE, + .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, + .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD, }; static VkPipelineColorBlendStateCreateInfo color_blending = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - .logicOpEnable = VK_FALSE, - .logicOp = VK_LOGIC_OP_COPY, - .attachmentCount = 1, - .pAttachments = &color_blending_attachment_state, - .blendConstants = { - 0.0f, - 0.0f, - 0.0f, - 0.0f - } + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = 1, + .pAttachments = &color_blending_attachment_state, + .blendConstants = { + 0.0f, + 0.0f, + 0.0f, + 0.0f + } }; const VkDynamicState dynamic_states[] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_LINE_WIDTH, + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_LINE_WIDTH, }; static VkPipelineDynamicStateCreateInfo dynamic_state_create_info = { - .sType= VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .dynamicStateCount = 2, - .pDynamicStates = dynamic_states + .sType= VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = 2, + .pDynamicStates = dynamic_states }; bool vulkan_pipeline_render_pass_init(vulkan *v) { - VkSubpassDependency dependency = { - .srcSubpass = VK_SUBPASS_EXTERNAL, - .dstSubpass = 0, - .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .srcAccessMask = 0, - .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT - }; - - VkAttachmentDescription color_attachment = { - .samples = VK_SAMPLE_COUNT_1_BIT, - .format = v->swapchain.format.format, - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR - }; - VkAttachmentReference reference = { - .attachment = 0, - .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - }; - VkSubpassDescription subpass = { - .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - - .colorAttachmentCount = 1, - .pColorAttachments = &reference, - }; - - VkRenderPassCreateInfo render_pass_info = { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - - .attachmentCount = 1, - .pAttachments = &color_attachment, - - .subpassCount = 1, - .pSubpasses = &subpass, - - .dependencyCount = 1, - .pDependencies = &dependency - }; - - - return vkCreateRenderPass( - v->devices.logical_device, - &render_pass_info, - NULL, - &v->pipelines.render_pass - ) == VK_SUCCESS; + VkSubpassDependency dependency = { + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = 0, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT + }; + + VkAttachmentDescription color_attachment = { + .samples = VK_SAMPLE_COUNT_1_BIT, + .format = v->swapchain.format.format, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR + }; + VkAttachmentReference reference = { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; + VkSubpassDescription subpass = { + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + + .colorAttachmentCount = 1, + .pColorAttachments = &reference, + }; + + VkRenderPassCreateInfo render_pass_info = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + + .attachmentCount = 1, + .pAttachments = &color_attachment, + + .subpassCount = 1, + .pSubpasses = &subpass, + + .dependencyCount = 1, + .pDependencies = &dependency + }; + + + return vkCreateRenderPass( + v->devices.logical_device, + &render_pass_info, + NULL, + &v->pipelines.render_pass + ) == VK_SUCCESS; } bool vulkan_pipeline_layout_init(vulkan *v) { - VkPipelineLayoutCreateInfo request = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .setLayoutCount = 0, - .pSetLayouts = NULL, - .pushConstantRangeCount = 0, - .pPushConstantRanges = NULL, - }; - - return vkCreatePipelineLayout(v->devices.logical_device, &request, NULL, &v->pipelines.layout) == VK_SUCCESS; + VkPipelineLayoutCreateInfo request = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = 0, + .pSetLayouts = NULL, + .pushConstantRangeCount = 0, + .pPushConstantRanges = NULL, + }; + + return vkCreatePipelineLayout(v->devices.logical_device, &request, NULL, &v->pipelines.layout) == VK_SUCCESS; } bool vulkan_pipeline_graphics_init(vulkan *v) { #define NUM_SHADER_STAGES 3 - VkPipelineShaderStageCreateInfo stages[NUM_SHADER_STAGES]; + VkPipelineShaderStageCreateInfo stages[NUM_SHADER_STAGES]; - if (!vulkan_shader_pipeline_shader_stage_get(VULKAN_SHADER_VERTEX_TEST, &stages[0])) { - return false; - } + shader_t *vetex_shader = vulkan_shader_compile(v->devices.logical_device, VULKAN_SHADER_VERTEX_TEST); + shader_t *geometry_shader = vulkan_shader_compile(v->devices.logical_device, VULKAN_SHADER_GEOMETRY_TEST); + shader_t *fragment_shader = vulkan_shader_compile(v->devices.logical_device, VULKAN_SHADER_FRAGMENT_TEST); - if (!vulkan_shader_pipeline_shader_stage_get(VULKAN_SHADER_GEOMETRY_TEST, &stages[1])) { - return false; - } + if (!vetex_shader || !geometry_shader || !fragment_shader) { + return false; + } - if (!vulkan_shader_pipeline_shader_stage_get(VULKAN_SHADER_FRAGMENT_TEST, &stages[2])) { - return false; - } + stages[0] = vetex_shader->stage_info; + stages[1] = geometry_shader->stage_info; + stages[2] = fragment_shader->stage_info; - VkGraphicsPipelineCreateInfo graphics_pipeline_create_info = { - .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .stageCount = NUM_SHADER_STAGES, - .pStages = stages, + VkGraphicsPipelineCreateInfo graphics_pipeline_create_info = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = NUM_SHADER_STAGES, + .pStages = stages, - .pVertexInputState = &vertext_input_state_create_info, - .pInputAssemblyState = &input_assembly_state_create_info, - .pViewportState = &viewport_state_creation_info, - .pRasterizationState = &rasterizer, - .pMultisampleState = &multisampling, - .pDepthStencilState = NULL, // Optional - .pColorBlendState = &color_blending, - .pDynamicState = NULL, // &dynamic_state_create_info, // Optional + .pVertexInputState = &vertext_input_state_create_info, + .pInputAssemblyState = &input_assembly_state_create_info, + .pViewportState = &viewport_state_creation_info, + .pRasterizationState = &rasterizer, + .pMultisampleState = &multisampling, + .pDepthStencilState = NULL, // Optional + .pColorBlendState = &color_blending, + .pDynamicState = NULL, // &dynamic_state_create_info, // Optional - .layout = v->pipelines.layout, + .layout = v->pipelines.layout, - .renderPass = v->pipelines.render_pass, - .subpass = 0, + .renderPass = v->pipelines.render_pass, + .subpass = 0, - .basePipelineHandle = VK_NULL_HANDLE, - //.basePipelineIndex = -1, - }; + .basePipelineHandle = VK_NULL_HANDLE, + //.basePipelineIndex = -1, + }; - return vkCreateGraphicsPipelines( - v->devices.logical_device, - VK_NULL_HANDLE, - 1, - &graphics_pipeline_create_info, - NULL, - &v->pipelines.graphics - ) == VK_SUCCESS; + return vkCreateGraphicsPipelines( + v->devices.logical_device, + VK_NULL_HANDLE, + 1, + &graphics_pipeline_create_info, + NULL, + &v->pipelines.graphics + ) == VK_SUCCESS; } bool vulkan_pipeline_init(vulkan *v) { - // configure viewport size - viewport.width = vulkan_window_width_get(); - viewport.height = vulkan_window_height_get(); + // configure viewport size + viewport.width = vulkan_window_width_get(); + viewport.height = vulkan_window_height_get(); - // configure swapchain extent - scissor.extent = v->swapchain.extent; + // configure swapchain extent + scissor.extent = v->swapchain.extent; - if (!vulkan_pipeline_layout_init(v)) { - printf("Failed to create pipeline layout\n"); - return false; - } + if (!vulkan_pipeline_layout_init(v)) { + printf("Failed to create pipeline layout\n"); + return false; + } - if (!vulkan_pipeline_render_pass_init(v)) { - printf("Failed to initialize render pass\n"); - return false; - } + if (!vulkan_pipeline_render_pass_init(v)) { + printf("Failed to initialize render pass\n"); + return false; + } - if (!vulkan_pipeline_graphics_init(v)) { - printf("Failed to initialize graphics pipeline\n"); - return false; - } + if (!vulkan_pipeline_graphics_init(v)) { + printf("Failed to initialize graphics pipeline\n"); + return false; + } - return true; + return true; } diff --git a/src/engine/graphics/vulkan/shaders/shader.c b/src/engine/graphics/vulkan/shaders/shader.c index ebdf86a..60aead5 100644 --- a/src/engine/graphics/vulkan/shaders/shader.c +++ b/src/engine/graphics/vulkan/shaders/shader.c @@ -1,133 +1,137 @@ #include #include +#include #include "shader.h" -typedef struct { - char *file_name; - char *source; - const uint32_t *binary; - - VkPipelineShaderStageCreateInfo stage_info; - VkShaderModule module; - shaderc_compilation_result_t result; -} shader_data; - - +dict *compiled_shader_map; llist *compiled; shaderc_compiler_t compiler; void vulkan_shader_compiler_init() { - compiler = shaderc_compiler_initialize(); + compiler = shaderc_compiler_initialize(); } static inline bool vulkan_shader_shaderc_kind_to_stage_bit(shaderc_shader_kind kind, VkShaderStageFlagBits *bits) { - if (kind == shaderc_glsl_vertex_shader) { - *bits = VK_SHADER_STAGE_VERTEX_BIT; - return true; - } - - if (kind == shaderc_glsl_fragment_shader) { - *bits = VK_SHADER_STAGE_FRAGMENT_BIT; - return true; - } - - if (kind == shaderc_glsl_geometry_shader) { - *bits = VK_SHADER_STAGE_GEOMETRY_BIT; - return true; - } - - printf("Compiled unknown shaderc type\n"); - return false; + if (kind == shaderc_glsl_vertex_shader) { + *bits = VK_SHADER_STAGE_VERTEX_BIT; + return true; + } + + if (kind == shaderc_glsl_fragment_shader) { + *bits = VK_SHADER_STAGE_FRAGMENT_BIT; + return true; + } + + if (kind == shaderc_glsl_geometry_shader) { + *bits = VK_SHADER_STAGE_GEOMETRY_BIT; + return true; + } + + printf("Compiled unknown shaderc type\n"); + return false; } -bool vulkan_shader_compile(vulkan *v, char *file_name, shaderc_shader_kind kind) { - shader_data *resource = malloc(sizeof(shader_data)); - resource->file_name = strdup(file_name); - resource->source = read_file(file_name); - resource->result = shaderc_compile_into_spv( - compiler, - resource->source, strlen(resource->source), - kind, - file_name, - "main", // TODO: Configurable shaders? - NULL // TODO: Add preprocessor directives - ); - - - // Was the compile successful? - if (shaderc_result_get_compilation_status(resource->result) != shaderc_compilation_status_success) { - printf("Failed to compile shader (%s): %s\n", file_name, shaderc_result_get_error_message(resource->result)); - return false; - } - - const char *binary = shaderc_result_get_bytes(resource->result); - resource->binary = (const uint32_t *) binary; - - VkShaderModuleCreateInfo request = { - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .codeSize = shaderc_result_get_length(resource->result), - .pCode = resource->binary, - .pNext = NULL - }; - - if (vkCreateShaderModule(v->devices.logical_device, &request, NULL, &resource->module) != VK_SUCCESS) { - printf("Could not allocate shader on GPU: %s\n", file_name); - return false; - } - - - // Create pipeline stage info for vulkan configuration down the line - resource->stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - resource->stage_info.pName = "main"; - resource->stage_info.module = resource->module; - resource->stage_info.pNext = NULL; - resource->stage_info.pSpecializationInfo = NULL; - resource->stage_info.flags = 0; - - if (!vulkan_shader_shaderc_kind_to_stage_bit(kind, &resource->stage_info.stage)) { - return false; - } - - // Track shader - llist_add(&compiled, file_name, resource, sizeof(shader_data)); - - return true; +/** + * Find the shader kind from the file name + * + * @param file_name + * @return the shader kind or shaderc_glsl_infer_from_source if we could not determine from the + */ +static inline shaderc_shader_kind vulkan_shader_shaderc_detect_kind(char *file_name) { +#define NUM_SHADER_KINDS 3 + + static const char *extensions[NUM_SHADER_KINDS] = { + "vert", + "frag", + "geom" + }; + static const shaderc_shader_kind kinds[NUM_SHADER_KINDS] = { + shaderc_glsl_vertex_shader, + shaderc_glsl_fragment_shader, + shaderc_glsl_geometry_shader + }; + + const char *file_extension = file_extract_extension(file_name); + + for (size_t i = 0; i < NUM_SHADER_KINDS; i++) { + if (strcmp(extensions[i], file_extension) == 0) { + return kinds[i]; + } + } + + return shaderc_glsl_infer_from_source; } - -bool vulkan_shader_compile_all(vulkan *v) { - // TODO: Detect and load all shaders - return vulkan_shader_compile(v, VULKAN_SHADER_FRAGMENT_TEST, shaderc_fragment_shader) && - vulkan_shader_compile(v, VULKAN_SHADER_VERTEX_TEST, shaderc_glsl_vertex_shader) && - vulkan_shader_compile(v, VULKAN_SHADER_GEOMETRY_TEST, shaderc_glsl_geometry_shader); +shader_t *vulkan_shader_compile(VkDevice device, char *file_name) { + shader_t *resource; + + // Is this shader compiled already? + if (dict_get(compiled_shader_map, file_name, &resource, NULL)) { + return resource; + } + + shaderc_shader_kind kind = vulkan_shader_shaderc_detect_kind(file_name); + + resource = malloc(sizeof(shader_t)); + resource->device = device; + resource->file_name = strdup(file_name); + resource->source = read_file(file_name); + resource->result = shaderc_compile_into_spv( + compiler, + resource->source, strlen(resource->source), + kind, + file_name, + "main", // TODO: Configurable shaders? + NULL // TODO: Add preprocessor directives + ); + + + // Was the compile successful? + if (shaderc_result_get_compilation_status(resource->result) != shaderc_compilation_status_success) { + printf("Failed to compile shader (%s): %s\n", file_name, shaderc_result_get_error_message(resource->result)); + return NULL; + } + + const char *binary = shaderc_result_get_bytes(resource->result); + resource->binary = (const uint32_t *) binary; + + VkShaderModuleCreateInfo request = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = shaderc_result_get_length(resource->result), + .pCode = resource->binary, + .pNext = NULL + }; + + if (vkCreateShaderModule(device, &request, NULL, &resource->module) != VK_SUCCESS) { + printf("Could not allocate shader on GPU: %s\n", file_name); + return NULL; + } + + + // Create pipeline stage info for vulkan configuration down the line + resource->stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + resource->stage_info.pName = "main"; + resource->stage_info.module = resource->module; + resource->stage_info.pNext = NULL; + resource->stage_info.pSpecializationInfo = NULL; + resource->stage_info.flags = 0; + + if (!vulkan_shader_shaderc_kind_to_stage_bit(kind, &resource->stage_info.stage)) { + return NULL; + } + + // Track shader + llist_add(&compiled, file_name, resource, sizeof(shader_t)); + + return resource; } -bool vulkan_shader_module_get(char *shader_file_name, VkShaderModule *module) { - shader_data *data = llist_get(&compiled, shader_file_name); - if (data) { - *module = data->module; - return true; - } - return NULL; -} - -bool vulkan_shader_pipeline_shader_stage_get(char *shader_file_name, VkPipelineShaderStageCreateInfo *request) { - shader_data *data = llist_get(&compiled, shader_file_name); - if (data) { - *request = data->stage_info; - return true; - } - return NULL; -} -bool vulkan_shader_init(vulkan *v) { - // Init the compiler library - vulkan_shader_compiler_init(); +bool vulkan_shader_init() { + compiled_shader_map = dict_new(); - // Compile all of the shaders into SPIR-V Bytecode - if (!vulkan_shader_compile_all(v)) { - return false; - } + // Init the compiler library + vulkan_shader_compiler_init(); - return true; + return true; } diff --git a/src/engine/graphics/vulkan/shaders/shader.h b/src/engine/graphics/vulkan/shaders/shader.h index dd2bba0..24a7d13 100644 --- a/src/engine/graphics/vulkan/shaders/shader.h +++ b/src/engine/graphics/vulkan/shaders/shader.h @@ -8,7 +8,48 @@ #define VULKAN_SHADER_VERTEX_TEST "assets/shaders/vt.vert" #define VULKAN_SHADER_GEOMETRY_TEST "assets/shaders/vt.geom" -bool vulkan_shader_pipeline_shader_stage_get(char *shader_file_name, VkPipelineShaderStageCreateInfo *request); -bool vulkan_shader_init(vulkan *v); +typedef struct { + /** + * Name of the file this shadr source came from + */ + char *file_name; + + /** + * Source code of the shader + */ + char *source; + + /** + * SPIR-V opcodes + */ + const uint32_t *binary; + + /** + * Device this shader was compiled onto + */ + VkDevice device; + + /** + * Shader stage configuration for pipelines + */ + VkPipelineShaderStageCreateInfo stage_info; + VkShaderModule module; + + /** + * Output of the shaderc compiler + */ + shaderc_compilation_result_t result; +} shader_t; + +/** + * Compile a shader. + * + * @param device - Device to compile onto + * @param file_name - The file name of the shader + * @return + */ +shader_t *vulkan_shader_compile(VkDevice device, char *file_name); + +bool vulkan_shader_init(); #endif diff --git a/src/engine/util/dict.c b/src/engine/util/dict.c index 3d278a3..9898185 100644 --- a/src/engine/util/dict.c +++ b/src/engine/util/dict.c @@ -33,7 +33,7 @@ dict *dict_init(size_t num_buckets) { return d; } -bool dict_get(dict *d, const char *const name, void **value, size_t *length) { +bool dict_get(dict *d, const char *const name, void *value, size_t *length) { const size_t len_name = strlen(name); bucket_index_t index = dict_bucket_for(d, name, len_name); @@ -45,7 +45,7 @@ bool dict_get(dict *d, const char *const name, void **value, size_t *length) { } bool dict_get_string(dict *d, const char *const name, char **value) { - return dict_get(d, name, (void **) value, NULL); + return dict_get(d, name, (void *) value, NULL); } bool dict_has(dict *d, const char *const name) { diff --git a/src/engine/util/dict.h b/src/engine/util/dict.h index ba12505..6afde73 100644 --- a/src/engine/util/dict.h +++ b/src/engine/util/dict.h @@ -23,7 +23,7 @@ dict *dict_init(size_t num_buckets); * @param length * @return */ -bool dict_get(dict *d, const char *name, void **value, size_t *length); +bool dict_get(dict *d, const char *name, void *value, size_t *length); /** diff --git a/src/engine/util/files.c b/src/engine/util/files.c index 1271ec8..fe90ee2 100644 --- a/src/engine/util/files.c +++ b/src/engine/util/files.c @@ -7,70 +7,76 @@ #include #include -long int fsize(const char *filename) -{ - struct stat st; +long int fsize(const char *filename) { + struct stat st; - if (stat(filename, &st) == 0) - return st.st_size; + if (stat(filename, &st) == 0) + return st.st_size; - return -1; + return -1; } -char* read_file(const char* filename) -{ - long int reported_size = fsize(filename); - FILE *f; +char *read_file(const char *filename) { + long int reported_size = fsize(filename); + FILE *f; - if (reported_size == -1 || !(f = fopen(filename, "rb"))) { - return NULL; - } + if (reported_size == -1 || !(f = fopen(filename, "rb"))) { + return NULL; + } - const size_t file_size = (size_t) reported_size; - size_t data_left = file_size; - char *buffer = malloc(file_size + 1); - char *tmp = buffer; + const size_t file_size = (size_t) reported_size; + size_t data_left = file_size; + char *buffer = malloc(file_size + 1); + char *tmp = buffer; - while (data_left > 0) - { - const size_t len = fread((void *) tmp, sizeof(char), sizeof(buffer), f); - data_left -= len; - tmp += len; - } - buffer[file_size] = 0; + while (data_left > 0) { + const size_t len = fread((void *) tmp, sizeof(char), sizeof(buffer), f); + data_left -= len; + tmp += len; + } + buffer[file_size] = 0; - fclose(f); + fclose(f); - return buffer; + return buffer; } -llist* list_files(const char* folder_name, const char *ext) -{ - static char buff[128]; +llist *list_files(const char *folder_name, const char *ext) { + static char buff[128]; - DIR *dir; - struct dirent *ent; + DIR *dir; + struct dirent *ent; - size_t ext_len = ext ? strlen(ext) : 0; - llist* files = NULL; + size_t ext_len = ext ? strlen(ext) : 0; + llist *files = NULL; - if ((dir = opendir(folder_name)) != NULL) { - while ((ent = readdir(dir)) != NULL) { + if ((dir = opendir(folder_name)) != NULL) { + while ((ent = readdir(dir)) != NULL) { - // Filter extensions - // TODO: Make sure this condition will actually work. - if (ext && strcmp(ext, ent->d_name + (strlen(ent->d_name) - ext_len)) != 0) { - continue; - } + // Filter extensions + // TODO: Make sure this condition will actually work. + if (ext && strcmp(ext, ent->d_name + (strlen(ent->d_name) - ext_len)) != 0) { + continue; + } - memset(buff, 0, sizeof(buff)); - strcat(buff, folder_name); - strcat(buff, ent->d_name); + memset(buff, 0, sizeof(buff)); + strcat(buff, folder_name); + strcat(buff, ent->d_name); - llist_add(&files, buff, NULL, 0); - } - closedir(dir); - } + llist_add(&files, buff, NULL, 0); + } + closedir(dir); + } - return files; + return files; +} + +const char *file_extract_extension(const char *filename) { + const char *dot = strrchr(filename, '.'); + + if (!dot || dot == filename) { + return ""; + } + + return dot + 1; } diff --git a/src/engine/util/files.h b/src/engine/util/files.h index 7eb4e2b..a594031 100644 --- a/src/engine/util/files.h +++ b/src/engine/util/files.h @@ -25,6 +25,14 @@ char* read_file(const char* filename); llist* list_files(const char* folder_name, const char *ext); + +/** + * Get the file extension from file name + * @param filename + * @return + */ +const char *file_extract_extension(const char *filename); + /** * Native wrapper to read_file */ From 72eb05d66cd705d7e7771572364febee0f7ca9c7 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sun, 23 Sep 2018 12:01:14 -0400 Subject: [PATCH 25/30] Move shader loading and configuration out of pipeline.c and into shader.c --- CMakeLists.txt | 5 +- src/engine/graphics/vulkan/pipeline.c | 76 ++++----------------- src/engine/graphics/vulkan/shaders/shader.c | 59 ++++++++++++++++ src/engine/graphics/vulkan/shaders/shader.h | 22 ++++++ 4 files changed, 97 insertions(+), 65 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbe339f..af3cb2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,7 +109,10 @@ set(SOURCE_FILES src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h src/engine/graphics/vulkan/framebuffer.c src/engine/graphics/vulkan/framebuffer.h src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h - src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h src/engine/graphics/vulkan/shaders/vbuffer.c src/engine/graphics/vulkan/shaders/vbuffer.h src/engine/graphics/vulkan/memory.c src/engine/graphics/vulkan/memory.h src/engine/util/bits.h) + src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h + src/engine/graphics/vulkan/shaders/vbuffer.c src/engine/graphics/vulkan/shaders/vbuffer.h + src/engine/graphics/vulkan/memory.c src/engine/graphics/vulkan/memory.h + src/engine/util/bits.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan/pipeline.c b/src/engine/graphics/vulkan/pipeline.c index 77567cc..61ecb0a 100644 --- a/src/engine/graphics/vulkan/pipeline.c +++ b/src/engine/graphics/vulkan/pipeline.c @@ -1,45 +1,12 @@ #include #include #include +#include #include "pipeline.h" #include "window.h" #include "src/engine/graphics/vulkan/shaders/shader.h" -#define NUM_VERTEX_INPUT_BINDING_ATTRIBUTE_DESCRIPTIONS 1 -static VkVertexInputAttributeDescription vertex_input_binding_attrbute_descriptions[NUM_VERTEX_INPUT_BINDING_ATTRIBUTE_DESCRIPTIONS] = { - { - .binding = 0, - .offset = 0, - .format = VK_FORMAT_R32G32_SFLOAT, - .location = 0 - } -}; - -#define NUM_VERTEX_INPUT_BINDING_DESCRIPTIONS 1 -static VkVertexInputBindingDescription vertex_input_binding_description[NUM_VERTEX_INPUT_BINDING_DESCRIPTIONS] = { - { - .binding = 0, - .stride = sizeof(vec2), - .inputRate = VK_VERTEX_INPUT_RATE_VERTEX - } -}; - -static VkPipelineVertexInputStateCreateInfo vertext_input_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .vertexBindingDescriptionCount = NUM_VERTEX_INPUT_BINDING_DESCRIPTIONS, - .pVertexBindingDescriptions = vertex_input_binding_description, - .vertexAttributeDescriptionCount = NUM_VERTEX_INPUT_BINDING_ATTRIBUTE_DESCRIPTIONS, - .pVertexAttributeDescriptions = vertex_input_binding_attrbute_descriptions -}; - - -static VkPipelineInputAssemblyStateCreateInfo input_assembly_state_create_info = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, - .primitiveRestartEnable = VK_FALSE -}; - static VkViewport viewport = { .x = 0.0f, .y = 0.0f, @@ -122,12 +89,6 @@ const VkDynamicState dynamic_states[] = { VK_DYNAMIC_STATE_LINE_WIDTH, }; -static VkPipelineDynamicStateCreateInfo dynamic_state_create_info = { - .sType= VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .dynamicStateCount = 2, - .pDynamicStates = dynamic_states -}; - bool vulkan_pipeline_render_pass_init(vulkan *v) { @@ -195,31 +156,18 @@ bool vulkan_pipeline_layout_init(vulkan *v) { return vkCreatePipelineLayout(v->devices.logical_device, &request, NULL, &v->pipelines.layout) == VK_SUCCESS; } -bool vulkan_pipeline_graphics_init(vulkan *v) { - -#define NUM_SHADER_STAGES 3 - VkPipelineShaderStageCreateInfo stages[NUM_SHADER_STAGES]; - - shader_t *vetex_shader = vulkan_shader_compile(v->devices.logical_device, VULKAN_SHADER_VERTEX_TEST); - shader_t *geometry_shader = vulkan_shader_compile(v->devices.logical_device, VULKAN_SHADER_GEOMETRY_TEST); - shader_t *fragment_shader = vulkan_shader_compile(v->devices.logical_device, VULKAN_SHADER_FRAGMENT_TEST); - - if (!vetex_shader || !geometry_shader || !fragment_shader) { - return false; - } - - stages[0] = vetex_shader->stage_info; - stages[1] = geometry_shader->stage_info; - stages[2] = fragment_shader->stage_info; - +bool vulkan_pipeline_graphics_init( + vulkan *v, + shader_group_t *group +) { VkGraphicsPipelineCreateInfo graphics_pipeline_create_info = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .stageCount = NUM_SHADER_STAGES, - .pStages = stages, + .stageCount = group->num_shaders, + .pStages = group->stages, - .pVertexInputState = &vertext_input_state_create_info, - .pInputAssemblyState = &input_assembly_state_create_info, + .pVertexInputState = &group->vertex_input_state_create_info, + .pInputAssemblyState = &group->input_assembly_state, .pViewportState = &viewport_state_creation_info, .pRasterizationState = &rasterizer, .pMultisampleState = &multisampling, @@ -227,13 +175,11 @@ bool vulkan_pipeline_graphics_init(vulkan *v) { .pColorBlendState = &color_blending, .pDynamicState = NULL, // &dynamic_state_create_info, // Optional - .layout = v->pipelines.layout, .renderPass = v->pipelines.render_pass, .subpass = 0, - .basePipelineHandle = VK_NULL_HANDLE, //.basePipelineIndex = -1, }; @@ -258,6 +204,8 @@ bool vulkan_pipeline_init(vulkan *v) { scissor.extent = v->swapchain.extent; + shader_group_t *group = vulkan_shader_group_create(v->devices.logical_device); + if (!vulkan_pipeline_layout_init(v)) { printf("Failed to create pipeline layout\n"); return false; @@ -268,7 +216,7 @@ bool vulkan_pipeline_init(vulkan *v) { return false; } - if (!vulkan_pipeline_graphics_init(v)) { + if (!vulkan_pipeline_graphics_init(v, group)) { printf("Failed to initialize graphics pipeline\n"); return false; } diff --git a/src/engine/graphics/vulkan/shaders/shader.c b/src/engine/graphics/vulkan/shaders/shader.c index 60aead5..0f056c9 100644 --- a/src/engine/graphics/vulkan/shaders/shader.c +++ b/src/engine/graphics/vulkan/shaders/shader.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "shader.h" dict *compiled_shader_map; @@ -62,6 +63,63 @@ static inline shaderc_shader_kind vulkan_shader_shaderc_detect_kind(char *file_n return shaderc_glsl_infer_from_source; } +shader_group_t *vulkan_shader_group_create(VkDevice device) { +#define NUM_SHADERS 3 + shader_group_t *group = malloc(sizeof(shader_group_t)); + memset(group, 0, sizeof(shader_group_t)); + // Shader space + group->num_shaders = NUM_SHADERS; + group->shaders = malloc(sizeof(shader_t *) * group->num_shaders); + group->stages = malloc(sizeof(VkPipelineShaderStageCreateInfo) * group->num_shaders); + + // Vertex input attribute space + group->num_vertex_input_attribute_descriptions = 1; + group->vertex_input_attribute_descriptions = malloc(sizeof(VkVertexInputAttributeDescription) * group->num_vertex_input_attribute_descriptions); + + // Vertex description space + group->num_vertex_input_binding_descriptions = 1; + group->vertex_input_binding_descriptions = malloc(sizeof(VkVertexInputBindingDescription) * group->num_vertex_input_binding_descriptions); + + // Load all shaders for this group + group->shaders[0] = vulkan_shader_compile(device, VULKAN_SHADER_VERTEX_TEST); + group->shaders[1] = vulkan_shader_compile(device, VULKAN_SHADER_GEOMETRY_TEST); + group->shaders[2] = vulkan_shader_compile(device, VULKAN_SHADER_FRAGMENT_TEST); + + + // Input Assembly State. + // Define what kind of data we will be sending in + group->input_assembly_state.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + group->input_assembly_state.pNext = NULL; + group->input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + group->input_assembly_state.primitiveRestartEnable = VK_FALSE; + + + // Define the Vertex Input Attribute Description + group->vertex_input_attribute_descriptions[0].binding = 0; + group->vertex_input_attribute_descriptions[0].offset = 0; + group->vertex_input_attribute_descriptions[0].format = VK_FORMAT_R32G32_SFLOAT; + group->vertex_input_attribute_descriptions[0].location = 0; + + // Input binding descriptions + group->vertex_input_binding_descriptions[0].binding = 0; + group->vertex_input_binding_descriptions[0].stride = sizeof(vec2); + group->vertex_input_binding_descriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + for (size_t i = 0; i < group->num_shaders; i++) { + group->stages[i] = group->shaders[i]->stage_info; + } + + // Vertex Input State Create Info + // - This is used to create and bind to the pipeline + group->vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + group->vertex_input_state_create_info.vertexBindingDescriptionCount = group->num_vertex_input_binding_descriptions; + group->vertex_input_state_create_info.pVertexBindingDescriptions = group->vertex_input_binding_descriptions; + group->vertex_input_state_create_info.vertexAttributeDescriptionCount = group->num_vertex_input_attribute_descriptions; + group->vertex_input_state_create_info.pVertexAttributeDescriptions = group->vertex_input_attribute_descriptions; + + return group; +} + shader_t *vulkan_shader_compile(VkDevice device, char *file_name) { shader_t *resource; @@ -73,6 +131,7 @@ shader_t *vulkan_shader_compile(VkDevice device, char *file_name) { shaderc_shader_kind kind = vulkan_shader_shaderc_detect_kind(file_name); resource = malloc(sizeof(shader_t)); + memset(resource, 0, sizeof(shader_t)); resource->device = device; resource->file_name = strdup(file_name); resource->source = read_file(file_name); diff --git a/src/engine/graphics/vulkan/shaders/shader.h b/src/engine/graphics/vulkan/shaders/shader.h index 24a7d13..556a8bf 100644 --- a/src/engine/graphics/vulkan/shaders/shader.h +++ b/src/engine/graphics/vulkan/shaders/shader.h @@ -41,6 +41,28 @@ typedef struct { shaderc_compilation_result_t result; } shader_t; +typedef struct { + VkPipelineInputAssemblyStateCreateInfo input_assembly_state; + + // Vertex Attribute Descriptions + uint32_t num_vertex_input_attribute_descriptions; + VkVertexInputAttributeDescription *vertex_input_attribute_descriptions; + + // Vertex Binding Descriptions + uint32_t num_vertex_input_binding_descriptions; + VkVertexInputBindingDescription *vertex_input_binding_descriptions; + + uint32_t num_shaders; + shader_t **shaders; + + VkPipelineShaderStageCreateInfo *stages; + + VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info; +} shader_group_t; + + +shader_group_t *vulkan_shader_group_create(VkDevice device); + /** * Compile a shader. * From 0a3b83e9c949c8ba9bbc5a6249f2b2e7ed9a9a42 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sun, 23 Sep 2018 12:34:16 -0400 Subject: [PATCH 26/30] Reformate code --- src/engine/graphics/vulkan/commandpool.c | 193 +++++------ src/engine/graphics/vulkan/commandpool.h | 1 + src/engine/graphics/vulkan/config.h | 1 + src/engine/graphics/vulkan/debug.c | 107 +++--- src/engine/graphics/vulkan/framebuffer.c | 51 +-- src/engine/graphics/vulkan/locking.c | 25 +- src/engine/graphics/vulkan/memory.c | 103 +++--- src/engine/graphics/vulkan/memory.h | 2 +- src/engine/graphics/vulkan/pipeline.c | 12 +- src/engine/graphics/vulkan/query.c | 54 +-- src/engine/graphics/vulkan/queues.c | 198 +++++------ src/engine/graphics/vulkan/queues.h | 1 + src/engine/graphics/vulkan/surface.c | 5 +- src/engine/graphics/vulkan/swapchain.c | 322 +++++++++--------- src/engine/graphics/vulkan/vulkan.c | 398 ++++++++++++----------- src/engine/graphics/vulkan/vulkan.h | 154 +++++---- src/engine/graphics/vulkan/window.c | 80 ++--- src/engine/graphics/vulkan/wrappers.h | 52 +-- 18 files changed, 914 insertions(+), 845 deletions(-) diff --git a/src/engine/graphics/vulkan/commandpool.c b/src/engine/graphics/vulkan/commandpool.c index 9e4943e..b65bc69 100644 --- a/src/engine/graphics/vulkan/commandpool.c +++ b/src/engine/graphics/vulkan/commandpool.c @@ -5,116 +5,121 @@ VkCommandBuffer *command_buffer; -VkCommandBuffer *vulkan_command_pool_get(size_t pool_index) { - // TODO: Bounds checking - return &command_buffer[pool_index]; +VkCommandBuffer *vulkan_command_pool_get(size_t pool_index) +{ + // TODO: Bounds checking + return &command_buffer[pool_index]; } -bool vulkan_command_pool_buffer_init(vulkan *v) { - command_buffer = malloc(sizeof(VkCommandBuffer) * v->swapchain.num_images); - VkCommandBufferAllocateInfo allocation_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = v->command_pool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = (uint32_t) v->swapchain.num_images - }; +bool vulkan_command_pool_buffer_init(vulkan *v) +{ + command_buffer = malloc(sizeof(VkCommandBuffer) * v->swapchain.num_images); + VkCommandBufferAllocateInfo allocation_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = v->command_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = (uint32_t) v->swapchain.num_images + }; - if (vkAllocateCommandBuffers(v->devices.logical_device, &allocation_info, command_buffer) != VK_SUCCESS) { - printf("Failed to allocate command buffer for pool\n"); - return false; - } + if (vkAllocateCommandBuffers(v->devices.logical_device, &allocation_info, command_buffer) != VK_SUCCESS) { + printf("Failed to allocate command buffer for pool\n"); + return false; + } - return true; + return true; } -bool vulkan_command_pool_buffer_recording_start(vulkan *v) { - for (size_t i = 0; i < v->swapchain.num_images; i++) { - VkCommandBufferBeginInfo command_buffer_begin_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, - .pInheritanceInfo = NULL - }; - - if (vkBeginCommandBuffer(command_buffer[i], &command_buffer_begin_info) != VK_SUCCESS) { - printf("Failed to start recording on command buffer %zu\n", i); - return false; - } - } - - return true; +bool vulkan_command_pool_buffer_recording_start(vulkan *v) +{ + for (size_t i = 0; i < v->swapchain.num_images; i++) { + VkCommandBufferBeginInfo command_buffer_begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, + .pInheritanceInfo = NULL + }; + + if (vkBeginCommandBuffer(command_buffer[i], &command_buffer_begin_info) != VK_SUCCESS) { + printf("Failed to start recording on command buffer %zu\n", i); + return false; + } + } + + return true; } -bool vulkan_command_pool_render_pass_begin(vulkan *v, vbuffer *buffer) { - for (size_t i = 0; i < v->swapchain.num_images; i++) { - VkClearValue clear_color = { - .color.float32 = { - 0, 0, 0, 0 - } - }; - VkRenderPassBeginInfo render_pass_info = { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .renderPass = v->pipelines.render_pass, - .framebuffer = v->swapchain.frame_buffers[i], - .renderArea = { - .offset = {0, 0}, - .extent = v->swapchain.extent - }, - .clearValueCount = 1, - .pClearValues = &clear_color, - }; - - { - vkCmdBeginRenderPass(command_buffer[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); - { - vkCmdBindPipeline(command_buffer[i], VK_PIPELINE_BIND_POINT_GRAPHICS, v->pipelines.graphics); - - // TODO: How the fuck to I get this buffer data into here?! - VkBuffer vertexBuffers[] = {buffer->buffer}; - VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(command_buffer[i], 0, 1, vertexBuffers, offsets); - - vkCmdDraw(command_buffer[i], (uint32_t) buffer->num_elements, 1, 0, 0); - - } - vkCmdEndRenderPass(command_buffer[i]); - - - if (vkEndCommandBuffer(command_buffer[i]) != VK_SUCCESS) { - printf("Failed to end command buffer sequence when sending render job to %zu\n", i); - return false; - } - } - } - - return true; +bool vulkan_command_pool_render_pass_begin(vulkan *v, vbuffer *buffer) +{ + for (size_t i = 0; i < v->swapchain.num_images; i++) { + VkClearValue clear_color = { + .color.float32 = { + 0, 0, 0, 0 + } + }; + VkRenderPassBeginInfo render_pass_info = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = v->pipelines.render_pass, + .framebuffer = v->swapchain.frame_buffers[i], + .renderArea = { + .offset = {0, 0}, + .extent = v->swapchain.extent + }, + .clearValueCount = 1, + .pClearValues = &clear_color, + }; + + { + vkCmdBeginRenderPass(command_buffer[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); + { + vkCmdBindPipeline(command_buffer[i], VK_PIPELINE_BIND_POINT_GRAPHICS, v->pipelines.graphics); + + // TODO: How the fuck to I get this buffer data into here?! + VkBuffer vertexBuffers[] = {buffer->buffer}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(command_buffer[i], 0, 1, vertexBuffers, offsets); + + vkCmdDraw(command_buffer[i], (uint32_t) buffer->num_elements, 1, 0, 0); + + } + vkCmdEndRenderPass(command_buffer[i]); + + + if (vkEndCommandBuffer(command_buffer[i]) != VK_SUCCESS) { + printf("Failed to end command buffer sequence when sending render job to %zu\n", i); + return false; + } + } + } + + return true; } -bool vulkan_command_pool_init(vulkan *v, vbuffer *buffer) { - VkCommandPoolCreateInfo poolInfo = { - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .flags = 0, - .queueFamilyIndex = v->queues.main_rendering_queue_id - }; +bool vulkan_command_pool_init(vulkan *v, vbuffer *buffer) +{ + VkCommandPoolCreateInfo poolInfo = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = 0, + .queueFamilyIndex = v->queues.main_rendering_queue_id + }; - if (vkCreateCommandPool(v->devices.logical_device, &poolInfo, NULL, &v->command_pool) != VK_SUCCESS) { - printf("Failed to initialize command pool\n"); - return false; - } + if (vkCreateCommandPool(v->devices.logical_device, &poolInfo, NULL, &v->command_pool) != VK_SUCCESS) { + printf("Failed to initialize command pool\n"); + return false; + } - if (!vulkan_command_pool_buffer_init(v)) { - return false; - } + if (!vulkan_command_pool_buffer_init(v)) { + return false; + } - if (!vulkan_command_pool_buffer_recording_start(v)) { - return false; - } + if (!vulkan_command_pool_buffer_recording_start(v)) { + return false; + } - if (!vulkan_command_pool_render_pass_begin(v, buffer)) { - return false; - } + if (!vulkan_command_pool_render_pass_begin(v, buffer)) { + return false; + } - return true; + return true; } diff --git a/src/engine/graphics/vulkan/commandpool.h b/src/engine/graphics/vulkan/commandpool.h index 2277ae1..c3acf95 100644 --- a/src/engine/graphics/vulkan/commandpool.h +++ b/src/engine/graphics/vulkan/commandpool.h @@ -4,6 +4,7 @@ #include "vulkan.h" bool vulkan_command_pool_init(vulkan *v, vbuffer *buffer); + VkCommandBuffer *vulkan_command_pool_get(size_t pool_index); #endif diff --git a/src/engine/graphics/vulkan/config.h b/src/engine/graphics/vulkan/config.h index 270d423..476a4ea 100644 --- a/src/engine/graphics/vulkan/config.h +++ b/src/engine/graphics/vulkan/config.h @@ -5,6 +5,7 @@ #include VkPhysicalDevice vulkan_config_pick_physical_device(vulkan *v); + bool vulkan_config_init(vulkan *v); #endif diff --git a/src/engine/graphics/vulkan/debug.c b/src/engine/graphics/vulkan/debug.c index 60b0d9a..f086f1d 100644 --- a/src/engine/graphics/vulkan/debug.c +++ b/src/engine/graphics/vulkan/debug.c @@ -7,74 +7,79 @@ #define NUM_WANTED_VALIDATION_LAYERS ((uint32_t) 2) const char *wanted_validation_layers[NUM_WANTED_VALIDATION_LAYERS] = { - "VK_LAYER_LUNARG_core_validation", - "VK_LAYER_LUNARG_standard_validation" + "VK_LAYER_LUNARG_core_validation", + "VK_LAYER_LUNARG_standard_validation" }; static VKAPI_ATTR VkBool32 VKAPI_CALL on_error( - VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkDebugUtilsMessengerCallbackDataEXT *data, - void *user_date -) { - // Ignore lack of usage - ((void) severity); - ((void) type); - ((void) data); - ((void) user_date); - - printf("Validation Message: %s\n", data->pMessage); - - return VK_FALSE; + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT *data, + void *user_date +) +{ + // Ignore lack of usage + ((void) severity); + ((void) type); + ((void) data); + ((void) user_date); + + printf("Validation Message: %s\n", data->pMessage); + + return VK_FALSE; } -uint32_t vulkan_debug_num_validation_layers() { - return NUM_WANTED_VALIDATION_LAYERS; +uint32_t vulkan_debug_num_validation_layers() +{ + return NUM_WANTED_VALIDATION_LAYERS; } -const char **vulkan_debug_validation_layers() { - return wanted_validation_layers; +const char **vulkan_debug_validation_layers() +{ + return wanted_validation_layers; } -void vulkan_debug_init(vulkan *v) { - VkDebugUtilsMessengerCreateInfoEXT creation_request = { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, - .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, - .pfnUserCallback = on_error, - .pUserData = NULL // Optional - }; - - wrap_vulkan_create_debug_utils_messenger_ext( - v->instance, - &creation_request, - NULL, - &v->debugging.debug_utils_messenger_callback - ); +void vulkan_debug_init(vulkan *v) +{ + VkDebugUtilsMessengerCreateInfoEXT creation_request = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = on_error, + .pUserData = NULL // Optional + }; + + wrap_vulkan_create_debug_utils_messenger_ext( + v->instance, + &creation_request, + NULL, + &v->debugging.debug_utils_messenger_callback + ); } -bool vulkan_debug_has_all_wanted_validation_layers(vulkan *v) { +bool vulkan_debug_has_all_wanted_validation_layers(vulkan *v) +{ - for (uint32_t wanted_layer_index = 0; wanted_layer_index < NUM_WANTED_VALIDATION_LAYERS; wanted_layer_index++) { - bool found = false; + for (uint32_t wanted_layer_index = 0; wanted_layer_index < NUM_WANTED_VALIDATION_LAYERS; wanted_layer_index++) { + bool found = false; - // Search array of available layers - for (uint32_t i = 0; !found && i < v->layers.num_properties; i++) { - found = strcmp(wanted_validation_layers[wanted_layer_index], v->layers.properties[i].layerName) == 0; - } + // Search array of available layers + for (uint32_t i = 0; !found && i < v->layers.num_properties; i++) { + found = strcmp(wanted_validation_layers[wanted_layer_index], v->layers.properties[i].layerName) == 0; + } - if (!found) { - return false; - } - } + if (!found) { + return false; + } + } - return true; + return true; } diff --git a/src/engine/graphics/vulkan/framebuffer.c b/src/engine/graphics/vulkan/framebuffer.c index 010b067..2edf3f2 100644 --- a/src/engine/graphics/vulkan/framebuffer.c +++ b/src/engine/graphics/vulkan/framebuffer.c @@ -1,33 +1,34 @@ #include #include "framebuffer.h" -bool vulkan_framebuffer_init(vulkan *v) { - v->swapchain.frame_buffers = malloc(sizeof(VkFramebuffer) * v->swapchain.num_images); +bool vulkan_framebuffer_init(vulkan *v) +{ + v->swapchain.frame_buffers = malloc(sizeof(VkFramebuffer) * v->swapchain.num_images); - VkFramebufferCreateInfo framebuffer_create_info = { - .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .renderPass = v->pipelines.render_pass, - .attachmentCount = 1, - .pAttachments = NULL, // configured later - .width = v->swapchain.extent.width, - .height = v->swapchain.extent.height, - .layers = 1 - }; + VkFramebufferCreateInfo framebuffer_create_info = { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .renderPass = v->pipelines.render_pass, + .attachmentCount = 1, + .pAttachments = NULL, // configured later + .width = v->swapchain.extent.width, + .height = v->swapchain.extent.height, + .layers = 1 + }; - for (size_t i = 0; i < v->swapchain.num_images; i++) { - framebuffer_create_info.pAttachments = &v->swapchain.image_views[i]; - VkResult creation_result = vkCreateFramebuffer( - v->devices.logical_device, - &framebuffer_create_info, - NULL, - &v->swapchain.frame_buffers[i] - ); + for (size_t i = 0; i < v->swapchain.num_images; i++) { + framebuffer_create_info.pAttachments = &v->swapchain.image_views[i]; + VkResult creation_result = vkCreateFramebuffer( + v->devices.logical_device, + &framebuffer_create_info, + NULL, + &v->swapchain.frame_buffers[i] + ); - if (creation_result != VK_SUCCESS) { - printf("Failed to create vulkan framebuffer for swapchain image %zu\n", i); - return false; - } - } + if (creation_result != VK_SUCCESS) { + printf("Failed to create vulkan framebuffer for swapchain image %zu\n", i); + return false; + } + } - return true; + return true; } diff --git a/src/engine/graphics/vulkan/locking.c b/src/engine/graphics/vulkan/locking.c index f42502f..be55bcb 100644 --- a/src/engine/graphics/vulkan/locking.c +++ b/src/engine/graphics/vulkan/locking.c @@ -2,24 +2,27 @@ VkSemaphoreCreateInfo semaphore_create_info = { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - .flags = 0, - .pNext = NULL + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .flags = 0, + .pNext = NULL }; VkSemaphore frame_buffer_image_available; VkSemaphore rendering_finished; -bool vulkan_locking_init(vulkan *v) { - VkDevice device = v->devices.logical_device; - return vkCreateSemaphore(device, &semaphore_create_info, NULL, &frame_buffer_image_available) == VK_SUCCESS && - vkCreateSemaphore(device, &semaphore_create_info, NULL, &rendering_finished) == VK_SUCCESS; +bool vulkan_locking_init(vulkan *v) +{ + VkDevice device = v->devices.logical_device; + return vkCreateSemaphore(device, &semaphore_create_info, NULL, &frame_buffer_image_available) == VK_SUCCESS && + vkCreateSemaphore(device, &semaphore_create_info, NULL, &rendering_finished) == VK_SUCCESS; } -VkSemaphore vulkan_locking_semphore_get_frame_buffer_image_available() { - return frame_buffer_image_available; +VkSemaphore vulkan_locking_semphore_get_frame_buffer_image_available() +{ + return frame_buffer_image_available; } -VkSemaphore vulkan_locking_semphore_get_rendering_finished() { - return rendering_finished; +VkSemaphore vulkan_locking_semphore_get_rendering_finished() +{ + return rendering_finished; } diff --git a/src/engine/graphics/vulkan/memory.c b/src/engine/graphics/vulkan/memory.c index f836116..6b31a1e 100644 --- a/src/engine/graphics/vulkan/memory.c +++ b/src/engine/graphics/vulkan/memory.c @@ -4,70 +4,75 @@ vulkan_device_memory_info info; static inline bool vulkan_memory_properties_has_all_desired_features( - const VkMemoryPropertyFlags available, - const VkMemoryPropertyFlags desired -) { - return IS_EVERY_BIT_SET(available, desired); + const VkMemoryPropertyFlags available, + const VkMemoryPropertyFlags desired +) +{ + return IS_EVERY_BIT_SET(available, desired); } -uint32_t vulkan_memory_type_find(uint32_t memory_type_mask, VkMemoryPropertyFlags properties) { - for (uint32_t i = 0; i < info.properties.memoryTypeCount; i++) { - const VkMemoryPropertyFlags memory_type_properties = info.properties.memoryTypes[i].propertyFlags; +uint32_t vulkan_memory_type_find(uint32_t memory_type_mask, VkMemoryPropertyFlags properties) +{ + for (uint32_t i = 0; i < info.properties.memoryTypeCount; i++) { + const VkMemoryPropertyFlags memory_type_properties = info.properties.memoryTypes[i].propertyFlags; - if (!IS_BIT_SET(memory_type_mask, i)) { - continue; - } + if (!IS_BIT_SET(memory_type_mask, i)) { + continue; + } - if (!vulkan_memory_properties_has_all_desired_features(memory_type_properties, properties)) { - continue; - } + if (!vulkan_memory_properties_has_all_desired_features(memory_type_properties, properties)) { + continue; + } - return i; - } + return i; + } - return UINT32_MAX; + return UINT32_MAX; } // TODO: Implement memory mapping, flushing mapped memory, and invalidating mapped memory caches. // TODO: Move memory mapping out of vbuffer.c/h bool vulkan_memory_allocate( - const vulkan *const v, - const uint32_t memory_type_mask, - const VkMemoryPropertyFlags properties, - const uint32_t size, - VkDeviceMemory *const memory -) { - - // If you don't store the memory address we refuse to allocate anything - if (!memory) { - return false; - } - - // Memory index that supports our variable filter flags - uint32_t memory_type_index = vulkan_memory_type_find(memory_type_mask, properties); - - if (memory_type_index == UINT32_MAX) { - return false; - } - - VkMemoryAllocateInfo memory_allocation_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .allocationSize = size, - .memoryTypeIndex = memory_type_index - }; - - return vkAllocateMemory(v->devices.logical_device, &memory_allocation_info, NULL, memory) == VK_SUCCESS; + const vulkan *const v, + const uint32_t memory_type_mask, + const VkMemoryPropertyFlags properties, + const uint32_t size, + VkDeviceMemory *const memory +) +{ + + // If you don't store the memory address we refuse to allocate anything + if (!memory) { + return false; + } + + // Memory index that supports our variable filter flags + uint32_t memory_type_index = vulkan_memory_type_find(memory_type_mask, properties); + + if (memory_type_index == UINT32_MAX) { + return false; + } + + VkMemoryAllocateInfo memory_allocation_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = size, + .memoryTypeIndex = memory_type_index + }; + + return vkAllocateMemory(v->devices.logical_device, &memory_allocation_info, NULL, memory) == VK_SUCCESS; } void vukan_memory_free( - const vulkan *const v, - VkDeviceMemory memory -) { - vkFreeMemory(v->devices.logical_device, memory, NULL); + const vulkan *const v, + VkDeviceMemory memory +) +{ + vkFreeMemory(v->devices.logical_device, memory, NULL); } -bool vulkan_memory_init(vulkan *v) { - vkGetPhysicalDeviceMemoryProperties(v->devices.selected_device, &info.properties); - return true; +bool vulkan_memory_init(vulkan *v) +{ + vkGetPhysicalDeviceMemoryProperties(v->devices.selected_device, &info.properties); + return true; } diff --git a/src/engine/graphics/vulkan/memory.h b/src/engine/graphics/vulkan/memory.h index 8df2110..27f8b3e 100644 --- a/src/engine/graphics/vulkan/memory.h +++ b/src/engine/graphics/vulkan/memory.h @@ -5,7 +5,7 @@ #include "vulkan.h" typedef struct { - VkPhysicalDeviceMemoryProperties properties; + VkPhysicalDeviceMemoryProperties properties; } vulkan_device_memory_info; bool vulkan_memory_allocate( diff --git a/src/engine/graphics/vulkan/pipeline.c b/src/engine/graphics/vulkan/pipeline.c index 61ecb0a..e1b7783 100644 --- a/src/engine/graphics/vulkan/pipeline.c +++ b/src/engine/graphics/vulkan/pipeline.c @@ -89,7 +89,8 @@ const VkDynamicState dynamic_states[] = { VK_DYNAMIC_STATE_LINE_WIDTH, }; -bool vulkan_pipeline_render_pass_init(vulkan *v) { +bool vulkan_pipeline_render_pass_init(vulkan *v) +{ VkSubpassDependency dependency = { @@ -144,7 +145,8 @@ bool vulkan_pipeline_render_pass_init(vulkan *v) { ) == VK_SUCCESS; } -bool vulkan_pipeline_layout_init(vulkan *v) { +bool vulkan_pipeline_layout_init(vulkan *v) +{ VkPipelineLayoutCreateInfo request = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .setLayoutCount = 0, @@ -159,7 +161,8 @@ bool vulkan_pipeline_layout_init(vulkan *v) { bool vulkan_pipeline_graphics_init( vulkan *v, shader_group_t *group -) { +) +{ VkGraphicsPipelineCreateInfo graphics_pipeline_create_info = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, @@ -194,7 +197,8 @@ bool vulkan_pipeline_graphics_init( ) == VK_SUCCESS; } -bool vulkan_pipeline_init(vulkan *v) { +bool vulkan_pipeline_init(vulkan *v) +{ // configure viewport size viewport.width = vulkan_window_width_get(); diff --git a/src/engine/graphics/vulkan/query.c b/src/engine/graphics/vulkan/query.c index f1e5a65..1e6deba 100644 --- a/src/engine/graphics/vulkan/query.c +++ b/src/engine/graphics/vulkan/query.c @@ -7,39 +7,42 @@ /** * Load hardware and rendering information from GLFW */ -bool glfw_query(vulkan *v) { - v->g.extensions = glfwGetRequiredInstanceExtensions(&v->g.num_extensions); - return true; +bool glfw_query(vulkan *v) +{ + v->g.extensions = glfwGetRequiredInstanceExtensions(&v->g.num_extensions); + return true; } /** * Load available extensions from vulkan * @return */ -bool vulkan_query_extensions(vulkan *v) { - if (vkEnumerateInstanceExtensionProperties(NULL, &v->extensions.num_properties, NULL) != VK_SUCCESS) { - return false; - } +bool vulkan_query_extensions(vulkan *v) +{ + if (vkEnumerateInstanceExtensionProperties(NULL, &v->extensions.num_properties, NULL) != VK_SUCCESS) { + return false; + } - v->extensions.properties = malloc(sizeof(VkExtensionProperties) * v->extensions.num_properties); + v->extensions.properties = malloc(sizeof(VkExtensionProperties) * v->extensions.num_properties); - return vkEnumerateInstanceExtensionProperties(NULL, &v->extensions.num_properties, v->extensions.properties) == - VK_SUCCESS; + return vkEnumerateInstanceExtensionProperties(NULL, &v->extensions.num_properties, v->extensions.properties) == + VK_SUCCESS; } -bool vulkan_query_layers(vulkan *v) { - if (vkEnumerateInstanceLayerProperties(&v->layers.num_properties, NULL) != VK_SUCCESS) { - return false; - } +bool vulkan_query_layers(vulkan *v) +{ + if (vkEnumerateInstanceLayerProperties(&v->layers.num_properties, NULL) != VK_SUCCESS) { + return false; + } - v->layers.properties = malloc(sizeof(VkLayerProperties) * v->layers.num_properties); + v->layers.properties = malloc(sizeof(VkLayerProperties) * v->layers.num_properties); - if (vkEnumerateInstanceLayerProperties(&v->layers.num_properties, v->layers.properties) != VK_SUCCESS) { - printf("Failed to get extension properties\n"); - return false; - } + if (vkEnumerateInstanceLayerProperties(&v->layers.num_properties, v->layers.properties) != VK_SUCCESS) { + printf("Failed to get extension properties\n"); + return false; + } - return true; + return true; } @@ -47,9 +50,10 @@ bool vulkan_query_layers(vulkan *v) { * Query all hardware on the system * @return */ -bool vulkan_hardware_query(vulkan *v) { - return - glfw_query(v) && - vulkan_query_extensions(v) && - vulkan_query_layers(v); +bool vulkan_hardware_query(vulkan *v) +{ + return + glfw_query(v) && + vulkan_query_extensions(v) && + vulkan_query_layers(v); } diff --git a/src/engine/graphics/vulkan/queues.c b/src/engine/graphics/vulkan/queues.c index 94b6162..667c78b 100644 --- a/src/engine/graphics/vulkan/queues.c +++ b/src/engine/graphics/vulkan/queues.c @@ -5,128 +5,134 @@ #include "vulkan.h" typedef bool (*vulkan_queues_selection_criteria_t)(vulkan *v, VkPhysicalDevice device, uint32_t i, - VkQueueFamilyProperties *properties); + VkQueueFamilyProperties *properties); bool vulkan_queues_selection_filter_is_presentable(vulkan *v, VkPhysicalDevice device, uint32_t i, - VkQueueFamilyProperties *properties) { - ((void) properties); - VkBool32 presentable = false; - vkGetPhysicalDeviceSurfaceSupportKHR(device, i, v->surface, &presentable); - return (bool) presentable; + VkQueueFamilyProperties *properties) +{ + ((void) properties); + VkBool32 presentable = false; + vkGetPhysicalDeviceSurfaceSupportKHR(device, i, v->surface, &presentable); + return (bool) presentable; } bool vulkan_queues_selection_filter_is_graphics_queue(vulkan *v, VkPhysicalDevice device, uint32_t i, - VkQueueFamilyProperties *properties) { + VkQueueFamilyProperties *properties) +{ - ((void) v); - ((void) device); - ((void) i); - return (bool) properties->queueFlags & VK_QUEUE_GRAPHICS_BIT; + ((void) v); + ((void) device); + ((void) i); + return (bool) properties->queueFlags & VK_QUEUE_GRAPHICS_BIT; } -VkResult vulkan_queues_init_queue_family(vulkan *v, VkPhysicalDevice device, float priority) { - - - v->queues.num_queue_families = 2; - - // We don't need to double create the same queue. - // TODO: Hack. Make this handle a dynamic number of queues - if (v->queues.main_presentation_queue_id == v->queues.main_rendering_queue_id) { - v->queues.num_queue_families = 1; - v->queues.queue_families[0] = v->queues.main_presentation_queue_id; - } else { - v->queues.num_queue_families = 2; - v->queues.queue_families[0] = v->queues.main_presentation_queue_id; - v->queues.queue_families[1] = v->queues.main_rendering_queue_id; - } - - VkDeviceQueueCreateInfo queue_creations[] = { - { - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .queueFamilyIndex = v->queues.main_rendering_queue_id, - .queueCount = 1, - .pQueuePriorities = &priority - }, - { - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .queueFamilyIndex = v->queues.main_presentation_queue_id, - .queueCount = 1, - .pQueuePriorities = &priority - }, - }; - - VkPhysicalDeviceFeatures device_features; - memset(&device_features, 0, sizeof(VkPhysicalDeviceFeatures)); - - // Geometry shaders enabled. TODO: Refactor - device_features.geometryShader = VK_TRUE; - - VkDeviceCreateInfo request = { - .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pQueueCreateInfos = queue_creations, - .queueCreateInfoCount = v->queues.num_queue_families, - .pEnabledFeatures = &device_features, - - // Device extensions - .enabledExtensionCount = v->required_configuration.num_logical_extensions, - .ppEnabledExtensionNames = v->required_configuration.logical_extensions, - - // Validation Layers - .enabledLayerCount = v->required_configuration.num_layers, - .ppEnabledLayerNames = v->required_configuration.layers - }; - - - return vkCreateDevice(device, &request, NULL, &v->devices.logical_device); +VkResult vulkan_queues_init_queue_family(vulkan *v, VkPhysicalDevice device, float priority) +{ + + + v->queues.num_queue_families = 2; + + // We don't need to double create the same queue. + // TODO: Hack. Make this handle a dynamic number of queues + if (v->queues.main_presentation_queue_id == v->queues.main_rendering_queue_id) { + v->queues.num_queue_families = 1; + v->queues.queue_families[0] = v->queues.main_presentation_queue_id; + } else { + v->queues.num_queue_families = 2; + v->queues.queue_families[0] = v->queues.main_presentation_queue_id; + v->queues.queue_families[1] = v->queues.main_rendering_queue_id; + } + + VkDeviceQueueCreateInfo queue_creations[] = { + { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = v->queues.main_rendering_queue_id, + .queueCount = 1, + .pQueuePriorities = &priority + }, + { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = v->queues.main_presentation_queue_id, + .queueCount = 1, + .pQueuePriorities = &priority + }, + }; + + VkPhysicalDeviceFeatures device_features; + memset(&device_features, 0, sizeof(VkPhysicalDeviceFeatures)); + + // Geometry shaders enabled. TODO: Refactor + device_features.geometryShader = VK_TRUE; + + VkDeviceCreateInfo request = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pQueueCreateInfos = queue_creations, + .queueCreateInfoCount = v->queues.num_queue_families, + .pEnabledFeatures = &device_features, + + // Device extensions + .enabledExtensionCount = v->required_configuration.num_logical_extensions, + .ppEnabledExtensionNames = v->required_configuration.logical_extensions, + + // Validation Layers + .enabledLayerCount = v->required_configuration.num_layers, + .ppEnabledLayerNames = v->required_configuration.layers + }; + + + return vkCreateDevice(device, &request, NULL, &v->devices.logical_device); } -uint32_t vulkan_queues_find_appropriate_queue(vulkan *v, vulkan_queues_selection_criteria_t filter) { - for (uint32_t i = 0; i < v->queues.num_properties; i++) { - VkQueueFamilyProperties *properties = &v->queues.properties[i]; +uint32_t vulkan_queues_find_appropriate_queue(vulkan *v, vulkan_queues_selection_criteria_t filter) +{ + for (uint32_t i = 0; i < v->queues.num_properties; i++) { + VkQueueFamilyProperties *properties = &v->queues.properties[i]; - if (filter(v, v->devices.selected_device, i, properties)) { - return i; - } - } - return UINT32_MAX; + if (filter(v, v->devices.selected_device, i, properties)) { + return i; + } + } + return UINT32_MAX; } -void vulkan_queues_cleanup(vulkan *v) { - vkDestroyDevice(v->devices.logical_device, NULL); +void vulkan_queues_cleanup(vulkan *v) +{ + vkDestroyDevice(v->devices.logical_device, NULL); } -bool vulkan_queues_init(vulkan *v) { - VkPhysicalDevice device = v->devices.selected_device; +bool vulkan_queues_init(vulkan *v) +{ + VkPhysicalDevice device = v->devices.selected_device; - // Find properties - vkGetPhysicalDeviceQueueFamilyProperties(device, &v->queues.num_properties, NULL); - v->queues.properties = malloc(sizeof(VkQueueFamilyProperties) * v->queues.num_properties); - vkGetPhysicalDeviceQueueFamilyProperties(device, &v->queues.num_properties, v->queues.properties); + // Find properties + vkGetPhysicalDeviceQueueFamilyProperties(device, &v->queues.num_properties, NULL); + v->queues.properties = malloc(sizeof(VkQueueFamilyProperties) * v->queues.num_properties); + vkGetPhysicalDeviceQueueFamilyProperties(device, &v->queues.num_properties, v->queues.properties); - v->queues.main_rendering_queue_id = vulkan_queues_find_appropriate_queue(v, - vulkan_queues_selection_filter_is_graphics_queue); - v->queues.main_presentation_queue_id = vulkan_queues_find_appropriate_queue(v, - vulkan_queues_selection_filter_is_presentable); + v->queues.main_rendering_queue_id = vulkan_queues_find_appropriate_queue(v, + vulkan_queues_selection_filter_is_graphics_queue); + v->queues.main_presentation_queue_id = vulkan_queues_find_appropriate_queue(v, + vulkan_queues_selection_filter_is_presentable); - if (v->queues.main_rendering_queue_id == UINT32_MAX || v->queues.main_presentation_queue_id == UINT32_MAX) { - return false; - } + if (v->queues.main_rendering_queue_id == UINT32_MAX || v->queues.main_presentation_queue_id == UINT32_MAX) { + return false; + } - if (vulkan_queues_init_queue_family(v, v->devices.selected_device, 1.0f) != VK_SUCCESS) { - printf("Failed to initialize queue family\n"); - return false; - } + if (vulkan_queues_init_queue_family(v, v->devices.selected_device, 1.0f) != VK_SUCCESS) { + printf("Failed to initialize queue family\n"); + return false; + } - // Load instance into vulkan structure - vkGetDeviceQueue(v->devices.logical_device, v->queues.main_rendering_queue_id, 0, &v->queues.rendering); - vkGetDeviceQueue(v->devices.logical_device, v->queues.main_presentation_queue_id, 0, &v->queues.presenting); + // Load instance into vulkan structure + vkGetDeviceQueue(v->devices.logical_device, v->queues.main_rendering_queue_id, 0, &v->queues.rendering); + vkGetDeviceQueue(v->devices.logical_device, v->queues.main_presentation_queue_id, 0, &v->queues.presenting); - return true; + return true; } diff --git a/src/engine/graphics/vulkan/queues.h b/src/engine/graphics/vulkan/queues.h index 6b25e94..4770be6 100644 --- a/src/engine/graphics/vulkan/queues.h +++ b/src/engine/graphics/vulkan/queues.h @@ -4,6 +4,7 @@ #include "vulkan.h" void vulkan_queues_cleanup(vulkan *v); + bool vulkan_queues_init(vulkan *v); #endif diff --git a/src/engine/graphics/vulkan/surface.c b/src/engine/graphics/vulkan/surface.c index c778844..bdcf1bb 100644 --- a/src/engine/graphics/vulkan/surface.c +++ b/src/engine/graphics/vulkan/surface.c @@ -1,5 +1,6 @@ #include "surface.h" -bool vulkan_surface_init(vulkan *v) { - return glfwCreateWindowSurface(v->instance, v->g.window, NULL, &v->surface) == VK_SUCCESS; +bool vulkan_surface_init(vulkan *v) +{ + return glfwCreateWindowSurface(v->instance, v->g.window, NULL, &v->surface) == VK_SUCCESS; } diff --git a/src/engine/graphics/vulkan/swapchain.c b/src/engine/graphics/vulkan/swapchain.c index d2a7436..ad4be72 100644 --- a/src/engine/graphics/vulkan/swapchain.c +++ b/src/engine/graphics/vulkan/swapchain.c @@ -2,191 +2,199 @@ #include "swapchain.h" #include "window.h" -VkSurfaceFormatKHR vulkan_swapchain_select_format(vulkan *v) { - VkSurfaceFormatKHR best_format = { - .format = VK_FORMAT_B8G8R8A8_UNORM, - .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - }; - - if (v->swapchain.formats[0].format == VK_FORMAT_UNDEFINED) { - return best_format; - } else { - for (uint32_t i = 0; i < v->swapchain.num_formats; i++) { - VkSurfaceFormatKHR found_format = v->swapchain.formats[i]; - if (found_format.format == best_format.format && found_format.colorSpace == best_format.colorSpace) { - return found_format; - } - } - } - - return v->swapchain.formats[0]; +VkSurfaceFormatKHR vulkan_swapchain_select_format(vulkan *v) +{ + VkSurfaceFormatKHR best_format = { + .format = VK_FORMAT_B8G8R8A8_UNORM, + .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + }; + + if (v->swapchain.formats[0].format == VK_FORMAT_UNDEFINED) { + return best_format; + } else { + for (uint32_t i = 0; i < v->swapchain.num_formats; i++) { + VkSurfaceFormatKHR found_format = v->swapchain.formats[i]; + if (found_format.format == best_format.format && found_format.colorSpace == best_format.colorSpace) { + return found_format; + } + } + } + + return v->swapchain.formats[0]; } -VkPresentModeKHR vulkan_swapchain_select_presentation_mode(vulkan *v) { - VkPresentModeKHR mode_order[] = { - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_FIFO_KHR - }; - - for (uint32_t mode_order_idx = 0; sizeof(mode_order) / sizeof(VkPresentModeKHR); mode_order_idx++) { - for (uint32_t i = 0; i < v->swapchain.num_modes; i++) { - if (v->swapchain.modes[i] == mode_order[mode_order_idx]) { - return v->swapchain.modes[i]; - } - } - } - - return VK_PRESENT_MODE_FIFO_KHR; +VkPresentModeKHR vulkan_swapchain_select_presentation_mode(vulkan *v) +{ + VkPresentModeKHR mode_order[] = { + VK_PRESENT_MODE_MAILBOX_KHR, + VK_PRESENT_MODE_IMMEDIATE_KHR, + VK_PRESENT_MODE_FIFO_KHR + }; + + for (uint32_t mode_order_idx = 0; sizeof(mode_order) / sizeof(VkPresentModeKHR); mode_order_idx++) { + for (uint32_t i = 0; i < v->swapchain.num_modes; i++) { + if (v->swapchain.modes[i] == mode_order[mode_order_idx]) { + return v->swapchain.modes[i]; + } + } + } + + return VK_PRESENT_MODE_FIFO_KHR; } -VkExtent2D vulkan_swapchain_choose_extent(vulkan *v) { - if (v->swapchain.capabilities.currentExtent.width != UINT32_MAX) { - return v->swapchain.capabilities.currentExtent; - } +VkExtent2D vulkan_swapchain_choose_extent(vulkan *v) +{ + if (v->swapchain.capabilities.currentExtent.width != UINT32_MAX) { + return v->swapchain.capabilities.currentExtent; + } - VkExtent2D minimum = v->swapchain.capabilities.minImageExtent; - VkExtent2D maximum = v->swapchain.capabilities.maxImageExtent; + VkExtent2D minimum = v->swapchain.capabilities.minImageExtent; + VkExtent2D maximum = v->swapchain.capabilities.maxImageExtent; - VkExtent2D extent = { - SCREEN_W, SCREEN_H - }; + VkExtent2D extent = { + SCREEN_W, SCREEN_H + }; - // Clamp width and height between minimum and maximum - if (minimum.width > extent.width) { - extent.width = minimum.width; - } - if (maximum.width < extent.width) { - extent.width = maximum.width; - } + // Clamp width and height between minimum and maximum + if (minimum.width > extent.width) { + extent.width = minimum.width; + } + if (maximum.width < extent.width) { + extent.width = maximum.width; + } - if (minimum.height > extent.height) { - extent.height = minimum.height; - } - if (maximum.height < extent.height) { - extent.height = maximum.height; - } + if (minimum.height > extent.height) { + extent.height = minimum.height; + } + if (maximum.height < extent.height) { + extent.height = maximum.height; + } - return extent; + return extent; } -uint32_t vulkan_swapchain_choose_image_count(vulkan *v) { - uint32_t count = v->swapchain.capabilities.minImageCount + 1; - if (v->swapchain.capabilities.maxImageCount > 0 && v->swapchain.capabilities.maxImageCount < count) { - count = v->swapchain.capabilities.maxImageCount; - } - return count; +uint32_t vulkan_swapchain_choose_image_count(vulkan *v) +{ + uint32_t count = v->swapchain.capabilities.minImageCount + 1; + if (v->swapchain.capabilities.maxImageCount > 0 && v->swapchain.capabilities.maxImageCount < count) { + count = v->swapchain.capabilities.maxImageCount; + } + return count; } -VkResult vulkan_swapchain_create(vulkan *v) { - v->swapchain.format = vulkan_swapchain_select_format(v); - v->swapchain.extent = vulkan_swapchain_choose_extent(v); - - VkSwapchainCreateInfoKHR request = { - .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - .surface = v->surface, - .minImageCount = vulkan_swapchain_choose_image_count(v), - .imageFormat = v->swapchain.format.format, - .imageColorSpace = v->swapchain.format.colorSpace, - .imageExtent = v->swapchain.extent, - .imageArrayLayers = 1, - .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - - .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = NULL, - - .preTransform = v->swapchain.capabilities.currentTransform, - .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - - .presentMode = vulkan_swapchain_select_presentation_mode(v), - .clipped = VK_TRUE, - - .oldSwapchain = VK_NULL_HANDLE - }; - - if (v->queues.main_presentation_queue_id != v->queues.main_rendering_queue_id) { - request.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - request.queueFamilyIndexCount = v->queues.num_queue_families; - request.pQueueFamilyIndices = v->queues.queue_families; - } - - return vkCreateSwapchainKHR(v->devices.logical_device, &request, NULL, &v->swapchain.swapchain); +VkResult vulkan_swapchain_create(vulkan *v) +{ + v->swapchain.format = vulkan_swapchain_select_format(v); + v->swapchain.extent = vulkan_swapchain_choose_extent(v); + + VkSwapchainCreateInfoKHR request = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .surface = v->surface, + .minImageCount = vulkan_swapchain_choose_image_count(v), + .imageFormat = v->swapchain.format.format, + .imageColorSpace = v->swapchain.format.colorSpace, + .imageExtent = v->swapchain.extent, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = NULL, + + .preTransform = v->swapchain.capabilities.currentTransform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + + .presentMode = vulkan_swapchain_select_presentation_mode(v), + .clipped = VK_TRUE, + + .oldSwapchain = VK_NULL_HANDLE + }; + + if (v->queues.main_presentation_queue_id != v->queues.main_rendering_queue_id) { + request.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + request.queueFamilyIndexCount = v->queues.num_queue_families; + request.pQueueFamilyIndices = v->queues.queue_families; + } + + return vkCreateSwapchainKHR(v->devices.logical_device, &request, NULL, &v->swapchain.swapchain); } -VkResult vulkan_swapchan_get_images(vulkan *v) { +VkResult vulkan_swapchan_get_images(vulkan *v) +{ - vkGetSwapchainImagesKHR(v->devices.logical_device, v->swapchain.swapchain, &v->swapchain.num_images, NULL); - v->swapchain.images = malloc(sizeof(VkImage) * v->swapchain.num_images); - return vkGetSwapchainImagesKHR(v->devices.logical_device, v->swapchain.swapchain, &v->swapchain.num_images, - v->swapchain.images); + vkGetSwapchainImagesKHR(v->devices.logical_device, v->swapchain.swapchain, &v->swapchain.num_images, NULL); + v->swapchain.images = malloc(sizeof(VkImage) * v->swapchain.num_images); + return vkGetSwapchainImagesKHR(v->devices.logical_device, v->swapchain.swapchain, &v->swapchain.num_images, + v->swapchain.images); } -bool vulkan_swapchain_make_image_views(vulkan *v) { - v->swapchain.image_views = malloc(sizeof(VkImageView) * v->swapchain.num_images); - for (uint32_t i = 0; i < v->swapchain.num_images; i++) { - VkImageViewCreateInfo request = { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = v->swapchain.images[i], - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = v->swapchain.format.format, - .components = { - .r = VK_COMPONENT_SWIZZLE_IDENTITY, - .g = VK_COMPONENT_SWIZZLE_IDENTITY, - .b = VK_COMPONENT_SWIZZLE_IDENTITY, - .a = VK_COMPONENT_SWIZZLE_IDENTITY, - }, - .subresourceRange = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1 - } - }; - - if (vkCreateImageView(v->devices.logical_device, &request, NULL, &v->swapchain.image_views[i]) != VK_SUCCESS) { - return false; - } - } - return true; +bool vulkan_swapchain_make_image_views(vulkan *v) +{ + v->swapchain.image_views = malloc(sizeof(VkImageView) * v->swapchain.num_images); + for (uint32_t i = 0; i < v->swapchain.num_images; i++) { + VkImageViewCreateInfo request = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = v->swapchain.images[i], + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = v->swapchain.format.format, + .components = { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + } + }; + + if (vkCreateImageView(v->devices.logical_device, &request, NULL, &v->swapchain.image_views[i]) != VK_SUCCESS) { + return false; + } + } + return true; } -bool vulkan_swapchain_init(vulkan *v) { - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(v->devices.selected_device, v->surface, &v->swapchain.capabilities); - vkGetPhysicalDeviceSurfaceFormatsKHR(v->devices.selected_device, v->surface, &v->swapchain.num_formats, NULL); - vkGetPhysicalDeviceSurfacePresentModesKHR(v->devices.selected_device, v->surface, &v->swapchain.num_modes, NULL); +bool vulkan_swapchain_init(vulkan *v) +{ + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(v->devices.selected_device, v->surface, &v->swapchain.capabilities); + vkGetPhysicalDeviceSurfaceFormatsKHR(v->devices.selected_device, v->surface, &v->swapchain.num_formats, NULL); + vkGetPhysicalDeviceSurfacePresentModesKHR(v->devices.selected_device, v->surface, &v->swapchain.num_modes, NULL); - v->swapchain.formats = malloc(sizeof(VkSurfaceFormatKHR) * v->swapchain.num_formats); - v->swapchain.modes = malloc(sizeof(VkPresentModeKHR) * v->swapchain.num_modes); + v->swapchain.formats = malloc(sizeof(VkSurfaceFormatKHR) * v->swapchain.num_formats); + v->swapchain.modes = malloc(sizeof(VkPresentModeKHR) * v->swapchain.num_modes); - vkGetPhysicalDeviceSurfaceFormatsKHR(v->devices.selected_device, v->surface, &v->swapchain.num_formats, - v->swapchain.formats); - vkGetPhysicalDeviceSurfacePresentModesKHR(v->devices.selected_device, v->surface, &v->swapchain.num_modes, - v->swapchain.modes); + vkGetPhysicalDeviceSurfaceFormatsKHR(v->devices.selected_device, v->surface, &v->swapchain.num_formats, + v->swapchain.formats); + vkGetPhysicalDeviceSurfacePresentModesKHR(v->devices.selected_device, v->surface, &v->swapchain.num_modes, + v->swapchain.modes); - if (!v->swapchain.num_modes || !v->swapchain.num_formats) { - printf("Could not find a supported swapchain mode or format\n"); - return false; - } + if (!v->swapchain.num_modes || !v->swapchain.num_formats) { + printf("Could not find a supported swapchain mode or format\n"); + return false; + } - if (vulkan_swapchain_create(v) != VK_SUCCESS) { - printf("Failed to create swapchain instance from configuration\n"); - return false; - } + if (vulkan_swapchain_create(v) != VK_SUCCESS) { + printf("Failed to create swapchain instance from configuration\n"); + return false; + } - if (vulkan_swapchan_get_images(v) != VK_SUCCESS) { - printf("Failed to load images out of swapchain\n"); - return false; - } + if (vulkan_swapchan_get_images(v) != VK_SUCCESS) { + printf("Failed to load images out of swapchain\n"); + return false; + } - if (!vulkan_swapchain_make_image_views(v)) { - printf("Failed to make image views\n"); - return false; - } + if (!vulkan_swapchain_make_image_views(v)) { + printf("Failed to make image views\n"); + return false; + } - return true; + return true; } \ No newline at end of file diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index bfec9de..00476dc 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -21,222 +21,228 @@ #include "memory.h" vulkan v = { - .definition = { - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pApplicationName = "Solid Snake", - .applicationVersion = VK_MAKE_VERSION(0, 0, 1), - .pEngineName = "Solid Engine", - .engineVersion = VK_MAKE_VERSION(0, 0, 1), - .apiVersion = VK_API_VERSION_1_0 - }, - .devices.selected_device = VK_NULL_HANDLE + .definition = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "Solid Snake", + .applicationVersion = VK_MAKE_VERSION(0, 0, 1), + .pEngineName = "Solid Engine", + .engineVersion = VK_MAKE_VERSION(0, 0, 1), + .apiVersion = VK_API_VERSION_1_0 + }, + .devices.selected_device = VK_NULL_HANDLE }; vec2 triangle_center_position; vbuffer triangle_position_buffer; -VkResult vulkan_create_instance() { - VkInstanceCreateInfo creation_request = { - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - .pApplicationInfo = &v.definition - }; +VkResult vulkan_create_instance() +{ + VkInstanceCreateInfo creation_request = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pApplicationInfo = &v.definition + }; - creation_request.ppEnabledLayerNames = v.required_configuration.layers; - creation_request.enabledLayerCount = v.required_configuration.num_layers; + creation_request.ppEnabledLayerNames = v.required_configuration.layers; + creation_request.enabledLayerCount = v.required_configuration.num_layers; - creation_request.ppEnabledExtensionNames = v.required_configuration.extensions; - creation_request.enabledExtensionCount = v.required_configuration.num_extensions; + creation_request.ppEnabledExtensionNames = v.required_configuration.extensions; + creation_request.enabledExtensionCount = v.required_configuration.num_extensions; - return vkCreateInstance(&creation_request, NULL, &v.instance); + return vkCreateInstance(&creation_request, NULL, &v.instance); } -void vulkan_info_print() { - printf("Vulkan Initialized\n"); +void vulkan_info_print() +{ + printf("Vulkan Initialized\n"); - printf("Loaded Vulkan Extensions: %u\n", v.extensions.num_properties); - for (uint32_t i = 0; i < v.extensions.num_properties; i++) { - printf("\t%d - %s (%d)\n", i, v.extensions.properties[i].extensionName, v.extensions.properties[i].specVersion); - } + printf("Loaded Vulkan Extensions: %u\n", v.extensions.num_properties); + for (uint32_t i = 0; i < v.extensions.num_properties; i++) { + printf("\t%d - %s (%d)\n", i, v.extensions.properties[i].extensionName, v.extensions.properties[i].specVersion); + } - printf("Loaded Vulkan Instance Layers: %u\n", v.layers.num_properties); - for (uint32_t i = 0; i < v.layers.num_properties; i++) { - printf("\t%d - %s (%d)\n", i, v.layers.properties[i].layerName, v.layers.properties[i].specVersion); - } + printf("Loaded Vulkan Instance Layers: %u\n", v.layers.num_properties); + for (uint32_t i = 0; i < v.layers.num_properties; i++) { + printf("\t%d - %s (%d)\n", i, v.layers.properties[i].layerName, v.layers.properties[i].specVersion); + } - printf("Using %u as the main graphics queue\n", v.queues.main_rendering_queue_id); + printf("Using %u as the main graphics queue\n", v.queues.main_rendering_queue_id); } -bool vulkan_init() { - - if (!vulkan_window_init(&v)) { - printf("Failed to create window!\n"); - return false; - } - - // Find hardware info - if (!vulkan_hardware_query(&v)) { - printf("Failed to query vulkan hardware!\n"); - return false; - } - - // Choose extensions and layers to use - vulkan_config_init(&v); - - // Create vulkan instance - if (vulkan_create_instance() != VK_SUCCESS) { - printf("Failed to create vulkan instance\n"); - return false; - } - - // Start the debugger - vulkan_debug_init(&v); - - // Select a device - if ((v.devices.selected_device = vulkan_config_pick_physical_device(&v)) == VK_NULL_HANDLE) { - printf("Failed to find suitable device!\n"); - return false; - } - - // Make drawable surface - if (!vulkan_surface_init(&v)) { - printf("Failed to create drawing surface\n"); - return false; - } - - // Find a queue with graphics pipeline support - if (!vulkan_queues_init(&v)) { - printf("Could not find graphics bit in chosen device!\n"); - return false; - } - - if (!vulkan_swapchain_init(&v)) { - return false; - } - - if (!vulkan_shader_init(&v)) { - return false; - } - - - if (!vulkan_locking_init(&v)) { - printf("Could not create locks\n"); - return false; - } - - if (!vulkan_pipeline_init(&v)) { - return false; - } - - if (!vulkan_framebuffer_init(&v)) { - return false; - } - - if (!vulkan_memory_init(&v)) { - printf("Failed to init memory\n"); - return false; - } - - // TODO: Do not allocate this here. This is game state logic - if (!vulkan_vbuffer_allocate(&v, &triangle_position_buffer, sizeof(vec2), 1, true)) { - printf("Failed allocate buffer\n"); - return false; - } - - // TODO: We should NOT be passing the triangle position buffer in like this - if (!vulkan_command_pool_init(&v, &triangle_position_buffer)) { - printf("Failed to init command pool\n"); - return false; - } - - // Info to prove we have loaded everything - vulkan_info_print(); - - return true; +bool vulkan_init() +{ + + if (!vulkan_window_init(&v)) { + printf("Failed to create window!\n"); + return false; + } + + // Find hardware info + if (!vulkan_hardware_query(&v)) { + printf("Failed to query vulkan hardware!\n"); + return false; + } + + // Choose extensions and layers to use + vulkan_config_init(&v); + + // Create vulkan instance + if (vulkan_create_instance() != VK_SUCCESS) { + printf("Failed to create vulkan instance\n"); + return false; + } + + // Start the debugger + vulkan_debug_init(&v); + + // Select a device + if ((v.devices.selected_device = vulkan_config_pick_physical_device(&v)) == VK_NULL_HANDLE) { + printf("Failed to find suitable device!\n"); + return false; + } + + // Make drawable surface + if (!vulkan_surface_init(&v)) { + printf("Failed to create drawing surface\n"); + return false; + } + + // Find a queue with graphics pipeline support + if (!vulkan_queues_init(&v)) { + printf("Could not find graphics bit in chosen device!\n"); + return false; + } + + if (!vulkan_swapchain_init(&v)) { + return false; + } + + if (!vulkan_shader_init(&v)) { + return false; + } + + + if (!vulkan_locking_init(&v)) { + printf("Could not create locks\n"); + return false; + } + + if (!vulkan_pipeline_init(&v)) { + return false; + } + + if (!vulkan_framebuffer_init(&v)) { + return false; + } + + if (!vulkan_memory_init(&v)) { + printf("Failed to init memory\n"); + return false; + } + + // TODO: Do not allocate this here. This is game state logic + if (!vulkan_vbuffer_allocate(&v, &triangle_position_buffer, sizeof(vec2), 1, true)) { + printf("Failed allocate buffer\n"); + return false; + } + + // TODO: We should NOT be passing the triangle position buffer in like this + if (!vulkan_command_pool_init(&v, &triangle_position_buffer)) { + printf("Failed to init command pool\n"); + return false; + } + + // Info to prove we have loaded everything + vulkan_info_print(); + + return true; } -void vulkan_render() { - - /** - * set triangle position - */ - triangle_center_position[0] = (cursor_x - (vulkan_window_width_get() / 2.0f)) / vulkan_window_width_get(); - triangle_center_position[1] = (cursor_y - (vulkan_window_height_get() / 2.0f)) / vulkan_window_height_get(); - - // send to gpu via memory mapped region - memcpy(triangle_position_buffer.mapped_memory, &triangle_center_position, sizeof(vec2) * 1); - - uint32_t image_index; - vkAcquireNextImageKHR( - v.devices.logical_device, - v.swapchain.swapchain, - UINT64_MAX, - vulkan_locking_semphore_get_frame_buffer_image_available(), - VK_NULL_HANDLE, - &image_index - ); - - // Render starting configuration - VkSemaphore waiting_semaphores[] = { - vulkan_locking_semphore_get_frame_buffer_image_available() - }; - VkPipelineStageFlags stages[] = { - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT - }; - - // Render ending configuration - VkSemaphore signaling_semaphores[] = { - vulkan_locking_semphore_get_rendering_finished() - }; - - - VkSubmitInfo submit_info = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .waitSemaphoreCount = 1, - .pWaitSemaphores = waiting_semaphores, - .pWaitDstStageMask = stages, - - - // Link the command buffer to the render stage - .commandBufferCount = 1, - .pCommandBuffers = vulkan_command_pool_get(image_index), - - - // After rendering signal these semphores - .signalSemaphoreCount = 1, - .pSignalSemaphores = signaling_semaphores - }; - - // Submitting render job - if (vkQueueSubmit(v.queues.rendering, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { - printf("Failed to render!\n"); - } - - // Submitting presenting job - VkSwapchainKHR subscribing_swapchains[] = { - v.swapchain.swapchain - }; - - VkPresentInfoKHR present_info = { - .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - // Subscribe - .waitSemaphoreCount = 1, - .pWaitSemaphores = signaling_semaphores, - - .swapchainCount = 1, - .pSwapchains = subscribing_swapchains, - .pImageIndices = &image_index, - - .pResults = NULL - }; - - vkQueuePresentKHR(v.queues.presenting, &present_info); +void vulkan_render() +{ + + /** + * set triangle position + */ + triangle_center_position[0] = (cursor_x - (vulkan_window_width_get() / 2.0f)) / vulkan_window_width_get(); + triangle_center_position[1] = (cursor_y - (vulkan_window_height_get() / 2.0f)) / vulkan_window_height_get(); + + // send to gpu via memory mapped region + memcpy(triangle_position_buffer.mapped_memory, &triangle_center_position, sizeof(vec2) * 1); + + uint32_t image_index; + vkAcquireNextImageKHR( + v.devices.logical_device, + v.swapchain.swapchain, + UINT64_MAX, + vulkan_locking_semphore_get_frame_buffer_image_available(), + VK_NULL_HANDLE, + &image_index + ); + + // Render starting configuration + VkSemaphore waiting_semaphores[] = { + vulkan_locking_semphore_get_frame_buffer_image_available() + }; + VkPipelineStageFlags stages[] = { + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + }; + + // Render ending configuration + VkSemaphore signaling_semaphores[] = { + vulkan_locking_semphore_get_rendering_finished() + }; + + + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = 1, + .pWaitSemaphores = waiting_semaphores, + .pWaitDstStageMask = stages, + + + // Link the command buffer to the render stage + .commandBufferCount = 1, + .pCommandBuffers = vulkan_command_pool_get(image_index), + + + // After rendering signal these semphores + .signalSemaphoreCount = 1, + .pSignalSemaphores = signaling_semaphores + }; + + // Submitting render job + if (vkQueueSubmit(v.queues.rendering, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { + printf("Failed to render!\n"); + } + + // Submitting presenting job + VkSwapchainKHR subscribing_swapchains[] = { + v.swapchain.swapchain + }; + + VkPresentInfoKHR present_info = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + // Subscribe + .waitSemaphoreCount = 1, + .pWaitSemaphores = signaling_semaphores, + + .swapchainCount = 1, + .pSwapchains = subscribing_swapchains, + .pImageIndices = &image_index, + + .pResults = NULL + }; + + vkQueuePresentKHR(v.queues.presenting, &present_info); } -void vulkan_update() { - vulkan_window_update(); +void vulkan_update() +{ + vulkan_window_update(); } -void vulkan_cleanup() { - vulkan_window_cleanup(); +void vulkan_cleanup() +{ + vulkan_window_cleanup(); } diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h index b71ec8e..bd5a360 100644 --- a/src/engine/graphics/vulkan/vulkan.h +++ b/src/engine/graphics/vulkan/vulkan.h @@ -7,111 +7,121 @@ #include #include -typedef struct { - uint32_t num_extensions; - const char **extensions; - GLFWwindow *window; +typedef struct +{ + uint32_t num_extensions; + const char **extensions; + GLFWwindow *window; } glfw; -typedef struct { - VkDebugUtilsMessengerEXT debug_utils_messenger_callback; +typedef struct +{ + VkDebugUtilsMessengerEXT debug_utils_messenger_callback; } vulkan_debugging; -typedef struct { - /** - * Info about available devices - */ - VkPhysicalDevice *devices; - uint32_t num_devices; +typedef struct +{ + /** + * Info about available devices + */ + VkPhysicalDevice *devices; + uint32_t num_devices; - /** - * The device we are currently rendering to - */ - VkPhysicalDevice selected_device; - VkDevice logical_device; + /** + * The device we are currently rendering to + */ + VkPhysicalDevice selected_device; + VkDevice logical_device; } vulkan_devices; -typedef struct { - VkExtensionProperties *properties; - uint32_t num_properties; +typedef struct +{ + VkExtensionProperties *properties; + uint32_t num_properties; } vulkan_extensions; -typedef struct { - VkLayerProperties *properties; - uint32_t num_properties; +typedef struct +{ + VkLayerProperties *properties; + uint32_t num_properties; - const char **layers; - uint32_t num_layers; + const char **layers; + uint32_t num_layers; } vulkan_layers; -typedef struct { - uint32_t num_properties; - VkQueueFamilyProperties *properties; +typedef struct +{ + uint32_t num_properties; + VkQueueFamilyProperties *properties; - uint32_t num_queue_families; - uint32_t queue_families[2]; + uint32_t num_queue_families; + uint32_t queue_families[2]; - uint32_t main_rendering_queue_id; - uint32_t main_presentation_queue_id; - VkQueue rendering; - VkQueue presenting; + uint32_t main_rendering_queue_id; + uint32_t main_presentation_queue_id; + VkQueue rendering; + VkQueue presenting; } vulkan_queues; -typedef struct { - uint32_t num_extensions; - const char **extensions; - uint32_t num_logical_extensions; - const char **logical_extensions; - uint32_t num_layers; - const char **layers; +typedef struct +{ + uint32_t num_extensions; + const char **extensions; + uint32_t num_logical_extensions; + const char **logical_extensions; + uint32_t num_layers; + const char **layers; } vulkan_required_configuration; -typedef struct { - VkSurfaceFormatKHR format; - VkExtent2D extent; - VkSwapchainKHR swapchain; +typedef struct +{ + VkSurfaceFormatKHR format; + VkExtent2D extent; + VkSwapchainKHR swapchain; - VkImage *images; - VkImageView *image_views; - uint32_t num_images; + VkImage *images; + VkImageView *image_views; + uint32_t num_images; - VkSurfaceCapabilitiesKHR capabilities; + VkSurfaceCapabilitiesKHR capabilities; - VkSurfaceFormatKHR *formats; - uint32_t num_formats; + VkSurfaceFormatKHR *formats; + uint32_t num_formats; - VkPresentModeKHR *modes; - uint32_t num_modes; + VkPresentModeKHR *modes; + uint32_t num_modes; - VkFramebuffer *frame_buffers; + VkFramebuffer *frame_buffers; } vulkan_swapchain; -typedef struct { - VkRenderPass render_pass; - VkPipelineLayout layout; - VkPipeline graphics; +typedef struct +{ + VkRenderPass render_pass; + VkPipelineLayout layout; + VkPipeline graphics; } vulkan_pipelines; -typedef struct { - VkApplicationInfo definition; +typedef struct +{ + VkApplicationInfo definition; - glfw g; - VkInstance instance; - VkSurfaceKHR surface; - VkCommandPool command_pool; + glfw g; + VkInstance instance; + VkSurfaceKHR surface; + VkCommandPool command_pool; - vulkan_layers layers; - vulkan_extensions extensions; - vulkan_debugging debugging; - vulkan_devices devices; - vulkan_queues queues; - vulkan_swapchain swapchain; - vulkan_pipelines pipelines; + vulkan_layers layers; + vulkan_extensions extensions; + vulkan_debugging debugging; + vulkan_devices devices; + vulkan_queues queues; + vulkan_swapchain swapchain; + vulkan_pipelines pipelines; - vulkan_required_configuration required_configuration; + vulkan_required_configuration required_configuration; } vulkan; diff --git a/src/engine/graphics/vulkan/window.c b/src/engine/graphics/vulkan/window.c index a391099..2a58dd8 100644 --- a/src/engine/graphics/vulkan/window.c +++ b/src/engine/graphics/vulkan/window.c @@ -10,60 +10,66 @@ volatile float cursor_y; void vulkan_on_mouse_move(GLFWwindow *window, double x, double y) { - (void) window; - cursor_x = (float) x; - cursor_y = (float) y; + (void) window; + cursor_x = (float) x; + cursor_y = (float) y; } -bool vulkan_window_init(vulkan *v) { - glfwInit(); +bool vulkan_window_init(vulkan *v) +{ + glfwInit(); - // Disable loading OpenGL and use GLFW for loading APIs - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + // Disable loading OpenGL and use GLFW for loading APIs + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - window = v->g.window = glfwCreateWindow( - vulkan_window_width_get(), vulkan_window_height_get(), - "Solid Engine", - NULL, - NULL - ); + window = v->g.window = glfwCreateWindow( + vulkan_window_width_get(), vulkan_window_height_get(), + "Solid Engine", + NULL, + NULL + ); - if (!v->g.window) { - printf("Failed to create window!\n"); - glfwTerminate(); - return false; - } + if (!v->g.window) { + printf("Failed to create window!\n"); + glfwTerminate(); + return false; + } - // TODO: Move into it's own location - glfwSetCursorPosCallback(v->g.window, vulkan_on_mouse_move); + // TODO: Move into it's own location + glfwSetCursorPosCallback(v->g.window, vulkan_on_mouse_move); - glfwMakeContextCurrent(v->g.window); + glfwMakeContextCurrent(v->g.window); - return true; + return true; } -int vulkan_window_width_get() { - return SCREEN_W; +int vulkan_window_width_get() +{ + return SCREEN_W; } -int vulkan_window_height_get() { - return SCREEN_H; +int vulkan_window_height_get() +{ + return SCREEN_H; } -void vulkan_window_update() { - glfwPollEvents(); +void vulkan_window_update() +{ + glfwPollEvents(); } -void vulkan_window_cleanup() { - glfwDestroyWindow(window); - glfwTerminate(); +void vulkan_window_cleanup() +{ + glfwDestroyWindow(window); + glfwTerminate(); } -bool vulkan_window_is_close_requested() { - if (!window) { - return true; - } - return (bool) glfwWindowShouldClose(window); +bool vulkan_window_is_close_requested() +{ + if (!window) { + return true; + } + return (bool) glfwWindowShouldClose(window); } diff --git a/src/engine/graphics/vulkan/wrappers.h b/src/engine/graphics/vulkan/wrappers.h index 0011ad2..7b6f5ce 100644 --- a/src/engine/graphics/vulkan/wrappers.h +++ b/src/engine/graphics/vulkan/wrappers.h @@ -12,20 +12,21 @@ * @return */ static inline VkResult wrap_vulkan_create_debug_utils_messenger_ext( - VkInstance instance, - const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkDebugUtilsMessengerEXT *pCallback -) { - const PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr( - instance, - "vkCreateDebugUtilsMessengerEXT" - ); - if (func != NULL) { - return func(instance, pCreateInfo, pAllocator, pCallback); - } else { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } + VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugUtilsMessengerEXT *pCallback +) +{ + const PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr( + instance, + "vkCreateDebugUtilsMessengerEXT" + ); + if (func != NULL) { + return func(instance, pCreateInfo, pAllocator, pCallback); + } else { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } } /** @@ -35,17 +36,18 @@ static inline VkResult wrap_vulkan_create_debug_utils_messenger_ext( * @param pAllocator */ static inline void wrap_vulkan_destroy_debug_utils_messenger_ext( - VkInstance instance, - VkDebugUtilsMessengerEXT callback, - const VkAllocationCallbacks *pAllocator -) { - PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr( - instance, - "vkDestroyDebugUtilsMessengerEXT" - ); - if (func != NULL) { - func(instance, callback, pAllocator); - } + VkInstance instance, + VkDebugUtilsMessengerEXT callback, + const VkAllocationCallbacks *pAllocator +) +{ + PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr( + instance, + "vkDestroyDebugUtilsMessengerEXT" + ); + if (func != NULL) { + func(instance, callback, pAllocator); + } } #endif From bd4f709776d0f3db33654eaa113b5ec92e09c1c9 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sun, 23 Sep 2018 12:57:50 -0400 Subject: [PATCH 27/30] Move buffer and memory into it's own folder --- CMakeLists.txt | 4 +- src/engine/graphics/vulkan/commandpool.c | 4 +- src/engine/graphics/vulkan/commandpool.h | 2 +- src/engine/graphics/vulkan/memory.h | 26 --------- src/engine/graphics/vulkan/memory/buffer.c | 52 +++++++++++++++++ src/engine/graphics/vulkan/memory/buffer.h | 41 +++++++++++++ .../graphics/vulkan/{ => memory}/memory.c | 25 +++++++- src/engine/graphics/vulkan/memory/memory.h | 40 +++++++++++++ src/engine/graphics/vulkan/shaders/vbuffer.c | 58 ++++++------------- src/engine/graphics/vulkan/shaders/vbuffer.h | 13 +---- src/engine/graphics/vulkan/vulkan.c | 6 +- 11 files changed, 184 insertions(+), 87 deletions(-) delete mode 100644 src/engine/graphics/vulkan/memory.h create mode 100644 src/engine/graphics/vulkan/memory/buffer.c create mode 100644 src/engine/graphics/vulkan/memory/buffer.h rename src/engine/graphics/vulkan/{ => memory}/memory.c (82%) create mode 100644 src/engine/graphics/vulkan/memory/memory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index af3cb2e..11712e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,8 +111,8 @@ set(SOURCE_FILES src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h src/engine/graphics/vulkan/shaders/vbuffer.c src/engine/graphics/vulkan/shaders/vbuffer.h - src/engine/graphics/vulkan/memory.c src/engine/graphics/vulkan/memory.h - src/engine/util/bits.h) + src/engine/graphics/vulkan/memory/memory.c src/engine/graphics/vulkan/memory/memory.h + src/engine/util/bits.h src/engine/graphics/vulkan/memory/buffer.h src/engine/graphics/vulkan/memory/buffer.c) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/graphics/vulkan/commandpool.c b/src/engine/graphics/vulkan/commandpool.c index b65bc69..bc5904c 100644 --- a/src/engine/graphics/vulkan/commandpool.c +++ b/src/engine/graphics/vulkan/commandpool.c @@ -49,7 +49,7 @@ bool vulkan_command_pool_buffer_recording_start(vulkan *v) } -bool vulkan_command_pool_render_pass_begin(vulkan *v, vbuffer *buffer) +bool vulkan_command_pool_render_pass_begin(vulkan *v, buffer_t *buffer) { for (size_t i = 0; i < v->swapchain.num_images; i++) { VkClearValue clear_color = { @@ -95,7 +95,7 @@ bool vulkan_command_pool_render_pass_begin(vulkan *v, vbuffer *buffer) return true; } -bool vulkan_command_pool_init(vulkan *v, vbuffer *buffer) +bool vulkan_command_pool_init(vulkan *v, buffer_t *buffer) { VkCommandPoolCreateInfo poolInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, diff --git a/src/engine/graphics/vulkan/commandpool.h b/src/engine/graphics/vulkan/commandpool.h index c3acf95..20ae2f3 100644 --- a/src/engine/graphics/vulkan/commandpool.h +++ b/src/engine/graphics/vulkan/commandpool.h @@ -3,7 +3,7 @@ #include "vulkan.h" -bool vulkan_command_pool_init(vulkan *v, vbuffer *buffer); +bool vulkan_command_pool_init(vulkan *v, buffer_t *buffer); VkCommandBuffer *vulkan_command_pool_get(size_t pool_index); diff --git a/src/engine/graphics/vulkan/memory.h b/src/engine/graphics/vulkan/memory.h deleted file mode 100644 index 27f8b3e..0000000 --- a/src/engine/graphics/vulkan/memory.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef ENGINE_MEMORY_H -#define ENGINE_MEMORY_H - -#include -#include "vulkan.h" - -typedef struct { - VkPhysicalDeviceMemoryProperties properties; -} vulkan_device_memory_info; - -bool vulkan_memory_allocate( - const vulkan *v, - uint32_t memory_type_mask, - VkMemoryPropertyFlags properties, - uint32_t size, - VkDeviceMemory *memory -); - -void vukan_memory_free( - const vulkan *v, - VkDeviceMemory memory -); - -bool vulkan_memory_init(vulkan *v); - -#endif diff --git a/src/engine/graphics/vulkan/memory/buffer.c b/src/engine/graphics/vulkan/memory/buffer.c new file mode 100644 index 0000000..d2267fc --- /dev/null +++ b/src/engine/graphics/vulkan/memory/buffer.c @@ -0,0 +1,52 @@ +#include +#include +#include + +bool vulkan_buffer_allocate( + vulkan *v, + buffer_t *buffer, + VkMemoryPropertyFlags buffer_memory_property_flags, + VkBufferUsageFlags buffer_usage_flags, VkSharingMode buffer_sharing_mode, + uint32_t element_size, uint32_t num_elements, + bool map_memory_region +) +{ + const VkDeviceSize size = element_size * num_elements; + + // Clear out old buffer + memset(buffer, 0, sizeof(buffer_t)); + + // Engine metadata + buffer->element_size = element_size; + buffer->num_elements = num_elements; + + // Set up buffer dimension info + buffer->info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer->info.size = size; + buffer->info.usage = buffer_usage_flags; + buffer->info.sharingMode = buffer_sharing_mode; + + if (vkCreateBuffer(v->devices.logical_device, &buffer->info, NULL, &buffer->buffer) != VK_SUCCESS) { + return false; + } + + vkGetBufferMemoryRequirements(v->devices.logical_device, buffer->buffer, &buffer->required_memory); + + if (!vulkan_memory_allocate(v, buffer->required_memory.memoryTypeBits, buffer_memory_property_flags, size, &buffer->memory)) { + return false; + } + + // Bind the memory to the new buffer + if (vkBindBufferMemory(v->devices.logical_device, buffer->buffer, buffer->memory, 0) != VK_SUCCESS) { + return false; + } + + if (map_memory_region) { + // Map memory location into trapped page (I guess?) + if (!vulkan_memory_map(v, buffer->memory, 0, buffer->info.size, &buffer->mapped_memory)) { + return false; + } + } + + return true; +} \ No newline at end of file diff --git a/src/engine/graphics/vulkan/memory/buffer.h b/src/engine/graphics/vulkan/memory/buffer.h new file mode 100644 index 0000000..f05e8c6 --- /dev/null +++ b/src/engine/graphics/vulkan/memory/buffer.h @@ -0,0 +1,41 @@ +#ifndef ENGINE_GRAPHICS_VULKAN_MEMORY_BUFFER_H +#define ENGINE_GRAPHICS_VULKAN_MEMORY_BUFFER_H + +#include +#include +#include + +typedef struct { + VkBufferCreateInfo info; + VkBuffer buffer; + VkMemoryRequirements required_memory; + VkDeviceMemory memory; + size_t element_size; + size_t num_elements; + void *mapped_memory; +} buffer_t; + + +/** + * Allocate a buffer + * + * @param v - Vulkan instance to attach to + * @param buffer - Buffer to create + * @param buffer_memory_property_flags - What interface requirements we have. (CPU can see? Coherent? etc) + * @param buffer_usage_flags - Mask provided by the GPU which describes where we can look for memory + * @param buffer_sharing_mode - Sharing mode + * @param element_size - Width of a single element within the buffer + * @param num_elements - Number of elements in the buffer + * @param map_memory_region - If we should map a segment of memory for this buffer + * @return + */ +bool vulkan_buffer_allocate( + vulkan *v, + buffer_t *buffer, + VkMemoryPropertyFlags buffer_memory_property_flags, + VkBufferUsageFlags buffer_usage_flags, VkSharingMode buffer_sharing_mode, + uint32_t element_size, uint32_t num_elements, + bool map_memory_region +); + +#endif diff --git a/src/engine/graphics/vulkan/memory.c b/src/engine/graphics/vulkan/memory/memory.c similarity index 82% rename from src/engine/graphics/vulkan/memory.c rename to src/engine/graphics/vulkan/memory/memory.c index 6b31a1e..0208a0a 100644 --- a/src/engine/graphics/vulkan/memory.c +++ b/src/engine/graphics/vulkan/memory/memory.c @@ -37,7 +37,7 @@ bool vulkan_memory_allocate( const vulkan *const v, const uint32_t memory_type_mask, const VkMemoryPropertyFlags properties, - const uint32_t size, + const VkDeviceSize size, VkDeviceMemory *const memory ) { @@ -63,6 +63,29 @@ bool vulkan_memory_allocate( return vkAllocateMemory(v->devices.logical_device, &memory_allocation_info, NULL, memory) == VK_SUCCESS; } +bool vulkan_memory_map( + const vulkan *const v, + VkDeviceMemory memory, + VkDeviceSize offset, VkDeviceSize size, + void **ptr +) +{ + return vkMapMemory(v->devices.logical_device, memory, offset, size, 0, ptr) == VK_SUCCESS; +} + + + +void vulkan_memory_unmap( + const vulkan *const v, + VkDeviceMemory memory, + void **ptr +) +{ + vkUnmapMemory(v->devices.logical_device, memory); + *ptr = NULL; +} + + void vukan_memory_free( const vulkan *const v, VkDeviceMemory memory diff --git a/src/engine/graphics/vulkan/memory/memory.h b/src/engine/graphics/vulkan/memory/memory.h new file mode 100644 index 0000000..63a1f51 --- /dev/null +++ b/src/engine/graphics/vulkan/memory/memory.h @@ -0,0 +1,40 @@ +#ifndef ENGINE_MEMORY_H +#define ENGINE_MEMORY_H + +#include +#include "src/engine/graphics/vulkan/vulkan.h" + +typedef struct +{ + VkPhysicalDeviceMemoryProperties properties; +} vulkan_device_memory_info; + +bool vulkan_memory_allocate( + const vulkan *v, + uint32_t memory_type_mask, + VkMemoryPropertyFlags properties, + VkDeviceSize size, + VkDeviceMemory *memory +); + +void vukan_memory_free( + const vulkan *v, + VkDeviceMemory memory +); + +bool vulkan_memory_map( + const vulkan *v, + VkDeviceMemory memory, + VkDeviceSize offset, VkDeviceSize size, + void **ptr +); + +void vulkan_memory_unmap( + const vulkan *v, + VkDeviceMemory memory, + void **ptr +); + +bool vulkan_memory_init(vulkan *v); + +#endif diff --git a/src/engine/graphics/vulkan/shaders/vbuffer.c b/src/engine/graphics/vulkan/shaders/vbuffer.c index 4cf43b3..f2b5f3b 100644 --- a/src/engine/graphics/vulkan/shaders/vbuffer.c +++ b/src/engine/graphics/vulkan/shaders/vbuffer.c @@ -1,47 +1,23 @@ #include -#include +#include #include "vbuffer.h" const VkMemoryPropertyFlags vbuffer_memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; -bool vulkan_vbuffer_allocate(vulkan *v, vbuffer *buffer, uint32_t element_size, uint32_t num_elements, - bool map_memory_region) { - const uint32_t size = element_size * num_elements; - - // Clear out old vbuffer - memset(buffer, 0, sizeof(vbuffer)); - - // Engine metadata - buffer->element_size = element_size; - buffer->num_elements = num_elements; - - // Set up buffer dimension info - buffer->info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer->info.size = size; - buffer->info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - buffer->info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - if (vkCreateBuffer(v->devices.logical_device, &buffer->info, NULL, &buffer->buffer) != VK_SUCCESS) { - return false; - } - - vkGetBufferMemoryRequirements(v->devices.logical_device, buffer->buffer, &buffer->required_memory); - - if (!vulkan_memory_allocate(v, buffer->required_memory.memoryTypeBits, vbuffer_memory_properties, size, &buffer->memory)) { - return false; - } - - // Bind the memory to the new buffer - if (vkBindBufferMemory(v->devices.logical_device, buffer->buffer, buffer->memory, 0) != VK_SUCCESS) { - return false; - } - - if (map_memory_region) { - // Map memory location into trapped page (I guess?) - if (vkMapMemory(v->devices.logical_device, buffer->memory, 0, buffer->info.size, 0, &buffer->mapped_memory) != VK_SUCCESS) { - return false; - } - } - - return true; +bool vulkan_vbuffer_allocate( + vulkan *v, + buffer_t *buffer, + uint32_t element_size, + uint32_t num_elements, + bool map_memory_region +) +{ + return vulkan_buffer_allocate( + v, + buffer, + vbuffer_memory_properties, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE, + element_size, num_elements, + map_memory_region + ); } diff --git a/src/engine/graphics/vulkan/shaders/vbuffer.h b/src/engine/graphics/vulkan/shaders/vbuffer.h index ea45d62..662ed97 100644 --- a/src/engine/graphics/vulkan/shaders/vbuffer.h +++ b/src/engine/graphics/vulkan/shaders/vbuffer.h @@ -5,19 +5,10 @@ #include #include #include +#include -typedef struct { - VkBufferCreateInfo info; - VkBuffer buffer; - VkMemoryRequirements required_memory; - VkDeviceMemory memory; - size_t element_size; - size_t num_elements; - void *mapped_memory; -} vbuffer; - -bool vulkan_vbuffer_allocate(vulkan *v, vbuffer *buffer, uint32_t element_size, uint32_t num_elements, +bool vulkan_vbuffer_allocate(vulkan *v, buffer_t *buffer, uint32_t element_size, uint32_t num_elements, bool map_memory_region); #endif diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index 00476dc..0de27de 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -18,7 +18,7 @@ #include "framebuffer.h" #include "commandpool.h" #include "locking.h" -#include "memory.h" +#include "src/engine/graphics/vulkan/memory/memory.h" vulkan v = { .definition = { @@ -33,7 +33,7 @@ vulkan v = { }; vec2 triangle_center_position; -vbuffer triangle_position_buffer; +buffer_t triangle_position_buffer; VkResult vulkan_create_instance() { @@ -117,7 +117,7 @@ bool vulkan_init() return false; } - if (!vulkan_shader_init(&v)) { + if (!vulkan_shader_init()) { return false; } From 9ad6f2dd0ac549b56680a82cdc4cd3f5561f9c48 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Mon, 24 Sep 2018 19:46:54 -0400 Subject: [PATCH 28/30] Implement basic entity system and allow all the basic entity functions Entities can be created, updated, drawn, freed. The draw functionality takes in a VkCommandBuffer and draws the state of the entity to the into the buffer. --- CMakeLists.txt | 7 +- src/engine/entity/definitions/triangle.c | 57 ++++++ src/engine/entity/definitions/triangle.h | 17 ++ src/engine/entity/entity.c | 47 +++++ src/engine/entity/entity.h | 66 +++++++ src/engine/entity/manager.c | 123 +++++++++++++ src/engine/entity/manager.h | 47 +++++ src/engine/graphics/vulkan/commandpool.c | 213 +++++++++++++++++------ src/engine/graphics/vulkan/commandpool.h | 6 +- src/engine/graphics/vulkan/vulkan.c | 96 +--------- src/engine/main.c | 15 +- src/engine/util/dict.c | 75 +++++--- src/engine/util/dict.h | 2 + 13 files changed, 588 insertions(+), 183 deletions(-) create mode 100644 src/engine/entity/definitions/triangle.c create mode 100644 src/engine/entity/definitions/triangle.h create mode 100644 src/engine/entity/entity.c create mode 100644 src/engine/entity/entity.h create mode 100644 src/engine/entity/manager.c create mode 100644 src/engine/entity/manager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 11712e0..efa3815 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,7 +112,12 @@ set(SOURCE_FILES src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h src/engine/graphics/vulkan/shaders/vbuffer.c src/engine/graphics/vulkan/shaders/vbuffer.h src/engine/graphics/vulkan/memory/memory.c src/engine/graphics/vulkan/memory/memory.h - src/engine/util/bits.h src/engine/graphics/vulkan/memory/buffer.h src/engine/graphics/vulkan/memory/buffer.c) + src/engine/util/bits.h src/engine/graphics/vulkan/memory/buffer.h src/engine/graphics/vulkan/memory/buffer.c + + src/engine/entity/entity.c src/engine/entity/entity.h + src/engine/entity/definitions/triangle.c src/engine/entity/definitions/triangle.h + src/engine/entity/manager.c src/engine/entity/manager.h + ) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/entity/definitions/triangle.c b/src/engine/entity/definitions/triangle.c new file mode 100644 index 0000000..c5b234b --- /dev/null +++ b/src/engine/entity/definitions/triangle.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include +#include "triangle.h" + + +vec2 triangle_center_position; +buffer_t triangle_position_buffer; + + +void entity_triangle_update(entity_t *entity, void *metadata) +{ + (void) entity; + (void) metadata; + /** + * set triangle position + */ + triangle_center_position[0] = (cursor_x - (vulkan_window_width_get() / 2.0f)) / vulkan_window_width_get(); + triangle_center_position[1] = (cursor_y - (vulkan_window_height_get() / 2.0f)) / vulkan_window_height_get(); + + // send to gpu via memory mapped region + memcpy(triangle_position_buffer.mapped_memory, &triangle_center_position, sizeof(vec2) * 1); +} + +void entity_triangle_free(entity_t *entity, void *metadata) +{ + (void) entity; + (void) metadata; +} + +void entity_triangle_draw(entity_t *e, VkCommandBuffer buffer) +{ + (void) e; + + VkBuffer vertexBuffers[] = {triangle_position_buffer.buffer}; + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(buffer, 0, 1, vertexBuffers, offsets); + + vkCmdDraw(buffer, (uint32_t) triangle_position_buffer.num_elements, 1, 0, 0); +} + + +void entity_triangle_init(entity_t *entity, vulkan *v) +{ + // TODO: Do not allocate this here. This is game state logic + if (!vulkan_vbuffer_allocate(v, &triangle_position_buffer, sizeof(vec2), 1, true)) { + printf("Failed allocate buffer\n"); + } + + entity->update = (void (*)(struct entity_struct *)) entity_triangle_update; + entity->draw = (void (*)(struct entity_struct *, VkCommandBuffer)) (void (*)(struct entity_struct *)) entity_triangle_draw; + entity->free = (void (*)(struct entity_struct *)) entity_triangle_free; +} diff --git a/src/engine/entity/definitions/triangle.h b/src/engine/entity/definitions/triangle.h new file mode 100644 index 0000000..4dd5923 --- /dev/null +++ b/src/engine/entity/definitions/triangle.h @@ -0,0 +1,17 @@ +#ifndef ENGINE_TRIANGLE_H +#define ENGINE_TRIANGLE_H + + +#include +#include +#include + +void entity_triangle_init(entity_t *entity, vulkan *v); + +void entity_triangle_update(entity_t *entity, void *metadata); + +void entity_triangle_free(entity_t *entity, void *metadata); + +void entity_triangle_draw(entity_t *e, VkCommandBuffer buffer); + +#endif diff --git a/src/engine/entity/entity.c b/src/engine/entity/entity.c new file mode 100644 index 0000000..1ad8317 --- /dev/null +++ b/src/engine/entity/entity.c @@ -0,0 +1,47 @@ +#include "entity.h" + +void entity_init_empty(entity_t *e, void *metadata) +{ + (void) metadata; + if (!e) { + return; + } + + e->allocated = false; + + // Null out behavior + e->draw = NULL; + e->free = NULL; + e->update = NULL; + + if (!e->paramaters) { + // This entity needs a dictionary allocated for them. + e->paramaters = dict_init(16); + } else { + // This entity already had a dict allocated. Just reuse this by emptying it + dict_clear(e->paramaters); + } +} + +void entity_update(entity_t *entity, void *metadata) +{ + (void) metadata; + if (entity->update) { + entity->update(entity); + } +} + +void entity_free(entity_t *entity, void *metadata) +{ + (void) metadata; + if (entity->free) { + entity->free(entity); + } +} + +void entity_draw(entity_t *e, VkCommandBuffer metadata) +{ + if (e->draw) { + e->draw(e, metadata); + } +} diff --git a/src/engine/entity/entity.h b/src/engine/entity/entity.h new file mode 100644 index 0000000..8b74625 --- /dev/null +++ b/src/engine/entity/entity.h @@ -0,0 +1,66 @@ +#ifndef ENGINE_ENTITY_ENTITY_H +#define ENGINE_ENTITY_ENTITY_H + +#include +#include +#include +#include + +/** + * Abstract definition of an entity + */ +typedef struct entity_struct +{ + /** + * Unique ID for every entity + */ + size_t id; + + /** + * Misc paramaters that can't be accounted for + */ + dict *paramaters; + + /** + * If this entity is already being used by something + */ + bool allocated; + + void (*free)(struct entity_struct *); + + void (*update)(struct entity_struct *); + + void (*draw)(struct entity_struct *, VkCommandBuffer buffer); +} entity_t; + +/** + * Abstract definition of initialization of an entity + */ +typedef void (*entity_initializer_t)(entity_t *, void *); + +/** + * Consume and process an entity + */ +typedef void (*entity_consumer_t)(entity_t *, void *); + + +/** + * Initialize an empty entity + * @param e + */ +void entity_init_empty(entity_t *e, void *metadata); + + +void entity_update(entity_t *entity, void *metadata); + +void entity_free(entity_t *entity, void *metadata); + +/** + * Draw an entity to a command buffer + * + * @param e + * @param buffer + */ +void entity_draw(entity_t *e, VkCommandBuffer buffer); + +#endif diff --git a/src/engine/entity/manager.c b/src/engine/entity/manager.c new file mode 100644 index 0000000..ab106f8 --- /dev/null +++ b/src/engine/entity/manager.c @@ -0,0 +1,123 @@ +#include +#include "manager.h" + +struct +{ + size_t freed_entities; + + size_t next_entity_id; + size_t num_entities; + size_t next_allocation_index; + entity_t *entities; +} entity_pool; + + +bool entity_manager_init(size_t num_entites) +{ + entity_pool.freed_entities = 0; + + entity_pool.next_entity_id = 0; + entity_pool.num_entities = num_entites; + entity_pool.next_allocation_index = 0; + entity_pool.entities = calloc(sizeof(entity_t), num_entites); + + + // Pre-allocate null entities + entity_manager_for_each(entity_init_empty, NULL, false); + + return true; +} + +entity_t *entity_manager_take(entity_initializer_t initializer, void *metadata) +{ + entity_t *entity = NULL; + + if (entity_pool.freed_entities) { + // We have non-compacted entities. We need to linearly search rather + // than allocating a new entity + for (size_t i = 0; i < entity_pool.num_entities; i++) { + if (entity_pool.entities[i].allocated) { + continue; + } + + entity = &entity_pool.entities[i]; + break; + } + + if (!entity) { + printf("No entities were free despite freed_entities being marked as %zu\n", entity_pool.freed_entities); + return NULL; + } + + entity_pool.freed_entities -= 1; + } else { + // All of our entities are compactly allocated. We can take from the end + // of our preallocated set and avoid a linear search + if (entity_pool.num_entities < entity_pool.next_allocation_index) { + // TODO: Slab allocation? + printf("Ran out of entities to allocate\n"); + return NULL; + } + entity = &entity_pool.entities[entity_pool.next_allocation_index++]; + } + + entity->id = entity_pool.next_entity_id++; + entity->allocated = true; + + // Call initializer + initializer(entity, metadata); + + return entity; +} + + +void entity_manager_for_each(entity_consumer_t consumer, void *metadata, bool only_allocated) +{ + size_t remaining_freed_entities = entity_pool.freed_entities; + + for (size_t i = 0; i < entity_pool.num_entities; i++) { + + // If we only want to run against allocated entities stop + // as soon as we find a non allocated entity + if (only_allocated) { + if (!entity_pool.entities[i].allocated) { + + // We expected some freed entities. If we have already hit all of the freed entities + // that we knew about then we can finally die + if (!remaining_freed_entities) { + return; + } + + // Otherwise we need to mark that we've seen a freed entity and it skip this one + remaining_freed_entities -= 1; + continue; + } + } + + // Pass to consumer + consumer(&entity_pool.entities[i], metadata); + } +} + + +/** + * Return an entity to the unallocated pool + * @param entity + */ +void entity_manager_release(entity_t *entity) +{ + entity_free(entity, NULL); + entity_init_empty(entity, NULL); + + entity_pool.freed_entities += 1; +} + +void entity_manager_update() +{ + entity_manager_for_each(entity_update, NULL, true); +} + +void entity_manager_draw(VkCommandBuffer buffer) +{ + entity_manager_for_each((entity_consumer_t) entity_draw, buffer, true); +} diff --git a/src/engine/entity/manager.h b/src/engine/entity/manager.h new file mode 100644 index 0000000..58d027b --- /dev/null +++ b/src/engine/entity/manager.h @@ -0,0 +1,47 @@ +#ifndef ENGINE_ENTITY_MANAGER_H +#define ENGINE_ENTITY_MANAGER_H + +#include +#include +#include "entity.h" + +/** + * Wrap entity_manager_make with casts for simplicity + */ +#define entity_manager_make(initializer, metadata) entity_manager_take((entity_initializer_t) initializer, (void*) metadata) + +/** + * Initialize the entity pool + * @param num_entites + * @return + */ +bool entity_manager_init(size_t num_entites); + +/** + * Find a free entity + * @param initializer - Initialization function + * @param metadata - Metadata required to create this entity + * @return + */ +entity_t *entity_manager_take(entity_initializer_t initializer, void *metadata); + +/** + * Return an entity to the unallocated pool + * @param entity + */ +void entity_manager_release(entity_t *entity); + +/** + * Run a function against every allocated entity + * @param consumer + * @param metadata - Data passed to the consumer in addition to the entity + * @param only_allocated + */ +void entity_manager_for_each(entity_consumer_t consumer, void *metadata, bool only_allocated); + + +void entity_manager_update(); + +void entity_manager_draw(VkCommandBuffer buffer); + +#endif diff --git a/src/engine/graphics/vulkan/commandpool.c b/src/engine/graphics/vulkan/commandpool.c index bc5904c..f70f82f 100644 --- a/src/engine/graphics/vulkan/commandpool.c +++ b/src/engine/graphics/vulkan/commandpool.c @@ -1,9 +1,15 @@ #include #include #include +#include +#include #include "commandpool.h" +#include "locking.h" +bool *command_buffer_submitted; +VkFence *fences; VkCommandBuffer *command_buffer; +size_t current_command_buffer = 0; VkCommandBuffer *vulkan_command_pool_get(size_t pool_index) { @@ -11,9 +17,19 @@ VkCommandBuffer *vulkan_command_pool_get(size_t pool_index) return &command_buffer[pool_index]; } + +VkFence vulkan_command_fence_get(size_t pool_index) +{ + // TODO: Bounds checking + return fences[pool_index]; +} + + bool vulkan_command_pool_buffer_init(vulkan *v) { - command_buffer = malloc(sizeof(VkCommandBuffer) * v->swapchain.num_images); + fences = calloc(sizeof(VkFence), v->swapchain.num_images); + command_buffer = calloc(sizeof(VkCommandBuffer), v->swapchain.num_images); + command_buffer_submitted = calloc(sizeof(bool), v->swapchain.num_images); VkCommandBufferAllocateInfo allocation_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .commandPool = v->command_pool, @@ -21,6 +37,17 @@ bool vulkan_command_pool_buffer_init(vulkan *v) .commandBufferCount = (uint32_t) v->swapchain.num_images }; + for (size_t i = 0; i < v->swapchain.num_images; i++) { + VkFenceCreateInfo fence_create_info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = 0, + .pNext = NULL + }; + if (vkCreateFence(v->devices.logical_device, &fence_create_info, NULL, &fences[i]) != VK_SUCCESS) { + printf("Failed to allocate fence for command buffer!\n"); + return false; + } + } if (vkAllocateCommandBuffers(v->devices.logical_device, &allocation_info, command_buffer) != VK_SUCCESS) { printf("Failed to allocate command buffer for pool\n"); @@ -30,76 +57,156 @@ bool vulkan_command_pool_buffer_init(vulkan *v) return true; } -bool vulkan_command_pool_buffer_recording_start(vulkan *v) +bool vulkan_command_pool_render_pass_begin(vulkan *v, uint32_t image_id) { - for (size_t i = 0; i < v->swapchain.num_images; i++) { - VkCommandBufferBeginInfo command_buffer_begin_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, - .pInheritanceInfo = NULL - }; + VkClearValue clear_color = { + .color.float32 = { + 0, 0, 0, 0 + } + }; + VkRenderPassBeginInfo render_pass_info = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = v->pipelines.render_pass, + .framebuffer = v->swapchain.frame_buffers[image_id], + .renderArea = { + .offset = {0, 0}, + .extent = v->swapchain.extent + }, + .clearValueCount = 1, + .pClearValues = &clear_color, + }; + + VkCommandBufferBeginInfo command_buffer_begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, + .pInheritanceInfo = NULL, + }; + + + vkResetCommandBuffer(command_buffer[image_id], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + + if (vkBeginCommandBuffer(command_buffer[current_command_buffer], &command_buffer_begin_info) != VK_SUCCESS) { + printf("Failed to start recording on command buffer %u\n", image_id); + return false; + } + + { + vkCmdBeginRenderPass(command_buffer[current_command_buffer], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); + { + // TODO: Bind pipeline based on material + vkCmdBindPipeline(command_buffer[current_command_buffer], VK_PIPELINE_BIND_POINT_GRAPHICS, v->pipelines.graphics); + + // TODO: Maybe put this in a cleaner place? + entity_manager_draw(command_buffer[current_command_buffer]); - if (vkBeginCommandBuffer(command_buffer[i], &command_buffer_begin_info) != VK_SUCCESS) { - printf("Failed to start recording on command buffer %zu\n", i); - return false; } + vkCmdEndRenderPass(command_buffer[current_command_buffer]); + } + + if (vkEndCommandBuffer(command_buffer[current_command_buffer]) != VK_SUCCESS) { + printf("Failed to end command buffer sequence when sending render job to %u\n", image_id); + return false; } + return true; } - -bool vulkan_command_pool_render_pass_begin(vulkan *v, buffer_t *buffer) +void vulkan_command_pool_render(vulkan *v) { - for (size_t i = 0; i < v->swapchain.num_images; i++) { - VkClearValue clear_color = { - .color.float32 = { - 0, 0, 0, 0 - } - }; - VkRenderPassBeginInfo render_pass_info = { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .renderPass = v->pipelines.render_pass, - .framebuffer = v->swapchain.frame_buffers[i], - .renderArea = { - .offset = {0, 0}, - .extent = v->swapchain.extent - }, - .clearValueCount = 1, - .pClearValues = &clear_color, - }; + if (command_buffer_submitted[current_command_buffer]) { + if (vkWaitForFences(v->devices.logical_device, 1, &fences[current_command_buffer], VK_TRUE, UINT64_MAX) != VK_SUCCESS) { + printf("Failed to wait on rendering fence\n"); + return; + } + } - { - vkCmdBeginRenderPass(command_buffer[i], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); - { - vkCmdBindPipeline(command_buffer[i], VK_PIPELINE_BIND_POINT_GRAPHICS, v->pipelines.graphics); + if (vkResetFences(v->devices.logical_device, 1, &fences[current_command_buffer]) != VK_SUCCESS) { + printf("Failed to resent rendering fence\n"); + } - // TODO: How the fuck to I get this buffer data into here?! - VkBuffer vertexBuffers[] = {buffer->buffer}; - VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(command_buffer[i], 0, 1, vertexBuffers, offsets); + uint32_t image_index; + vkAcquireNextImageKHR( + v->devices.logical_device, + v->swapchain.swapchain, + UINT64_MAX, + vulkan_locking_semphore_get_frame_buffer_image_available(), + VK_NULL_HANDLE, + &image_index + ); + + if (!vulkan_command_pool_render_pass_begin(v, image_index)) { + printf("Failed to render\n"); + } - vkCmdDraw(command_buffer[i], (uint32_t) buffer->num_elements, 1, 0, 0); + // Render starting configuration + VkSemaphore waiting_semaphores[] = { + vulkan_locking_semphore_get_frame_buffer_image_available() + }; + VkPipelineStageFlags stages[] = { + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + }; - } - vkCmdEndRenderPass(command_buffer[i]); + // Render ending configuration + VkSemaphore signaling_semaphores[] = { + vulkan_locking_semphore_get_rendering_finished() + }; - if (vkEndCommandBuffer(command_buffer[i]) != VK_SUCCESS) { - printf("Failed to end command buffer sequence when sending render job to %zu\n", i); - return false; - } - } + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = 1, + .pWaitSemaphores = waiting_semaphores, + .pWaitDstStageMask = stages, + + + // Link the command buffer to the render stage + .commandBufferCount = 1, + .pCommandBuffers = vulkan_command_pool_get(image_index), + + + // After rendering signal these semphores + .signalSemaphoreCount = 1, + .pSignalSemaphores = signaling_semaphores + }; + + // Submitting render job + if (vkQueueSubmit(v->queues.rendering, 1, &submit_info, vulkan_command_fence_get(current_command_buffer)) != VK_SUCCESS) { + printf("Failed to render!\n"); } - return true; + // Submitting presenting job + VkSwapchainKHR subscribing_swapchains[] = { + v->swapchain.swapchain + }; + + VkPresentInfoKHR present_info = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + // Subscribe + .waitSemaphoreCount = 1, + .pWaitSemaphores = signaling_semaphores, + + .swapchainCount = 1, + .pSwapchains = subscribing_swapchains, + .pImageIndices = &image_index, + + .pResults = NULL + }; + + vkQueuePresentKHR(v->queues.presenting, &present_info); + + // mark this command buffer as dirty + command_buffer_submitted[current_command_buffer] = true; + + // Increment command buffer + current_command_buffer = (current_command_buffer + 1) % v->swapchain.num_images; } -bool vulkan_command_pool_init(vulkan *v, buffer_t *buffer) +bool vulkan_command_pool_init(vulkan *v) { VkCommandPoolCreateInfo poolInfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .flags = 0, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = v->queues.main_rendering_queue_id }; @@ -113,13 +220,5 @@ bool vulkan_command_pool_init(vulkan *v, buffer_t *buffer) return false; } - if (!vulkan_command_pool_buffer_recording_start(v)) { - return false; - } - - if (!vulkan_command_pool_render_pass_begin(v, buffer)) { - return false; - } - return true; } diff --git a/src/engine/graphics/vulkan/commandpool.h b/src/engine/graphics/vulkan/commandpool.h index 20ae2f3..9bb8cec 100644 --- a/src/engine/graphics/vulkan/commandpool.h +++ b/src/engine/graphics/vulkan/commandpool.h @@ -3,7 +3,11 @@ #include "vulkan.h" -bool vulkan_command_pool_init(vulkan *v, buffer_t *buffer); +VkFence vulkan_command_fence_get(size_t pool_index); + +void vulkan_command_pool_render(vulkan *v); + +bool vulkan_command_pool_init(vulkan *v); VkCommandBuffer *vulkan_command_pool_get(size_t pool_index); diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index 0de27de..a219d40 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #include "query.h" #include "vulkan.h" #include "config.h" @@ -31,10 +34,7 @@ vulkan v = { }, .devices.selected_device = VK_NULL_HANDLE }; - -vec2 triangle_center_position; -buffer_t triangle_position_buffer; - +entity_t *e; VkResult vulkan_create_instance() { VkInstanceCreateInfo creation_request = { @@ -140,18 +140,14 @@ bool vulkan_init() return false; } - // TODO: Do not allocate this here. This is game state logic - if (!vulkan_vbuffer_allocate(&v, &triangle_position_buffer, sizeof(vec2), 1, true)) { - printf("Failed allocate buffer\n"); - return false; - } - // TODO: We should NOT be passing the triangle position buffer in like this - if (!vulkan_command_pool_init(&v, &triangle_position_buffer)) { + if (!vulkan_command_pool_init(&v)) { printf("Failed to init command pool\n"); - return false; } + // TODO: Move creation of entities out of vulkan.c + e = entity_manager_make(entity_triangle_init, &v); + // Info to prove we have loaded everything vulkan_info_print(); @@ -160,81 +156,7 @@ bool vulkan_init() void vulkan_render() { - - /** - * set triangle position - */ - triangle_center_position[0] = (cursor_x - (vulkan_window_width_get() / 2.0f)) / vulkan_window_width_get(); - triangle_center_position[1] = (cursor_y - (vulkan_window_height_get() / 2.0f)) / vulkan_window_height_get(); - - // send to gpu via memory mapped region - memcpy(triangle_position_buffer.mapped_memory, &triangle_center_position, sizeof(vec2) * 1); - - uint32_t image_index; - vkAcquireNextImageKHR( - v.devices.logical_device, - v.swapchain.swapchain, - UINT64_MAX, - vulkan_locking_semphore_get_frame_buffer_image_available(), - VK_NULL_HANDLE, - &image_index - ); - - // Render starting configuration - VkSemaphore waiting_semaphores[] = { - vulkan_locking_semphore_get_frame_buffer_image_available() - }; - VkPipelineStageFlags stages[] = { - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT - }; - - // Render ending configuration - VkSemaphore signaling_semaphores[] = { - vulkan_locking_semphore_get_rendering_finished() - }; - - - VkSubmitInfo submit_info = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .waitSemaphoreCount = 1, - .pWaitSemaphores = waiting_semaphores, - .pWaitDstStageMask = stages, - - - // Link the command buffer to the render stage - .commandBufferCount = 1, - .pCommandBuffers = vulkan_command_pool_get(image_index), - - - // After rendering signal these semphores - .signalSemaphoreCount = 1, - .pSignalSemaphores = signaling_semaphores - }; - - // Submitting render job - if (vkQueueSubmit(v.queues.rendering, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { - printf("Failed to render!\n"); - } - - // Submitting presenting job - VkSwapchainKHR subscribing_swapchains[] = { - v.swapchain.swapchain - }; - - VkPresentInfoKHR present_info = { - .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - // Subscribe - .waitSemaphoreCount = 1, - .pWaitSemaphores = signaling_semaphores, - - .swapchainCount = 1, - .pSwapchains = subscribing_swapchains, - .pImageIndices = &image_index, - - .pResults = NULL - }; - - vkQueuePresentKHR(v.queues.presenting, &present_info); + vulkan_command_pool_render(&v); } void vulkan_update() diff --git a/src/engine/main.c b/src/engine/main.c index 32c2219..a553914 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "src/engine/scripting/callbacks.h" #include "src/engine/scripting/script.h" @@ -47,21 +48,19 @@ void init() { int main() { + if (!entity_manager_init(128)) { + printf("Failed to initialize the entity manager\n"); + return 1; + } + if (!vulkan_init()) { printf("Failed to initialize graphics layer\n"); return 1; } - //init(); // Init our code. - - //REGISTER_GLFW_CALLBACKS(); - while (!vulkan_window_is_close_requested()) { - //update(); - //draw(); - - //glfwSwapBuffers(window); + entity_manager_update(); vulkan_update(); vulkan_render(); } diff --git a/src/engine/util/dict.c b/src/engine/util/dict.c index 9898185..6810b93 100644 --- a/src/engine/util/dict.c +++ b/src/engine/util/dict.c @@ -14,51 +14,68 @@ typedef size_t bucket_index_t; * @param length - Length of the name * @return */ -static inline bucket_index_t dict_bucket_for(dict *d, const char *const name, const size_t length) { - const uint_fast32_t hash = hashing_crc32_make(name, length); - const size_t num_buckets = d->num_buckets; - return (bucket_index_t) (hash % num_buckets); +static inline bucket_index_t dict_bucket_for(dict *d, const char *const name, const size_t length) +{ + const uint_fast32_t hash = hashing_crc32_make(name, length); + const size_t num_buckets = d->num_buckets; + return (bucket_index_t) (hash % num_buckets); } -static inline bool dict_bucket_empty(dict *d, bucket_index_t i) { - return llist_empty(&d->buckets[i]); +static inline bool dict_bucket_empty(dict *d, bucket_index_t i) +{ + return llist_empty(&d->buckets[i]); } -dict *dict_init(size_t num_buckets) { - const size_t size_of_buckets = sizeof(llist *) * num_buckets; - dict *d = malloc(sizeof(dict) + size_of_buckets); - d->num_buckets = num_buckets; - memset(d->buckets, 0, size_of_buckets); - return d; +dict *dict_init(size_t num_buckets) +{ + const size_t size_of_buckets = sizeof(llist *) * num_buckets; + dict *d = malloc(sizeof(dict) + size_of_buckets); + d->num_buckets = num_buckets; + memset(d->buckets, 0, size_of_buckets); + return d; } -bool dict_get(dict *d, const char *const name, void *value, size_t *length) { - const size_t len_name = strlen(name); - bucket_index_t index = dict_bucket_for(d, name, len_name); +void dict_clear(dict *d) +{ + if (d) { + for (bucket_index_t i = 0; i < d->num_buckets; i++) { + llist_free(&d->buckets[i]); + } + } +} + +bool dict_get(dict *d, const char *const name, void *value, size_t *length) +{ + const size_t len_name = strlen(name); + bucket_index_t index = dict_bucket_for(d, name, len_name); - if (dict_bucket_empty(d, index)) { - return false; - } + if (dict_bucket_empty(d, index)) { + return false; + } - return llist_retrive(&d->buckets[index], name, value, length); + return llist_retrive(&d->buckets[index], name, value, length); } -bool dict_get_string(dict *d, const char *const name, char **value) { - return dict_get(d, name, (void *) value, NULL); +bool dict_get_string(dict *d, const char *const name, char **value) +{ + return dict_get(d, name, (void *) value, NULL); } -bool dict_has(dict *d, const char *const name) { - return dict_get(d, name, NULL, NULL); +bool dict_has(dict *d, const char *const name) +{ + return dict_get(d, name, NULL, NULL); } -void dict_set(dict *d, const char *const name, void *value, size_t length) { - const size_t len_name = strlen(name); - bucket_index_t index = dict_bucket_for(d, name, len_name); - llist_add(&d->buckets[index], name, value, length); +void dict_set(dict *d, const char *const name, void *value, size_t length) +{ + const size_t len_name = strlen(name); + bucket_index_t index = dict_bucket_for(d, name, len_name); + llist_add(&d->buckets[index], name, value, length); } -void dict_set_string(dict *d, const char *const name, char *value) { - dict_set(d, name, value, strlen(value)); +void dict_set_string(dict *d, const char *const name, char *value) +{ + dict_set(d, name, value, strlen(value)); } diff --git a/src/engine/util/dict.h b/src/engine/util/dict.h index 6afde73..21197f7 100644 --- a/src/engine/util/dict.h +++ b/src/engine/util/dict.h @@ -14,6 +14,8 @@ typedef struct { dict *dict_init(size_t num_buckets); +void dict_clear(dict *d); + /** * Get a value from the dictionary * From 6e095710d743d3cdd764be4daa6905308be362c5 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sun, 30 Sep 2018 14:08:51 -0400 Subject: [PATCH 29/30] Refactor entire command buffer/command pool code. This needed to happen for two reasons: 1. The rendering loop was a huge mess and was impossible to follow 2. The requirements for staging buffers and model loading would not play well with the previous organization. We need to be able to control render passes and commands buffers seperately. --- CMakeLists.txt | 5 +- src/engine/entity/definitions/triangle.c | 22 +- src/engine/graphics/vulkan/commandpool.c | 224 ------------------ src/engine/graphics/vulkan/commandpool.h | 14 -- src/engine/graphics/vulkan/commands/buffer.c | 63 +++++ src/engine/graphics/vulkan/commands/buffer.h | 34 +++ src/engine/graphics/vulkan/commands/pool.c | 140 +++++++++++ src/engine/graphics/vulkan/commands/pool.h | 72 ++++++ src/engine/graphics/vulkan/commands/render.c | 30 +++ src/engine/graphics/vulkan/commands/render.h | 27 +++ .../graphics/vulkan/materials/material.c | 3 + .../graphics/vulkan/materials/material.h | 22 ++ src/engine/graphics/vulkan/memory/buffer.c | 47 +++- src/engine/graphics/vulkan/memory/buffer.h | 23 +- src/engine/graphics/vulkan/memory/memory.c | 4 +- src/engine/graphics/vulkan/memory/memory.h | 2 +- src/engine/graphics/vulkan/memory/vbuffer.c | 18 ++ src/engine/graphics/vulkan/memory/vbuffer.h | 29 +++ src/engine/graphics/vulkan/shaders/vbuffer.c | 23 -- src/engine/graphics/vulkan/shaders/vbuffer.h | 14 -- src/engine/graphics/vulkan/swapchain.c | 19 +- src/engine/graphics/vulkan/swapchain.h | 2 + src/engine/graphics/vulkan/vulkan.c | 84 ++++++- src/engine/graphics/vulkan/vulkan.h | 1 - src/engine/main.c | 1 - 25 files changed, 611 insertions(+), 312 deletions(-) delete mode 100644 src/engine/graphics/vulkan/commandpool.c delete mode 100644 src/engine/graphics/vulkan/commandpool.h create mode 100644 src/engine/graphics/vulkan/commands/buffer.c create mode 100644 src/engine/graphics/vulkan/commands/buffer.h create mode 100644 src/engine/graphics/vulkan/commands/pool.c create mode 100644 src/engine/graphics/vulkan/commands/pool.h create mode 100644 src/engine/graphics/vulkan/commands/render.c create mode 100644 src/engine/graphics/vulkan/commands/render.h create mode 100644 src/engine/graphics/vulkan/materials/material.c create mode 100644 src/engine/graphics/vulkan/materials/material.h create mode 100644 src/engine/graphics/vulkan/memory/vbuffer.c create mode 100644 src/engine/graphics/vulkan/memory/vbuffer.h delete mode 100644 src/engine/graphics/vulkan/shaders/vbuffer.c delete mode 100644 src/engine/graphics/vulkan/shaders/vbuffer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index efa3815..08dd391 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,16 +108,15 @@ set(SOURCE_FILES src/engine/graphics/vulkan/shaders/shader.c src/engine/graphics/vulkan/shaders/shader.h src/engine/graphics/vulkan/pipeline.c src/engine/graphics/vulkan/pipeline.h src/engine/graphics/vulkan/framebuffer.c src/engine/graphics/vulkan/framebuffer.h - src/engine/graphics/vulkan/commandpool.c src/engine/graphics/vulkan/commandpool.h src/engine/graphics/vulkan/locking.c src/engine/graphics/vulkan/locking.h - src/engine/graphics/vulkan/shaders/vbuffer.c src/engine/graphics/vulkan/shaders/vbuffer.h + src/engine/graphics/vulkan/memory/vbuffer.c src/engine/graphics/vulkan/memory/vbuffer.h src/engine/graphics/vulkan/memory/memory.c src/engine/graphics/vulkan/memory/memory.h src/engine/util/bits.h src/engine/graphics/vulkan/memory/buffer.h src/engine/graphics/vulkan/memory/buffer.c src/engine/entity/entity.c src/engine/entity/entity.h src/engine/entity/definitions/triangle.c src/engine/entity/definitions/triangle.h src/engine/entity/manager.c src/engine/entity/manager.h - ) + src/engine/graphics/vulkan/commands/pool.c src/engine/graphics/vulkan/commands/pool.h src/engine/graphics/vulkan/commands/buffer.c src/engine/graphics/vulkan/commands/buffer.h src/engine/graphics/vulkan/commands/render.c src/engine/graphics/vulkan/commands/render.h) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/engine/entity/definitions/triangle.c b/src/engine/entity/definitions/triangle.c index c5b234b..2f711b8 100644 --- a/src/engine/entity/definitions/triangle.c +++ b/src/engine/entity/definitions/triangle.c @@ -2,28 +2,28 @@ #include #include #include -#include +#include #include -#include #include "triangle.h" -vec2 triangle_center_position; +vec2 *triangle_center_position; buffer_t triangle_position_buffer; - void entity_triangle_update(entity_t *entity, void *metadata) { (void) entity; (void) metadata; + + vec2 v = { + (cursor_x - (vulkan_window_width_get() / 2.0f)) / vulkan_window_width_get(), + (cursor_y - (vulkan_window_height_get() / 2.0f)) / vulkan_window_height_get() + }; + /** * set triangle position */ - triangle_center_position[0] = (cursor_x - (vulkan_window_width_get() / 2.0f)) / vulkan_window_width_get(); - triangle_center_position[1] = (cursor_y - (vulkan_window_height_get() / 2.0f)) / vulkan_window_height_get(); - - // send to gpu via memory mapped region - memcpy(triangle_position_buffer.mapped_memory, &triangle_center_position, sizeof(vec2) * 1); + memcpy(triangle_center_position, &v, sizeof(vec2)); } void entity_triangle_free(entity_t *entity, void *metadata) @@ -47,10 +47,12 @@ void entity_triangle_draw(entity_t *e, VkCommandBuffer buffer) void entity_triangle_init(entity_t *entity, vulkan *v) { // TODO: Do not allocate this here. This is game state logic - if (!vulkan_vbuffer_allocate(v, &triangle_position_buffer, sizeof(vec2), 1, true)) { + if (!vulkan_memory_vbuffer_allocate(v, &triangle_position_buffer, sizeof(vec2), 1, true)) { printf("Failed allocate buffer\n"); } + triangle_center_position = triangle_position_buffer.mapped_memory; + entity->update = (void (*)(struct entity_struct *)) entity_triangle_update; entity->draw = (void (*)(struct entity_struct *, VkCommandBuffer)) (void (*)(struct entity_struct *)) entity_triangle_draw; entity->free = (void (*)(struct entity_struct *)) entity_triangle_free; diff --git a/src/engine/graphics/vulkan/commandpool.c b/src/engine/graphics/vulkan/commandpool.c deleted file mode 100644 index f70f82f..0000000 --- a/src/engine/graphics/vulkan/commandpool.c +++ /dev/null @@ -1,224 +0,0 @@ -#include -#include -#include -#include -#include -#include "commandpool.h" -#include "locking.h" - -bool *command_buffer_submitted; -VkFence *fences; -VkCommandBuffer *command_buffer; -size_t current_command_buffer = 0; - -VkCommandBuffer *vulkan_command_pool_get(size_t pool_index) -{ - // TODO: Bounds checking - return &command_buffer[pool_index]; -} - - -VkFence vulkan_command_fence_get(size_t pool_index) -{ - // TODO: Bounds checking - return fences[pool_index]; -} - - -bool vulkan_command_pool_buffer_init(vulkan *v) -{ - fences = calloc(sizeof(VkFence), v->swapchain.num_images); - command_buffer = calloc(sizeof(VkCommandBuffer), v->swapchain.num_images); - command_buffer_submitted = calloc(sizeof(bool), v->swapchain.num_images); - VkCommandBufferAllocateInfo allocation_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = v->command_pool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = (uint32_t) v->swapchain.num_images - }; - - for (size_t i = 0; i < v->swapchain.num_images; i++) { - VkFenceCreateInfo fence_create_info = { - .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - .flags = 0, - .pNext = NULL - }; - if (vkCreateFence(v->devices.logical_device, &fence_create_info, NULL, &fences[i]) != VK_SUCCESS) { - printf("Failed to allocate fence for command buffer!\n"); - return false; - } - } - - if (vkAllocateCommandBuffers(v->devices.logical_device, &allocation_info, command_buffer) != VK_SUCCESS) { - printf("Failed to allocate command buffer for pool\n"); - return false; - } - - return true; -} - -bool vulkan_command_pool_render_pass_begin(vulkan *v, uint32_t image_id) -{ - VkClearValue clear_color = { - .color.float32 = { - 0, 0, 0, 0 - } - }; - VkRenderPassBeginInfo render_pass_info = { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .renderPass = v->pipelines.render_pass, - .framebuffer = v->swapchain.frame_buffers[image_id], - .renderArea = { - .offset = {0, 0}, - .extent = v->swapchain.extent - }, - .clearValueCount = 1, - .pClearValues = &clear_color, - }; - - VkCommandBufferBeginInfo command_buffer_begin_info = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, - .pInheritanceInfo = NULL, - }; - - - vkResetCommandBuffer(command_buffer[image_id], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); - - if (vkBeginCommandBuffer(command_buffer[current_command_buffer], &command_buffer_begin_info) != VK_SUCCESS) { - printf("Failed to start recording on command buffer %u\n", image_id); - return false; - } - - { - vkCmdBeginRenderPass(command_buffer[current_command_buffer], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); - { - // TODO: Bind pipeline based on material - vkCmdBindPipeline(command_buffer[current_command_buffer], VK_PIPELINE_BIND_POINT_GRAPHICS, v->pipelines.graphics); - - // TODO: Maybe put this in a cleaner place? - entity_manager_draw(command_buffer[current_command_buffer]); - - } - vkCmdEndRenderPass(command_buffer[current_command_buffer]); - } - - if (vkEndCommandBuffer(command_buffer[current_command_buffer]) != VK_SUCCESS) { - printf("Failed to end command buffer sequence when sending render job to %u\n", image_id); - return false; - } - - - return true; -} - -void vulkan_command_pool_render(vulkan *v) -{ - if (command_buffer_submitted[current_command_buffer]) { - if (vkWaitForFences(v->devices.logical_device, 1, &fences[current_command_buffer], VK_TRUE, UINT64_MAX) != VK_SUCCESS) { - printf("Failed to wait on rendering fence\n"); - return; - } - } - - if (vkResetFences(v->devices.logical_device, 1, &fences[current_command_buffer]) != VK_SUCCESS) { - printf("Failed to resent rendering fence\n"); - } - - uint32_t image_index; - vkAcquireNextImageKHR( - v->devices.logical_device, - v->swapchain.swapchain, - UINT64_MAX, - vulkan_locking_semphore_get_frame_buffer_image_available(), - VK_NULL_HANDLE, - &image_index - ); - - if (!vulkan_command_pool_render_pass_begin(v, image_index)) { - printf("Failed to render\n"); - } - - // Render starting configuration - VkSemaphore waiting_semaphores[] = { - vulkan_locking_semphore_get_frame_buffer_image_available() - }; - VkPipelineStageFlags stages[] = { - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT - }; - - // Render ending configuration - VkSemaphore signaling_semaphores[] = { - vulkan_locking_semphore_get_rendering_finished() - }; - - - VkSubmitInfo submit_info = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .waitSemaphoreCount = 1, - .pWaitSemaphores = waiting_semaphores, - .pWaitDstStageMask = stages, - - - // Link the command buffer to the render stage - .commandBufferCount = 1, - .pCommandBuffers = vulkan_command_pool_get(image_index), - - - // After rendering signal these semphores - .signalSemaphoreCount = 1, - .pSignalSemaphores = signaling_semaphores - }; - - // Submitting render job - if (vkQueueSubmit(v->queues.rendering, 1, &submit_info, vulkan_command_fence_get(current_command_buffer)) != VK_SUCCESS) { - printf("Failed to render!\n"); - } - - // Submitting presenting job - VkSwapchainKHR subscribing_swapchains[] = { - v->swapchain.swapchain - }; - - VkPresentInfoKHR present_info = { - .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - // Subscribe - .waitSemaphoreCount = 1, - .pWaitSemaphores = signaling_semaphores, - - .swapchainCount = 1, - .pSwapchains = subscribing_swapchains, - .pImageIndices = &image_index, - - .pResults = NULL - }; - - vkQueuePresentKHR(v->queues.presenting, &present_info); - - // mark this command buffer as dirty - command_buffer_submitted[current_command_buffer] = true; - - // Increment command buffer - current_command_buffer = (current_command_buffer + 1) % v->swapchain.num_images; -} - -bool vulkan_command_pool_init(vulkan *v) -{ - VkCommandPoolCreateInfo poolInfo = { - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, - .queueFamilyIndex = v->queues.main_rendering_queue_id - }; - - - if (vkCreateCommandPool(v->devices.logical_device, &poolInfo, NULL, &v->command_pool) != VK_SUCCESS) { - printf("Failed to initialize command pool\n"); - return false; - } - - if (!vulkan_command_pool_buffer_init(v)) { - return false; - } - - return true; -} diff --git a/src/engine/graphics/vulkan/commandpool.h b/src/engine/graphics/vulkan/commandpool.h deleted file mode 100644 index 9bb8cec..0000000 --- a/src/engine/graphics/vulkan/commandpool.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef ENGINE_CPOOL_H -#define ENGINE_CPOOL_H - -#include "vulkan.h" - -VkFence vulkan_command_fence_get(size_t pool_index); - -void vulkan_command_pool_render(vulkan *v); - -bool vulkan_command_pool_init(vulkan *v); - -VkCommandBuffer *vulkan_command_pool_get(size_t pool_index); - -#endif diff --git a/src/engine/graphics/vulkan/commands/buffer.c b/src/engine/graphics/vulkan/commands/buffer.c new file mode 100644 index 0000000..50989e6 --- /dev/null +++ b/src/engine/graphics/vulkan/commands/buffer.c @@ -0,0 +1,63 @@ +#include +#include "buffer.h" +#include "pool.h" + + +bool vulkan_commands_buffer_begin(cbuffer_pool_t *pool, uint32_t cbuffer_id) +{ + VkCommandBuffer buffer = vulkan_commands_cpool_cbuffer_get(pool, cbuffer_id); + + VkCommandBufferBeginInfo command_buffer_begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, + .pInheritanceInfo = NULL, + }; + + + vkResetCommandBuffer(buffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + + if (vkBeginCommandBuffer(buffer, &command_buffer_begin_info) != VK_SUCCESS) { + printf("Failed to start recording on command buffer %u\n", cbuffer_id); + return false; + } + + return true; +} + + +void vulkan_commands_buffer_end( + cbuffer_pool_t *pool, uint32_t cbuffer_id, + uint32_t num_waiting_semaphores, VkSemaphore *waiting_semaphores, const VkPipelineStageFlags *waiting_semaphores_signaled_at, + uint32_t num_signaling_semaphores, VkSemaphore *signaling_semaphores +) +{ + VkQueue queue = pool->owners.queue; + VkCommandBuffer buffer = vulkan_commands_cpool_cbuffer_get(pool, cbuffer_id); + VkFence fence = vulkan_commands_cpool_fence_get(pool, cbuffer_id); + + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = num_waiting_semaphores, + .pWaitSemaphores = waiting_semaphores, + .pWaitDstStageMask = waiting_semaphores_signaled_at, + + + // Link the command buffer to the render stage + .commandBufferCount = 1, + .pCommandBuffers = &buffer, + + // After rendering signal these semphores + .signalSemaphoreCount = num_signaling_semaphores, + .pSignalSemaphores = signaling_semaphores + }; + + // Mark that we've started using this command buffer + vulkan_commands_cpool_cbuffer_id_mark(pool, cbuffer_id); + + vkEndCommandBuffer(buffer); + + // Submitting render job + if (vkQueueSubmit(queue, 1, &submit_info, fence) != VK_SUCCESS) { + printf("Failed to render!\n"); + } +} diff --git a/src/engine/graphics/vulkan/commands/buffer.h b/src/engine/graphics/vulkan/commands/buffer.h new file mode 100644 index 0000000..7f8b0eb --- /dev/null +++ b/src/engine/graphics/vulkan/commands/buffer.h @@ -0,0 +1,34 @@ +#ifndef ENGINE_GRAPHICS_VULKAN_COMMANDS_BUFFER_H +#define ENGINE_GRAPHICS_VULKAN_COMMANDS_BUFFER_H + +#include + + +/** + * Begin a command buffer + * + * @param pool + * @param cbuffer_id + * @return + */ +bool vulkan_commands_buffer_begin(cbuffer_pool_t *pool, uint32_t cbuffer_id); + +/** + * Submit a command buffer to the GPU on a given queue + * + * @param pool + * @param cbuffer_id + * @param num_waiting_semaphores + * @param waiting_semaphores + * @param waiting_semaphores_signaled_at + * @param num_signaling_semaphores + * @param signaling_semaphores + */ +void vulkan_commands_buffer_end( + cbuffer_pool_t *pool, uint32_t cbuffer_id, + uint32_t num_waiting_semaphores, VkSemaphore *waiting_semaphores, const VkPipelineStageFlags *waiting_semaphores_signaled_at, + uint32_t num_signaling_semaphores, VkSemaphore *signaling_semaphores +); + + +#endif diff --git a/src/engine/graphics/vulkan/commands/pool.c b/src/engine/graphics/vulkan/commands/pool.c new file mode 100644 index 0000000..7ba3f1e --- /dev/null +++ b/src/engine/graphics/vulkan/commands/pool.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include + +/** + * Allocate a VkCommandPool for a given device and queue + * + * @param device + * @param queue_family_index + * @return + */ +VkCommandPool vulkan_commands_cpool_commandpool_allocate(VkDevice device, uint32_t queue_family_index) +{ + VkCommandPool result; + VkCommandPoolCreateInfo command_pool_create_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + .queueFamilyIndex = queue_family_index + }; + + + if (vkCreateCommandPool(device, &command_pool_create_info, NULL, &result) != VK_SUCCESS) { + printf("Failed to initialize command pool\n"); + return VK_NULL_HANDLE; + } + + return result; +} + +bool vulkan_commands_cpool_fences_allocate(VkDevice device, VkFence *fences, uint32_t size) +{ + const VkFenceCreateInfo fence_create_info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = 0, + .pNext = NULL + }; + + for (uint32_t i = 0; i < size; i++) { + if (vkCreateFence(device, &fence_create_info, NULL, &fences[i]) != VK_SUCCESS) { + printf("Failed to allocate fence for command buffer!\n"); + return false; + } + } + return true; +} + +bool vulkan_commands_cpool_buffers_allocate(VkDevice device, VkCommandPool pool, VkCommandBuffer *buffers, uint32_t size) +{ + const VkCommandBufferAllocateInfo allocation_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = size + }; + + if (vkAllocateCommandBuffers(device, &allocation_info, buffers) != VK_SUCCESS) { + printf("Failed to allocate command buffer for pool\n"); + return false; + } + + return true; +} + +cbuffer_pool_t *vulkan_commands_cpool_allocate(vulkan *v, uint32_t size) +{ + cbuffer_pool_t *pool = calloc(sizeof(cbuffer_pool_t), 1); + + pool->owners.device = v->devices.logical_device; + pool->owners.pool = vulkan_commands_cpool_commandpool_allocate(v->devices.logical_device, v->queues.main_rendering_queue_id); + pool->owners.queue = v->queues.rendering; + pool->size = size; + + pool->fences = calloc(sizeof(VkFence), size); + pool->already_submitted = calloc(sizeof(bool), size); // this all defaults to 0 which is the correct behavior + pool->buffers = calloc(sizeof(VkCommandBuffer), size); + + // Create resources on device + vulkan_commands_cpool_fences_allocate(v->devices.logical_device, pool->fences, size); + vulkan_commands_cpool_buffers_allocate(v->devices.logical_device, pool->owners.pool, pool->buffers, size); + + // We haven't use anything yet + pool->last_used = 0; + + return pool; +} + + +uint32_t vulkan_commands_cpool_cbuffer_id_take(cbuffer_pool_t *pool) +{ + VkDevice device = pool->owners.device; + // Wait for and locate an unused fence + while (true) { + uint32_t peaking = CBUFFER_POOL_NEXT_INDEX(pool->last_used, pool->size); + + // Check to see if we've come full circle around out command buffer + while (peaking != pool->last_used) { + VkFence fence = vulkan_commands_cpool_fence_get(pool, peaking); + VkCommandBuffer buffer = vulkan_commands_cpool_cbuffer_get(pool, peaking); + + + // We have found a good fence if it's never been submitted before OR if the fence has been signaled by the GPU + if (!pool->already_submitted[peaking] || vkGetFenceStatus(device, fence) == VK_SUCCESS) { + + // If this was already submitted we need to clean up the Fence and CommandBuffer object + if (pool->already_submitted[peaking]) { + vkResetFences(device, 1, &fence); + vkResetCommandBuffer(buffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + } + + return peaking; + } + + peaking = CBUFFER_POOL_NEXT_INDEX(peaking, pool->size); + } + + // Block until we have a fence available + if (vkWaitForFences(device, pool->size, pool->fences, VK_FALSE, UINT64_MAX) != VK_SUCCESS) { + printf("Failed to block on fences"); + } + } +} + +VkCommandBuffer vulkan_commands_cpool_cbuffer_get(cbuffer_pool_t *pool, uint32_t cbuffer_id) +{ + // TODO: Locking & bounds checking + return pool->buffers[cbuffer_id]; +} + +VkFence vulkan_commands_cpool_fence_get(cbuffer_pool_t *pool, uint32_t cbuffer_id) +{ + // TODO: Locking & bounds checking + return pool->fences[cbuffer_id]; +} + +void vulkan_commands_cpool_cbuffer_id_mark(cbuffer_pool_t *pool, uint32_t cbuffer_id) +{ + pool->last_used = cbuffer_id; + pool->already_submitted[cbuffer_id] = true; +} diff --git a/src/engine/graphics/vulkan/commands/pool.h b/src/engine/graphics/vulkan/commands/pool.h new file mode 100644 index 0000000..8c465d0 --- /dev/null +++ b/src/engine/graphics/vulkan/commands/pool.h @@ -0,0 +1,72 @@ +#ifndef ENGINE_GRAPHICS_VULKAN_COMMANDS_POOL_H +#define ENGINE_GRAPHICS_VULKAN_COMMANDS_POOL_H + + +#include +#include + +#define CBUFFER_POOL_NEXT_INDEX(last_used, size) ((last_used + 1) % size) + +typedef struct +{ + struct + { + // The device we are allocated against + VkDevice device; + + // The CommandPool object we allocated + VkCommandPool pool; + + // The queue we intend to submit to + VkQueue queue; + } owners; + + uint32_t last_used; + + uint32_t size; + bool *already_submitted; + VkFence *fences; + VkCommandBuffer *buffers; + +} cbuffer_pool_t; + +/** + * Allocate a pool of command buffers + * @param v + * @param size + * @return + */ +cbuffer_pool_t *vulkan_commands_cpool_allocate(vulkan *v, uint32_t size); + +/** + * Find an unused VkCommandBuffer and VkFence pair. + * @param pool + * @return + */ +uint32_t vulkan_commands_cpool_cbuffer_id_take(cbuffer_pool_t *pool); + +/** + * Get a VkCommandBuffer by it's cbuffer_id + * + * @param pool + * @param cbuffer_id + * @return + */ +VkCommandBuffer vulkan_commands_cpool_cbuffer_get(cbuffer_pool_t *pool, uint32_t cbuffer_id); + +/** + * Get a VkFence by it's cbuffer_id + * @param pool + * @param cbuffer_id + * @return + */ +VkFence vulkan_commands_cpool_fence_get(cbuffer_pool_t *pool, uint32_t cbuffer_id); + +/** + * Mark that we've dirtied this CommandBuffer and Fence + * @param pool + * @return + */ +void vulkan_commands_cpool_cbuffer_id_mark(cbuffer_pool_t *pool, uint32_t cbuffer_id); + +#endif diff --git a/src/engine/graphics/vulkan/commands/render.c b/src/engine/graphics/vulkan/commands/render.c new file mode 100644 index 0000000..aa5a2b9 --- /dev/null +++ b/src/engine/graphics/vulkan/commands/render.c @@ -0,0 +1,30 @@ +#include "render.h" + +void vulkan_commands_render_begin(vulkan *v, cbuffer_pool_t *pool, uint32_t cbuffer_id, uint32_t swapchain_image_id) +{ + VkClearValue clear_color = { + .color.float32 = { + 0, 0, 0, 0 + } + }; + VkRenderPassBeginInfo render_pass_info = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = v->pipelines.render_pass, + .framebuffer = v->swapchain.frame_buffers[swapchain_image_id], + .renderArea = { + .offset = {0, 0}, + .extent = v->swapchain.extent + }, + .clearValueCount = 1, + .pClearValues = &clear_color, + }; + + + vkCmdBeginRenderPass(pool->buffers[cbuffer_id], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); +} + + +void vulkan_commands_render_end(cbuffer_pool_t *pool, uint32_t cbuffer_id) +{ + vkCmdEndRenderPass(pool->buffers[cbuffer_id]); +} diff --git a/src/engine/graphics/vulkan/commands/render.h b/src/engine/graphics/vulkan/commands/render.h new file mode 100644 index 0000000..f9ab510 --- /dev/null +++ b/src/engine/graphics/vulkan/commands/render.h @@ -0,0 +1,27 @@ +#ifndef ENGINE_GRAPHICS_VULKAN_COMMANDS_RENDER_H +#define ENGINE_GRAPHICS_VULKAN_COMMANDS_RENDER_H + +#include +#include +#include + + +/** + * Begin a swapchain command + * + * @param v + * @param pool + * @param cbuffer_id + * @param swapchain_image_id + */ +void vulkan_commands_render_begin(vulkan *v, cbuffer_pool_t *pool, uint32_t cbuffer_id, uint32_t swapchain_image_id); + +/** + * End a swapchain command + * + * @param pool + * @param cbuffer_id + */ +void vulkan_commands_render_end(cbuffer_pool_t *pool, uint32_t cbuffer_id); + +#endif diff --git a/src/engine/graphics/vulkan/materials/material.c b/src/engine/graphics/vulkan/materials/material.c new file mode 100644 index 0000000..87a2271 --- /dev/null +++ b/src/engine/graphics/vulkan/materials/material.c @@ -0,0 +1,3 @@ +#include "material.h" + + diff --git a/src/engine/graphics/vulkan/materials/material.h b/src/engine/graphics/vulkan/materials/material.h new file mode 100644 index 0000000..f0bdead --- /dev/null +++ b/src/engine/graphics/vulkan/materials/material.h @@ -0,0 +1,22 @@ +#ifndef ENGINE_GRAPHICS_VULKAN_MATERIALS_MATERIAL_H +#define ENGINE_GRAPHICS_VULKAN_MATERIALS_MATERIAL_H + +#include +#include +#include + +typedef struct material_s +{ + VkPipeline pipeline; + buffer_t verticies; +} material_t; + +/** + * Setup material for rendering + * + * @param material + * @param buffer + */ +void vulkan_material_bind(material_t *material, VkCommandBuffer buffer); + +#endif diff --git a/src/engine/graphics/vulkan/memory/buffer.c b/src/engine/graphics/vulkan/memory/buffer.c index d2267fc..72ee03d 100644 --- a/src/engine/graphics/vulkan/memory/buffer.c +++ b/src/engine/graphics/vulkan/memory/buffer.c @@ -2,7 +2,8 @@ #include #include -bool vulkan_buffer_allocate( + +bool vulkan_memory_buffer_allocate( vulkan *v, buffer_t *buffer, VkMemoryPropertyFlags buffer_memory_property_flags, @@ -11,6 +12,16 @@ bool vulkan_buffer_allocate( bool map_memory_region ) { + + if (map_memory_region) { + // If we want to memory map this region it must be visible to the host!!! + buffer_memory_property_flags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + buffer_usage_flags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + } else { + // If we dont mmap this region it must be possible to copy into this buffer + buffer_usage_flags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + } + const VkDeviceSize size = element_size * num_elements; // Clear out old buffer @@ -32,7 +43,7 @@ bool vulkan_buffer_allocate( vkGetBufferMemoryRequirements(v->devices.logical_device, buffer->buffer, &buffer->required_memory); - if (!vulkan_memory_allocate(v, buffer->required_memory.memoryTypeBits, buffer_memory_property_flags, size, &buffer->memory)) { + if (!vulkan_memory_allocate(v, buffer->required_memory.memoryTypeBits, buffer_memory_property_flags, buffer->required_memory.size, &buffer->memory)) { return false; } @@ -49,4 +60,34 @@ bool vulkan_buffer_allocate( } return true; -} \ No newline at end of file +} + + +void vulkan_memory_buffer_free(vulkan *v, buffer_t *buffer) +{ + if (!buffer || !buffer->memory) { + return; + } + + // If we have mapped memory, we need to unmap it first. + if (buffer->mapped_memory) { + vulkan_memory_unmap(v, buffer->memory, &buffer->mapped_memory); + } + + vulkan_memory_free(v, buffer->memory); + // Clear out old buffer + memset(buffer, 0, sizeof(buffer_t)); +} + +void vulkan_memory_buffer_copy( + buffer_t *from, buffer_t *to, + VkCommandBuffer buffer +) +{ + VkBufferCopy copy_request = { + .srcOffset = 0, + .dstOffset = 0, + .size = from->info.size, + }; + vkCmdCopyBuffer(buffer, from->buffer, to->buffer, 1, ©_request); +} diff --git a/src/engine/graphics/vulkan/memory/buffer.h b/src/engine/graphics/vulkan/memory/buffer.h index f05e8c6..f050545 100644 --- a/src/engine/graphics/vulkan/memory/buffer.h +++ b/src/engine/graphics/vulkan/memory/buffer.h @@ -5,7 +5,8 @@ #include #include -typedef struct { +typedef struct +{ VkBufferCreateInfo info; VkBuffer buffer; VkMemoryRequirements required_memory; @@ -29,7 +30,7 @@ typedef struct { * @param map_memory_region - If we should map a segment of memory for this buffer * @return */ -bool vulkan_buffer_allocate( +bool vulkan_memory_buffer_allocate( vulkan *v, buffer_t *buffer, VkMemoryPropertyFlags buffer_memory_property_flags, @@ -38,4 +39,22 @@ bool vulkan_buffer_allocate( bool map_memory_region ); +/** + * Vulkan free a memory buffer from the GPU + * @param v + * @param buffer + */ +void vulkan_memory_buffer_free(vulkan *v, buffer_t *buffer); + +/** + * Schedule a buffer copy into the VkCommandBuffer + * @param from - Source buffer + * @param to - Destination buffer + * @param buffer - Command buffer + */ +void vulkan_memory_buffer_copy( + buffer_t *from, buffer_t *to, + VkCommandBuffer buffer +); + #endif diff --git a/src/engine/graphics/vulkan/memory/memory.c b/src/engine/graphics/vulkan/memory/memory.c index 0208a0a..25b65a1 100644 --- a/src/engine/graphics/vulkan/memory/memory.c +++ b/src/engine/graphics/vulkan/memory/memory.c @@ -86,8 +86,8 @@ void vulkan_memory_unmap( } -void vukan_memory_free( - const vulkan *const v, +void vulkan_memory_free( + const vulkan *v, VkDeviceMemory memory ) { diff --git a/src/engine/graphics/vulkan/memory/memory.h b/src/engine/graphics/vulkan/memory/memory.h index 63a1f51..45a1e69 100644 --- a/src/engine/graphics/vulkan/memory/memory.h +++ b/src/engine/graphics/vulkan/memory/memory.h @@ -17,7 +17,7 @@ bool vulkan_memory_allocate( VkDeviceMemory *memory ); -void vukan_memory_free( +void vulkan_memory_free( const vulkan *v, VkDeviceMemory memory ); diff --git a/src/engine/graphics/vulkan/memory/vbuffer.c b/src/engine/graphics/vulkan/memory/vbuffer.c new file mode 100644 index 0000000..d801928 --- /dev/null +++ b/src/engine/graphics/vulkan/memory/vbuffer.c @@ -0,0 +1,18 @@ +#include +#include +#include "vbuffer.h" + + +bool vulkan_memory_vbuffer_allocate( + vulkan *v, + buffer_t *buffer, + uint32_t element_size, + uint32_t num_elements, + bool map_memory_region +) +{ + // Memory is going to be used to store vertex data + const VkBufferUsageFlags usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + const VkSharingMode sharing = VK_SHARING_MODE_EXCLUSIVE; + return vulkan_memory_buffer_allocate(v, buffer, 0, usage, sharing, element_size, num_elements, map_memory_region); +} diff --git a/src/engine/graphics/vulkan/memory/vbuffer.h b/src/engine/graphics/vulkan/memory/vbuffer.h new file mode 100644 index 0000000..a5e123e --- /dev/null +++ b/src/engine/graphics/vulkan/memory/vbuffer.h @@ -0,0 +1,29 @@ +#ifndef ENGINE_GRAPHICS_VULKAN_MEMORY_VBUFFER_H +#define ENGINE_GRAPHICS_VULKAN_MEMORY_VBUFFER_H + + +#include +#include +#include +#include + + +/** + * Allocate a buffer for usage in a vertex buffer + * + * @param v + * @param buffer + * @param element_size + * @param num_elements + * @param map_memory_region + * @return + */ +bool vulkan_memory_vbuffer_allocate( + vulkan *v, + buffer_t *buffer, + uint32_t element_size, + uint32_t num_elements, + bool map_memory_region +); + +#endif diff --git a/src/engine/graphics/vulkan/shaders/vbuffer.c b/src/engine/graphics/vulkan/shaders/vbuffer.c deleted file mode 100644 index f2b5f3b..0000000 --- a/src/engine/graphics/vulkan/shaders/vbuffer.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include "vbuffer.h" - -const VkMemoryPropertyFlags vbuffer_memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - -bool vulkan_vbuffer_allocate( - vulkan *v, - buffer_t *buffer, - uint32_t element_size, - uint32_t num_elements, - bool map_memory_region -) -{ - return vulkan_buffer_allocate( - v, - buffer, - vbuffer_memory_properties, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE, - element_size, num_elements, - map_memory_region - ); -} diff --git a/src/engine/graphics/vulkan/shaders/vbuffer.h b/src/engine/graphics/vulkan/shaders/vbuffer.h deleted file mode 100644 index 662ed97..0000000 --- a/src/engine/graphics/vulkan/shaders/vbuffer.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef ENGINE_GRAPHICS_VULKAN_SHADERS_VBUFFER_H -#define ENGINE_GRAPHICS_VULKAN_SHADERS_VBUFFER_H - - -#include -#include -#include -#include - - -bool vulkan_vbuffer_allocate(vulkan *v, buffer_t *buffer, uint32_t element_size, uint32_t num_elements, - bool map_memory_region); - -#endif diff --git a/src/engine/graphics/vulkan/swapchain.c b/src/engine/graphics/vulkan/swapchain.c index ad4be72..c3fe522 100644 --- a/src/engine/graphics/vulkan/swapchain.c +++ b/src/engine/graphics/vulkan/swapchain.c @@ -1,6 +1,7 @@ #include #include "swapchain.h" #include "window.h" +#include "locking.h" VkSurfaceFormatKHR vulkan_swapchain_select_format(vulkan *v) { @@ -197,4 +198,20 @@ bool vulkan_swapchain_init(vulkan *v) } return true; -} \ No newline at end of file +} + +uint32_t vulkan_swapchain_aquire(vulkan *v) +{ + uint32_t image_index; + + vkAcquireNextImageKHR( + v->devices.logical_device, + v->swapchain.swapchain, + UINT64_MAX, + vulkan_locking_semphore_get_frame_buffer_image_available(), + VK_NULL_HANDLE, + &image_index + ); + + return image_index; +} diff --git a/src/engine/graphics/vulkan/swapchain.h b/src/engine/graphics/vulkan/swapchain.h index d1946cd..5ea2f72 100644 --- a/src/engine/graphics/vulkan/swapchain.h +++ b/src/engine/graphics/vulkan/swapchain.h @@ -5,4 +5,6 @@ bool vulkan_swapchain_init(vulkan *v); +uint32_t vulkan_swapchain_aquire(vulkan *v); + #endif diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index a219d40..c090976 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -2,12 +2,8 @@ #include #include #include -#include #include #include -#include -#include -#include #include "query.h" #include "vulkan.h" #include "config.h" @@ -16,12 +12,22 @@ #include "window.h" #include "surface.h" #include "swapchain.h" -#include "src/engine/graphics/vulkan/shaders/shader.h" #include "pipeline.h" #include "framebuffer.h" -#include "commandpool.h" #include "locking.h" -#include "src/engine/graphics/vulkan/memory/memory.h" + + +#include +#include +#include + +#include +#include + +#include + +#include +#include vulkan v = { .definition = { @@ -34,7 +40,10 @@ vulkan v = { }, .devices.selected_device = VK_NULL_HANDLE }; -entity_t *e; + +entity_t *triangle; +cbuffer_pool_t *cpool; + VkResult vulkan_create_instance() { VkInstanceCreateInfo creation_request = { @@ -141,22 +150,71 @@ bool vulkan_init() } // TODO: We should NOT be passing the triangle position buffer in like this - if (!vulkan_command_pool_init(&v)) { + if (!(cpool = vulkan_commands_cpool_allocate(&v, v.swapchain.num_images * 2))) { printf("Failed to init command pool\n"); } - // TODO: Move creation of entities out of vulkan.c - e = entity_manager_make(entity_triangle_init, &v); - // Info to prove we have loaded everything vulkan_info_print(); + + triangle = entity_manager_make(entity_triangle_init, &v); return true; } void vulkan_render() { - vulkan_command_pool_render(&v); + + // Render starting configuration + VkSemaphore waiting_semaphore = vulkan_locking_semphore_get_frame_buffer_image_available(); + VkPipelineStageFlags waiting_semaphore_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + + // Render ending configuration + VkSemaphore signaling_semaphore = vulkan_locking_semphore_get_rendering_finished(); + + + // Get the next image to render onto + uint32_t swapchain_image_id = vulkan_swapchain_aquire(&v); + + // Get a free command buffer to use + uint32_t cbuffer_id = vulkan_commands_cpool_cbuffer_id_take(cpool); + + vulkan_commands_buffer_begin(cpool, cbuffer_id); + { + vulkan_commands_render_begin(&v, cpool, cbuffer_id, swapchain_image_id); + { + VkCommandBuffer buffer = vulkan_commands_cpool_cbuffer_get(cpool, cbuffer_id); + + // TODO: Bind pipeline in a better way + vkCmdBindPipeline(buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, v.pipelines.graphics); + + // Draw all entities into the command buffer + entity_manager_draw(buffer); + } + vulkan_commands_render_end(cpool, cbuffer_id); + } + vulkan_commands_buffer_end( + cpool, cbuffer_id, + 1, &waiting_semaphore, &waiting_semaphore_stage, + 1, &signaling_semaphore + ); + + + // Schedule this render job to be presented + VkPresentInfoKHR present_info = { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + // Subscribe + .waitSemaphoreCount = 1, + .pWaitSemaphores = &signaling_semaphore, + + .swapchainCount = 1, + .pSwapchains = &v.swapchain.swapchain, + .pImageIndices = &swapchain_image_id, + + .pResults = NULL + }; + + vkQueuePresentKHR(v.queues.presenting, &present_info); } void vulkan_update() diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h index bd5a360..edd6ed8 100644 --- a/src/engine/graphics/vulkan/vulkan.h +++ b/src/engine/graphics/vulkan/vulkan.h @@ -111,7 +111,6 @@ typedef struct glfw g; VkInstance instance; VkSurfaceKHR surface; - VkCommandPool command_pool; vulkan_layers layers; vulkan_extensions extensions; diff --git a/src/engine/main.c b/src/engine/main.c index a553914..7708b48 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -58,7 +58,6 @@ int main() { return 1; } - while (!vulkan_window_is_close_requested()) { entity_manager_update(); vulkan_update(); From a344583fd790e9526cc2c329f07d42a1617a6291 Mon Sep 17 00:00:00 2001 From: "Joshua D. Katz" Date: Sun, 30 Sep 2018 23:33:26 -0400 Subject: [PATCH 30/30] Test out a staging buffer for sending position data over to the GPU --- src/engine/entity/definitions/triangle.c | 27 ++++++++++++++++++---- src/engine/graphics/vulkan/commands/pool.h | 3 +++ src/engine/graphics/vulkan/memory/buffer.c | 2 +- src/engine/graphics/vulkan/vulkan.c | 6 ++--- src/engine/graphics/vulkan/vulkan.h | 1 + src/engine/main.c | 7 ++++++ 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/engine/entity/definitions/triangle.c b/src/engine/entity/definitions/triangle.c index 2f711b8..a1fedee 100644 --- a/src/engine/entity/definitions/triangle.c +++ b/src/engine/entity/definitions/triangle.c @@ -4,18 +4,20 @@ #include #include #include +#include +#include #include "triangle.h" vec2 *triangle_center_position; -buffer_t triangle_position_buffer; +buffer_t triangle_position_buffer, triangle_position_staging_buffer; void entity_triangle_update(entity_t *entity, void *metadata) { (void) entity; (void) metadata; - vec2 v = { + vec2 position = { (cursor_x - (vulkan_window_width_get() / 2.0f)) / vulkan_window_width_get(), (cursor_y - (vulkan_window_height_get() / 2.0f)) / vulkan_window_height_get() }; @@ -23,7 +25,19 @@ void entity_triangle_update(entity_t *entity, void *metadata) /** * set triangle position */ - memcpy(triangle_center_position, &v, sizeof(vec2)); + memcpy(triangle_center_position, &position, sizeof(vec2)); + + + uint32_t cbuffer_id = vulkan_commands_cpool_cbuffer_id_take(cpool); + vulkan_commands_buffer_begin(cpool, cbuffer_id); + { + vulkan_memory_buffer_copy(&triangle_position_staging_buffer, &triangle_position_buffer, vulkan_commands_cpool_cbuffer_get(cpool, cbuffer_id)); + } + vulkan_commands_buffer_end( + cpool, cbuffer_id, + 0, NULL, NULL, + 0, NULL + ); } void entity_triangle_free(entity_t *entity, void *metadata) @@ -47,11 +61,14 @@ void entity_triangle_draw(entity_t *e, VkCommandBuffer buffer) void entity_triangle_init(entity_t *entity, vulkan *v) { // TODO: Do not allocate this here. This is game state logic - if (!vulkan_memory_vbuffer_allocate(v, &triangle_position_buffer, sizeof(vec2), 1, true)) { + if (!vulkan_memory_vbuffer_allocate(v, &triangle_position_buffer, sizeof(vec2), 1, false)) { printf("Failed allocate buffer\n"); } - triangle_center_position = triangle_position_buffer.mapped_memory; + if (!vulkan_memory_vbuffer_allocate(v, &triangle_position_staging_buffer, sizeof(vec2), 1, true)) { + printf("Failed allocate buffer\n"); + } + triangle_center_position = triangle_position_staging_buffer.mapped_memory; entity->update = (void (*)(struct entity_struct *)) entity_triangle_update; entity->draw = (void (*)(struct entity_struct *, VkCommandBuffer)) (void (*)(struct entity_struct *)) entity_triangle_draw; diff --git a/src/engine/graphics/vulkan/commands/pool.h b/src/engine/graphics/vulkan/commands/pool.h index 8c465d0..9fbe3a1 100644 --- a/src/engine/graphics/vulkan/commands/pool.h +++ b/src/engine/graphics/vulkan/commands/pool.h @@ -30,6 +30,9 @@ typedef struct } cbuffer_pool_t; +// TODO: This is terrible. Find a better way to do DI +extern cbuffer_pool_t *cpool; + /** * Allocate a pool of command buffers * @param v diff --git a/src/engine/graphics/vulkan/memory/buffer.c b/src/engine/graphics/vulkan/memory/buffer.c index 72ee03d..20fb9ca 100644 --- a/src/engine/graphics/vulkan/memory/buffer.c +++ b/src/engine/graphics/vulkan/memory/buffer.c @@ -87,7 +87,7 @@ void vulkan_memory_buffer_copy( VkBufferCopy copy_request = { .srcOffset = 0, .dstOffset = 0, - .size = from->info.size, + .size = from->required_memory.size, }; vkCmdCopyBuffer(buffer, from->buffer, to->buffer, 1, ©_request); } diff --git a/src/engine/graphics/vulkan/vulkan.c b/src/engine/graphics/vulkan/vulkan.c index c090976..e0b2a7c 100644 --- a/src/engine/graphics/vulkan/vulkan.c +++ b/src/engine/graphics/vulkan/vulkan.c @@ -41,7 +41,9 @@ vulkan v = { .devices.selected_device = VK_NULL_HANDLE }; -entity_t *triangle; +// TODO: This is terrible. Find a better way to do DI +vulkan *vulkan_pointer = &v; + cbuffer_pool_t *cpool; VkResult vulkan_create_instance() @@ -157,8 +159,6 @@ bool vulkan_init() // Info to prove we have loaded everything vulkan_info_print(); - - triangle = entity_manager_make(entity_triangle_init, &v); return true; } diff --git a/src/engine/graphics/vulkan/vulkan.h b/src/engine/graphics/vulkan/vulkan.h index edd6ed8..83b4fb4 100644 --- a/src/engine/graphics/vulkan/vulkan.h +++ b/src/engine/graphics/vulkan/vulkan.h @@ -123,6 +123,7 @@ typedef struct vulkan_required_configuration required_configuration; } vulkan; +extern vulkan *vulkan_pointer; bool vulkan_init(); diff --git a/src/engine/main.c b/src/engine/main.c index 7708b48..fd88e92 100644 --- a/src/engine/main.c +++ b/src/engine/main.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "src/engine/scripting/callbacks.h" #include "src/engine/scripting/script.h" @@ -48,6 +49,7 @@ void init() { int main() { + if (!entity_manager_init(128)) { printf("Failed to initialize the entity manager\n"); return 1; @@ -58,12 +60,17 @@ int main() { return 1; } + entity_t *entity = entity_manager_make(entity_triangle_init, vulkan_pointer); + + while (!vulkan_window_is_close_requested()) { entity_manager_update(); vulkan_update(); vulkan_render(); } + + entity_free(entity, NULL); vulkan_cleanup(); return 0;