Split gfx context & swapchain
This commit is contained in:
parent
401f82c523
commit
d318dfa4a2
6 changed files with 297 additions and 285 deletions
|
@ -7,6 +7,7 @@ const img = @import("zstbi");
|
||||||
|
|
||||||
const validation = @import("./validation_layers.zig");
|
const validation = @import("./validation_layers.zig");
|
||||||
const Swapchain = @import("Swapchain.zig");
|
const Swapchain = @import("Swapchain.zig");
|
||||||
|
const QueueUtils = @import("queue_utils.zig");
|
||||||
|
|
||||||
const device_extensions = [_][*:0]const u8{vk.extensions.khr_swapchain.name};
|
const device_extensions = [_][*:0]const u8{vk.extensions.khr_swapchain.name};
|
||||||
|
|
||||||
|
@ -23,15 +24,6 @@ pub const apis: []const vk.ApiInfo = &.{
|
||||||
const enable_validation_layers = builtin.mode == .Debug;
|
const enable_validation_layers = builtin.mode == .Debug;
|
||||||
const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"};
|
const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"};
|
||||||
|
|
||||||
const QueueFamilyIndices = struct {
|
|
||||||
graphics_family: ?u32 = null,
|
|
||||||
presentation_family: ?u32 = null,
|
|
||||||
|
|
||||||
fn isValid(self: QueueFamilyIndices) bool {
|
|
||||||
return self.graphics_family != null and self.presentation_family != null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const BaseDispatch = vk.BaseWrapper(apis);
|
const BaseDispatch = vk.BaseWrapper(apis);
|
||||||
const InstanceDispatch = vk.InstanceWrapper(apis);
|
const InstanceDispatch = vk.InstanceWrapper(apis);
|
||||||
const DeviceDispatch = vk.DeviceWrapper(apis);
|
const DeviceDispatch = vk.DeviceWrapper(apis);
|
||||||
|
@ -171,7 +163,7 @@ fn getPhysicalDevice(self: *Self) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createLogicalDevice(self: *Self) !void {
|
fn createLogicalDevice(self: *Self) !void {
|
||||||
const indices = try self.getQueueFamilies(self.physical_device);
|
const indices = try QueueUtils.getQueueFamilies(self.*, self.physical_device);
|
||||||
// 1 is the highest priority
|
// 1 is the highest priority
|
||||||
const priority = [_]f32{1};
|
const priority = [_]f32{1};
|
||||||
|
|
||||||
|
@ -214,7 +206,7 @@ fn createLogicalDevice(self: *Self) !void {
|
||||||
|
|
||||||
self.device = Device.init(device_handle, vkd);
|
self.device = Device.init(device_handle, vkd);
|
||||||
|
|
||||||
const queues = try self.getDeviceQueues();
|
const queues = try QueueUtils.getDeviceQueues(self.*);
|
||||||
|
|
||||||
self.graphics_queue = Queue.init(queues[0], self.device.wrapper);
|
self.graphics_queue = Queue.init(queues[0], self.device.wrapper);
|
||||||
self.presentation_queue = Queue.init(queues[1], self.device.wrapper);
|
self.presentation_queue = Queue.init(queues[1], self.device.wrapper);
|
||||||
|
@ -237,43 +229,6 @@ fn getRequiredExtensions(self: Self) ![][*:0]const u8 {
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getQueueFamilies(self: Self, pdev: vk.PhysicalDevice) !QueueFamilyIndices {
|
|
||||||
var indices: QueueFamilyIndices = .{ .graphics_family = null };
|
|
||||||
|
|
||||||
var queue_family_count: u32 = 0;
|
|
||||||
self.instance.getPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_count, null);
|
|
||||||
|
|
||||||
const queue_family_list = try self.allocator.alloc(vk.QueueFamilyProperties, queue_family_count);
|
|
||||||
defer self.allocator.free(queue_family_list);
|
|
||||||
|
|
||||||
self.instance.getPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_count, queue_family_list.ptr);
|
|
||||||
|
|
||||||
for (queue_family_list, 0..) |queue_family, i| {
|
|
||||||
if (queue_family.queue_count > 0 and queue_family.queue_flags.graphics_bit) {
|
|
||||||
indices.graphics_family = @intCast(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
const presentation_support = try self.instance.getPhysicalDeviceSurfaceSupportKHR(pdev, @intCast(i), self.surface);
|
|
||||||
if (queue_family.queue_count > 0 and presentation_support == vk.TRUE) {
|
|
||||||
indices.presentation_family = @intCast(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indices.isValid()) {
|
|
||||||
return indices;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getDeviceQueues(self: Self) ![2]vk.Queue {
|
|
||||||
const indices = try self.getQueueFamilies(self.physical_device);
|
|
||||||
|
|
||||||
const graphics_queue = self.device.getDeviceQueue(indices.graphics_family.?, 0);
|
|
||||||
const presentation_queue = self.device.getDeviceQueue(indices.presentation_family.?, 0);
|
|
||||||
return .{ graphics_queue, presentation_queue };
|
|
||||||
}
|
|
||||||
|
|
||||||
fn checkInstanceExtensions(self: Self, required_extensions: *const [][*:0]const u8) !bool {
|
fn checkInstanceExtensions(self: Self, required_extensions: *const [][*:0]const u8) !bool {
|
||||||
var prop_count: u32 = 0;
|
var prop_count: u32 = 0;
|
||||||
_ = try self.vkb.enumerateInstanceExtensionProperties(null, &prop_count, null);
|
_ = try self.vkb.enumerateInstanceExtensionProperties(null, &prop_count, null);
|
||||||
|
@ -330,13 +285,13 @@ fn checkDeviceSuitable(self: Self, pdev: vk.PhysicalDevice) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
const pdev_features = self.instance.getPhysicalDeviceFeatures(pdev);
|
const pdev_features = self.instance.getPhysicalDeviceFeatures(pdev);
|
||||||
const queue_family_indices = self.getQueueFamilies(pdev) catch return false;
|
const queue_family_indices = QueueUtils.getQueueFamilies(self, pdev) catch return false;
|
||||||
const extension_support = self.checkDeviceExtensions(pdev) catch return false;
|
const extension_support = self.checkDeviceExtensions(pdev) catch return false;
|
||||||
|
|
||||||
const swapchain_details = Swapchain.getSwapchainDetails(
|
const swapchain_details = Swapchain.getSwapchainDetails(
|
||||||
self.allocator,
|
self.allocator,
|
||||||
self.instance,
|
self.instance,
|
||||||
self.physical_device,
|
pdev,
|
||||||
self.surface,
|
self.surface,
|
||||||
) catch return false;
|
) catch return false;
|
||||||
defer self.allocator.free(swapchain_details.formats);
|
defer self.allocator.free(swapchain_details.formats);
|
||||||
|
|
|
@ -4,8 +4,8 @@ const zm = @import("zmath");
|
||||||
const ai = @import("assimp.zig").c;
|
const ai = @import("assimp.zig").c;
|
||||||
|
|
||||||
const Mesh = @import("Mesh.zig");
|
const Mesh = @import("Mesh.zig");
|
||||||
const Device = @import("vulkan_renderer.zig").Device;
|
const Device = @import("Context.zig").Device;
|
||||||
const Instance = @import("vulkan_renderer.zig").Instance;
|
const Instance = @import("Context.zig").Instance;
|
||||||
const Vertex = @import("utilities.zig").Vertex;
|
const Vertex = @import("utilities.zig").Vertex;
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
|
@ -4,6 +4,8 @@ const sdl = @import("sdl");
|
||||||
|
|
||||||
const Context = @import("Context.zig");
|
const Context = @import("Context.zig");
|
||||||
const Instance = Context.Instance;
|
const Instance = Context.Instance;
|
||||||
|
const QueueUtils = @import("queue_utils.zig");
|
||||||
|
const Utilities = @import("utilities.zig");
|
||||||
|
|
||||||
pub const SwapchainDetails = struct {
|
pub const SwapchainDetails = struct {
|
||||||
surface_capabilities: vk.SurfaceCapabilitiesKHR,
|
surface_capabilities: vk.SurfaceCapabilitiesKHR,
|
||||||
|
@ -22,11 +24,14 @@ allocator: std.mem.Allocator,
|
||||||
|
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
|
|
||||||
swapchain: vk.SwapchainKHR,
|
handle: vk.SwapchainKHR,
|
||||||
|
|
||||||
swapchain_images: []SwapchainImage,
|
swapchain_images: []SwapchainImage,
|
||||||
swapchain_framebuffers: []vk.Framebuffer,
|
swapchain_framebuffers: []vk.Framebuffer,
|
||||||
|
|
||||||
|
swapchain_image_format: vk.Format,
|
||||||
|
extent: vk.Extent2D,
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator, context: Context) !Self {
|
pub fn create(allocator: std.mem.Allocator, context: Context) !Self {
|
||||||
var self: Self = undefined;
|
var self: Self = undefined;
|
||||||
|
|
||||||
|
@ -42,7 +47,7 @@ pub fn create(allocator: std.mem.Allocator, context: Context) !Self {
|
||||||
// 2. Choose best presentation mode
|
// 2. Choose best presentation mode
|
||||||
const present_mode = chooseBestPresentationMode(swapchain_details.presentation_modes);
|
const present_mode = chooseBestPresentationMode(swapchain_details.presentation_modes);
|
||||||
// 3. Choose swapchain image resolution
|
// 3. Choose swapchain image resolution
|
||||||
const extent = chooseSwapExtent(&context.window, swapchain_details.surface_capabilities);
|
const extent = chooseSwapExtent(&self.ctx.window, swapchain_details.surface_capabilities);
|
||||||
|
|
||||||
// How many images are in the swapchain? Get 1 more than the minimum to allow triple buffering
|
// How many images are in the swapchain? Get 1 more than the minimum to allow triple buffering
|
||||||
var image_count: u32 = swapchain_details.surface_capabilities.min_image_count + 1;
|
var image_count: u32 = swapchain_details.surface_capabilities.min_image_count + 1;
|
||||||
|
@ -71,7 +76,7 @@ pub fn create(allocator: std.mem.Allocator, context: Context) !Self {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get queue family indices
|
// Get queue family indices
|
||||||
const family_indices = try self.getQueueFamilies(self.physical_device);
|
const family_indices = try QueueUtils.getQueueFamilies(self.ctx, self.ctx.physical_device);
|
||||||
|
|
||||||
// If graphic and presentation families are different, then swapchain must let images be shared between families
|
// If graphic and presentation families are different, then swapchain must let images be shared between families
|
||||||
|
|
||||||
|
@ -86,18 +91,18 @@ pub fn create(allocator: std.mem.Allocator, context: Context) !Self {
|
||||||
swapchain_create_info.p_queue_family_indices = &qfi;
|
swapchain_create_info.p_queue_family_indices = &qfi;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.swapchain = try self.device.createSwapchainKHR(&swapchain_create_info, null);
|
self.handle = try self.ctx.device.createSwapchainKHR(&swapchain_create_info, null);
|
||||||
self.swapchain_image_format = surface_format.format;
|
self.swapchain_image_format = surface_format.format;
|
||||||
self.extent = extent;
|
self.extent = extent;
|
||||||
|
|
||||||
// Swapchain images
|
// Swapchain images
|
||||||
var swapchain_image_count: u32 = 0;
|
var swapchain_image_count: u32 = 0;
|
||||||
_ = try self.device.getSwapchainImagesKHR(self.swapchain, &swapchain_image_count, null);
|
_ = try self.ctx.device.getSwapchainImagesKHR(self.handle, &swapchain_image_count, null);
|
||||||
|
|
||||||
const images = try self.allocator.alloc(vk.Image, swapchain_image_count);
|
const images = try self.allocator.alloc(vk.Image, swapchain_image_count);
|
||||||
defer self.allocator.free(images);
|
defer self.allocator.free(images);
|
||||||
|
|
||||||
_ = try self.device.getSwapchainImagesKHR(self.swapchain, &swapchain_image_count, images.ptr);
|
_ = try self.ctx.device.getSwapchainImagesKHR(self.handle, &swapchain_image_count, images.ptr);
|
||||||
|
|
||||||
self.swapchain_images = try self.allocator.alloc(SwapchainImage, swapchain_image_count);
|
self.swapchain_images = try self.allocator.alloc(SwapchainImage, swapchain_image_count);
|
||||||
|
|
||||||
|
@ -111,6 +116,78 @@ pub fn create(allocator: std.mem.Allocator, context: Context) !Self {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn createImage(
|
||||||
|
self: *Self,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
format: vk.Format,
|
||||||
|
tiling: vk.ImageTiling,
|
||||||
|
use_flags: vk.ImageUsageFlags,
|
||||||
|
prop_flags: vk.MemoryPropertyFlags,
|
||||||
|
image_memory: *vk.DeviceMemory,
|
||||||
|
) !vk.Image {
|
||||||
|
// -- Create Image --
|
||||||
|
const image_create_info: vk.ImageCreateInfo = .{
|
||||||
|
.image_type = .@"2d", // Type of image (1D, 2D or 3D)
|
||||||
|
.extent = .{
|
||||||
|
.width = width, // Width of image extent
|
||||||
|
.height = height, // Height of image extent
|
||||||
|
.depth = 1, // Depth of image (just 1, no 3D aspecct)
|
||||||
|
},
|
||||||
|
.mip_levels = 1, // Number of mipmap levels
|
||||||
|
.array_layers = 1, // Number of level in image array
|
||||||
|
.format = format, // Format type of image
|
||||||
|
.tiling = tiling, // How image data should be tiled (arranged for optimal reading)
|
||||||
|
.initial_layout = .undefined, // Layout of image data on creation
|
||||||
|
.usage = use_flags, // Bit flags defining what image will be used for
|
||||||
|
.samples = .{ .@"1_bit" = true }, // Number of samples for multi-sampling
|
||||||
|
.sharing_mode = .exclusive, // Whether image can be shared between queues
|
||||||
|
};
|
||||||
|
|
||||||
|
const image = try self.ctx.device.createImage(&image_create_info, null);
|
||||||
|
|
||||||
|
// -- Create memory for image --
|
||||||
|
// Get memory requirements for a type of image
|
||||||
|
const memory_requirements = self.ctx.device.getImageMemoryRequirements(image);
|
||||||
|
|
||||||
|
// Allocate memory using image requirements and user-defined properties
|
||||||
|
const memory_alloc_info: vk.MemoryAllocateInfo = .{
|
||||||
|
.allocation_size = memory_requirements.size,
|
||||||
|
.memory_type_index = Utilities.findMemoryTypeIndex(self.ctx.physical_device, self.ctx.instance, memory_requirements.memory_type_bits, prop_flags),
|
||||||
|
};
|
||||||
|
|
||||||
|
image_memory.* = try self.ctx.device.allocateMemory(&memory_alloc_info, null);
|
||||||
|
|
||||||
|
// Connect memory to image
|
||||||
|
try self.ctx.device.bindImageMemory(image, image_memory.*, 0);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createImageView(self: Self, image: vk.Image, format: vk.Format, aspect_flags: vk.ImageAspectFlags) !vk.ImageView {
|
||||||
|
const image_view_create_info: vk.ImageViewCreateInfo = .{
|
||||||
|
.image = image,
|
||||||
|
.format = format,
|
||||||
|
.view_type = .@"2d",
|
||||||
|
.components = .{
|
||||||
|
// Used for remapping rgba values to other rgba values
|
||||||
|
.r = .identity,
|
||||||
|
.g = .identity,
|
||||||
|
.b = .identity,
|
||||||
|
.a = .identity,
|
||||||
|
},
|
||||||
|
.subresource_range = .{
|
||||||
|
.aspect_mask = aspect_flags, // Which aspect of image to view (e.g.: colour, depth, stencil, etc...)
|
||||||
|
.base_mip_level = 0, // Start mipmap level to view from
|
||||||
|
.level_count = 1, // Number of mipmap levels to view
|
||||||
|
.base_array_layer = 0, // Start array level to view from
|
||||||
|
.layer_count = 1, // Number of array levels to view
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return try self.ctx.device.createImageView(&image_view_create_info, null);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getSwapchainDetails(allocator: std.mem.Allocator, instance: Instance, pdev: vk.PhysicalDevice, surface: vk.SurfaceKHR) !SwapchainDetails {
|
pub fn getSwapchainDetails(allocator: std.mem.Allocator, instance: Instance, pdev: vk.PhysicalDevice, surface: vk.SurfaceKHR) !SwapchainDetails {
|
||||||
// Capabilities
|
// Capabilities
|
||||||
const surface_capabilities = try instance.getPhysicalDeviceSurfaceCapabilitiesKHR(pdev, surface);
|
const surface_capabilities = try instance.getPhysicalDeviceSurfaceCapabilitiesKHR(pdev, surface);
|
||||||
|
|
53
src/queue_utils.zig
Normal file
53
src/queue_utils.zig
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
|
const Context = @import("Context.zig");
|
||||||
|
const Instance = Context.Instance;
|
||||||
|
const Device = Context.Device;
|
||||||
|
|
||||||
|
pub const QueueFamilyIndices = struct {
|
||||||
|
graphics_family: ?u32 = null,
|
||||||
|
presentation_family: ?u32 = null,
|
||||||
|
|
||||||
|
pub fn isValid(self: QueueFamilyIndices) bool {
|
||||||
|
return self.graphics_family != null and self.presentation_family != null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn getQueueFamilies(ctx: Context, pdev: vk.PhysicalDevice) !QueueFamilyIndices {
|
||||||
|
var indices: QueueFamilyIndices = .{ .graphics_family = null };
|
||||||
|
|
||||||
|
var queue_family_count: u32 = 0;
|
||||||
|
ctx.instance.getPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_count, null);
|
||||||
|
|
||||||
|
const queue_family_list = try ctx.allocator.alloc(vk.QueueFamilyProperties, queue_family_count);
|
||||||
|
defer ctx.allocator.free(queue_family_list);
|
||||||
|
|
||||||
|
ctx.instance.getPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_count, queue_family_list.ptr);
|
||||||
|
|
||||||
|
for (queue_family_list, 0..) |queue_family, i| {
|
||||||
|
if (queue_family.queue_count > 0 and queue_family.queue_flags.graphics_bit) {
|
||||||
|
indices.graphics_family = @intCast(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const presentation_support = try ctx.instance.getPhysicalDeviceSurfaceSupportKHR(pdev, @intCast(i), ctx.surface);
|
||||||
|
if (queue_family.queue_count > 0 and presentation_support == vk.TRUE) {
|
||||||
|
indices.presentation_family = @intCast(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indices.isValid()) {
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getDeviceQueues(ctx: Context) ![2]vk.Queue {
|
||||||
|
const indices = try getQueueFamilies(ctx, ctx.physical_device);
|
||||||
|
|
||||||
|
const graphics_queue = ctx.device.getDeviceQueue(indices.graphics_family.?, 0);
|
||||||
|
const presentation_queue = ctx.device.getDeviceQueue(indices.presentation_family.?, 0);
|
||||||
|
return .{ graphics_queue, presentation_queue };
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
const Instance = @import("vulkan_renderer.zig").Instance;
|
const Instance = @import("Context.zig").Instance;
|
||||||
const Device = @import("vulkan_renderer.zig").Device;
|
const Device = @import("Context.zig").Device;
|
||||||
const CommandBuffer = @import("vulkan_renderer.zig").CommandBuffer;
|
const CommandBuffer = @import("vulkan_renderer.zig").CommandBuffer;
|
||||||
|
|
||||||
pub const Vector3 = @Vector(3, f32);
|
pub const Vector3 = @Vector(3, f32);
|
||||||
|
|
|
@ -7,6 +7,7 @@ const zm = @import("zmath");
|
||||||
const img = @import("zstbi");
|
const img = @import("zstbi");
|
||||||
const ai = @import("assimp.zig").c;
|
const ai = @import("assimp.zig").c;
|
||||||
|
|
||||||
|
const QueueUtils = @import("queue_utils.zig");
|
||||||
const StringUtils = @import("string_utils.zig");
|
const StringUtils = @import("string_utils.zig");
|
||||||
const Utilities = @import("utilities.zig");
|
const Utilities = @import("utilities.zig");
|
||||||
const Vertex = Utilities.Vertex;
|
const Vertex = Utilities.Vertex;
|
||||||
|
@ -39,8 +40,7 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
current_frame: u32 = 0,
|
current_frame: u32 = 0,
|
||||||
|
|
||||||
context: Context,
|
ctx: Context,
|
||||||
|
|
||||||
swapchain: Swapchain,
|
swapchain: Swapchain,
|
||||||
|
|
||||||
// Scene settings
|
// Scene settings
|
||||||
|
@ -98,9 +98,7 @@ pub const VulkanRenderer = struct {
|
||||||
graphics_command_pool: vk.CommandPool,
|
graphics_command_pool: vk.CommandPool,
|
||||||
|
|
||||||
// Utilities
|
// Utilities
|
||||||
swapchain_image_format: vk.Format,
|
|
||||||
depth_format: vk.Format,
|
depth_format: vk.Format,
|
||||||
extent: vk.Extent2D,
|
|
||||||
|
|
||||||
// Synchronisation
|
// Synchronisation
|
||||||
image_available: [MAX_FRAME_DRAWS]vk.Semaphore,
|
image_available: [MAX_FRAME_DRAWS]vk.Semaphore,
|
||||||
|
@ -110,9 +108,10 @@ pub const VulkanRenderer = struct {
|
||||||
pub fn init(allocator: std.mem.Allocator, window: sdl.Window) !Self {
|
pub fn init(allocator: std.mem.Allocator, window: sdl.Window) !Self {
|
||||||
var self: Self = undefined;
|
var self: Self = undefined;
|
||||||
|
|
||||||
self.context = try Context.init(allocator, window);
|
self.allocator = allocator;
|
||||||
|
self.ctx = try Context.init(allocator, window);
|
||||||
self.current_frame = 0;
|
self.current_frame = 0;
|
||||||
self.swapchain = try Swapchain.create(allocator, self.context);
|
self.swapchain = try Swapchain.create(allocator, self.ctx);
|
||||||
|
|
||||||
try self.createColourBufferImage();
|
try self.createColourBufferImage();
|
||||||
try self.createDepthBufferImage();
|
try self.createDepthBufferImage();
|
||||||
|
@ -123,7 +122,7 @@ pub const VulkanRenderer = struct {
|
||||||
try self.createFramebuffers();
|
try self.createFramebuffers();
|
||||||
try self.createCommandPool();
|
try self.createCommandPool();
|
||||||
|
|
||||||
self.sampler_descriptor_sets = try std.ArrayList(vk.DescriptorSet).initCapacity(self.allocator, self.swapchain_images.len);
|
self.sampler_descriptor_sets = try std.ArrayList(vk.DescriptorSet).initCapacity(self.allocator, self.swapchain.swapchain_images.len);
|
||||||
|
|
||||||
try self.createCommandBuffers();
|
try self.createCommandBuffers();
|
||||||
try self.createTextureSampler();
|
try self.createTextureSampler();
|
||||||
|
@ -139,7 +138,7 @@ pub const VulkanRenderer = struct {
|
||||||
self.texture_image_views = std.ArrayList(vk.ImageView).init(self.allocator);
|
self.texture_image_views = std.ArrayList(vk.ImageView).init(self.allocator);
|
||||||
self.model_list = std.ArrayList(MeshModel).init(allocator);
|
self.model_list = std.ArrayList(MeshModel).init(allocator);
|
||||||
|
|
||||||
const aspect: f32 = @as(f32, @floatFromInt(self.extent.width)) / @as(f32, @floatFromInt(self.extent.height));
|
const aspect: f32 = @as(f32, @floatFromInt(self.swapchain.extent.width)) / @as(f32, @floatFromInt(self.swapchain.extent.height));
|
||||||
self.ubo_view_projection.projection = zm.perspectiveFovRh(
|
self.ubo_view_projection.projection = zm.perspectiveFovRh(
|
||||||
std.math.degreesToRadians(45.0),
|
std.math.degreesToRadians(45.0),
|
||||||
aspect,
|
aspect,
|
||||||
|
@ -172,19 +171,19 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
pub fn draw(self: *Self) !void {
|
pub fn draw(self: *Self) !void {
|
||||||
// Wait for given fence to signal (open) from last draw before continuing
|
// Wait for given fence to signal (open) from last draw before continuing
|
||||||
_ = try self.device.waitForFences(
|
_ = try self.ctx.device.waitForFences(
|
||||||
1,
|
1,
|
||||||
@ptrCast(&self.draw_fences[self.current_frame]),
|
@ptrCast(&self.draw_fences[self.current_frame]),
|
||||||
vk.TRUE,
|
vk.TRUE,
|
||||||
std.math.maxInt(u64),
|
std.math.maxInt(u64),
|
||||||
);
|
);
|
||||||
// Manually reset (close) fences
|
// Manually reset (close) fences
|
||||||
try self.device.resetFences(1, @ptrCast(&self.draw_fences[self.current_frame]));
|
try self.ctx.device.resetFences(1, @ptrCast(&self.draw_fences[self.current_frame]));
|
||||||
|
|
||||||
// -- Get next image
|
// -- Get next image
|
||||||
// Get index of next image to be drawn to, and signal semaphore when ready to be drawn to
|
// Get index of next image to be drawn to, and signal semaphore when ready to be drawn to
|
||||||
const image_index_result = try self.device.acquireNextImageKHR(
|
const image_index_result = try self.ctx.device.acquireNextImageKHR(
|
||||||
self.swapchain,
|
self.swapchain.handle,
|
||||||
std.math.maxInt(u64),
|
std.math.maxInt(u64),
|
||||||
self.image_available[self.current_frame],
|
self.image_available[self.current_frame],
|
||||||
.null_handle,
|
.null_handle,
|
||||||
|
@ -208,26 +207,26 @@ pub const VulkanRenderer = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Submit command buffer to queue
|
// Submit command buffer to queue
|
||||||
try self.device.queueSubmit(self.graphics_queue.handle, 1, @ptrCast(&submit_info), self.draw_fences[self.current_frame]);
|
try self.ctx.device.queueSubmit(self.ctx.graphics_queue.handle, 1, @ptrCast(&submit_info), self.draw_fences[self.current_frame]);
|
||||||
|
|
||||||
// -- Present rendered image to screen
|
// -- Present rendered image to screen
|
||||||
const present_info: vk.PresentInfoKHR = .{
|
const present_info: vk.PresentInfoKHR = .{
|
||||||
.wait_semaphore_count = 1, // Number of semaphores to wait on
|
.wait_semaphore_count = 1, // Number of semaphores to wait on
|
||||||
.p_wait_semaphores = @ptrCast(&self.render_finished[self.current_frame]), // Semaphores to wait on
|
.p_wait_semaphores = @ptrCast(&self.render_finished[self.current_frame]), // Semaphores to wait on
|
||||||
.swapchain_count = 1, // Number of swapchains to present to
|
.swapchain_count = 1, // Number of swapchains to present to
|
||||||
.p_swapchains = @ptrCast(&self.swapchain), // Swapchains to present images to
|
.p_swapchains = @ptrCast(&self.swapchain.handle), // Swapchains to present images to
|
||||||
.p_image_indices = @ptrCast(&image_index_result.image_index), // Index of images in swapchains to present
|
.p_image_indices = @ptrCast(&image_index_result.image_index), // Index of images in swapchains to present
|
||||||
};
|
};
|
||||||
|
|
||||||
// Present image
|
// Present image
|
||||||
_ = try self.device.queuePresentKHR(self.presentation_queue.handle, &present_info);
|
_ = try self.ctx.device.queuePresentKHR(self.ctx.presentation_queue.handle, &present_info);
|
||||||
|
|
||||||
// Get next frame (use % to keep the current frame below MAX_FRAME_DRAWS)
|
// Get next frame (use % to keep the current frame below MAX_FRAME_DRAWS)
|
||||||
self.current_frame = (self.current_frame + 1) % MAX_FRAME_DRAWS;
|
self.current_frame = (self.current_frame + 1) % MAX_FRAME_DRAWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
self.device.deviceWaitIdle() catch undefined;
|
self.ctx.device.deviceWaitIdle() catch undefined;
|
||||||
|
|
||||||
for (0..self.model_list.items.len) |i| {
|
for (0..self.model_list.items.len) |i| {
|
||||||
self.model_list.items[i].destroy();
|
self.model_list.items[i].destroy();
|
||||||
|
@ -239,16 +238,16 @@ pub const VulkanRenderer = struct {
|
||||||
}
|
}
|
||||||
self.image_files.deinit();
|
self.image_files.deinit();
|
||||||
|
|
||||||
self.device.destroySampler(self.texture_sampler, null);
|
self.ctx.device.destroySampler(self.texture_sampler, null);
|
||||||
|
|
||||||
for (
|
for (
|
||||||
self.texture_images.items,
|
self.texture_images.items,
|
||||||
self.texture_image_memory.items,
|
self.texture_image_memory.items,
|
||||||
self.texture_image_views.items,
|
self.texture_image_views.items,
|
||||||
) |tex_image, tex_image_memory, tex_image_view| {
|
) |tex_image, tex_image_memory, tex_image_view| {
|
||||||
self.device.destroyImage(tex_image, null);
|
self.ctx.device.destroyImage(tex_image, null);
|
||||||
self.device.freeMemory(tex_image_memory, null);
|
self.ctx.device.freeMemory(tex_image_memory, null);
|
||||||
self.device.destroyImageView(tex_image_view, null);
|
self.ctx.device.destroyImageView(tex_image_view, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.texture_images.deinit();
|
self.texture_images.deinit();
|
||||||
|
@ -256,9 +255,9 @@ pub const VulkanRenderer = struct {
|
||||||
self.texture_image_views.deinit();
|
self.texture_image_views.deinit();
|
||||||
|
|
||||||
for (0..self.depth_buffer_image.len) |i| {
|
for (0..self.depth_buffer_image.len) |i| {
|
||||||
self.device.destroyImageView(self.depth_buffer_image_view[i], null);
|
self.ctx.device.destroyImageView(self.depth_buffer_image_view[i], null);
|
||||||
self.device.destroyImage(self.depth_buffer_image[i], null);
|
self.ctx.device.destroyImage(self.depth_buffer_image[i], null);
|
||||||
self.device.freeMemory(self.depth_buffer_image_memory[i], null);
|
self.ctx.device.freeMemory(self.depth_buffer_image_memory[i], null);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allocator.free(self.depth_buffer_image);
|
self.allocator.free(self.depth_buffer_image);
|
||||||
|
@ -266,61 +265,61 @@ pub const VulkanRenderer = struct {
|
||||||
self.allocator.free(self.depth_buffer_image_view);
|
self.allocator.free(self.depth_buffer_image_view);
|
||||||
|
|
||||||
for (0..self.colour_buffer_image.len) |i| {
|
for (0..self.colour_buffer_image.len) |i| {
|
||||||
self.device.destroyImageView(self.colour_buffer_image_view[i], null);
|
self.ctx.device.destroyImageView(self.colour_buffer_image_view[i], null);
|
||||||
self.device.destroyImage(self.colour_buffer_image[i], null);
|
self.ctx.device.destroyImage(self.colour_buffer_image[i], null);
|
||||||
self.device.freeMemory(self.colour_buffer_image_memory[i], null);
|
self.ctx.device.freeMemory(self.colour_buffer_image_memory[i], null);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allocator.free(self.colour_buffer_image);
|
self.allocator.free(self.colour_buffer_image);
|
||||||
self.allocator.free(self.colour_buffer_image_memory);
|
self.allocator.free(self.colour_buffer_image_memory);
|
||||||
self.allocator.free(self.colour_buffer_image_view);
|
self.allocator.free(self.colour_buffer_image_view);
|
||||||
|
|
||||||
self.device.destroyDescriptorPool(self.input_descriptor_pool, null);
|
self.ctx.device.destroyDescriptorPool(self.input_descriptor_pool, null);
|
||||||
self.device.destroyDescriptorPool(self.descriptor_pool, null);
|
self.ctx.device.destroyDescriptorPool(self.descriptor_pool, null);
|
||||||
self.device.destroyDescriptorSetLayout(self.descriptor_set_layout, null);
|
self.ctx.device.destroyDescriptorSetLayout(self.descriptor_set_layout, null);
|
||||||
self.device.destroyDescriptorPool(self.sampler_descriptor_pool, null);
|
self.ctx.device.destroyDescriptorPool(self.sampler_descriptor_pool, null);
|
||||||
self.device.destroyDescriptorSetLayout(self.sampler_set_layout, null);
|
self.ctx.device.destroyDescriptorSetLayout(self.sampler_set_layout, null);
|
||||||
self.device.destroyDescriptorSetLayout(self.input_set_layout, null);
|
self.ctx.device.destroyDescriptorSetLayout(self.input_set_layout, null);
|
||||||
self.sampler_descriptor_sets.deinit();
|
self.sampler_descriptor_sets.deinit();
|
||||||
self.allocator.free(self.input_descriptor_sets);
|
self.allocator.free(self.input_descriptor_sets);
|
||||||
|
|
||||||
for (0..self.swapchain_images.len) |i| {
|
for (0..self.swapchain.swapchain_images.len) |i| {
|
||||||
self.device.destroyBuffer(self.vp_uniform_buffer[i], null);
|
self.ctx.device.destroyBuffer(self.vp_uniform_buffer[i], null);
|
||||||
self.device.freeMemory(self.vp_uniform_buffer_memory[i], null);
|
self.ctx.device.freeMemory(self.vp_uniform_buffer_memory[i], null);
|
||||||
}
|
}
|
||||||
self.allocator.free(self.vp_uniform_buffer);
|
self.allocator.free(self.vp_uniform_buffer);
|
||||||
self.allocator.free(self.vp_uniform_buffer_memory);
|
self.allocator.free(self.vp_uniform_buffer_memory);
|
||||||
self.allocator.free(self.descriptor_sets);
|
self.allocator.free(self.descriptor_sets);
|
||||||
|
|
||||||
for (0..MAX_FRAME_DRAWS) |i| {
|
for (0..MAX_FRAME_DRAWS) |i| {
|
||||||
self.device.destroySemaphore(self.render_finished[i], null);
|
self.ctx.device.destroySemaphore(self.render_finished[i], null);
|
||||||
self.device.destroySemaphore(self.image_available[i], null);
|
self.ctx.device.destroySemaphore(self.image_available[i], null);
|
||||||
self.device.destroyFence(self.draw_fences[i], null);
|
self.ctx.device.destroyFence(self.draw_fences[i], null);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allocator.free(self.command_buffers);
|
self.allocator.free(self.command_buffers);
|
||||||
self.device.destroyCommandPool(self.graphics_command_pool, null);
|
self.ctx.device.destroyCommandPool(self.graphics_command_pool, null);
|
||||||
|
|
||||||
for (self.swapchain_framebuffers) |framebuffer| {
|
for (self.swapchain.swapchain_framebuffers) |framebuffer| {
|
||||||
self.device.destroyFramebuffer(framebuffer, null);
|
self.ctx.device.destroyFramebuffer(framebuffer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allocator.free(self.swapchain_framebuffers);
|
self.allocator.free(self.swapchain.swapchain_framebuffers);
|
||||||
|
|
||||||
self.device.destroyPipeline(self.second_pipeline, null);
|
self.ctx.device.destroyPipeline(self.second_pipeline, null);
|
||||||
self.device.destroyPipelineLayout(self.second_pipeline_layout, null);
|
self.ctx.device.destroyPipelineLayout(self.second_pipeline_layout, null);
|
||||||
self.device.destroyPipeline(self.graphics_pipeline, null);
|
self.ctx.device.destroyPipeline(self.graphics_pipeline, null);
|
||||||
self.device.destroyPipelineLayout(self.pipeline_layout, null);
|
self.ctx.device.destroyPipelineLayout(self.pipeline_layout, null);
|
||||||
self.device.destroyRenderPass(self.render_pass, null);
|
self.ctx.device.destroyRenderPass(self.render_pass, null);
|
||||||
|
|
||||||
for (self.swapchain_images) |swapchain_image| {
|
for (self.swapchain.swapchain_images) |swapchain_image| {
|
||||||
self.device.destroyImageView(swapchain_image.image_view, null);
|
self.ctx.device.destroyImageView(swapchain_image.image_view, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allocator.free(self.swapchain_images);
|
self.allocator.free(self.swapchain.swapchain_images);
|
||||||
self.device.destroySwapchainKHR(self.swapchain, null);
|
self.ctx.device.destroySwapchainKHR(self.swapchain.handle, null);
|
||||||
|
|
||||||
self.context.deinit();
|
self.ctx.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createRenderPass(self: *Self) !void {
|
fn createRenderPass(self: *Self) !void {
|
||||||
|
@ -332,8 +331,8 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
// Colour attachment (input)
|
// Colour attachment (input)
|
||||||
const colour_format = chooseSupportedFormat(
|
const colour_format = chooseSupportedFormat(
|
||||||
self.physical_device,
|
self.ctx.physical_device,
|
||||||
self.instance,
|
self.ctx.instance,
|
||||||
&[_]vk.Format{.r8g8b8a8_srgb},
|
&[_]vk.Format{.r8g8b8a8_srgb},
|
||||||
.optimal,
|
.optimal,
|
||||||
.{ .color_attachment_bit = true },
|
.{ .color_attachment_bit = true },
|
||||||
|
@ -384,7 +383,7 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
// Colour attachment of the render pass
|
// Colour attachment of the render pass
|
||||||
const swapchain_colour_attachment: vk.AttachmentDescription = .{
|
const swapchain_colour_attachment: vk.AttachmentDescription = .{
|
||||||
.format = self.swapchain_image_format, // Format to use for attachment
|
.format = self.swapchain.swapchain_image_format, // Format to use for attachment
|
||||||
.samples = .{ .@"1_bit" = true }, // Number of samples to write for multisampling
|
.samples = .{ .@"1_bit" = true }, // Number of samples to write for multisampling
|
||||||
.load_op = .clear, // Describes what to do with attachment before rendering
|
.load_op = .clear, // Describes what to do with attachment before rendering
|
||||||
.store_op = .store, // Describes what to do with attachment after rendering
|
.store_op = .store, // Describes what to do with attachment after rendering
|
||||||
|
@ -471,7 +470,7 @@ pub const VulkanRenderer = struct {
|
||||||
.p_dependencies = &subpass_dependencies,
|
.p_dependencies = &subpass_dependencies,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.render_pass = try self.device.createRenderPass(&render_pass_create_info, null);
|
self.render_pass = try self.ctx.device.createRenderPass(&render_pass_create_info, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createDescriptorSetLayout(self: *Self) !void {
|
fn createDescriptorSetLayout(self: *Self) !void {
|
||||||
|
@ -495,7 +494,7 @@ pub const VulkanRenderer = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create descriptor set layout
|
// Create descriptor set layout
|
||||||
self.descriptor_set_layout = try self.device.createDescriptorSetLayout(&layout_create_info, null);
|
self.descriptor_set_layout = try self.ctx.device.createDescriptorSetLayout(&layout_create_info, null);
|
||||||
|
|
||||||
// -- Texture sampler descriptor set layout --
|
// -- Texture sampler descriptor set layout --
|
||||||
|
|
||||||
|
@ -514,7 +513,7 @@ pub const VulkanRenderer = struct {
|
||||||
.p_bindings = @ptrCast(&sampler_layout_binding),
|
.p_bindings = @ptrCast(&sampler_layout_binding),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.sampler_set_layout = try self.device.createDescriptorSetLayout(&texture_layout_info, null);
|
self.sampler_set_layout = try self.ctx.device.createDescriptorSetLayout(&texture_layout_info, null);
|
||||||
|
|
||||||
// -- Create input attachment image descriptor set layout
|
// -- Create input attachment image descriptor set layout
|
||||||
// Colour input binding
|
// Colour input binding
|
||||||
|
@ -542,7 +541,7 @@ pub const VulkanRenderer = struct {
|
||||||
.p_bindings = &input_bindings,
|
.p_bindings = &input_bindings,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.input_set_layout = try self.device.createDescriptorSetLayout(&input_layout_create_info, null);
|
self.input_set_layout = try self.ctx.device.createDescriptorSetLayout(&input_layout_create_info, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createPushConstantRange(self: *Self) !void {
|
fn createPushConstantRange(self: *Self) !void {
|
||||||
|
@ -555,14 +554,14 @@ pub const VulkanRenderer = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createColourBufferImage(self: *Self) !void {
|
fn createColourBufferImage(self: *Self) !void {
|
||||||
self.colour_buffer_image = try self.allocator.alloc(vk.Image, self.swapchain_images.len);
|
self.colour_buffer_image = try self.allocator.alloc(vk.Image, self.swapchain.swapchain_images.len);
|
||||||
self.colour_buffer_image_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain_images.len);
|
self.colour_buffer_image_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain.swapchain_images.len);
|
||||||
self.colour_buffer_image_view = try self.allocator.alloc(vk.ImageView, self.swapchain_images.len);
|
self.colour_buffer_image_view = try self.allocator.alloc(vk.ImageView, self.swapchain.swapchain_images.len);
|
||||||
|
|
||||||
// Get supported format for colour attachment
|
// Get supported format for colour attachment
|
||||||
const colour_format = chooseSupportedFormat(
|
const colour_format = chooseSupportedFormat(
|
||||||
self.physical_device,
|
self.ctx.physical_device,
|
||||||
self.instance,
|
self.ctx.instance,
|
||||||
&[_]vk.Format{.r8g8b8a8_srgb},
|
&[_]vk.Format{.r8g8b8a8_srgb},
|
||||||
.optimal,
|
.optimal,
|
||||||
.{ .color_attachment_bit = true },
|
.{ .color_attachment_bit = true },
|
||||||
|
@ -570,9 +569,9 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
// Create colour buffers
|
// Create colour buffers
|
||||||
for (0..self.colour_buffer_image.len) |i| {
|
for (0..self.colour_buffer_image.len) |i| {
|
||||||
self.colour_buffer_image[i] = try self.createImage(
|
self.colour_buffer_image[i] = try self.swapchain.createImage(
|
||||||
self.extent.width,
|
self.swapchain.extent.width,
|
||||||
self.extent.height,
|
self.swapchain.extent.height,
|
||||||
colour_format,
|
colour_format,
|
||||||
.optimal,
|
.optimal,
|
||||||
.{ .color_attachment_bit = true, .input_attachment_bit = true },
|
.{ .color_attachment_bit = true, .input_attachment_bit = true },
|
||||||
|
@ -580,7 +579,7 @@ pub const VulkanRenderer = struct {
|
||||||
&self.colour_buffer_image_memory[i],
|
&self.colour_buffer_image_memory[i],
|
||||||
);
|
);
|
||||||
|
|
||||||
self.colour_buffer_image_view[i] = try self.createImageView(
|
self.colour_buffer_image_view[i] = try self.swapchain.createImageView(
|
||||||
self.colour_buffer_image[i],
|
self.colour_buffer_image[i],
|
||||||
colour_format,
|
colour_format,
|
||||||
.{ .color_bit = true },
|
.{ .color_bit = true },
|
||||||
|
@ -589,15 +588,15 @@ pub const VulkanRenderer = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createDepthBufferImage(self: *Self) !void {
|
fn createDepthBufferImage(self: *Self) !void {
|
||||||
self.depth_buffer_image = try self.allocator.alloc(vk.Image, self.swapchain_images.len);
|
self.depth_buffer_image = try self.allocator.alloc(vk.Image, self.swapchain.swapchain_images.len);
|
||||||
self.depth_buffer_image_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain_images.len);
|
self.depth_buffer_image_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain.swapchain_images.len);
|
||||||
self.depth_buffer_image_view = try self.allocator.alloc(vk.ImageView, self.swapchain_images.len);
|
self.depth_buffer_image_view = try self.allocator.alloc(vk.ImageView, self.swapchain.swapchain_images.len);
|
||||||
|
|
||||||
// Get supported depth buffer format
|
// Get supported depth buffer format
|
||||||
const formats = [_]vk.Format{ .d32_sfloat_s8_uint, .d32_sfloat, .d24_unorm_s8_uint };
|
const formats = [_]vk.Format{ .d32_sfloat_s8_uint, .d32_sfloat, .d24_unorm_s8_uint };
|
||||||
self.depth_format = chooseSupportedFormat(
|
self.depth_format = chooseSupportedFormat(
|
||||||
self.physical_device,
|
self.ctx.physical_device,
|
||||||
self.instance,
|
self.ctx.instance,
|
||||||
&formats,
|
&formats,
|
||||||
.optimal,
|
.optimal,
|
||||||
.{ .depth_stencil_attachment_bit = true },
|
.{ .depth_stencil_attachment_bit = true },
|
||||||
|
@ -605,9 +604,9 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
for (0..self.depth_buffer_image.len) |i| {
|
for (0..self.depth_buffer_image.len) |i| {
|
||||||
// Create depth buffer image
|
// Create depth buffer image
|
||||||
self.depth_buffer_image[i] = try self.createImage(
|
self.depth_buffer_image[i] = try self.swapchain.createImage(
|
||||||
self.extent.width,
|
self.swapchain.extent.width,
|
||||||
self.extent.height,
|
self.swapchain.extent.height,
|
||||||
self.depth_format,
|
self.depth_format,
|
||||||
.optimal,
|
.optimal,
|
||||||
.{ .depth_stencil_attachment_bit = true, .input_attachment_bit = true },
|
.{ .depth_stencil_attachment_bit = true, .input_attachment_bit = true },
|
||||||
|
@ -616,23 +615,23 @@ pub const VulkanRenderer = struct {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create depth buffer image view
|
// Create depth buffer image view
|
||||||
self.depth_buffer_image_view[i] = try self.createImageView(self.depth_buffer_image[i], self.depth_format, .{ .depth_bit = true });
|
self.depth_buffer_image_view[i] = try self.swapchain.createImageView(self.depth_buffer_image[i], self.depth_format, .{ .depth_bit = true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createGraphicsPipeline(self: *Self) !void {
|
fn createGraphicsPipeline(self: *Self) !void {
|
||||||
// Create shader modules
|
// Create shader modules
|
||||||
const vert = try self.device.createShaderModule(&.{
|
const vert = try self.ctx.device.createShaderModule(&.{
|
||||||
.code_size = shaders.shader_vert.len,
|
.code_size = shaders.shader_vert.len,
|
||||||
.p_code = @ptrCast(&shaders.shader_vert),
|
.p_code = @ptrCast(&shaders.shader_vert),
|
||||||
}, null);
|
}, null);
|
||||||
defer self.device.destroyShaderModule(vert, null);
|
defer self.ctx.device.destroyShaderModule(vert, null);
|
||||||
|
|
||||||
const frag = try self.device.createShaderModule(&.{
|
const frag = try self.ctx.device.createShaderModule(&.{
|
||||||
.code_size = shaders.shader_frag.len,
|
.code_size = shaders.shader_frag.len,
|
||||||
.p_code = @ptrCast(&shaders.shader_frag),
|
.p_code = @ptrCast(&shaders.shader_frag),
|
||||||
}, null);
|
}, null);
|
||||||
defer self.device.destroyShaderModule(frag, null);
|
defer self.ctx.device.destroyShaderModule(frag, null);
|
||||||
|
|
||||||
// -- Shader stage creation information --
|
// -- Shader stage creation information --
|
||||||
|
|
||||||
|
@ -707,15 +706,15 @@ pub const VulkanRenderer = struct {
|
||||||
self.viewport = .{
|
self.viewport = .{
|
||||||
.x = 0.0,
|
.x = 0.0,
|
||||||
.y = 0.0,
|
.y = 0.0,
|
||||||
.width = @floatFromInt(self.extent.width),
|
.width = @floatFromInt(self.swapchain.extent.width),
|
||||||
.height = @floatFromInt(self.extent.height),
|
.height = @floatFromInt(self.swapchain.extent.height),
|
||||||
.min_depth = 0.0,
|
.min_depth = 0.0,
|
||||||
.max_depth = 1.0,
|
.max_depth = 1.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.scissor = .{
|
self.scissor = .{
|
||||||
.offset = .{ .x = 0, .y = 0 },
|
.offset = .{ .x = 0, .y = 0 },
|
||||||
.extent = self.extent,
|
.extent = self.swapchain.extent,
|
||||||
};
|
};
|
||||||
|
|
||||||
const viewport_state_create_info: vk.PipelineViewportStateCreateInfo = .{
|
const viewport_state_create_info: vk.PipelineViewportStateCreateInfo = .{
|
||||||
|
@ -793,7 +792,7 @@ pub const VulkanRenderer = struct {
|
||||||
.p_push_constant_ranges = @ptrCast(&self.push_constant_range),
|
.p_push_constant_ranges = @ptrCast(&self.push_constant_range),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.pipeline_layout = try self.device.createPipelineLayout(&pipeline_layout_create_info, null);
|
self.pipeline_layout = try self.ctx.device.createPipelineLayout(&pipeline_layout_create_info, null);
|
||||||
|
|
||||||
// -- Depth stencil testing --
|
// -- Depth stencil testing --
|
||||||
var depth_stencil_create_info: vk.PipelineDepthStencilStateCreateInfo = .{
|
var depth_stencil_create_info: vk.PipelineDepthStencilStateCreateInfo = .{
|
||||||
|
@ -828,7 +827,7 @@ pub const VulkanRenderer = struct {
|
||||||
.base_pipeline_index = -1, // Or index of pipeline being created to derive from (in case creating multiple at once)
|
.base_pipeline_index = -1, // Or index of pipeline being created to derive from (in case creating multiple at once)
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = try self.device.createGraphicsPipelines(
|
_ = try self.ctx.device.createGraphicsPipelines(
|
||||||
.null_handle,
|
.null_handle,
|
||||||
1,
|
1,
|
||||||
@ptrCast(&pipeline_create_info),
|
@ptrCast(&pipeline_create_info),
|
||||||
|
@ -838,17 +837,17 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
// -- Create second pass pipeline
|
// -- Create second pass pipeline
|
||||||
// Second pass shaders
|
// Second pass shaders
|
||||||
const second_vert_shader_module = try self.device.createShaderModule(&.{
|
const second_vert_shader_module = try self.ctx.device.createShaderModule(&.{
|
||||||
.code_size = shaders.second_vert.len,
|
.code_size = shaders.second_vert.len,
|
||||||
.p_code = @ptrCast(&shaders.second_vert),
|
.p_code = @ptrCast(&shaders.second_vert),
|
||||||
}, null);
|
}, null);
|
||||||
defer self.device.destroyShaderModule(second_vert_shader_module, null);
|
defer self.ctx.device.destroyShaderModule(second_vert_shader_module, null);
|
||||||
|
|
||||||
const second_frag_shader_module = try self.device.createShaderModule(&.{
|
const second_frag_shader_module = try self.ctx.device.createShaderModule(&.{
|
||||||
.code_size = shaders.second_frag.len,
|
.code_size = shaders.second_frag.len,
|
||||||
.p_code = @ptrCast(&shaders.second_frag),
|
.p_code = @ptrCast(&shaders.second_frag),
|
||||||
}, null);
|
}, null);
|
||||||
defer self.device.destroyShaderModule(second_frag_shader_module, null);
|
defer self.ctx.device.destroyShaderModule(second_frag_shader_module, null);
|
||||||
|
|
||||||
// Set new shaders
|
// Set new shaders
|
||||||
vertex_shader_create_info.module = second_vert_shader_module;
|
vertex_shader_create_info.module = second_vert_shader_module;
|
||||||
|
@ -871,7 +870,7 @@ pub const VulkanRenderer = struct {
|
||||||
.p_set_layouts = @ptrCast(&self.input_set_layout),
|
.p_set_layouts = @ptrCast(&self.input_set_layout),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.second_pipeline_layout = try self.device.createPipelineLayout(&second_pipeline_layout_create_info, null);
|
self.second_pipeline_layout = try self.ctx.device.createPipelineLayout(&second_pipeline_layout_create_info, null);
|
||||||
|
|
||||||
pipeline_create_info.stage_count = @intCast(second_shader_stages.len);
|
pipeline_create_info.stage_count = @intCast(second_shader_stages.len);
|
||||||
pipeline_create_info.p_stages = &second_shader_stages;
|
pipeline_create_info.p_stages = &second_shader_stages;
|
||||||
|
@ -879,7 +878,7 @@ pub const VulkanRenderer = struct {
|
||||||
pipeline_create_info.subpass = 1;
|
pipeline_create_info.subpass = 1;
|
||||||
|
|
||||||
// Create second pipeline
|
// Create second pipeline
|
||||||
_ = try self.device.createGraphicsPipelines(
|
_ = try self.ctx.device.createGraphicsPipelines(
|
||||||
.null_handle,
|
.null_handle,
|
||||||
1,
|
1,
|
||||||
@ptrCast(&pipeline_create_info),
|
@ptrCast(&pipeline_create_info),
|
||||||
|
@ -889,10 +888,10 @@ pub const VulkanRenderer = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createFramebuffers(self: *Self) !void {
|
fn createFramebuffers(self: *Self) !void {
|
||||||
self.swapchain_framebuffers = try self.allocator.alloc(vk.Framebuffer, self.swapchain_images.len);
|
self.swapchain.swapchain_framebuffers = try self.allocator.alloc(vk.Framebuffer, self.swapchain.swapchain_images.len);
|
||||||
|
|
||||||
// Create a frammebuffer for each swapchain image
|
// Create a frammebuffer for each swapchain image
|
||||||
for (self.swapchain_images, 0..) |swapchain_image, i| {
|
for (self.swapchain.swapchain_images, 0..) |swapchain_image, i| {
|
||||||
// Order matters
|
// Order matters
|
||||||
const attachments = [_]vk.ImageView{
|
const attachments = [_]vk.ImageView{
|
||||||
swapchain_image.image_view,
|
swapchain_image.image_view,
|
||||||
|
@ -904,18 +903,18 @@ pub const VulkanRenderer = struct {
|
||||||
.render_pass = self.render_pass, // Render pass layout the frambuffer will be used with
|
.render_pass = self.render_pass, // Render pass layout the frambuffer will be used with
|
||||||
.attachment_count = @intCast(attachments.len),
|
.attachment_count = @intCast(attachments.len),
|
||||||
.p_attachments = &attachments, // List of attachments (1:1 with render pass)
|
.p_attachments = &attachments, // List of attachments (1:1 with render pass)
|
||||||
.width = self.extent.width, // Framebuffer width
|
.width = self.swapchain.extent.width, // Framebuffer width
|
||||||
.height = self.extent.height, // Framebuffer height
|
.height = self.swapchain.extent.height, // Framebuffer height
|
||||||
.layers = 1, // Framebuffer layers
|
.layers = 1, // Framebuffer layers
|
||||||
};
|
};
|
||||||
|
|
||||||
self.swapchain_framebuffers[i] = try self.device.createFramebuffer(&framebuffer_create_info, null);
|
self.swapchain.swapchain_framebuffers[i] = try self.ctx.device.createFramebuffer(&framebuffer_create_info, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createCommandPool(self: *Self) !void {
|
fn createCommandPool(self: *Self) !void {
|
||||||
// Get indices of queue families from device
|
// Get indices of queue families from device
|
||||||
const queue_family_indices = try self.getQueueFamilies(self.physical_device);
|
const queue_family_indices = try QueueUtils.getQueueFamilies(self.ctx, self.ctx.physical_device);
|
||||||
|
|
||||||
const pool_create_info: vk.CommandPoolCreateInfo = .{
|
const pool_create_info: vk.CommandPoolCreateInfo = .{
|
||||||
// Queue family type that buffers from this command pool will use
|
// Queue family type that buffers from this command pool will use
|
||||||
|
@ -924,12 +923,12 @@ pub const VulkanRenderer = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a graphics queue family command pool
|
// Create a graphics queue family command pool
|
||||||
self.graphics_command_pool = try self.device.createCommandPool(&pool_create_info, null);
|
self.graphics_command_pool = try self.ctx.device.createCommandPool(&pool_create_info, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createCommandBuffers(self: *Self) !void {
|
fn createCommandBuffers(self: *Self) !void {
|
||||||
// Allocate one command buffer for each framebuffer
|
// Allocate one command buffer for each framebuffer
|
||||||
const command_buffer_handles = try self.allocator.alloc(vk.CommandBuffer, self.swapchain_framebuffers.len);
|
const command_buffer_handles = try self.allocator.alloc(vk.CommandBuffer, self.swapchain.swapchain_framebuffers.len);
|
||||||
defer self.allocator.free(command_buffer_handles);
|
defer self.allocator.free(command_buffer_handles);
|
||||||
self.command_buffers = try self.allocator.alloc(CommandBuffer, command_buffer_handles.len);
|
self.command_buffers = try self.allocator.alloc(CommandBuffer, command_buffer_handles.len);
|
||||||
|
|
||||||
|
@ -940,9 +939,9 @@ pub const VulkanRenderer = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allocate command buffers and place handles in array of buffers
|
// Allocate command buffers and place handles in array of buffers
|
||||||
try self.device.allocateCommandBuffers(&command_buffer_allocate_info, command_buffer_handles.ptr);
|
try self.ctx.device.allocateCommandBuffers(&command_buffer_allocate_info, command_buffer_handles.ptr);
|
||||||
for (command_buffer_handles, 0..) |command_buffer_handle, i| {
|
for (command_buffer_handles, 0..) |command_buffer_handle, i| {
|
||||||
self.command_buffers[i] = CommandBuffer.init(command_buffer_handle, self.device.wrapper);
|
self.command_buffers[i] = CommandBuffer.init(command_buffer_handle, self.ctx.device.wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -952,9 +951,9 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
// Semaphore creation information
|
// Semaphore creation information
|
||||||
for (0..MAX_FRAME_DRAWS) |i| {
|
for (0..MAX_FRAME_DRAWS) |i| {
|
||||||
self.image_available[i] = try self.device.createSemaphore(&.{}, null);
|
self.image_available[i] = try self.ctx.device.createSemaphore(&.{}, null);
|
||||||
self.render_finished[i] = try self.device.createSemaphore(&.{}, null);
|
self.render_finished[i] = try self.ctx.device.createSemaphore(&.{}, null);
|
||||||
self.draw_fences[i] = try self.device.createFence(&fence_create_info, null);
|
self.draw_fences[i] = try self.ctx.device.createFence(&fence_create_info, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -978,7 +977,7 @@ pub const VulkanRenderer = struct {
|
||||||
.compare_op = .never,
|
.compare_op = .never,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.texture_sampler = try self.device.createSampler(&sampler_create_info, null);
|
self.texture_sampler = try self.ctx.device.createSampler(&sampler_create_info, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createUniformBuffers(self: *Self) !void {
|
fn createUniformBuffers(self: *Self) !void {
|
||||||
|
@ -986,15 +985,15 @@ pub const VulkanRenderer = struct {
|
||||||
const vp_buffer_size: vk.DeviceSize = @sizeOf(UboViewProjection);
|
const vp_buffer_size: vk.DeviceSize = @sizeOf(UboViewProjection);
|
||||||
|
|
||||||
// One uniform buffer for each image (and by extension, command buffer)
|
// One uniform buffer for each image (and by extension, command buffer)
|
||||||
self.vp_uniform_buffer = try self.allocator.alloc(vk.Buffer, self.swapchain_images.len);
|
self.vp_uniform_buffer = try self.allocator.alloc(vk.Buffer, self.swapchain.swapchain_images.len);
|
||||||
self.vp_uniform_buffer_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain_images.len);
|
self.vp_uniform_buffer_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain.swapchain_images.len);
|
||||||
|
|
||||||
// Create the uniform buffers
|
// Create the uniform buffers
|
||||||
for (0..self.vp_uniform_buffer.len) |i| {
|
for (0..self.vp_uniform_buffer.len) |i| {
|
||||||
try Utilities.createBuffer(
|
try Utilities.createBuffer(
|
||||||
self.physical_device,
|
self.ctx.physical_device,
|
||||||
self.instance,
|
self.ctx.instance,
|
||||||
self.device,
|
self.ctx.device,
|
||||||
vp_buffer_size,
|
vp_buffer_size,
|
||||||
.{ .uniform_buffer_bit = true },
|
.{ .uniform_buffer_bit = true },
|
||||||
.{ .host_visible_bit = true, .host_coherent_bit = true },
|
.{ .host_visible_bit = true, .host_coherent_bit = true },
|
||||||
|
@ -1019,13 +1018,13 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
// Data to create descriptor pool
|
// Data to create descriptor pool
|
||||||
const pool_create_info: vk.DescriptorPoolCreateInfo = .{
|
const pool_create_info: vk.DescriptorPoolCreateInfo = .{
|
||||||
.max_sets = @intCast(self.swapchain_images.len), // Maximum number of descriptor sets that can be created from pool
|
.max_sets = @intCast(self.swapchain.swapchain_images.len), // Maximum number of descriptor sets that can be created from pool
|
||||||
.pool_size_count = @intCast(descriptor_pool_sizes.len), // Amount of pool sizes being passed
|
.pool_size_count = @intCast(descriptor_pool_sizes.len), // Amount of pool sizes being passed
|
||||||
.p_pool_sizes = &descriptor_pool_sizes, // Pool sizes to create pool with
|
.p_pool_sizes = &descriptor_pool_sizes, // Pool sizes to create pool with
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create descriptor pool
|
// Create descriptor pool
|
||||||
self.descriptor_pool = try self.device.createDescriptorPool(&pool_create_info, null);
|
self.descriptor_pool = try self.ctx.device.createDescriptorPool(&pool_create_info, null);
|
||||||
|
|
||||||
// -- Create sampler descriptor pool --
|
// -- Create sampler descriptor pool --
|
||||||
|
|
||||||
|
@ -1042,7 +1041,7 @@ pub const VulkanRenderer = struct {
|
||||||
.p_pool_sizes = @ptrCast(&sampler_pool_size),
|
.p_pool_sizes = @ptrCast(&sampler_pool_size),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.sampler_descriptor_pool = try self.device.createDescriptorPool(&sampler_pool_create_info, null);
|
self.sampler_descriptor_pool = try self.ctx.device.createDescriptorPool(&sampler_pool_create_info, null);
|
||||||
|
|
||||||
// -- Create input attachment descriptor pool
|
// -- Create input attachment descriptor pool
|
||||||
// Colour attachment pool size
|
// Colour attachment pool size
|
||||||
|
@ -1061,19 +1060,19 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
// Create input attachment pool
|
// Create input attachment pool
|
||||||
const input_pool_create_info: vk.DescriptorPoolCreateInfo = .{
|
const input_pool_create_info: vk.DescriptorPoolCreateInfo = .{
|
||||||
.max_sets = @intCast(self.swapchain_images.len),
|
.max_sets = @intCast(self.swapchain.swapchain_images.len),
|
||||||
.pool_size_count = @intCast(input_pool_sizes.len),
|
.pool_size_count = @intCast(input_pool_sizes.len),
|
||||||
.p_pool_sizes = &input_pool_sizes,
|
.p_pool_sizes = &input_pool_sizes,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.input_descriptor_pool = try self.device.createDescriptorPool(&input_pool_create_info, null);
|
self.input_descriptor_pool = try self.ctx.device.createDescriptorPool(&input_pool_create_info, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createDescriptorSets(self: *Self) !void {
|
fn createDescriptorSets(self: *Self) !void {
|
||||||
// One descriptor set for every buffer
|
// One descriptor set for every buffer
|
||||||
self.descriptor_sets = try self.allocator.alloc(vk.DescriptorSet, self.swapchain_images.len);
|
self.descriptor_sets = try self.allocator.alloc(vk.DescriptorSet, self.swapchain.swapchain_images.len);
|
||||||
|
|
||||||
var set_layouts = try self.allocator.alloc(vk.DescriptorSetLayout, self.swapchain_images.len);
|
var set_layouts = try self.allocator.alloc(vk.DescriptorSetLayout, self.swapchain.swapchain_images.len);
|
||||||
defer self.allocator.free(set_layouts);
|
defer self.allocator.free(set_layouts);
|
||||||
for (0..set_layouts.len) |i| {
|
for (0..set_layouts.len) |i| {
|
||||||
set_layouts[i] = self.descriptor_set_layout;
|
set_layouts[i] = self.descriptor_set_layout;
|
||||||
|
@ -1082,15 +1081,15 @@ pub const VulkanRenderer = struct {
|
||||||
// Descriptor set allocation info
|
// Descriptor set allocation info
|
||||||
const set_alloc_info: vk.DescriptorSetAllocateInfo = .{
|
const set_alloc_info: vk.DescriptorSetAllocateInfo = .{
|
||||||
.descriptor_pool = self.descriptor_pool, // Pool to allocate descriptor set from
|
.descriptor_pool = self.descriptor_pool, // Pool to allocate descriptor set from
|
||||||
.descriptor_set_count = @intCast(self.swapchain_images.len), // Number of sets to allocate
|
.descriptor_set_count = @intCast(self.swapchain.swapchain_images.len), // Number of sets to allocate
|
||||||
.p_set_layouts = set_layouts.ptr, // Layouts to use to allocate sets (1:1 relationship)
|
.p_set_layouts = set_layouts.ptr, // Layouts to use to allocate sets (1:1 relationship)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allocate descriptor sets (multiple)
|
// Allocate descriptor sets (multiple)
|
||||||
try self.device.allocateDescriptorSets(&set_alloc_info, self.descriptor_sets.ptr);
|
try self.ctx.device.allocateDescriptorSets(&set_alloc_info, self.descriptor_sets.ptr);
|
||||||
|
|
||||||
// Update all of descriptor set buffer bindings
|
// Update all of descriptor set buffer bindings
|
||||||
for (0..self.swapchain_images.len) |i| {
|
for (0..self.swapchain.swapchain_images.len) |i| {
|
||||||
// -- View projection descriptor
|
// -- View projection descriptor
|
||||||
// Buffer info and data offset info
|
// Buffer info and data offset info
|
||||||
const vp_buffer_info: vk.DescriptorBufferInfo = .{
|
const vp_buffer_info: vk.DescriptorBufferInfo = .{
|
||||||
|
@ -1115,15 +1114,15 @@ pub const VulkanRenderer = struct {
|
||||||
const set_writes = [_]vk.WriteDescriptorSet{vp_set_write};
|
const set_writes = [_]vk.WriteDescriptorSet{vp_set_write};
|
||||||
|
|
||||||
// Update the descriptor sets with new buffer/binding info
|
// Update the descriptor sets with new buffer/binding info
|
||||||
self.device.updateDescriptorSets(@intCast(set_writes.len), &set_writes, 0, null);
|
self.ctx.device.updateDescriptorSets(@intCast(set_writes.len), &set_writes, 0, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createInputDescriptorSets(self: *Self) !void {
|
fn createInputDescriptorSets(self: *Self) !void {
|
||||||
self.input_descriptor_sets = try self.allocator.alloc(vk.DescriptorSet, self.swapchain_images.len);
|
self.input_descriptor_sets = try self.allocator.alloc(vk.DescriptorSet, self.swapchain.swapchain_images.len);
|
||||||
|
|
||||||
// Fill array of layouts ready for set creation
|
// Fill array of layouts ready for set creation
|
||||||
var set_layouts = try self.allocator.alloc(vk.DescriptorSetLayout, self.swapchain_images.len);
|
var set_layouts = try self.allocator.alloc(vk.DescriptorSetLayout, self.swapchain.swapchain_images.len);
|
||||||
defer self.allocator.free(set_layouts);
|
defer self.allocator.free(set_layouts);
|
||||||
for (0..set_layouts.len) |i| {
|
for (0..set_layouts.len) |i| {
|
||||||
set_layouts[i] = self.input_set_layout;
|
set_layouts[i] = self.input_set_layout;
|
||||||
|
@ -1132,15 +1131,15 @@ pub const VulkanRenderer = struct {
|
||||||
// Input attachment descriptor set allocation info
|
// Input attachment descriptor set allocation info
|
||||||
const set_alloc_info: vk.DescriptorSetAllocateInfo = .{
|
const set_alloc_info: vk.DescriptorSetAllocateInfo = .{
|
||||||
.descriptor_pool = self.input_descriptor_pool,
|
.descriptor_pool = self.input_descriptor_pool,
|
||||||
.descriptor_set_count = @intCast(self.swapchain_images.len),
|
.descriptor_set_count = @intCast(self.swapchain.swapchain_images.len),
|
||||||
.p_set_layouts = set_layouts.ptr,
|
.p_set_layouts = set_layouts.ptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allocate descriptor sets
|
// Allocate descriptor sets
|
||||||
try self.device.allocateDescriptorSets(&set_alloc_info, self.input_descriptor_sets.ptr);
|
try self.ctx.device.allocateDescriptorSets(&set_alloc_info, self.input_descriptor_sets.ptr);
|
||||||
|
|
||||||
// Update each descriptor set with input attachment
|
// Update each descriptor set with input attachment
|
||||||
for (0..self.swapchain_images.len) |i| {
|
for (0..self.swapchain.swapchain_images.len) |i| {
|
||||||
// Colour attachment descriptor
|
// Colour attachment descriptor
|
||||||
const colour_attachment_descriptor: vk.DescriptorImageInfo = .{
|
const colour_attachment_descriptor: vk.DescriptorImageInfo = .{
|
||||||
.image_layout = .shader_read_only_optimal,
|
.image_layout = .shader_read_only_optimal,
|
||||||
|
@ -1183,13 +1182,13 @@ pub const VulkanRenderer = struct {
|
||||||
const set_writes = [_]vk.WriteDescriptorSet{ colour_write, depth_write };
|
const set_writes = [_]vk.WriteDescriptorSet{ colour_write, depth_write };
|
||||||
|
|
||||||
// Update descriptor sets
|
// Update descriptor sets
|
||||||
self.device.updateDescriptorSets(@intCast(set_writes.len), &set_writes, 0, null);
|
self.ctx.device.updateDescriptorSets(@intCast(set_writes.len), &set_writes, 0, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn updateUniformBuffers(self: *Self, image_index: u32) !void {
|
fn updateUniformBuffers(self: *Self, image_index: u32) !void {
|
||||||
// Copy VP data
|
// Copy VP data
|
||||||
const data = try self.device.mapMemory(
|
const data = try self.ctx.device.mapMemory(
|
||||||
self.vp_uniform_buffer_memory[image_index],
|
self.vp_uniform_buffer_memory[image_index],
|
||||||
0,
|
0,
|
||||||
@sizeOf(UboViewProjection),
|
@sizeOf(UboViewProjection),
|
||||||
|
@ -1198,7 +1197,7 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
const vp_data: *UboViewProjection = @ptrCast(@alignCast(data));
|
const vp_data: *UboViewProjection = @ptrCast(@alignCast(data));
|
||||||
vp_data.* = self.ubo_view_projection;
|
vp_data.* = self.ubo_view_projection;
|
||||||
self.device.unmapMemory(self.vp_uniform_buffer_memory[image_index]);
|
self.ctx.device.unmapMemory(self.vp_uniform_buffer_memory[image_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recordCommands(self: *Self, current_image: u32) !void {
|
fn recordCommands(self: *Self, current_image: u32) !void {
|
||||||
|
@ -1219,11 +1218,11 @@ pub const VulkanRenderer = struct {
|
||||||
.render_pass = self.render_pass, // Render pass to begin
|
.render_pass = self.render_pass, // Render pass to begin
|
||||||
.render_area = .{
|
.render_area = .{
|
||||||
.offset = .{ .x = 0, .y = 0 }, // Start point of render pass in pixels
|
.offset = .{ .x = 0, .y = 0 }, // Start point of render pass in pixels
|
||||||
.extent = self.extent, // Size of region to run render pass on (starting at offset)
|
.extent = self.swapchain.extent, // Size of region to run render pass on (starting at offset)
|
||||||
},
|
},
|
||||||
.p_clear_values = &clear_values, // List of clear values
|
.p_clear_values = &clear_values, // List of clear values
|
||||||
.clear_value_count = @intCast(clear_values.len),
|
.clear_value_count = @intCast(clear_values.len),
|
||||||
.framebuffer = self.swapchain_framebuffers[current_image],
|
.framebuffer = self.swapchain.swapchain_framebuffers[current_image],
|
||||||
};
|
};
|
||||||
|
|
||||||
const command_buffer = self.command_buffers[current_image];
|
const command_buffer = self.command_buffers[current_image];
|
||||||
|
@ -1307,78 +1306,6 @@ pub const VulkanRenderer = struct {
|
||||||
try command_buffer.endCommandBuffer();
|
try command_buffer.endCommandBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createImage(
|
|
||||||
self: *Self,
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
format: vk.Format,
|
|
||||||
tiling: vk.ImageTiling,
|
|
||||||
use_flags: vk.ImageUsageFlags,
|
|
||||||
prop_flags: vk.MemoryPropertyFlags,
|
|
||||||
image_memory: *vk.DeviceMemory,
|
|
||||||
) !vk.Image {
|
|
||||||
// -- Create Image --
|
|
||||||
const image_create_info: vk.ImageCreateInfo = .{
|
|
||||||
.image_type = .@"2d", // Type of image (1D, 2D or 3D)
|
|
||||||
.extent = .{
|
|
||||||
.width = width, // Width of image extent
|
|
||||||
.height = height, // Height of image extent
|
|
||||||
.depth = 1, // Depth of image (just 1, no 3D aspecct)
|
|
||||||
},
|
|
||||||
.mip_levels = 1, // Number of mipmap levels
|
|
||||||
.array_layers = 1, // Number of level in image array
|
|
||||||
.format = format, // Format type of image
|
|
||||||
.tiling = tiling, // How image data should be tiled (arranged for optimal reading)
|
|
||||||
.initial_layout = .undefined, // Layout of image data on creation
|
|
||||||
.usage = use_flags, // Bit flags defining what image will be used for
|
|
||||||
.samples = .{ .@"1_bit" = true }, // Number of samples for multi-sampling
|
|
||||||
.sharing_mode = .exclusive, // Whether image can be shared between queues
|
|
||||||
};
|
|
||||||
|
|
||||||
const image = try self.device.createImage(&image_create_info, null);
|
|
||||||
|
|
||||||
// -- Create memory for image --
|
|
||||||
// Get memory requirements for a type of image
|
|
||||||
const memory_requirements = self.device.getImageMemoryRequirements(image);
|
|
||||||
|
|
||||||
// Allocate memory using image requirements and user-defined properties
|
|
||||||
const memory_alloc_info: vk.MemoryAllocateInfo = .{
|
|
||||||
.allocation_size = memory_requirements.size,
|
|
||||||
.memory_type_index = Utilities.findMemoryTypeIndex(self.physical_device, self.instance, memory_requirements.memory_type_bits, prop_flags),
|
|
||||||
};
|
|
||||||
|
|
||||||
image_memory.* = try self.device.allocateMemory(&memory_alloc_info, null);
|
|
||||||
|
|
||||||
// Connect memory to image
|
|
||||||
try self.device.bindImageMemory(image, image_memory.*, 0);
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn createImageView(self: Self, image: vk.Image, format: vk.Format, aspect_flags: vk.ImageAspectFlags) !vk.ImageView {
|
|
||||||
const image_view_create_info: vk.ImageViewCreateInfo = .{
|
|
||||||
.image = image,
|
|
||||||
.format = format,
|
|
||||||
.view_type = .@"2d",
|
|
||||||
.components = .{
|
|
||||||
// Used for remapping rgba values to other rgba values
|
|
||||||
.r = .identity,
|
|
||||||
.g = .identity,
|
|
||||||
.b = .identity,
|
|
||||||
.a = .identity,
|
|
||||||
},
|
|
||||||
.subresource_range = .{
|
|
||||||
.aspect_mask = aspect_flags, // Which aspect of image to view (e.g.: colour, depth, stencil, etc...)
|
|
||||||
.base_mip_level = 0, // Start mipmap level to view from
|
|
||||||
.level_count = 1, // Number of mipmap levels to view
|
|
||||||
.base_array_layer = 0, // Start array level to view from
|
|
||||||
.layer_count = 1, // Number of array levels to view
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return try self.device.createImageView(&image_view_create_info, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn createTextureImage(self: *Self, file_name: []const u8) !u32 {
|
fn createTextureImage(self: *Self, file_name: []const u8) !u32 {
|
||||||
// Load image file
|
// Load image file
|
||||||
var width: u32 = undefined;
|
var width: u32 = undefined;
|
||||||
|
@ -1389,13 +1316,13 @@ pub const VulkanRenderer = struct {
|
||||||
// Create staging buffer to hold loaded data, ready to copy to device
|
// Create staging buffer to hold loaded data, ready to copy to device
|
||||||
var image_staging_buffer: vk.Buffer = undefined;
|
var image_staging_buffer: vk.Buffer = undefined;
|
||||||
var image_staging_buffer_memory: vk.DeviceMemory = undefined;
|
var image_staging_buffer_memory: vk.DeviceMemory = undefined;
|
||||||
defer self.device.destroyBuffer(image_staging_buffer, null);
|
defer self.ctx.device.destroyBuffer(image_staging_buffer, null);
|
||||||
defer self.device.freeMemory(image_staging_buffer_memory, null);
|
defer self.ctx.device.freeMemory(image_staging_buffer_memory, null);
|
||||||
|
|
||||||
try Utilities.createBuffer(
|
try Utilities.createBuffer(
|
||||||
self.physical_device,
|
self.ctx.physical_device,
|
||||||
self.instance,
|
self.ctx.instance,
|
||||||
self.device,
|
self.ctx.device,
|
||||||
image_size,
|
image_size,
|
||||||
.{ .transfer_src_bit = true },
|
.{ .transfer_src_bit = true },
|
||||||
.{ .host_visible_bit = true, .host_coherent_bit = true },
|
.{ .host_visible_bit = true, .host_coherent_bit = true },
|
||||||
|
@ -1404,15 +1331,15 @@ pub const VulkanRenderer = struct {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Copy data to staging buffer
|
// Copy data to staging buffer
|
||||||
const data = try self.device.mapMemory(image_staging_buffer_memory, 0, image_size, .{});
|
const data = try self.ctx.device.mapMemory(image_staging_buffer_memory, 0, image_size, .{});
|
||||||
const image_data: [*]u8 = @ptrCast(@alignCast(data));
|
const image_data: [*]u8 = @ptrCast(@alignCast(data));
|
||||||
|
|
||||||
@memcpy(image_data, image[0..]);
|
@memcpy(image_data, image[0..]);
|
||||||
self.device.unmapMemory(image_staging_buffer_memory);
|
self.ctx.device.unmapMemory(image_staging_buffer_memory);
|
||||||
|
|
||||||
// Create image to hold final texture
|
// Create image to hold final texture
|
||||||
var tex_image_memory: vk.DeviceMemory = undefined;
|
var tex_image_memory: vk.DeviceMemory = undefined;
|
||||||
const tex_image: vk.Image = try self.createImage(
|
const tex_image: vk.Image = try self.swapchain.createImage(
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
.r8g8b8a8_srgb,
|
.r8g8b8a8_srgb,
|
||||||
|
@ -1424,8 +1351,8 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
// Transition image to be DST for copy operation
|
// Transition image to be DST for copy operation
|
||||||
try Utilities.transitionImageLayout(
|
try Utilities.transitionImageLayout(
|
||||||
self.device,
|
self.ctx.device,
|
||||||
self.graphics_queue.handle,
|
self.ctx.graphics_queue.handle,
|
||||||
self.graphics_command_pool,
|
self.graphics_command_pool,
|
||||||
tex_image,
|
tex_image,
|
||||||
.undefined,
|
.undefined,
|
||||||
|
@ -1434,8 +1361,8 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
// Copy data to image
|
// Copy data to image
|
||||||
try Utilities.copyImageBuffer(
|
try Utilities.copyImageBuffer(
|
||||||
self.device,
|
self.ctx.device,
|
||||||
self.graphics_queue.handle,
|
self.ctx.graphics_queue.handle,
|
||||||
self.graphics_command_pool,
|
self.graphics_command_pool,
|
||||||
image_staging_buffer,
|
image_staging_buffer,
|
||||||
tex_image,
|
tex_image,
|
||||||
|
@ -1445,8 +1372,8 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
// Transition image to be shader readable for shader usage
|
// Transition image to be shader readable for shader usage
|
||||||
try Utilities.transitionImageLayout(
|
try Utilities.transitionImageLayout(
|
||||||
self.device,
|
self.ctx.device,
|
||||||
self.graphics_queue.handle,
|
self.ctx.graphics_queue.handle,
|
||||||
self.graphics_command_pool,
|
self.graphics_command_pool,
|
||||||
tex_image,
|
tex_image,
|
||||||
.transfer_dst_optimal,
|
.transfer_dst_optimal,
|
||||||
|
@ -1466,7 +1393,7 @@ pub const VulkanRenderer = struct {
|
||||||
const texture_image_loc = try self.createTextureImage(file_name);
|
const texture_image_loc = try self.createTextureImage(file_name);
|
||||||
|
|
||||||
// Create image view and add to list
|
// Create image view and add to list
|
||||||
const image_view = try self.createImageView(
|
const image_view = try self.swapchain.createImageView(
|
||||||
self.texture_images.items[texture_image_loc],
|
self.texture_images.items[texture_image_loc],
|
||||||
.r8g8b8a8_srgb,
|
.r8g8b8a8_srgb,
|
||||||
.{ .color_bit = true },
|
.{ .color_bit = true },
|
||||||
|
@ -1522,10 +1449,10 @@ pub const VulkanRenderer = struct {
|
||||||
// Load in all our meshes
|
// Load in all our meshes
|
||||||
const model_meshes = try MeshModel.loadNode(
|
const model_meshes = try MeshModel.loadNode(
|
||||||
self.allocator,
|
self.allocator,
|
||||||
self.instance,
|
self.ctx.instance,
|
||||||
self.physical_device,
|
self.ctx.physical_device,
|
||||||
self.device,
|
self.ctx.device,
|
||||||
self.graphics_queue.handle,
|
self.ctx.graphics_queue.handle,
|
||||||
self.graphics_command_pool,
|
self.graphics_command_pool,
|
||||||
scene.*.mRootNode,
|
scene.*.mRootNode,
|
||||||
scene,
|
scene,
|
||||||
|
@ -1550,7 +1477,7 @@ pub const VulkanRenderer = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allocate descriptor sets
|
// Allocate descriptor sets
|
||||||
try self.device.allocateDescriptorSets(&set_alloc_info, @ptrCast(&descriptor_set));
|
try self.ctx.device.allocateDescriptorSets(&set_alloc_info, @ptrCast(&descriptor_set));
|
||||||
|
|
||||||
const image_info: vk.DescriptorImageInfo = .{
|
const image_info: vk.DescriptorImageInfo = .{
|
||||||
.image_layout = .shader_read_only_optimal, // Image layout when in use
|
.image_layout = .shader_read_only_optimal, // Image layout when in use
|
||||||
|
@ -1571,7 +1498,7 @@ pub const VulkanRenderer = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the new descriptor set
|
// Update the new descriptor set
|
||||||
self.device.updateDescriptorSets(1, @ptrCast(&descriptor_write), 0, null);
|
self.ctx.device.updateDescriptorSets(1, @ptrCast(&descriptor_write), 0, null);
|
||||||
|
|
||||||
try self.sampler_descriptor_sets.append(descriptor_set);
|
try self.sampler_descriptor_sets.append(descriptor_set);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue