comment command buffers + swapchain stuff. going to follow vulkan-tutorial instead

This commit is contained in:
David Allemang
2024-04-01 21:12:34 -04:00
parent 1b3302cc99
commit d6baf2ef09
3 changed files with 335 additions and 397 deletions

View File

@@ -1,59 +0,0 @@
const std = @import("std");
/// Slices must be sorted. Checks if `a` includes all elements of `b`.
pub fn includes(comptime T: type, a: []const T, b: []const T) bool {
var ia: usize = 0;
var ib: usize = 0;
while (ib != b.len) {
if (ia == a.len) return false;
if (b[ib] < a[ia]) return false;
if (!(a[ia] < b[ib])) ib += 1;
ia += 1;
}
return true;
}
test includes {
try std.testing.expect(includes(
usize,
&.{},
&.{},
));
try std.testing.expect(includes(
usize,
&.{ 1, 2, 3, 4, 5 },
&.{},
));
try std.testing.expect(includes(
usize,
&.{ 1, 2, 3, 4, 5 },
&.{ 1, 2, 3, 4, 5 },
));
try std.testing.expect(!includes(
usize,
&.{},
&.{ 1, 2, 3, 4, 5 },
));
try std.testing.expect(includes(
usize,
&.{ 1, 2, 2, 4 },
&.{ 2, 2 },
));
try std.testing.expect(includes(
usize,
&.{ 1, 2, 2, 4 },
&.{ 1, 2, 2, 4 },
));
try std.testing.expect(!includes(
usize,
&.{ 1, 2, 2, 4 },
&.{ 2, 2, 2 },
));
try std.testing.expect(!includes(
usize,
&.{ 1, 2, 2, 4 },
&.{ 2, 2, 3 },
));
}

View File

