|
|
|
|
@@ -7,12 +7,24 @@ const vk = @import("vulkan");
|
|
|
|
|
|
|
|
|
|
const CommandBuffer = @import("CommandBuffer.zig");
|
|
|
|
|
const Engine = @import("Engine.zig");
|
|
|
|
|
const GenericBuffer = @import("GenericBuffer.zig").GenericBuffer;
|
|
|
|
|
const StagingBuffer = @import("StagingBuffer.zig");
|
|
|
|
|
|
|
|
|
|
image: vk.Image,
|
|
|
|
|
image_view: vk.ImageView,
|
|
|
|
|
device_memory: vk.DeviceMemory,
|
|
|
|
|
|
|
|
|
|
pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocator: std.mem.Allocator) !Skybox {
|
|
|
|
|
vertex_buffer: GenericBuffer(void, [3]f32),
|
|
|
|
|
index_buffer: shaders.IndexBuffer,
|
|
|
|
|
sampler: vk.Sampler,
|
|
|
|
|
|
|
|
|
|
descriptor_set_layout: vk.DescriptorSetLayout,
|
|
|
|
|
descriptor_pool: vk.DescriptorPool,
|
|
|
|
|
descriptor_set: vk.DescriptorSet,
|
|
|
|
|
pipeline_layout: vk.PipelineLayout,
|
|
|
|
|
pipeline: vk.Pipeline,
|
|
|
|
|
|
|
|
|
|
pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, global_uniforms_buffer: vk.Buffer, render_pass: vk.RenderPass, temp_allocator: std.mem.Allocator) !Skybox {
|
|
|
|
|
std.log.debug("Loading skybox \"{s}\"...", .{filename});
|
|
|
|
|
|
|
|
|
|
// --- LOAD IMAGE FROM MEMORY ----------------------------------------------
|
|
|
|
|
@@ -29,7 +41,33 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
defer img.deinit();
|
|
|
|
|
std.debug.assert(img.num_components == 4);
|
|
|
|
|
|
|
|
|
|
// --- CREATE EQUIRECTANGULAR IMAGE AND COPY INTO IT -----------------------
|
|
|
|
|
// --- SYNCHRONIZATION PRIMITIVES ------------------------------------------
|
|
|
|
|
|
|
|
|
|
const semaphore_transfer_transition = try engine.createSemaphore();
|
|
|
|
|
defer engine.destroySemaphore(semaphore_transfer_transition);
|
|
|
|
|
|
|
|
|
|
const semaphore_transition_compute = try engine.createSemaphore();
|
|
|
|
|
defer engine.destroySemaphore(semaphore_transition_compute);
|
|
|
|
|
|
|
|
|
|
const semaphore_compute_transition = try engine.createSemaphore();
|
|
|
|
|
defer engine.destroySemaphore(semaphore_compute_transition);
|
|
|
|
|
|
|
|
|
|
const fence = try engine.createFence(.{});
|
|
|
|
|
defer engine.destroyFence(fence);
|
|
|
|
|
|
|
|
|
|
// --- LOAD IMAGE INTO STAGING BUFFER --------------------------------------
|
|
|
|
|
|
|
|
|
|
var staging_buffer = try StagingBuffer.init(engine, .{
|
|
|
|
|
.capacity = @intCast(img.data.len),
|
|
|
|
|
.target_queue = .compute,
|
|
|
|
|
});
|
|
|
|
|
defer staging_buffer.deinit(engine);
|
|
|
|
|
|
|
|
|
|
const staging_memory = try staging_buffer.map(engine);
|
|
|
|
|
@memcpy(staging_memory, img.data);
|
|
|
|
|
staging_buffer.unmap(engine);
|
|
|
|
|
|
|
|
|
|
// --- CREATE EQUIRECTANGULAR IMAGE ----------------------------------------
|
|
|
|
|
|
|
|
|
|
const equirect_image = try engine.createImage(.{
|
|
|
|
|
.image_type = .@"2d",
|
|
|
|
|
@@ -42,23 +80,21 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
.mip_levels = 1,
|
|
|
|
|
.array_layers = 1,
|
|
|
|
|
.samples = .{ .@"1_bit" = true },
|
|
|
|
|
.tiling = .linear,
|
|
|
|
|
.tiling = .optimal,
|
|
|
|
|
.usage = .{
|
|
|
|
|
.transfer_dst_bit = true,
|
|
|
|
|
.sampled_bit = true,
|
|
|
|
|
},
|
|
|
|
|
.queue_family_indices = &.{
|
|
|
|
|
engine.compute_queue.allocation.family,
|
|
|
|
|
engine.transfer_queue.allocation.family,
|
|
|
|
|
},
|
|
|
|
|
.initial_layout = .preinitialized,
|
|
|
|
|
.initial_layout = .undefined,
|
|
|
|
|
});
|
|
|
|
|
defer engine.destroyImage(equirect_image);
|
|
|
|
|
|
|
|
|
|
const equirect_memory_requirements = engine.getImageMemoryRequirements(equirect_image);
|
|
|
|
|
const equirect_device_memory = try engine.allocate(equirect_memory_requirements, .{
|
|
|
|
|
.host_visible_bit = true,
|
|
|
|
|
.host_coherent_bit = true,
|
|
|
|
|
});
|
|
|
|
|
const equirect_device_memory = try engine.allocate(equirect_memory_requirements, .{ .device_local_bit = true });
|
|
|
|
|
defer engine.freeMemory(equirect_device_memory);
|
|
|
|
|
|
|
|
|
|
try engine.bindImageMemory(equirect_image, equirect_device_memory, 0);
|
|
|
|
|
@@ -77,9 +113,94 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
});
|
|
|
|
|
defer engine.destroyImageView(equirect_image_view);
|
|
|
|
|
|
|
|
|
|
const data = try engine.mapMemory(equirect_device_memory, 0, equirect_memory_requirements.size, .{});
|
|
|
|
|
@memcpy(data, img.data);
|
|
|
|
|
engine.unmapMemory(equirect_device_memory);
|
|
|
|
|
// --- TRANSITION TO TRANSFER_DST_OPTIMAL AND COPY -------------------------
|
|
|
|
|
|
|
|
|
|
var transfer_command_buffer = try CommandBuffer.init(engine, .transfer, .transient);
|
|
|
|
|
defer transfer_command_buffer.deinit(engine);
|
|
|
|
|
|
|
|
|
|
try transfer_command_buffer.beginCommandBuffer();
|
|
|
|
|
transfer_command_buffer.pipelineBarrier(.{
|
|
|
|
|
.src_stage_mask = .{ .top_of_pipe_bit = true },
|
|
|
|
|
.dst_stage_mask = .{ .transfer_bit = true },
|
|
|
|
|
.image_memory_barriers = &.{
|
|
|
|
|
.{
|
|
|
|
|
.src_access_mask = .{},
|
|
|
|
|
.dst_access_mask = .{ .transfer_write_bit = true },
|
|
|
|
|
.old_layout = .undefined,
|
|
|
|
|
.new_layout = .transfer_dst_optimal,
|
|
|
|
|
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
|
|
|
|
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
|
|
|
|
.image = equirect_image,
|
|
|
|
|
.subresource_range = .{
|
|
|
|
|
.aspect_mask = .{ .color_bit = true },
|
|
|
|
|
.base_mip_level = 0,
|
|
|
|
|
.level_count = 1,
|
|
|
|
|
.base_array_layer = 0,
|
|
|
|
|
.layer_count = 1,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
transfer_command_buffer.copyBufferToImage(
|
|
|
|
|
staging_buffer.buffer,
|
|
|
|
|
equirect_image,
|
|
|
|
|
.transfer_dst_optimal,
|
|
|
|
|
&.{
|
|
|
|
|
.{
|
|
|
|
|
.buffer_offset = 0,
|
|
|
|
|
.buffer_row_length = img.width,
|
|
|
|
|
.buffer_image_height = img.height,
|
|
|
|
|
.image_subresource = .{
|
|
|
|
|
.aspect_mask = .{ .color_bit = true },
|
|
|
|
|
.mip_level = 0,
|
|
|
|
|
.base_array_layer = 0,
|
|
|
|
|
.layer_count = 1,
|
|
|
|
|
},
|
|
|
|
|
.image_offset = .{ .x = 0, .y = 0, .z = 0 },
|
|
|
|
|
.image_extent = .{ .width = img.width, .height = img.height, .depth = 1 },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
try transfer_command_buffer.endCommandBuffer();
|
|
|
|
|
|
|
|
|
|
try transfer_command_buffer.submit(engine, .{
|
|
|
|
|
.signal_semaphores = &.{semaphore_transfer_transition},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// --- TRANSITION TO SHADER_READ_ONLY_OPTIMAL ------------------------------
|
|
|
|
|
|
|
|
|
|
var transition1_command_buffer = try CommandBuffer.init(engine, .graphics, .transient);
|
|
|
|
|
defer transition1_command_buffer.deinit(engine);
|
|
|
|
|
|
|
|
|
|
try transition1_command_buffer.beginCommandBuffer();
|
|
|
|
|
transition1_command_buffer.pipelineBarrier(.{
|
|
|
|
|
.src_stage_mask = .{ .transfer_bit = true },
|
|
|
|
|
.dst_stage_mask = .{ .compute_shader_bit = true },
|
|
|
|
|
.image_memory_barriers = &.{
|
|
|
|
|
.{
|
|
|
|
|
.src_access_mask = .{ .transfer_write_bit = true },
|
|
|
|
|
.dst_access_mask = .{ .shader_read_bit = true },
|
|
|
|
|
.old_layout = .transfer_dst_optimal,
|
|
|
|
|
.new_layout = .shader_read_only_optimal,
|
|
|
|
|
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
|
|
|
|
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
|
|
|
|
.image = equirect_image,
|
|
|
|
|
.subresource_range = .{
|
|
|
|
|
.aspect_mask = .{ .color_bit = true },
|
|
|
|
|
.base_mip_level = 0,
|
|
|
|
|
.level_count = 1,
|
|
|
|
|
.base_array_layer = 0,
|
|
|
|
|
.layer_count = 1,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
try transition1_command_buffer.endCommandBuffer();
|
|
|
|
|
|
|
|
|
|
try transition1_command_buffer.submit(engine, .{
|
|
|
|
|
.wait_semaphores = &.{.{ .semaphore = semaphore_transfer_transition }},
|
|
|
|
|
.signal_semaphores = &.{semaphore_transition_compute},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// --- CREATE CUBEMAP IMAGE ------------------------------------------------
|
|
|
|
|
|
|
|
|
|
@@ -147,9 +268,9 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
.border_color = .float_transparent_black,
|
|
|
|
|
.unnormalized_coordinates = .false,
|
|
|
|
|
});
|
|
|
|
|
defer engine.destroySampler(sampler);
|
|
|
|
|
errdefer engine.destroySampler(sampler);
|
|
|
|
|
|
|
|
|
|
const descriptor_set_layout = try engine.createDescriptorSetLayout(.{
|
|
|
|
|
const compute_descriptor_set_layout = try engine.createDescriptorSetLayout(.{
|
|
|
|
|
.bindings = &.{
|
|
|
|
|
.{
|
|
|
|
|
.binding = 0,
|
|
|
|
|
@@ -172,17 +293,17 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
defer engine.destroyDescriptorSetLayout(descriptor_set_layout);
|
|
|
|
|
defer engine.destroyDescriptorSetLayout(compute_descriptor_set_layout);
|
|
|
|
|
|
|
|
|
|
const pipeline_layout = try engine.createPipelineLayout(.{
|
|
|
|
|
.set_layouts = &.{descriptor_set_layout},
|
|
|
|
|
const compute_pipeline_layout = try engine.createPipelineLayout(.{
|
|
|
|
|
.set_layouts = &.{compute_descriptor_set_layout},
|
|
|
|
|
});
|
|
|
|
|
defer engine.destroyPipelineLayout(pipeline_layout);
|
|
|
|
|
defer engine.destroyPipelineLayout(compute_pipeline_layout);
|
|
|
|
|
|
|
|
|
|
const compute_shader = try engine.createShaderModule(.{ .code = &shaders.equirect_to_cube_comp_spv });
|
|
|
|
|
defer engine.destroyShaderModule(compute_shader);
|
|
|
|
|
|
|
|
|
|
var pipeline: vk.Pipeline = undefined;
|
|
|
|
|
var compute_pipeline: vk.Pipeline = undefined;
|
|
|
|
|
_ = try engine.device.createComputePipelines(.null_handle, 1, &.{
|
|
|
|
|
.{
|
|
|
|
|
.stage = .{
|
|
|
|
|
@@ -190,14 +311,14 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
.module = compute_shader,
|
|
|
|
|
.p_name = "main",
|
|
|
|
|
},
|
|
|
|
|
.layout = pipeline_layout,
|
|
|
|
|
.layout = compute_pipeline_layout,
|
|
|
|
|
.base_pipeline_handle = .null_handle,
|
|
|
|
|
.base_pipeline_index = -1,
|
|
|
|
|
},
|
|
|
|
|
}, &engine.vk_allocator.interface, @ptrCast(&pipeline));
|
|
|
|
|
defer engine.destroyPipeline(pipeline);
|
|
|
|
|
}, &engine.vk_allocator.interface, @ptrCast(&compute_pipeline));
|
|
|
|
|
defer engine.destroyPipeline(compute_pipeline);
|
|
|
|
|
|
|
|
|
|
const descriptor_pool = try engine.createDescriptorPool(.{
|
|
|
|
|
const compute_descriptor_pool = try engine.createDescriptorPool(.{
|
|
|
|
|
.max_sets = 1,
|
|
|
|
|
.pool_sizes = &.{
|
|
|
|
|
.{
|
|
|
|
|
@@ -214,17 +335,17 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
defer engine.destroyDescriptorPool(descriptor_pool);
|
|
|
|
|
defer engine.destroyDescriptorPool(compute_descriptor_pool);
|
|
|
|
|
|
|
|
|
|
const descriptor_set = try engine.allocateDescriptorSet(.{
|
|
|
|
|
.descriptor_pool = descriptor_pool,
|
|
|
|
|
.set_layout = descriptor_set_layout,
|
|
|
|
|
const compute_descriptor_set = try engine.allocateDescriptorSet(.{
|
|
|
|
|
.descriptor_pool = compute_descriptor_pool,
|
|
|
|
|
.set_layout = compute_descriptor_set_layout,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
try engine.updateDescriptorSets(.{
|
|
|
|
|
.writes = &.{
|
|
|
|
|
.{
|
|
|
|
|
.dst_set = descriptor_set,
|
|
|
|
|
.dst_set = compute_descriptor_set,
|
|
|
|
|
.dst_binding = 1,
|
|
|
|
|
.dst_array_element = 0,
|
|
|
|
|
.descriptor_type = .sampled_image,
|
|
|
|
|
@@ -239,7 +360,7 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.{
|
|
|
|
|
.dst_set = descriptor_set,
|
|
|
|
|
.dst_set = compute_descriptor_set,
|
|
|
|
|
.dst_binding = 2,
|
|
|
|
|
.dst_array_element = 0,
|
|
|
|
|
.descriptor_type = .storage_image,
|
|
|
|
|
@@ -258,14 +379,6 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
|
|
|
|
|
// --- COMMAND BUFFERS -----------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// 0. Synchronization primitives
|
|
|
|
|
|
|
|
|
|
const semaphore = try engine.createSemaphore();
|
|
|
|
|
defer engine.destroySemaphore(semaphore);
|
|
|
|
|
|
|
|
|
|
const fence = try engine.createFence(.{});
|
|
|
|
|
defer engine.destroyFence(fence);
|
|
|
|
|
|
|
|
|
|
// 1. Run compute shader
|
|
|
|
|
|
|
|
|
|
var compute_command_buffer = try CommandBuffer.init(engine, .compute, .transient);
|
|
|
|
|
@@ -310,22 +423,28 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
compute_command_buffer.bindPipeline(.compute, pipeline);
|
|
|
|
|
compute_command_buffer.bindDescriptorSet(.compute, pipeline_layout, 0, descriptor_set, null);
|
|
|
|
|
compute_command_buffer.bindPipeline(.compute, compute_pipeline);
|
|
|
|
|
compute_command_buffer.bindDescriptorSet(.compute, compute_pipeline_layout, 0, compute_descriptor_set, null);
|
|
|
|
|
compute_command_buffer.proxy.dispatch(@divExact(cube_size, 8), @divExact(cube_size, 8), 6);
|
|
|
|
|
try compute_command_buffer.endCommandBuffer();
|
|
|
|
|
|
|
|
|
|
try compute_command_buffer.submit(engine, .{
|
|
|
|
|
.signal_semaphores = &.{semaphore},
|
|
|
|
|
.wait_semaphores = &.{
|
|
|
|
|
.{
|
|
|
|
|
.semaphore = semaphore_transition_compute,
|
|
|
|
|
.stage_flags = .{ .compute_shader_bit = true },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.signal_semaphores = &.{semaphore_compute_transition},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 2. Transition cubemap
|
|
|
|
|
|
|
|
|
|
var transition_command_buffer = try CommandBuffer.init(engine, .graphics, .transient);
|
|
|
|
|
defer transition_command_buffer.deinit(engine);
|
|
|
|
|
var transition2_command_buffer = try CommandBuffer.init(engine, .graphics, .transient);
|
|
|
|
|
defer transition2_command_buffer.deinit(engine);
|
|
|
|
|
|
|
|
|
|
try transition_command_buffer.beginCommandBuffer();
|
|
|
|
|
transition_command_buffer.pipelineBarrier(.{
|
|
|
|
|
try transition2_command_buffer.beginCommandBuffer();
|
|
|
|
|
transition2_command_buffer.pipelineBarrier(.{
|
|
|
|
|
.src_stage_mask = .{ .compute_shader_bit = true },
|
|
|
|
|
.dst_stage_mask = .{ .top_of_pipe_bit = true },
|
|
|
|
|
.image_memory_barriers = &.{
|
|
|
|
|
@@ -347,10 +466,10 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
try transition_command_buffer.endCommandBuffer();
|
|
|
|
|
try transition2_command_buffer.endCommandBuffer();
|
|
|
|
|
|
|
|
|
|
try transition_command_buffer.submit(engine, .{
|
|
|
|
|
.wait_semaphores = &.{.{ .semaphore = semaphore }},
|
|
|
|
|
try transition2_command_buffer.submit(engine, .{
|
|
|
|
|
.wait_semaphores = &.{.{ .semaphore = semaphore_compute_transition }},
|
|
|
|
|
.fence = fence,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@@ -358,15 +477,319 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|
|
|
|
|
|
|
|
|
try engine.waitForFence(fence);
|
|
|
|
|
|
|
|
|
|
// --- SKYBOX PIPELINE -----------------------------------------------------
|
|
|
|
|
|
|
|
|
|
var vertex_buffer = try GenericBuffer(void, [3]f32).init(engine, .{
|
|
|
|
|
.usage = .vertex,
|
|
|
|
|
.target_queue = .graphics,
|
|
|
|
|
.array_capacity = 8,
|
|
|
|
|
});
|
|
|
|
|
errdefer vertex_buffer.deinit(engine);
|
|
|
|
|
|
|
|
|
|
// 6━━━━7
|
|
|
|
|
// ╱│ ╱┃
|
|
|
|
|
// 4━┿━━5 ┃ Z
|
|
|
|
|
// ┃ │ ┃ ┃ │
|
|
|
|
|
// ┃ 2──╂─3 │ Y
|
|
|
|
|
// ┃╱ ┃╱ │╱
|
|
|
|
|
// 0━━━━1 O────X
|
|
|
|
|
|
|
|
|
|
try vertex_buffer.write(engine, .{
|
|
|
|
|
.elements = &.{
|
|
|
|
|
.{ -1, -1, -1 },
|
|
|
|
|
.{ 1, -1, -1 },
|
|
|
|
|
.{ -1, 1, -1 },
|
|
|
|
|
.{ 1, 1, -1 },
|
|
|
|
|
.{ -1, -1, 1 },
|
|
|
|
|
.{ 1, -1, 1 },
|
|
|
|
|
.{ -1, 1, 1 },
|
|
|
|
|
.{ 1, 1, 1 },
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var index_buffer = try GenericBuffer(void, u16).init(engine, .{
|
|
|
|
|
.usage = .index,
|
|
|
|
|
.target_queue = .graphics,
|
|
|
|
|
.array_capacity = 36,
|
|
|
|
|
});
|
|
|
|
|
errdefer index_buffer.deinit(engine);
|
|
|
|
|
|
|
|
|
|
try index_buffer.write(engine, .{
|
|
|
|
|
.elements = &.{
|
|
|
|
|
// Positive X
|
|
|
|
|
3, 1, 7,
|
|
|
|
|
7, 1, 5,
|
|
|
|
|
// Negative X
|
|
|
|
|
0, 2, 4,
|
|
|
|
|
4, 2, 6,
|
|
|
|
|
// Positive Y
|
|
|
|
|
2, 3, 6,
|
|
|
|
|
6, 3, 7,
|
|
|
|
|
// Negative Y
|
|
|
|
|
1, 0, 5,
|
|
|
|
|
5, 0, 4,
|
|
|
|
|
// Positive Z
|
|
|
|
|
6, 7, 4,
|
|
|
|
|
4, 7, 5,
|
|
|
|
|
// Negative Z
|
|
|
|
|
0, 1, 2,
|
|
|
|
|
2, 1, 3,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const descriptor_set_layout = try engine.createDescriptorSetLayout(.{
|
|
|
|
|
.bindings = &.{
|
|
|
|
|
.{
|
|
|
|
|
.binding = 0,
|
|
|
|
|
.descriptor_type = .uniform_buffer,
|
|
|
|
|
.descriptor_count = 1,
|
|
|
|
|
.stage_flags = .{ .vertex_bit = true },
|
|
|
|
|
},
|
|
|
|
|
.{
|
|
|
|
|
.binding = 1,
|
|
|
|
|
.descriptor_type = .sampler,
|
|
|
|
|
.descriptor_count = 1,
|
|
|
|
|
.stage_flags = .{ .fragment_bit = true },
|
|
|
|
|
.immutable_samplers = &.{sampler},
|
|
|
|
|
},
|
|
|
|
|
.{
|
|
|
|
|
.binding = 2,
|
|
|
|
|
.descriptor_type = .sampled_image,
|
|
|
|
|
.descriptor_count = 1,
|
|
|
|
|
.stage_flags = .{ .fragment_bit = true },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
errdefer engine.destroyDescriptorSetLayout(descriptor_set_layout);
|
|
|
|
|
|
|
|
|
|
const pipeline_layout = try engine.createPipelineLayout(.{
|
|
|
|
|
.set_layouts = &.{descriptor_set_layout},
|
|
|
|
|
});
|
|
|
|
|
errdefer engine.destroyPipelineLayout(pipeline_layout);
|
|
|
|
|
|
|
|
|
|
const descriptor_pool = try engine.createDescriptorPool(.{
|
|
|
|
|
.max_sets = 1,
|
|
|
|
|
.pool_sizes = &.{
|
|
|
|
|
.{
|
|
|
|
|
.type = .uniform_buffer,
|
|
|
|
|
.descriptor_count = 1,
|
|
|
|
|
},
|
|
|
|
|
.{
|
|
|
|
|
.type = .sampler,
|
|
|
|
|
.descriptor_count = 1,
|
|
|
|
|
},
|
|
|
|
|
.{
|
|
|
|
|
.type = .sampled_image,
|
|
|
|
|
.descriptor_count = 1,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
errdefer engine.destroyDescriptorPool(compute_descriptor_pool);
|
|
|
|
|
|
|
|
|
|
const descriptor_set = try engine.allocateDescriptorSet(.{
|
|
|
|
|
.descriptor_pool = descriptor_pool,
|
|
|
|
|
.set_layout = descriptor_set_layout,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
try engine.updateDescriptorSets(.{
|
|
|
|
|
.writes = &.{
|
|
|
|
|
.{
|
|
|
|
|
.dst_set = descriptor_set,
|
|
|
|
|
.dst_binding = 0,
|
|
|
|
|
.dst_array_element = 0,
|
|
|
|
|
.descriptor_type = .uniform_buffer,
|
|
|
|
|
.descriptor_infos = .{
|
|
|
|
|
.buffer = &.{
|
|
|
|
|
.{
|
|
|
|
|
.buffer = global_uniforms_buffer,
|
|
|
|
|
.offset = 0,
|
|
|
|
|
.range = vk.WHOLE_SIZE,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.{
|
|
|
|
|
.dst_set = descriptor_set,
|
|
|
|
|
.dst_binding = 2,
|
|
|
|
|
.dst_array_element = 0,
|
|
|
|
|
.descriptor_type = .sampled_image,
|
|
|
|
|
.descriptor_infos = .{
|
|
|
|
|
.image = &.{
|
|
|
|
|
.{
|
|
|
|
|
.sampler = .null_handle,
|
|
|
|
|
.image_view = cubemap_image_view,
|
|
|
|
|
.image_layout = .shader_read_only_optimal,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const vertex_shader = try engine.createShaderModule(.{ .code = &shaders.skybox_vert_spv });
|
|
|
|
|
defer engine.destroyShaderModule(vertex_shader);
|
|
|
|
|
|
|
|
|
|
const fragment_shader = try engine.createShaderModule(.{ .code = &shaders.skybox_frag_spv });
|
|
|
|
|
defer engine.destroyShaderModule(fragment_shader);
|
|
|
|
|
|
|
|
|
|
const pipeline = try engine.createGraphicsPipeline(.{
|
|
|
|
|
.stages = &.{
|
|
|
|
|
.{
|
|
|
|
|
.stage = .{ .vertex_bit = true },
|
|
|
|
|
.module = vertex_shader,
|
|
|
|
|
.name = "main",
|
|
|
|
|
},
|
|
|
|
|
.{
|
|
|
|
|
.stage = .{ .fragment_bit = true },
|
|
|
|
|
.module = fragment_shader,
|
|
|
|
|
.name = "main",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.vertex_input_state = .{
|
|
|
|
|
.vertex_binding_descriptions = &.{
|
|
|
|
|
.{
|
|
|
|
|
.binding = 0,
|
|
|
|
|
.stride = @sizeOf([3]f32),
|
|
|
|
|
.input_rate = .vertex,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.vertex_attribute_descriptions = &.{
|
|
|
|
|
.{
|
|
|
|
|
.location = 0,
|
|
|
|
|
.binding = 0,
|
|
|
|
|
.format = .r32g32b32_sfloat,
|
|
|
|
|
.offset = 0,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.input_assembly_state = .{
|
|
|
|
|
.topology = .triangle_list,
|
|
|
|
|
.primitive_restart_enable = .false,
|
|
|
|
|
},
|
|
|
|
|
.viewport_state = .{
|
|
|
|
|
.viewports = &.{undefined}, // dynamic
|
|
|
|
|
.scissors = &.{undefined}, // dynamic
|
|
|
|
|
},
|
|
|
|
|
.rasterization_state = .{
|
|
|
|
|
.depth_clamp_enable = .false,
|
|
|
|
|
.rasterizer_discard_enable = .false,
|
|
|
|
|
.polygon_mode = .fill,
|
|
|
|
|
.cull_mode = .{ .back_bit = true },
|
|
|
|
|
.front_face = .counter_clockwise,
|
|
|
|
|
.depth_bias_enable = .false,
|
|
|
|
|
.depth_bias_constant_factor = 0,
|
|
|
|
|
.depth_bias_clamp = 0,
|
|
|
|
|
.depth_bias_slope_factor = 0,
|
|
|
|
|
.line_width = 1,
|
|
|
|
|
},
|
|
|
|
|
.multisample_state = .{
|
|
|
|
|
.rasterization_samples = .{ .@"1_bit" = true },
|
|
|
|
|
.sample_shading_enable = .false,
|
|
|
|
|
.min_sample_shading = 1,
|
|
|
|
|
.alpha_to_coverage_enable = .false,
|
|
|
|
|
.alpha_to_one_enable = .false,
|
|
|
|
|
},
|
|
|
|
|
.depth_stencil_state = .{
|
|
|
|
|
.depth_test_enable = .true,
|
|
|
|
|
.depth_write_enable = .false,
|
|
|
|
|
.depth_compare_op = .equal,
|
|
|
|
|
.depth_bounds_test_enable = .false,
|
|
|
|
|
.stencil_test_enable = .false,
|
|
|
|
|
.front = undefined,
|
|
|
|
|
.back = undefined,
|
|
|
|
|
.min_depth_bounds = 0,
|
|
|
|
|
.max_depth_bounds = 1,
|
|
|
|
|
},
|
|
|
|
|
.color_blend_state = .{
|
|
|
|
|
.logic_op_enable = .false,
|
|
|
|
|
.logic_op = .copy,
|
|
|
|
|
.attachments = &.{
|
|
|
|
|
.{
|
|
|
|
|
.blend_enable = .false,
|
|
|
|
|
.src_color_blend_factor = .one,
|
|
|
|
|
.dst_color_blend_factor = .zero,
|
|
|
|
|
.color_blend_op = .add,
|
|
|
|
|
.src_alpha_blend_factor = .one,
|
|
|
|
|
.dst_alpha_blend_factor = .zero,
|
|
|
|
|
.alpha_blend_op = .add,
|
|
|
|
|
.color_write_mask = .{
|
|
|
|
|
.r_bit = true,
|
|
|
|
|
.g_bit = true,
|
|
|
|
|
.b_bit = true,
|
|
|
|
|
.a_bit = true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.blend_constants = .{ 0, 0, 0, 0 },
|
|
|
|
|
},
|
|
|
|
|
.dynamic_state = .{
|
|
|
|
|
.dynamic_states = &.{ .viewport, .scissor },
|
|
|
|
|
},
|
|
|
|
|
.layout = pipeline_layout,
|
|
|
|
|
.render_pass = render_pass,
|
|
|
|
|
.subpass = 0,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return .{
|
|
|
|
|
.image = cubemap_image,
|
|
|
|
|
.image_view = cubemap_image_view,
|
|
|
|
|
.device_memory = cubemap_device_memory,
|
|
|
|
|
|
|
|
|
|
.vertex_buffer = vertex_buffer,
|
|
|
|
|
.index_buffer = index_buffer,
|
|
|
|
|
.sampler = sampler,
|
|
|
|
|
|
|
|
|
|
.descriptor_set_layout = descriptor_set_layout,
|
|
|
|
|
.descriptor_pool = descriptor_pool,
|
|
|
|
|
.descriptor_set = descriptor_set,
|
|
|
|
|
.pipeline_layout = pipeline_layout,
|
|
|
|
|
.pipeline = pipeline,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn deinit(self: *Skybox, engine: *Engine) void {
|
|
|
|
|
engine.destroyPipeline(self.pipeline);
|
|
|
|
|
engine.destroyPipelineLayout(self.pipeline_layout);
|
|
|
|
|
engine.destroyDescriptorPool(self.descriptor_pool);
|
|
|
|
|
engine.destroyDescriptorSetLayout(self.descriptor_set_layout);
|
|
|
|
|
|
|
|
|
|
engine.destroySampler(self.sampler);
|
|
|
|
|
self.index_buffer.deinit(engine);
|
|
|
|
|
self.vertex_buffer.deinit(engine);
|
|
|
|
|
|
|
|
|
|
engine.destroyImageView(self.image_view);
|
|
|
|
|
engine.freeMemory(self.device_memory);
|
|
|
|
|
engine.destroyImage(self.image);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn bind(self: *const Skybox, command_buffer: CommandBuffer, extent: vk.Extent2D) !void {
|
|
|
|
|
command_buffer.setViewport(0, &.{
|
|
|
|
|
.{
|
|
|
|
|
.x = 0,
|
|
|
|
|
.y = 0,
|
|
|
|
|
.width = @floatFromInt(extent.width),
|
|
|
|
|
.height = @floatFromInt(extent.height),
|
|
|
|
|
.min_depth = 0,
|
|
|
|
|
.max_depth = 1,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
command_buffer.setScissor(0, &.{
|
|
|
|
|
.{
|
|
|
|
|
.offset = .{ .x = 0, .y = 0 },
|
|
|
|
|
.extent = extent,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
command_buffer.bindPipeline(.graphics, self.pipeline);
|
|
|
|
|
try command_buffer.bindVertexBuffers(0, &.{
|
|
|
|
|
.{
|
|
|
|
|
.buffer = self.vertex_buffer.buffer,
|
|
|
|
|
.offset = 0,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn draw(self: *const Skybox, command_buffer: CommandBuffer) void {
|
|
|
|
|
command_buffer.bindDescriptorSet(.graphics, self.pipeline_layout, 0, self.descriptor_set, null);
|
|
|
|
|
command_buffer.drawIndexed(.{ .index_count = 36 });
|
|
|
|
|
}
|
|
|
|
|
|