123 lines
3.5 KiB
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);
|
|
}
|
|
};
|