forked from vv/efemra
1
0
Fork 0

lots more goodies and compiling again

This commit is contained in:
Vivianne 2022-07-18 03:14:55 -07:00
parent dd30befb3c
commit 4b59b2d387
20 changed files with 808 additions and 147 deletions

View File

@ -1 +1,88 @@
pub const Float4 = @Vector(4, f32);
const std = @import("std");
pub const Float4 = packed struct {
const Self = @This();
x: f32 = 0,
y: f32 = 0,
z: f32 = 0,
w: f32 = 0,
pub inline fn add(lhs: Self, rhs: Self) Self {
return Self{
.x = lhs.x + rhs.x,
.y = lhs.y + rhs.y,
.z = lhs.z + rhs.z,
.w = lhs.w + rhs.w,
};
}
pub inline fn sub(lhs: Self, rhs: Self) Self {
return Self{
.x = lhs.x - rhs.x,
.y = lhs.y - rhs.y,
.z = lhs.z - rhs.z,
.w = lhs.w - rhs.w,
};
}
pub inline fn mul(lhs: Self, rhs: Self) Self {
return Self{
.x = lhs.x * rhs.x,
.y = lhs.y * rhs.y,
.z = lhs.z * rhs.z,
.w = lhs.w * rhs.w,
};
}
pub inline fn mulvs(lhs: Self, rhs: f32) Self {
return Self{
.x = lhs.x * rhs,
.y = lhs.y * rhs,
.z = lhs.z * rhs,
.w = lhs.w * rhs,
};
}
pub inline fn divvs(lhs: Self, rhs: f32) Self {
return lhs.mulvs(1.0 / rhs);
}
pub inline fn sum3(self: Self) f32 {
return self.x + self.y + self.z;
}
pub inline fn dot3(a: Self, b: Self) f32 {
return a.mul(b).sum3();
}
pub inline fn zxy(self: Self) Self {
return Self{
.x = self.z,
.y = self.x,
.z = self.y,
.w = 0,
};
}
pub inline fn cross3(a: Self, b: Self) Self {
return zxy(sub(mul(zxy(a), b), mul(a, zxy(b))));
}
pub inline fn max(a: Self, b: Self) Self {
return Self{
.x = @maximum(a.x, b.x),
.y = @maximum(a.y, b.y),
.z = @maximum(a.z, b.z),
.w = @maximum(a.w, b.w),
};
}
pub inline fn length3(self: Self) f32 {
return @sqrt(@maximum(std.math.f32_epsilon, self.dot3(self)));
}
pub inline fn normalize3(self: Self) Self {
return self.divvs(self.length3());
}
};

View File

@ -1,9 +1,64 @@
const std = @import("std");
const Float4 = @import("float4.zig").Float4;
// TODO: comptime magic?
pub const Float4x4 = packed struct {
c0: Float4,
c1: Float4,
c2: Float4,
c3: Float4,
const Self = @This();
const zero = Self{};
c0: Float4 = Float4{},
c1: Float4 = Float4{},
c2: Float4 = Float4{},
c3: Float4 = Float4{},
pub inline fn mulCol(self: Self, col: Float4) Float4 {
const a = self.c0.mulvs(col.x);
const b = self.c1.mulvs(col.y);
const c = self.c2.mulvs(col.z);
const d = self.c0.mulvs(col.w);
return a.add(b).add(c.add(d));
}
pub inline fn mul(a: Self, b: Self) Self {
return Self{
.c0 = a.mulCol(b.c0),
.c1 = a.mulCol(b.c1),
.c2 = a.mulCol(b.c2),
.c3 = a.mulCol(b.c3),
};
}
pub inline fn lookAt(eye: Float4, at: Float4, up: Float4) Float4x4 {
// right-handed (ew)
const f = at.sub(eye).normalize3();
const s = f.cross3(up).normalize3();
const u = s.cross3(f).normalize3();
const tx = -s.dot3(eye);
const ty = -u.dot3(eye);
const tz = f.dot3(eye);
return Float4x4{
.c0 = .{ .x = s.x, .y = u.x, .z = -f.x, .w = 0 },
.c1 = .{ .x = s.y, .y = u.y, .z = -f.y, .w = 0 },
.c2 = .{ .x = s.z, .y = u.z, .z = -f.z, .w = 0 },
.c3 = .{ .x = tx, .y = ty, .z = tz, .w = 1 },
};
}
pub inline fn glPerspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) Self {
const t = std.math.tan(fov_y * 0.5);
var m = zero;
m.c0.x = 1.0 / (aspect * t);
m.c1.y = 1.0 / t;
m.c2.z = -1.0 * (z_far * z_near) / (z_far - z_near);
m.c3.z = -2.0 * (z_far * z_near) / (z_far - z_near);
return m;
}
pub inline fn vkPerspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) Self {
var m = glPerspective(fov_y, aspect, z_near, z_far);
m.c1.y *= -1.0;
return m;
}
};

29
src/math/quat.zig Normal file
View File

@ -0,0 +1,29 @@
const Float4 = @import("float4.zig").Float4;
pub const Quat = struct {
const Self = @This();
v: Float4,
pub inline fn mulDir(q: Self, dir: Float4) Float4 {
const uv = q.v.cross3(dir);
const uuv = q.v.cross3(uv);
var y = uv.mulvs(q.v.w);
y = y.add(uuv);
y = y.mulvs(2);
y = y.add(dir);
return y;
}
pub inline fn fwd(q: Self) Float4 {
const dir = Float4{ .x = 0, .y = 0, .z = -1, .w = 0 };
return q.mulDir(dir);
}
pub inline fn up(q: Self) Float4 {
const dir = Float4{ .x = 0, .y = 1, .z = 0, .w = 0 };
return q.mulDir(dir);
}
};

