187 lines
5.6 KiB
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 },
|
|
};
|
|
}
|