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

187 lines
5.6 KiB
Zig

const vk = @import("vulkan");
const vma = @import("vma");
const Device = @import("device.zig").Device;
const Command = @import("Command.zig");
const SubmitId = @import("swapchain.zig").SubmitId;
const std = @import("std");
const queues = @import("queues.zig");
const settings = @import("settings.zig");
const memory = @import("memory.zig");
const Swapchain = @import("swapchain.zig").Swapchain;
pub const Image = packed struct {
const Self = @This();
state: ImageState,
handle: vk.Image,
allocation: vma.Allocation,
view: vk.ImageView,
format: vk.Format,
width: u16,
height: u16,
depth: u12,
mip_levels: u8,
array_layers: u8,
usage: vk.ImageUsageFlags,
image_type: vk.ImageType,
imported: bool,
pub fn init(info: *const vk.ImageCreateInfo, mem_usage: memory.Usage) !Self {
const self = Self{};
memory.imageNew(self, info, mem_usage);
return self;
}
pub fn release(self: *const Self) !void {
self.getSubmit();
}
pub fn deinit(self: *const Self, device: *const Device) void {
memory.imageDel(self, device);
}
/// import vk.Image handle into an existing Image object.
pub fn import(self: *Image, device: *const Device, info: *const vk.ImageCreateInfo, handle: vk.Image) !void {
self.handle = handle;
self.image_type = info.image_type;
self.format = info.format;
self.state.layout = info.initial_layout;
self.usage = info.usage;
self.width = @intCast(u16, info.extent.width);
self.height = @intCast(u16, info.extent.height);
self.depth = @intCast(u12, info.extent.depth);
self.mip_levels = @intCast(u8, info.mip_levels);
self.array_layers = @intCast(u8, info.array_layers);
self.imported = true;
var view_info = try infoToViewInfo(info);
view_info.image = self.handle;
self.view = try device.dispatch.createImageView(device.handle, &view_info, null);
errdefer memory.imageDel(self);
}
fn getSubmit(self: *Self) SubmitId {
std.debug.assert(!self.state.substates);
const id = if (self.state.stage != 0) {
.{
.counter = self.state.cmd_id,
.queue_id = self.state.owner,
.valid = true,
};
} else {
Command.getHeadSubmit(self.state.owner);
};
std.debug.assert(id.valid);
return id;
}
};
const ImageState = packed struct {
owner: queues.QueueId,
cmd_id: i32,
stage: vk.PipelineStageFlags,
access: vk.AccessFlags,
layout: vk.ImageLayout,
substates: [*]SubImageState,
};
const ImageSet = struct {
const Self = @This();
frames: [settings.resource_sets]Image,
pub fn init(info: *const vk.ImageCreateInfo, mem_usage: vma.MemUsage) !Self {
const self = Self{};
errdefer self.deinit();
for (self.frames) |frame| {
try frame.init(info, mem_usage);
}
}
pub fn deinit(self: *Self) void {
for (self.frames) |frame| {
frame.deinit();
}
}
pub fn reserve(self: *Self, info: *const vk.ImageCreateInfo, mem_usage: memory.Usage) !void {
try self.current().reserve(info, mem_usage);
}
pub fn current(self: *Self, swapchain: *Swapchain) *Image {
std.debug.assert(swapchain.sync_index < self.frames.len);
return &self.frames[swapchain.sync_index];
}
pub fn prev(self: *Self, swapchain: *Swapchain) *Image {
const prev_index = (swapchain.sync_index + (settings.resource_sets - 1)) % settings.resource_sets;
std.debug.assert(prev_index < self.frames.len);
return &self.frames[prev_index];
}
};
const SubImageState = packed struct {
stage: vk.PipelineStageFlags,
access: vk.AccessFlags,
layout: vk.ImageLayout,
};
pub fn infoToViewInfo(info: *const vk.ImageCreateInfo) !vk.ImageViewCreateInfo {
// anything but transfer usage needs a view
const viewless: vk.ImageUsageFlags = .{ .transfer_src_bit = true, .transfer_dst_bit = true };
if (!info.usage.contains(viewless)) {
return vk.ImageViewCreateInfo{
.s_type = .image_view_create_info,
.flags = .{},
.format = info.format,
.view_type = infoToViewType(info),
.image = undefined,
.components = undefined,
.subresource_range = .{
.aspect_mask = infoToAspects(info),
.base_mip_level = 0,
.level_count = info.mip_levels,
.base_array_layer = 0,
.layer_count = info.array_layers,
},
};
}
// Unsure if this should be error or not
return error.NotConvertibleToViewInfo;
}
pub fn infoToViewType(info: *const vk.ImageCreateInfo) vk.ImageViewType {
return switch (info.image_type) {
.@"1d" => {
return if (info.array_layers <= 1) .@"1d" else .@"1d_array";
},
.@"3d" => {
return .@"3d";
},
else => {
if (info.array_layers <= 1) {
return .@"2d";
} else if (info.array_layers == 6) {
return .cube;
} else {
return .@"2d_array";
}
},
};
}
pub fn infoToAspects(info: *const vk.ImageCreateInfo) vk.ImageAspectFlags {
return switch (info.format) {
.d16_unorm, .x8_d24_unorm_pack32, .d32_sfloat => .{ .depth_bit = true },
.d16_unorm_s8_uint, .d24_unorm_s8_uint, .d32_sfloat_s8_uint => .{ .depth_bit = true, .stencil_bit = true },
.s8_uint => .{ .stencil_bit = true },
else => .{ .color_bit = true },
};
}