gui pipeline setup, misc vulkan work
This commit is contained in:
parent
b89d01984c
commit
82df45e488
Binary file not shown.
BIN
assets/shaders/gui.frag.spv
Normal file
BIN
assets/shaders/gui.frag.spv
Normal file
Binary file not shown.
BIN
assets/shaders/gui.vert.spv
Normal file
BIN
assets/shaders/gui.vert.spv
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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;
|
||||
}
|
||||
|
||||
void
|
||||
DrawRect(Renderer* rd, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col)
|
||||
{
|
||||
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;
|
||||
|
||||
u32 index_count = rd.ui_count * 6;
|
||||
|
||||
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;
|
||||
|
||||
rd.ui_count += 1;
|
||||
}
|
||||
|
||||
Pipeline
|
||||
BuildGfxPipeline(Renderer* rd, string vertex, string fragment)
|
||||
BuildGfxPipeline(Renderer* rd, GfxPipelineInfo* info)
|
||||
{
|
||||
u8[] vert_bytes = ap.LoadAssetData(vertex);
|
||||
u8[] frag_bytes = ap.LoadAssetData(fragment);
|
||||
|
||||
scope(exit)
|
||||
{
|
||||
ap.UnloadAssetData(vertex);
|
||||
ap.UnloadAssetData(fragment);
|
||||
}
|
||||
|
||||
assert(vert_bytes && frag_bytes, "Unable to load shaders");
|
||||
|
||||
Result!(Shader) vert_module = vk.BuildShader(&rd.vulkan, vert_bytes);
|
||||
Result!(Shader) frag_module = vk.BuildShader(&rd.vulkan, frag_bytes);
|
||||
|
||||
assert(vert_module.ok && frag_module.ok, "Unable to build vulkan shaders");
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
18
src/shaders/gui.frag.glsl
Normal 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
46
src/shaders/gui.vert.glsl
Normal 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);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user