fix renderer with compute/gfx pipelines, handle window events

This commit is contained in:
matthew 2025-07-12 17:20:47 +10:00
parent 42bef67206
commit 56cadf09df
6 changed files with 182 additions and 120 deletions

Binary file not shown.

View File

@ -14,6 +14,9 @@ void main()
while (true)
{
p.HandleEvents(&window);
if (window.close) break;
r.Cycle(&rd);
}
}

View File

@ -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 = {

View File

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

View File

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

View File

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