fixing vertex outputs
Test / build_and_test (push) Successful in 2m19s
Build / build (push) Successful in 4m2s

This commit is contained in:
2026-07-02 21:00:56 +02:00
parent 23c3731f06
commit d4ac14ae92
22 changed files with 259 additions and 85 deletions
+2 -2
View File
@@ -88,10 +88,12 @@ pub fn build(b: *std.Build) !void {
const drm = b.dependency("drm", .{}).module("drm"); const drm = b.dependency("drm", .{}).module("drm");
const logs_option: LogType = b.option(LogType, "logs", "Driver logs") orelse .none; const logs_option: LogType = b.option(LogType, "logs", "Driver logs") orelse .none;
const debug_allocator_option = b.option(bool, "device-debug-allocator", "Debug device allocator") orelse false;
const options = b.addOptions(); const options = b.addOptions();
options.addOption(std.SemanticVersion, "driver_version", driver_version); options.addOption(std.SemanticVersion, "driver_version", driver_version);
options.addOption(LogType, "logs", logs_option); options.addOption(LogType, "logs", logs_option);
options.addOption(bool, "device_debug_allocator", debug_allocator_option);
base_mod.addImport("vulkan", vulkan); base_mod.addImport("vulkan", vulkan);
base_mod.addImport("zmath", zmath); base_mod.addImport("zmath", zmath);
@@ -274,14 +276,12 @@ fn customSoft(
fn optionsSoft(b: *std.Build, options: *Step.Options) !void { fn optionsSoft(b: *std.Build, options: *Step.Options) !void {
const single_threaded_option = b.option(bool, "soft-single-threaded", "Single threaded runtime mode") orelse false; const single_threaded_option = b.option(bool, "soft-single-threaded", "Single threaded runtime mode") orelse false;
const debug_allocator_option = b.option(bool, "soft-debug-allocator", "Debug device allocator") orelse false;
const shaders_simd_option = b.option(bool, "soft-shader-simd", "Shaders SIMD acceleration") orelse true; const shaders_simd_option = b.option(bool, "soft-shader-simd", "Shaders SIMD acceleration") orelse true;
const compute_dump_early_results_table_option = b.option(u32, "soft-compute-dump-early-results-table", "Dump compute shaders results table before invocation"); const compute_dump_early_results_table_option = b.option(u32, "soft-compute-dump-early-results-table", "Dump compute shaders results table before invocation");
const compute_dump_final_results_table_option = b.option(u32, "soft-compute-dump-final-results-table", "Dump compute shaders results table after invocation"); const compute_dump_final_results_table_option = b.option(u32, "soft-compute-dump-final-results-table", "Dump compute shaders results table after invocation");
const approxiamte_rgb_option = b.option(bool, "soft-approximates-rgb", "Approximate sRGB <-> RGB conversions") orelse true; const approxiamte_rgb_option = b.option(bool, "soft-approximates-rgb", "Approximate sRGB <-> RGB conversions") orelse true;
options.addOption(bool, "soft_single_threaded", single_threaded_option); options.addOption(bool, "soft_single_threaded", single_threaded_option);
options.addOption(bool, "soft_debug_allocator", debug_allocator_option);
options.addOption(bool, "soft_shaders_simd", shaders_simd_option); options.addOption(bool, "soft_shaders_simd", shaders_simd_option);
options.addOption(?u32, "soft_compute_dump_early_results_table", compute_dump_early_results_table_option); options.addOption(?u32, "soft_compute_dump_early_results_table", compute_dump_early_results_table_option);
options.addOption(?u32, "soft_compute_dump_final_results_table", compute_dump_final_results_table_option); options.addOption(?u32, "soft_compute_dump_final_results_table", compute_dump_final_results_table_option);
+2 -2
View File
@@ -32,8 +32,8 @@
// Soft dependencies // Soft dependencies
.SPIRV_Interpreter = .{ .SPIRV_Interpreter = .{
.url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#445bb93296bd6da4a74aa40152aaa779170887cf", .url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#53da7f93154086574bf41a13130299d1bc6df670",
.hash = "SPIRV_Interpreter-0.0.1-ajmpn113CQDBhtMXf88no5gcMJhlricW5G_rWc7AvRS5", .hash = "SPIRV_Interpreter-0.0.1-ajmpn95-CQCUUA6EfT9id_Y50N7kjcKftj0VrGLyi751",
.lazy = true, .lazy = true,
}, },
//.SPIRV_Interpreter = .{ //.SPIRV_Interpreter = .{
+14 -1
View File
@@ -76,7 +76,20 @@ fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, d
drm_device.device_info.pci.vendor_id != lib.INTEL_PCI_VENDOR_ID) drm_device.device_info.pci.vendor_id != lib.INTEL_PCI_VENDOR_ID)
continue; continue;
const physical_device = try FlintPhysicalDevice.create(allocator, interface, &drm_device); const version = device.getVersion(io_var, allocator) catch continue;
defer version.deinit(allocator);
const kmd_type: lib.KmdType = if (std.mem.eql(u8, version.name, "i915"))
.I915
else if (std.mem.eql(u8, version.name, "xe"))
.Xe
else
.Invalid;
if (kmd_type == .Invalid)
continue;
const physical_device = try FlintPhysicalDevice.create(allocator, interface, &drm_device, kmd_type);
errdefer physical_device.interface.release(allocator) catch {}; errdefer physical_device.interface.release(allocator) catch {};
const dispatchable = try Dispatchable(base.PhysicalDevice).wrap(allocator, &physical_device.interface); const dispatchable = try Dispatchable(base.PhysicalDevice).wrap(allocator, &physical_device.interface);
+3 -1
View File
@@ -30,8 +30,9 @@ pub const EXTENSIONS = [_]vk.ExtensionProperties{
}; };
interface: Interface, interface: Interface,
kmd_type: lib.KmdType,
pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, drm_device: *const base.drm.Device) VkError!*Self { pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, drm_device: *const base.drm.Device, kmd_type: lib.KmdType) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory; const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
errdefer allocator.destroy(self); errdefer allocator.destroy(self);
@@ -223,6 +224,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, drm_device
self.* = .{ self.* = .{
.interface = interface, .interface = interface,
.kmd_type = kmd_type,
}; };
return self; return self;
-8
View File
@@ -31,14 +31,7 @@ const VkError = base.VkError;
const Self = @This(); const Self = @This();
pub const Interface = base.Device; pub const Interface = base.Device;
const DeviceAllocator = struct {
pub inline fn allocator(_: @This()) std.mem.Allocator {
return base.fallback_host_allocator;
}
};
interface: Interface, interface: Interface,
allocator: DeviceAllocator,
pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self { pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory; const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
@@ -80,7 +73,6 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
self.* = .{ self.* = .{
.interface = interface, .interface = interface,
.allocator = .{},
}; };
try self.interface.createQueues(allocator, info); try self.interface.createQueues(allocator, info);
+1 -1
View File
@@ -195,7 +195,7 @@ pub fn beginQuery(interface: *Interface, pool: *base.QueryPool, query: u32, _: v
if (active.pool == impl.pool and active.query == impl.query) if (active.pool == impl.pool and active.query == impl.query)
return; return;
} }
device.active_occlusion_queries.append(device.renderer.device.device_allocator.allocator(), .{ device.active_occlusion_queries.append(device.renderer.device.interface.device_allocator.allocator(), .{
.pool = impl.pool, .pool = impl.pool,
.query = impl.query, .query = impl.query,
}) catch return VkError.OutOfDeviceMemory; }) catch return VkError.OutOfDeviceMemory;
-18
View File
@@ -35,14 +35,7 @@ pub const Interface = base.Device;
const SpawnError = std.Thread.SpawnError; const SpawnError = std.Thread.SpawnError;
const DeviceAllocator = struct {
pub inline fn allocator(_: @This()) std.mem.Allocator {
return base.fallback_host_allocator;
}
};
interface: Interface, interface: Interface,
device_allocator: if (config.soft_debug_allocator) std.heap.DebugAllocator(.{}) else DeviceAllocator,
pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self { pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory; const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
@@ -91,7 +84,6 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
self.* = .{ self.* = .{
.interface = interface, .interface = interface,
.device_allocator = if (config.soft_debug_allocator) .init else .{},
}; };
initialized = true; initialized = true;
@@ -102,16 +94,6 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
if (config.soft_debug_allocator) {
// All device memory allocations should've been freed by now
const leaks = self.device_allocator.detectLeaks();
if (leaks != 0)
std.log.scoped(.vkDestroyDevice).err("Device was destroyed leaking {d:.3}KB", .{@as(f32, @floatFromInt(leaks)) / 1000})
else
std.log.scoped(.vkDestroyDevice).debug("No device memory leaks detected", .{});
self.device_allocator.deinitWithoutLeakChecks();
}
allocator.destroy(self); allocator.destroy(self);
} }
+2 -3
View File
@@ -28,15 +28,14 @@ pub fn create(device: *SoftDevice, allocator: std.mem.Allocator, size: vk.Device
self.* = .{ self.* = .{
.interface = interface, .interface = interface,
.data = device.device_allocator.allocator().alloc(u8, size) catch return VkError.OutOfDeviceMemory, .data = device.interface.device_allocator.allocator().alloc(u8, size) catch return VkError.OutOfDeviceMemory,
}; };
return self; return self;
} }
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", interface.owner)); interface.owner.device_allocator.allocator().free(self.data);
soft_device.device_allocator.allocator().free(self.data);
allocator.destroy(self); allocator.destroy(self);
} }
+29 -10
View File
@@ -79,11 +79,10 @@ pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache:
.destroy = destroy, .destroy = destroy,
}; };
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", device));
const module = try NonDispatchable(ShaderModule).fromHandleObject(info.stage.module); const module = try NonDispatchable(ShaderModule).fromHandleObject(info.stage.module);
const soft_module: *SoftShaderModule = @alignCast(@fieldParentPtr("interface", module)); const soft_module: *SoftShaderModule = @alignCast(@fieldParentPtr("interface", module));
const device_allocator = soft_device.device_allocator.allocator(); const device_allocator = device.device_allocator.allocator();
const soft_cache: ?*SoftPipelineCache = if (cache) |pipeline_cache| const soft_cache: ?*SoftPipelineCache = if (cache) |pipeline_cache|
@alignCast(@fieldParentPtr("interface", pipeline_cache)) @alignCast(@fieldParentPtr("interface", pipeline_cache))
else else
@@ -123,8 +122,7 @@ pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache:
.destroy = destroy, .destroy = destroy,
}; };
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", device)); const device_allocator = device.device_allocator.allocator();
const device_allocator = soft_device.device_allocator.allocator();
const soft_cache: ?*SoftPipelineCache = if (cache) |pipeline_cache| const soft_cache: ?*SoftPipelineCache = if (cache) |pipeline_cache|
@alignCast(@fieldParentPtr("interface", pipeline_cache)) @alignCast(@fieldParentPtr("interface", pipeline_cache))
else else
@@ -185,8 +183,7 @@ pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache:
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", interface.owner)); const device_allocator = interface.owner.device_allocator.allocator();
const device_allocator = soft_device.device_allocator.allocator();
var it = self.stages.iterator(); var it = self.stages.iterator();
while (it.next()) |entry| { while (it.next()) |entry| {
@@ -486,10 +483,22 @@ fn readImageFloat4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32,
.@"2d", .@"2d_array", .cube, .cube_array => .{ .x = x, .y = y, .z = 0 }, .@"2d", .@"2d_array", .cube, .cube_array => .{ .x = x, .y = y, .z = 0 },
else => .{ .x = x, .y = y, .z = z }, else => .{ .x = x, .y = y, .z = z },
}; };
const sample_count = image.interface.samples.toInt();
const sample_index: u32 = if (sample_count > 1) blk: {
if (image_view.interface.view_type == .@"2d_array" or image_view.interface.view_type == .cube_array)
break :blk @intCast(@mod(z, @as(i32, @intCast(sample_count))));
break :blk @intCast(z);
} else 0;
const array_z: i32 = if (sample_count > 1 and
(image_view.interface.view_type == .@"2d_array" or image_view.interface.view_type == .cube_array))
@divFloor(z, @as(i32, @intCast(sample_count)))
else
z;
const array_layer = image_view.interface.subresource_range.base_array_layer + switch (image_view.interface.view_type) { const array_layer = image_view.interface.subresource_range.base_array_layer + switch (image_view.interface.view_type) {
.@"1d_array" => @as(u32, @intCast(y)), .@"1d_array" => @as(u32, @intCast(y)),
.@"2d_array" => @as(u32, @intCast(z)), .@"2d_array" => @as(u32, @intCast(array_z)),
.cube => cube_face, .cube => cube_face,
.cube_array => @as(u32, @intCast(array_z)),
else => 0, else => 0,
}; };
const aspect_mask = imageReadAspect(image_view, false); const aspect_mask = imageReadAspect(image_view, false);
@@ -498,7 +507,6 @@ fn readImageFloat4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32,
.mip_level = mip_level, .mip_level = mip_level,
.array_layer = array_layer, .array_layer = array_layer,
}; };
const sample_index: u32 = if (image.interface.samples.toInt() > 1) @intCast(z) else 0;
const format = base.format.fromAspect(image_view.interface.format, aspect_mask); const format = base.format.fromAspect(image_view.interface.format, aspect_mask);
const raw_pixel = if (dim == .SubpassData) blk: { const raw_pixel = if (dim == .SubpassData) blk: {
if (findInputAttachmentSnapshot(image_view, subresource)) |snapshot| { if (findInputAttachmentSnapshot(image_view, subresource)) |snapshot| {
@@ -541,10 +549,22 @@ fn readImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, l
.@"2d", .@"2d_array", .cube, .cube_array => .{ .x = x, .y = y, .z = 0 }, .@"2d", .@"2d_array", .cube, .cube_array => .{ .x = x, .y = y, .z = 0 },
else => .{ .x = x, .y = y, .z = z }, else => .{ .x = x, .y = y, .z = z },
}; };
const sample_count = image.interface.samples.toInt();
const sample_index: u32 = if (sample_count > 1) blk: {
if (image_view.interface.view_type == .@"2d_array" or image_view.interface.view_type == .cube_array)
break :blk @intCast(@mod(z, @as(i32, @intCast(sample_count))));
break :blk @intCast(z);
} else 0;
const array_z: i32 = if (sample_count > 1 and
(image_view.interface.view_type == .@"2d_array" or image_view.interface.view_type == .cube_array))
@divFloor(z, @as(i32, @intCast(sample_count)))
else
z;
const array_layer = image_view.interface.subresource_range.base_array_layer + switch (image_view.interface.view_type) { const array_layer = image_view.interface.subresource_range.base_array_layer + switch (image_view.interface.view_type) {
.@"1d_array" => @as(u32, @intCast(y)), .@"1d_array" => @as(u32, @intCast(y)),
.@"2d_array" => @as(u32, @intCast(z)), .@"2d_array" => @as(u32, @intCast(array_z)),
.cube => cube_face, .cube => cube_face,
.cube_array => @as(u32, @intCast(array_z)),
else => 0, else => 0,
}; };
const aspect_mask = imageReadAspect(image_view, true); const aspect_mask = imageReadAspect(image_view, true);
@@ -553,7 +573,6 @@ fn readImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, l
.mip_level = mip_level, .mip_level = mip_level,
.array_layer = array_layer, .array_layer = array_layer,
}; };
const sample_index: u32 = if (image.interface.samples.toInt() > 1) @intCast(z) else 0;
const format = base.format.fromAspect(image_view.interface.format, aspect_mask); const format = base.format.fromAspect(image_view.interface.format, aspect_mask);
const raw_pixel = if (dim == .SubpassData) blk: { const raw_pixel = if (dim == .SubpassData) blk: {
if (findInputAttachmentSnapshot(image_view, subresource)) |snapshot| { if (findInputAttachmentSnapshot(image_view, subresource)) |snapshot| {
+1 -2
View File
@@ -67,8 +67,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", interface.owner)); const data_allocator = interface.owner.device_allocator.allocator();
const data_allocator = soft_device.device_allocator.allocator();
for (self.shaders.items) |*shader| { for (self.shaders.items) |*shader| {
shader.deinit(allocator, data_allocator); shader.deinit(allocator, data_allocator);
+3 -3
View File
@@ -69,7 +69,7 @@ pub fn submit(interface: *Interface, infos: []Interface.SubmitInfo, p_fence: ?*b
const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", interface.owner)); const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
const io = interface.owner.io(); const io = interface.owner.io();
const allocator = soft_device.device_allocator.allocator(); const allocator = interface.owner.device_allocator.allocator();
const data = allocator.create(TaskData) catch return VkError.OutOfDeviceMemory; const data = allocator.create(TaskData) catch return VkError.OutOfDeviceMemory;
errdefer allocator.destroy(data); errdefer allocator.destroy(data);
@@ -111,7 +111,7 @@ fn executeSubmitInfo(soft_device: *SoftDevice, info: Interface.SubmitInfo) VkErr
var execution_device: ExecutionDevice = undefined; var execution_device: ExecutionDevice = undefined;
execution_device.setup(soft_device); execution_device.setup(soft_device);
defer execution_device.deinit(soft_device.device_allocator.allocator()); defer execution_device.deinit(soft_device.interface.device_allocator.allocator());
for (info.command_buffers.items) |command_buffer| { for (info.command_buffers.items) |command_buffer| {
const soft_command_buffer: *SoftCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer)); const soft_command_buffer: *SoftCommandBuffer = @alignCast(@fieldParentPtr("interface", command_buffer));
@@ -125,7 +125,7 @@ fn executeSubmitInfo(soft_device: *SoftDevice, info: Interface.SubmitInfo) VkErr
fn taskRunner(data: *TaskData) void { fn taskRunner(data: *TaskData) void {
const io = data.queue.interface.owner.io(); const io = data.queue.interface.owner.io();
const allocator = data.soft_device.device_allocator.allocator(); const allocator = data.soft_device.interface.device_allocator.allocator();
defer { defer {
deinitSubmitInfos(allocator, &data.infos); deinitSubmitInfos(allocator, &data.infos);
-1
View File
@@ -276,7 +276,6 @@ pub fn queryImageLod(image: *SoftImage, image_view: *SoftImageView, sampler: *Se
const clamped_lod = std.math.clamp(biased_lod, sampler.interface.min_lod, sampler.interface.max_lod); const clamped_lod = std.math.clamp(biased_lod, sampler.interface.min_lod, sampler.interface.max_lod);
const max_level: f32 = @floatFromInt(viewMipCount(image_view) - 1); const max_level: f32 = @floatFromInt(viewMipCount(image_view) - 1);
const level = std.math.clamp(mipmapModeLevel(sampler, clamped_lod), 0.0, max_level); const level = std.math.clamp(mipmapModeLevel(sampler, clamped_lod), 0.0, max_level);
return .{ level, lod, 0.0, 0.0 }; return .{ level, lod, 0.0, 0.0 };
} }
+2 -4
View File
@@ -25,8 +25,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
var interface = try Interface.init(device, allocator, info); var interface = try Interface.init(device, allocator, info);
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", device)); const device_allocator = device.device_allocator.allocator();
const device_allocator = soft_device.device_allocator.allocator();
interface.vtable = &.{ interface.vtable = &.{
.destroy = destroy, .destroy = destroy,
@@ -62,8 +61,7 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
} }
pub fn drop(self: *Self, allocator: std.mem.Allocator) void { pub fn drop(self: *Self, allocator: std.mem.Allocator) void {
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", self.interface.owner)); const device_allocator = self.interface.owner.device_allocator.allocator();
const device_allocator = soft_device.device_allocator.allocator();
self.module.deinit(device_allocator); self.module.deinit(device_allocator);
+14 -9
View File
@@ -75,7 +75,7 @@ pub fn dispatchBase(self: *Self, base_group_x: u32, base_group_y: u32, base_grou
const spv_module = &shader.module.module; const spv_module = &shader.module.module;
self.batch_size = if (spv_module.reflection_infos.has_atomics) 1 else shader.runtimes.len; self.batch_size = if (spv_module.reflection_infos.has_atomics) 1 else shader.runtimes.len;
const allocator = self.device.device_allocator.allocator(); const allocator = self.device.interface.device_allocator.allocator();
const local_size = try getLocalSize(&shader.runtimes[0].rt, allocator, spv_module); const local_size = try getLocalSize(&shader.runtimes[0].rt, allocator, spv_module);
const local_size_xy = std.math.mul(usize, local_size[0], local_size[1]) catch return VkError.ValidationFailed; const local_size_xy = std.math.mul(usize, local_size[0], local_size[1]) catch return VkError.ValidationFailed;
const invocations_per_workgroup = std.math.mul(usize, local_size_xy, local_size[2]) catch return VkError.ValidationFailed; const invocations_per_workgroup = std.math.mul(usize, local_size_xy, local_size[2]) catch return VkError.ValidationFailed;
@@ -124,7 +124,7 @@ fn runWrapper(data: RunData) void {
} }
inline fn run(data: RunData) !void { inline fn run(data: RunData) !void {
const allocator = data.self.device.device_allocator.allocator(); const allocator = data.self.device.interface.device_allocator.allocator();
const io = data.self.device.interface.io(); const io = data.self.device.interface.io();
const shader = data.pipeline.stages.getPtrAssertContains(.compute); const shader = data.pipeline.stages.getPtrAssertContains(.compute);
@@ -233,7 +233,8 @@ fn runBarrierWorkgroup(
group_count: @Vector(3, u32), group_count: @Vector(3, u32),
group_id: @Vector(3, u32), group_id: @Vector(3, u32),
) !void { ) !void {
const allocator = data.self.device.device_allocator.allocator(); const allocator = data.self.device.interface.device_allocator.allocator();
const workgroup_memory = try runtimes[0].createWorkgroupMemory(allocator); const workgroup_memory = try runtimes[0].createWorkgroupMemory(allocator);
defer runtimes[0].destroyWorkgroupMemory(allocator, workgroup_memory); defer runtimes[0].destroyWorkgroupMemory(allocator, workgroup_memory);
for (runtimes, 0..) |*rt, i| { for (runtimes, 0..) |*rt, i| {
@@ -292,21 +293,25 @@ fn dumpResultsTable(allocator: std.mem.Allocator, io: std.Io, rt: *spv.Runtime,
} }
fn setupWorkgroupBuiltins(self: *Self, rt: *spv.Runtime, local_size: @Vector(3, u32), group_count: @Vector(3, u32), group_id: @Vector(3, u32)) spv.Runtime.RuntimeError!void { fn setupWorkgroupBuiltins(self: *Self, rt: *spv.Runtime, local_size: @Vector(3, u32), group_count: @Vector(3, u32), group_id: @Vector(3, u32)) spv.Runtime.RuntimeError!void {
rt.writeBuiltIn(self.device.device_allocator.allocator(), std.mem.asBytes(&local_size), .WorkgroupSize) catch |err| switch (err) { const allocator = self.device.interface.device_allocator.allocator();
rt.writeBuiltIn(allocator, std.mem.asBytes(&local_size), .WorkgroupSize) catch |err| switch (err) {
SpvRuntimeError.NotFound => {}, SpvRuntimeError.NotFound => {},
else => return err, else => return err,
}; };
rt.writeBuiltIn(self.device.device_allocator.allocator(), std.mem.asBytes(&group_count), .NumWorkgroups) catch |err| switch (err) { rt.writeBuiltIn(allocator, std.mem.asBytes(&group_count), .NumWorkgroups) catch |err| switch (err) {
SpvRuntimeError.NotFound => {}, SpvRuntimeError.NotFound => {},
else => return err, else => return err,
}; };
rt.writeBuiltIn(self.device.device_allocator.allocator(), std.mem.asBytes(&group_id), .WorkgroupId) catch |err| switch (err) { rt.writeBuiltIn(allocator, std.mem.asBytes(&group_id), .WorkgroupId) catch |err| switch (err) {
SpvRuntimeError.NotFound => {}, SpvRuntimeError.NotFound => {},
else => return err, else => return err,
}; };
} }
fn setupSubgroupBuiltins(self: *Self, rt: *spv.Runtime, local_size: @Vector(3, u32), group_id: @Vector(3, u32), local_invocation_index: usize) spv.Runtime.RuntimeError!void { fn setupSubgroupBuiltins(self: *Self, rt: *spv.Runtime, local_size: @Vector(3, u32), group_id: @Vector(3, u32), local_invocation_index: usize) spv.Runtime.RuntimeError!void {
const allocator = self.device.interface.device_allocator.allocator();
const local_base = local_size * group_id; const local_base = local_size * group_id;
var local_invocation = @Vector(3, u32){ 0, 0, 0 }; var local_invocation = @Vector(3, u32){ 0, 0, 0 };
@@ -320,15 +325,15 @@ fn setupSubgroupBuiltins(self: *Self, rt: *spv.Runtime, local_size: @Vector(3, u
const global_invocation_index = local_base + local_invocation; const global_invocation_index = local_base + local_invocation;
const local_invocation_index_u32: u32 = @intCast(local_invocation_index); const local_invocation_index_u32: u32 = @intCast(local_invocation_index);
rt.writeBuiltIn(self.device.device_allocator.allocator(), std.mem.asBytes(&local_invocation), .LocalInvocationId) catch |err| switch (err) { rt.writeBuiltIn(allocator, std.mem.asBytes(&local_invocation), .LocalInvocationId) catch |err| switch (err) {
SpvRuntimeError.NotFound => {}, SpvRuntimeError.NotFound => {},
else => return err, else => return err,
}; };
rt.writeBuiltIn(self.device.device_allocator.allocator(), std.mem.asBytes(&local_invocation_index_u32), .LocalInvocationIndex) catch |err| switch (err) { rt.writeBuiltIn(allocator, std.mem.asBytes(&local_invocation_index_u32), .LocalInvocationIndex) catch |err| switch (err) {
SpvRuntimeError.NotFound => {}, SpvRuntimeError.NotFound => {},
else => return err, else => return err,
}; };
rt.writeBuiltIn(self.device.device_allocator.allocator(), std.mem.asBytes(&global_invocation_index), .GlobalInvocationId) catch |err| switch (err) { rt.writeBuiltIn(allocator, std.mem.asBytes(&global_invocation_index), .GlobalInvocationId) catch |err| switch (err) {
SpvRuntimeError.NotFound => {}, SpvRuntimeError.NotFound => {},
else => return err, else => return err,
}; };
+6 -3
View File
@@ -187,7 +187,7 @@ pub fn init(device: *SoftDevice, state: *PipelineState, active_occlusion_queries
} }
pub fn resetInputAttachmentSnapshots(self: *Self) void { pub fn resetInputAttachmentSnapshots(self: *Self) void {
const allocator = self.device.device_allocator.allocator(); const allocator = self.device.interface.device_allocator.allocator();
for (self.input_attachment_snapshots) |snapshot| { for (self.input_attachment_snapshots) |snapshot| {
allocator.free(snapshot.data); allocator.free(snapshot.data);
} }
@@ -196,12 +196,12 @@ pub fn resetInputAttachmentSnapshots(self: *Self) void {
} }
pub fn draw(self: *Self, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) VkError!void { pub fn draw(self: *Self, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) VkError!void {
var bounded_allocator: BoundedAllocator = .init(self.device.device_allocator.allocator(), 4 * @"1GiB"); var bounded_allocator: BoundedAllocator = .init(self.device.interface.device_allocator.allocator(), 4 * @"1GiB");
try self.drawCall(&bounded_allocator, vertex_count, instance_count, first_vertex, first_instance, null, null); try self.drawCall(&bounded_allocator, vertex_count, instance_count, first_vertex, first_instance, null, null);
} }
pub fn drawIndexed(self: *Self, index_count: usize, instance_count: usize, first_index: usize, first_instance: usize, vertex_offset: i32) VkError!void { pub fn drawIndexed(self: *Self, index_count: usize, instance_count: usize, first_index: usize, first_instance: usize, vertex_offset: i32) VkError!void {
var bounded_allocator: BoundedAllocator = .init(self.device.device_allocator.allocator(), 4 * @"1GiB"); var bounded_allocator: BoundedAllocator = .init(self.device.interface.device_allocator.allocator(), 4 * @"1GiB");
const allocator = bounded_allocator.allocator(); const allocator = bounded_allocator.allocator();
const indexed_draw = try self.readIndexBuffer(allocator, index_count, first_index, vertex_offset); const indexed_draw = try self.readIndexBuffer(allocator, index_count, first_index, vertex_offset);
@@ -266,6 +266,9 @@ fn drawCall(self: *Self, bounded_allocator: *BoundedAllocator, vertex_count: usi
return VkError.Unknown; return VkError.Unknown;
}; };
if (pipeline.interface.mode.graphics.rasterization.rasterizer_discard_enable)
return;
draw_call.viewport = try self.resolveViewport(0); draw_call.viewport = try self.resolveViewport(0);
draw_call.scissor = try self.resolveScissor(0); draw_call.scissor = try self.resolveScissor(0);
+69 -5
View File
@@ -67,10 +67,8 @@ pub fn shaderInvocation(
else => return err, else => return err,
}; };
if (rt.getBuiltinResult(.FragCoord)) |frag_coord_word| { if (rt.getBuiltinResult(.FragCoord)) |frag_coord_word| {
const frag_x: i32 = @intFromFloat(position[0]); const frag_coord_dx = zm.f32x4(1.0, 0.0, 0.0, 0.0);
const frag_y: i32 = @intFromFloat(position[1]); const frag_coord_dy = zm.f32x4(0.0, 1.0, 0.0, 0.0);
const frag_coord_dx = zm.f32x4(if (@mod(frag_x, 2) == 0) 1.0 else -1.0, 0.0, 0.0, 0.0);
const frag_coord_dy = zm.f32x4(0.0, if (@mod(frag_y, 2) == 0) 1.0 else -1.0, 0.0, 0.0);
try rt.setDerivativeFromMemory(allocator, frag_coord_word, std.mem.asBytes(&frag_coord_dx), std.mem.asBytes(&frag_coord_dy)); try rt.setDerivativeFromMemory(allocator, frag_coord_word, std.mem.asBytes(&frag_coord_dx), std.mem.asBytes(&frag_coord_dy));
} }
if (point_coord) |coord| { if (point_coord) |coord| {
@@ -170,7 +168,9 @@ pub fn shaderInvocation(
if (input.size != 0) { if (input.size != 0) {
const input_bytes = input.blob[0..input.size]; const input_bytes = input.blob[0..input.size];
if (!has_result_value or input.size < memory_size) if (has_result_value and input.size < memory_size)
try writeAggregateInputLocations(allocator, rt, fragment_inputs, result_word, location, component, memory_size)
else if (!has_result_value)
try rt.writeInputLocation(input_bytes, @intCast(location)) try rt.writeInputLocation(input_bytes, @intCast(location))
else else
try rt.writeInput(allocator, input_bytes, result_word); try rt.writeInput(allocator, input_bytes, result_word);
@@ -262,6 +262,70 @@ pub fn shaderInvocation(
}; };
} }
fn writeAggregateInputLocations(
allocator: std.mem.Allocator,
rt: *spv.Runtime,
inputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS]VertexInterpolationLocation,
result_word: spv.SpvWord,
location: usize,
component: usize,
memory_size: usize,
) SpvRuntimeError!void {
const value = try rt.results[result_word].getConstValue();
switch (value.*) {
.Array, .Matrix => {},
else => {
const input = inputs[location][component];
if (input.size != 0)
try rt.writeInputLocation(input.blob[0..input.size], @intCast(location));
return;
},
}
const bytes = allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return SpvRuntimeError.OutOfMemory;
defer allocator.free(bytes);
@memset(bytes, 0);
var source_location = location;
var offset: usize = 0;
try copyAggregateInputLocations(value, inputs, &source_location, component, bytes[0..memory_size], &offset);
try rt.writeInput(allocator, bytes[0..memory_size], result_word);
}
fn copyAggregateInputLocations(
value: anytype,
inputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS]VertexInterpolationLocation,
source_location: *usize,
component: usize,
bytes: []u8,
offset: *usize,
) SpvRuntimeError!void {
switch (value.*) {
.Array => |array| {
for (array.values) |*element|
try copyAggregateInputLocations(element, inputs, source_location, component, bytes, offset);
},
.Matrix => |columns| {
for (columns) |*column|
try copyAggregateInputLocations(column, inputs, source_location, component, bytes, offset);
},
else => {
if (source_location.* >= inputs.len or component >= 4)
return SpvRuntimeError.OutOfBounds;
const input = inputs[source_location.*][component];
const element_size = try value.getPlainMemorySize();
if (offset.* > bytes.len or element_size > bytes.len - offset.*)
return SpvRuntimeError.OutOfBounds;
if (input.size != 0) {
const copy_size = @min(element_size, input.size);
@memcpy(bytes[offset.* .. offset.* + copy_size], input.blob[0..copy_size]);
}
offset.* += element_size;
source_location.* += 1;
},
}
}
fn readFragmentOutput( fn readFragmentOutput(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
rt: anytype, rt: anytype,
+1 -1
View File
@@ -107,7 +107,7 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
const pipeline_data = (renderer.state.pipeline orelse return VkError.InvalidHandleDrv).interface.mode.graphics; const pipeline_data = (renderer.state.pipeline orelse return VkError.InvalidHandleDrv).interface.mode.graphics;
const topology = pipeline_data.input_assembly.topology; const topology = pipeline_data.input_assembly.topology;
if (renderer.input_attachment_snapshots.len == 0) { if (renderer.input_attachment_snapshots.len == 0) {
renderer.input_attachment_snapshots = try snapshotInputAttachments(renderer.device.device_allocator.allocator(), draw_call); renderer.input_attachment_snapshots = try snapshotInputAttachments(renderer.device.interface.device_allocator.allocator(), draw_call);
} }
draw_call.input_attachment_snapshots = renderer.input_attachment_snapshots; draw_call.input_attachment_snapshots = renderer.input_attachment_snapshots;
+2 -1
View File
@@ -612,7 +612,8 @@ pub fn writeToTargets(
const color = maybe_color orelse continue; const color = maybe_color orelse continue;
const color_offset = targetSampleOffset(color, x, y, sample_index) orelse continue; const color_offset = targetSampleOffset(color, x, y, sample_index) orelse continue;
if (base.format.isUnnormalizedInteger(color.format)) { if (base.format.isUnnormalizedInteger(color.format)) {
blitter.writeInt4(std.mem.bytesToValue(U32x4, &outputs[location]), color.base[color_offset..], color.format); const value = std.mem.bytesToValue(U32x4, &outputs[location]);
blitter.writeInt4(value, color.base[color_offset..], color.format);
} else { } else {
const src = fragmentOutputFloat4(outputs[location], color.format); const src = fragmentOutputFloat4(outputs[location], color.format);
const encoded_dst = blitter.readFloat4(color.base[color_offset..], color.format); const encoded_dst = blitter.readFloat4(color.base[color_offset..], color.format);
@@ -381,7 +381,7 @@ inline fn run(data: RunData) !void {
if (early_depth.mask == 0) if (early_depth.mask == 0)
continue; continue;
const interpolation_barycentrics = if (data.sample_count > 1) blk: { const interpolation_barycentrics = if (data.sample_count > 1 and data.fragment_uses_centroid) blk: {
const sample_pos = firstCoveredSamplePosition(data.sample_count, early_depth.mask); const sample_pos = firstCoveredSamplePosition(data.sample_count, early_depth.mask);
const centroid_p = zm.f32x4( const centroid_p = zm.f32x4(
@as(f32, @floatFromInt(x)) + sample_pos.x, @as(f32, @floatFromInt(x)) + sample_pos.x,
+82 -7
View File
@@ -115,6 +115,7 @@ inline fn run(data: RunData) !void {
try readPosition(rt, std.mem.asBytes(&output.position)); try readPosition(rt, std.mem.asBytes(&output.position));
try readPointSize(rt, &output.point_size); try readPointSize(rt, &output.point_size);
try readActiveInterfaceOutputs(data, output, rt, entry);
for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| { for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| {
const location_result = rt.getResultByLocation(@intCast(location), .output) catch |err| switch (err) { const location_result = rt.getResultByLocation(@intCast(location), .output) catch |err| switch (err) {
@@ -122,6 +123,7 @@ inline fn run(data: RunData) !void {
else => return err, else => return err,
}; };
if (output.outputs[location][0] == null)
try readVertexOutput(data, output, rt, location, 0, location_result); try readVertexOutput(data, output, rt, location, 0, location_result);
for (1..4) |component| { for (1..4) |component| {
@@ -133,12 +135,11 @@ inline fn run(data: RunData) !void {
if (component_result == location_result) if (component_result == location_result)
continue; continue;
if (output.outputs[location][component] == null)
try readVertexOutput(data, output, rt, location, component, component_result); try readVertexOutput(data, output, rt, location, component, component_result);
} }
} }
try readActiveInterfaceOutputs(data, output, rt, entry);
try rt.flushDescriptorSets(data.allocator); try rt.flushDescriptorSets(data.allocator);
} }
} }
@@ -170,9 +171,8 @@ fn readActiveInterfaceOutputs(data: RunData, output: *Renderer.Vertex, rt: *spv.
if (rt.results[type_word].variant) |type_variant| switch (type_variant) { if (rt.results[type_word].variant) |type_variant| switch (type_variant) {
.Type => |t| switch (t) { .Type => |t| switch (t) {
.Structure => |structure| { .Structure => |structure| {
const base_location = location orelse continue;
for (structure.members_type_word, 0..) |_, member_index| { for (structure.members_type_word, 0..) |_, member_index| {
const member_location = interfaceMemberLocation(rt, type_word, base_location, @intCast(member_index)); const member_location = explicitInterfaceMemberLocation(rt, type_word, @intCast(member_index)) orelse continue;
if (member_location >= spv.SPIRV_MAX_OUTPUT_LOCATIONS) if (member_location >= spv.SPIRV_MAX_OUTPUT_LOCATIONS)
continue; continue;
if (output.outputs[member_location][component] != null) if (output.outputs[member_location][component] != null)
@@ -199,8 +199,16 @@ fn readActiveInterfaceOutputs(data: RunData, output: *Renderer.Vertex, rt: *spv.
} }
fn readVertexOutput(data: RunData, output: *Renderer.Vertex, rt: *spv.Runtime, location: usize, component: usize, result_word: spv.SpvWord) !void { fn readVertexOutput(data: RunData, output: *Renderer.Vertex, rt: *spv.Runtime, location: usize, component: usize, result_word: spv.SpvWord) !void {
const value = try rt.results[result_word].getConstValue();
const memory_size = try rt.getResultMemorySize(result_word); const memory_size = try rt.getResultMemorySize(result_word);
const interpolation_type = vertexOutputInterpolationType(data, rt, location, component, result_word); const interpolation_type = vertexOutputInterpolationType(data, rt, location, component, result_word);
switch (value.*) {
.Array, .Matrix => {
try readVertexOutputAggregate(data, output, value, location, component, interpolation_type);
return;
},
else => {},
}
output.outputs[location][component] = .{ output.outputs[location][component] = .{
.interpolation_type = interpolation_type, .interpolation_type = interpolation_type,
@@ -211,6 +219,66 @@ fn readVertexOutput(data: RunData, output: *Renderer.Vertex, rt: *spv.Runtime, l
try rt.readOutput(output.outputs[location][component].?.blob, result_word); try rt.readOutput(output.outputs[location][component].?.blob, result_word);
} }
fn readVertexOutputAggregate(
data: RunData,
output: *Renderer.Vertex,
value: anytype,
location: usize,
component: usize,
interpolation_type: Renderer.InterpolationType,
) !void {
var target_location = location;
switch (value.*) {
.Array => |array| {
for (array.values) |*element| {
try readVertexOutputAggregate(data, output, element, target_location, component, interpolation_type);
target_location += vertexOutputValueLocationCount(element);
}
},
.Matrix => |columns| {
for (columns) |*column| {
try writeVertexOutputValue(data, output, column, target_location, component, interpolation_type);
target_location += 1;
}
},
else => try writeVertexOutputValue(data, output, value, location, component, interpolation_type),
}
}
fn writeVertexOutputValue(
data: RunData,
output: *Renderer.Vertex,
value: anytype,
location: usize,
component: usize,
interpolation_type: Renderer.InterpolationType,
) !void {
if (location >= spv.SPIRV_MAX_OUTPUT_LOCATIONS or component >= 4)
return VkError.ValidationFailed;
const memory_size = try value.getPlainMemorySize();
output.outputs[location][component] = .{
.interpolation_type = interpolation_type,
.blob = data.allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return VkError.OutOfDeviceMemory,
.size = memory_size,
};
@memset(output.outputs[location][component].?.blob, 0);
_ = try value.read(output.outputs[location][component].?.blob[0..memory_size]);
}
fn vertexOutputValueLocationCount(value: anytype) usize {
return switch (value.*) {
.Array => |array| count: {
var location_count: usize = 0;
for (array.values) |*element|
location_count += vertexOutputValueLocationCount(element);
break :count location_count;
},
.Matrix => |columns| columns.len,
else => 1,
};
}
fn vertexOutputInterpolationType(data: RunData, rt: *spv.Runtime, location: usize, component: usize, result_word: spv.SpvWord) Renderer.InterpolationType { fn vertexOutputInterpolationType(data: RunData, rt: *spv.Runtime, location: usize, component: usize, result_word: spv.SpvWord) Renderer.InterpolationType {
const result_is_integer = resultIsInteger(rt, result_word); const result_is_integer = resultIsInteger(rt, result_word);
@@ -259,7 +327,7 @@ fn interfaceLocationMemberHasDecoration(rt: *const spv.Runtime, location: usize,
continue; continue;
const type_word = pointerTargetType(rt, variable.type_word) orelse continue; const type_word = pointerTargetType(rt, variable.type_word) orelse continue;
const base_location = resultLocation(rt, @intCast(id)) orelse continue; const base_location = resultLocation(rt, @intCast(id));
const type_result = rt.results[type_word]; const type_result = rt.results[type_word];
const type_variant = type_result.variant orelse continue; const type_variant = type_result.variant orelse continue;
switch (type_variant) { switch (type_variant) {
@@ -292,14 +360,21 @@ fn resultLocation(rt: *const spv.Runtime, result_word: spv.SpvWord) ?usize {
return null; return null;
} }
fn interfaceMemberLocation(rt: *const spv.Runtime, type_word: spv.SpvWord, base_location: usize, member_index: spv.SpvWord) usize { fn interfaceMemberLocation(rt: *const spv.Runtime, type_word: spv.SpvWord, base_location: ?usize, member_index: spv.SpvWord) ?usize {
if (explicitInterfaceMemberLocation(rt, type_word, member_index)) |location|
return location;
return if (base_location) |location| location + @as(usize, @intCast(member_index)) else null;
}
fn explicitInterfaceMemberLocation(rt: *const spv.Runtime, type_word: spv.SpvWord, member_index: spv.SpvWord) ?usize {
if (type_word < rt.results.len) { if (type_word < rt.results.len) {
for (rt.results[type_word].decorations.items) |decoration| { for (rt.results[type_word].decorations.items) |decoration| {
if (decoration.rtype == .Location and decoration.index == member_index) if (decoration.rtype == .Location and decoration.index == member_index)
return decoration.literal_1; return decoration.literal_1;
} }
} }
return base_location + @as(usize, @intCast(member_index)); return null;
} }
fn interfaceMemberHasDecoration(rt: *const spv.Runtime, variable_word: spv.SpvWord, member_index: spv.SpvWord, decoration: anytype) bool { fn interfaceMemberHasDecoration(rt: *const spv.Runtime, variable_word: spv.SpvWord, member_index: spv.SpvWord, decoration: anytype) bool {
+21
View File
@@ -1,5 +1,7 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const lib = @import("lib.zig");
const config = lib.config;
const Dispatchable = @import("Dispatchable.zig").Dispatchable; const Dispatchable = @import("Dispatchable.zig").Dispatchable;
const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable;
@@ -37,10 +39,17 @@ const SwapchainKHR = @import("wsi/SwapchainKHR.zig");
const Self = @This(); const Self = @This();
pub const ObjectType: vk.ObjectType = .device; pub const ObjectType: vk.ObjectType = .device;
const DeviceAllocator = struct {
pub inline fn allocator(_: @This()) std.mem.Allocator {
return lib.fallback_host_allocator;
}
};
instance: *Instance, instance: *Instance,
physical_device: *const PhysicalDevice, physical_device: *const PhysicalDevice,
queues: std.AutoArrayHashMapUnmanaged(u32, std.ArrayList(*Dispatchable(Queue))), queues: std.AutoArrayHashMapUnmanaged(u32, std.ArrayList(*Dispatchable(Queue))),
host_allocator: VulkanAllocator, host_allocator: VulkanAllocator,
device_allocator: if (config.device_debug_allocator) std.heap.DebugAllocator(.{}) else DeviceAllocator,
enabled_khr_swapchain: bool, enabled_khr_swapchain: bool,
enabled_khr_device_group: bool, enabled_khr_device_group: bool,
@@ -110,6 +119,7 @@ pub fn init(allocator: std.mem.Allocator, instance: *Instance, physical_device:
.host_allocator = VulkanAllocator.from(allocator).cloneWithScope(.object), .host_allocator = VulkanAllocator.from(allocator).cloneWithScope(.object),
.enabled_khr_swapchain = enabled_khr_swapchain, .enabled_khr_swapchain = enabled_khr_swapchain,
.enabled_khr_device_group = enabled_khr_device_group, .enabled_khr_device_group = enabled_khr_device_group,
.device_allocator = if (config.device_debug_allocator) .init else .{},
.dispatch_table = undefined, .dispatch_table = undefined,
.vtable = undefined, .vtable = undefined,
}; };
@@ -154,6 +164,17 @@ pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) VkError!void {
family.deinit(allocator); family.deinit(allocator);
} }
self.queues.deinit(allocator); self.queues.deinit(allocator);
if (config.device_debug_allocator) {
// All device memory allocations should've been freed by now
const leaks = self.device_allocator.detectLeaks();
if (leaks != 0)
std.log.scoped(.vkDestroyDevice).err("Device was destroyed leaking {d:.3}KB", .{@as(f32, @floatFromInt(leaks)) / 1000})
else
std.log.scoped(.vkDestroyDevice).debug("No device memory leaks detected", .{});
self.device_allocator.deinitWithoutLeakChecks();
}
try self.dispatch_table.destroy(self, allocator); try self.dispatch_table.destroy(self, allocator);
} }
+2
View File
@@ -45,6 +45,7 @@ mode: union(enum) {
scissor: ?[]vk.Rect2D, scissor: ?[]vk.Rect2D,
}, },
rasterization: struct { rasterization: struct {
rasterizer_discard_enable: bool,
polygon_mode: vk.PolygonMode, polygon_mode: vk.PolygonMode,
cull_mode: vk.CullModeFlags, cull_mode: vk.CullModeFlags,
front_face: vk.FrontFace, front_face: vk.FrontFace,
@@ -194,6 +195,7 @@ pub fn initGraphics(device: *Device, allocator: std.mem.Allocator, cache: ?*Pipe
}, },
}, },
.rasterization = .{ .rasterization = .{
.rasterizer_discard_enable = rasterizer_discard_enable,
.polygon_mode = if (info.p_rasterization_state) |state| state.polygon_mode else return VkError.ValidationFailed, .polygon_mode = if (info.p_rasterization_state) |state| state.polygon_mode else return VkError.ValidationFailed,
.cull_mode = if (info.p_rasterization_state) |state| state.cull_mode else return VkError.ValidationFailed, .cull_mode = if (info.p_rasterization_state) |state| state.cull_mode else return VkError.ValidationFailed,
.front_face = if (info.p_rasterization_state) |state| state.front_face else return VkError.ValidationFailed, .front_face = if (info.p_rasterization_state) |state| state.front_face else return VkError.ValidationFailed,