Kaynağa Gözat

Added pipeline

Kajetan Johannes Hammerle 3 ay önce
ebeveyn
işleme
621470fe38

+ 1 - 0
.gitignore

@@ -9,3 +9,4 @@ compiler
 *.swo
 *.cpp
 *.hpp
+*.spv

+ 2 - 4
CMakeLists.txt

@@ -79,10 +79,8 @@ install(TARGETS gaming_core FILE_SET HEADERS)
 
 include("cmake/add_shader.cmake")
 
-add_shader(NAME shader SOURCES
-    shaders/vertex.vert.glsl
-    shaders/fragment.frag.glsl
-)
+add_shader(NAME vertex SOURCES shaders/vertex.vert.glsl)
+add_shader(NAME fragment SOURCES shaders/fragment.frag.glsl)
 
 add_executable(test ${SRC_TESTS})
 target_link_libraries(test PRIVATE gaming_core)

+ 1 - 1
cmake/add_shader.cmake

@@ -6,7 +6,7 @@ function(add_shader)
         message( FATAL_ERROR "add_shader misses NAME" )
     endif()
 
-    set(output ${CMAKE_BINARY_DIR}/shader/${args_NAME}.spv)
+    set(output ${CMAKE_SOURCE_DIR}/shaders/${args_NAME}.spv)
 
     add_custom_command(
         OUTPUT ${output}

+ 47 - 27
src/VulkanUtils.c

@@ -1,5 +1,6 @@
 #include "VulkanUtils.h"
 
+#include <core/File.h>
 #include <core/Logger.h>
 
 static VkInstance instance;
@@ -405,6 +406,52 @@ void destroyVulkanSemaphore(VkSemaphore s, VkDevice d) {
     }
 }
 