View File

@ -0,0 +1,32 @@
const std = @import("std");
const Float4 = @import("../math/float4.zig").Float4;
const Float4x4 = @import("../math/float4x4.zig").Float4x4;
const Quat = @import("../math/quat.zig").Quat;
const Self = @This();
var s_camera: Self = std.mem.zeroes(Self);
position: Float4,
rotation: Quat,
z_near: f32,
z_far: f32,
fov_y: f32,
pub fn get() Self {
return s_camera;
}
pub inline fn getProj(self: *const Self, aspect: f32) Float4x4 {
return Float4x4.vkPerspective(std.math.degreesToRadians(f32, self.fov_y), aspect, self.z_near, self.z_far);
}
pub inline fn getView(self: *const Self) Float4x4 {
const pos = self.position;
const rot = self.rotation;
return Float4x4.lookAt(pos, pos.add(rot.fwd()), rot.up());
}
pub inline fn getWorldToClip(self: *const Self, aspect: f32) Float4x4 {
return self.getProj(aspect).mul(self.getView());
}

View File

@ -0,0 +1,102 @@
const std = @import("std");
const assert = std.debug.assert;
const vk = @import("vulkan");
const Device = @import("device.zig").Device;
const ProfileMark = @import("../../common/profiler.zig").ProfileMark;
const settings = @import("settings.zig");
const Swapchain = @import("swapchain.zig").Swapchain;
var s_sets = std.mem.zeroes([settings.resource_sets]vk.DescriptorSet);
var s_writes = std.mem.zeroes([settings.Bid.Count]vk.WriteDescriptorSet);
var s_bindings = std.mem.zeroes([settings.Bid.Count]Binding);
var s_dirty = std.mem.zeroes([settings.Bid.Count]i32);
const pm_update = ProfileMark.init("Bindings.update");
pub fn update(device: *const Device, swapchain: *const Swapchain) void {
pm_update.begin();
defer pm_update.end();
// kara says: why do validation layers think there is a command buffer in flight using this desc set?
// submit.awaitAll();
//const set = getSet(swapchain);
// TexTable.write(set);
flush(device, swapchain);
}
pub fn getSet(swapchain: *const Swapchain) vk.DescriptorSet {
const sync_index = swapchain.sync_index;
assert(sync_index < s_sets.len);
assert(s_sets[sync_index] != .null_handle);
return s_sets[sync_index];
}
const pm_flush = ProfileMark.init("Bindings.flush");
pub fn flush(device: *const Device, swapchain: *const Swapchain) void {
pm_flush.begin();
defer pm_flush.end();
const set = getSet(swapchain);
var write_count: i32 = 0;
for (s_bindings) |binding, i| {
assert(s_dirty[i] >= 0);
if (s_dirty[i] <= 0) {
continue;
}
s_dirty[i] -= 1;
var write = &s_writes[write_count];
write_count += 1;
write.* = .{
.s_type = .write_descriptor_set,
.descriptor_type = binding.desc_type,
.dst_set = set,
.dst_binding = i,
.dst_array_element = 0,
.descriptor_count = 1,
};
switch (binding.info) {
.buffer => |*buffer| {
switch (binding.desc_type) {
.uniform_buffer, .storage_buffer, .uniform_buffer_dynamic, .storage_buffer_dynamic => {
write.p_buffer_info = buffer;
},
else => {
assert(false);
},
}
},
.image => |*image| {
switch (binding.desc_type) {
.sampler, .combined_image_sampler, .sampled_image, .storage_image, .input_attachment => {
write.p_image_info = image;
},
else => {
assert(false);
},
}
},
}
if (write_count > 0) {
device.dispatch.updateDescriptorSets(device.handle, write_count, s_writes, 0, null);
}
}
}
pub const Binding = struct {
const Type = enum {
buffer,
image,
};
const Union = union(Type) {
buffer: vk.DescriptorBufferInfo,
image: vk.DescriptorImageInfo,
};
desc_type: vk.DescriptorType,
info: Union,
};

View File

