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

123 lines
3.5 KiB
Zig

const std = @import("std");
const vk = @import("vulkan");
const Image = @import("image.zig").Image;
const renderpass = @import("render_pass.zig");
const Device = @import("device.zig").Device;
// TODO memory
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
const num_attachments = 8;
const Key = struct {
attachments: [num_attachments]vk.ImageView,
formats: [num_attachments]vk.Format,
width: u16,
height: u16,
};
const Value = struct {
handle: vk.Framebuffer,
};
const Self = @This();
const FramebufHashMap = std.AutoArrayHashMap(Key, Value);
var s_fbufs: FramebufHashMap = undefined;
pub fn init() !void {
s_fbufs = FramebufHashMap.init(allocator);
try s_fbufs.ensureTotalCapacity(16);
}
pub fn deinit(device: *const Device) void {
for (s_fbufs.values()) |*entry| {
device.dispatch.destroyFramebuffer(device.handle, entry.handle, null);
}
s_fbufs.deinit();
}
pub fn getOrAdd(attachments: []*const Image, width: i32, height: i32) !*Framebuffer {
std.debug.assert(attachments.len >= 1);
std.debug.assert(attachments.len <= num_attachments);
const key = Key{
.width = width,
.height = height,
};
for (attachments) |attachment, i| {
if (attachment.view) |view| {
key.attachments[i] = view;
key.formats[i] = attachment.format;
}
}
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),
};
result.value_ptr.* = value;
}
return result.value_ptr;
}
pub fn remove(device: *const Device, view: vk.ImageView) void {
var iter = s_fbufs.iterator();
while (iter.next()) |entry| {
if (containsView(entry.key_ptr, view)) {
Framebuffer.deinit(entry.value_ptr.handle, device);
_ = s_fbufs.swapRemove(entry.key_ptr.*);
}
}
}
fn containsView(key: *const Key, view: vk.ImageView) bool {
for (key.attachments) |attachment| {
if (attachment == view) {
return true;
}
}
return false;
}
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 = .{
.src_access_mask = .shader_read_bit,
.dst_access_mask = .color_attachment_write_bit,
.src_stage_mask = .fragment_shader_bit,
.dst_stage_mask = .color_attachment_output_bit,
};
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
else
.color_attachment_optimal;
pass_desc.attachments[i].layout = layout;
}
const pass = try renderpass.get(&pass_desc);
return try device.dispatch.createFramebuffer(device.handle, .{
.s_type = .framebuffer_create_info,
.render_pass = pass,
.attachment_count = attachments.len,
.p_attachments = attachments.ptr,
.width = width,
.height = height,
.layers = 1,
}, null);
}
pub fn deinit(framebuffer: vk.Framebuffer, device: *const Device) void {
device.dispatch.destroyFramebuffer(device.handle, framebuffer, null);
}
};