@@ -2,8 +2,6 @@ const std = @import("std");
const vk = @import("vk"); const vk = @import("vk");
const c = @import("c.zig"); const c = @import("c.zig");
const shaders = @import("shaders"); const shaders = @import("shaders");
const Swapchain = @import("swapchain.zig").Swapchain;
const Context = @import("swapchain.zig").Context;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const gfx = @import("gfx.zig"); const gfx = @import("gfx.zig");
@@ -298,80 +296,82 @@ pub fn main() !void {
try create_device(ally, instance, surface, vki); try create_device(ally, instance, surface, vki);
defer vkd.destroyDevice(dev, null); defer vkd.destroyDevice(dev, null);
const queue = vkd.getDeviceQueue(dev, family, 0);
const preferred_format: vk.SurfaceFormatKHR = .{ const preferred_format: vk.SurfaceFormatKHR = .{
.format = .b8g8r8a8_srgb, .format = .b8g8r8a8_srgb,
.color_space = .srgb_nonlinear_khr, .color_space = .srgb_nonlinear_khr,
}; };
const format = try find_surface_format(pdev, surface, preferred_format, vki); const format = try find_surface_format(pdev, surface, preferred_format, vki);
const queue = vkd.getDeviceQueue(dev, family, 0); _ = &extent;
const gc: Context = .{ // const gc: Context = .{
.vki = vki, // .vki = vki,
.vkd = vkd, // .vkd = vkd,
.pdev = pdev, // .pdev = pdev,
.dev = dev, // .dev = dev,
.surface = surface, // .surface = surface,
.queue = queue, // .queue = queue,
.family = family, // .family = family,
}; // };
//
// var swapchain = try Swapchain.init(&gc, ally, extent, format);
// defer swapchain.deinit();
var swapchain = try Swapchain.init(&gc, ally, extent, format); const pipeline_layout = try vkd.createPipelineLayout(dev, &.{
defer swapchain.deinit();
const pipeline_layout = try gc.vkd.createPipelineLayout(gc.dev, &.{
.flags = .{}, .flags = .{},
.set_layout_count = 0, .set_layout_count = 0,
.p_set_layouts = undefined, .p_set_layouts = undefined,
.push_constant_range_count = 0, .push_constant_range_count = 0,
.p_push_constant_ranges = undefined, .p_push_constant_ranges = undefined,
}, null); }, null);
defer gc.vkd.destroyPipelineLayout(gc.dev, pipeline_layout, null); defer vkd.destroyPipelineLayout(dev, pipeline_layout, null);
const pipeline = try createPipeline(&gc, pipeline_layout, format); const pipeline = try createPipeline(dev, pipeline_layout, format, vkd);
defer gc.vkd.destroyPipeline(gc.dev, pipeline, null); defer vkd.destroyPipeline(dev, pipeline, null);
const pool = try gc.vkd.createCommandPool(gc.dev, &.{ const pool = try vkd.createCommandPool(dev, &.{
.queue_family_index = family, .queue_family_index = family,
}, null); }, null);
defer gc.vkd.destroyCommandPool(gc.dev, pool, null); defer vkd.destroyCommandPool(dev, pool, null);
const vertex_buffer = try gc.vkd.createBuffer(gc.dev, &.{ const vertex_buffer = try vkd.createBuffer(dev, &.{
.size = @sizeOf(@TypeOf(vertices)), .size = @sizeOf(@TypeOf(vertices)),
.usage = .{ .transfer_dst_bit = true, .vertex_buffer_bit = true }, .usage = .{ .transfer_dst_bit = true, .vertex_buffer_bit = true },
.sharing_mode = .exclusive, .sharing_mode = .exclusive,
}, null); }, null);
defer gc.vkd.destroyBuffer(gc.dev, vertex_buffer, null); defer vkd.destroyBuffer(dev, vertex_buffer, null);
const vertex_mem_reqs = gc.vkd.getBufferMemoryRequirements(gc.dev, vertex_buffer); const vertex_mem_reqs = vkd.getBufferMemoryRequirements(dev, vertex_buffer);
const vertex_memory = try gc.allocate(vertex_mem_reqs, .{ .device_local_bit = true }); const vertex_memory = try allocate(pdev, vki, dev, vkd, vertex_mem_reqs, .{ .device_local_bit = true });
defer gc.vkd.freeMemory(gc.dev, vertex_memory, null); defer vkd.freeMemory(dev, vertex_memory, null);
try gc.vkd.bindBufferMemory(gc.dev, vertex_buffer, vertex_memory, 0); try vkd.bindBufferMemory(dev, vertex_buffer, vertex_memory, 0);
try uploadData(Vertex, &gc, pool, vertex_buffer, &vertices); try uploadData(Vertex, pdev, vki, dev, vkd, queue, pool, vertex_buffer, &vertices);
const index_buffer = try gc.vkd.createBuffer(gc.dev, &.{ const index_buffer = try vkd.createBuffer(dev, &.{
.size = @sizeOf(@TypeOf(indices)), .size = @sizeOf(@TypeOf(indices)),
.usage = .{ .transfer_dst_bit = true, .index_buffer_bit = true }, .usage = .{ .transfer_dst_bit = true, .index_buffer_bit = true },
.sharing_mode = .exclusive, .sharing_mode = .exclusive,
}, null); }, null);
defer gc.vkd.destroyBuffer(gc.dev, index_buffer, null); defer vkd.destroyBuffer(dev, index_buffer, null);
const index_mem_reqs = gc.vkd.getBufferMemoryRequirements(gc.dev, index_buffer); const index_mem_reqs = vkd.getBufferMemoryRequirements(dev, index_buffer);
const index_memory = try gc.allocate(index_mem_reqs, .{ .device_local_bit = true }); const index_memory = try allocate(pdev, vki, dev, vkd, index_mem_reqs, .{ .device_local_bit = true });
defer gc.vkd.freeMemory(gc.dev, index_memory, null); defer vkd.freeMemory(dev, index_memory, null);
try gc.vkd.bindBufferMemory(gc.dev, index_buffer, index_memory, 0); try vkd.bindBufferMemory(dev, index_buffer, index_memory, 0);
try uploadData(Index, &gc, pool, index_buffer, &indices); try uploadData(Index, pdev, vki, dev, vkd, queue, pool, index_buffer, &indices);
var cmdbufs = try createCommandBuffers( // var cmdbufs = try createCommandBuffers(
&gc, // &gc,
pool, // pool,
ally, // ally,
vertex_buffer, // vertex_buffer,
index_buffer, // index_buffer,
pipeline, // pipeline,
swapchain, // swapchain,
); // );
defer destroyCommandBuffers(&gc, pool, ally, cmdbufs); // defer destroyCommandBuffers(&gc, pool, ally, cmdbufs);
while (c.glfwWindowShouldClose(window) == c.GLFW_FALSE) { while (c.glfwWindowShouldClose(window) == c.GLFW_FALSE) {
var w: c_int = undefined; var w: c_int = undefined;
@@ -384,80 +384,98 @@ pub fn main() !void {
continue; continue;
} }
const cmdbuf = cmdbufs[swapchain.image_index]; // const cmdbuf = cmdbufs[swapchain.image_index];
const state = swapchain.present(cmdbuf) catch |err| switch (err) { // const state = swapchain.present(cmdbuf) catch |err| switch (err) {
error.OutOfDateKHR => Swapchain.PresentState.suboptimal, // error.OutOfDateKHR => Swapchain.PresentState.suboptimal,
else => |narrow| return narrow, // else => |narrow| return narrow,
}; // };
if (state == .suboptimal or extent.width != @as(u32, @intCast(w)) or extent.height != @as(u32, @intCast(h))) { // if (state == .suboptimal or extent.width != @as(u32, @intCast(w)) or extent.height != @as(u32, @intCast(h))) {
extent.width = @intCast(w); // extent.width = @intCast(w);
extent.height = @intCast(h); // extent.height = @intCast(h);
try swapchain.recreate(extent, format); // try swapchain.recreate(extent, format);
//
destroyCommandBuffers(&gc, pool, ally, cmdbufs); // destroyCommandBuffers(&gc, pool, ally, cmdbufs);
//
cmdbufs = try createCommandBuffers( // cmdbufs = try createCommandBuffers(
&gc, // &gc,
pool, // pool,
ally, // ally,
vertex_buffer, // vertex_buffer,
index_buffer, // index_buffer,
pipeline, // pipeline,
swapchain, // swapchain,
); // );
} // }
c.glfwPollEvents(); c.glfwPollEvents();
} }
try swapchain.waitForAllFences(); // try swapchain.waitForAllFences();
try gc.vkd.deviceWaitIdle(gc.dev); try vkd.deviceWaitIdle(dev);
} }
fn uploadData(comptime T: type, gc: *const Context, pool: vk.CommandPool, buffer: vk.Buffer, source: []const T) !void { fn uploadData(
comptime T: type,
pdev: vk.PhysicalDevice,
vki: gfx.InstanceDispatch,
dev: vk.Device,
vkd: gfx.DeviceDispatch,
queue: vk.Queue,
pool: vk.CommandPool,
buffer: vk.Buffer,
source: []const T,
) !void {
// if (@typeInfo(T) == .Struct and @typeInfo(T).Struct.layout == .auto) @compileError("Requires defined T layout"); // if (@typeInfo(T) == .Struct and @typeInfo(T).Struct.layout == .auto) @compileError("Requires defined T layout");
const size = @sizeOf(T) * source.len; const size = @sizeOf(T) * source.len;
const staging_buffer = try gc.vkd.createBuffer(gc.dev, &.{ const staging_buffer = try vkd.createBuffer(dev, &.{
.size = size, .size = size,
.usage = .{ .transfer_src_bit = true }, .usage = .{ .transfer_src_bit = true },
.sharing_mode = .exclusive, .sharing_mode = .exclusive,
}, null); }, null);
defer gc.vkd.destroyBuffer(gc.dev, staging_buffer, null); defer vkd.destroyBuffer(dev, staging_buffer, null);
const mem_reqs = gc.vkd.getBufferMemoryRequirements(gc.dev, staging_buffer); const mem_reqs = vkd.getBufferMemoryRequirements(dev, staging_buffer);
const staging_memory = try gc.allocate(mem_reqs, .{ const staging_memory = try allocate(pdev, vki, dev, vkd, mem_reqs, .{
.host_visible_bit = true, .host_visible_bit = true,
.host_coherent_bit = true, .host_coherent_bit = true,
}); });
defer gc.vkd.freeMemory(gc.dev, staging_memory, null); defer vkd.freeMemory(dev, staging_memory, null);
try gc.vkd.bindBufferMemory(gc.dev, staging_buffer, staging_memory, 0); try vkd.bindBufferMemory(dev, staging_buffer, staging_memory, 0);
{ {
const data = try gc.vkd.mapMemory(gc.dev, staging_memory, 0, vk.WHOLE_SIZE, .{}); const data = try vkd.mapMemory(dev, staging_memory, 0, vk.WHOLE_SIZE, .{});
defer gc.vkd.unmapMemory(gc.dev, staging_memory); defer vkd.unmapMemory(dev, staging_memory);
const dest: [*]T = @ptrCast(@alignCast(data)); const dest: [*]T = @ptrCast(@alignCast(data));
@memcpy(dest, source); @memcpy(dest, source);
} }
try copyBuffer(gc, pool, buffer, staging_buffer, size); try copyBuffer(dev, queue, pool, buffer, staging_buffer, size, vkd);
} }
fn copyBuffer(gc: *const Context, pool: vk.CommandPool, dst: vk.Buffer, src: vk.Buffer, size: vk.DeviceSize) !void { fn copyBuffer(
dev: vk.Device,
queue: vk.Queue,
pool: vk.CommandPool,
dst: vk.Buffer,
src: vk.Buffer,
size: vk.DeviceSize,
vkd: gfx.DeviceDispatch,
) !void {
var cmdbuf: vk.CommandBuffer = undefined; var cmdbuf: vk.CommandBuffer = undefined;
try gc.vkd.allocateCommandBuffers(gc.dev, &.{ try vkd.allocateCommandBuffers(dev, &.{
.command_pool = pool, .command_pool = pool,
.level = .primary, .level = .primary,
.command_buffer_count = 1, .command_buffer_count = 1,
}, @ptrCast(&cmdbuf)); }, @ptrCast(&cmdbuf));
defer gc.vkd.freeCommandBuffers(gc.dev, pool, 1, @ptrCast(&cmdbuf)); defer vkd.freeCommandBuffers(dev, pool, 1, @ptrCast(&cmdbuf));
try gc.vkd.beginCommandBuffer(cmdbuf, &.{ try vkd.beginCommandBuffer(cmdbuf, &.{
.flags = .{ .one_time_submit_bit = true }, .flags = .{ .one_time_submit_bit = true },
}); });
@@ -466,9 +484,9 @@ fn copyBuffer(gc: *const Context, pool: vk.CommandPool, dst: vk.Buffer, src: vk.
.dst_offset = 0, .dst_offset = 0,
.size = size, .size = size,
}; };
gc.vkd.cmdCopyBuffer(cmdbuf, src, dst, 1, @ptrCast(&region)); vkd.cmdCopyBuffer(cmdbuf, src, dst, 1, @ptrCast(&region));
try gc.vkd.endCommandBuffer(cmdbuf); try vkd.endCommandBuffer(cmdbuf);
const si = vk.SubmitInfo{ const si = vk.SubmitInfo{
.command_buffer_count = 1, .command_buffer_count = 1,
@@ -480,165 +498,162 @@ fn copyBuffer(gc: *const Context, pool: vk.CommandPool, dst: vk.Buffer, src: vk.
// see https://stackoverflow.com/a/62183243 // see https://stackoverflow.com/a/62183243
// //
// this may be a misunderstanding on how submission works... // this may be a misunderstanding on how submission works...
try gc.vkd.queueSubmit(gc.queue, 1, @ptrCast(&si), .null_handle); try vkd.queueSubmit(queue, 1, @ptrCast(&si), .null_handle);
try gc.vkd.queueWaitIdle(gc.queue); try vkd.queueWaitIdle(queue);
} }
fn createCommandBuffers( // fn createCommandBuffers(
gc: *const Context, // pool: vk.CommandPool,
pool: vk.CommandPool, // allocator: Allocator,
allocator: Allocator, // vertex_buffer: vk.Buffer,
vertex_buffer: vk.Buffer, // index_buffer: vk.Buffer,
index_buffer: vk.Buffer, // pipeline: vk.Pipeline,
pipeline: vk.Pipeline, // extent: vk.Extent2D,
swapchain: Swapchain, // ) ![]vk.CommandBuffer {
) ![]vk.CommandBuffer { // const cmdbufs = try allocator.alloc(vk.CommandBuffer, swapchain.swap_images.len);
const extent = swapchain.extent; // errdefer allocator.free(cmdbufs);
//
// try vkd.allocateCommandBuffers(dev, &.{
// .command_pool = pool,
// .level = .primary,
// .command_buffer_count = @as(u32, @truncate(cmdbufs.len)),
// }, cmdbufs.ptr);
// errdefer vkd.freeCommandBuffers(dev, pool, @truncate(cmdbufs.len), cmdbufs.ptr);
//
// const clear = vk.ClearValue{
// .color = .{ .float_32 = .{ 0, 0, 0, 1 } },
// };
//
// const viewport = vk.Viewport{
// .x = 0,
// .y = 0,
// .width = @as(f32, @floatFromInt(extent.width)),
// .height = @as(f32, @floatFromInt(extent.height)),
// .min_depth = 0,
// .max_depth = 1,
// };
//
// const scissor = vk.Rect2D{
// .offset = .{ .x = 0, .y = 0 },
// .extent = extent,
// };
//
// for (cmdbufs, swapchain.swap_images) |cmdbuf, image| {
// try vkd.beginCommandBuffer(cmdbuf, &.{});
//
// vkd.cmdPipelineBarrier(
// cmdbuf,
// .{ .top_of_pipe_bit = true },
// .{ .color_attachment_output_bit = true },
// .{},
// 0,
// null,
// 0,
// null,
// 1,
// @ptrCast(&vk.ImageMemoryBarrier{
// .src_access_mask = .{},
// .dst_access_mask = .{ .color_attachment_write_bit = true },
// .old_layout = .undefined,
// .new_layout = .color_attachment_optimal,
// .src_queue_family_index = 0,
// .dst_queue_family_index = 0,
// .image = image.image,
// .subresource_range = .{
// .aspect_mask = .{ .color_bit = true },
// .base_mip_level = 0,
// .level_count = 1,
// .base_array_layer = 0,
// .layer_count = 1,
// },
// }),
// );
//
// vkd.cmdSetViewport(cmdbuf, 0, 1, @ptrCast(&viewport));
// vkd.cmdSetScissor(cmdbuf, 0, 1, @ptrCast(&scissor));
//
// const color_attachments = [_]vk.RenderingAttachmentInfoKHR{
// .{
// .image_view = image.view,
// .image_layout = .color_attachment_optimal,
// .resolve_mode = .{},
// .resolve_image_view = .null_handle,
// .resolve_image_layout = .undefined,
// .load_op = .clear,
// .store_op = .store,
// .clear_value = clear,
// },
// };
//
// const render_info = vk.RenderingInfoKHR{
// .render_area = scissor, // since we always do full-frame changes
// .layer_count = 1,
// .view_mask = 0,
// .color_attachment_count = color_attachments.len,
// .p_color_attachments = &color_attachments,
// };
//
// vkd.cmdBeginRenderingKHR(cmdbuf, &render_info);
//
// vkd.cmdBindPipeline(cmdbuf, .graphics, pipeline);
// const offset = [_]vk.DeviceSize{0};
// vkd.cmdBindVertexBuffers(cmdbuf, 0, 1, @ptrCast(&vertex_buffer), &offset);
// vkd.cmdBindIndexBuffer(cmdbuf, index_buffer, 0, .uint16);
// vkd.cmdDrawIndexed(cmdbuf, indices.len, 1, 0, 0, 0);
//
// vkd.cmdEndRenderingKHR(cmdbuf);
//
// vkd.cmdPipelineBarrier(
// cmdbuf,
// .{ .color_attachment_output_bit = true },
// .{ .bottom_of_pipe_bit = true },
// .{},
// 0,
// null,
// 0,
// null,
// 1,
// @ptrCast(&vk.ImageMemoryBarrier{
// .src_access_mask = .{ .color_attachment_write_bit = true },
// .dst_access_mask = .{},
// .old_layout = .color_attachment_optimal,
// .new_layout = .present_src_khr,
// .src_queue_family_index = 0,
// .dst_queue_family_index = 0,
// .image = image.image,
// .subresource_range = .{
// .aspect_mask = .{ .color_bit = true },
// .base_mip_level = 0,
// .level_count = 1,
// .base_array_layer = 0,
// .layer_count = 1,
// },
// }),
// );
//
// try vkd.endCommandBuffer(cmdbuf);
// }
//
// return cmdbufs;
// }
const cmdbufs = try allocator.alloc(vk.CommandBuffer, swapchain.swap_images.len); // fn destroyCommandBuffers(gc: *const Context, pool: vk.CommandPool, allocator: Allocator, cmdbufs: []vk.CommandBuffer) void {
errdefer allocator.free(cmdbufs); // vkd.freeCommandBuffers(dev, pool, @truncate(cmdbufs.len), cmdbufs.ptr);
// allocator.free(cmdbufs);
// }
try gc.vkd.allocateCommandBuffers(gc.dev, &.{ fn createPipeline(dev: vk.Device, layout: vk.PipelineLayout, format: vk.SurfaceFormatKHR, vkd: gfx.DeviceDispatch) !vk.Pipeline {
.command_pool = pool, const vert = try vkd.createShaderModule(dev, &.{
.level = .primary,
.command_buffer_count = @as(u32, @truncate(cmdbufs.len)),
}, cmdbufs.ptr);
errdefer gc.vkd.freeCommandBuffers(gc.dev, pool, @truncate(cmdbufs.len), cmdbufs.ptr);
const clear = vk.ClearValue{
.color = .{ .float_32 = .{ 0, 0, 0, 1 } },
};
const viewport = vk.Viewport{
.x = 0,
.y = 0,
.width = @as(f32, @floatFromInt(extent.width)),
.height = @as(f32, @floatFromInt(extent.height)),
.min_depth = 0,
.max_depth = 1,
};
const scissor = vk.Rect2D{
.offset = .{ .x = 0, .y = 0 },
.extent = extent,
};
for (cmdbufs, swapchain.swap_images) |cmdbuf, image| {
try gc.vkd.beginCommandBuffer(cmdbuf, &.{});
gc.vkd.cmdPipelineBarrier(
cmdbuf,
.{ .top_of_pipe_bit = true },
.{ .color_attachment_output_bit = true },
.{},
0,
null,
0,
null,
1,
@ptrCast(&vk.ImageMemoryBarrier{
.src_access_mask = .{},
.dst_access_mask = .{ .color_attachment_write_bit = true },
.old_layout = .undefined,
.new_layout = .color_attachment_optimal,
.src_queue_family_index = 0,
.dst_queue_family_index = 0,
.image = image.image,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_mip_level = 0,
.level_count = 1,
.base_array_layer = 0,
.layer_count = 1,
},
}),
);
gc.vkd.cmdSetViewport(cmdbuf, 0, 1, @ptrCast(&viewport));
gc.vkd.cmdSetScissor(cmdbuf, 0, 1, @ptrCast(&scissor));
const color_attachments = [_]vk.RenderingAttachmentInfoKHR{
.{
.image_view = image.view,
.image_layout = .color_attachment_optimal,
.resolve_mode = .{},
.resolve_image_view = .null_handle,
.resolve_image_layout = .undefined,
.load_op = .clear,
.store_op = .store,
.clear_value = clear,
},
};
const render_info = vk.RenderingInfoKHR{
.render_area = scissor, // since we always do full-frame changes
.layer_count = 1,
.view_mask = 0,
.color_attachment_count = color_attachments.len,
.p_color_attachments = &color_attachments,
};
gc.vkd.cmdBeginRenderingKHR(cmdbuf, &render_info);
gc.vkd.cmdBindPipeline(cmdbuf, .graphics, pipeline);
const offset = [_]vk.DeviceSize{0};
gc.vkd.cmdBindVertexBuffers(cmdbuf, 0, 1, @ptrCast(&vertex_buffer), &offset);
gc.vkd.cmdBindIndexBuffer(cmdbuf, index_buffer, 0, .uint16);
gc.vkd.cmdDrawIndexed(cmdbuf, indices.len, 1, 0, 0, 0);
gc.vkd.cmdEndRenderingKHR(cmdbuf);
gc.vkd.cmdPipelineBarrier(
cmdbuf,
.{ .color_attachment_output_bit = true },
.{ .bottom_of_pipe_bit = true },
.{},
0,
null,
0,
null,
1,
@ptrCast(&vk.ImageMemoryBarrier{
.src_access_mask = .{ .color_attachment_write_bit = true },
.dst_access_mask = .{},
.old_layout = .color_attachment_optimal,
.new_layout = .present_src_khr,
.src_queue_family_index = 0,
.dst_queue_family_index = 0,
.image = image.image,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_mip_level = 0,
.level_count = 1,
.base_array_layer = 0,
.layer_count = 1,
},
}),
);
try gc.vkd.endCommandBuffer(cmdbuf);
}
return cmdbufs;
}
fn destroyCommandBuffers(gc: *const Context, pool: vk.CommandPool, allocator: Allocator, cmdbufs: []vk.CommandBuffer) void {
gc.vkd.freeCommandBuffers(gc.dev, pool, @truncate(cmdbufs.len), cmdbufs.ptr);
allocator.free(cmdbufs);
}
fn createPipeline(gc: *const Context, layout: vk.PipelineLayout, format: vk.SurfaceFormatKHR) !vk.Pipeline {
const vert = try gc.vkd.createShaderModule(gc.dev, &.{
.code_size = shaders.triangle_vert.len, .code_size = shaders.triangle_vert.len,
.p_code = @as([*]const u32, @ptrCast(&shaders.triangle_vert)), .p_code = @as([*]const u32, @ptrCast(&shaders.triangle_vert)),
}, null); }, null);
defer gc.vkd.destroyShaderModule(gc.dev, vert, null); defer vkd.destroyShaderModule(dev, vert, null);
const frag = try gc.vkd.createShaderModule(gc.dev, &.{ const frag = try vkd.createShaderModule(dev, &.{
.code_size = shaders.triangle_frag.len, .code_size = shaders.triangle_frag.len,
.p_code = @as([*]const u32, @ptrCast(&shaders.triangle_frag)), .p_code = @as([*]const u32, @ptrCast(&shaders.triangle_frag)),
}, null); }, null);
defer gc.vkd.destroyShaderModule(gc.dev, frag, null); defer vkd.destroyShaderModule(dev, frag, null);
const pssci = [_]vk.PipelineShaderStageCreateInfo{ const pssci = [_]vk.PipelineShaderStageCreateInfo{
.{ .{
@@ -653,46 +668,6 @@ fn createPipeline(gc: *const Context, layout: vk.PipelineLayout, format: vk.Surf
}, },
}; };
const pvisci = vk.PipelineVertexInputStateCreateInfo{
.vertex_binding_description_count = 1,
.p_vertex_binding_descriptions = @ptrCast(&Vertex.binding_description),
.vertex_attribute_description_count = Vertex.attribute_description.len,
.p_vertex_attribute_descriptions = &Vertex.attribute_description,
};
const piasci = vk.PipelineInputAssemblyStateCreateInfo{
.topology = .triangle_list,
.primitive_restart_enable = vk.FALSE,
};
const pvsci = vk.PipelineViewportStateCreateInfo{
.viewport_count = 1,
.p_viewports = undefined, // set in createCommandBuffers with cmdSetViewport
.scissor_count = 1,
.p_scissors = undefined, // set in createCommandBuffers with cmdSetScissor
};
const prsci = vk.PipelineRasterizationStateCreateInfo{
.depth_clamp_enable = vk.FALSE,
.rasterizer_discard_enable = vk.FALSE,
.polygon_mode = .fill,
.cull_mode = .{ .back_bit = true },
.front_face = .counter_clockwise,
.depth_bias_enable = vk.FALSE,
.depth_bias_constant_factor = 0,
.depth_bias_clamp = 0,
.depth_bias_slope_factor = 0,
.line_width = 1,
};
const pmsci = vk.PipelineMultisampleStateCreateInfo{
.rasterization_samples = .{ .@"1_bit" = true },
.sample_shading_enable = vk.FALSE,
.min_sample_shading = 1,
.alpha_to_coverage_enable = vk.FALSE,
.alpha_to_one_enable = vk.FALSE,
};
const pcbas = vk.PipelineColorBlendAttachmentState{ const pcbas = vk.PipelineColorBlendAttachmentState{
.blend_enable = vk.FALSE, .blend_enable = vk.FALSE,
.src_color_blend_factor = .one, .src_color_blend_factor = .one,
@@ -704,58 +679,107 @@ fn createPipeline(gc: *const Context, layout: vk.PipelineLayout, format: vk.Surf
.color_write_mask = .{ .r_bit = true, .g_bit = true, .b_bit = true, .a_bit = true }, .color_write_mask = .{ .r_bit = true, .g_bit = true, .b_bit = true, .a_bit = true },
}; };
const pcbsci = vk.PipelineColorBlendStateCreateInfo{ const dynstate = [_]vk.DynamicState{ .viewport, .scissor };
const gpci = vk.GraphicsPipelineCreateInfo{
.flags = .{},
.stage_count = @intCast(pssci.len),
.p_stages = &pssci,
.p_vertex_input_state = &vk.PipelineVertexInputStateCreateInfo{
.vertex_binding_description_count = 1,
.p_vertex_binding_descriptions = @ptrCast(&Vertex.binding_description),
.vertex_attribute_description_count = Vertex.attribute_description.len,
.p_vertex_attribute_descriptions = &Vertex.attribute_description,
},
.p_input_assembly_state = &vk.PipelineInputAssemblyStateCreateInfo{
.topology = .triangle_list,
.primitive_restart_enable = vk.FALSE,
},
.p_tessellation_state = null,
.p_viewport_state = &vk.PipelineViewportStateCreateInfo{
.viewport_count = 1,
.p_viewports = undefined, // set in createCommandBuffers with cmdSetViewport
.scissor_count = 1,
.p_scissors = undefined, // set in createCommandBuffers with cmdSetScissor
},
.p_rasterization_state = &vk.PipelineRasterizationStateCreateInfo{
.depth_clamp_enable = vk.FALSE,
.rasterizer_discard_enable = vk.FALSE,
.polygon_mode = .fill,
.cull_mode = .{ .back_bit = true },
.front_face = .counter_clockwise,
.depth_bias_enable = vk.FALSE,
.depth_bias_constant_factor = 0,
.depth_bias_clamp = 0,
.depth_bias_slope_factor = 0,
.line_width = 1,
},
.p_multisample_state = &vk.PipelineMultisampleStateCreateInfo{
.rasterization_samples = .{ .@"1_bit" = true },
.sample_shading_enable = vk.FALSE,
.min_sample_shading = 1,
.alpha_to_coverage_enable = vk.FALSE,
.alpha_to_one_enable = vk.FALSE,
},
.p_depth_stencil_state = null,
.p_color_blend_state = &vk.PipelineColorBlendStateCreateInfo{
.logic_op_enable = vk.FALSE, .logic_op_enable = vk.FALSE,
.logic_op = .copy, .logic_op = .copy,
.attachment_count = 1, .attachment_count = 1,
.p_attachments = @ptrCast(&pcbas), .p_attachments = @ptrCast(&pcbas),
.blend_constants = [_]f32{ 0, 0, 0, 0 }, .blend_constants = [_]f32{ 0, 0, 0, 0 },
}; },
.p_dynamic_state = &vk.PipelineDynamicStateCreateInfo{
const dynstate = [_]vk.DynamicState{ .viewport, .scissor };
const pdsci = vk.PipelineDynamicStateCreateInfo{
.flags = .{}, .flags = .{},
.dynamic_state_count = dynstate.len, .dynamic_state_count = dynstate.len,
.p_dynamic_states = &dynstate, .p_dynamic_states = &dynstate,
}; },
const prci = vk.PipelineRenderingCreateInfoKHR{
.color_attachment_count = 1,
.p_color_attachment_formats = @ptrCast(&format),
.depth_attachment_format = .undefined,
.stencil_attachment_format = .undefined,
.view_mask = 0,
};
const gpci = vk.GraphicsPipelineCreateInfo{
.flags = .{},
.stage_count = 2,
.p_stages = &pssci,
.p_vertex_input_state = &pvisci,
.p_input_assembly_state = &piasci,
.p_tessellation_state = null,
.p_viewport_state = &pvsci,
.p_rasterization_state = &prsci,
.p_multisample_state = &pmsci,
.p_depth_stencil_state = null,
.p_color_blend_state = &pcbsci,
.p_dynamic_state = &pdsci,
.layout = layout, .layout = layout,
.render_pass = .null_handle, .render_pass = .null_handle,
.subpass = 0, .subpass = 0,
.base_pipeline_handle = .null_handle, .base_pipeline_handle = .null_handle,
.base_pipeline_index = -1, .base_pipeline_index = -1,
.p_next = &prci, .p_next = &vk.PipelineRenderingCreateInfoKHR{
.color_attachment_count = 1,
.p_color_attachment_formats = @ptrCast(&format),
.depth_attachment_format = .undefined,
.stencil_attachment_format = .undefined,
.view_mask = 0,
},
}; };
var pipeline: vk.Pipeline = undefined; var pipeline: vk.Pipeline = undefined;
_ = try gc.vkd.createGraphicsPipelines( _ = try vkd.createGraphicsPipelines(dev, .null_handle, 1, @ptrCast(&gpci), null, @ptrCast(&pipeline));
gc.dev,
.null_handle,
1,
@ptrCast(&gpci),
null,
@ptrCast(&pipeline),
);
return pipeline; return pipeline;
} }
pub fn findMemoryTypeIndex(
pdev: vk.PhysicalDevice,
memory_type_bits: u32,
flags: vk.MemoryPropertyFlags,
vki: gfx.InstanceDispatch,
) !u32 {
const mem_props = vki.getPhysicalDeviceMemoryProperties(pdev);
for (mem_props.memory_types[0..mem_props.memory_type_count], 0..) |mem_type, i| {
if (memory_type_bits & (@as(u32, 1) << @truncate(i)) != 0 and mem_type.property_flags.contains(flags)) {
return @truncate(i);
}
}
return error.NoSuitableMemoryType;
}
pub fn allocate(
pdev: vk.PhysicalDevice,
vki: gfx.InstanceDispatch,
dev: vk.Device,
vkd: gfx.DeviceDispatch,
requirements: vk.MemoryRequirements,
flags: vk.MemoryPropertyFlags,
) !vk.DeviceMemory {
return try vkd.allocateMemory(dev, &.{
.allocation_size = requirements.size,
.memory_type_index = try findMemoryTypeIndex(pdev, requirements.memory_type_bits, flags, vki),
}, null);
}

View File

@@ -14,33 +14,6 @@ pub const Context = struct {
queue: vk.Queue, queue: vk.Queue,
family: u32, family: u32,
pub fn findMemoryTypeIndex(
self: @This(),
memory_type_bits: u32,
flags: vk.MemoryPropertyFlags,
) !u32 {
const mem_props = self.vki.getPhysicalDeviceMemoryProperties(self.pdev);
for (mem_props.memory_types[0..mem_props.memory_type_count], 0..) |mem_type, i| {
if (memory_type_bits & (@as(u32, 1) << @truncate(i)) != 0 and mem_type.property_flags.contains(flags)) {
return @truncate(i);
}
}
return error.NoSuitableMemoryType;
}
pub fn allocate(
self: @This(),
requirements: vk.MemoryRequirements,
flags: vk.MemoryPropertyFlags,
) !vk.DeviceMemory {
return try self.vkd.allocateMemory(self.dev, &.{
.allocation_size = requirements.size,
.memory_type_index = try self.findMemoryTypeIndex(requirements.memory_type_bits, flags),
}, null);
}
}; };
pub const Swapchain = struct { pub const Swapchain = struct {