Vulkan TRIANGLE!!!

This commit is contained in:
sergeypdev 2024-09-25 10:59:06 +04:00
parent f0c9e04887
commit fe69fa1f51
7 changed files with 410 additions and 227 deletions

View File

@ -1,12 +1,21 @@
#if VERTEX_SHADER
vec2 positions[3] = vec2[](
vec2(0.0, -0.5),
vec2(-0.5, 0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
vec2(0.0, -0.5)
);
vec3 colors[3] = vec3[](
vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0)
);
layout(location = 0) out vec3 VertexColor;
void main() {
VertexColor = colors[gl_VertexIndex];
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
}
@ -14,10 +23,12 @@ void main() {
#if FRAGMENT_SHADER
layout(location = 0) in vec3 VertexColor;
layout(location = 0) out vec4 FragColor;
void main() {
FragColor = vec4(0.6, 0.8, 1.0, 1.0);
FragColor = vec4(VertexColor, 1.0);
}
#endif

View File

@ -27,6 +27,8 @@ const Vec3 = @import("zalgebra").Vec3;
const Mat4 = @import("zalgebra").Mat4;
const sdl = @import("sdl.zig");
const tracy = @import("tracy");
const vk = @import("vk");
const GraphicsContext = @import("GraphicsContext.zig");
pub const AssetId = assets.AssetId;
pub const Handle = assets.Handle;
@ -56,6 +58,7 @@ rw_lock: std.Thread.RwLock.DefaultRwLock = .{},
asset_watcher: AssetWatcher = undefined,
vertex_heap: VertexBufferHeap,
gc: *GraphicsContext,
const AssetWatcher = struct {
assetman: *AssetManager,
@ -145,7 +148,7 @@ const AssetWatcher = struct {
}
};
pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator) AssetManager {
pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, gc: *GraphicsContext) AssetManager {
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const exe_dir_path = std.fs.selfExeDirPath(&buf) catch @panic("can't find self exe dir path");
const exe_dir = std.fs.openDirAbsolute(exe_dir_path, .{}) catch @panic("can't open self exe dir path");
@ -155,6 +158,7 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator) AssetM
.frame_arena = frame_arena,
.exe_dir = exe_dir,
.vertex_heap = VertexBufferHeap.init(allocator) catch @panic("OOM"),
.gc = gc,
};
}
@ -212,16 +216,14 @@ pub fn resolveShaderWithDefines(self: *AssetManager, handle: Handle.Shader, defi
return self.loadShader(handle.id, permuted_asset_id, defines);
}
// pub fn resolveShaderProgram(self: *AssetManager, handle: Handle.ShaderProgram) LoadedShaderProgram {
// return self.resolveShaderProgramWithDefines(handle, &.{});
// }
//
pub fn resolveShaderProgram(self: *AssetManager, handle: Handle.ShaderProgram) LoadedShaderProgram {
return self.resolveShaderProgramWithDefines(handle, &.{});
}
pub fn resolveShaderProgramWithDefines(self: *AssetManager, handle: Handle.ShaderProgram, defines: []const DefinePair) LoadedShaderProgram {
if (handle.id == 0) return NullShaderProgram;
const permuted_asset_id = permuteAssetIdDefines(handle.id, defines);
if (self.resolveAsset(permuted_asset_id)) |asset| {
if (self.resolveAsset(handle.id)) |asset| {
switch (asset.*) {
.shaderProgram => |shader| {
return shader;
@ -230,7 +232,7 @@ pub fn resolveShaderProgramWithDefines(self: *AssetManager, handle: Handle.Shade
}
}
return self.loadShaderProgram(handle, permuted_asset_id, defines);
return self.loadShaderProgram(handle);
}
pub fn resolveMesh(self: *AssetManager, handle: Handle.Mesh) LoadedMesh {
@ -307,88 +309,147 @@ pub const ShaderProgramDefinition = struct {
compute: []const u8,
};
pub fn loadShaderProgram(self: *AssetManager, handle: Handle.ShaderProgram, permuted_id: AssetId, defines: []const DefinePair) LoadedShaderProgram {
return self.loadShaderProgramErr(handle.id, permuted_id, defines) catch |err| {
pub fn loadShaderProgram(self: *AssetManager, handle: Handle.ShaderProgram) LoadedShaderProgram {
return self.loadShaderProgramErr(handle.id) catch |err| {
std.log.err("Failed to load shader program {}\n", .{err});
return NullShaderProgram;
};
}
fn loadShaderProgramErr(self: *AssetManager, id: AssetId, permuted_id: AssetId) !LoadedShaderProgram {
fn loadShaderProgramErr(self: *AssetManager, id: AssetId) !LoadedShaderProgram {
const data = try self.loadFile(self.frame_arena, asset_manifest.getPath(id), SHADER_MAX_BYTES);
var serializer = formats.Serializer{ .write = false, .endian = formats.native_endian, .stream = .{ .const_buffer = data.bytes } };
var serializer = formats.Serializer{ .write = false, .endian = formats.native_endian, .stream = .{ .buffer = std.io.fixedBufferStream(data.bytes) } };
var program: formats.ShaderProgram = undefined;
try program.serialize(&serializer);
const prog = gl.createProgram();
errdefer gl.deleteProgram(prog);
const pipeline = blk: {
switch (program) {
.graphics => |graphics_pipeline| {
const vertex_shader = try self.compileShader(graphics_pipeline.vertex.source, .vertex);
defer gl.deleteShader(vertex_shader);
const fragment_shader = try self.compileShader(graphics_pipeline.fragment.source, .fragment);
defer gl.deleteShader(fragment_shader);
const vertex_shader_modle = try self.gc.device.createShaderModule(&.{
.code_size = graphics_pipeline.vertex.source.len,
.p_code = @alignCast(@ptrCast(graphics_pipeline.vertex.source.ptr)),
}, null);
defer self.gc.device.destroyShaderModule(vertex_shader_modle, null);
const fragment_shader_modle = try self.gc.device.createShaderModule(&.{
.code_size = graphics_pipeline.fragment.source.len,
.p_code = @alignCast(@ptrCast(graphics_pipeline.fragment.source.ptr)),
}, null);
defer self.gc.device.destroyShaderModule(fragment_shader_modle, null);
gl.attachShader(prog, vertex_shader);
defer gl.detachShader(prog, vertex_shader);
gl.attachShader(prog, fragment_shader);
defer gl.detachShader(prog, fragment_shader);
const dynamic_states = [_]vk.DynamicState{
.viewport_with_count,
.scissor_with_count,
};
gl.linkProgram(prog);
const pipeline_layout = try self.gc.device.createPipelineLayout(&.{}, null);
defer self.gc.device.destroyPipelineLayout(pipeline_layout, null);
var pipelines = [1]vk.Pipeline{.null_handle};
_ = try self.gc.device.createGraphicsPipelines(self.gc.pipeline_cache, 1, &.{
vk.GraphicsPipelineCreateInfo{
.base_pipeline_index = 0,
.p_input_assembly_state = &vk.PipelineInputAssemblyStateCreateInfo{
.primitive_restart_enable = vk.FALSE,
.topology = .triangle_list,
},
.p_vertex_input_state = &vk.PipelineVertexInputStateCreateInfo{},
.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.0,
.depth_bias_clamp = 0.0,
.depth_bias_slope_factor = 0.0,
.line_width = 1.0,
},
.p_viewport_state = &vk.PipelineViewportStateCreateInfo{},
.layout = pipeline_layout,
// .p_depth_stencil_state = &vk.PipelineDepthStencilStateCreateInfo{
// .depth_test_enable = true,
// .depth_write_enable = true,
// .depth_compare_op = .less,
// .depth_bounds_test_enable = true,
// .stencil_test_enable = false,
// .front = std.mem.zeroes(vk.StencilOpState),
// .back = std.mem.zeroes(vk.StencilOpState),
// .min_depth_bounds = 0.0,
// .max_depth_bounds = 1.0,
// },
.p_dynamic_state = &vk.PipelineDynamicStateCreateInfo{
.dynamic_state_count = @intCast(dynamic_states.len),
.p_dynamic_states = &dynamic_states,
},
.p_multisample_state = &vk.PipelineMultisampleStateCreateInfo{
.sample_shading_enable = vk.FALSE,
.rasterization_samples = .{ .@"1_bit" = true },
.min_sample_shading = 1.0,
.alpha_to_coverage_enable = vk.FALSE,
.alpha_to_one_enable = vk.FALSE,
},
.p_color_blend_state = &vk.PipelineColorBlendStateCreateInfo{
.logic_op_enable = vk.FALSE,
.logic_op = .copy,
.attachment_count = 0,
.blend_constants = [4]f32{ 0.0, 0.0, 0.0, 0.0 },
},
.stage_count = 2,
.p_stages = &.{
vk.PipelineShaderStageCreateInfo{
.module = vertex_shader_modle,
.stage = .{ .vertex_bit = true },
.p_name = "main",
},
vk.PipelineShaderStageCreateInfo{
.module = fragment_shader_modle,
.stage = .{ .fragment_bit = true },
.p_name = "main",
},
},
.subpass = 0,
},
}, null, &pipelines);
break :blk pipelines[0];
},
.compute => |compute_pipeline| {
const compute_shader = try self.compileShader(compute_pipeline.compute.source, .compute);
defer gl.deleteShader(compute_shader);
_ = compute_pipeline; // autofix
return error.ComputeNotSupportedYet;
// const compute_shader_module = try self.gc.device.createShaderModule(&.{
// .code_size = compute_pipeline.compute.source.len,
// .p_code = compute_pipeline.compute.source.ptr,
// }, null);
// defer self.gc.device.destroyShaderModule(compute_shader_module, null);
gl.attachShader(prog, compute_shader);
defer gl.detachShader(prog, compute_shader);
gl.linkProgram(prog);
// var pipelines = [1]vk.Pipeline{.null_handle};
// _ = try self.gc.device.createGraphicsPipelines(self.gc.pipeline_cache, 1, &.{
// vk.GraphicsPipelineCreateInfo{
// .p_stages = &.{
// vk.PipelineShaderStageCreateInfo{
// .module = compute_shader_module,
// .stage = .{ .compute_bit = true },
// .p_name = "main",
// },
// },
// .stage_count = 1,
// },
// }, null, &pipelines);
// return pipelines[0];
},
}
var success: c_int = 0;
gl.getProgramiv(prog, gl.LINK_STATUS, &success);
if (success == 0) {
var info_len: gl.GLint = 0;
gl.getProgramiv(prog, gl.INFO_LOG_LENGTH, &info_len);
if (info_len > 0) {
const info_log = try self.frame_arena.allocSentinel(u8, @intCast(info_len - 1), 0);
gl.getProgramInfoLog(prog, @intCast(info_log.len), null, info_log);
std.log.err("ERROR::PROGRAM::LINK_FAILED\n{s}\n", .{info_log});
} else {
std.log.err("ERROR::PROGRAM::LINK_FAILED\nNo info log.\n", .{});
}
return error.ProgramLinkFailed;
}
var program_length: gl.GLsizei = 0;
gl.getProgramiv(prog, gl.PROGRAM_BINARY_LENGTH, &program_length);
if (program_length > 0) {
const program_binary = try self.frame_arena.allocSentinel(u8, @intCast(program_length - 1), 0);
var binary_format: gl.GLenum = gl.NONE;
var return_len: gl.GLsizei = 0;
gl.getProgramBinary(prog, program_length, &return_len, &binary_format, @ptrCast(program_binary.ptr));
checkGLError();
if (program_length == return_len) {
std.log.debug("Program {s} binary:\n{s}\n", .{ asset_manifest.getPath(id), program_binary[0..@intCast(return_len)] });
}
}
};
const loaded_shader_program = LoadedShaderProgram{
.program = prog,
.permuted_id = permuted_id,
.pipeline = pipeline,
};
{
self.rw_lock.lock();
defer self.rw_lock.unlock();
try self.loaded_assets.put(self.allocator, permuted_id, .{
try self.loaded_assets.put(self.allocator, id, .{
.shaderProgram = loaded_shader_program,
});
try self.modified_times.put(self.allocator, id, data.modified);
@ -403,8 +464,7 @@ const NullShader = LoadedShader{
};
const NullShaderProgram = LoadedShaderProgram{
.program = 0,
.permuted_id = 0,
.pipeline = .null_handle,
};
const NullMesh = LoadedMesh{
@ -693,8 +753,7 @@ const LoadedShader = struct {
};
const LoadedShaderProgram = struct {
program: gl.GLuint,
permuted_id: AssetId,
pipeline: vk.Pipeline,
};
pub const LoadedMesh = struct {
@ -1512,7 +1571,12 @@ fn freeAsset(self: *AssetManager, asset: *LoadedAsset) void {
self.allocator.free(shader.source);
},
.shaderProgram => |*program| {
gl.deleteProgram(program.program);
self.gc.queues.graphics.mu.lock();
defer self.gc.queues.graphics.mu.unlock();
self.gc.device.queueWaitIdle(self.gc.queues.graphics.handle) catch @panic("Wait Idle failed");
self.gc.device.destroyPipeline(program.pipeline, null);
},
.texture => |*texture| {
gl.GL_ARB_bindless_texture.makeTextureHandleNonResidentARB(texture.handle);

View File

@ -13,20 +13,19 @@ const apis: []const vk.ApiInfo = &.{
vk.extensions.khr_swapchain,
};
pub const Instance = vk.InstanceProxy(apis);
pub const Device = vk.DeviceProxy(apis);
pub const CommandBuffer = vk.CommandBufferProxy(apis);
const BaseDispatch = vk.BaseWrapper(apis);
const InstanceDispatch = vk.InstanceWrapper(apis);
const Instance = vk.InstanceProxy(apis);
const Device = vk.DeviceProxy(apis);
const DeviceDispatch = Device.Wrapper;
const CommandBuffer = vk.CommandBufferProxy(apis);
const device_extensions = [_][:0]const u8{
vk.extensions.khr_swapchain.name,
};
const vk_layers = [_][:0]const u8{"VK_LAYER_KHRONOS_validation"};
const MAX_FRAME_LAG = 3;
allocator: std.mem.Allocator = undefined,
window: *c.SDL_Window = undefined,
vkb: BaseDispatch = undefined,
@ -41,19 +40,20 @@ swapchain: vk.SwapchainKHR = .null_handle,
swapchain_extent: vk.Extent2D = .{ .width = 0, .height = 0 },
swapchain_images: []vk.Image = &.{},
// NOTE: TEST
frame: u32 = 0,
frame_syncs: [MAX_FRAME_LAG]Sync = [1]Sync{.{}} ** MAX_FRAME_LAG,
command_pool: vk.CommandPool = .null_handle,
pipeline_cache: vk.PipelineCache = .null_handle,
const Sync = struct {
acquire_swapchain_image: vk.Semaphore = .null_handle,
draw_sema: vk.Semaphore = .null_handle,
draw_fence: vk.Fence = .null_handle,
pub const CommandPool = struct {
device: Device,
handle: vk.CommandPool,
pub fn waitForDrawAndReset(self: *Sync, gc: *GraphicsContext) !void {
_ = try gc.device.waitForFences(1, &.{self.draw_fence}, vk.TRUE, std.math.maxInt(u64));
try gc.device.resetFences(1, &.{self.draw_fence});
pub fn allocateCommandBuffer(self: *const CommandPool) !CommandBuffer {
var cmd_bufs = [_]vk.CommandBuffer{.null_handle};
try self.device.allocateCommandBuffers(&.{
.command_pool = self.handle,
.level = .primary,
.command_buffer_count = cmd_bufs.len,
}, &cmd_bufs);
return CommandBuffer.init(cmd_bufs[0], self.device.wrapper);
}
};
@ -110,7 +110,10 @@ pub fn init(self: *GraphicsContext, allocator: std.mem.Allocator, window: *c.SDL
const queue_config = try selectQueues(self.instance, self.device_info.physical_device);
const device_create_config = vk.DeviceCreateInfo{
.p_next = @ptrCast(&vk.PhysicalDeviceSynchronization2Features{ .synchronization_2 = vk.TRUE }),
.p_next = &vk.PhysicalDeviceVulkan13Features{
.dynamic_rendering = vk.TRUE,
.synchronization_2 = vk.TRUE,
},
.p_queue_create_infos = &queue_config.queue_create_info,
.queue_create_info_count = queue_config.queue_count,
.p_enabled_features = &self.device_info.features,
@ -158,36 +161,17 @@ pub fn init(self: *GraphicsContext, allocator: std.mem.Allocator, window: *c.SDL
.device_to_host = device_to_host_queue,
};
for (0..MAX_FRAME_LAG) |i| {
self.frame_syncs[i].acquire_swapchain_image = try self.device.createSemaphore(&.{}, null);
self.frame_syncs[i].draw_sema = try self.device.createSemaphore(&.{}, null);
self.frame_syncs[i].draw_fence = try self.device.createFence(&.{ .flags = .{ .signaled_bit = true } }, null);
}
self.command_pool = try self.queues.graphics.createCommandPool(.{});
self.pipeline_cache = try self.device.createPipelineCache(&.{}, null);
}
pub fn draw(self: *GraphicsContext) !void {
var cmd_bufs = [_]vk.CommandBuffer{.null_handle};
try self.device.allocateCommandBuffers(&.{
.command_pool = self.command_pool,
.level = .primary,
.command_buffer_count = cmd_bufs.len,
}, &cmd_bufs);
const test_cmd_buf = CommandBuffer.init(cmd_bufs[0], &self.vkd);
const sync = &self.frame_syncs[self.frame];
try sync.waitForDrawAndReset(self);
// Move this out into a separate func
const swapchain_image_index: u32 = blk: {
pub fn acquireSwapchainImage(self: *GraphicsContext, acuire_semaphore: vk.Semaphore) !u32 {
var found = false;
var swapchain_img: u32 = 0;
try self.maybeResizeSwapchain();
while (!found) {
const acquire_result = try self.device.acquireNextImageKHR(self.swapchain, std.math.maxInt(u64), sync.acquire_swapchain_image, .null_handle);
const acquire_result = try self.device.acquireNextImageKHR(self.swapchain, std.math.maxInt(u64), acuire_semaphore, .null_handle);
switch (acquire_result.result) {
.success, .suboptimal_khr => {
@ -212,86 +196,7 @@ pub fn draw(self: *GraphicsContext) !void {
}
}
break :blk swapchain_img;
};
const current_image = self.swapchain_images[swapchain_image_index];
try test_cmd_buf.beginCommandBuffer(&.{});
{
{
const img_barrier = vk.ImageMemoryBarrier2{
.image = current_image,
.old_layout = .undefined,
.new_layout = .transfer_dst_optimal,
.src_access_mask = .{},
.dst_access_mask = .{},
.src_queue_family_index = self.queues.graphics.family,
.dst_queue_family_index = self.queues.graphics.family,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_array_layer = 0,
.base_mip_level = 0,
.layer_count = 1,
.level_count = 1,
},
};
test_cmd_buf.pipelineBarrier2(&.{
.p_image_memory_barriers = &.{img_barrier},
.image_memory_barrier_count = 1,
});
}
test_cmd_buf.clearColorImage(current_image, .transfer_dst_optimal, &.{ .float_32 = .{ 0.8, 0.7, 0.6, 1.0 } }, 1, &.{.{
.aspect_mask = .{ .color_bit = true },
.base_array_layer = 0,
.base_mip_level = 0,
.layer_count = 1,
.level_count = 1,
}});
{
const img_barrier = vk.ImageMemoryBarrier2{
.image = current_image,
.old_layout = .transfer_dst_optimal,
.new_layout = .present_src_khr,
.src_access_mask = .{},
.dst_access_mask = .{},
.src_queue_family_index = self.queues.graphics.family,
.dst_queue_family_index = self.queues.graphics.family,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_array_layer = 0,
.base_mip_level = 0,
.layer_count = 1,
.level_count = 1,
},
};
test_cmd_buf.pipelineBarrier2(&.{
.p_image_memory_barriers = &.{img_barrier},
.image_memory_barrier_count = 1,
});
}
}
try test_cmd_buf.endCommandBuffer();
try self.queues.graphics.submit(
&SubmitInfo{
.wait_semaphores = &.{sync.acquire_swapchain_image},
.wait_dst_stage_mask = &.{.{ .transfer_bit = true }},
.command_buffers = &.{test_cmd_buf.handle},
.signal_semaphores = &.{sync.draw_sema},
},
sync.draw_fence,
);
_ = try self.device.queuePresentKHR(self.queues.graphics.handle, &.{
.swapchain_count = 1,
.wait_semaphore_count = 1,
.p_wait_semaphores = &.{sync.draw_sema},
.p_swapchains = &.{self.swapchain},
.p_image_indices = &.{swapchain_image_index},
});
self.frame = (self.frame + 1) % MAX_FRAME_LAG;
return swapchain_img;
}
fn maybeResizeSwapchain(self: *GraphicsContext) !void {
@ -353,11 +258,14 @@ pub const QueueInstance = struct {
handle: vk.Queue,
family: u32,
pub fn createCommandPool(self: *Self, flags: vk.CommandPoolCreateFlags) !vk.CommandPool {
return self.device.createCommandPool(&.{
pub fn createCommandPool(self: *Self, flags: vk.CommandPoolCreateFlags) !CommandPool {
return .{
.handle = try self.device.createCommandPool(&.{
.flags = flags,
.queue_family_index = self.family,
}, null);
}, null),
.device = self.device,
};
}
pub fn submit(self: *Self, info: *const SubmitInfo, fence: vk.Fence) Device.QueueSubmitError!void {

181
src/Render2.zig Normal file
View File

@ -0,0 +1,181 @@
const std = @import("std");
const AssetManager = @import("AssetManager.zig");
const GraphicsContext = @import("GraphicsContext.zig");
const vk = @import("vk");
const a = @import("asset_manifest");
const Render2 = @This();
const MAX_FRAME_LAG = 3;
assetman: *AssetManager,
gc: *GraphicsContext,
command_pool: GraphicsContext.CommandPool,
// NOTE: TEST
frame: u32 = 0,
frame_syncs: [MAX_FRAME_LAG]Sync = [1]Sync{.{}} ** MAX_FRAME_LAG,
pub fn init(assetman: *AssetManager, gc: *GraphicsContext) !Render2 {
var self = Render2{
.assetman = assetman,
.gc = gc,
.command_pool = try gc.queues.graphics.createCommandPool(.{}),
};
// NOTE: TEST
for (0..MAX_FRAME_LAG) |i| {
self.frame_syncs[i].acquire_swapchain_image = try self.gc.device.createSemaphore(&.{}, null);
self.frame_syncs[i].draw_sema = try self.gc.device.createSemaphore(&.{}, null);
self.frame_syncs[i].draw_fence = try self.gc.device.createFence(&.{ .flags = .{ .signaled_bit = true } }, null);
}
return self;
}
pub fn draw(self: *Render2) !void {
const sync = &self.frame_syncs[self.frame];
try sync.waitForDrawAndReset(self.gc.device);
// Move this out into a separate func
const swapchain_image_index: u32 = try self.gc.acquireSwapchainImage(sync.acquire_swapchain_image);
const current_image = self.gc.swapchain_images[swapchain_image_index];
const current_image_view = try self.gc.device.createImageView(&.{
.components = .{ .r = .r, .g = .g, .b = .b, .a = .a },
.format = .r8g8b8a8_unorm,
.view_type = .@"2d",
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_array_layer = 0,
.base_mip_level = 0,
.layer_count = 1,
.level_count = 1,
},
.image = current_image,
}, null);
defer self.gc.device.destroyImageView(current_image_view, null);
const cmds = try self.command_pool.allocateCommandBuffer();
try cmds.beginCommandBuffer(&.{});
{
{
const img_barrier = vk.ImageMemoryBarrier2{
.image = current_image,
.old_layout = .undefined,
.new_layout = .color_attachment_optimal,
.src_access_mask = .{},
.dst_access_mask = .{ .color_attachment_write_bit = true },
.dst_stage_mask = .{ .color_attachment_output_bit = true },
.src_queue_family_index = self.gc.queues.graphics.family,
.dst_queue_family_index = self.gc.queues.graphics.family,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_array_layer = 0,
.base_mip_level = 0,
.layer_count = 1,
.level_count = 1,
},
};
cmds.pipelineBarrier2(&.{
.p_image_memory_barriers = &.{img_barrier},
.image_memory_barrier_count = 1,
});
}
{
cmds.beginRendering(&.{
.render_area = vk.Rect2D{ .offset = .{ .x = 0, .y = 0 }, .extent = self.gc.swapchain_extent },
.layer_count = 1,
.view_mask = 0,
.color_attachment_count = 1,
.p_color_attachments = &.{
vk.RenderingAttachmentInfo{
.clear_value = .{ .color = .{ .float_32 = .{ 0.8, 0.7, 0.6, 1.0 } } },
.load_op = .clear,
.store_op = .store,
.image_layout = .color_attachment_optimal,
.image_view = current_image_view,
.resolve_image_layout = .color_attachment_optimal,
.resolve_mode = .{},
},
},
});
defer cmds.endRendering();
cmds.bindPipeline(.graphics, self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.triangle).pipeline);
cmds.setViewportWithCount(1, &.{vk.Viewport{
.x = 0,
.y = 0,
.width = @floatFromInt(self.gc.swapchain_extent.width),
.height = @floatFromInt(self.gc.swapchain_extent.height),
.min_depth = 0,
.max_depth = 1,
}});
cmds.setScissorWithCount(1, &.{vk.Rect2D{
.offset = .{ .x = 0, .y = 0 },
.extent = self.gc.swapchain_extent,
}});
cmds.draw(3, 1, 0, 0);
}
{
const img_barrier = vk.ImageMemoryBarrier2{
.image = current_image,
.old_layout = .color_attachment_optimal,
.new_layout = .present_src_khr,
.src_access_mask = .{ .color_attachment_write_bit = true },
.dst_access_mask = .{},
.src_stage_mask = .{ .color_attachment_output_bit = true },
.src_queue_family_index = self.gc.queues.graphics.family,
.dst_queue_family_index = self.gc.queues.graphics.family,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_array_layer = 0,
.base_mip_level = 0,
.layer_count = 1,
.level_count = 1,
},
};
cmds.pipelineBarrier2(&.{
.p_image_memory_barriers = &.{img_barrier},
.image_memory_barrier_count = 1,
});
}
}
try cmds.endCommandBuffer();
try self.gc.queues.graphics.submit(
&GraphicsContext.SubmitInfo{
.wait_semaphores = &.{sync.acquire_swapchain_image},
.wait_dst_stage_mask = &.{.{ .transfer_bit = true }},
.command_buffers = &.{cmds.handle},
.signal_semaphores = &.{sync.draw_sema},
},
sync.draw_fence,
);
_ = try self.gc.device.queuePresentKHR(self.gc.queues.graphics.handle, &.{
.swapchain_count = 1,
.wait_semaphore_count = 1,
.p_wait_semaphores = &.{sync.draw_sema},
.p_swapchains = &.{self.gc.swapchain},
.p_image_indices = &.{swapchain_image_index},
});
self.frame = (self.frame + 1) % MAX_FRAME_LAG;
}
const Sync = struct {
acquire_swapchain_image: vk.Semaphore = .null_handle,
draw_sema: vk.Semaphore = .null_handle,
draw_fence: vk.Fence = .null_handle,
pub fn waitForDrawAndReset(self: *Sync, device: GraphicsContext.Device) !void {
_ = try device.waitForFences(1, &.{self.draw_fence}, vk.TRUE, std.math.maxInt(u64));
try device.resetFences(1, &.{self.draw_fence});
}
};

View File

@ -153,13 +153,16 @@ pub const ShaderProgram = union(ShaderProgramPipelineType) {
if (!serializer.write) {
self.* = .{ .graphics = undefined };
}
try serializer.skipAlign(4);
try serializer.serializeByteSlice(&self.graphics.vertex.source);
try serializer.skipAlign(4);
try serializer.serializeByteSlice(&self.graphics.fragment.source);
},
.compute => {
if (!serializer.write) {
self.* = .{ .compute = undefined };
}
try serializer.skipAlign(4);
try serializer.serializeByteSlice(&self.compute.compute.source);
},
}
@ -217,11 +220,23 @@ pub const Serializer = struct {
}
}
pub fn skipAlign(self: *Serializer, alignment: u64) !void {
const pos = try self.stream.getPos();
const new_pos = std.mem.alignForward(u64, pos, alignment);
try self.stream.seekTo(new_pos);
}
pub fn serializeBytes(self: *Serializer, data: *[]u8) !void {
if (self.write) {
_ = try self.stream.write(data.*);
} else {
_ = try self.stream.read(data.*);
switch (self.stream) {
.buffer => |*buf| {
data.* = buf.buffer[buf.pos .. buf.pos + data.len];
buf.seekBy(@intCast(data.len)) catch @panic("INVALID READ STREAM SIZE");
},
else => @panic("UNSUPPORTED READ STREAM"),
}
}
}

View File

@ -6,6 +6,7 @@ const c = @import("sdl.zig");
// const gl = @import("gl.zig");
const AssetManager = @import("AssetManager.zig");
const Render = @import("Render.zig");
const Render2 = @import("Render2.zig");
const formats = @import("formats.zig");
const za = @import("zalgebra");
const Vec2 = za.Vec2;
@ -173,7 +174,8 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
globals.g_mem.* = .{
.global_allocator = global_allocator.*,
.frame_fba = std.heap.FixedBufferAllocator.init(frame_arena_buffer),
.assetman = AssetManager.init(global_allocator.*, globals.g_mem.frame_fba.allocator()),
.assetman = AssetManager.init(global_allocator.*, globals.g_mem.frame_fba.allocator(), &globals.g_init.gc),
.render2 = Render2.init(&globals.g_mem.assetman, &globals.g_init.gc) catch @panic("OOM"),
// .render = Render.init(global_allocator.*, globals.g_mem.frame_fba.allocator(), &globals.g_mem.assetman),
.world = .{ .frame_arena = globals.g_mem.frame_fba.allocator() },
};
@ -461,7 +463,7 @@ export fn game_update() bool {
}
}
ginit.gc.draw() catch @panic("draw error");
gmem.render2.draw() catch @panic("RENDER ERROR");
// Render
if (false) {

View File

@ -1,6 +1,7 @@
const std = @import("std");
const c = @import("sdl.zig");
const Render = @import("Render.zig");
const Render2 = @import("Render2.zig");
const AssetManager = @import("AssetManager.zig");
const World = @import("entity.zig").World;
const GraphicsContext = @import("GraphicsContext.zig");
@ -36,6 +37,7 @@ pub const GameMemory = struct {
frame_fba: std.heap.FixedBufferAllocator,
assetman: AssetManager,
render: Render = undefined,
render2: Render2,
performance_frequency: u64 = 0,
last_frame_time: u64 = 0,
delta_time: f32 = 0.0000001,