diff --git a/assets/shaders/gradient.comp.spv b/assets/shaders/gradient.comp.spv index 49ba2be..319e010 100644 Binary files a/assets/shaders/gradient.comp.spv and b/assets/shaders/gradient.comp.spv differ diff --git a/src/gears/main.d b/src/gears/main.d index f9d8d6b..8656dd8 100644 --- a/src/gears/main.d +++ b/src/gears/main.d @@ -14,6 +14,9 @@ void main() while (true) { + p.HandleEvents(&window); + if (window.close) break; + r.Cycle(&rd); } } diff --git a/src/gears/platform.d b/src/gears/platform.d index 5693a7d..b3973cf 100644 --- a/src/gears/platform.d +++ b/src/gears/platform.d @@ -16,6 +16,7 @@ struct Window xcb_atom_t minimize_event; u16 w; u16 h; + bool close; }; struct Library @@ -145,6 +146,40 @@ Window CreateWindow(string name, u16 width, u16 height) return window; }; +void +HandleEvents(Window* window) +{ + xcb_generic_event_t* e; + + do + { + e = xcb_poll_for_event(window.conn); + + if (e) + { + switch (e.response_type & ~0x80) + { + case XCB_CLIENT_MESSAGE: + { + xcb_client_message_event_t* msg = cast(xcb_client_message_event_t*)e; + if (msg.window != window.window) + { + break; + } + + if (msg.data.data32[0] == window.close_event) + { + window.close = true; + } + } break; + default: + break; + } + } + } + while (e); +} + Library LoadLibrary(string name) { Library lib = { diff --git a/src/gears/renderer.d b/src/gears/renderer.d index 98f5454..90b3160 100644 --- a/src/gears/renderer.d +++ b/src/gears/renderer.d @@ -75,6 +75,14 @@ Cycle(Renderer* rd) if (success) { + vk.Bind(&rd.vulkan, rd.compute_pipeline); + + vk.PrepCompute(&rd.vulkan); + + vk.Dispatch(&rd.vulkan); + + vk.BeginRender(&rd.vulkan); + vk.Bind(&rd.vulkan, rd.triangle_pipeline); vk.Draw(&rd.vulkan, 3, 1); diff --git a/src/gears/vulkan.d b/src/gears/vulkan.d index 1e153f7..19b93c0 100644 --- a/src/gears/vulkan.d +++ b/src/gears/vulkan.d @@ -9,6 +9,7 @@ import u = util : HashTable, Result, Logf, Log; import a = alloc; import p = platform; import renderer; +import std.math.rounding : Ceil = ceil; bool g_VLAYER_SUPPORT = false; @@ -119,7 +120,8 @@ struct Vulkan a.Arena arena; a.Arena[FRAME_OVERLAP] frame_arenas; - u64 frame_no; + u32 frame_index; + u32 semaphore_index; u.SLList!(SI) cleanup_list; @@ -146,8 +148,8 @@ struct Vulkan VkCommandPool[FRAME_OVERLAP] cmd_pools; VkCommandBuffer[FRAME_OVERLAP] cmds; - VkSemaphore[] swapchain_sems; - VkSemaphore[FRAME_OVERLAP] render_sems; + VkSemaphore[] submit_sems; + VkSemaphore[FRAME_OVERLAP] acquire_sems; VkFence[FRAME_OVERLAP] render_fences; VkCommandPool imm_pool; @@ -221,18 +223,6 @@ Init(p.Window* window, u64 permanent_mem, u64 frame_mem) return result; } -u64 -FrameIndex(Vulkan* vk) -{ - return vk.frame_no % FRAME_OVERLAP; -} - -u64 -SemIndex(Vulkan* vk) -{ - return vk.frame_no % vk.present_images.length; -} - VkImage CurrentImage(Vulkan* vk) { @@ -242,22 +232,19 @@ CurrentImage(Vulkan* vk) bool BeginFrame(Vulkan* vk) { - u64 index = FrameIndex(vk); - u64 sem_index = SemIndex(vk); - // TODO: move vkWaitForFences so it no longer holds up the frame, will need to change how fences are handled in regards to images though - VkResult result = vkWaitForFences(vk.device, 1, vk.render_fences.ptr + index, VK_TRUE, 1000000000); + VkResult result = vkWaitForFences(vk.device, 1, vk.render_fences.ptr + vk.frame_index, VK_TRUE, 1000000000); bool success = VkCheck("BeginFrame failure: vkWaitForFences error", result); if (success) { - result = vkResetFences(vk.device, 1, vk.render_fences.ptr + index); + result = vkResetFences(vk.device, 1, vk.render_fences.ptr + vk.frame_index); success = VkCheck("BeginFrame failure: vkResetFences error", result); } if (success) { - result = vkAcquireNextImageKHR(vk.device, vk.swapchain, 1000000000, vk.swapchain_sems[sem_index], null, &vk.image_index); + result = vkAcquireNextImageKHR(vk.device, vk.swapchain, 1000000000, vk.acquire_sems[vk.frame_index], null, &vk.image_index); if (result == VK_ERROR_OUT_OF_DATE_KHR) { RecreateSwapchain(vk); @@ -270,7 +257,7 @@ BeginFrame(Vulkan* vk) if (success) { - result = vkResetCommandBuffer(vk.cmds[index], 0); + result = vkResetCommandBuffer(vk.cmds[vk.frame_index], 0); success = VkCheck("BeginFrame failure: vkResetCommandBuffer failure", result); } @@ -281,82 +268,76 @@ BeginFrame(Vulkan* vk) flags: VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, }; - result = vkBeginCommandBuffer(vk.cmds[index], &cmd_info); + result = vkBeginCommandBuffer(vk.cmds[vk.frame_index], &cmd_info); success = VkCheck("BeginFrame failure: vkBeginCommandBuffer error", result); } - if (success) - { - Transition(vk.cmds[index], &vk.draw_image.base, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - Transition(vk.cmds[index], &vk.depth_image.base, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); - - VkImage image = CurrentImage(vk); - Transition(vk.cmds[index], image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - f32[4] clear_col; - clear_col[] = 0.2; - - VkRenderingAttachmentInfo col_attach = { - sType: VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, - imageView: vk.draw_image.view, - imageLayout: vk.draw_image.base.layout, - loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, - storeOp: VK_ATTACHMENT_STORE_OP_STORE, - clearValue: { color: { clear_col } }, - }; - - VkRenderingAttachmentInfo depth_attach = { - sType: VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, - imageView: vk.depth_image.view, - imageLayout: vk.depth_image.base.layout, - loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, - storeOp: VK_ATTACHMENT_STORE_OP_STORE, - }; - - VkRenderingInfo render_info = { - sType: VK_STRUCTURE_TYPE_RENDERING_INFO, - layerCount: 1, - colorAttachmentCount: 1, - pColorAttachments: &col_attach, - pDepthAttachment: &depth_attach, - renderArea: { - extent: { - width: vk.swapchain_extent.width, - height: vk.swapchain_extent.height, - }, - }, - }; - - vkCmdBeginRendering(vk.cmds[index], &render_info); - vkCmdBindDescriptorSets( - vk.cmds[index], - VK_PIPELINE_BIND_POINT_GRAPHICS, - vk.pipeline_layout, - 0, - cast(u32)vk.desc_sets.length, - vk.desc_sets.ptr, - 0, - null - ); - } - return success; } +void +BeginRender(Vulkan* vk) +{ + // TODO: probably get rid of these + Transition(vk.cmds[vk.frame_index], &vk.draw_image.base, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + Transition(vk.cmds[vk.frame_index], &vk.depth_image.base, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL); + + VkImage image = CurrentImage(vk); + Transition(vk.cmds[vk.frame_index], image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkRenderingAttachmentInfo col_attach = { + sType: VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + imageView: vk.draw_image.view, + imageLayout: vk.draw_image.base.layout, + loadOp: VK_ATTACHMENT_LOAD_OP_LOAD, + storeOp: VK_ATTACHMENT_STORE_OP_STORE, + }; + + VkRenderingAttachmentInfo depth_attach = { + sType: VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + imageView: vk.depth_image.view, + imageLayout: vk.depth_image.base.layout, + loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, + storeOp: VK_ATTACHMENT_STORE_OP_STORE, + }; + + VkRenderingInfo render_info = { + sType: VK_STRUCTURE_TYPE_RENDERING_INFO, + layerCount: 1, + colorAttachmentCount: 1, + pColorAttachments: &col_attach, + pDepthAttachment: &depth_attach, + renderArea: { + extent: { + width: vk.swapchain_extent.width, + height: vk.swapchain_extent.height, + }, + }, + }; + + vkCmdBeginRendering(vk.cmds[vk.frame_index], &render_info); +} + +void +PrepCompute(Vulkan* vk) +{ + Transition(vk.cmds[vk.frame_index], &vk.draw_image, VK_IMAGE_LAYOUT_GENERAL); +} + bool FinishFrame(Vulkan* vk) { - scope(exit) vk.frame_no += 1; + scope(exit) vk.frame_index = (vk.frame_index + 1) % FRAME_OVERLAP; bool success = true; - u64 index = FrameIndex(vk); - u64 sem_index = SemIndex(vk); VkImage image = CurrentImage(vk); + VkSemaphore acquire_sem = vk.acquire_sems[vk.frame_index]; + VkSemaphore submit_sem = vk.submit_sems[vk.image_index]; - vkCmdEndRendering(vk.cmds[index]); + vkCmdEndRendering(vk.cmds[vk.frame_index]); - Transition(vk.cmds[index], &vk.draw_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + Transition(vk.cmds[vk.frame_index], &vk.draw_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); VkExtent2D extent = { width: vk.swapchain_extent.width, @@ -364,30 +345,30 @@ FinishFrame(Vulkan* vk) }; // TODO: Find out how to copy from same dimension images - Copy(vk.cmds[index], vk.draw_image.base.image, image, extent, extent); + Copy(vk.cmds[vk.frame_index], vk.draw_image.base.image, image, extent, extent); - Transition(vk.cmds[index], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + Transition(vk.cmds[vk.frame_index], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - VkResult result = vkEndCommandBuffer(vk.cmds[index]); + VkResult result = vkEndCommandBuffer(vk.cmds[vk.frame_index]); success = VkCheck("FinishFrame failure: vkEndCommandBuffer error", result); if (success) { VkCommandBufferSubmitInfo cmd_info = { sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, - commandBuffer: vk.cmds[index], + commandBuffer: vk.cmds[vk.frame_index], }; VkSemaphoreSubmitInfo wait_info = { sType: VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - semaphore: vk.swapchain_sems[sem_index], + semaphore: acquire_sem, stageMask: VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, value: 1, }; VkSemaphoreSubmitInfo signal_info = { sType: VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - semaphore: vk.render_sems[index], + semaphore: submit_sem, stageMask: VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, value: 1, }; @@ -402,7 +383,7 @@ FinishFrame(Vulkan* vk) pCommandBufferInfos: &cmd_info, }; - result = vkQueueSubmit2(vk.queues.gfx_queue, 1, &submit_info, vk.render_fences[index]); + result = vkQueueSubmit2(vk.queues.gfx_queue, 1, &submit_info, vk.render_fences[vk.frame_index]); success = VkCheck("FinishFrame failure: vkQueueSubmit2 error", result); } @@ -413,7 +394,7 @@ FinishFrame(Vulkan* vk) swapchainCount: 1, pSwapchains: &vk.swapchain, waitSemaphoreCount: 1, - pWaitSemaphores: vk.render_sems.ptr + index, + pWaitSemaphores: &submit_sem, pImageIndices: &vk.image_index, }; @@ -434,13 +415,13 @@ FinishFrame(Vulkan* vk) void Draw(Vulkan* vk, u32 index_count, u32 instance_count) { - vkCmdDraw(vk.cmds[FrameIndex(vk)], index_count, instance_count, 0, 0); + vkCmdDraw(vk.cmds[vk.frame_index], index_count, instance_count, 0, 0); } void DrawIndexed(Vulkan* vk, u32 index_count, u32 instance_count) { - vkCmdDrawIndexed(vk.cmds[FrameIndex(vk)], index_count, instance_count, 0, 0, 0); + vkCmdDrawIndexed(vk.cmds[vk.frame_index], index_count, instance_count, 0, 0, 0); } pragma(inline): void @@ -487,9 +468,18 @@ Copy(VkCommandBuffer cmd, VkImage src, VkImage dst, VkExtent2D src_ext, VkExtent void Bind(Vulkan* vk, PipelineHandle pipeline) { - u64 index = FrameIndex(vk); - - vkCmdBindPipeline(vk.cmds[index], pipeline.type, pipeline.handle); + vkCmdBindPipeline(vk.cmds[vk.frame_index], pipeline.type, pipeline.handle); + + vkCmdBindDescriptorSets( + vk.cmds[vk.frame_index], + pipeline.type, + vk.pipeline_layout, + 0, + cast(u32)vk.desc_sets.length, + vk.desc_sets.ptr, + 0, + null + ); VkViewport viewport = { width: cast(f32)vk.swapchain_extent.width, @@ -497,7 +487,7 @@ Bind(Vulkan* vk, PipelineHandle pipeline) maxDepth: 1.0F, }; - vkCmdSetViewport(vk.cmds[index], 0, 1, &viewport); + vkCmdSetViewport(vk.cmds[vk.frame_index], 0, 1, &viewport); VkRect2D scissor = { extent: { @@ -506,7 +496,7 @@ Bind(Vulkan* vk, PipelineHandle pipeline) }, }; - vkCmdSetScissor(vk.cmds[index], 0, 1, &scissor); + vkCmdSetScissor(vk.cmds[vk.frame_index], 0, 1, &scissor); } pragma(inline): void @@ -953,21 +943,44 @@ InitDescriptors(Vulkan* vk) sampler: vk.nearest_sampler, }; - VkWriteDescriptorSet write = { - sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - dstSet: vk.desc_sets[DT.Shared], - dstBinding: 3, - descriptorCount: 1, - descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, - pImageInfo: &sampler_info, + VkDescriptorImageInfo draw_image_info = { + imageView: vk.draw_image.view, + imageLayout: VK_IMAGE_LAYOUT_GENERAL, }; - vkUpdateDescriptorSets(vk.device, 1, &write, 0, null); + VkWriteDescriptorSet[] writes = [ + { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 3, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_SAMPLER, + pImageInfo: &sampler_info, + }, + { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 2, + descriptorCount: 1, + descriptorType: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + pImageInfo: &draw_image_info, + }, + ]; + + vkUpdateDescriptorSets(vk.device, cast(u32)writes.length, writes.ptr, 0, null); } return success; } +void +Dispatch(Vulkan* vk) +{ + f32 w = Ceil(cast(f32)(vk.swapchain_extent.width) / 16.0F); + f32 h = Ceil(cast(f32)(vk.swapchain_extent.height) / 16.0F); + vkCmdDispatch(vk.cmds[vk.frame_index], cast(u32)w, cast(u32)h, 1); +} + bool VkCheck(string message, VkResult result) { @@ -1010,12 +1023,16 @@ InitFrameStructures(Vulkan* vk) level: VK_COMMAND_BUFFER_LEVEL_PRIMARY, }; - vk.swapchain_sems = a.AllocArray!(VkSemaphore)(arena, vk.present_images.length); + u32 sem_count = cast(u32)vk.present_images.length; + vk.submit_sems = a.AllocArray!(VkSemaphore)(arena, sem_count); - foreach(i; 0 .. vk.swapchain_sems.length) + foreach(i; 0 .. sem_count) { - VkResult result = vkCreateSemaphore(vk.device, &sem_info, null, vk.swapchain_sems.ptr + i); - success = VkCheck("vkCreateSemaphore failure", result); + if (success) + { + VkResult result = vkCreateSemaphore(vk.device, &sem_info, null, vk.submit_sems.ptr + i); + success = VkCheck("vkCreateSemaphore failure", result); + } } foreach(i; 0 .. FRAME_OVERLAP) @@ -1043,7 +1060,7 @@ InitFrameStructures(Vulkan* vk) if (success) { - result = vkCreateSemaphore(vk.device, &sem_info, null, vk.render_sems.ptr + i); + result = vkCreateSemaphore(vk.device, &sem_info, null, vk.acquire_sems.ptr + i); success = VkCheck("vkCreateSemaphore failure", result); } } @@ -1809,7 +1826,7 @@ DestroyFS(Vulkan* vk) vkDestroyCommandPool(vk.device, vk.imm_pool, null); } - foreach(i, sem; vk.swapchain_sems) + foreach(sem; vk.submit_sems) { if (sem) { @@ -1819,11 +1836,6 @@ DestroyFS(Vulkan* vk) foreach(i; 0 .. FRAME_OVERLAP) { - if (vk.render_sems[i]) - { - vkDestroySemaphore(vk.device, vk.render_sems[i], null); - } - if (vk.render_fences[i]) { vkDestroyFence(vk.device, vk.render_fences[i], null); @@ -1838,6 +1850,11 @@ DestroyFS(Vulkan* vk) { vkDestroyCommandPool(vk.device, vk.cmd_pools[i], null); } + + if (vk.acquire_sems[i]) + { + vkDestroySemaphore(vk.device, vk.acquire_sems[i], null); + } } } @@ -1922,7 +1939,6 @@ version(Windows) return success; } - void EnableVLayers(Vulkan* vk) { diff --git a/src/shaders/gradient.comp.glsl b/src/shaders/gradient.comp.glsl index 0d838e5..ce38a5b 100644 --- a/src/shaders/gradient.comp.glsl +++ b/src/shaders/gradient.comp.glsl @@ -12,11 +12,11 @@ void main() ivec2 texel_coord = ivec2(gl_GlobalInvocationID.xy); ivec2 size = imageSize(DrawImage); - if (texel_coord.x < size. x && texel_coord.y < size.y) + if (texel_coord.x < size.x && texel_coord.y < size.y) { vec4 color = vec4(0.0); - if (gl_GlobalInvocationID.x != 0 && gl_LocalInvocationID.y != 0) + if (gl_LocalInvocationID.x != 0 && gl_LocalInvocationID.y != 0) { color.x = float(texel_coord.x) / size.x; color.y = float(texel_coord.y) / size.y;