diff options
| author | Hunter Kvalevog <hunter@kvog.sh> | 2026-04-03 20:49:17 -0500 |
|---|---|---|
| committer | Hunter Kvalevog <hunter@kvog.sh> | 2026-04-03 20:49:17 -0500 |
| commit | f58bfac1cd6d9789ed0f878058179c8b4adb8b23 (patch) | |
| tree | c2867fe91cc0a7596aec9ca9ba9130e3d6d2a645 /vk-asylum | |
| parent | f409e568ef60940d5dfb2c3479d43dd19882f780 (diff) | |
Diffstat (limited to 'vk-asylum')
| -rwxr-xr-x | vk-asylum/build-shaders.sh | 2 | ||||
| -rw-r--r-- | vk-asylum/main.c | 447 | ||||
| -rw-r--r-- | vk-asylum/shaders.h | 2 |
3 files changed, 348 insertions, 103 deletions
diff --git a/vk-asylum/build-shaders.sh b/vk-asylum/build-shaders.sh index 51d4475..780ab86 100755 --- a/vk-asylum/build-shaders.sh +++ b/vk-asylum/build-shaders.sh @@ -3,4 +3,4 @@ mkdir -p build glslc -fshader-stage=vert ./triangle_vs.glsl -o build/triangle_vs.spv glslc -fshader-stage=frag ./triangle_fs.glsl -o build/triangle_fs.spv echo "const uint32_t triangle_vert_spv[] = { "$(hexdump -v -e '1/4 "0x%08x, "' build/triangle_vs.spv)" };" > shaders.h -echo "const uint32_t triangle_frag_spv[] = { "$(hexdump -v -e '1/4 "0x%08x, "' build/triangle_vs.spv)" };" >> shaders.h +echo "const uint32_t triangle_frag_spv[] = { "$(hexdump -v -e '1/4 "0x%08x, "' build/triangle_fs.spv)" };" >> shaders.h diff --git a/vk-asylum/main.c b/vk-asylum/main.c index 74e86e2..ef8410b 100644 --- a/vk-asylum/main.c +++ b/vk-asylum/main.c @@ -17,12 +17,27 @@ #define WND_W 1024 #define WND_H 768 +typedef struct Vec3 Vec3; +struct Vec3 +{ + float x; + float y; + float z; +}; + +typedef struct Vertex Vertex; +struct Vertex +{ + Vec3 p; + Vec3 c; +}; + int main(int argc, char* argv[]) { (void)argc; (void)argv; SDL_Init(SDL_INIT_VIDEO); - SDL_Window* wnd = SDL_CreateWindow("vk-asylum", WND_W, WND_H, SDL_WINDOW_VULKAN); + SDL_Window* wnd = SDL_CreateWindow("vk-asylum", WND_W, WND_H, SDL_WINDOW_VULKAN | SDL_WINDOW_HIGH_PIXEL_DENSITY); ASSERT(wnd); VkResult r = VK_SUCCESS; @@ -33,22 +48,35 @@ int main(int argc, char* argv[]) .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .apiVersion = VK_API_VERSION_1_4, }; + const char* layers[] = { "VK_LAYER_KHRONOS_validation" }; VkInstanceCreateInfo vkici = (VkInstanceCreateInfo){ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &vkai, + .enabledLayerCount = 1, + .ppEnabledLayerNames = layers, }; - vkici.ppEnabledExtensionNames = SDL_Vulkan_GetInstanceExtensions(&vkici.enabledExtensionCount); - printf("Instance extensions requested by SDL:\n"); - for (uint32_t i = 0; i < vkici.enabledExtensionCount; ++i) { - printf(" %s\n", vkici.ppEnabledExtensionNames[i]); + // Extensions required for the SDL window backend + uint32_t num_sdl_extensions = 0; + const char* const* sdl_extensions = SDL_Vulkan_GetInstanceExtensions(&num_sdl_extensions); + + const char* extensions[64] = { 0 }; + for (; vkici.enabledExtensionCount < num_sdl_extensions; ++vkici.enabledExtensionCount) { + extensions[vkici.enabledExtensionCount] = sdl_extensions[vkici.enabledExtensionCount]; } #ifdef __APPLE__ // Required for instance extension VK_KHR_portability_enumeration (MoltenVK) vkici.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + extensions[vkici.enabledExtensionCount++] = VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME; #endif + vkici.ppEnabledExtensionNames = extensions; + printf("Instance extensions requested by SDL:\n"); + for (uint32_t i = 0; i < vkici.enabledExtensionCount; ++i) { + printf(" %s\n", vkici.ppEnabledExtensionNames[i]); + } + if ((r = vkCreateInstance(&vkici, 0, &vk)) != VK_SUCCESS) { DIE("Failed to create Vulkan instance: %s", VkResultToString(r)); } @@ -59,7 +87,7 @@ int main(int argc, char* argv[]) DIE("Failed to create Vulkan surface: %s", SDL_GetError()); } - VkPhysicalDevice vk_pdev = 0; + VkPhysicalDevice vk_pdev = VK_NULL_HANDLE; { uint32_t vk_pdev_count = 0; vkEnumeratePhysicalDevices(vk, &vk_pdev_count, 0); @@ -69,19 +97,31 @@ int main(int argc, char* argv[]) VkPhysicalDevice* vk_pdevs = calloc(vk_pdev_count, sizeof(VkPhysicalDevice)); vkEnumeratePhysicalDevices(vk, &vk_pdev_count, vk_pdevs); + + // Select the first device with dynamic rendering support // Just pick the first available physical device vk_pdev = vk_pdevs[0]; printf("Vulkan devices:\n"); for (uint32_t i = 0; i < vk_pdev_count; ++i) { - VkPhysicalDeviceProperties vk_pdev_props = { 0 }; - vkGetPhysicalDeviceProperties(vk_pdev, &vk_pdev_props); + VkPhysicalDeviceProperties vk_pdev_props = { 0 }; + vkGetPhysicalDeviceProperties(vk_pdevs[i], &vk_pdev_props); + VkPhysicalDeviceDynamicRenderingFeatures vk_pdev_dr = (VkPhysicalDeviceDynamicRenderingFeatures){ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, + }; + VkPhysicalDeviceFeatures2 vk_pdev_features = (VkPhysicalDeviceFeatures2){ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &vk_pdev_dr, + }; + vkGetPhysicalDeviceFeatures2(vk_pdevs[i], &vk_pdev_features); printf(" %s\n", vk_pdev_props.deviceName); + printf(" dynamic rendering? %s\n", vk_pdev_dr.dynamicRendering ? "YES" : "NO"); } free(vk_pdevs); } + ASSERT(vk_pdev != VK_NULL_HANDLE); uint32_t vk_qf_index = (uint32_t)-1; { @@ -113,14 +153,25 @@ int main(int argc, char* argv[]) .queueCount = 1, .pQueuePriorities = &priority, }; - - const char* device_extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; + + VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering = (VkPhysicalDeviceDynamicRenderingFeatures){ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, + .dynamicRendering = VK_TRUE, + }; + + const char* device_extensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, +#ifdef __APPLE__ + "VK_KHR_portability_subset", +#endif + }; VkDeviceCreateInfo device_create = (VkDeviceCreateInfo){ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queue_create, .enabledExtensionCount = COUNTOF(device_extensions), .ppEnabledExtensionNames = device_extensions, + .pNext = &dynamic_rendering, }; if ((r = vkCreateDevice(vk_pdev, &device_create, 0, &vk_dev)) != VK_SUCCESS) { @@ -169,11 +220,13 @@ int main(int argc, char* argv[]) uint32_t vk_swap_image_count = 0; VkImage* vk_swap_images = 0; VkImageView* vk_swap_image_views = 0; + VkFence* vk_swap_fences = 0; { vkGetSwapchainImagesKHR(vk_dev, vk_swp, &vk_swap_image_count, 0); ASSERT(vk_swap_image_count > 0); vk_swap_images = calloc(vk_swap_image_count, sizeof(VkImage)); vkGetSwapchainImagesKHR(vk_dev, vk_swp, &vk_swap_image_count, vk_swap_images); + vk_swap_fences = calloc(vk_swap_image_count, sizeof(VkFence)); vk_swap_image_views = calloc(vk_swap_image_count, sizeof(VkImageView)); for (uint32_t i = 0; i < vk_swap_image_count; ++i) { @@ -195,69 +248,87 @@ int main(int argc, char* argv[]) if ((r = vkCreateImageView(vk_dev, &image_view_create, 0, &vk_swap_image_views[i])) != VK_SUCCESS) { DIE("Failed to create image view #%u: %s", i, VkResultToString(r)); } + + VkFenceCreateInfo fence_create = (VkFenceCreateInfo){ + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = VK_FENCE_CREATE_SIGNALED_BIT, // start in signaled state + }; + if ((r = vkCreateFence(vk_dev, &fence_create, 0, &vk_swap_fences[i])) != VK_SUCCESS) { + DIE("Failed to create swap image fence #%u: %s", i, VkResultToString(r)); + } } } - - VkRenderPass vk_pass = 0; - { - VkAttachmentDescription attachment = (VkAttachmentDescription){ - .format = VK_FORMAT_B8G8R8A8_SRGB, - .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 color_ref = (VkAttachmentReference){ - .attachment = 0, - .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - }; - VkSubpassDescription subpass = (VkSubpassDescription){ - .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .colorAttachmentCount = 1, - .pColorAttachments = &color_ref, - }; - VkSubpassDependency dep = (VkSubpassDependency){ - .srcSubpass = VK_SUBPASS_EXTERNAL, - .dstSubpass = 0, - .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - }; - VkRenderPassCreateInfo render_pass_create = (VkRenderPassCreateInfo){ - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = &attachment, - .subpassCount = 1, - .pSubpasses = &subpass, - .dependencyCount = 1, - .pDependencies = &dep, - }; - if ((r = vkCreateRenderPass(vk_dev, &render_pass_create, 0, &vk_pass)) != VK_SUCCESS) { - DIE("Failed to create render pass: %s", VkResultToString(r)); - } - } - - VkFramebuffer* vk_framebuffers = calloc(vk_swap_image_count, sizeof(VkFramebuffer)); - { - for (uint32_t i = 0; i < vk_swap_image_count; ++i) { - VkImageView attachments[] = { vk_swap_image_views[i] }; - VkFramebufferCreateInfo framebuffer_create = (VkFramebufferCreateInfo){ - .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .renderPass = vk_pass, - .attachmentCount = 1, - .pAttachments = attachments, - .width = vk_extent.width, - .height = vk_extent.height, - .layers = 1, - }; - if ((r = vkCreateFramebuffer(vk_dev, &framebuffer_create, 0, &vk_framebuffers[i])) != VK_SUCCESS) { - DIE("Failed to create render pass #%u: %s", i, VkResultToString(r)); - } - } - } + + VkShaderModule vk_vshader = VK_NULL_HANDLE; + VkShaderModule vk_fshader = VK_NULL_HANDLE; + { +#include "shaders.h" + VkShaderModuleCreateInfo shader_create = (VkShaderModuleCreateInfo){ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + }; + shader_create.codeSize = sizeof(triangle_vert_spv); + shader_create.pCode = triangle_vert_spv; + if ((r = vkCreateShaderModule(vk_dev, &shader_create, 0, &vk_vshader)) != VK_SUCCESS) { + DIE("Failed to create vertex shader module: %s", VkResultToString(r)); + } + shader_create.codeSize = sizeof(triangle_frag_spv); + shader_create.pCode = triangle_frag_spv; + if ((r = vkCreateShaderModule(vk_dev, &shader_create, 0, &vk_fshader)) != VK_SUCCESS) { + DIE("Failed to create fragment shader module: %s", VkResultToString(r)); + } + } + + VkBuffer vk_vbuf = VK_NULL_HANDLE; + { + Vertex vdata[] = { + (Vertex){ .p = (Vec3){ 0.0f, -0.5f, 0.0f, }, .c = (Vec3){ 1.0f, 0.0f, 0.0f } }, + (Vertex){ .p = (Vec3){ 0.5f, 0.5f, 0.0f, }, .c = (Vec3){ 0.0f, 1.0f, 0.0f } }, + (Vertex){ .p = (Vec3){ -0.5f, 0.5f, 0.0f, }, .c = (Vec3){ 0.0f, 0.0f, 1.0f } }, + }; + VkBufferCreateInfo buffer_create = (VkBufferCreateInfo){ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = sizeof(vdata), + .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + if ((r = vkCreateBuffer(vk_dev, &buffer_create, 0, &vk_vbuf)) != VK_SUCCESS) { + DIE("Failed to create vertex buffer: %s", VkResultToString(r)); + } + + VkMemoryRequirements memreq; + vkGetBufferMemoryRequirements(vk_dev, vk_vbuf, &memreq); + + VkMemoryAllocateInfo alloc_info = (VkMemoryAllocateInfo){ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = memreq.size, + .memoryTypeIndex = UINT32_MAX, + }; + + VkPhysicalDeviceMemoryProperties memprops; + vkGetPhysicalDeviceMemoryProperties(vk_pdev, &memprops); + for (uint32_t i = 0; i < memprops.memoryTypeCount; ++i) { + if (memreq.memoryTypeBits & (1 << i)) { + const uint32_t needed = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + if ((memprops.memoryTypes[i].propertyFlags & needed) == needed) { + alloc_info.memoryTypeIndex = i; + break; + } + } + } + ASSERT(alloc_info.memoryTypeIndex != UINT32_MAX); + + VkDeviceMemory vkmem; + if ((r = vkAllocateMemory(vk_dev, &alloc_info, 0, &vkmem)) != VK_SUCCESS) { + DIE("Failed to allocate GPU memory for vertex buffer: %s", VkResultToString(r)); + } + + vkBindBufferMemory(vk_dev, vk_vbuf, vkmem, 0); + + void* data = 0; + vkMapMemory(vk_dev, vkmem, 0, sizeof(vdata), 0, &data); + memcpy(data, vdata, sizeof(vdata)); + vkUnmapMemory(vk_dev, vkmem); + } VkPipeline vk_pipeline = 0; { @@ -268,6 +339,128 @@ int main(int argc, char* argv[]) if ((r = vkCreatePipelineLayout(vk_dev, &pipeline_layout_create, 0, &pipeline_layout)) != VK_SUCCESS) { DIE("Failed to create pipeline layout: %s", VkResultToString(r)); } + + VkPipelineShaderStageCreateInfo stages[] = { + (VkPipelineShaderStageCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = vk_vshader, + .pName = "main", + }, + (VkPipelineShaderStageCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = vk_fshader, + .pName = "main", + } + }; + + VkPipelineInputAssemblyStateCreateInfo input_assembly = (VkPipelineInputAssemblyStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + }; + + VkViewport viewport = (VkViewport){ + .width = vk_extent.width, + .height = vk_extent.height, + .maxDepth = 1.0f, + }; + + VkRect2D scissor = (VkRect2D){ + .extent = vk_extent, + }; + + VkPipelineViewportStateCreateInfo viewport_state_create = (VkPipelineViewportStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .pViewports = &viewport, + .scissorCount = 1, + .pScissors = &scissor, + }; + + VkPipelineRasterizationStateCreateInfo raster_state_create = (VkPipelineRasterizationStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .lineWidth = 1.0, + }; + + VkPipelineMultisampleStateCreateInfo multisample_state = (VkPipelineMultisampleStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + }; + + VkPipelineColorBlendAttachmentState blending_attach = (VkPipelineColorBlendAttachmentState){ + .colorWriteMask = 0x0F, + }; + + VkPipelineColorBlendStateCreateInfo blending = (VkPipelineColorBlendStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &blending_attach, + }; + + VkFormat color_format = VK_FORMAT_B8G8R8A8_SRGB; + VkPipelineRenderingCreateInfo rendering = (VkPipelineRenderingCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &color_format, + }; + + VkPipelineDepthStencilStateCreateInfo depth_stencil = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = VK_FALSE, + .depthWriteEnable = VK_FALSE, + .depthCompareOp = VK_COMPARE_OP_ALWAYS, + }; + + VkVertexInputBindingDescription input_binding = (VkVertexInputBindingDescription){ + .binding = 0, + .stride = sizeof(Vertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }; + + VkVertexInputAttributeDescription input_attrs[] = { + (VkVertexInputAttributeDescription){ + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(Vertex, p), + }, + (VkVertexInputAttributeDescription){ + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(Vertex, c), + }, + }; + + VkPipelineVertexInputStateCreateInfo vertex_input = (VkPipelineVertexInputStateCreateInfo){ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &input_binding, + .vertexAttributeDescriptionCount = COUNTOF(input_attrs), + .pVertexAttributeDescriptions = input_attrs, + }; + + VkGraphicsPipelineCreateInfo pipeline_create = (VkGraphicsPipelineCreateInfo){ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = &rendering, + .stageCount = COUNTOF(stages), + .pStages = stages, + .pInputAssemblyState = &input_assembly, + .pViewportState = &viewport_state_create, + .pRasterizationState = &raster_state_create, + .pMultisampleState = &multisample_state, + .pColorBlendState = &blending, + .layout = pipeline_layout, + .pVertexInputState = &vertex_input, + .pDepthStencilState = &depth_stencil, + }; + if ((r = vkCreateGraphicsPipelines(vk_dev, VK_NULL_HANDLE, 1, &pipeline_create, 0, &vk_pipeline)) != VK_SUCCESS) { + DIE("Failed to create pipeline: %s", VkResultToString(r)); + } } VkCommandPool vk_cmd_pool = 0; @@ -302,38 +495,82 @@ int main(int argc, char* argv[]) if ((r = vkBeginCommandBuffer(vk_cmd_buffers[i], &cmd_buffer_begin_info)) != VK_SUCCESS) { DIE("Failed to begin command buffer for swapchain image #%u: %s", i, VkResultToString(r)); } - - VkClearValue clear_val = (VkClearValue){ - .color.float32[0] = 1.0f, - .color.float32[1] = 0.0f, - .color.float32[2] = 1.0f, - .color.float32[3] = 1.0f, - }; - VkRenderPassBeginInfo render_pass_begin_info = (VkRenderPassBeginInfo){ - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .renderPass = vk_pass, - .framebuffer = vk_framebuffers[i], - .renderArea.extent = vk_extent, - .clearValueCount = 1, - .pClearValues = &clear_val - }; - vkCmdBeginRenderPass(vk_cmd_buffers[i], &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); - - // - - vkCmdEndRenderPass(vk_cmd_buffers[i]); - vkEndCommandBuffer(vk_cmd_buffers[i]); + + VkImageMemoryBarrier vk_barrier = (VkImageMemoryBarrier){ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .image = vk_swap_images[i], + .subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .subresourceRange.levelCount = 1, + .subresourceRange.layerCount = 1, + }; + vkCmdPipelineBarrier(vk_cmd_buffers[i], VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, 0, 0, 0, 1, &vk_barrier); + + VkRenderingAttachmentInfo vk_rendering_attachment = (VkRenderingAttachmentInfo){ + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .imageView = vk_swap_image_views[i], + .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .clearValue.color = {{1.0f, 0.0f, 1.0f, 1.0f}}, + }; + VkRenderingInfo vk_rendering_info = (VkRenderingInfo){ + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, + .renderArea.extent = vk_extent, + .layerCount = 1, + .colorAttachmentCount = 1, + .pColorAttachments = &vk_rendering_attachment, + }; + vkCmdBeginRendering(vk_cmd_buffers[i], &vk_rendering_info); + + vkCmdBindPipeline(vk_cmd_buffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, vk_pipeline); + VkDeviceSize offset = 0; + vkCmdBindVertexBuffers(vk_cmd_buffers[i], 0, 1, &vk_vbuf, &offset); + vkCmdDraw(vk_cmd_buffers[i], 3, 1, 0, 0); + + vkCmdEndRendering(vk_cmd_buffers[i]); + + vk_barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + vk_barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + vk_barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + vk_barrier.dstAccessMask = 0; + vkCmdPipelineBarrier(vk_cmd_buffers[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &vk_barrier); + + if ((r = vkEndCommandBuffer(vk_cmd_buffers[i])) != VK_SUCCESS) { + DIE("Failed to end command buffer for swapchain image #%u: %s", i, VkResultToString(r)); + } } - VkSemaphore vk_image_available = 0; - VkSemaphore vk_render_finished = 0; + VkSemaphore* vk_image_available = calloc(vk_swap_image_count, sizeof(VkSemaphore)); + VkSemaphore* vk_render_finished = calloc(vk_swap_image_count, sizeof(VkSemaphore)); { VkSemaphoreCreateInfo semaphore_create = (VkSemaphoreCreateInfo){ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, }; - vkCreateSemaphore(vk_dev, &semaphore_create, 0, &vk_image_available); - vkCreateSemaphore(vk_dev, &semaphore_create, 0, &vk_render_finished); + for (uint32_t i = 0; i < vk_swap_image_count; ++i) { + vkCreateSemaphore(vk_dev, &semaphore_create, 0, &vk_image_available[i]); + vkCreateSemaphore(vk_dev, &semaphore_create, 0, &vk_render_finished[i]); + } } + +#define MAX_FRAMES_IN_FLIGHT 2 + VkFence vk_frame_fences[MAX_FRAMES_IN_FLIGHT]; + { + VkFenceCreateInfo create = (VkFenceCreateInfo){ + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = VK_FENCE_CREATE_SIGNALED_BIT, + }; + for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { + if ((r = vkCreateFence(vk_dev, &create, 0, &vk_frame_fences[i])) != VK_SUCCESS) { + DIE("Failed to create frame fence #%u: %s", i, VkResultToString(r)); + } + } + } + + uint32_t frame_idx = 0; bool running = true; while (running) { @@ -347,27 +584,31 @@ int main(int argc, char* argv[]) } uint32_t next_image_idx = 0; - vkAcquireNextImageKHR(vk_dev, vk_swp, UINT64_MAX, vk_image_available, VK_NULL_HANDLE, &next_image_idx); + vkAcquireNextImageKHR(vk_dev, vk_swp, UINT64_MAX, vk_image_available[frame_idx], VK_NULL_HANDLE, &next_image_idx); + // Wait for GPU to finish using this swapchain image + vkWaitForFences(vk_dev, 1, &vk_frame_fences[frame_idx], VK_TRUE, UINT64_MAX); + vkResetFences(vk_dev, 1, &vk_frame_fences[frame_idx]); + VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; VkSubmitInfo submit_info = (VkSubmitInfo){ .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .waitSemaphoreCount = 1, - .pWaitSemaphores = &vk_image_available, + .pWaitSemaphores = &vk_image_available[frame_idx], .pWaitDstStageMask = wait_stages, .commandBufferCount = 1, .pCommandBuffers = &vk_cmd_buffers[next_image_idx], .signalSemaphoreCount = 1, - .pSignalSemaphores = &vk_render_finished, + .pSignalSemaphores = &vk_render_finished[next_image_idx], }; - if ((r = vkQueueSubmit(vk_graphics_queue, 1, &submit_info, VK_NULL_HANDLE)) != VK_SUCCESS) { + if ((r = vkQueueSubmit(vk_graphics_queue, 1, &submit_info, vk_frame_fences[frame_idx])) != VK_SUCCESS) { DIE("Failed to submit graphics queue: %s", VkResultToString(r)); } VkPresentInfoKHR present_info = (VkPresentInfoKHR){ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .waitSemaphoreCount = 1, - .pWaitSemaphores = &vk_render_finished, + .pWaitSemaphores = &vk_render_finished[next_image_idx], .swapchainCount = 1, .pSwapchains = &vk_swp, .pImageIndices = &next_image_idx, @@ -375,6 +616,10 @@ int main(int argc, char* argv[]) if ((r = vkQueuePresentKHR(vk_graphics_queue, &present_info)) != VK_SUCCESS) { DIE("Failed to submit present queue: %s", VkResultToString(r)); } + + frame_idx = (frame_idx + 1) % MAX_FRAMES_IN_FLIGHT; } + + vkDeviceWaitIdle(vk_dev); } diff --git a/vk-asylum/shaders.h b/vk-asylum/shaders.h index 3ceda9c..435e2f0 100644 --- a/vk-asylum/shaders.h +++ b/vk-asylum/shaders.h @@ -1,2 +1,2 @@ const uint32_t triangle_vert_spv[] = { 0x07230203, 0x00010000, 0x000d000b, 0x0000001f, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0009000f, 0x00000000, 0x00000004, 0x6e69616d, 0x00000000, 0x0000000d, 0x00000012, 0x0000001c, 0x0000001d, 0x00030003, 0x00000002, 0x000001c2, 0x000a0004, 0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365, 0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63, 0x69645f65, 0x74636572, 0x00657669, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, 0x00060005, 0x0000000b, 0x505f6c67, 0x65567265, 0x78657472, 0x00000000, 0x00060006, 0x0000000b, 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69, 0x00070006, 0x0000000b, 0x00000001, 0x505f6c67, 0x746e696f, 0x657a6953, 0x00000000, 0x00070006, 0x0000000b, 0x00000002, 0x435f6c67, 0x4470696c, 0x61747369, 0x0065636e, 0x00070006, 0x0000000b, 0x00000003, 0x435f6c67, 0x446c6c75, 0x61747369, 0x0065636e, 0x00030005, 0x0000000d, 0x00000000, 0x00030005, 0x00000012, 0x00705f76, 0x00030005, 0x0000001c, 0x00635f66, 0x00030005, 0x0000001d, 0x00635f76, 0x00030047, 0x0000000b, 0x00000002, 0x00050048, 0x0000000b, 0x00000000, 0x0000000b, 0x00000000, 0x00050048, 0x0000000b, 0x00000001, 0x0000000b, 0x00000001, 0x00050048, 0x0000000b, 0x00000002, 0x0000000b, 0x00000003, 0x00050048, 0x0000000b, 0x00000003, 0x0000000b, 0x00000004, 0x00040047, 0x00000012, 0x0000001e, 0x00000000, 0x00040047, 0x0000001c, 0x0000001e, 0x00000000, 0x00040047, 0x0000001d, 0x0000001e, 0x00000001, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, 0x00000004, 0x00040015, 0x00000008, 0x00000020, 0x00000000, 0x0004002b, 0x00000008, 0x00000009, 0x00000001, 0x0004001c, 0x0000000a, 0x00000006, 0x00000009, 0x0006001e, 0x0000000b, 0x00000007, 0x00000006, 0x0000000a, 0x0000000a, 0x00040020, 0x0000000c, 0x00000003, 0x0000000b, 0x0004003b, 0x0000000c, 0x0000000d, 0x00000003, 0x00040015, 0x0000000e, 0x00000020, 0x00000001, 0x0004002b, 0x0000000e, 0x0000000f, 0x00000000, 0x00040017, 0x00000010, 0x00000006, 0x00000003, 0x00040020, 0x00000011, 0x00000001, 0x00000010, 0x0004003b, 0x00000011, 0x00000012, 0x00000001, 0x0004002b, 0x00000006, 0x00000014, 0x3f800000, 0x00040020, 0x00000019, 0x00000003, 0x00000007, 0x00040020, 0x0000001b, 0x00000003, 0x00000010, 0x0004003b, 0x0000001b, 0x0000001c, 0x00000003, 0x0004003b, 0x00000011, 0x0000001d, 0x00000001, 0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x0004003d, 0x00000010, 0x00000013, 0x00000012, 0x00050051, 0x00000006, 0x00000015, 0x00000013, 0x00000000, 0x00050051, 0x00000006, 0x00000016, 0x00000013, 0x00000001, 0x00050051, 0x00000006, 0x00000017, 0x00000013, 0x00000002, 0x00070050, 0x00000007, 0x00000018, 0x00000015, 0x00000016, 0x00000017, 0x00000014, 0x00050041, 0x00000019, 0x0000001a, 0x0000000d, 0x0000000f, 0x0003003e, 0x0000001a, 0x00000018, 0x0004003d, 0x00000010, 0x0000001e, 0x0000001d, 0x0003003e, 0x0000001c, 0x0000001e, 0x000100fd, 0x00010038, }; -const uint32_t triangle_frag_spv[] = { 0x07230203, 0x00010000, 0x000d000b, 0x0000001f, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0009000f, 0x00000000, 0x00000004, 0x6e69616d, 0x00000000, 0x0000000d, 0x00000012, 0x0000001c, 0x0000001d, 0x00030003, 0x00000002, 0x000001c2, 0x000a0004, 0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365, 0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63, 0x69645f65, 0x74636572, 0x00657669, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, 0x00060005, 0x0000000b, 0x505f6c67, 0x65567265, 0x78657472, 0x00000000, 0x00060006, 0x0000000b, 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69, 0x00070006, 0x0000000b, 0x00000001, 0x505f6c67, 0x746e696f, 0x657a6953, 0x00000000, 0x00070006, 0x0000000b, 0x00000002, 0x435f6c67, 0x4470696c, 0x61747369, 0x0065636e, 0x00070006, 0x0000000b, 0x00000003, 0x435f6c67, 0x446c6c75, 0x61747369, 0x0065636e, 0x00030005, 0x0000000d, 0x00000000, 0x00030005, 0x00000012, 0x00705f76, 0x00030005, 0x0000001c, 0x00635f66, 0x00030005, 0x0000001d, 0x00635f76, 0x00030047, 0x0000000b, 0x00000002, 0x00050048, 0x0000000b, 0x00000000, 0x0000000b, 0x00000000, 0x00050048, 0x0000000b, 0x00000001, 0x0000000b, 0x00000001, 0x00050048, 0x0000000b, 0x00000002, 0x0000000b, 0x00000003, 0x00050048, 0x0000000b, 0x00000003, 0x0000000b, 0x00000004, 0x00040047, 0x00000012, 0x0000001e, 0x00000000, 0x00040047, 0x0000001c, 0x0000001e, 0x00000000, 0x00040047, 0x0000001d, 0x0000001e, 0x00000001, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, 0x00000004, 0x00040015, 0x00000008, 0x00000020, 0x00000000, 0x0004002b, 0x00000008, 0x00000009, 0x00000001, 0x0004001c, 0x0000000a, 0x00000006, 0x00000009, 0x0006001e, 0x0000000b, 0x00000007, 0x00000006, 0x0000000a, 0x0000000a, 0x00040020, 0x0000000c, 0x00000003, 0x0000000b, 0x0004003b, 0x0000000c, 0x0000000d, 0x00000003, 0x00040015, 0x0000000e, 0x00000020, 0x00000001, 0x0004002b, 0x0000000e, 0x0000000f, 0x00000000, 0x00040017, 0x00000010, 0x00000006, 0x00000003, 0x00040020, 0x00000011, 0x00000001, 0x00000010, 0x0004003b, 0x00000011, 0x00000012, 0x00000001, 0x0004002b, 0x00000006, 0x00000014, 0x3f800000, 0x00040020, 0x00000019, 0x00000003, 0x00000007, 0x00040020, 0x0000001b, 0x00000003, 0x00000010, 0x0004003b, 0x0000001b, 0x0000001c, 0x00000003, 0x0004003b, 0x00000011, 0x0000001d, 0x00000001, 0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x0004003d, 0x00000010, 0x00000013, 0x00000012, 0x00050051, 0x00000006, 0x00000015, 0x00000013, 0x00000000, 0x00050051, 0x00000006, 0x00000016, 0x00000013, 0x00000001, 0x00050051, 0x00000006, 0x00000017, 0x00000013, 0x00000002, 0x00070050, 0x00000007, 0x00000018, 0x00000015, 0x00000016, 0x00000017, 0x00000014, 0x00050041, 0x00000019, 0x0000001a, 0x0000000d, 0x0000000f, 0x0003003e, 0x0000001a, 0x00000018, 0x0004003d, 0x00000010, 0x0000001e, 0x0000001d, 0x0003003e, 0x0000001c, 0x0000001e, 0x000100fd, 0x00010038, }; +const uint32_t triangle_frag_spv[] = { 0x07230203, 0x00010000, 0x000d000b, 0x00000013, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0007000f, 0x00000004, 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, 0x0000000c, 0x00030010, 0x00000004, 0x00000007, 0x00030003, 0x00000002, 0x000001c2, 0x000a0004, 0x475f4c47, 0x4c474f4f, 0x70635f45, 0x74735f70, 0x5f656c79, 0x656e696c, 0x7269645f, 0x69746365, 0x00006576, 0x00080004, 0x475f4c47, 0x4c474f4f, 0x6e695f45, 0x64756c63, 0x69645f65, 0x74636572, 0x00657669, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, 0x00050005, 0x00000009, 0x756f5f66, 0x6f635f74, 0x00726f6c, 0x00030005, 0x0000000c, 0x00635f66, 0x00040047, 0x00000009, 0x0000001e, 0x00000000, 0x00040047, 0x0000000c, 0x0000001e, 0x00000000, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, 0x00000004, 0x00040020, 0x00000008, 0x00000003, 0x00000007, 0x0004003b, 0x00000008, 0x00000009, 0x00000003, 0x00040017, 0x0000000a, 0x00000006, 0x00000003, 0x00040020, 0x0000000b, 0x00000001, 0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c, 0x00000001, 0x0004002b, 0x00000006, 0x0000000e, 0x3f800000, 0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x0004003d, 0x0000000a, 0x0000000d, 0x0000000c, 0x00050051, 0x00000006, 0x0000000f, 0x0000000d, 0x00000000, 0x00050051, 0x00000006, 0x00000010, 0x0000000d, 0x00000001, 0x00050051, 0x00000006, 0x00000011, 0x0000000d, 0x00000002, 0x00070050, 0x00000007, 0x00000012, 0x0000000f, 0x00000010, 0x00000011, 0x0000000e, 0x0003003e, 0x00000009, 0x00000012, 0x000100fd, 0x00010038, }; |