Vulkan TRIANGLE!!!
This commit is contained in:
parent
f0c9e04887
commit
fe69fa1f51
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
181
src/Render2.zig
Normal 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});
|
||||
}
|
||||
};
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user