forked from vv/efemra
1
0
Fork 0
efemra/src/rendering/vulkan/MainPass.zig

462 lines
16 KiB
Zig

const std = @import("std");
const vk = @import("vulkan");
const resources = @import("resources");
const ProfileMark = @import("../../common/profiler.zig").ProfileMark;
const settings = @import("settings.zig");
const Device = @import("device.zig").Device;
const Command = @import("Command.zig");
const Swapchain = @import("swapchain.zig").Swapchain;
const Image = @import("image.zig").Image;
const Buffer = @import("Buffer.zig");
const Camera = @import("../Camera.zig");
const shaders = @import("shaders.zig");
const Pass = @import("Pass.zig");
const framebuffer = @import("framebuffer.zig");
const Targets = @import("Targets.zig");
const RenderPass = @import("RenderPass.zig");
const Bindings = @import("Bindings.zig");
const Entities = @import("../Entities.zig");
const Texture = @import("../textures.zig").Texture;
const vec = @import("../../math/vec.zig");
const mat = @import("../../math/mat.zig");
const Vec2f = vec.Vec2f;
const Vec4f = vec.Vec4f;
const Vec4i = vec.Vec4i;
const Vec2u = vec.Vec2u;
const Vec4u = vec.Vec4u;
const Mat4f = mat.Mat4f;
pub fn init(device: *const Device, swapchain: *Swapchain) !void {
errdefer {
std.debug.print("Failed to init MainPass", .{});
deinit(device);
}
// try ScreenBlit.init()
try DepthPass.init(device, swapchain);
try OpaquePass.init(device, swapchain);
// try Exposure.init();
// try UIPass.init();
}
pub fn deinit(device: *const Device) void {
// ScreenBlit.deinit()
DepthPass.deinit(device);
OpaquePass.deinit(device);
// Exposure.deinit();
// UIPass.deinit();
}
const pm_setup = ProfileMark.init("MainPass.setup");
pub fn setup(device: *const Device, swapchain: *const Swapchain) !void {
pm_setup.begin();
defer pm_setup.end();
DepthPass.setup();
try OpaquePass.setup(device, swapchain);
// Exposure.setup();
// UIPass.setup();
}
const pm_execute = ProfileMark.init("MainPass.execute");
pub fn execute(device: *const Device, swapchain: *Swapchain) !void {
pm_execute.begin();
defer pm_execute.end();
// todo: pt_trace convar check
try DepthPass.execute(device, swapchain);
try OpaquePass.execute(device, swapchain);
// Exposure.execute();
// UIPass.execute();
}
const DepthPass = struct {
const PushConstants = packed struct {
local_to_clip: Mat4f,
};
var s_render_pass: vk.RenderPass = undefined;
var s_pass: Pass = undefined;
pub fn init(device: *const Device, swapchain: *Swapchain) !void {
errdefer DepthPass.deinit(device);
const depth_buffer = Targets.getDepthBuffer(swapchain);
var info = RenderPass.Description{
.src_stage_mask = .{ .fragment_shader_bit = true },
.src_access_mask = .{ .shader_read_bit = true },
.dst_stage_mask = .{ .color_attachment_output_bit = true },
.dst_access_mask = .{ .color_attachment_write_bit = true },
};
info.attachments[0] = .{
.format = depth_buffer.format,
.layout = .depth_stencil_attachment_optimal,
.load = .clear,
.store = .store,
};
s_render_pass = try RenderPass.get(device, info);
var vert_bindings = [_]vk.VertexInputBindingDescription{
.{
.binding = 0,
.stride = @sizeOf(Vec2f),
.input_rate = .vertex,
},
};
var vert_attributes = [_]vk.VertexInputAttributeDescription{
.{
.binding = 0,
.format = .r32g32b32a32_sfloat,
.location = 0,
.offset = 0,
},
};
var sh: [2]vk.PipelineShaderStageCreateInfo = undefined;
sh[0] = try shaders.createModule(device, .{ .vertex_bit = true }, &resources.DepthOnly_vert, "VSMain");
defer shaders.deinitModule(device, sh[0].module);
sh[1] = try shaders.createModule(device, .{ .fragment_bit = true }, &resources.DepthOnly_frag, "PSMain");
defer shaders.deinitModule(device, sh[1].module);
const desc = Pass.Description{
.push_constant_bytes = @sizeOf(PushConstants),
.shaders = &sh,
.render_pass = s_render_pass,
.subpass = null,
.vert_layout = .{
.bindings = &vert_bindings,
.attributes = &vert_attributes,
},
.fixed_funcs = .{
.viewport = swapchain.getViewport(),
.scissor = swapchain.getRect(),
.topology = .triangle_list,
.polygon_mode = .fill,
.front_face = .counter_clockwise,
.cull_mode = .{ .back_bit = true },
.depth_compare_op = .less,
.scissor_on = false,
.depth_clamp = false,
.depth_test_enable = true,
.depth_write_enable = true,
},
};
try s_pass.init(device, &desc);
}
pub fn deinit(device: *const Device) void {
s_pass.deinit(device);
}
pub fn setup() void {}
const pm_depth_execute = ProfileMark.init("DepthPass.execute");
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 attachments = &[_]*Image{Targets.getDepthBuffer(swapchain)};
const rect = vk.Rect2D{
.offset = std.mem.zeroes(vk.Offset2D),
.extent = .{
.width = attachments[0].width,
.height = attachments[0].height,
},
};
const fbuf = try framebuffer.getOrAdd(device, attachments, rect.extent.width, rect.extent.height);
const cmd = try Command.Buffer.get(.graphics, device);
_ = try Image.State.depthAttachWrite(device, cmd, attachments[0]);
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 },
},
});
defer cmd.endRenderPass(device);
// TODO: draw entities/meshes
cmd.pushConstants(device, &s_pass, &PushConstants{ .local_to_clip = world_to_clip });
// TODO: imSys_drawDepth()
}
};
const OpaquePass = struct {
const Globals = packed struct {
g_WorldToClip: Mat4f,
g_Eye: Vec4f,
g_HdrEnabled: f32,
g_Whitepoint: f32,
g_DisplayNits: f32,
g_UiNits: f32,
g_RenderSize: Vec2u,
g_DisplaySize: Vec2u,
};
const PushConstants = packed struct {
kLocalToWorld: Mat4f,
kIMc0: Vec4f, // components of inverse matrix
kIMc1: Vec4f,
kIMc2: Vec4f,
kTexInds: Vec4u,
};
var s_render_pass: vk.RenderPass = undefined;
var s_pass: Pass = undefined;
var s_per_camera_buffer: Buffer.Set = undefined;
pub fn init(device: *const Device, swapchain: *Swapchain) !void {
errdefer OpaquePass.deinit(device);
const scene_buffer = Targets.getSceneBuffer(swapchain);
const depth_buffer = Targets.getDepthBuffer(swapchain);
var info = RenderPass.Description{
.src_stage_mask = .{ .fragment_shader_bit = true },
.dst_stage_mask = .{ .color_attachment_output_bit = true },
.src_access_mask = .{ .shader_read_bit = true },
.dst_access_mask = .{ .color_attachment_write_bit = true },
};
info.attachments[0] = .{
.format = depth_buffer.format,
.layout = .depth_stencil_attachment_optimal,
.load = .load,
.store = .dont_care,
};
info.attachments[1] = .{
.format = scene_buffer.format,
.layout = .color_attachment_optimal,
.load = .clear,
.store = .store,
};
s_render_pass = try RenderPass.get(device, info);
try s_per_camera_buffer.init(device, @sizeOf(Globals), .{ .uniform_buffer_bit = true }, .cpuToGpu);
errdefer s_per_camera_buffer.release(device);
var sh: [2]vk.PipelineShaderStageCreateInfo = undefined;
sh[0] = try shaders.createModule(device, .{ .vertex_bit = true }, &resources.brush_vert, "VSMain");
defer shaders.deinitModule(device, sh[0].module);
sh[1] = try shaders.createModule(device, .{ .fragment_bit = true }, &resources.brush_frag, "PSMain");
defer shaders.deinitModule(device, sh[1].module);
// TODO: probably a few ways to make this more elegant using comptime?
const vert_bindings = [_]vk.VertexInputBindingDescription{
// positionWs
.{
.binding = 0,
.stride = @sizeOf(Vec4f),
.input_rate = .vertex,
},
// normalWS and lightmap index
.{
.binding = 1,
.stride = @sizeOf(Vec4f),
.input_rate = .vertex,
},
// uv0 and uv1
.{
.binding = 2,
.stride = @sizeOf(Vec4f),
.input_rate = .vertex,
},
// texture indices
.{
.binding = 3,
.stride = @sizeOf(Vec4i),
.input_rate = .vertex,
},
};
const vert_attributes = [_]vk.VertexInputAttributeDescription{
// positionOS
.{
.binding = 0,
.location = 0,
.format = .r32g32b32a32_sfloat,
.offset = 0,
},
// normalOS and lightmap index
.{
.binding = 1,
.location = 1,
.format = .r32g32b32a32_sfloat,
.offset = 0,
},
// uv0 and uv1
.{
.binding = 2,
.location = 2,
.format = .r32g32b32a32_sfloat,
.offset = 0,
},
// texture indices
.{
.binding = 3,
.location = 3,
.format = .r32g32b32a32_uint,
.offset = 0,
},
};
var desc = Pass.Description{
.push_constant_bytes = @sizeOf(PushConstants),
.shaders = &sh,
.render_pass = s_render_pass,
.subpass = 0,
.vert_layout = .{
.bindings = &vert_bindings,
.attributes = &vert_attributes,
},
.fixed_funcs = .{
.viewport = swapchain.getViewport(),
.scissor = swapchain.getRect(),
.topology = .triangle_list,
.polygon_mode = .fill,
.front_face = .counter_clockwise,
.cull_mode = .{ .back_bit = true },
.depth_compare_op = .equal,
.scissor_on = false,
.depth_clamp = false,
.depth_test_enable = true,
.depth_write_enable = false,
.attachments = &[_]Pass.BlendState{
.{
.color_write_mask = .{ .r_bit = true, .g_bit = true, .b_bit = true, .a_bit = true },
.blend_enable = true,
.color_blend_op = .add,
.alpha_blend_op = .add,
},
},
},
};
try s_pass.init(device, &desc);
}
pub fn deinit(device: *const Device) void {
s_pass.deinit(device);
s_per_camera_buffer.release(device);
}
const pm_opaque_setup = ProfileMark.init("OpaquePass.setup");
pub fn setup(device: *const Device, swapchain: *const Swapchain) !void {
pm_opaque_setup.begin();
defer pm_opaque_setup.end();
// TODO: move this into some parameter provider standalone file, says kara
{
const camera = Camera.get();
const globals = Globals{
.g_WorldToClip = camera.getWorldToClip(Targets.getRenderAspect()),
.g_Eye = camera.position,
.g_HdrEnabled = 0, // TODO getHdrEnabled
.g_Whitepoint = 0, // TODO getWhitepoint
.g_DisplayNits = 0, // TODO getDisplayNitsMax
.g_UiNits = 0, // TODO getUiNits
.g_RenderSize = .{
.x = Targets.getRenderWidth(),
.y = Targets.getRenderHeight(),
},
.g_DisplaySize = .{
.x = Targets.getDisplayWidth(swapchain),
.y = Targets.getDisplayHeight(swapchain),
},
};
try s_per_camera_buffer.write(device, swapchain, @ptrCast([*]const u8, &globals)[0..@sizeOf(Globals)]);
}
Bindings.bindBuffer(settings.Bid.Globals.id, .uniform_buffer, s_per_camera_buffer.current(swapchain));
}
const pm_opaque_execute = ProfileMark.init("OpaquePass.execute");
pub fn execute(device: *const Device, swapchain: *Swapchain) !void {
pm_opaque_execute.begin();
defer pm_opaque_execute.end();
var attachments = [_]*Image{
Targets.getDepthBuffer(swapchain),
Targets.getSceneBuffer(swapchain),
};
const rect = vk.Rect2D{
.extent = .{
.width = attachments[0].width,
.height = attachments[0].height,
},
.offset = std.mem.zeroes(vk.Offset2D),
};
const fbuf = try framebuffer.getOrAdd(device, &attachments, rect.extent.width, rect.extent.height);
const cmdbuf = try Command.Buffer.get(.graphics, device);
_ = try Image.State.depthAttachWrite(device, cmdbuf, attachments[0]);
_ = try Image.State.colorAttachWrite(device, cmdbuf, attachments[1]);
// textable fragsampleall
cmdbuf.defaultViewport(device, swapchain);
cmdbuf.bindPass(device, swapchain, &s_pass);
const clear_values = [_]vk.ClearValue{
.{
.depth_stencil = .{ .depth = 1, .stencil = 0 },
},
.{
.color = .{ .float_32 = .{ 0, 0, 0, 1 } },
},
};
cmdbuf.beginRenderPass(device, s_render_pass, fbuf, rect, &clear_values);
defer cmdbuf.endRenderPass(device);
const ents = Entities.get();
for (ents.meshes.items) |mesh, i| {
const mAlbedo = Texture.get(ents.materials.items[i].albedo);
const mRome = Texture.get(ents.materials.items[i].rome);
const mNormal = Texture.get(ents.materials.items[i].normal);
const pc = PushConstants{
.kLocalToWorld = ents.matrices.items[i],
.kIMc0 = ents.inv_matrices.items[i].c0,
.kIMc1 = ents.inv_matrices.items[i].c1,
.kIMc2 = ents.inv_matrices.items[i].c2,
.kTexInds = .{
.x = if (mAlbedo) |albedo| albedo.slot.index else 0,
.y = if (mRome) |rome| rome.slot.index else 0,
.z = if (mNormal) |normal| normal.slot.index else 0,
.w = 0,
},
};
cmdbuf.pushConstants(device, &s_pass, &pc);
cmdbuf.drawMesh(mesh.id);
}
const pc = PushConstants{
.kLocalToWorld = Mat4f.id,
.kIMc0 = Vec4f{ .x = 1, .y = 0, .z = 0, .w = 0 },
.kIMc1 = Vec4f{ .x = 0, .y = 1, .z = 0, .w = 0 },
.kIMc2 = Vec4f{ .x = 0, .y = 0, .z = 1, .w = 0 },
.kTexInds = Vec4u{},
};
cmdbuf.pushConstants(device, &s_pass, &pc);
}
};