Add chess GUI and move generation

This commit is contained in:
2026-05-19 16:05:53 -08:00
parent b36f5b0b84
commit 4131c93f99
69 changed files with 80468 additions and 218 deletions
+101 -38
View File
@@ -15,6 +15,15 @@ pub const VertexBufferContext = struct {
ldc.vkd.freeMemory(ldc.device, self.memory, null);
}
};
pub const BufferContext = struct {
buffer: vk.Buffer,
memory: vk.DeviceMemory,
pub fn destroy(self: *const BufferContext, ldc: *const device.LogicalDeviceContext) void {
ldc.vkd.destroyBuffer(ldc.device, self.buffer, null);
ldc.vkd.freeMemory(ldc.device, self.memory, null);
}
};
pub fn initVertexBuffer(
vc: context.VulkanContext,
@@ -22,50 +31,24 @@ pub fn initVertexBuffer(
vertices: []const geometry.Vertex,
) !VertexBufferContext {
const buffer_size: vk.DeviceSize = @intCast(@sizeOf(geometry.Vertex) * vertices.len);
const buffer_create_info = vk.BufferCreateInfo{
.size = buffer_size,
.usage = .{
.vertex_buffer_bit = true,
},
.sharing_mode = .exclusive,
const usage: vk.BufferUsageFlags = .{
.vertex_buffer_bit = true,
};
const memory_properties: vk.MemoryPropertyFlags = .{
.host_visible_bit = true,
.host_coherent_bit = true,
};
const buffer = try ldc.vkd.createBuffer(ldc.device, &buffer_create_info, null);
errdefer ldc.vkd.destroyBuffer(ldc.device, buffer, null);
const memory_requirements = ldc.vkd.getBufferMemoryRequirements(
ldc.device,
buffer,
);
const memory_index = try findMemoryType(
vc,
ldc,
memory_requirements.memory_type_bits,
.{
.host_visible_bit = true,
.host_coherent_bit = true,
},
);
const alloc_info = vk.MemoryAllocateInfo{
.allocation_size = memory_requirements.size,
.memory_type_index = memory_index,
};
const memory = try ldc.vkd.allocateMemory(ldc.device, &alloc_info, null);
errdefer ldc.vkd.freeMemory(ldc.device, memory, null);
try ldc.vkd.bindBufferMemory(ldc.device, buffer, memory, 0);
const buffer_context = try createBuffer(vc, ldc, buffer_size, usage, memory_properties);
const mapped = try ldc.vkd.mapMemory(
ldc.device,
memory,
buffer_context.memory,
0,
buffer_size,
.{},
);
defer ldc.vkd.unmapMemory(ldc.device, memory);
defer ldc.vkd.unmapMemory(ldc.device, buffer_context.memory);
const dst: [*]u8 = @ptrCast(mapped);
const dst_slice = dst[0..buffer_size];
@@ -74,13 +57,13 @@ pub fn initVertexBuffer(
std.mem.copyForwards(u8, dst_slice, src_bytes);
return .{
.buffer = buffer,
.memory = memory,
.buffer = buffer_context.buffer,
.memory = buffer_context.memory,
.vertex_count = @intCast(vertices.len),
};
}
fn findMemoryType(
pub fn findMemoryType(
vc: context.VulkanContext,
ldc: device.LogicalDeviceContext,
type_filter: u32,
@@ -107,3 +90,83 @@ fn findMemoryType(
return error.NoSuitableMemoryType;
}
pub fn createBuffer(
vc: context.VulkanContext,
ldc: device.LogicalDeviceContext,
size: vk.DeviceSize,
usage: vk.BufferUsageFlags,
properties: vk.MemoryPropertyFlags,
) !BufferContext {
const buffer_create_info = vk.BufferCreateInfo{
.size = size,
.usage = usage,
.sharing_mode = .exclusive,
};
const buffer = try ldc.vkd.createBuffer(ldc.device, &buffer_create_info, null);
errdefer ldc.vkd.destroyBuffer(ldc.device, buffer, null);
const memory_requirements = ldc.vkd.getBufferMemoryRequirements(
ldc.device,
buffer,
);
const memory_index = try findMemoryType(
vc,
ldc,
memory_requirements.memory_type_bits,
properties,
);
const alloc_info = vk.MemoryAllocateInfo{
.allocation_size = memory_requirements.size,
.memory_type_index = memory_index,
};
const memory = try ldc.vkd.allocateMemory(ldc.device, &alloc_info, null);
errdefer ldc.vkd.freeMemory(ldc.device, memory, null);
try ldc.vkd.bindBufferMemory(ldc.device, buffer, memory, 0);
return .{
.buffer = buffer,
.memory = memory,
};
}
pub fn initStagingBuffer(
vc: context.VulkanContext,
ldc: device.LogicalDeviceContext,
bytes: []const u8,
) !BufferContext {
const buffer_size: vk.DeviceSize = @intCast(bytes.len);
const buffer_context = try createBuffer(
vc,
ldc,
buffer_size,
.{
.transfer_src_bit = true,
},
.{
.host_visible_bit = true,
.host_coherent_bit = true,
},
);
const mapped = try ldc.vkd.mapMemory(
ldc.device,
buffer_context.memory,
0,
buffer_size,
.{},
);
defer ldc.vkd.unmapMemory(ldc.device, buffer_context.memory);
const dst: [*]u8 = @ptrCast(mapped);
const dst_slice = dst[0..buffer_size];
std.mem.copyForwards(u8, dst_slice, bytes);
return buffer_context;
}
+124 -31
View File
@@ -1,4 +1,5 @@
const std = @import("std");
const log = std.log.scoped(.graphics);
const vk = @import("vulkan");
const device = @import("device.zig");
@@ -7,6 +8,8 @@ const render_pass = @import("render_pass.zig");
const swapchain = @import("swapchain.zig");
const pipeline = @import("pipeline.zig");
const buffer = @import("buffer.zig");
const descriptors = @import("descriptors.zig");
const piece_render = @import("../piece_render.zig");
pub const CommandContext = struct {
command_pool: vk.CommandPool,
@@ -19,13 +22,8 @@ pub const CommandContext = struct {
}
};
pub fn initCommandBuffers(
pub fn initCommandPoolOnly(
ldc: device.LogicalDeviceContext,
render_pass_context: render_pass.RenderPassContext,
framebuffer_context: framebuffers.FramebufferContext,
pipeline_context: pipeline.PipelineContext,
swapchain_context: swapchain.SwapchainContext,
vertex_buffer_context: buffer.VertexBufferContext,
allocator: std.mem.Allocator,
) !CommandContext {
const command_pool_create_info = vk.CommandPoolCreateInfo{
@@ -41,32 +39,56 @@ pub fn initCommandBuffers(
null,
);
errdefer ldc.vkd.destroyCommandPool(ldc.device, command_pool, null);
std.debug.print("created command pool\n", .{});
const command_buffers = try allocator.alloc(vk.CommandBuffer, framebuffer_context.framebuffers.len);
const command_buffers = try allocator.alloc(vk.CommandBuffer, 0);
errdefer allocator.free(command_buffers);
const command_buffer_allocate_info = vk.CommandBufferAllocateInfo{
return .{
.command_pool = command_pool,
.command_buffers = command_buffers,
.allocator = allocator,
};
}
pub fn initCommandBuffers(
ldc: device.LogicalDeviceContext,
render_pass_context: render_pass.RenderPassContext,
framebuffer_context: framebuffers.FramebufferContext,
board_pipeline_context: pipeline.PipelineContext,
piece_pipeline_context: pipeline.PipelineContext,
descriptor_contexts: [piece_render.PieceGroupCount]?descriptors.DescriptorContext,
swapchain_context: swapchain.SwapchainContext,
board_vertex_buffer_context: buffer.VertexBufferContext,
piece_vertex_buffers: [piece_render.PieceGroupCount]?buffer.VertexBufferContext,
allocator: std.mem.Allocator,
) !CommandContext {
var command_context = try initCommandPoolOnly(ldc, allocator);
errdefer command_context.destroy(&ldc);
log.debug("created command pool", .{});
allocator.free(command_context.command_buffers);
command_context.command_buffers = try allocator.alloc(vk.CommandBuffer, framebuffer_context.framebuffers.len);
errdefer allocator.free(command_context.command_buffers);
const command_buffer_allocate_info = vk.CommandBufferAllocateInfo{
.command_pool = command_context.command_pool,
.level = .primary,
.command_buffer_count = @intCast(command_buffers.len),
.command_buffer_count = @intCast(command_context.command_buffers.len),
};
try ldc.vkd.allocateCommandBuffers(
ldc.device,
&command_buffer_allocate_info,
command_buffers.ptr,
command_context.command_buffers.ptr,
);
std.debug.print("allocated command buffers: {}\n", .{command_buffers.len});
log.debug("allocated command buffers: {}", .{command_context.command_buffers.len});
for (command_buffers, 0..) |command_buffer, i| {
for (command_context.command_buffers, 0..) |command_buffer, i| {
const begin_info = vk.CommandBufferBeginInfo{};
try ldc.vkd.beginCommandBuffer(command_buffer, &begin_info);
// This is the only "drawing" currently happening: begin a render pass
// and clear the swapchain image. The embedded shaders are not used yet.
const clear_color = vk.ClearValue{
.color = .{
.float_32 = .{ 0.02, 0.02, 0.08, 1.0 },
@@ -93,36 +115,107 @@ pub fn initCommandBuffers(
ldc.vkd.cmdBindPipeline(
command_buffer,
.graphics,
pipeline_context.graphics_pipeline,
board_pipeline_context.graphics_pipeline,
);
const vertex_buffers = [_]vk.Buffer{
vertex_buffer_context.buffer,
};
const offsets = [_]vk.DeviceSize{
0,
};
const board_vertex_buffers = [_]vk.Buffer{board_vertex_buffer_context.buffer};
const board_offsets = [_]vk.DeviceSize{0};
ldc.vkd.cmdBindVertexBuffers(
command_buffer,
0,
&vertex_buffers,
&offsets,
&board_vertex_buffers,
&board_offsets,
);
ldc.vkd.cmdDraw(command_buffer, vertex_buffer_context.vertex_count, 1, 0, 0);
ldc.vkd.cmdDraw(command_buffer, board_vertex_buffer_context.vertex_count, 1, 0, 0);
ldc.vkd.cmdBindPipeline(
command_buffer,
.graphics,
piece_pipeline_context.graphics_pipeline,
);
for (piece_vertex_buffers, descriptor_contexts) |maybe_piece_buffer, maybe_descriptor_context| {
const piece_buffer = maybe_piece_buffer orelse continue;
const piece_descriptor_context = maybe_descriptor_context orelse continue;
const descriptor_sets = [_]vk.DescriptorSet{piece_descriptor_context.descriptor_set};
ldc.vkd.cmdBindDescriptorSets(
command_buffer,
.graphics,
piece_pipeline_context.pipeline_layout,
0,
&descriptor_sets,
null,
);
const piece_buffers = [_]vk.Buffer{piece_buffer.buffer};
const piece_offsets = [_]vk.DeviceSize{0};
ldc.vkd.cmdBindVertexBuffers(
command_buffer,
0,
&piece_buffers,
&piece_offsets,
);
ldc.vkd.cmdDraw(command_buffer, piece_buffer.vertex_count, 1, 0, 0);
}
ldc.vkd.cmdEndRenderPass(command_buffer);
try ldc.vkd.endCommandBuffer(command_buffer);
}
std.debug.print("recorded command buffers\n", .{});
log.debug("recorded command buffers", .{});
return .{
.command_pool = command_pool,
.command_buffers = command_buffers,
.allocator = allocator,
return command_context;
}
pub fn beginSingleTimeCommands(
ldc: device.LogicalDeviceContext,
command_context: CommandContext,
) !vk.CommandBuffer {
const command_buffer_allocate_info = vk.CommandBufferAllocateInfo{
.command_pool = command_context.command_pool,
.level = .primary,
.command_buffer_count = 1,
};
var command_buffer: vk.CommandBuffer = undefined;
try ldc.vkd.allocateCommandBuffers(
ldc.device,
&command_buffer_allocate_info,
@ptrCast(&command_buffer),
);
const begin_info = vk.CommandBufferBeginInfo{
.flags = .{
.one_time_submit_bit = true,
},
};
try ldc.vkd.beginCommandBuffer(command_buffer, &begin_info);
return command_buffer;
}
pub fn endSingleTimeCommands(
ldc: device.LogicalDeviceContext,
command_context: CommandContext,
command_buffer: vk.CommandBuffer,
) !void {
try ldc.vkd.endCommandBuffer(command_buffer);
const command_buffers = [_]vk.CommandBuffer{command_buffer};
const submit_info = vk.SubmitInfo{
.command_buffer_count = command_buffers.len,
.p_command_buffers = &command_buffers,
};
try ldc.vkd.queueSubmit(ldc.graphics_queue, &[_]vk.SubmitInfo{submit_info}, .null_handle);
try ldc.vkd.queueWaitIdle(ldc.graphics_queue);
ldc.vkd.freeCommandBuffers(ldc.device, command_context.command_pool, &command_buffers);
}
+4 -3
View File
@@ -1,4 +1,5 @@
const std = @import("std");
const log = std.log.scoped(.graphics);
const glfw = @import("zglfw");
const vk = @import("vulkan");
@@ -16,9 +17,9 @@ pub fn initInstance(name: [:0]const u8) !VulkanContext {
const base = vk.BaseWrapper.load(glfw.getInstanceProcAddress);
const required_extensions = try glfw.getRequiredInstanceExtensions();
std.debug.print("Required instance extensions:\n", .{});
log.debug("Required instance extensions:", .{});
for (required_extensions) |extension| {
std.debug.print(" {s}\n", .{extension});
log.debug(" {s}", .{extension});
}
const app_info = vk.ApplicationInfo{
.p_application_name = name,
@@ -35,7 +36,7 @@ pub fn initInstance(name: [:0]const u8) !VulkanContext {
};
const instance = try base.createInstance(&instance_create_info, null);
std.debug.print("Created Vulkan Instance\n", .{});
log.debug("Created Vulkan Instance", .{});
const vki = vk.InstanceWrapper.load(instance, base.dispatch.vkGetInstanceProcAddr.?);
+91
View File
@@ -0,0 +1,91 @@
const vk = @import("vulkan");
const device = @import("device.zig");
const pipeline = @import("pipeline.zig");
const texture = @import("texture.zig");
pub const DescriptorContext = struct {
descriptor_pool: vk.DescriptorPool,
descriptor_set: vk.DescriptorSet,
pub fn destroy(self: *const DescriptorContext, ldc: *const device.LogicalDeviceContext) void {
ldc.vkd.destroyDescriptorPool(ldc.device, self.descriptor_pool, null);
}
};
pub fn initTextureDescriptor(
ldc: device.LogicalDeviceContext,
pipeline_context: pipeline.PipelineContext,
texture_context: texture.TextureContext,
) !DescriptorContext {
const pool_size = vk.DescriptorPoolSize{
.type = .combined_image_sampler,
.descriptor_count = 1,
};
const pool_sizes = [_]vk.DescriptorPoolSize{pool_size};
const pool_info = vk.DescriptorPoolCreateInfo{
.max_sets = 1,
.pool_size_count = pool_sizes.len,
.p_pool_sizes = &pool_sizes,
};
const descriptor_pool = try ldc.vkd.createDescriptorPool(
ldc.device,
&pool_info,
null,
);
errdefer ldc.vkd.destroyDescriptorPool(ldc.device, descriptor_pool, null);
const set_layouts = [_]vk.DescriptorSetLayout{
pipeline_context.descriptor_set_layout,
};
const alloc_info = vk.DescriptorSetAllocateInfo{
.descriptor_pool = descriptor_pool,
.descriptor_set_count = set_layouts.len,
.p_set_layouts = &set_layouts,
};
var descriptor_sets: [1]vk.DescriptorSet = undefined;
try ldc.vkd.allocateDescriptorSets(
ldc.device,
&alloc_info,
&descriptor_sets,
);
const descriptor_set = descriptor_sets[0];
const image_info = vk.DescriptorImageInfo{
.image_layout = .shader_read_only_optimal,
.image_view = texture_context.image_view,
.sampler = texture_context.sampler,
};
const image_infos = [_]vk.DescriptorImageInfo{image_info};
const descriptor_write = vk.WriteDescriptorSet{
.dst_set = descriptor_set,
.dst_binding = 0,
.dst_array_element = 0,
.descriptor_count = 1,
.descriptor_type = .combined_image_sampler,
.p_image_info = &image_infos,
.p_buffer_info = undefined,
.p_texel_buffer_view = undefined,
};
const descriptor_writes = [_]vk.WriteDescriptorSet{descriptor_write};
ldc.vkd.updateDescriptorSets(
ldc.device,
&descriptor_writes,
null,
);
return .{
.descriptor_pool = descriptor_pool,
.descriptor_set = descriptor_set,
};
}
+7 -6
View File
@@ -1,4 +1,5 @@
const std = @import("std");
const log = std.log.scoped(.graphics);
const vk = @import("vulkan");
const context = @import("context.zig");
@@ -41,11 +42,11 @@ pub fn initLogicalDevice(
const device = try vc.vki.createDevice(physical_device, &device_create_info, null);
errdefer vc.vki.destroyDevice(device, null);
std.debug.print("created logical device\n", .{});
log.debug("created logical device", .{});
const vkd = vk.DeviceWrapper.load(device, vc.vki.dispatch.vkGetDeviceProcAddr.?);
const graphics_queue = vkd.getDeviceQueue(device, graphics_queue_family_index, 0);
std.debug.print("retrieved graphics queue\n", .{});
log.debug("retrieved graphics queue", .{});
return .{
.physical_device = physical_device,
@@ -61,11 +62,11 @@ pub fn debugPhysicalGPUs(
physical_devices: []vk.PhysicalDevice,
surface: vk.SurfaceKHR,
) !void {
std.debug.print("physical devices: {}\n", .{physical_devices.len});
log.debug("physical devices: {}", .{physical_devices.len});
for (physical_devices, 0..) |physical_device, i| {
const props = vc.vki.getPhysicalDeviceProperties(physical_device);
std.debug.print("device {}: {s}\n", .{ i, std.mem.sliceTo(&props.device_name, 0) });
log.debug("device {}: {s}", .{ i, std.mem.sliceTo(&props.device_name, 0) });
const queue_families = try vc.vki.getPhysicalDeviceQueueFamilyPropertiesAlloc(
physical_device,
std.heap.page_allocator,
@@ -83,8 +84,8 @@ pub fn debugPhysicalGPUs(
surface,
);
std.debug.print(
" queue {}: count={}, graphics={}, compute={}, transfer={}, present={}\n",
log.debug(
" queue {}: count={}, graphics={}, compute={}, transfer={}, present={}",
.{
queue_index,
queue_family.queue_count,
+3 -2
View File
@@ -1,4 +1,5 @@
const std = @import("std");
const log = std.log.scoped(.graphics);
const vk = @import("vulkan");
const commands = @import("commands.zig");
@@ -33,7 +34,7 @@ pub fn drawFrame(
const image_index = image_result.image_index;
const should_recreate_after_present = image_result.result == .suboptimal_khr;
std.debug.print("Acquired swapchain image: {}\n", .{image_index});
log.debug("Acquired swapchain image: {}", .{image_index});
try ldc.vkd.resetFences(ldc.device, &wait_fences);
@@ -76,7 +77,7 @@ pub fn drawFrame(
error.OutOfDateKHR => return .Recreate,
else => return err,
};
std.debug.print("Presented one frame\n", .{});
log.debug("Presented one frame", .{});
if (should_recreate_after_present or present_result == .suboptimal_khr) {
return FrameResult.Recreate;
+2 -1
View File
@@ -1,4 +1,5 @@
const std = @import("std");
const log = std.log.scoped(.graphics);
const vk = @import("vulkan");
const device = @import("device.zig");
@@ -53,7 +54,7 @@ pub fn initFramebuffers(
created_framebuffer_count += 1;
}
std.debug.print("created framebuffers: {}\n", .{framebuffers.len});
log.debug("created framebuffers: {}", .{framebuffers.len});
return .{
.framebuffers = framebuffers,
+120 -23
View File
@@ -7,10 +7,14 @@ const geometry = @import("../geometry.zig");
pub const PipelineContext = struct {
graphics_pipeline: vk.Pipeline,
pipeline_layout: vk.PipelineLayout,
descriptor_set_layout: vk.DescriptorSetLayout = .null_handle,
pub fn destroy(self: *const PipelineContext, ldc: *const device.LogicalDeviceContext) void {
ldc.vkd.destroyPipeline(ldc.device, self.graphics_pipeline, null);
ldc.vkd.destroyPipelineLayout(ldc.device, self.pipeline_layout, null);
if (self.descriptor_set_layout != .null_handle) {
ldc.vkd.destroyDescriptorSetLayout(ldc.device, self.descriptor_set_layout, null);
}
}
};
@@ -31,8 +35,112 @@ pub fn createShaderModule(ldc: device.LogicalDeviceContext, allocator: std.mem.A
return try ldc.vkd.createShaderModule(ldc.device, &create_info, null);
}
pub fn initPipelineContext(ldc: device.LogicalDeviceContext, extent: vk.Extent2D, render_pass: vk.RenderPass, vert_spv: []const u8, frag_spv: []const u8, allocator: std.mem.Allocator) !PipelineContext {
const pipeline_layout_create_info = vk.PipelineLayoutCreateInfo{};
pub fn initBoardPipelineContext(ldc: device.LogicalDeviceContext, extent: vk.Extent2D, render_pass: vk.RenderPass, vert_spv: []const u8, frag_spv: []const u8, allocator: std.mem.Allocator) !PipelineContext {
const attribute_descriptions = [_]vk.VertexInputAttributeDescription{
.{
.location = 0,
.binding = 0,
.format = .r32g32_sfloat,
.offset = @offsetOf(geometry.Vertex, "position"),
},
.{
.location = 1,
.binding = 0,
.format = .r32g32b32a32_sfloat,
.offset = @offsetOf(geometry.Vertex, "color"),
},
};
return try initPipelineContext(
ldc,
extent,
render_pass,
vert_spv,
frag_spv,
allocator,
null,
&attribute_descriptions,
);
}
pub fn initPiecePipelineContext(ldc: device.LogicalDeviceContext, extent: vk.Extent2D, render_pass: vk.RenderPass, vert_spv: []const u8, frag_spv: []const u8, allocator: std.mem.Allocator) !PipelineContext {
const sampler_layout_binding = vk.DescriptorSetLayoutBinding{
.binding = 0,
.descriptor_type = .combined_image_sampler,
.descriptor_count = 1,
.stage_flags = .{
.fragment_bit = true,
},
.p_immutable_samplers = null,
};
const descriptor_set_layout_bindings = [_]vk.DescriptorSetLayoutBinding{
sampler_layout_binding,
};
const descriptor_set_layout_create_info = vk.DescriptorSetLayoutCreateInfo{
.binding_count = descriptor_set_layout_bindings.len,
.p_bindings = &descriptor_set_layout_bindings,
};
const descriptor_set_layout = try ldc.vkd.createDescriptorSetLayout(
ldc.device,
&descriptor_set_layout_create_info,
null,
);
errdefer ldc.vkd.destroyDescriptorSetLayout(ldc.device, descriptor_set_layout, null);
const descriptor_set_layouts = [_]vk.DescriptorSetLayout{
descriptor_set_layout,
};
const attribute_descriptions = [_]vk.VertexInputAttributeDescription{
.{
.location = 0,
.binding = 0,
.format = .r32g32_sfloat,
.offset = @offsetOf(geometry.Vertex, "position"),
},
.{
.location = 1,
.binding = 0,
.format = .r32g32b32a32_sfloat,
.offset = @offsetOf(geometry.Vertex, "color"),
},
.{
.location = 2,
.binding = 0,
.format = .r32g32_sfloat,
.offset = @offsetOf(geometry.Vertex, "uv"),
},
};
return try initPipelineContext(
ldc,
extent,
render_pass,
vert_spv,
frag_spv,
allocator,
&descriptor_set_layouts,
&attribute_descriptions,
);
}
fn initPipelineContext(
ldc: device.LogicalDeviceContext,
extent: vk.Extent2D,
render_pass: vk.RenderPass,
vert_spv: []const u8,
frag_spv: []const u8,
allocator: std.mem.Allocator,
descriptor_set_layouts: ?[]const vk.DescriptorSetLayout,
attribute_descriptions: []const vk.VertexInputAttributeDescription,
) !PipelineContext {
const pipeline_layout_create_info = vk.PipelineLayoutCreateInfo{
.set_layout_count = if (descriptor_set_layouts) |layouts| @intCast(layouts.len) else 0,
.p_set_layouts = if (descriptor_set_layouts) |layouts| layouts.ptr else null,
};
const pipeline_layout = try ldc.vkd.createPipelineLayout(
ldc.device,
@@ -70,18 +178,11 @@ pub fn initPipelineContext(ldc: device.LogicalDeviceContext, extent: vk.Extent2D
.input_rate = .vertex,
};
const attribute_description = vk.VertexInputAttributeDescription{
.location = 0,
.binding = 0,
.format = .r32g32_sfloat,
.offset = @offsetOf(geometry.Vertex, "position"),
};
const vertex_input_info = vk.PipelineVertexInputStateCreateInfo{
.vertex_binding_description_count = 1,
.p_vertex_binding_descriptions = @ptrCast(&binding_description),
.vertex_attribute_description_count = 1,
.p_vertex_attribute_descriptions = @ptrCast(&attribute_description),
.vertex_attribute_description_count = @intCast(attribute_descriptions.len),
.p_vertex_attribute_descriptions = attribute_descriptions.ptr,
};
const input_assembly = vk.PipelineInputAssemblyStateCreateInfo{
@@ -91,9 +192,9 @@ pub fn initPipelineContext(ldc: device.LogicalDeviceContext, extent: vk.Extent2D
const viewport = vk.Viewport{
.x = 0.0,
.y = 0.0,
.y = @floatFromInt(extent.height),
.width = @floatFromInt(extent.width),
.height = @floatFromInt(extent.height),
.height = -@as(f32, @floatFromInt(extent.height)),
.min_depth = 0.0,
.max_depth = 1.0,
};
@@ -115,9 +216,7 @@ pub fn initPipelineContext(ldc: device.LogicalDeviceContext, extent: vk.Extent2D
.rasterizer_discard_enable = .false,
.polygon_mode = .fill,
.line_width = 1.0,
.cull_mode = .{
.back_bit = true,
},
.cull_mode = .{},
.front_face = .clockwise,
.depth_bias_enable = .false,
.depth_bias_constant_factor = 0.0,
@@ -141,9 +240,9 @@ pub fn initPipelineContext(ldc: device.LogicalDeviceContext, extent: vk.Extent2D
.b_bit = true,
.a_bit = true,
},
.blend_enable = .false,
.src_color_blend_factor = .one,
.dst_color_blend_factor = .zero,
.blend_enable = .true,
.src_color_blend_factor = .src_alpha,
.dst_color_blend_factor = .one_minus_src_alpha,
.color_blend_op = .add,
.src_alpha_blend_factor = .one,
.dst_alpha_blend_factor = .zero,
@@ -176,10 +275,7 @@ pub fn initPipelineContext(ldc: device.LogicalDeviceContext, extent: vk.Extent2D
.base_pipeline_index = -1,
};
const pipeline_infos = [_]vk.GraphicsPipelineCreateInfo{
pipeline_info,
};
const pipeline_infos = [_]vk.GraphicsPipelineCreateInfo{pipeline_info};
var pipelines: [1]vk.Pipeline = undefined;
_ = try ldc.vkd.createGraphicsPipelines(
@@ -193,5 +289,6 @@ pub fn initPipelineContext(ldc: device.LogicalDeviceContext, extent: vk.Extent2D
return .{
.graphics_pipeline = pipelines[0],
.pipeline_layout = pipeline_layout,
.descriptor_set_layout = if (descriptor_set_layouts) |layouts| layouts[0] else .null_handle,
};
}
+2 -1
View File
@@ -1,4 +1,5 @@
const std = @import("std");
const log = std.log.scoped(.graphics);
const vk = @import("vulkan");
const device = @import("device.zig");
@@ -59,7 +60,7 @@ pub fn initRenderPass(ldc: device.LogicalDeviceContext, format: vk.Format) !Rend
};
const render_pass = try ldc.vkd.createRenderPass(ldc.device, &render_pass_create_info, null);
std.debug.print("created render pass\n", .{});
log.debug("created render pass", .{});
return .{ .render_pass = render_pass };
}
+16 -13
View File
@@ -1,4 +1,5 @@
const std = @import("std");
const log = std.log.scoped(.graphics);
const glfw = @import("zglfw");
const vk = @import("vulkan");
@@ -30,6 +31,7 @@ pub fn initSwapchain(
ldc: device.LogicalDeviceContext,
surface: vk.SurfaceKHR,
window: *glfw.Window,
old_swapchain: vk.SwapchainKHR,
allocator: std.mem.Allocator,
) !SwapchainContext {
const surface_caps = try vc.vki.getPhysicalDeviceSurfaceCapabilitiesKHR(
@@ -37,16 +39,16 @@ pub fn initSwapchain(
surface,
);
std.debug.print(
"surface current extent: {}x{}\n",
log.debug(
"surface current extent: {}x{}",
.{
surface_caps.current_extent.width,
surface_caps.current_extent.height,
},
);
std.debug.print(
"surface min/max image count: {}/{}\n",
log.debug(
"surface min/max image count: {}/{}",
.{
surface_caps.min_image_count,
surface_caps.max_image_count,
@@ -100,16 +102,16 @@ pub fn initSwapchain(
chosen_image_count = surface_caps.max_image_count;
}
std.debug.print(
"chosen swapchain format={any}, color_space={any}\n",
log.debug(
"chosen swapchain format={any}, color_space={any}",
.{ chosen_surface_format.format, chosen_surface_format.color_space },
);
std.debug.print("chosen present mode={any}\n", .{chosen_present_mode});
std.debug.print(
"chosen extent={}x{}\n",
log.debug("chosen present mode={any}", .{chosen_present_mode});
log.debug(
"chosen extent={}x{}",
.{ chosen_extent.width, chosen_extent.height },
);
std.debug.print("chosen image count={}\n", .{chosen_image_count});
log.debug("chosen image count={}", .{chosen_image_count});
const swapchain_create_info = vk.SwapchainCreateInfoKHR{
.surface = surface,
@@ -128,11 +130,12 @@ pub fn initSwapchain(
},
.present_mode = chosen_present_mode,
.clipped = .true,
.old_swapchain = old_swapchain,
};
const swapchain = try ldc.vkd.createSwapchainKHR(ldc.device, &swapchain_create_info, null);
errdefer ldc.vkd.destroySwapchainKHR(ldc.device, swapchain, null);
std.debug.print("created swapchain\n", .{});
log.debug("created swapchain", .{});
const swapchain_images = try ldc.vkd.getSwapchainImagesAllocKHR(
ldc.device,
@@ -140,7 +143,7 @@ pub fn initSwapchain(
allocator,
);
errdefer allocator.free(swapchain_images);
std.debug.print("swapchain images: {}\n", .{swapchain_images.len});
log.debug("swapchain images: {}", .{swapchain_images.len});
const swapchain_image_views = try allocator.alloc(vk.ImageView, swapchain_images.len);
errdefer allocator.free(swapchain_image_views);
@@ -182,7 +185,7 @@ pub fn initSwapchain(
created_image_view_count += 1;
}
std.debug.print("created swapchain image views: {}\n", .{swapchain_image_views.len});
log.debug("created swapchain image views: {}", .{swapchain_image_views.len});
return .{
.swapchain = swapchain,
+2 -1
View File
@@ -1,4 +1,5 @@
const std = @import("std");
const log = std.log.scoped(.graphics);
const vk = @import("vulkan");
const device = @import("device.zig");
@@ -44,7 +45,7 @@ pub fn initSyncObjects(ldc: device.LogicalDeviceContext) !SyncContext {
null,
);
std.debug.print("created synchronization objects\n", .{});
log.debug("created synchronization objects", .{});
return .{
.image_available_semaphore = image_available_semaphore,
+293
View File
@@ -0,0 +1,293 @@
const vk = @import("vulkan");
const context = @import("context.zig");
const device = @import("device.zig");
const buffer = @import("buffer.zig");
const commands = @import("commands.zig");
const assets = @import("../assets.zig");
pub const TextureContext = struct {
image: vk.Image,
memory: vk.DeviceMemory,
image_view: vk.ImageView,
sampler: vk.Sampler,
pub fn destroy(self: *const TextureContext, ldc: *const device.LogicalDeviceContext) void {
ldc.vkd.destroySampler(ldc.device, self.sampler, null);
ldc.vkd.destroyImageView(ldc.device, self.image_view, null);
ldc.vkd.destroyImage(ldc.device, self.image, null);
ldc.vkd.freeMemory(ldc.device, self.memory, null);
}
};
pub fn createImage(
vc: context.VulkanContext,
ldc: device.LogicalDeviceContext,
width: u32,
height: u32,
format: vk.Format,
tiling: vk.ImageTiling,
usage: vk.ImageUsageFlags,
properties: vk.MemoryPropertyFlags,
) !TextureContext {
const image_create_info = vk.ImageCreateInfo{
.image_type = .@"2d",
.extent = .{
.width = width,
.height = height,
.depth = 1,
},
.mip_levels = 1,
.array_layers = 1,
.format = format,
.tiling = tiling,
.initial_layout = .undefined,
.usage = usage,
.samples = .{ .@"1_bit" = true },
.sharing_mode = .exclusive,
};
const image = try ldc.vkd.createImage(ldc.device, &image_create_info, null);
errdefer ldc.vkd.destroyImage(ldc.device, image, null);
const memory_requirements = ldc.vkd.getImageMemoryRequirements(ldc.device, image);
const memory_type_index = try buffer.findMemoryType(
vc,
ldc,
memory_requirements.memory_type_bits,
properties,
);
const alloc_info = vk.MemoryAllocateInfo{
.allocation_size = memory_requirements.size,
.memory_type_index = memory_type_index,
};
const memory = try ldc.vkd.allocateMemory(ldc.device, &alloc_info, null);
errdefer ldc.vkd.freeMemory(ldc.device, memory, null);
try ldc.vkd.bindImageMemory(ldc.device, image, memory, 0);
const image_view = try createImageView(ldc, image, format);
errdefer ldc.vkd.destroyImageView(ldc.device, image_view, null);
const sampler = try createTextureSampler(ldc);
errdefer ldc.vkd.destroySampler(ldc.device, sampler, null);
return .{
.image = image,
.memory = memory,
.image_view = image_view,
.sampler = sampler,
};
}
fn createImageView(
ldc: device.LogicalDeviceContext,
image: vk.Image,
format: vk.Format,
) !vk.ImageView {
const view_create_info = vk.ImageViewCreateInfo{
.image = image,
.view_type = .@"2d",
.format = format,
.components = .{
.r = .identity,
.g = .identity,
.b = .identity,
.a = .identity,
},
.subresource_range = .{
.aspect_mask = .{
.color_bit = true,
},
.base_mip_level = 0,
.level_count = 1,
.base_array_layer = 0,
.layer_count = 1,
},
};
return try ldc.vkd.createImageView(
ldc.device,
&view_create_info,
null,
);
}
fn createTextureSampler(ldc: device.LogicalDeviceContext) !vk.Sampler {
const sampler_create_info = vk.SamplerCreateInfo{
.mag_filter = .linear,
.min_filter = .linear,
.mipmap_mode = .linear,
.address_mode_u = .clamp_to_edge,
.address_mode_v = .clamp_to_edge,
.address_mode_w = .clamp_to_edge,
.mip_lod_bias = 0.0,
.anisotropy_enable = .false,
.max_anisotropy = 1.0,
.compare_enable = .false,
.compare_op = .always,
.min_lod = 0.0,
.max_lod = 0.0,
.border_color = .int_opaque_black,
.unnormalized_coordinates = .false,
};
return try ldc.vkd.createSampler(
ldc.device,
&sampler_create_info,
null,
);
}
pub fn transitionImageLayout(
ldc: device.LogicalDeviceContext,
command_context: commands.CommandContext,
image: vk.Image,
old_layout: vk.ImageLayout,
new_layout: vk.ImageLayout,
) !void {
const command_buffer = try commands.beginSingleTimeCommands(ldc, command_context);
var barrier = vk.ImageMemoryBarrier{
.src_access_mask = .{},
.dst_access_mask = .{},
.old_layout = old_layout,
.new_layout = new_layout,
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
.image = image,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_mip_level = 0,
.level_count = 1,
.base_array_layer = 0,
.layer_count = 1,
},
};
var source_stage: vk.PipelineStageFlags = undefined;
var destination_stage: vk.PipelineStageFlags = undefined;
if (old_layout == .undefined and new_layout == .transfer_dst_optimal) {
barrier.src_access_mask = .{};
barrier.dst_access_mask = .{ .transfer_write_bit = true };
source_stage = .{ .top_of_pipe_bit = true };
destination_stage = .{ .transfer_bit = true };
} else if (old_layout == .transfer_dst_optimal and new_layout == .shader_read_only_optimal) {
barrier.src_access_mask = .{ .transfer_write_bit = true };
barrier.dst_access_mask = .{ .shader_read_bit = true };
source_stage = .{ .transfer_bit = true };
destination_stage = .{ .fragment_shader_bit = true };
} else {
return error.UnsupportedLayoutTransition;
}
const image_barriers = [_]vk.ImageMemoryBarrier{barrier};
ldc.vkd.cmdPipelineBarrier(
command_buffer,
source_stage,
destination_stage,
.{},
null,
null,
&image_barriers,
);
try commands.endSingleTimeCommands(ldc, command_context, command_buffer);
}
pub fn copyBufferToImage(
ldc: device.LogicalDeviceContext,
command_context: commands.CommandContext,
source_buffer: vk.Buffer,
destination_image: vk.Image,
width: u32,
height: u32,
) !void {
const command_buffer = try commands.beginSingleTimeCommands(ldc, command_context);
const region = vk.BufferImageCopy{
.buffer_offset = 0,
.buffer_row_length = 0,
.buffer_image_height = 0,
.image_subresource = .{
.aspect_mask = .{ .color_bit = true },
.mip_level = 0,
.base_array_layer = 0,
.layer_count = 1,
},
.image_offset = .{ .x = 0, .y = 0, .z = 0 },
.image_extent = .{
.width = width,
.height = height,
.depth = 1,
},
};
const regions = [_]vk.BufferImageCopy{region};
ldc.vkd.cmdCopyBufferToImage(
command_buffer,
source_buffer,
destination_image,
.transfer_dst_optimal,
&regions,
);
try commands.endSingleTimeCommands(ldc, command_context, command_buffer);
}
pub fn initTextureFromRgba(
vc: context.VulkanContext,
ldc: device.LogicalDeviceContext,
command_context: commands.CommandContext,
asset: []const u8,
width: u32,
height: u32,
format: vk.Format,
tiling: vk.ImageTiling,
usage: vk.ImageUsageFlags,
properties: vk.MemoryPropertyFlags,
) !TextureContext {
const staging = try buffer.initStagingBuffer(vc, ldc, asset);
defer staging.destroy(&ldc);
const texture = try createImage(
vc,
ldc,
width,
height,
format,
tiling,
usage,
properties,
);
try transitionImageLayout(
ldc,
command_context,
texture.image,
.undefined,
.transfer_dst_optimal,
);
try copyBufferToImage(
ldc,
command_context,
staging.buffer,
texture.image,
width,
height,
);
try transitionImageLayout(
ldc,
command_context,
texture.image,
.transfer_dst_optimal,
.shader_read_only_optimal,
);
return texture;
}