diff --git a/assets/shaders/gradient.comp.spv b/assets/shaders/gradient.comp.spv index 319e010..23de3cb 100644 Binary files a/assets/shaders/gradient.comp.spv and b/assets/shaders/gradient.comp.spv differ diff --git a/assets/shaders/gui.frag.spv b/assets/shaders/gui.frag.spv new file mode 100644 index 0000000..fec021e Binary files /dev/null and b/assets/shaders/gui.frag.spv differ diff --git a/assets/shaders/gui.vert.spv b/assets/shaders/gui.vert.spv new file mode 100644 index 0000000..07752bf Binary files /dev/null and b/assets/shaders/gui.vert.spv differ diff --git a/assets/shaders/triangle.frag.spv b/assets/shaders/triangle.frag.spv index d039d54..2bd01d0 100644 Binary files a/assets/shaders/triangle.frag.spv and b/assets/shaders/triangle.frag.spv differ diff --git a/assets/shaders/triangle.vert.spv b/assets/shaders/triangle.vert.spv index 44718ec..7f35aa6 100644 Binary files a/assets/shaders/triangle.vert.spv and b/assets/shaders/triangle.vert.spv differ diff --git a/src/gears/renderer.d b/src/gears/renderer.d index 90b3160..c6887a0 100644 --- a/src/gears/renderer.d +++ b/src/gears/renderer.d @@ -10,6 +10,7 @@ import p = platform; alias Shader = VkShaderModule; alias Pipeline = vk.PipelineHandle; alias Attribute = VkVertexInputAttributeDescription; +alias Buffer = VkBuffer; enum InputRate : int { @@ -17,7 +18,9 @@ enum InputRate : int Instance = VK_VERTEX_INPUT_RATE_INSTANCE, } -enum Format: int +alias IR = InputRate; + +enum Format: VkFormat { UINT = VK_FORMAT_R32_UINT, R_F32 = VK_FORMAT_R32_SFLOAT, @@ -26,6 +29,20 @@ enum Format: int RGBA_F32 = VK_FORMAT_R32G32B32A32_SFLOAT, } +alias FMT = Format; + +enum BufferType : int +{ + None = 0, + Vertex = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + Index = VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + Uniform = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + Storage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + Staging = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, +} + +alias BT = BufferType; + enum PipelineType : int { Graphics, @@ -36,8 +53,8 @@ alias PT = PipelineType; struct GfxPipelineInfo { - Shader vertex_shader; - Shader frag_shader; + string vertex_shader; + string frag_shader; InputRate input_rate; u32 input_rate_stride; Attribute[] vertex_attributes; @@ -47,8 +64,55 @@ struct Renderer { vk.Vulkan vulkan; p.Window* window; + + GlobalUniforms globals; + UIVertex[] ui_vertex_buf; + u32[] ui_index_buf; + u32 ui_count; + Pipeline triangle_pipeline; Pipeline compute_pipeline; + Pipeline ui_pipeline; +} + +struct GlobalUniforms +{ + Vec2 res; +} + +struct ShaderUniforms +{ + f32 placeholder; +} + +struct UIVertex +{ + Vec2 p0; + Vec2 p1; + Vec4 col; + u32 texture; +} + +struct Vertex +{ + Vec3 pos; + Vec3 n; + Vec2 uv; + u32 col; +} + +struct MeshPart +{ + u32 mat; + u32 offset; + u32 length; +} + +struct Model +{ + Buffer vertex_buffer; + Buffer index_buffer; + MeshPart[] parts; } Renderer @@ -60,9 +124,30 @@ Init(p.Window* window) Renderer rd = { vulkan: vk_result.value, window: window, + ui_vertex_buf: vk.GetUIVertexBuffer(&vk_result.value), + ui_index_buf: vk.GetUIIndexBuffer(&vk_result.value), }; - rd.triangle_pipeline = BuildGfxPipeline(&rd, "shaders/triangle.vert", "shaders/triangle.frag"); + GfxPipelineInfo triangle_info = { + vertex_shader: "shaders/triangle.vert", + frag_shader: "shaders/triangle.frag", + }; + + GfxPipelineInfo ui_info = { + vertex_shader: "shaders/gui.vert", + frag_shader: "shaders/gui.frag", + input_rate: IR.Instance, + input_rate_stride: UIVertex.sizeof, + vertex_attributes: [ + { binding: 0, location: 0, format: FMT.RG_F32, offset: 0 }, + { binding: 0, location: 1, format: FMT.RG_F32, offset: UIVertex.p1.offsetof }, + { binding: 0, location: 2, format: FMT.RGBA_F32, offset: UIVertex.col.offsetof }, + { binding: 0, location: 3, format: FMT.UINT, offset: UIVertex.texture.offsetof }, + ], + }; + + rd.triangle_pipeline = BuildGfxPipeline(&rd, &triangle_info); + rd.ui_pipeline = BuildGfxPipeline(&rd, &ui_info); rd.compute_pipeline = BuildCompPipeline(&rd, "shaders/gradient.comp"); return rd; @@ -73,16 +158,28 @@ Cycle(Renderer* rd) { bool success = vk.BeginFrame(&rd.vulkan); + rd.ui_count = 0; + if (success) { vk.Bind(&rd.vulkan, rd.compute_pipeline); + vk.SetUniform(&rd.vulkan, &rd.globals); + + DrawRect(rd, 150.0, 300.0, 200.0, 350.0, Vec4(r: 0.0, g: 0.0, b: 1.0, a: 1.0)); + vk.PrepCompute(&rd.vulkan); vk.Dispatch(&rd.vulkan); vk.BeginRender(&rd.vulkan); + vk.Bind(&rd.vulkan, rd.ui_pipeline); + + vk.BindUIBuffers(&rd.vulkan); + + vk.DrawIndexed(&rd.vulkan, 6, rd.ui_count); + vk.Bind(&rd.vulkan, rd.triangle_pipeline); vk.Draw(&rd.vulkan, 3, 1); @@ -93,51 +190,37 @@ Cycle(Renderer* rd) return success; } -Pipeline -BuildGfxPipeline(Renderer* rd, string vertex, string fragment) +void +DrawRect(Renderer* rd, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col) { - u8[] vert_bytes = ap.LoadAssetData(vertex); - u8[] frag_bytes = ap.LoadAssetData(fragment); - - scope(exit) - { - ap.UnloadAssetData(vertex); - ap.UnloadAssetData(fragment); - } + rd.ui_vertex_buf[rd.ui_count].p0.x = p0_x; + rd.ui_vertex_buf[rd.ui_count].p0.y = p0_y; + rd.ui_vertex_buf[rd.ui_count].p1.x = p1_x; + rd.ui_vertex_buf[rd.ui_count].p1.y = p1_y; + rd.ui_vertex_buf[rd.ui_count].col = col; - assert(vert_bytes && frag_bytes, "Unable to load shaders"); + u32 index_count = rd.ui_count * 6; - Result!(Shader) vert_module = vk.BuildShader(&rd.vulkan, vert_bytes); - Result!(Shader) frag_module = vk.BuildShader(&rd.vulkan, frag_bytes); + rd.ui_index_buf[index_count+0] = index_count+0; + rd.ui_index_buf[index_count+1] = index_count+1; + rd.ui_index_buf[index_count+2] = index_count+2; + rd.ui_index_buf[index_count+3] = index_count+1; + rd.ui_index_buf[index_count+4] = index_count+2; + rd.ui_index_buf[index_count+5] = index_count+3; - assert(vert_module.ok && frag_module.ok, "Unable to build vulkan shaders"); + rd.ui_count += 1; +} - scope(exit) - { - vk.Destroy(&rd.vulkan, vert_module.value); - vk.Destroy(&rd.vulkan, frag_module.value); - } - - GfxPipelineInfo pipeline_info = { - vertex_shader: vert_module.value, - frag_shader: frag_module.value, - }; - - return vk.CreateGraphicsPipeline(&rd.vulkan, &pipeline_info); +Pipeline +BuildGfxPipeline(Renderer* rd, GfxPipelineInfo* info) +{ + return vk.CreateGraphicsPipeline(&rd.vulkan, info); } Pipeline BuildCompPipeline(Renderer* rd, string compute) { - u8[] comp_bytes = ap.LoadAssetData(compute); - assert(comp_bytes != null, "Unable to load compute shader data"); - scope(exit) ap.UnloadAssetData(compute); - - Result!(Shader) comp_module = vk.BuildShader(&rd.vulkan, comp_bytes); - assert(comp_module.ok, "Unable to build compute shader"); - scope(exit) vk.Destroy(&rd.vulkan, comp_module.value); - - return vk.CreateComputePipeline(&rd.vulkan, comp_module.value); + return vk.CreateComputePipeline(&rd.vulkan, compute); } void @@ -147,3 +230,5 @@ Destroy(Renderer* rd) vk.Destroy(&rd.vulkan, rd.compute_pipeline); vk.Destroy(&rd.vulkan); } + + diff --git a/src/gears/vulkan.d b/src/gears/vulkan.d index 3542c84..a3d34d2 100644 --- a/src/gears/vulkan.d +++ b/src/gears/vulkan.d @@ -5,9 +5,10 @@ import std.stdio; import std.algorithm.comparison; import core.stdc.string : strcmp; import std.format : sformat; -import u = util : HashTable, Result, Logf, Log; +import u = util : HashTable, Result, Logf, Log, MB; import a = alloc; import p = platform; +import ap = assets; import renderer; import std.math.rounding : Ceil = ceil; @@ -68,7 +69,7 @@ enum StepInitialized : u32 Surface, Device, Vma, - MappedBuffers, // TODO + Buffers, FrameStructures, Swapchain, DrawImages, @@ -82,7 +83,6 @@ enum DescType : u32 Shared = 0, SampledImage, Material, - Mesh, Max, } @@ -106,6 +106,23 @@ struct ImageView { Image base; VkImageView view; + + alias base this; +} + +struct MappedBuffer(T) +{ + Buffer base; + T[] data; + u64 offset; + + alias base this; +} + +struct Buffer +{ + VkBuffer buffer; + VmaAllocation alloc; } struct DescBindings @@ -165,7 +182,15 @@ struct Vulkan VkPipelineLayout pipeline_layout; + MappedBuffer!(u8) transfer_buf; + MappedBuffer!(UIVertex) ui_vert_buf; + MappedBuffer!(u32) ui_index_buf; + MappedBuffer!(GlobalUniforms) global_buf; + MappedBuffer!(ShaderUniforms) shader_buf; + QueueInfo queues; + + alias queues this; } struct PipelineHandle @@ -214,6 +239,7 @@ Init(p.Window* window, u64 permanent_mem, u64 frame_mem) if (success) success = CreateDrawImages(&vk); if (success) success = InitFrameStructures(&vk); if (success) success = InitDescriptors(&vk); + if (success) InitBuffers(&vk); u.Result!(Vulkan) result = { ok: success, @@ -223,10 +249,106 @@ Init(p.Window* window, u64 permanent_mem, u64 frame_mem) return result; } +Buffer +CreateBuffer(Vulkan* vk, BufferType type, u64 size, bool host_visible) +{ + assert(type != BT.None, "CreateBuffer failure: type is None"); + + VkBufferCreateInfo buffer_info = { + sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + usage: type, + size: size, + }; + + VmaAllocationCreateInfo alloc_info = { + usage: VMA_MEMORY_USAGE_UNKNOWN, + flags: VMA_ALLOCATION_CREATE_MAPPED_BIT, + }; + + if (host_visible) + { + alloc_info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + alloc_info.preferredFlags = VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + } + else + { + buffer_info.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + alloc_info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + + if (vk.queues.gfx_index != vk.queues.tfer_index) + { + buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + buffer_info.queueFamilyIndexCount = 2; + buffer_info.pQueueFamilyIndices = cast(const u32*)[vk.queues.gfx_index, vk.queues.tfer_index]; + } + + VmaAllocationInfo vma_info; + Buffer buf; + VkResult result = vmaCreateBuffer(vk.vma, &buffer_info, &alloc_info, &buf.buffer, &buf.alloc, &vma_info); + // TODO: handle errors here then reallocate buffer + assert(VkCheck("CreateBuffer failure: vmaCreateBuffer error", result), "CreateBuffer failure"); + + return buf; +} + +void +InitBuffers(Vulkan* vk) +{ + Push(vk, SI.Buffers); + + vk.global_buf = CreateMappedBuffer!(GlobalUniforms)(vk, BT.Uniform, 1); + + u64 transfer_size = MB(64); + vk.transfer_buf = CreateMappedBuffer!(u8)(vk, BT.Staging, transfer_size); + + u64 ui_size = MB(30); + vk.ui_vert_buf = CreateMappedBuffer!(UIVertex)(vk, BT.Vertex, ui_size / UIVertex.sizeof); + vk.ui_index_buf = CreateMappedBuffer!(u32)(vk, BT.Index, ui_size / u32.sizeof); +} + +void +BindUIBuffers(Vulkan* vk) +{ + VkDeviceSize offset = 0; + + vkCmdBindIndexBuffer(vk.cmds[vk.frame_index], vk.ui_index_buf.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindVertexBuffers(vk.cmds[vk.frame_index], 0, 1, &vk.ui_vert_buf.buffer, &offset); +} + +MappedBuffer!(T) +CreateMappedBuffer(T)(Vulkan* vk, BufferType type, u64 count) +{ + MappedBuffer!(T) buf; + buf.base = CreateBuffer(vk, type, T.sizeof * count, true); + buf.data = MapBuffer!(T)(vk, &buf.base, count); + return buf; +} + +T[] +MapBuffer(T)(Vulkan* vk, Buffer* buffer, u64 count) +{ + void* ptr; + vmaMapMemory(vk.vma, buffer.alloc, &ptr); + return (cast(T*)ptr)[0 .. count]; +} + VkImage CurrentImage(Vulkan* vk) { - return vk.present_images[vk.image_index].base.image; + return vk.present_images[vk.image_index].image; +} + +UIVertex[] +GetUIVertexBuffer(Vulkan* vk) +{ + return vk.ui_vert_buf.data; +} + +u32[] +GetUIIndexBuffer(Vulkan* vk) +{ + return vk.ui_index_buf.data; } bool @@ -279,8 +401,8 @@ 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); + Transition(vk.cmds[vk.frame_index], &vk.draw_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + Transition(vk.cmds[vk.frame_index], &vk.depth_image, 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); @@ -288,7 +410,7 @@ BeginRender(Vulkan* vk) VkRenderingAttachmentInfo col_attach = { sType: VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, imageView: vk.draw_image.view, - imageLayout: vk.draw_image.base.layout, + imageLayout: vk.draw_image.layout, loadOp: VK_ATTACHMENT_LOAD_OP_LOAD, // CLEAR instead of LOAD if wanting to clear colors, also clearColor value (or whatever) storeOp: VK_ATTACHMENT_STORE_OP_STORE, }; @@ -296,7 +418,7 @@ BeginRender(Vulkan* vk) VkRenderingAttachmentInfo depth_attach = { sType: VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, imageView: vk.depth_image.view, - imageLayout: vk.depth_image.base.layout, + imageLayout: vk.depth_image.layout, loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR, storeOp: VK_ATTACHMENT_STORE_OP_STORE, }; @@ -345,7 +467,7 @@ FinishFrame(Vulkan* vk) }; // TODO: Find out how to copy from same dimension images - Copy(vk.cmds[vk.frame_index], vk.draw_image.base.image, image, extent, extent); + Copy(vk.cmds[vk.frame_index], vk.draw_image.image, image, extent, extent); Transition(vk.cmds[vk.frame_index], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); @@ -424,6 +546,135 @@ DrawIndexed(Vulkan* vk, u32 index_count, u32 instance_count) vkCmdDrawIndexed(vk.cmds[vk.frame_index], index_count, instance_count, 0, 0, 0); } +bool +ImmSubmit(Vulkan* vk, void delegate() fn) +{ + VkResult result = vkWaitForFences(vk.device, 1, &vk.imm_fence, true, 999999999); + bool success = VkCheck("ImmSubmit failure: vkWaitForFences error", result); + + if (success) + { + result = vkResetFences(vk.device, 1, &vk.imm_fence); + success = VkCheck("ImmSubmit failure: vkResetFences error", result); + } + + if (success) + { + result = vkResetCommandBuffer(vk.imm_cmd, 0); + success = VkCheck("ImmSubmit failure: vkResetCommandBuffer error", result); + } + + bool imm_started; + if (success) + { + VkCommandBufferBeginInfo cmd_info = { + sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + flags: VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + + result = vkBeginCommandBuffer(vk.imm_cmd, &cmd_info); + imm_started = success = VkCheck("ImmSubmit failure: vkBeginCommandBuffer error", result); + } + + if (success) + { + fn(); + + result = vkEndCommandBuffer(vk.imm_cmd); + success = VkCheck("ImmSubmit failure: vkEndCommandBuffer error", result); + } + + if (success) + { + VkCommandBufferSubmitInfo cmd_info = { + sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + commandBuffer: vk.imm_cmd, + }; + + VkSubmitInfo2 submit_info = { + sType: VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + commandBufferInfoCount: 1, + pCommandBufferInfos: &cmd_info, + }; + + result = vkQueueSubmit2(vk.tfer_queue, 1, &submit_info, vk.imm_fence); + success = VkCheck("ImmSubmit failure: vkQueueSubmit2 error", result); + } + + return success; +} + +void +Transfer(Vulkan* vk, Buffer* buf, u8[] data) +{ + u64 copied = 0; + while(copied != data.length) + { + u64 transfer_length = cast(u64)vk.transfer_buf.data.length; + u64 data_length = cast(u64)data.length - copied; + u64 copy_length = transfer_length > data_length ? data_length : transfer_length; + + vk.transfer_buf.data[0 .. copy_length] = data[copied .. copy_length]; + + auto fn = delegate() + { + VkBufferCopy copy = { + srcOffset: 0, + dstOffset: copied, + size: copy_length, + }; + + vkCmdCopyBuffer(vk.imm_cmd, vk.transfer_buf.buffer, buf.buffer, 1, ©); + }; + + ImmSubmit(vk, fn); + + copied += copy_length; + } +} + +void +Transfer(Vulkan* vk, Image* image, u8[] data, u32 w, u32 h) +{ + u64 copied = 0; + while(copied != data.length) + { + u64 transfer_length = cast(u64)vk.transfer_buf.data.length; + u64 data_length = cast(u64)data.length - copied; + u64 copy_length = transfer_length > data_length ? data_length : transfer_length; + + vk.transfer_buf.data[0 .. copy_length] = data[copied .. copy_length]; + + auto fn = delegate() + { + VkBufferImageCopy copy = { + bufferRowLength: w, + bufferImageHeight: h, + imageSubresource: { + aspectMask: VK_IMAGE_ASPECT_COLOR_BIT, + layerCount: 1, + }, + imageExtent: { + width: w, + height: h, + depth: 1, + }, + bufferOffset: copied, + }; + + Transition(vk.imm_cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + vkCmdCopyBufferToImage(vk.imm_cmd, vk.transfer_buf.buffer, image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + + Transition(vk.imm_cmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + }; + + ImmSubmit(vk, fn); + + copied += copy_length; + } +} + pragma(inline): void Copy(VkCommandBuffer cmd, VkImage src, VkImage dst, VkExtent2D src_ext, VkExtent2D dst_ext) { @@ -532,8 +783,8 @@ Transition(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkI pragma(inline): void Transition(VkCommandBuffer cmd, ImageView* view, VkImageLayout new_layout) { - Transition(cmd, view.base.image, view.base.layout, new_layout); - view.base.layout = new_layout; + Transition(cmd, view.image, view.layout, new_layout); + view.layout = new_layout; } pragma(inline): void @@ -606,8 +857,8 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info) VkPipelineRenderingCreateInfo rendering_info = { sType: VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, colorAttachmentCount: 1, - pColorAttachmentFormats: &vk.draw_image.base.format, - depthAttachmentFormat: vk.depth_image.base.format, + pColorAttachmentFormats: &vk.draw_image.format, + depthAttachmentFormat: vk.depth_image.format, }; VkPipelineColorBlendAttachmentState blend_state = { @@ -656,8 +907,30 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info) }, ]; - __traits(getMember, shader_info.ptr + 0, "module") = build_info.vertex_shader; - __traits(getMember, shader_info.ptr + 1, "module") = build_info.frag_shader; + u8[] vert_bytes = ap.LoadAssetData(build_info.vertex_shader); + u8[] frag_bytes = ap.LoadAssetData(build_info.frag_shader); + + scope(exit) + { + ap.UnloadAssetData(build_info.vertex_shader); + ap.UnloadAssetData(build_info.frag_shader); + } + + assert(vert_bytes && frag_bytes, "Unable to load shaders"); + + Result!(Shader) vert_module = BuildShader(vk, vert_bytes); + Result!(Shader) frag_module = BuildShader(vk, frag_bytes); + + assert(vert_module.ok && frag_module.ok, "Unable to build vulkan shaders"); + + scope(exit) + { + Destroy(vk, vert_module.value); + Destroy(vk, frag_module.value); + } + + __traits(getMember, shader_info.ptr + 0, "module") = vert_module.value; + __traits(getMember, shader_info.ptr + 1, "module") = frag_module.value; VkGraphicsPipelineCreateInfo create_info = { sType: VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, @@ -683,9 +956,8 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info) return pipeline; } - Pipeline -CreateComputePipeline(Vulkan* vk, Shader shader) +CreateComputePipeline(Vulkan* vk, string shader) { VkComputePipelineCreateInfo info = { sType: VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, @@ -697,7 +969,15 @@ CreateComputePipeline(Vulkan* vk, Shader shader) }, }; - __traits(getMember, &info.stage, "module") = shader; + u8[] comp_bytes = ap.LoadAssetData(shader); + assert(comp_bytes != null, "Unable to load compute shader data"); + scope(exit) ap.UnloadAssetData(shader); + + Result!(Shader) comp_module = BuildShader(vk, comp_bytes); + assert(comp_module.ok, "Unable to build compute shader"); + scope(exit) Destroy(vk, comp_module.value); + + __traits(getMember, &info.stage, "module") = comp_module.value; PipelineHandle pipeline = { type: VK_PIPELINE_BIND_POINT_COMPUTE }; VkResult result = vkCreateComputePipelines(vk.device, null, 1, &info, null, &pipeline.handle); @@ -706,6 +986,31 @@ CreateComputePipeline(Vulkan* vk, Shader shader) return pipeline; } +void +SetUniform(Vulkan* vk, GlobalUniforms* globals) +{ + globals.res.x = vk.swapchain_extent.width; + globals.res.y = vk.swapchain_extent.height; + + vk.global_buf.data[0] = *globals; + + VkDescriptorBufferInfo buffer_info = { + buffer: vk.global_buf.buffer, + range: VK_WHOLE_SIZE, + }; + + VkWriteDescriptorSet write = { + sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: vk.desc_sets[DT.Shared], + dstBinding: 0, + descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + descriptorCount: 1, + pBufferInfo: &buffer_info, + }; + + vkUpdateDescriptorSets(vk.device, 1, &write, 0, null); +} + void Destroy(Vulkan* vk, Shader shader) { @@ -757,12 +1062,28 @@ Destroy(Vulkan* vk) case SI.Descriptors: Destroy(vk.desc_pool, vk.desc_layouts, vk.pipeline_layout, vk.nearest_sampler, vk.device); break; + case SI.Buffers: + Destroy(vk, &vk.transfer_buf); + break; default: break; } } } +void +Destroy(T)(Vulkan* vk, MappedBuffer!(T)* buf) +{ + vmaUnmapMemory(vk.vma, buf.alloc); + Destroy(vk, &buf.base); +} + +void +Destroy(Vulkan* vk, Buffer* buf) +{ + vmaDestroyBuffer(vk.vma, buf.buffer, buf.alloc); +} + bool InitDescriptors(Vulkan* vk) { @@ -824,7 +1145,6 @@ InitDescriptors(Vulkan* vk) VkDescriptorType[DT.max] type_lookup = [ DT.SampledImage: VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, DT.Material: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - DT.Mesh: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, ]; VkDescriptorBindingFlags bindless_flag = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; @@ -1145,14 +1465,14 @@ CreateDrawImages(Vulkan* vk) format: draw_format, }; - VkResult result = vmaCreateImage(vk.vma, &image_info, &alloc_info, &vk.draw_image.base.image, &vk.draw_image.base.alloc, null); + VkResult result = vmaCreateImage(vk.vma, &image_info, &alloc_info, &vk.draw_image.image, &vk.draw_image.alloc, null); success = VkCheck("vmaCreateImage failure", result); if (success) { VkImageViewCreateInfo view_info = { sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - image: vk.draw_image.base.image, + image: vk.draw_image.image, format: draw_format, viewType: VK_IMAGE_VIEW_TYPE_2D, subresourceRange: { @@ -1182,7 +1502,7 @@ CreateDrawImages(Vulkan* vk) extent: vk.swapchain_extent, }; - result = vmaCreateImage(vk.vma, &depth_image_info, &alloc_info, &vk.depth_image.base.image, &vk.depth_image.base.alloc, null); + result = vmaCreateImage(vk.vma, &depth_image_info, &alloc_info, &vk.depth_image.image, &vk.depth_image.alloc, null); success = VkCheck("vmaCreateImage failure", result); } @@ -1190,7 +1510,7 @@ CreateDrawImages(Vulkan* vk) { VkImageViewCreateInfo depth_view_info = { sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - image: vk.depth_image.base.image, + image: vk.depth_image.image, viewType: VK_IMAGE_VIEW_TYPE_2D, format: depth_format, subresourceRange: { @@ -1206,10 +1526,10 @@ CreateDrawImages(Vulkan* vk) success = VkCheck("vmaCreateImageView failure", result); } - vk.draw_image.base.format = draw_format; - vk.draw_image.base.layout = VK_IMAGE_LAYOUT_UNDEFINED; - vk.depth_image.base.format = depth_format; - vk.depth_image.base.layout = VK_IMAGE_LAYOUT_UNDEFINED; + vk.draw_image.format = draw_format; + vk.draw_image.layout = VK_IMAGE_LAYOUT_UNDEFINED; + vk.depth_image.format = depth_format; + vk.depth_image.layout = VK_IMAGE_LAYOUT_UNDEFINED; return success; } @@ -1310,7 +1630,7 @@ CreateSwapchain(Vulkan* vk) foreach(i, image; vk.present_images) { - vk.present_images[i].base.image = images[i]; + vk.present_images[i].image = images[i]; view_info.image = images[i]; view_info.format = vk.surface_format.format; @@ -1771,9 +2091,9 @@ Destroy(ImageView* view, VkDevice device, VmaAllocator vma) vkDestroyImageView(device, view.view, null); } - if (view.base.image) + if (view.image) { - vmaDestroyImage(vma, view.base.image, view.base.alloc); + vmaDestroyImage(vma, view.image, view.alloc); } } diff --git a/src/generated/assets_codegen.d b/src/generated/assets_codegen.d index ac1a0c0..5469113 100644 --- a/src/generated/assets_codegen.d +++ b/src/generated/assets_codegen.d @@ -26,19 +26,25 @@ static immutable u64[] MODEL_HASHES = [ ]; static immutable string[] SHADER_FILES = [ + "shaders/gui.frag.spv", "shaders/triangle.vert.spv", + "shaders/gui.vert.spv", "shaders/gradient.comp.spv", "shaders/triangle.frag.spv", ]; static immutable string[] SHADER_NAMES = [ + "shaders/gui.frag", "shaders/triangle.vert", + "shaders/gui.vert", "shaders/gradient.comp", "shaders/triangle.frag", ]; static immutable u64[] SHADER_HASHES = [ + 15780387719315455808, 8769314645675479020, + 14797956403837654625, 16130483095684998267, 6282520872716708711, ]; diff --git a/src/shaders/gui.frag.glsl b/src/shaders/gui.frag.glsl new file mode 100644 index 0000000..500f07f --- /dev/null +++ b/src/shaders/gui.frag.glsl @@ -0,0 +1,18 @@ +#version 460 + +#extension GL_EXT_buffer_reference : require +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : require + +#include "structures.layout" + +layout (location = 0) in vec4 in_color; +layout (location = 1) in vec2 in_uv; +layout (location = 2) flat in uint in_image; + +layout (location = 0) out vec4 out_frag_col; + +void main() +{ + out_frag_col = in_color; +} diff --git a/src/shaders/gui.vert.glsl b/src/shaders/gui.vert.glsl new file mode 100644 index 0000000..6e4c839 --- /dev/null +++ b/src/shaders/gui.vert.glsl @@ -0,0 +1,46 @@ +#version 460 + +#extension GL_EXT_buffer_reference : require +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : require + +#include "structures.layout" + +layout (location = 0) in vec2 in_gui_pos_0; +layout (location = 1) in vec2 in_gui_pos_1; +layout (location = 2) in vec4 in_col; +layout (location = 3) in uint in_image; + +layout (location = 0) out vec4 out_color; +layout (location = 1) out vec2 out_uv; +layout (location = 2) out uint out_image; + +vec2 uvs[] = { + vec2(0.0, 1.0), + vec2(0.0, 0.0), + vec2(1.0, 1.0), + vec2(1.0, 0.0) +}; + +vec2 rotate(vec2 coords, float theta) +{ + return mat2(cos(theta), sin(theta), -sin(theta), cos(theta)) * coords; +} + +void main() +{ + // Draw with 6 indices, gl_VertexIndex will use the appropriate index, iterates through 0-3 and not 0-5 + vec2 dst_pos = gl_VertexIndex == 0 ? vec2(in_gui_pos_0.x, in_gui_pos_1.y) : + gl_VertexIndex == 1 ? vec2(in_gui_pos_0.x, in_gui_pos_0.y) : + gl_VertexIndex == 2 ? vec2(in_gui_pos_1.x, in_gui_pos_1.y) : + gl_VertexIndex == 3 ? vec2(in_gui_pos_1.x, in_gui_pos_0.y) : vec2(0.0, 0.0); + + out_uv = uvs[gl_VertexIndex]; + out_color = in_col; + out_image = in_image; + + gl_Position = vec4(2 * dst_pos.x / G.res.x - 1, + 2 * dst_pos.y / G.res.y - 1, + 0, + 1); +} diff --git a/src/shaders/structures.layout b/src/shaders/structures.layout index f6788dc..99c5f96 100644 --- a/src/shaders/structures.layout +++ b/src/shaders/structures.layout @@ -1,11 +1,3 @@ -struct Vertex { - vec4 pos; -}; - -layout (buffer_reference, std430) readonly buffer VertexBuffer { - Vertex vertices[]; -}; - layout (set = 0, binding = 0) uniform GlobalUniforms { vec2 res; } G; @@ -24,10 +16,6 @@ layout (set = 2, binding = 0) uniform Material { float placeholder; } Materials[]; -layout (set = 3, binding = 0) uniform Mesh { - VertexBuffer buf; -} Meshes[]; - layout (push_constant) uniform Constants { float placeholder; } PC; diff --git a/src/shared/assets.d b/src/shared/assets.d index 3fd53da..8225d08 100644 --- a/src/shared/assets.d +++ b/src/shared/assets.d @@ -41,6 +41,12 @@ struct ModelMeta u64 index_count; } +struct TexData +{ + void* data; + TexMeta meta; +} + struct TexMeta { u32 w; @@ -146,3 +152,5 @@ UnloadAssetData(string name) } } + + diff --git a/src/shared/util.d b/src/shared/util.d index a773084..45cd275 100644 --- a/src/shared/util.d +++ b/src/shared/util.d @@ -4,6 +4,7 @@ import includes; import std.stdio; import core.stdc.string : memset; import a = alloc; +import core.simd; void Logf(Args...)(string fmt, Args args) @@ -313,3 +314,45 @@ Hash(string str) { return xxh3_64bits_withSeed(str.ptr, str.length, HASH_SEED); } + +struct Matrix(T, int S) +{ + T[S][S] m; + alias m this; +} + +alias Mat2 = Matrix!(f32, 2); +alias Mat3 = Matrix!(f32, 3); +alias Mat4 = Matrix!(f32, 4); + +struct Vector(T, int S) +{ + union + { + struct + { + T r = 0.0; + T g = 0.0; + static if (S > 2) + T b = 0.0; + static if (S > 3) + T a = 0.0; + }; + struct + { + T x; + T y; + static if (S > 2) + T z; + static if (S > 3) + T w; + }; + static if (S == 4) + T[S] v; + float4 simd; + } +} + +alias Vec2 = Vector!(f32, 2); +alias Vec3 = Vector!(f32, 3); +alias Vec4 = Vector!(f32, 4);