transitioned to render passes and vulkan 1.2, works but has a bug

This commit is contained in:
matthew 2025-08-07 07:25:17 +10:00
parent 8e35be5c62
commit 0c8aaa4b8c
14 changed files with 99 additions and 99 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -4,7 +4,7 @@ set -eu
# SHADERS
shader_compiler="glslc"
shader_flags="--target-spv=spv1.6 -std=460 --target-env=vulkan1.3"
shader_flags="--target-spv=spv1.5 -std=460 --target-env=vulkan1.3"
shader_out="-oassets/shaders/"
mkdir -p assets/shaders

View File

@ -108,22 +108,16 @@ InitGame(PlatformWindow* window)
UVec2 ext = GetExtent(&g.rd);
CreateImageView(&g.rd, &g.draw_image, ext.x, ext.y, GetDrawImageFormat(&g.rd), IU.Draw, false);
CreateImageView(&g.rd, &g.depth_image, ext.x, ext.y, FMT.D_SF32, IU.Depth, true);
CreateImageView(&g.rd, &g.aux_image, ext.x, ext.y, FMT.R_U32, IU.Storage);
GfxPipelineInfo triangle_info = {
vertex_shader: "shaders/triangle.vert.spv",
frag_shader: "shaders/triangle.frag.spv",
draw_image: &g.draw_image,
depth_image: &g.depth_image,
};
GfxPipelineInfo ui_info = {
vertex_shader: "shaders/gui.vert.spv",
frag_shader: "shaders/gui.frag.spv",
draw_image: &g.draw_image,
depth_image: &g.depth_image,
input_rate: IR.Instance,
input_rate_stride: UIVertex.sizeof,
vertex_attributes: [
@ -137,8 +131,6 @@ InitGame(PlatformWindow* window)
GfxPipelineInfo pbr_info = {
vertex_shader: "shaders/pbr.vert.spv",
frag_shader: "shaders/pbr.frag.spv",
draw_image: &g.draw_image,
depth_image: &g.depth_image,
input_rate_stride: Vertex.sizeof,
vertex_attributes: [
{ binding: 0, location: 0, format: FMT.RGBA_F32, offset: 0 },
@ -152,8 +144,6 @@ InitGame(PlatformWindow* window)
GfxPipelineInfo oit_info = {
vertex_shader: "shaders/full_screen_triangle.vert.spv",
frag_shader: "shaders/oit.frag.spv",
draw_image: &g.draw_image,
depth_image: &g.depth_image,
};
CompPipelineInfo gradient_info = {
@ -250,8 +240,6 @@ Cycle(Game* g)
ProcessInputs(g, &g.camera);
ResizeDrawImageIfNeeded(&g.rd, &g.draw_image);
ResizeDrawImageIfNeeded(&g.rd, &g.depth_image);
ResizeDrawImageIfNeeded(&g.rd, &g.aux_image);
UpdateAuxImage(&g.rd, &g.aux_image);
@ -282,7 +270,7 @@ Cycle(Game* g)
g.globals.res.y = ext.y;
SetUniform(&g.rd, &g.globals);
BeginRendering(&g.rd, &g.draw_image, &g.depth_image);
BeginRendering(&g.rd);
Bind(&g.rd, &g.ui_pipeline);
@ -323,7 +311,7 @@ Cycle(Game* g)
//FinishRendering(&g.rd);
SubmitAndPresent(&g.rd, &g.draw_image);
SubmitAndPresent(&g.rd);
}
pragma(inline): void

View File

@ -61,6 +61,7 @@ const char*[] VK_BASE_DEVICE_EXTENSIONS = [
cast(char*)VK_KHR_SWAPCHAIN_EXTENSION_NAME,
cast(char*)VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME,
cast(char*)VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
cast(char*)VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
];
const char*[] VK_AMD_DEVICE_EXTENSIONS = [
@ -150,9 +151,9 @@ struct GlobalUniforms
Mat4 projection_view = Mat4Identity();
Vec4 light_color;
Vec4 ambient_color;
vec3 light_direction;
Vec3 light_direction;
f32 padding;
vec2 res;
Vec2 res;
}
struct Image
@ -219,8 +220,6 @@ struct GfxPipelineInfo
Attribute[] vertex_attributes;
Specialization vert_spec;
Specialization frag_spec;
ImageView* draw_image;
ImageView* depth_image;
bool self_dependency;
}
@ -307,7 +306,7 @@ struct Vulkan
VkExtent3D swapchain_extent;
VkRenderPass render_pass;
VkFramebuffer[] framebuffers;
VkFramebuffer framebuffer;
ImageView[] present_images;
u32 image_index;
@ -418,6 +417,7 @@ Init(PlatformWindow* window, u64 permanent_mem, u64 frame_mem)
if (success) success = InitDescriptors(&vk);
if (success) InitBuffers(&vk);
if (success) success = InitConversionPipeline(&vk);
if (success) InitFramebufferAndRenderPass(&vk);
assert(success, "Error initializing vulkan");
@ -671,6 +671,12 @@ BeginFrame(Vulkan* vk)
void
BeginRendering(Vulkan* vk)
{
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);
VkClearValue clear_color = {
color: {
float32: [0.0, 0.0, 0.0, 1.0],
@ -680,13 +686,16 @@ BeginRendering(Vulkan* vk)
VkRenderPassBeginInfo pass_info = {
sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
renderPass: vk.render_pass,
framebuffer: vk.framebuffers[vk.image_index],
framebuffer: vk.framebuffer,
renderArea: {
offset: {
x: 0,
y: 0,
},
extent: vk.swapchain_extent,
extent: {
width: vk.swapchain_extent.width,
height: vk.swapchain_extent.height,
},
},
clearValueCount: 1,
pClearValues: &clear_color,
@ -738,7 +747,7 @@ FinishRendering(Vulkan* vk)
}
void
SubmitAndPresent(Vulkan* vk, ImageView* draw_image)
SubmitAndPresent(Vulkan* vk)
{
scope(exit)
{
@ -750,7 +759,7 @@ SubmitAndPresent(Vulkan* vk, ImageView* draw_image)
VkSemaphore acquire_sem = vk.acquire_sems[vk.frame_index];
VkSemaphore submit_sem = vk.submit_sems[vk.image_index];
Transition(vk.cmds[vk.frame_index], 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,
@ -758,27 +767,43 @@ SubmitAndPresent(Vulkan* vk, ImageView* draw_image)
};
// TODO: Find out how to copy from same dimension images (pretty sure its not blitting)
Copy(vk.cmds[vk.frame_index], &draw_image.base, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, extent, extent);
Copy(vk.cmds[vk.frame_index], &vk.draw_image.base, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, extent, extent);
Transition(vk.cmds[vk.frame_index], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
VkResult result = vkEndCommandBuffer(vk.cmds[vk.frame_index]);
VkCheckA("FinishFrame failure: vkEndCommandBuffer error", result);
VkPipelineStage stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submit_info = {
sType: VK_STRUCTURE_TYPE_SUBMIT_INFO,
waitSemaphoreCount: 1,
pWaitSemaphores: &acquire_sem,
pWaitDstStageMask: &stage,
commandBufferCount: 1,
pCommandBuffers: vk.cmds.ptr + vk.frame_index,
signalSemaphoreCount: 1,
pSignalSemaphores: &submit_sem,
VkCommandBufferSubmitInfo cmd_info = {
sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
commandBuffer: vk.cmds[vk.frame_index],
};
result = vkQueueSubmit(vk.queues.gfx_queue, 1, &submit_info, vk.render_fences[vk.frame_index]);
VkSemaphoreSubmitInfo wait_info = {
sType: VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
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: submit_sem,
stageMask: VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT,
value: 1,
};
VkSubmitInfo2 submit_info = {
sType: VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
waitSemaphoreInfoCount: 1,
pWaitSemaphoreInfos: &wait_info,
signalSemaphoreInfoCount: 1,
pSignalSemaphoreInfos: &signal_info,
commandBufferInfoCount: 1,
pCommandBufferInfos: &cmd_info,
};
result = vkQueueSubmit2(vk.queues.gfx_queue, 1, &submit_info, vk.render_fences[vk.frame_index]);
VkCheckA("FinishFrame failure: vkQueueSubmit2 error", result);
VkPresentInfoKHR present_info = {
@ -1146,18 +1171,22 @@ PushConstants(Vulkan* vk, PushConst* pc)
void
ImageBarrier(Vulkan* vk)
{
vkCmdPipelineBarrier(
vk.cmds[vk.frame_index],
VK_PIPELINE_STAGE_2_TRANSFER_BIT,
VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
VK_DEPENDENCY_BY_REGION_BIT,
1,
&barrier,
0,
null,
0,
null
);
VkMemoryBarrier2 barrier = {
sType: VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
srcStageMask: VK_PIPELINE_STAGE_2_TRANSFER_BIT,
srcAccessMask: VK_ACCESS_2_TRANSFER_WRITE_BIT,
dstStageMask: VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
dstAccessMask: VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT,
};
VkDependencyInfo dependency = {
sType: VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
dependencyFlags: VK_DEPENDENCY_BY_REGION_BIT,
memoryBarrierCount: 1,
pMemoryBarriers: &barrier,
};
vkCmdPipelineBarrier2(vk.cmds[vk.frame_index], &dependency);
}
bool
@ -1311,8 +1340,7 @@ Copy(VkCommandBuffer cmd, Image* src, VkImage dst, VkImageLayout dst_layout, VkE
pragma(inline): void
Copy(VkCommandBuffer cmd, VkImage src, VkImage dst, VkImageLayout src_layout, VkImageLayout dst_layout, VkExtent2D src_ext, VkExtent2D dst_ext)
{
VkImageBlit2 blit = {
sType: VK_STRUCTURE_TYPE_IMAGE_BLIT_2,
VkImageBlit blit = {
srcOffsets: [
{ x: 0, y: 0 },
{ x: cast(i32)src_ext.width, y: cast(i32)src_ext.height, z: 1 },
@ -1335,18 +1363,16 @@ Copy(VkCommandBuffer cmd, VkImage src, VkImage dst, VkImageLayout src_layout, Vk
},
};
VkBlitImageInfo2 blit_info = {
sType: VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2,
srcImage: src,
srcImageLayout: src_layout,
dstImage: dst,
dstImageLayout: dst_layout,
filter: VK_FILTER_LINEAR,
regionCount: 1,
pRegions: &blit,
};
vkCmdBlitImage2(cmd, &blit_info);
vkCmdBlitImage(
cmd,
src,
src_layout,
dst,
dst_layout,
1,
&blit,
VK_FILTER_LINEAR
);
}
void
@ -1393,23 +1419,6 @@ Bind(Vulkan* vk, PipelineHandle* pipeline)
pragma(inline): void
Transition(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout)
{
// TODO: continue from here
VkPipelineStageFlags src_stage, dst_stage;
VkAccessFlagBits src_access, dst_access;
switch(current_layout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
{
src_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
} break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
{
src_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
src_mask = VK_ACCESS_FLAG_TRANSFER_WRITE_BIT;
} break;
}
VkImageMemoryBarrier2 barrier = {
sType: VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
srcStageMask: VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
@ -1469,11 +1478,11 @@ BuildShader(Vulkan* vk, u8[] bytes)
}
void
InitFramebufferAndRenderpass(Vulkan* vk, ImageView* draw_image, ImageView* depth_image)
InitFramebufferAndRenderPass(Vulkan* vk)
{
VkAttachmentDescription[] attach_descriptions = [
{
format: draw_image.format,
format: vk.draw_image.format,
samples: VK_SAMPLE_COUNT_1_BIT,
loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR,
storeOp: VK_ATTACHMENT_STORE_OP_STORE,
@ -1483,7 +1492,8 @@ InitFramebufferAndRenderpass(Vulkan* vk, ImageView* draw_image, ImageView* depth
finalLayout: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
},
{
format: depth_image.format,
samples: VK_SAMPLE_COUNT_1_BIT,
format: vk.depth_image.format,
initialLayout: VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
finalLayout: VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
},
@ -1532,21 +1542,15 @@ InitFramebufferAndRenderpass(Vulkan* vk, ImageView* draw_image, ImageView* depth
VkFramebufferCreateInfo framebuffer_info = {
sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
renderPass: vk.render_pass,
attachmentCount: 1,
attachmentCount: 2,
pAttachments: [vk.draw_image.view, vk.depth_image.view],
width: vk.swapchain_extent.width,
height: vk.swapchain_extent.height,
layers: 1,
};
vk.framebuffers = AllocArray!(VkFramebuffer)(&vk.arena, vk.present_images.length);
foreach(i, image; vk.present_images)
{
framebuffer_info.pAttachments = &image.view;
result = vkCreateFramebuffer(vk.device, &framebuffer_info, null, &vk.framebuffers[i]);
VkCheckA("vkCreateFramebuffer failure", result);
}
result = vkCreateFramebuffer(vk.device, &framebuffer_info, null, &vk.framebuffer);
VkCheckA("vkCreateFramebuffer failure", result);
}
Pipeline
@ -1713,6 +1717,7 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info)
stageCount: cast(u32)shader_info.length,
pStages: shader_info.ptr,
layout: vk.pipeline_layout,
renderPass: vk.render_pass,
};
VkResult result = vkCreateGraphicsPipelines(vk.device, null, 1, &create_info, null, &pipeline.handle);
@ -2625,6 +2630,7 @@ CreateSwapchain(Vulkan* vk)
foreach(i, image; vk.present_images)
{
vk.present_images[i].image = images[i];
vk.present_images[i].format = cast(Format)vk.surface_format.format;
view_info.image = images[i];
view_info.format = vk.surface_format.format;
@ -2751,8 +2757,14 @@ InitDevice(Vulkan* vk)
count += 1;
}
VkPhysicalDeviceSynchronization2Features synchronization2 = {
sType: VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
synchronization2: VK_TRUE,
};
VkPhysicalDeviceVulkan12Features features_12 = {
sType: VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
pNext: &synchronization2,
descriptorIndexing: VK_TRUE,
bufferDeviceAddress: VK_TRUE,
descriptorBindingUniformBufferUpdateAfterBind: VK_TRUE,
@ -2841,12 +2853,9 @@ CheckDeviceFeatures(VkPhysicalDevice device)
{
VkPhysicalDeviceFeatures2 features2 = { sType: VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
VkPhysicalDeviceVulkan12Features features_12 = { sType: VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES };
VkPhysicalDeviceVulkan13Features features_13 = { sType: VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES };
features2.pNext = &features_12;
vkGetPhysicalDeviceFeatures2(device, &features2);
features2.pNext = &features_13;
vkGetPhysicalDeviceFeatures2(device, &features2);
VkPhysicalDeviceFeatures features = features2.features;
bool result = true;
@ -2872,9 +2881,6 @@ CheckDeviceFeatures(VkPhysicalDevice device)
result &= cast(bool)features_12.timelineSemaphore;
result &= cast(bool)features_12.storageBuffer8BitAccess;
result &= cast(bool)features_13.synchronization2;
result &= cast(bool)features_13.dynamicRendering;
return result;
}

View File

@ -83,13 +83,16 @@ PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets = null;
PFN_vkDestroyDevice vkDestroyDevice = null;
PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool = null;
PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR = null;
PFN_vkQueueSubmit2 vkQueueSubmit2 = null;
PFN_vkDestroyImage vkDestroyImage = null;
PFN_vkCmdBlitImage vkCmdBlitImage = null;
PFN_vkDestroyImageView vkDestroyImageView = null;
PFN_vkDestroyCommandPool vkDestroyCommandPool = null;
PFN_vkDestroySemaphore vkDestroySemaphore = null;
PFN_vkDestroyFence vkDestroyFence = null;
PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout = null;
PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier = null;
PFN_vkCmdPipelineBarrier2 vkCmdPipelineBarrier2 = null;
PFN_vkDestroyPipeline vkDestroyPipeline = null;
PFN_vkWaitForFences vkWaitForFences = null;
PFN_vkBeginCommandBuffer vkBeginCommandBuffer = null;
@ -163,6 +166,7 @@ LoadDeviceFunctions(Vulkan* vk)
vkDestroyRenderPass = cast(PFN_vkDestroyRenderPass)vkGetDeviceProcAddr(vk.device, "vkDestroyRenderPass");
vkCreateImage = cast(PFN_vkCreateImage)vkGetDeviceProcAddr(vk.device, "vkCreateImage");
vkCreateImageView = cast(PFN_vkCreateImageView)vkGetDeviceProcAddr(vk.device, "vkCreateImageView");
vkQueueSubmit2 = cast(PFN_vkQueueSubmit2KHR)vkGetDeviceProcAddr(vk.device, "vkQueueSubmit2KHR");
vkCreateBufferView = cast(PFN_vkCreateBufferView)vkGetDeviceProcAddr(vk.device, "vkCreateBufferView");
vkGetSwapchainImagesKHR = cast(PFN_vkGetSwapchainImagesKHR)vkGetDeviceProcAddr(vk.device, "vkGetSwapchainImagesKHR");
vkGetDeviceQueue = cast(PFN_vkGetDeviceQueue)vkGetDeviceProcAddr(vk.device, "vkGetDeviceQueue");
@ -170,6 +174,7 @@ LoadDeviceFunctions(Vulkan* vk)
vkAllocateCommandBuffers = cast(PFN_vkAllocateCommandBuffers)vkGetDeviceProcAddr(vk.device, "vkAllocateCommandBuffers");
vkCreateCommandPool = cast(PFN_vkCreateCommandPool)vkGetDeviceProcAddr(vk.device, "vkCreateCommandPool");
vkCmdPipelineBarrier = cast(PFN_vkCmdPipelineBarrier)vkGetDeviceProcAddr(vk.device, "vkCmdPipelineBarrier");
vkCmdPipelineBarrier2 = cast(PFN_vkCmdPipelineBarrier2KHR)vkGetDeviceProcAddr(vk.device, "vkCmdPipelineBarrier2KHR");
vkCreateFence = cast(PFN_vkCreateFence)vkGetDeviceProcAddr(vk.device, "vkCreateFence");
vkCreateDescriptorPool = cast(PFN_vkCreateDescriptorPool)vkGetDeviceProcAddr(vk.device, "vkCreateDescriptorPool");
vkCreateDescriptorSetLayout = cast(PFN_vkCreateDescriptorSetLayout)vkGetDeviceProcAddr(vk.device, "vkCreateDescriptorSetLayout");
@ -203,6 +208,7 @@ LoadDeviceFunctions(Vulkan* vk)
vkCmdBindIndexBuffer = cast(PFN_vkCmdBindIndexBuffer)vkGetDeviceProcAddr(vk.device, "vkCmdBindIndexBuffer");
vkCmdBindVertexBuffers = cast(PFN_vkCmdBindVertexBuffers)vkGetDeviceProcAddr(vk.device, "vkCmdBindVertexBuffers");
vkCmdDrawIndexed = cast(PFN_vkCmdDrawIndexed)vkGetDeviceProcAddr(vk.device, "vkCmdDrawIndexed");
vkCmdBlitImage = cast(PFN_vkCmdBlitImage)vkGetDeviceProcAddr(vk.device, "vkCmdBlitImage");
vkCmdCopyBufferToImage = cast(PFN_vkCmdCopyBufferToImage)vkGetDeviceProcAddr(vk.device, "vkCmdCopyBufferToImage");
vkCmdCopyBuffer = cast(PFN_vkCmdCopyBuffer)vkGetDeviceProcAddr(vk.device, "vkCmdCopyBuffer");
vkResetFences = cast(PFN_vkResetFences)vkGetDeviceProcAddr(vk.device, "vkResetFences");