gui pipeline setup, misc vulkan work

This commit is contained in:
matthew 2025-07-13 18:27:13 +10:00
parent b89d01984c
commit 82df45e488
13 changed files with 595 additions and 81 deletions

Binary file not shown.

BIN
assets/shaders/gui.frag.spv Normal file

Binary file not shown.

BIN
assets/shaders/gui.vert.spv Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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);
}

View File

@ -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, &copy);
};
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, &copy);
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);
}
}

View File

@ -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,
];

18
src/shaders/gui.frag.glsl Normal file
View File

@ -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;
}

46
src/shaders/gui.vert.glsl Normal file
View File

@ -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);
}

View File

@ -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;

View File

@ -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)
}
}

View File

@ -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);