+static bool initShaderModule(FileContent* f, VkDevice d, VkShaderModule* sm) {
+    if((f->length % 4) != 0) {
+        LOG_ERROR("Shader size is not a multiple of 4");
+        return true;
+    }
+    VkShaderModuleCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+        .codeSize = f->length,
+        .pCode = (u32*)f->data};
+    VK_ASSERT(vkCreateShaderModule(d, &info, nullptr, sm));
+    return false;
+}
+
+bool initVulkanShaderModule(VkShaderModule* sm, VkDevice d, const char* path) {
+    FileContent f = {0};
+    if(readFile(&f, path)) {
+        return true;
+    }
+    bool r = initShaderModule(&f, d, sm);
+    destroyFileContent(&f);
+    return r;
+}
+
+void destroyVulkanShaderModule(VkShaderModule sm, VkDevice d) {
+    if(d != VK_NULL_HANDLE) {
+        vkDestroyShaderModule(d, sm, nullptr);
+    }
+}
+
+bool initVulkanPipelineLayout(VkPipelineLayout* pl, VkDevice d) {
+    VkPipelineLayoutCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+        .setLayoutCount = 0,
+        .pSetLayouts = nullptr,
+        .pushConstantRangeCount = 0,
+        .pPushConstantRanges = nullptr};
+    VK_ASSERT(vkCreatePipelineLayout(d, &info, nullptr, pl));
+    return false;
+}
+
+void destroyVulkanPipelineLayout(VkPipelineLayout pl, VkDevice d) {
+    if(d != VK_NULL_HANDLE) {
+        vkDestroyPipelineLayout(d, pl, nullptr);
+    }
+}
+
 /*static bool initCommandBuffers() {
     VkCommandPoolCreateInfo info = {
         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
@@ -433,33 +480,6 @@ static void destroyCommandBuffers() {
     vkDestroyCommandPool(vk.device.logical, vk.swapchain.commandPool, nullptr);
 }
 
-static bool initRenderPass() {
-    VkAttachmentDescription c = {
-        .format = vk.swapchain.format,
-        .samples = VK_SAMPLE_COUNT_1_BIT,
-        .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 ca = {
-        .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
-    VkSubpassDescription subpass = {
-        .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
-        .colorAttachmentCount = 1,
-        .pColorAttachments = &ca};
-    VkRenderPassCreateInfo info = {
-        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
-        .attachmentCount = 1,
-        .pAttachments = &c,
-        .subpassCount = 1,
-        .pSubpasses = &subpass};
-    VK_ASSERT(
-        vkCreateRenderPass(vk.device.logical, &info, nullptr, &vk.renderPass));
-    return false;
-}
-
 static bool initFramebuffers() {
     vk.swapchain.framebuffers =
         coreAllocate(sizeof(VkFramebuffer) * vk.swapchain.amount);

+ 6 - 0
src/VulkanUtils.h

@@ -80,4 +80,10 @@ void destroyVulkanSwapchainImages(VulkanSwapchainImages* si, VkDevice d);
 bool initVulkanSemaphore(VkSemaphore* s, VkDevice d);
 void destroyVulkanSemaphore(VkSemaphore s, VkDevice d);
 
+bool initVulkanShaderModule(VkShaderModule* sm, VkDevice d, const char* path);
+void destroyVulkanShaderModule(VkShaderModule sm, VkDevice d);
+
+bool initVulkanPipelineLayout(VkPipelineLayout* pl, VkDevice d);
+void destroyVulkanPipelineLayout(VkPipelineLayout pl, VkDevice d);
+
 #endif

+ 162 - 10
src/VulkanWrapper.c

@@ -11,7 +11,6 @@
 // VkFramebuffer* framebuffers;
 // VkSemaphore semaphore;
 // VkSemaphore renderSemaphore;
-// VkRenderPass renderPass;
 
 static VkPhysicalDevice physicalDevice;
 static u32 graphicsFamily = 0;
@@ -21,8 +20,14 @@ static VkQueue graphicsQueue;
 static VkQueue presentQueue;
 static VkSurfaceFormatKHR surfaceFormat;
 static VkSurfaceKHR surface;
+static VkExtent2D swapchainSize;
 static VkSwapchainKHR swapchain;
 static VulkanSwapchainImages images;
+static VkShaderModule vertexShaderModule;
+static VkShaderModule fragmentShaderModule;
+static VkPipelineLayout pipelineLayout;
+static VkRenderPass renderPass;
+static VkPipeline pipeline;
 
 static int getSurfaceFormatPoints(const VkSurfaceFormatKHR* sf) {
     if(sf->format == VK_FORMAT_B8G8R8A8_UNORM &&
@@ -74,6 +79,7 @@ static bool initSwapchain() {
         LOG_ERROR("Could not retrieve any swapchain size");
         return true;
     }
+    swapchainSize = d.size;
     if(findVulkanSurfaceFormat(
            &d.surfaceFormat, physicalDevice, surface, getSurfaceFormatPoints)) {
         LOG_ERROR("Could not find surface format");
@@ -197,26 +203,172 @@ static bool initSwapchainImages() {
     return false;
 }
 
+static bool initShaders() {
+    return initVulkanShaderModule(
+               &vertexShaderModule, device, "shaders/vertex.spv") ||
+           initVulkanShaderModule(
+               &fragmentShaderModule, device, "shaders/fragment.spv");
+}
+
+static bool initPipeline() {
+    VkPipelineShaderStageCreateInfo stages[2] = {
+        {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+         .stage = VK_SHADER_STAGE_VERTEX_BIT,
+         .module = vertexShaderModule,
+         .pName = "main"},
+        {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+         .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
+         .module = fragmentShaderModule,
+         .pName = "main"}};
+
+    VkPipelineVertexInputStateCreateInfo vertexInputState = {
+        .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO};
+
+    VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
+        .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+        .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+        .primitiveRestartEnable = false};
+
+    VkViewport viewport = {
+        .x = 0.0f,
+        .y = 0.0f,
+        .width = (float)swapchainSize.width,
+        .height = (float)swapchainSize.height,
+        .minDepth = 0.0f,
+        .maxDepth = 1.0f};
+    VkRect2D scissor = {.offset = {0, 0}, .extent = swapchainSize};
+    VkPipelineViewportStateCreateInfo viewportState = {
+        .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+        .viewportCount = 1,
+        .pViewports = &viewport,
+        .scissorCount = 1,
+        .pScissors = &scissor};
+
+    VkPipelineRasterizationStateCreateInfo rasterizationState = {
+        .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+        .depthClampEnable = false,
+        .rasterizerDiscardEnable = false,
+        .polygonMode = VK_POLYGON_MODE_FILL,
+        .cullMode = VK_CULL_MODE_BACK_BIT,
+        .frontFace = VK_FRONT_FACE_CLOCKWISE,
+        .depthBiasEnable = false,
+        .depthBiasConstantFactor = 0.0f,
+        .depthBiasClamp = 0.0f,
+        .depthBiasSlopeFactor = 0.0f,
+        .lineWidth = 1.0f};
+
+    VkPipelineMultisampleStateCreateInfo multisampleState = {
+        .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+        .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
+        .sampleShadingEnable = false,
+        .minSampleShading = 1.0f,
+        .pSampleMask = nullptr,
+        .alphaToCoverageEnable = false,
+        .alphaToOneEnable = false};
+
+    VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
+        .blendEnable = 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};
+
+    VkPipelineColorBlendStateCreateInfo colorBlendState = {
+        .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+        .logicOpEnable = false,
+        .logicOp = VK_LOGIC_OP_COPY,
+        .attachmentCount = 1,
+        .pAttachments = &colorBlendAttachmentState,
+        .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}};
+
+    VkDynamicState dynamicStates[] = {
+        VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
+
+    VkPipelineDynamicStateCreateInfo dynamicState = {
+        .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+        .dynamicStateCount = ARRAY_LENGTH(dynamicStates),
+        .pDynamicStates = dynamicStates};
+
+    VkGraphicsPipelineCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+        .stageCount = 2,
+        .pStages = stages,
+        .pVertexInputState = &vertexInputState,
+        .pInputAssemblyState = &inputAssemblyState,
+        .pTessellationState = nullptr,
+        .pViewportState = &viewportState,
+        .pRasterizationState = &rasterizationState,
+        .pMultisampleState = &multisampleState,
+        .pDepthStencilState = nullptr,
+        .pColorBlendState = &colorBlendState,
+        .pDynamicState = &dynamicState,
+        .layout = pipelineLayout,
+        .renderPass = renderPass,
+        .subpass = 0,
+        .basePipelineHandle = VK_NULL_HANDLE,
+        .basePipelineIndex = -1};
+
+    VK_ASSERT(vkCreateGraphicsPipelines(
+        device, VK_NULL_HANDLE, 1, &info, nullptr, &pipeline));
+    return false;
+}
+
+static bool initRenderPass() {
+    VkAttachmentDescription c = {
+        .format = surfaceFormat.format,
+        .samples = VK_SAMPLE_COUNT_1_BIT,
+        .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 ca = {
+        .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
+    VkSubpassDescription subpass = {
+        .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+        .colorAttachmentCount = 1,
+        .pColorAttachments = &ca};
+    VkRenderPassCreateInfo info = {
+        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+        .attachmentCount = 1,
+        .pAttachments = &c,
+        .subpassCount = 1,
+        .pSubpasses = &subpass};
+    VK_ASSERT(vkCreateRenderPass(device, &info, nullptr, &renderPass));
+    return false;
+}
+
 bool initVulkan() {
     return initVulkanInstance() || initVulkanDebugging() ||
            initVulkanSurface(&surface, getWindow()) || initPhysicalDevice() ||
-           initDevice() || initSwapchain() || initSwapchainImages();
+           initDevice() || initSwapchain() || initSwapchainImages() ||
+           initShaders() || initVulkanPipelineLayout(&pipelineLayout, device) ||
+           initRenderPass() || initPipeline();
     /*  || initSemaphore(&vk.semaphore) ||
        initSemaphore(&vk.renderSemaphore) || initCommandBuffers() ||
-       initRenderPass() || initFramebuffers()*/
+        || initFramebuffers()*/
 }
 
 void renderVulkan() {
 }
 
 void destroyVulkan(void) {
-    // if(vk.device.logical != VK_NULL_HANDLE) {
-    //     destroyFramebuffers();
-    //     vkDestroyRenderPass(vk.device.logical, vk.renderPass, nullptr);
-    //     destroyCommandBuffers();
-    //     destroySemaphore(vk.semaphore);
-    //     destroySemaphore(vk.renderSemaphore);
-    // }
+    if(device != VK_NULL_HANDLE) {
+        //     destroyFramebuffers();
+        //     destroyCommandBuffers();
+        //     destroySemaphore(vk.semaphore);
+        //     destroySemaphore(vk.renderSemaphore);
+        vkDestroyPipeline(device, pipeline, nullptr);
+        vkDestroyRenderPass(device, renderPass, nullptr);
+    }
+    destroyVulkanPipelineLayout(pipelineLayout, device);
+    destroyVulkanShaderModule(vertexShaderModule, device);
+    destroyVulkanShaderModule(fragmentShaderModule, device);
     destroyVulkanSwapchainImages(&images, device);
     destroyVulkanSwapchain(swapchain, device);
     destroyVulkanDevice(device);

+ 9 - 2
src/WindowManager.c

@@ -176,7 +176,7 @@ static void onMouseMove(GLFWwindow*, double x, double y) {
     mousePosition.data[1] = (float)y;
 }
 
-bool openWindow(const WindowOptions* o) {
+static bool openWindowI(const WindowOptions* o) {
     if(!glfwInit()) {
         LOG_ERROR("could not initialize GLFW");
         return true;
@@ -194,7 +194,6 @@ bool openWindow(const WindowOptions* o) {
         glfwCreateWindow(o->size.data[0], o->size.data[1], o->name, m, nullptr);
     if(window == nullptr) {
         LOG_ERROR("could not create window");
-        closeWindow();
         return true;
     }
     size = o->size;
@@ -206,6 +205,14 @@ bool openWindow(const WindowOptions* o) {
     return initVulkan();
 }
 
+bool openWindow(const WindowOptions* o) {
+    if(openWindowI(o)) {
+        closeWindow();
+        return true;
+    }
+    return false;
+}
+
 void closeWindow(void) {
     if(window != nullptr) {
         destroyVulkan();

+ 20 - 10
test/modules/WindowManagerTests.c

@@ -17,17 +17,20 @@ static bool isRunning(void*) {
 static void tick(void*) {
     ticks -= ticks > 0;
     if(!isInputEnabled()) {
-        printf("TPS: %.3f\nFPS: %.3f\n", (double)getWindowTicksPerSecond(),
-               (double)getWindowFramesPerSecond());
-        printf("%12s | Down: %d | DownTime: %3d | Released: %d\n",
-               getButtonName(closeButton), isButtonDown(closeButton),
-               getButtonDownTime(closeButton), wasButtonReleased(closeButton));
-        printf("%12s | Down: %d | DownTime: %3d | Released: %d\n",
-               getButtonName(testButton), isButtonDown(testButton),
-               getButtonDownTime(testButton), wasButtonReleased(testButton));
+        printf(
+            "TPS: %.3f\nFPS: %.3f\n", (double)getWindowTicksPerSecond(),
+            (double)getWindowFramesPerSecond());
+        printf(
+            "%12s | Down: %d | DownTime: %3d | Released: %d\n",
+            getButtonName(closeButton), isButtonDown(closeButton),
+            getButtonDownTime(closeButton), wasButtonReleased(closeButton));
+        printf(
+            "%12s | Down: %d | DownTime: %3d | Released: %d\n",
+            getButtonName(testButton), isButtonDown(testButton),
+            getButtonDownTime(testButton), wasButtonReleased(testButton));
         Vector2 mouse = getLastMousePosition();
-        printf("Mouse: %.2f %.2f\n", (double)mouse.data[0],
-               (double)mouse.data[1]);
+        printf(
+            "Mouse: %.2f %.2f\n", (double)mouse.data[0], (double)mouse.data[1]);
     }
     if(getButtonDownTime(textButton) == 1) {
         if(isInputEnabled()) {
@@ -45,7 +48,14 @@ static void tick(void*) {
 static void render(void*, float) {
 }
 
+static void printReport(
+    LogLevel l, const char* file, int line, void*, const char* message) {
+    printLog(l, file, line, "", TERMINAL_RED, "%s", message);
+}
+
 void testWindow(void) {
+    setReportHandler(printReport, nullptr);
+
     WindowOptions options = {{{800, 480}}, false, "Test"};
     if(openWindow(&options)) {
         return;