@ -14,6 +14,7 @@ const Renderer = @import("Renderer.zig");
const SubmitId = @import("submit_id.zig").SubmitId;
const Fence = @import("sync.zig").Fence;
const Semaphore = @import("sync.zig").Semaphore;
const Bindings = @import("Bindings.zig");
const queues = @import("queues.zig");
@ -210,18 +211,36 @@ pub const Buffer = struct {
self.ended = false;
}
pub fn bindDescSets(self: *Self, device: *const Device, bindpoint: vk.PipelineBindPoint, layout: vk.PipelineLayout, set_count: u32, sets: [*]const vk.DescriptorSet) void {
assert(self.handle != .null_handle);
assert(self.gfx or self.comp);
assert(layout != .null_handle);
if (set_count > 0) {
device.dispatch.cmdBindDescriptorSets(self.handle, bindpoint, layout, 0, set_count, sets, 0, undefined);
}
}
pub fn bindPass(self: *Self, device: *const Device, swapchain: *const Swapchain, pass: *const Pass) void {
assert(self.handle != .null_handle);
assert(self.gfx or self.comp);
assert(pass.pipeline != .null_handle);
device.dispatch.cmdBindPipeline(self.handle, pass.bindpoint, pass.pipeline);
const set = Bindings.getSet(swapchain);
self.bindDescSets(device, pass.bindpoint, pass.layout, 1, @ptrCast([*]const vk.DescriptorSet, &set));
}
const pm_buffer_beginrenderpass = ProfileMark.init("Command.Buffer.beginRenderPass");
pub fn beginRenderPass(self: *Self, device: *const Device, pass: vk.RenderPass, framebuf: vk.Framebuffer, rect: vk.Rect2D, clear_values: []*const vk.ClearValue) void {
pub fn beginRenderPass(self: *Self, device: *const Device, pass: vk.RenderPass, framebuf: vk.Framebuffer, rect: vk.Rect2D, clear_values: []const vk.ClearValue) void {
pm_buffer_beginrenderpass.begin();
defer pm_buffer_beginrenderpass.end();
assert(self.handle != .null_handle);
assert(!self.in_render_pass);
device.dispatch.beginRenderPass(self.handle, &.{
device.dispatch.cmdBeginRenderPass(self.handle, &.{
.render_pass = pass,
.framebuffer = framebuf,
.render_area = rect,
.clear_value_count = clear_values.len,
.clear_value_count = @intCast(u32, clear_values.len),
.p_clear_values = clear_values.ptr,
}, .@"inline");
self.in_render_pass = true;
@ -239,7 +258,7 @@ pub const Buffer = struct {
assert(self.handle != .null_handle);
assert(self.in_render_pass);
device.dispatch.cmdEndRenderPass(self.handle);
self.in_render_pass = 0;
self.in_render_pass = false;
self.subpass = 0;
}
@ -262,19 +281,19 @@ pub const Buffer = struct {
assert(self.handle != .null_handle);
assert(self.gfx or self.comp);
assert(size == pass.push_constant_bytes);
assert(pass.layout.toInt() != 0);
assert(pass.layout != .null_handle);
assert(pass.stage_flags.toInt() != 0);
device.dispatch.cmdPushConstants(self.handle, pass.layout, pass.stage_flags, 0, size, constants);
}
pub fn viewport(self: *Self, device: *const Device, vp: vk.Viewport, scissor: vk.Rect2D) void {
assert(self.handle != .null_handle);
device.dispatch.cmdSetViewport(self.handle, 0, 1, &vp);
device.dispatch.cmdSetScissor(self.handle, 0, 1, &scissor);
device.dispatch.cmdSetViewport(self.handle, 0, 1, @ptrCast([*]const vk.Viewport, &vp));
device.dispatch.cmdSetScissor(self.handle, 0, 1, @ptrCast([*]const vk.Rect2D, &scissor));
}
pub fn defaultViewport(self: *Self) void {
self.viewport(Swapchain.getViewport(), Swapchain.getRect());
pub fn defaultViewport(self: *Self, device: *const Device, swapchain: *const Swapchain) void {
self.viewport(device, swapchain.getViewport(), swapchain.getRect());
}
pub fn draw(self: *Self, device: *const Device, vertex_count: i32, first_vertex: i32) void {
@ -303,6 +322,10 @@ pub const Buffer = struct {
pm_buffer_submit.begin();
defer pm_buffer_submit.end();
_ = wait_sema;
_ = signal_sema;
_ = wait_mask;
assert(self.began);
assert(!self.ended);
assert(!self.submitted);

View File

@ -12,9 +12,8 @@ const Self = @This();
pub var context: Self = Self{};
pub fn init() Self {
pub fn init() void {
context = std.mem.zeroes(@This());
return context;
}
pub fn deinit() void {

View File

@ -10,7 +10,7 @@ const Camera = @import("../Camera.zig");
const Shader = @import("Shader.zig");
const Pass = @import("Pass.zig");
const framebuffer = @import("framebuffer.zig");
const DepthBuffer = @import("DepthBuffer.zig");
const Targets = @import("Targets.zig");
const RenderPass = @import("RenderPass.zig");
const Float4 = @import("../../math/float4.zig").Float4;
const Float4x4 = @import("../../math/float4x4.zig").Float4x4;
@ -19,14 +19,14 @@ const PushConstants = struct {
local_to_clip: Float4x4,
};
pub fn init() !void {
pub fn init(device: *const Device, swapchain: *Swapchain) !void {
errdefer {
std.debug.print("Failed to init MainPass");
std.debug.print("Failed to init MainPass", .{});
deinit();
}
// try ScreenBlit.init()
try DepthPass.init();
try DepthPass.init(device, swapchain);
try OpaquePass.init();
// try Exposure.init();
// try UIPass.init();
@ -52,12 +52,12 @@ pub fn setup() void {
}
const pm_execute = ProfileMark.init("MainPass.execute");
pub fn execute() void {
pub fn execute(device: *const Device, swapchain: *Swapchain) !void {
pm_execute.begin();
defer pm_execute.end();
// todo: pt_trace convar check
DepthPass.execute();
try DepthPass.execute(device, swapchain);
OpaquePass.execute();
// Exposure.execute();
@ -68,10 +68,10 @@ const DepthPass = struct {
var s_render_pass: vk.RenderPass = undefined;
var s_pass: Pass = undefined;
pub fn init() !void {
pub fn init(device: *const Device, swapchain: *Swapchain) !void {
errdefer DepthPass.deinit();
const depth_buffer = DepthBuffer.get();
const depth_buffer = swapchain.getDepthBuffer();
var info = RenderPass.Description{
.src_stage_mask = .{ .early_fragment_tests_bit = true },
@ -83,51 +83,49 @@ const DepthPass = struct {
info.attachments[0] = .{
.format = depth_buffer.format,
.layout = .depth_stencil_attachment_optimal,
.load = vk.VK_ATTACHMENT_LOAD_OP_CLEAR,
.store = vk.VK_ATTACHMENT_LOAD_OP_STORE,
.load = .clear,
.store = .store,
};
s_render_pass = try RenderPass.get(&info);
s_render_pass = try RenderPass.get(device, info);
var shaders = std.mem.zeroes([2]vk.PipelineShaderStageCreateInfo);
var shaders: [2]vk.PipelineShaderStageCreateInfo = undefined;
try Shader.init(&shaders[0], "DepthOnly.hlsl", "VSMain", .vertex);
errdefer Shader.deinit(&shaders[0]);
try Shader.init(&shaders[1], "DepthOnly.hlsl", "PSMain", .fragment);
errdefer Shader.deinit(&shaders[1]);
const vert_bindings = []vk.VertexInputBindingDescription{
var vert_bindings = [_]vk.VertexInputBindingDescription{
.{
.binding = 0,
.stride = @sizeOf(Float4),
.input_rate = .vertex,
},
};
const vert_attributes = []vk.VertexInputAtttributeDescription{
var vert_attributes = [_]vk.VertexInputAttributeDescription{
.{
.binding = 0,
.format = .r32g32b32a32_sfloat,
.location = 0,
.offset = 0,
},
};
try Pass.new(&s_pass, &.{
const createInfo = Pass.Description{
.push_constant_bytes = @sizeOf(PushConstants),
.shader_count = shaders.len,
.shaders = shaders,
.shaders = &shaders,
.render_pass = s_render_pass,
.subpass = 0,
.subpass = -1,
.vert_layout = .{
.binding_count = vert_bindings.len,
.bindings = vert_bindings.ptr,
.attribute_count = vert_attributes.len,
.attributes = vert_attributes.ptr,
.bindings = &vert_bindings,
.attributes = &vert_attributes,
},
.fixed_funcs = .{
.viewport = Swapchain.getViewport(),
.scissor = Swapchain.getRect(),
.viewport = swapchain.getViewport(),
.scissor = swapchain.getRect(),
.topology = .triangle_list,
.polygon_mode = .fill,
.front_face = .counter_clockwise,
.cull_mode = .back_bit,
.cull_mode = .{ .back_bit = true },
.depth_compare_op = .less,
.scissor_on = false,
.depth_clamp = false,
@ -135,7 +133,8 @@ const DepthPass = struct {
.depth_write_enable = true,
.attachment_count = 0,
},
});
};
try Pass.init(&s_pass, &createInfo);
}
pub fn deinit() void {
@ -145,15 +144,15 @@ const DepthPass = struct {
pub fn setup() void {}
const pm_depth_execute = ProfileMark.init("DepthPass.execute");
pub fn execute(device: *const Device) void {
pub fn execute(device: *const Device, swapchain: *Swapchain) !void {
pm_depth_execute.begin();
defer pm_depth_execute.end();
const camera = Camera.get();
const world_to_clip = camera.getWorldToClip(Swapchain.getAspect());
const world_to_clip = camera.getWorldToClip(swapchain.getAspect());
const attachments = []Image{DepthBuffer.get()};
const attachments = &[_]*Image{swapchain.getDepthBuffer()};
const rect = vk.Rect2D{
.offset = std.mem.zeroes(vk.Offset2D),
.extent = .{
@ -162,14 +161,14 @@ const DepthPass = struct {
},
};
const fbuf = framebuffer.get(attachments, rect.extent.width, rect.extent.height);
const fbuf = try framebuffer.getOrAdd(device, attachments, rect.extent.width, rect.extent.height);
const cmd = try Command.Buffer.get(.graphics, device);
Image.State.depthAttachWrite(cmd, attachments[0]);
_ = try Image.State.depthAttachWrite(device, cmd, attachments[0]);
cmd.defaultViewport(device);
cmd.bindPass(device, &s_pass);
cmd.beginRenderPass(device, s_render_pass, fbuf, rect, .{
cmd.defaultViewport(device, swapchain);
cmd.bindPass(device, swapchain, &s_pass);
cmd.beginRenderPass(device, s_render_pass, fbuf, rect, &.{
.{
.depth_stencil = .{ .depth = 1.0, .stencil = 0.0 },
},
@ -184,4 +183,12 @@ const DepthPass = struct {
}
};
const OpaquePass = struct {};
const OpaquePass = struct {
pub fn init() !void {}
pub fn deinit() void {}
pub fn setup() void {}
pub fn execute() void {}
};

View File

@ -0,0 +1,61 @@
const vk = @import("vulkan");
const Self = @This();
pipeline: vk.Pipeline,
layout: vk.PipelineLayout,
bindpoint: vk.PipelineBindPoint,
stage_flags: vk.ShaderStageFlags,
push_constant_bytes: i32,
const VertexLayout = struct {
bindings: []vk.VertexInputBindingDescription,
attributes: []vk.VertexInputAttributeDescription,
};
const BlendState = struct {
color_wite_mask: vk.ColorComponentFlags,
blend_enable: bool,
src_color_blend_factor: vk.BlendFactor,
dst_color_blend_factor: vk.BlendFactor,
color_blend_op: vk.BlendOp,
src_alpha_blend_factor: vk.BlendFactor,
dst_alpha_blend_factor: vk.BlendFactor,
alpha_blend_op: vk.BlendOp,
};
const FixedFuncs = struct {
viewport: vk.Viewport,
scissor: vk.Rect2D,
topology: vk.PrimitiveTopology,
polygon_mode: vk.PolygonMode,
cull_mode: vk.CullModeFlags,
front_face: vk.FrontFace,
depth_compare_op: vk.CompareOp,
scissor_on: bool,
depth_clamp: bool,
depth_test_enable: bool,
depth_write_enable: bool,
attachment_count: u3,
attachments: ?[8]BlendState = null,
};
pub const Description = struct {
// Graphics and compute
push_constant_bytes: i32,
shaders: []vk.PipelineShaderStageCreateInfo,
// Graphics only
render_pass: vk.RenderPass,
subpass: i32,
vert_layout: VertexLayout,
fixed_funcs: FixedFuncs,
};
pub fn init(self: *Self, desc: *const Description) !void {
_ = self;
_ = desc;
}
pub fn deinit(self: *Self) void {
_ = self;
}

View File

@ -1,13 +1,14 @@
const std = @import("std");
const vk = @import("vulkan");
const profiler = @import("/common/profiler.zig");
const profiler = @import("../../common/profiler.zig");
const Device = @import("device.zig").Device;
const vkd = @import("device.zig").DeviceDispatch;
const allocator: std.mem.Allocator = undefined;
// TODO memory
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
const s_cache = std.HashMap(Description, vk.RenderPass).init(allocator);
var s_cache = std.AutoHashMap(Description, vk.RenderPass).init(allocator);
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#renderpass-compatibility
// compatibility:
@ -16,8 +17,8 @@ const s_cache = std.HashMap(Description, vk.RenderPass).init(allocator);
const AttachmentState = packed struct {
format: vk.Format, // must match
layout: vk.ImageLayout, // can vary
load: u2, // vk.AttachmentLoadOp, can vary
store: u2, // vk.AttachmentStoreOp, can vary
load: vk.AttachmentLoadOp, // can vary
store: vk.AttachmentStoreOp, // can vary
};
pub const Description = struct {
@ -29,32 +30,31 @@ pub const Description = struct {
};
const pm_get = profiler.ProfileMark.init("renderpass.get");
pub fn get(desc: *const Description) !vk.RenderPass {
pub fn get(device: *const Device, desc: Description) !vk.RenderPass {
pm_get.begin();
defer pm_get.end();
const result = try s_cache.getOrPut(desc);
if (result.found_existing) {
return result.value_ptr;
return result.value_ptr.*;
}
const attachments = [8]vk.AttachmentDescription{};
const refs = [attachments.len]vk.AttachmentReference{};
var attachment_count = 0;
var ref_count = 0;
var attachments = std.mem.zeroes([8]vk.AttachmentDescription);
var refs = std.mem.zeroes([attachments.len]vk.AttachmentReference);
var attachment_count: u32 = 0;
var ref_count: usize = 0;
const format0 = desc.attachments[0].format;
const zero_is_depth = format0 >= .d16_unorm and format0 <= .d32_sfloat_s8_uint;
const zero_is_depth = @enumToInt(format0) >= @enumToInt(vk.Format.d16_unorm) and @enumToInt(format0) <= @enumToInt(vk.Format.d32_sfloat_s8_uint);
for (desc.attachments) |dst_attachment, i| {
for (desc.attachments) |*src, i| {
attachments[i].load_op = .dont_care;
attachments[i].store_op = .dont_care;
const src = &desc.attachments[i];
if (src.format != .@"undefined") {
std.debug.assert(attachment_count < attachments.len);
const dst = &dst_attachment;
var dst = &attachments[attachment_count];
dst.format = src.format;
dst.initial_layout = src.layout;
dst.samples = .@"1_bit";
dst.samples = .{ .@"1_bit" = true };
dst.stencil_load_op = .dont_care;
dst.stencil_store_op = .dont_care;
dst.load_op = src.load;
@ -75,35 +75,42 @@ pub fn get(desc: *const Description) !vk.RenderPass {
std.debug.assert(attachment_count <= attachments.len);
std.debug.assert(attachment_count <= refs.len);
const color_ref_count = if (zero_is_depth) attachment_count - 1 else attachment_count;
const depth_ref_count = if (zero_is_depth) 1 else 0;
const depth_ref_count = if (zero_is_depth) @as(u32, 1) else 0;
const handle = try new(attachment_count, attachments, 1, &.{
const subpasses = [_]vk.SubpassDescription{.{
.flags = .{},
.input_attachment_count = 0,
.p_input_attachments = undefined,
.p_resolve_attachments = null,
.preserve_attachment_count = 0,
.p_preserve_attachments = undefined,
.pipeline_bind_point = .graphics,
.color_attachment_count = color_ref_count,
.p_color_attachments = if (color_ref_count) &refs[depth_ref_count] else null,
.p_depth_stencil_attachment = if (depth_ref_count) &refs[0] else null,
}, 1, &.{
.src_subpass = .external,
.p_color_attachments = if (color_ref_count > 0) @ptrCast([*]const vk.AttachmentReference, &refs[depth_ref_count]) else undefined,
.p_depth_stencil_attachment = if (depth_ref_count > 0) @as(?*const vk.AttachmentReference, &refs[0]) else null,
}};
const dependencies = [_]vk.SubpassDependency{.{
.dependency_flags = .{},
.src_subpass = vk.SUBPASS_EXTERNAL,
.dst_subpass = 0,
.src_stage_mask = desc.src_stage_mask,
.dst_stage_mask = desc.dest_stage_mask,
.dst_stage_mask = desc.dst_stage_mask,
.src_access_mask = desc.src_access_mask,
.dst_access_mask = desc.dst_access_mask,
});
}};
const info = vk.RenderPassCreateInfo{
.flags = .{},
.attachment_count = attachment_count,
.p_attachments = &attachments,
.subpass_count = subpasses.len,
.p_subpasses = &subpasses,
.dependency_count = dependencies.len,
.p_dependencies = &dependencies,
};
const handle = try device.dispatch.createRenderPass(device.handle, &info, null);
result.value_ptr.* = handle;
}
fn new(device: *Device, attachment_count: i32, p_attachments: *const vk.AttachmentDescription, subpass_count: i32, p_subpasses: *const vk.SubpassDescription, dependency_count: i32, p_dependencies: *const vk.SubpassDependency) !vk.RenderPass {
const handle: vk.RenderPass = undefined;
try vkd.createRenderPass(device.dev, &.{
.attachment_count = attachment_count,
.p_attachments = p_attachments,
.subpass_count = subpass_count,
.p_subpasses = p_subpasses,
.dependency_count = dependency_count,
.p_dependencies = p_dependencies,
}, null, &handle);
return handle;
return result.value_ptr.*;
}

View File

@ -16,14 +16,12 @@ instance: Instance,
window: Window,
device: Device,
swapchain: Swapchain,
context: Context,
// sampler: Sampler, TODO
// tex_table: TexTable, TODO
// bindings: Bindings, TODO
// targets: Targets, TODO
// mesh_sys: MeshSys, TODO
// im_sys: ImSys, TODO
main_pass: MainPass,
const Self = @This();
@ -49,26 +47,24 @@ pub fn init() !Self {
try framebuffer.init();
errdefer framebuffer.deinit(&device);
const swapchain = try Swapchain.init(&instance, &window, &device, null);
errdefer swapchain.deinit();
var swapchain = try Swapchain.init(&instance, &window, &device, null);
errdefer swapchain.deinit(&device);
const context = Context.init();
errdefer context.deinit();
Context.init();
errdefer Context.deinit();
// try self.sampler.init();
// try self.texTable.init();
// try self.bindings.init();
// try self.targets.init();
// try self.meshSys.init();
// try self.imSys.init();
const main_pass = try MainPass.init();
try MainPass.init(&device, &swapchain);
return Self{
.instance = instance,
.window = window,
.device = device,
.swapchain = swapchain,
.context = context,
.main_pass = main_pass,
};
}
@ -89,14 +85,14 @@ pub fn update(self: *Self) !void {
// setup phase
{
self.main_pass.setup();
MainPass.setup();
// TODO textable update
try Command.flush(&self.device);
// TODO bindings update
}
// execute phase
self.main_pass.execute();
try MainPass.execute(&self.device, &self.swapchain);
// present phase
// currently only graphics queue
@ -114,7 +110,7 @@ pub fn deinit(self: Self) void {
// TODO: delete lightmap pack
self.main_pass.deinit();
MainPass.deinit();
// self.imSys.deinit();
// self.meshSys.deinit();
@ -162,7 +158,7 @@ fn windowUpdate(self: Self) !void {
self.device.waitIdle();
// TODO: UI pass del
self.swapchain.deinit();
self.swapchain.deinit(&self.device);
self.window.deinit();
self.window.init();

View File

@ -0,0 +1,12 @@
const vk = @import("vulkan");
const Thingie = enum {
vertex,
fragment,
};
pub fn init(info: *const vk.PipelineShaderStageCreateInfo, file_path: []const u8, section: []const u8, thingie: Thingie) !void {
_ = info;
_ = file_path;
_ = section;
_ = thingie;
}

View File

@ -0,0 +1,140 @@
const assert = @import("std").debug.assert;
const vk = @import("vulkan");
const Device = @import("device.zig").Device;
const Swapchain = @import("swapchain.zig").Swapchain;
const settings = @import("settings.zig");
const queues = @import("queues.zig");
const Image = @import("image.zig").Image;
const Self = @This();
width: i32,
height: i32,
depth: [settings.resource_sets]Image,
scene: [settings.resource_sets]Image,
// TODO: scaled render resolution
pub fn getDesiredWidth(swapchain: *const Swapchain) i32 {
getDisplayWidth(swapchain);
}
pub fn getDesiredHeight(swapchain: *const Swapchain) i32 {
getDisplayHeight(swapchain);
}
var s_targets: Self = undefined;
pub fn init(device: *const Device, swapchain: *const Swapchain) !void {
errdefer deinit(device);
const width = getDesiredWidth(swapchain);
const height = getDesiredHeight(swapchain);
s_targets.width = width;
s_targets.height = height;
for (s_targets.scene) |*s| {
const usage: vk.ImageUsageFlags = .{
.color_attachment_bit = true,
.sampled_bit = true,
.storage_bit = true,
.transfer_src_bit = true,
.transfer_dst_bit = true,
};
const queue_family_indices = []u32{
queues.get(.graphics).family,
queues.get(.compute).family,
};
try Image.init(s, &.{
.image_type = .@"2d",
.format = .r16g16b16a16_sfloat,
.extent = .{
.width = width,
.height = height,
.depth = 1,
},
.mip_levels = 1,
.array_layers = 1,
.samples = .@"1_bit",
.tiling = .optimal,
.usage = usage,
.sharing_mode = .exclusive,
.queue_family_index_count = queue_family_indices.len,
.p_queue_family_indices = queue_family_indices.ptr,
.initial_layout = .@"undefined",
}, .gpu_only);
}
for (s_targets.depth) |*d| {
const usage: vk.ImageUsageFlags = .{
.depth_stencil_attachment_bit = true,
.sampled_bit = true,
};
const queue_family_indices = []u32{
queues.get(.graphics).family,
};
try Image.init(d, &.{
.image_type = .@"2d",
.format = .x8_d24_unorm_pack32,
.extent = .{
.width = width,
.height = height,
.depth = 1,
},
.mip_levels = 1,
.array_layers = 1,
.samples = .@"1_bit",
.tiling = .optimal,
.usage = usage,
.sharing_mode = .exclusive,
.queue_family_index_count = queue_family_indices.len,
.p_queue_family_indices = queue_family_indices.ptr,
.initial_layout = .@"undefined",
}, .gpu_only);
}
}
pub fn deinit(device: *const Device) void {
for (s_targets.scene) |*s| {
s.deinit(device);
}
for (s_targets.depth) |*d| {
d.deinit(device);
}
}
pub fn recreate(device: *const Device) void {
if (getRenderWidth() != getDesiredWidth() or
getRenderHeight() != getDesiredHeight())
{
deinit(device);
init();
}
}
pub fn getDisplayWidth(swapchain: *const Swapchain) i32 {
swapchain.getBackBuffer().width;
}
pub fn getDisplayHeight(swapchain: *const Swapchain) i32 {
swapchain.getBackBuffer().height;
}
pub fn getRenderWidth() i32 {
return s_targets.width;
}
pub fn getRenderHeight() i32 {
return s_targets.height;
}
pub fn getRenderAspect() f32 {
return @intToFloat(f32, s_targets.width) / @intToFloat(f32, s_targets.height);
}
pub fn getRenderScale() f32 {
return 1.0; // TODO convar
}

View File

@ -66,12 +66,14 @@ pub const DeviceDispatch = vk.DeviceWrapper(.{
.cmdBeginRenderPass = true,
.cmdEndRenderPass = true,
.cmdBindPipeline = true,
.cmdBindDescriptorSets = true,
.cmdDraw = true,
.cmdSetViewport = true,
.cmdSetScissor = true,
.cmdBindVertexBuffers = true,
.cmdCopyBuffer = true,
.cmdPipelineBarrier = true,
.cmdPushConstants = true,
.getFenceStatus = true,
});

View File

@ -11,8 +11,8 @@ const allocator = gpa.allocator();
const num_attachments = 8;
const Key = struct {
attachments: [num_attachments]vk.ImageView,
formats: [num_attachments]vk.Format,
attachments: [num_attachments]vk.ImageView = std.mem.zeroes([num_attachments]vk.ImageView),
formats: [num_attachments]vk.Format = std.mem.zeroes([num_attachments]vk.Format),
width: u16,
height: u16,
};
@ -39,18 +39,18 @@ pub fn deinit(device: *const Device) void {
s_fbufs.deinit();
}
pub fn getOrAdd(attachments: []*const Image, width: i32, height: i32) !*Framebuffer {
pub fn getOrAdd(device: *const Device, attachments: []*const Image, width: u32, height: u32) !vk.Framebuffer {
std.debug.assert(attachments.len >= 1);
std.debug.assert(attachments.len <= num_attachments);
const key = Key{
.width = width,
.height = height,
var key = Key{
.width = @intCast(u16, width),
.height = @intCast(u16, height),
};
for (attachments) |attachment, i| {
if (attachment.view) |view| {
key.attachments[i] = view;
if (attachment.view != .null_handle) {
key.attachments[i] = attachment.view;
key.formats[i] = attachment.format;
}
}
@ -58,12 +58,12 @@ pub fn getOrAdd(attachments: []*const Image, width: i32, height: i32) !*Framebuf
const result = s_fbufs.getOrPutAssumeCapacity(key);
if (!result.found_existing) {
const value = Value{
.handle = try Framebuffer.init(key.attachments, key.formats, key.width, key.height),
.handle = try Framebuffer.init(device, key.attachments[0..attachments.len], key.formats[0..attachments.len], key.width, key.height),
};
result.value_ptr.* = value;
}
return result.value_ptr;
return result.value_ptr.handle;
}
pub fn remove(device: *const Device, view: vk.ImageView) void {
@ -87,8 +87,8 @@ fn containsView(key: *const Key, view: vk.ImageView) bool {
}
pub const Framebuffer = struct {
pub fn init(device: *Device, attachments: []const vk.ImageView, formats: []const vk.Format, width: i32, height: i32) !vk.Framebuffer {
const pass_desc: RenderPass.Description = .{
pub fn init(device: *const Device, attachments: []const vk.ImageView, formats: []const vk.Format, width: u32, height: u32) !vk.Framebuffer {
var pass_desc: RenderPass.Description = .{
.src_access_mask = .{ .shader_read_bit = true },
.dst_access_mask = .{ .color_attachment_write_bit = true },
.src_stage_mask = .{ .fragment_shader_bit = true },
@ -97,17 +97,18 @@ pub const Framebuffer = struct {
for (formats) |format, i| {
pass_desc.attachments[i].format = format;
const layout = if (i == 0 and format >= .d16_unorm and format <= .d32_sfloat_s8_uint)
.depth_stencil_attachment_optimal
const layout = if (i == 0 and @enumToInt(format) >= @enumToInt(vk.Format.d16_unorm) and @enumToInt(format) <= @enumToInt(vk.Format.d32_sfloat_s8_uint))
vk.ImageLayout.depth_stencil_attachment_optimal
else
.color_attachment_optimal;
vk.ImageLayout.color_attachment_optimal;
pass_desc.attachments[i].layout = layout;
}
const pass = try RenderPass.get(&pass_desc);
return try device.dispatch.createFramebuffer(device.handle, .{
const pass = try RenderPass.get(device, pass_desc);
return try device.dispatch.createFramebuffer(device.handle, &.{
.flags = .{},
.render_pass = pass,
.attachment_count = attachments.len,
.attachment_count = @intCast(u32, attachments.len),
.p_attachments = attachments.ptr,
.width = width,
.height = height,

View File

@ -22,7 +22,7 @@ pub const Image = struct {
state: State = .{},
handle: vk.Image = .null_handle,
allocation: vma.Allocation,
view: vk.ImageView,
view: vk.ImageView = .null_handle,
format: vk.Format,
width: u16,
height: u16,

View File

@ -213,32 +213,32 @@ const Pool = struct {
}
};
const ReleasableType = enum {
buffer,
image,
image_view,
attachment, // view used as an attachment
};
const ReleasableUnion = union(ReleasableType) {
buffer: struct {
handle: vk.Buffer,
allocation: vma.Allocation,
},
image: struct {
handle: vk.Image,
allocation: vma.Allocation,
view: vk.ImageView,
},
image_view: vk.ImageView,
attachment: vk.ImageView,
};
pub const Releasable = struct {
const Self = @This();
const Type = enum {
buffer,
image,
image_view,
attachment, // view used as an attachment
};
const Union = union(Type) {
buffer: struct {
handle: vk.Buffer,
allocation: vma.Allocation,
},
image: struct {
handle: vk.Image,
allocation: vma.Allocation,
view: vk.ImageView,
},
image_view: vk.ImageView,
attachment: vk.ImageView,
};
submit_id: SubmitId,
object: ReleasableUnion,
object: Union,
pub fn init(self: *const Self) void {
// TODO

View File

@ -1,3 +1,5 @@
const vk = @import("vulkan");
// Compile-time settings for Vulkan.
pub const app_name = "efemra";
@ -20,3 +22,66 @@ pub const cmds_per_queue = 64;
pub fn OnlyIf(comptime setting: bool, t: anytype) type {
return if (setting) t else void;
}
pub const Bid = struct {
id: u32,
desc_type: vk.DescriptorType,
count: u32 = 1,
stages: vk.ShaderStageFlags,
pub const TextureTable = struct {
const T1D = Bid{
.id = 0,
.desc_type = .combined_image_sampler,
.count = 64,
.stages = .{ .fragment_bit = true, .compute_bit = true },
};
const T2D = Bid{
.id = T1D.id + 1,
.desc_type = .combined_image_sampler,
.count = 512,
.stages = .{ .fragment_bit = true, .compute_bit = true },
};
const T3D = Bid{
.id = T2D.id + 1,
.desc_type = .combined_image_sampler,
.count = 64,
.stages = .{ .fragment_bit = true, .compute_bit = true },
};
const TCube = Bid{
.id = T3D.id + 1,
.desc_type = .combined_image_sampler,
.count = 64,
.stages = .{ .fragment_bit = true, .compute_bit = true },
};
const T2DArray = Bid{
.id = TCube.id + 1,
.desc_type = .combined_image_sampler,
.count = 64,
.stages = .{ .fragment_bit = true, .compute_bit = true },
};
};
const Globals = Bid{
.id = TextureTable.T2DArray.id + 1,
.desc_type = .uniform_buffer,
.stages = .{}.complement(), // all
};
const SceneLuminance = Bid{
.id = Globals.id + 1,
.desc_type = .combined_image_sampler,
.stages = .{ .fragment_bit = true, .compute_bit = true },
};
const HistogramBuffer = Bid{
.id = SceneLuminance.id + 1,
.desc_type = .storage_image,
.stages = .{ .compute_bit = true },
};
const ExposureBuffer = Bid{
.id = HistogramBuffer.id + 1,
.desc_type = .storage_buffer,
.stages = .{ .fragment_bit = true, .compute_bit = true },
};
const Count = ExposureBuffer.id + 1;
};

View File

@ -1,4 +1,5 @@
const std = @import("std");
const assert = std.debug.assert;
const vk = @import("vulkan");
const math = @import("std").math;
const Command = @import("Command.zig");
@ -278,7 +279,7 @@ pub const Swapchain = struct {
const timeout = std.math.maxInt(u64);
const result = try device.dispatch.acquireNextImageKHR(device.handle, self.handle, timeout, self.available_semas[self.sync_index].handle, .null_handle);
std.debug.assert(result.image_index < self.length);
assert(result.image_index < self.length);
const sub = self.image_submits[result.image_index];
if (sub.valid) {
try sub.wait(device);
@ -296,7 +297,7 @@ pub const Swapchain = struct {
const image_index = self.image_index;
const sync_index = self.sync_index;
{
const backbuf = self.getBackBuffer();
var backbuf = self.getBackBuffer();
const prev_use = backbuf.state.stage;
_ = try Image.State.presentSrc(device, command, backbuf);
@ -322,7 +323,49 @@ pub const Swapchain = struct {
}
}
pub fn getViewport(self: *const Self) vk.Viewport {
assert(self.handle != .null_handle);
return vk.Viewport{
.x = 0.0,
.y = 0.0,
.width = @intToFloat(f32, self.width),
.height = @intToFloat(f32, self.height),
.min_depth = 0.0,
.max_depth = 1.0,
};
}
pub fn getRect(self: *const Self) vk.Rect2D {
assert(self.handle != .null_handle);
return vk.Rect2D{
.extent = .{
.width = self.width,
.height = self.height,
},
.offset = std.mem.zeroes(vk.Offset2D),
};
}
pub fn getAspect(self: *const Self) f32 {
assert(self.handle != .null_handle);
return @intToFloat(f32, self.width) / @intToFloat(f32, self.height);
}
pub fn getBackBuffer(self: *Self) *Image {
return &self.images[self.image_index];
var img = &self.images[self.image_index];
assert(img.handle != .null_handle);
return img;
}
pub fn getDepthBuffer(self: *Self) *Image {
var img = &self.images[self.sync_index];
assert(img.handle != .null_handle);
return img;
}
pub fn getSceneBuffer(self: *Self) *Image {
var img = &self.images[self.sync_index];
assert(img.handle != .null_handle);
return img;
}
};