Create descriptor set layout, pipeline, vertex buffer and index buffer
This commit is contained in:
364
src/Game.zig
364
src/Game.zig
@@ -2,6 +2,7 @@ const Game = @This();
|
||||
const std = @import("std");
|
||||
|
||||
const glfw = @import("zglfw");
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const math = @import("math.zig");
|
||||
|
||||
@@ -9,14 +10,32 @@ const Atoms = @import("assets/Atoms.zig");
|
||||
const Textures = @import("assets/Textures.zig");
|
||||
const Materials = @import("assets/Materials.zig");
|
||||
const Swapchain = @import("engine/Swapchain.zig");
|
||||
const VertexBuffer = @import("engine/VertexBuffer.zig");
|
||||
const IndexBuffer = @import("engine/IndexBuffer.zig");
|
||||
const Iterator3 = math.Iterator3;
|
||||
const Matrix4x4 = math.Matrix4x4;
|
||||
const Quaternion = math.Quaternion;
|
||||
const Vector2 = math.Vector2;
|
||||
const Vector3 = math.Vector3;
|
||||
|
||||
const Vertex = extern struct {
|
||||
positionOS: [3]f32,
|
||||
texCoord: [2]u16,
|
||||
normalOS: [3]i8,
|
||||
tangentOS: [4]i8,
|
||||
};
|
||||
|
||||
const main_vert_spv align(4) = @embedFile("shaders/main_vert.spv").*;
|
||||
const main_frag_spv align(4) = @embedFile("shaders/main_frag.spv").*;
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
swapchain: *Swapchain,
|
||||
global_descriptor_set_layout: vk.DescriptorSetLayout,
|
||||
per_object_descriptor_set_layout: vk.DescriptorSetLayout,
|
||||
pipeline_layout: vk.PipelineLayout,
|
||||
pipeline: vk.Pipeline,
|
||||
vertex_buffer: VertexBuffer,
|
||||
index_buffer: IndexBuffer,
|
||||
|
||||
atoms: Atoms,
|
||||
materials: Materials,
|
||||
@@ -52,6 +71,271 @@ pub fn init(allocator: std.mem.Allocator, swapchain: *Swapchain) !Game {
|
||||
errdefer textures.deinit(swapchain.engine);
|
||||
|
||||
_ = try materials.getOrLoadId(swapchain.engine, &textures, &atoms, try atoms.getOrPutAtom("Bricks.json"));
|
||||
_ = try materials.getOrLoadId(swapchain.engine, &textures, &atoms, try atoms.getOrPutAtom("Dirt.json"));
|
||||
_ = try materials.getOrLoadId(swapchain.engine, &textures, &atoms, try atoms.getOrPutAtom("Gold.json"));
|
||||
_ = try materials.getOrLoadId(swapchain.engine, &textures, &atoms, try atoms.getOrPutAtom("Stone.json"));
|
||||
|
||||
const device = swapchain.engine.device;
|
||||
const interface = &swapchain.engine.vk_allocator.interface;
|
||||
|
||||
const global_descriptor_set_layout_bindings = [_]vk.DescriptorSetLayoutBinding{
|
||||
.{
|
||||
.binding = 0,
|
||||
.descriptor_type = .uniform_buffer,
|
||||
.descriptor_count = 1,
|
||||
.stage_flags = .{ .vertex_bit = true, .fragment_bit = true },
|
||||
},
|
||||
.{
|
||||
.binding = 1,
|
||||
.descriptor_type = .storage_buffer,
|
||||
.descriptor_count = 1,
|
||||
.stage_flags = .{ .vertex_bit = true, .fragment_bit = true },
|
||||
},
|
||||
.{
|
||||
.binding = 2,
|
||||
.descriptor_type = .storage_buffer,
|
||||
.descriptor_count = 1,
|
||||
.stage_flags = .{ .vertex_bit = true, .fragment_bit = true },
|
||||
},
|
||||
.{
|
||||
.binding = 3,
|
||||
.descriptor_type = .storage_buffer,
|
||||
.descriptor_count = 1,
|
||||
.stage_flags = .{ .vertex_bit = true, .fragment_bit = true },
|
||||
},
|
||||
.{
|
||||
.binding = 4,
|
||||
.descriptor_type = .sampler,
|
||||
.descriptor_count = 1,
|
||||
.stage_flags = .{ .vertex_bit = true, .fragment_bit = true },
|
||||
},
|
||||
.{
|
||||
.binding = 5,
|
||||
.descriptor_type = .sampled_image,
|
||||
.descriptor_count = 1024,
|
||||
.stage_flags = .{ .vertex_bit = true, .fragment_bit = true },
|
||||
},
|
||||
};
|
||||
|
||||
const global_descriptor_set_layout_bindings_flags = [_]vk.DescriptorBindingFlags{
|
||||
.{},
|
||||
.{},
|
||||
.{},
|
||||
.{},
|
||||
.{},
|
||||
.{ .variable_descriptor_count_bit = true },
|
||||
};
|
||||
|
||||
std.debug.assert(global_descriptor_set_layout_bindings.len == global_descriptor_set_layout_bindings_flags.len);
|
||||
|
||||
const global_descriptor_set_layout = try device.createDescriptorSetLayout(&.{
|
||||
.p_next = &vk.DescriptorSetLayoutBindingFlagsCreateInfo{
|
||||
.binding_count = global_descriptor_set_layout_bindings_flags.len,
|
||||
.p_binding_flags = &global_descriptor_set_layout_bindings_flags,
|
||||
},
|
||||
.binding_count = global_descriptor_set_layout_bindings.len,
|
||||
.p_bindings = &global_descriptor_set_layout_bindings,
|
||||
}, interface);
|
||||
errdefer device.destroyDescriptorSetLayout(global_descriptor_set_layout, interface);
|
||||
|
||||
const per_object_descriptor_set_layout_bindings = [_]vk.DescriptorSetLayoutBinding{
|
||||
.{
|
||||
.binding = 0,
|
||||
.descriptor_type = .uniform_buffer_dynamic,
|
||||
.descriptor_count = 1,
|
||||
.stage_flags = .{ .vertex_bit = true, .fragment_bit = true },
|
||||
},
|
||||
};
|
||||
|
||||
const per_object_descriptor_set_layout = try device.createDescriptorSetLayout(&.{
|
||||
.binding_count = per_object_descriptor_set_layout_bindings.len,
|
||||
.p_bindings = &per_object_descriptor_set_layout_bindings,
|
||||
}, interface);
|
||||
errdefer device.destroyDescriptorSetLayout(per_object_descriptor_set_layout, interface);
|
||||
|
||||
const descriptor_set_layouts = [_]vk.DescriptorSetLayout{
|
||||
global_descriptor_set_layout,
|
||||
per_object_descriptor_set_layout,
|
||||
};
|
||||
|
||||
const pipeline_layout = try device.createPipelineLayout(&.{
|
||||
.set_layout_count = descriptor_set_layouts.len,
|
||||
.p_set_layouts = &descriptor_set_layouts,
|
||||
}, interface);
|
||||
errdefer device.destroyPipelineLayout(pipeline_layout, interface);
|
||||
|
||||
const vertex_shader = try device.createShaderModule(&.{
|
||||
.code_size = main_vert_spv.len,
|
||||
.p_code = @ptrCast(&main_vert_spv),
|
||||
}, interface);
|
||||
defer device.destroyShaderModule(vertex_shader, interface);
|
||||
|
||||
const fragment_shader = try device.createShaderModule(&.{
|
||||
.code_size = main_frag_spv.len,
|
||||
.p_code = @ptrCast(&main_frag_spv),
|
||||
}, interface);
|
||||
defer device.destroyShaderModule(fragment_shader, interface);
|
||||
|
||||
var vertex_buffer: VertexBuffer = try .init(swapchain.engine, Vertex, 4);
|
||||
errdefer vertex_buffer.deinit(swapchain.engine);
|
||||
try vertex_buffer.write(Vertex, swapchain.engine, &.{
|
||||
.{
|
||||
.positionOS = .{ -0.5, -0.5, 0 },
|
||||
.texCoord = .{ 0, 65535 },
|
||||
.normalOS = .{ 127, 0, 0 },
|
||||
.tangentOS = .{ 127, 0, 0, -127 },
|
||||
},
|
||||
.{
|
||||
.positionOS = .{ 0.5, -0.5, 0 },
|
||||
.texCoord = .{ 65535, 65535 },
|
||||
.normalOS = .{ 127, 0, 0 },
|
||||
.tangentOS = .{ 127, 0, 0, -127 },
|
||||
},
|
||||
.{
|
||||
.positionOS = .{ -0.5, 0.5, 0 },
|
||||
.texCoord = .{ 0, 0 },
|
||||
.normalOS = .{ 127, 0, 0 },
|
||||
.tangentOS = .{ 127, 0, 0, -127 },
|
||||
},
|
||||
.{
|
||||
.positionOS = .{ 0.5, 0.5, 0 },
|
||||
.texCoord = .{ 65535, 0 },
|
||||
.normalOS = .{ 127, 0, 0 },
|
||||
.tangentOS = .{ 127, 0, 0, -127 },
|
||||
},
|
||||
});
|
||||
|
||||
var index_buffer: IndexBuffer = try .init(swapchain.engine, 6);
|
||||
errdefer index_buffer.deinit(swapchain.engine);
|
||||
try index_buffer.write(swapchain.engine, &.{ 0, 1, 2, 2, 1, 3 });
|
||||
|
||||
const pipeline_shader_stages = [_]vk.PipelineShaderStageCreateInfo{
|
||||
.{
|
||||
.stage = .{ .vertex_bit = true },
|
||||
.module = vertex_shader,
|
||||
.p_name = "main",
|
||||
},
|
||||
.{
|
||||
.stage = .{ .fragment_bit = true },
|
||||
.module = fragment_shader,
|
||||
.p_name = "main",
|
||||
},
|
||||
};
|
||||
|
||||
const vertex_input_binding_descriptions = [_]vk.VertexInputBindingDescription{
|
||||
.{
|
||||
.binding = 0,
|
||||
.stride = @sizeOf(Vertex),
|
||||
.input_rate = .vertex,
|
||||
},
|
||||
};
|
||||
|
||||
const vertex_input_attribute_descriptions = [_]vk.VertexInputAttributeDescription{
|
||||
.{
|
||||
.location = 0,
|
||||
.binding = 0,
|
||||
.format = .r32g32b32_sfloat,
|
||||
.offset = @offsetOf(Vertex, "positionOS"),
|
||||
},
|
||||
.{
|
||||
.location = 1,
|
||||
.binding = 0,
|
||||
.format = .r16g16_unorm,
|
||||
.offset = @offsetOf(Vertex, "texCoord"),
|
||||
},
|
||||
.{
|
||||
.location = 2,
|
||||
.binding = 0,
|
||||
.format = .r8g8b8_snorm,
|
||||
.offset = @offsetOf(Vertex, "normalOS"),
|
||||
},
|
||||
.{
|
||||
.location = 3,
|
||||
.binding = 0,
|
||||
.format = .r8g8b8a8_snorm,
|
||||
.offset = @offsetOf(Vertex, "tangentOS"),
|
||||
},
|
||||
};
|
||||
|
||||
const pipeline_color_blend_attachment_states = [_]vk.PipelineColorBlendAttachmentState{
|
||||
.{
|
||||
.blend_enable = .false,
|
||||
.src_color_blend_factor = .one,
|
||||
.dst_color_blend_factor = .zero,
|
||||
.color_blend_op = .add,
|
||||
.src_alpha_blend_factor = .one,
|
||||
.dst_alpha_blend_factor = .zero,
|
||||
.alpha_blend_op = .add,
|
||||
.color_write_mask = .{
|
||||
.r_bit = true,
|
||||
.g_bit = true,
|
||||
.b_bit = true,
|
||||
.a_bit = true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const dynamic_states = [_]vk.DynamicState{ .viewport, .scissor };
|
||||
|
||||
var pipeline: vk.Pipeline = undefined;
|
||||
_ = try device.createGraphicsPipelines(.null_handle, 1, &.{
|
||||
.{
|
||||
.stage_count = pipeline_shader_stages.len,
|
||||
.p_stages = &pipeline_shader_stages,
|
||||
.p_vertex_input_state = &.{
|
||||
.vertex_binding_description_count = vertex_input_binding_descriptions.len,
|
||||
.p_vertex_binding_descriptions = &vertex_input_binding_descriptions,
|
||||
.vertex_attribute_description_count = vertex_input_attribute_descriptions.len,
|
||||
.p_vertex_attribute_descriptions = &vertex_input_attribute_descriptions,
|
||||
},
|
||||
.p_input_assembly_state = &.{
|
||||
.topology = .triangle_list,
|
||||
.primitive_restart_enable = .false,
|
||||
},
|
||||
.p_viewport_state = &.{
|
||||
.viewport_count = 1,
|
||||
.p_viewports = undefined,
|
||||
.scissor_count = 1,
|
||||
.p_scissors = undefined,
|
||||
},
|
||||
.p_rasterization_state = &.{
|
||||
.depth_clamp_enable = .false,
|
||||
.rasterizer_discard_enable = .false,
|
||||
.polygon_mode = .fill,
|
||||
.cull_mode = .{ .back_bit = true },
|
||||
.front_face = .counter_clockwise,
|
||||
.depth_bias_enable = .false,
|
||||
.depth_bias_constant_factor = 0,
|
||||
.depth_bias_clamp = 0,
|
||||
.depth_bias_slope_factor = 0,
|
||||
.line_width = 1,
|
||||
},
|
||||
.p_multisample_state = &.{
|
||||
.rasterization_samples = .{ .@"1_bit" = true },
|
||||
.sample_shading_enable = .false,
|
||||
.min_sample_shading = 1,
|
||||
.alpha_to_coverage_enable = .false,
|
||||
.alpha_to_one_enable = .false,
|
||||
},
|
||||
.p_depth_stencil_state = null,
|
||||
.p_color_blend_state = &.{
|
||||
.logic_op_enable = .false,
|
||||
.logic_op = .copy,
|
||||
.attachment_count = pipeline_color_blend_attachment_states.len,
|
||||
.p_attachments = &pipeline_color_blend_attachment_states,
|
||||
.blend_constants = .{ 0, 0, 0, 0 },
|
||||
},
|
||||
.p_dynamic_state = &.{
|
||||
.dynamic_state_count = dynamic_states.len,
|
||||
.p_dynamic_states = &dynamic_states,
|
||||
},
|
||||
.layout = pipeline_layout,
|
||||
.render_pass = swapchain.render_pass,
|
||||
.subpass = 0,
|
||||
.base_pipeline_index = -1,
|
||||
},
|
||||
}, interface, @ptrCast(&pipeline));
|
||||
errdefer device.destroyPipeline(pipeline, interface);
|
||||
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
@@ -59,10 +343,27 @@ pub fn init(allocator: std.mem.Allocator, swapchain: *Swapchain) !Game {
|
||||
.atoms = atoms,
|
||||
.materials = materials,
|
||||
.textures = textures,
|
||||
.global_descriptor_set_layout = global_descriptor_set_layout,
|
||||
.per_object_descriptor_set_layout = per_object_descriptor_set_layout,
|
||||
.pipeline_layout = pipeline_layout,
|
||||
.pipeline = pipeline,
|
||||
.vertex_buffer = vertex_buffer,
|
||||
.index_buffer = index_buffer,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Game) void {
|
||||
const device = self.swapchain.engine.device;
|
||||
const interface = &self.swapchain.engine.vk_allocator.interface;
|
||||
|
||||
self.vertex_buffer.deinit(self.swapchain.engine);
|
||||
self.index_buffer.deinit(self.swapchain.engine);
|
||||
|
||||
device.destroyPipeline(self.pipeline, interface);
|
||||
device.destroyPipelineLayout(self.pipeline_layout, interface);
|
||||
device.destroyDescriptorSetLayout(self.per_object_descriptor_set_layout, interface);
|
||||
device.destroyDescriptorSetLayout(self.global_descriptor_set_layout, interface);
|
||||
|
||||
self.textures.deinit(self.swapchain.engine);
|
||||
self.materials.deinit(self.swapchain.engine);
|
||||
self.atoms.deinit();
|
||||
@@ -76,6 +377,10 @@ pub fn update(self: *Game, dt: f32) void {
|
||||
).rotate(self.camera_yaw).mulScalar(player_speed * dt);
|
||||
|
||||
self.camera_position = Vector3.add(self.camera_position, camera_d.asVector3(0));
|
||||
|
||||
self.render() catch |err| {
|
||||
std.log.err("Failed to render: {s}", .{@errorName(err)});
|
||||
};
|
||||
}
|
||||
|
||||
pub fn onKeyDown(self: *Game, key_code: glfw.Key, mods: glfw.Mods) void {
|
||||
@@ -127,3 +432,62 @@ pub fn onMouseMove(self: *Game, dx: f32, dy: f32) void {
|
||||
self.camera_pitch = std.math.clamp(self.camera_pitch, -0.5 * std.math.pi, 0.5 * std.math.pi);
|
||||
self.camera_yaw = @mod(self.camera_yaw, 2 * std.math.pi);
|
||||
}
|
||||
|
||||
fn render(self: *Game) !void {
|
||||
const engine = self.swapchain.engine;
|
||||
|
||||
const fence = try engine.device.createFence(&.{}, &engine.vk_allocator.interface);
|
||||
defer engine.device.destroyFence(fence, &engine.vk_allocator.interface);
|
||||
|
||||
const command_buffer = try engine.allocateGraphicsCommandBuffer();
|
||||
defer engine.freeGraphicsCommandBuffer(command_buffer);
|
||||
try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||
|
||||
const viewports = [_]vk.Viewport{
|
||||
.{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = 0,
|
||||
.height = 0,
|
||||
.min_depth = 0,
|
||||
.max_depth = 1,
|
||||
},
|
||||
};
|
||||
command_buffer.setViewport(0, viewports.len, &viewports);
|
||||
|
||||
const scissors = [_]vk.Rect2D{
|
||||
.{
|
||||
.offset = .{ .x = 0, .y = 0 },
|
||||
.extent = .{ .width = 0, .height = 0 },
|
||||
},
|
||||
};
|
||||
command_buffer.setScissor(0, scissors.len, &scissors);
|
||||
|
||||
{
|
||||
const clear_values = [_]vk.ClearValue{
|
||||
.{ .color = .{ .float_32 = .{ 0, 0, 0, 1 } } },
|
||||
};
|
||||
|
||||
command_buffer.beginRenderPass(&.{
|
||||
.render_pass = self.swapchain.render_pass,
|
||||
.framebuffer = self.swapchain.swapchain_images[0].framebuffer,
|
||||
.render_area = .{
|
||||
.offset = .{ .x = 0, .y = 0 },
|
||||
.extent = .{ .width = 0, .height = 0 },
|
||||
},
|
||||
.clear_value_count = clear_values.len,
|
||||
.p_clear_values = &clear_values,
|
||||
}, .@"inline");
|
||||
defer command_buffer.endRenderPass();
|
||||
|
||||
command_buffer.bindPipeline(.graphics, self.pipeline);
|
||||
|
||||
command_buffer.bindVertexBuffers(0, 1, @ptrCast(&self.vertex_buffer.buffer), &.{0});
|
||||
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
|
||||
command_buffer.drawIndexed(@intCast(self.index_buffer.index_count), 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
try command_buffer.endCommandBuffer();
|
||||
try engine.submitGraphicsCommandBuffer(command_buffer, fence);
|
||||
_ = try engine.device.waitForFences(1, @ptrCast(&fence), .true, std.math.maxInt(u64));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user