fixing compute shared atomic memory, fixing vertex/fragment payloads, implementing early fragment depth tests
This commit is contained in:
+2
-2
@@ -32,8 +32,8 @@
|
|||||||
|
|
||||||
// Soft dependencies
|
// Soft dependencies
|
||||||
.SPIRV_Interpreter = .{
|
.SPIRV_Interpreter = .{
|
||||||
.url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#b9b6087fef5a61a3d9e3187ff7c66dffc54603da",
|
.url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#fcf303a0c62a66ff32fc92fe9c92ca9294f72caf",
|
||||||
.hash = "SPIRV_Interpreter-0.0.1-ajmpn9JxCADthSmyktTCV_jIA8iJU_aiM_kboXqfPDDD",
|
.hash = "SPIRV_Interpreter-0.0.1-ajmpnx3dCAAfuabTUWPWdTVqPGBPeSUCCTI-ncKowi5D",
|
||||||
.lazy = true,
|
.lazy = true,
|
||||||
},
|
},
|
||||||
//.SPIRV_Interpreter = .{
|
//.SPIRV_Interpreter = .{
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ fn createShader(
|
|||||||
runtimes_count: usize,
|
runtimes_count: usize,
|
||||||
) VkError!Shader {
|
) VkError!Shader {
|
||||||
const entry = std.mem.span(stage.p_name);
|
const entry = std.mem.span(stage.p_name);
|
||||||
|
const execution_model = executionModelForStage(stage.stage) orelse return VkError.Unknown;
|
||||||
const runtimes = runtimes_allocator.alloc(Runtime, runtimes_count) catch return VkError.OutOfDeviceMemory;
|
const runtimes = runtimes_allocator.alloc(Runtime, runtimes_count) catch return VkError.OutOfDeviceMemory;
|
||||||
var initialized: usize = 0;
|
var initialized: usize = 0;
|
||||||
var module_ref = false;
|
var module_ref = false;
|
||||||
@@ -212,7 +213,7 @@ fn createShader(
|
|||||||
const image_api = imageApi();
|
const image_api = imageApi();
|
||||||
var cache_hit = false;
|
var cache_hit = false;
|
||||||
if (cache) |pipeline_cache| {
|
if (cache) |pipeline_cache| {
|
||||||
if (try pipeline_cache.cloneRuntime(runtimes_allocator, module, entry, stage.p_specialization_info, image_api)) |runtime| {
|
if (try pipeline_cache.cloneRuntime(runtimes_allocator, module, entry, execution_model, stage.p_specialization_info, image_api)) |runtime| {
|
||||||
runtimes[0] = .{
|
runtimes[0] = .{
|
||||||
.mutex = .init,
|
.mutex = .init,
|
||||||
.rt = runtime,
|
.rt = runtime,
|
||||||
@@ -226,7 +227,7 @@ fn createShader(
|
|||||||
for (runtimes[initialized..]) |*runtime| {
|
for (runtimes[initialized..]) |*runtime| {
|
||||||
runtime.* = .{
|
runtime.* = .{
|
||||||
.mutex = .init,
|
.mutex = .init,
|
||||||
.rt = (try cache.?.cloneRuntime(runtimes_allocator, module, entry, stage.p_specialization_info, image_api)).?,
|
.rt = (try cache.?.cloneRuntime(runtimes_allocator, module, entry, execution_model, stage.p_specialization_info, image_api)).?,
|
||||||
};
|
};
|
||||||
initialized += 1;
|
initialized += 1;
|
||||||
}
|
}
|
||||||
@@ -240,7 +241,7 @@ fn createShader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cache) |pipeline_cache| {
|
if (cache) |pipeline_cache| {
|
||||||
try pipeline_cache.storeRuntimeTemplate(object_allocator, cache_allocator, module, entry, stage.p_specialization_info, image_api);
|
try pipeline_cache.storeRuntimeTemplate(object_allocator, cache_allocator, module, entry, execution_model, stage.p_specialization_info, image_api);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,10 +259,29 @@ fn initRuntime(allocator: std.mem.Allocator, module: *SoftShaderModule, stage: *
|
|||||||
};
|
};
|
||||||
errdefer runtime.deinit(allocator);
|
errdefer runtime.deinit(allocator);
|
||||||
|
|
||||||
|
const entry = runtime.getEntryPointByNameAndExecutionModel(std.mem.span(stage.p_name), executionModelForStage(stage.stage) orelse return VkError.Unknown) catch |err| {
|
||||||
|
std.log.scoped(.SpvRuntimeInit).err("SPIR-V Runtime failed to select entry point, {s}", .{@errorName(err)});
|
||||||
|
return VkError.Unknown;
|
||||||
|
};
|
||||||
|
runtime.selectEntryPoint(entry) catch |err| {
|
||||||
|
std.log.scoped(.SpvRuntimeInit).err("SPIR-V Runtime failed to activate entry point, {s}", .{@errorName(err)});
|
||||||
|
return VkError.Unknown;
|
||||||
|
};
|
||||||
|
|
||||||
try applySpecialization(&runtime, allocator, stage.p_specialization_info);
|
try applySpecialization(&runtime, allocator, stage.p_specialization_info);
|
||||||
return runtime;
|
return runtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn executionModelForStage(stage: vk.ShaderStageFlags) ?spv.spv.SpvExecutionModel {
|
||||||
|
if (stage.vertex_bit) return .Vertex;
|
||||||
|
if (stage.tessellation_control_bit) return .TessellationControl;
|
||||||
|
if (stage.tessellation_evaluation_bit) return .TessellationEvaluation;
|
||||||
|
if (stage.geometry_bit) return .Geometry;
|
||||||
|
if (stage.fragment_bit) return .Fragment;
|
||||||
|
if (stage.compute_bit) return .GLCompute;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
fn applySpecialization(runtime: *spv.Runtime, allocator: std.mem.Allocator, specialization: ?*const vk.SpecializationInfo) VkError!void {
|
fn applySpecialization(runtime: *spv.Runtime, allocator: std.mem.Allocator, specialization: ?*const vk.SpecializationInfo) VkError!void {
|
||||||
const info = specialization orelse return;
|
const info = specialization orelse return;
|
||||||
const map = info.p_map_entries orelse return;
|
const map = info.p_map_entries orelse return;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const CacheRecord = extern struct {
|
|||||||
const CachedShader = struct {
|
const CachedShader = struct {
|
||||||
module: *SoftShaderModule,
|
module: *SoftShaderModule,
|
||||||
entry: []u8,
|
entry: []u8,
|
||||||
|
execution_model: spv.spv.SpvExecutionModel,
|
||||||
specs: []SpecConstant,
|
specs: []SpecConstant,
|
||||||
runtime: spv.Runtime,
|
runtime: spv.Runtime,
|
||||||
|
|
||||||
@@ -81,6 +82,7 @@ pub fn cloneRuntime(
|
|||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
module: *SoftShaderModule,
|
module: *SoftShaderModule,
|
||||||
entry: []const u8,
|
entry: []const u8,
|
||||||
|
execution_model: spv.spv.SpvExecutionModel,
|
||||||
specialization: ?*const vk.SpecializationInfo,
|
specialization: ?*const vk.SpecializationInfo,
|
||||||
image_api: spv.Runtime.ImageAPI,
|
image_api: spv.Runtime.ImageAPI,
|
||||||
) VkError!?spv.Runtime {
|
) VkError!?spv.Runtime {
|
||||||
@@ -89,8 +91,14 @@ pub fn cloneRuntime(
|
|||||||
defer self.mutex.unlock(io);
|
defer self.mutex.unlock(io);
|
||||||
|
|
||||||
for (self.shaders.items) |*shader| {
|
for (self.shaders.items) |*shader| {
|
||||||
if (shader.module == module and std.mem.eql(u8, shader.entry, entry) and specsEqual(shader.specs, specialization)) {
|
if (shader.module == module and shader.execution_model == execution_model and std.mem.eql(u8, shader.entry, entry) and specsEqual(shader.specs, specialization)) {
|
||||||
return spv.Runtime.initFrom(allocator, &shader.runtime, image_api) catch return VkError.OutOfDeviceMemory;
|
var runtime = spv.Runtime.initFrom(allocator, &shader.runtime, image_api) catch return VkError.OutOfDeviceMemory;
|
||||||
|
errdefer runtime.deinit(allocator);
|
||||||
|
|
||||||
|
const entry_point = runtime.getEntryPointByNameAndExecutionModel(entry, execution_model) catch return VkError.Unknown;
|
||||||
|
runtime.selectEntryPoint(entry_point) catch return VkError.Unknown;
|
||||||
|
|
||||||
|
return runtime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,6 +111,7 @@ pub fn storeRuntimeTemplate(
|
|||||||
data_allocator: std.mem.Allocator,
|
data_allocator: std.mem.Allocator,
|
||||||
module: *SoftShaderModule,
|
module: *SoftShaderModule,
|
||||||
entry: []const u8,
|
entry: []const u8,
|
||||||
|
execution_model: spv.spv.SpvExecutionModel,
|
||||||
specialization: ?*const vk.SpecializationInfo,
|
specialization: ?*const vk.SpecializationInfo,
|
||||||
image_api: spv.Runtime.ImageAPI,
|
image_api: spv.Runtime.ImageAPI,
|
||||||
) VkError!void {
|
) VkError!void {
|
||||||
@@ -112,6 +121,7 @@ pub fn storeRuntimeTemplate(
|
|||||||
|
|
||||||
for (self.shaders.items) |*shader| {
|
for (self.shaders.items) |*shader| {
|
||||||
if (shader.module == module and
|
if (shader.module == module and
|
||||||
|
shader.execution_model == execution_model and
|
||||||
std.mem.eql(u8, shader.entry, entry) and
|
std.mem.eql(u8, shader.entry, entry) and
|
||||||
specsEqual(shader.specs, specialization))
|
specsEqual(shader.specs, specialization))
|
||||||
{
|
{
|
||||||
@@ -122,6 +132,7 @@ pub fn storeRuntimeTemplate(
|
|||||||
var cached: CachedShader = .{
|
var cached: CachedShader = .{
|
||||||
.module = module,
|
.module = module,
|
||||||
.entry = data_allocator.dupe(u8, entry) catch return VkError.OutOfDeviceMemory,
|
.entry = data_allocator.dupe(u8, entry) catch return VkError.OutOfDeviceMemory,
|
||||||
|
.execution_model = execution_model,
|
||||||
.specs = try cloneSpecs(data_allocator, specialization),
|
.specs = try cloneSpecs(data_allocator, specialization),
|
||||||
.runtime = spv.Runtime.init(data_allocator, &module.module, image_api) catch return VkError.OutOfDeviceMemory,
|
.runtime = spv.Runtime.init(data_allocator, &module.module, image_api) catch return VkError.OutOfDeviceMemory,
|
||||||
};
|
};
|
||||||
@@ -141,6 +152,8 @@ pub fn storeRuntimeTemplate(
|
|||||||
|
|
||||||
module.ref();
|
module.ref();
|
||||||
module_ref = true;
|
module_ref = true;
|
||||||
|
const entry_point = cached.runtime.getEntryPointByNameAndExecutionModel(entry, execution_model) catch return VkError.Unknown;
|
||||||
|
cached.runtime.selectEntryPoint(entry_point) catch return VkError.Unknown;
|
||||||
try applySpecialization(&cached.runtime, data_allocator, specialization);
|
try applySpecialization(&cached.runtime, data_allocator, specialization);
|
||||||
try appendCacheRecord(&self.interface, module, entry, cached.specs);
|
try appendCacheRecord(&self.interface, module, entry, cached.specs);
|
||||||
|
|
||||||
|
|||||||
@@ -594,6 +594,9 @@ pub fn sampleImageInt4(image: *SoftImage, image_view: *SoftImageView, sampler: *
|
|||||||
const scale_v: f32 = if (sampler.interface.unnormalized_coordinates == .true) 1.0 else @floatFromInt(extent.height);
|
const scale_v: f32 = if (sampler.interface.unnormalized_coordinates == .true) 1.0 else @floatFromInt(extent.height);
|
||||||
const scale_w: f32 = if (sampler.interface.unnormalized_coordinates == .true) 1.0 else @floatFromInt(extent.depth);
|
const scale_w: f32 = if (sampler.interface.unnormalized_coordinates == .true) 1.0 else @floatFromInt(extent.depth);
|
||||||
|
|
||||||
|
const ix = @as(i32, @intFromFloat(@floor(coord.u * scale_u))) + offset.x;
|
||||||
|
const iy = @as(i32, @intFromFloat(@floor(coord.v * scale_v))) + offset.y;
|
||||||
|
const iz = @as(i32, @intFromFloat(@floor(coord.w * scale_w))) + offset.z;
|
||||||
const color = try readSampledInt4(
|
const color = try readSampledInt4(
|
||||||
image,
|
image,
|
||||||
image_view,
|
image_view,
|
||||||
@@ -601,9 +604,9 @@ pub fn sampleImageInt4(image: *SoftImage, image_view: *SoftImageView, sampler: *
|
|||||||
dim,
|
dim,
|
||||||
coord,
|
coord,
|
||||||
mip_level,
|
mip_level,
|
||||||
@as(i32, @intFromFloat(@floor(coord.u * scale_u))) + offset.x,
|
ix,
|
||||||
@as(i32, @intFromFloat(@floor(coord.v * scale_v))) + offset.y,
|
iy,
|
||||||
@as(i32, @intFromFloat(@floor(coord.w * scale_w))) + offset.z,
|
iz,
|
||||||
);
|
);
|
||||||
return swizzleInt4(color, image_view.interface.components);
|
return swizzleInt4(color, image_view.interface.components);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ pub fn dispatchBase(self: *Self, base_group_x: u32, base_group_y: u32, base_grou
|
|||||||
const pipeline = self.state.pipeline orelse return VkError.InvalidPipelineDrv;
|
const pipeline = self.state.pipeline orelse return VkError.InvalidPipelineDrv;
|
||||||
const shader = pipeline.stages.getPtr(.compute) orelse return VkError.InvalidPipelineDrv;
|
const shader = pipeline.stages.getPtr(.compute) orelse return VkError.InvalidPipelineDrv;
|
||||||
const spv_module = &shader.module.module;
|
const spv_module = &shader.module.module;
|
||||||
self.batch_size = 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.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);
|
||||||
@@ -131,7 +131,7 @@ inline fn run(data: RunData) !void {
|
|||||||
const rt = &shader.runtimes[data.batch_id].rt;
|
const rt = &shader.runtimes[data.batch_id].rt;
|
||||||
|
|
||||||
const entry = try rt.getEntryPointByName(shader.entry);
|
const entry = try rt.getEntryPointByName(shader.entry);
|
||||||
const uses_control_barrier = rt.mod.reflection_infos.has_control_barriers;
|
const uses_control_barrier = rt.mod.reflection_infos.has_control_barriers or rt.mod.reflection_infos.has_atomics;
|
||||||
|
|
||||||
var barrier_runtimes: []spv.Runtime = &.{};
|
var barrier_runtimes: []spv.Runtime = &.{};
|
||||||
var barrier_statuses: []spv.Runtime.EntryPointStatus = &.{};
|
var barrier_statuses: []spv.Runtime.EntryPointStatus = &.{};
|
||||||
@@ -146,17 +146,13 @@ inline fn run(data: RunData) !void {
|
|||||||
|
|
||||||
defer {
|
defer {
|
||||||
for (barrier_runtimes) |*barrier_rt| {
|
for (barrier_runtimes) |*barrier_rt| {
|
||||||
|
barrier_rt.resetInvocation(allocator);
|
||||||
barrier_rt.deinit(allocator);
|
barrier_rt.deinit(allocator);
|
||||||
}
|
}
|
||||||
allocator.free(barrier_runtimes);
|
allocator.free(barrier_runtimes);
|
||||||
allocator.free(barrier_statuses);
|
allocator.free(barrier_statuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!uses_control_barrier)
|
|
||||||
try ExecutionDevice.writeDescriptorSets(data.self.state, rt);
|
|
||||||
|
|
||||||
try rt.populatePushConstants(data.self.state.push_constant_blob[0..]);
|
|
||||||
|
|
||||||
var group_index: usize = data.batch_id;
|
var group_index: usize = data.batch_id;
|
||||||
while (group_index < data.group_count) : (group_index += data.self.batch_size) {
|
while (group_index < data.group_count) : (group_index += data.self.batch_size) {
|
||||||
var modulo: usize = group_index;
|
var modulo: usize = group_index;
|
||||||
@@ -185,8 +181,16 @@ inline fn run(data: RunData) !void {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const workgroup_memory = try rt.createWorkgroupMemory(allocator);
|
||||||
|
defer rt.destroyWorkgroupMemory(allocator, workgroup_memory);
|
||||||
|
|
||||||
for (0..data.invocations_per_workgroup) |i| {
|
for (0..data.invocations_per_workgroup) |i| {
|
||||||
rt.resetInvocation(allocator);
|
rt.resetInvocation(allocator);
|
||||||
|
if (rt.specialization_constants.count() != 0)
|
||||||
|
try rt.applySpecializationInvocationLayout(allocator);
|
||||||
|
try ExecutionDevice.writeDescriptorSets(data.self.state, rt);
|
||||||
|
try rt.populatePushConstants(data.self.state.push_constant_blob[0..]);
|
||||||
|
try rt.bindWorkgroupMemory(workgroup_memory);
|
||||||
try setupWorkgroupBuiltins(data.self, rt, data.local_size, group_count_vec, group_id_vec);
|
try setupWorkgroupBuiltins(data.self, rt, data.local_size, group_count_vec, group_id_vec);
|
||||||
|
|
||||||
const invocation_index = data.self.invocation_index.fetchAdd(1, .monotonic);
|
const invocation_index = data.self.invocation_index.fetchAdd(1, .monotonic);
|
||||||
@@ -208,13 +212,13 @@ inline fn run(data: RunData) !void {
|
|||||||
SpvRuntimeError.Killed => continue,
|
SpvRuntimeError.Killed => continue,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
|
try flushWorkgroupMemory(rt, workgroup_memory);
|
||||||
|
try rt.flushDescriptorSets(allocator);
|
||||||
|
|
||||||
if (data.self.final_dump != null and data.self.final_dump.? == invocation_index) {
|
if (data.self.final_dump != null and data.self.final_dump.? == invocation_index) {
|
||||||
@branchHint(.cold);
|
@branchHint(.cold);
|
||||||
try dumpResultsTable(allocator, io, rt, false);
|
try dumpResultsTable(allocator, io, rt, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
try rt.flushDescriptorSets(allocator);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,14 +232,19 @@ fn runBarrierWorkgroup(
|
|||||||
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.device_allocator.allocator();
|
||||||
|
const workgroup_memory = try runtimes[0].createWorkgroupMemory(allocator);
|
||||||
|
defer runtimes[0].destroyWorkgroupMemory(allocator, workgroup_memory);
|
||||||
for (runtimes, 0..) |*rt, i| {
|
for (runtimes, 0..) |*rt, i| {
|
||||||
rt.resetInvocation(allocator);
|
rt.resetInvocation(allocator);
|
||||||
|
if (rt.specialization_constants.count() != 0)
|
||||||
|
try rt.applySpecializationInvocationLayout(allocator);
|
||||||
try ExecutionDevice.writeDescriptorSets(data.self.state, rt);
|
try ExecutionDevice.writeDescriptorSets(data.self.state, rt);
|
||||||
try rt.populatePushConstants(data.self.state.push_constant_blob[0..]);
|
try rt.populatePushConstants(data.self.state.push_constant_blob[0..]);
|
||||||
|
try rt.bindWorkgroupMemory(workgroup_memory);
|
||||||
try setupWorkgroupBuiltins(data.self, rt, data.local_size, group_count, group_id);
|
try setupWorkgroupBuiltins(data.self, rt, data.local_size, group_count, group_id);
|
||||||
try setupSubgroupBuiltins(data.self, rt, data.local_size, group_id, i);
|
try setupSubgroupBuiltins(data.self, rt, data.local_size, group_id, i);
|
||||||
statuses[i] = try rt.beginEntryPoint(allocator, entry);
|
statuses[i] = try rt.beginEntryPoint(allocator, entry);
|
||||||
|
try flushWorkgroupMemory(rt, workgroup_memory);
|
||||||
try rt.flushDescriptorSets(allocator);
|
try rt.flushDescriptorSets(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,12 +262,20 @@ fn runBarrierWorkgroup(
|
|||||||
for (runtimes, 0..) |*rt, i| {
|
for (runtimes, 0..) |*rt, i| {
|
||||||
if (statuses[i] == .completed)
|
if (statuses[i] == .completed)
|
||||||
continue;
|
continue;
|
||||||
|
try rt.bindWorkgroupMemory(workgroup_memory);
|
||||||
statuses[i] = try rt.continueEntryPoint(allocator);
|
statuses[i] = try rt.continueEntryPoint(allocator);
|
||||||
|
try flushWorkgroupMemory(rt, workgroup_memory);
|
||||||
try rt.flushDescriptorSets(allocator);
|
try rt.flushDescriptorSets(allocator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn flushWorkgroupMemory(rt: *spv.Runtime, workgroup_memory: []const spv.Runtime.WorkgroupMemory) spv.Runtime.RuntimeError!void {
|
||||||
|
for (workgroup_memory) |memory| {
|
||||||
|
_ = try (try rt.results[memory.result].getValue()).read(memory.bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn dumpResultsTable(allocator: std.mem.Allocator, io: std.Io, rt: *spv.Runtime, comptime is_early: bool) !void {
|
fn dumpResultsTable(allocator: std.mem.Allocator, io: std.Io, rt: *spv.Runtime, comptime is_early: bool) !void {
|
||||||
@branchHint(.cold);
|
@branchHint(.cold);
|
||||||
const file = try std.Io.Dir.cwd().createFile(
|
const file = try std.Io.Dir.cwd().createFile(
|
||||||
|
|||||||
@@ -101,7 +101,9 @@ fn writeDescriptorValue(value: anytype, payload: DescriptorPayload, descriptor_i
|
|||||||
};
|
};
|
||||||
|
|
||||||
switch (payload) {
|
switch (payload) {
|
||||||
.raw => |data| _ = try dst.write(data),
|
.raw => |data| {
|
||||||
|
_ = try dst.write(data);
|
||||||
|
},
|
||||||
.sampled_image => |data| switch (dst.*) {
|
.sampled_image => |data| switch (dst.*) {
|
||||||
.Image => _ = try dst.write(std.mem.asBytes(&data.image)),
|
.Image => _ = try dst.write(std.mem.asBytes(&data.image)),
|
||||||
.Sampler => _ = try dst.write(std.mem.asBytes(&data.sampler)),
|
.Sampler => _ = try dst.write(std.mem.asBytes(&data.sampler)),
|
||||||
@@ -144,6 +146,10 @@ pub fn writeDescriptorSets(state: *PipelineState, rt: *spv.Runtime) !void {
|
|||||||
switch (binding) {
|
switch (binding) {
|
||||||
.buffer => |buffer_data_array| for (buffer_data_array, 0..) |buffer_data, descriptor_index| {
|
.buffer => |buffer_data_array| for (buffer_data_array, 0..) |buffer_data, descriptor_index| {
|
||||||
if (buffer_data.object) |buffer| {
|
if (buffer_data.object) |buffer| {
|
||||||
|
const memory = buffer.interface.memory orelse continue;
|
||||||
|
if (@intFromPtr(memory.vtable) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
const binding_layout = set.?.interface.layout.bindings[binding_index];
|
const binding_layout = set.?.interface.layout.bindings[binding_index];
|
||||||
const dynamic_offset: vk.DeviceSize = switch (binding_layout.descriptor_type) {
|
const dynamic_offset: vk.DeviceSize = switch (binding_layout.descriptor_type) {
|
||||||
.uniform_buffer_dynamic,
|
.uniform_buffer_dynamic,
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ pub const IndexBuffer = struct {
|
|||||||
index_type: vk.IndexType,
|
index_type: vk.IndexType,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const InterpolationType = enum { smooth, flat, noperspective };
|
||||||
|
|
||||||
pub const DynamicState = struct {
|
pub const DynamicState = struct {
|
||||||
viewports: ?[]const vk.Viewport,
|
viewports: ?[]const vk.Viewport,
|
||||||
scissor: ?[]const vk.Rect2D,
|
scissor: ?[]const vk.Rect2D,
|
||||||
@@ -57,7 +59,7 @@ pub const Vertex = struct {
|
|||||||
position: F32x4,
|
position: F32x4,
|
||||||
point_size: f32,
|
point_size: f32,
|
||||||
outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][4]?struct {
|
outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][4]?struct {
|
||||||
interpolation_type: enum { smooth, flat, noperspective },
|
interpolation_type: InterpolationType,
|
||||||
blob: []u8,
|
blob: []u8,
|
||||||
size: usize,
|
size: usize,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ pub fn shaderInvocation(
|
|||||||
defer mutex.unlock(io);
|
defer mutex.unlock(io);
|
||||||
|
|
||||||
rt.resetInvocation(allocator);
|
rt.resetInvocation(allocator);
|
||||||
|
if (rt.specialization_constants.count() != 0)
|
||||||
|
try rt.applySpecializationInvocationLayout(allocator);
|
||||||
|
try @import("Device.zig").writeDescriptorSets(draw_call.renderer.state, rt);
|
||||||
try rt.populatePushConstants(draw_call.renderer.state.push_constant_blob[0..]);
|
try rt.populatePushConstants(draw_call.renderer.state.push_constant_blob[0..]);
|
||||||
rt.writeBuiltIn(allocator, std.mem.asBytes(&position), .FragCoord) catch |err| switch (err) {
|
rt.writeBuiltIn(allocator, std.mem.asBytes(&position), .FragCoord) catch |err| switch (err) {
|
||||||
SpvRuntimeError.NotFound => {},
|
SpvRuntimeError.NotFound => {},
|
||||||
@@ -96,8 +99,8 @@ pub fn shaderInvocation(
|
|||||||
var input = fragment_inputs[location][component];
|
var input = fragment_inputs[location][component];
|
||||||
const result_word = rt.getResultByLocationComponent(@intCast(location), @intCast(component), .input) catch |err| switch (err) {
|
const result_word = rt.getResultByLocationComponent(@intCast(location), @intCast(component), .input) catch |err| switch (err) {
|
||||||
SpvRuntimeError.NotFound => {
|
SpvRuntimeError.NotFound => {
|
||||||
if (input.blob.len != 0) {
|
if (input.size != 0) {
|
||||||
rt.writeInputLocation(input.blob, @intCast(location)) catch |write_err| switch (write_err) {
|
rt.writeInputLocation(input.blob[0..input.size], @intCast(location)) catch |write_err| switch (write_err) {
|
||||||
SpvRuntimeError.NotFound => {},
|
SpvRuntimeError.NotFound => {},
|
||||||
else => return write_err,
|
else => return write_err,
|
||||||
};
|
};
|
||||||
@@ -110,11 +113,11 @@ pub fn shaderInvocation(
|
|||||||
const has_result_value = rt.results[result_word].variant != null;
|
const has_result_value = rt.results[result_word].variant != null;
|
||||||
const memory_size = if (has_result_value)
|
const memory_size = if (has_result_value)
|
||||||
try rt.getResultMemorySize(result_word)
|
try rt.getResultMemorySize(result_word)
|
||||||
else if (input.blob.len == 0)
|
else if (input.size == 0)
|
||||||
try rt.getInputLocationMemorySize(@intCast(location))
|
try rt.getInputLocationMemorySize(@intCast(location))
|
||||||
else
|
else
|
||||||
input.blob.len;
|
input.size;
|
||||||
if (input.blob.len == 0) {
|
if (input.size == 0) {
|
||||||
const zeroes = allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return SpvRuntimeError.OutOfMemory;
|
const zeroes = allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return SpvRuntimeError.OutOfMemory;
|
||||||
@memset(zeroes, 0);
|
@memset(zeroes, 0);
|
||||||
fragment_inputs[location][component] = .{
|
fragment_inputs[location][component] = .{
|
||||||
@@ -125,16 +128,17 @@ pub fn shaderInvocation(
|
|||||||
input = fragment_inputs[location][component];
|
input = fragment_inputs[location][component];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.blob.len != 0) {
|
if (input.size != 0) {
|
||||||
if (!has_result_value or input.blob.len < memory_size)
|
const input_bytes = input.blob[0..input.size];
|
||||||
try rt.writeInputLocation(input.blob, @intCast(location))
|
if (!has_result_value or input.size < memory_size)
|
||||||
|
try rt.writeInputLocation(input_bytes, @intCast(location))
|
||||||
else
|
else
|
||||||
try rt.writeInput(allocator, input.blob, result_word);
|
try rt.writeInput(allocator, input_bytes, result_word);
|
||||||
if (derivatives) |derivative| {
|
if (derivatives) |derivative| {
|
||||||
const dx = derivative.dx[location][component];
|
const dx = derivative.dx[location][component];
|
||||||
const dy = derivative.dy[location][component];
|
const dy = derivative.dy[location][component];
|
||||||
if (dx.blob.len != 0 and dy.blob.len != 0) {
|
if (dx.size != 0 and dy.size != 0) {
|
||||||
try rt.setDerivativeFromMemory(allocator, result_word, dx.blob, dy.blob);
|
try rt.setDerivativeFromMemory(allocator, result_word, dx.blob[0..dx.size], dy.blob[0..dy.size]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -431,6 +431,7 @@ fn rasterizeTransformedPoint(
|
|||||||
fragment_result.depth orelse vertex.position[2],
|
fragment_result.depth orelse vertex.position[2],
|
||||||
null,
|
null,
|
||||||
fragment_result.sample_mask,
|
fragment_result.sample_mask,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -283,6 +283,7 @@ inline fn run(data: RunData) !void {
|
|||||||
data.draw_call.renderer.state.pipeline.?.interface.mode.graphics.multisample.rasterization_samples.toInt(),
|
data.draw_call.renderer.state.pipeline.?.interface.mode.graphics.multisample.rasterization_samples.toInt(),
|
||||||
),
|
),
|
||||||
fragment_result.sample_mask,
|
fragment_result.sample_mask,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,6 +172,31 @@ pub fn depthTestAndUpdate(depth: *RenderTargetAccess, x: usize, y: usize, z: f32
|
|||||||
return depthTestAndUpdateAtOffset(depth, offset, z, state);
|
return depthTestAndUpdateAtOffset(depth, offset, z, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn depthTestSampleAndUpdate(
|
||||||
|
io: std.Io,
|
||||||
|
depth: *RenderTargetAccess,
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
sample_index: usize,
|
||||||
|
z: f32,
|
||||||
|
state: ?vk.PipelineDepthStencilStateCreateInfo,
|
||||||
|
) VkError!bool {
|
||||||
|
const depth_offset = targetSampleOffset(depth.*, x, y, sample_index) orelse return false;
|
||||||
|
|
||||||
|
depth.mutex.lock(io) catch return VkError.DeviceLost;
|
||||||
|
defer depth.mutex.unlock(io);
|
||||||
|
|
||||||
|
if (state) |depth_state| {
|
||||||
|
return depthTestAndUpdateAtOffset(depth, depth_offset, z, depth_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
const depth_value = blitter.readFloat4(depth.base[depth_offset..], depth.format);
|
||||||
|
if (z >= depth_value[0])
|
||||||
|
return false;
|
||||||
|
blitter.writeFloat4(zm.f32x4s(z), depth.base[depth_offset..], depth.format);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
fn depthTestAndUpdateAtOffset(depth: *RenderTargetAccess, offset: usize, z: f32, state: vk.PipelineDepthStencilStateCreateInfo) bool {
|
fn depthTestAndUpdateAtOffset(depth: *RenderTargetAccess, offset: usize, z: f32, state: vk.PipelineDepthStencilStateCreateInfo) bool {
|
||||||
if (state.depth_test_enable == .false)
|
if (state.depth_test_enable == .false)
|
||||||
return true;
|
return true;
|
||||||
@@ -477,6 +502,7 @@ pub fn writeToTargets(
|
|||||||
z: f32,
|
z: f32,
|
||||||
coverage_sample_mask: ?vk.SampleMask,
|
coverage_sample_mask: ?vk.SampleMask,
|
||||||
fragment_sample_mask: ?vk.SampleMask,
|
fragment_sample_mask: ?vk.SampleMask,
|
||||||
|
depth_already_applied: bool,
|
||||||
) VkError!void {
|
) VkError!void {
|
||||||
const io = draw_call.renderer.device.interface.io();
|
const io = draw_call.renderer.device.interface.io();
|
||||||
const pipeline_data = draw_call.renderer.state.pipeline.?.interface.mode.graphics;
|
const pipeline_data = draw_call.renderer.state.pipeline.?.interface.mode.graphics;
|
||||||
@@ -523,7 +549,8 @@ pub fn writeToTargets(
|
|||||||
|
|
||||||
// After work depth test to avoid overwritten depth pixels during fragment invocations.
|
// After work depth test to avoid overwritten depth pixels during fragment invocations.
|
||||||
var depth_passed: ?bool = null;
|
var depth_passed: ?bool = null;
|
||||||
if (depth_attachment_access) |depth| {
|
if (!depth_already_applied and depth_attachment_access != null) {
|
||||||
|
const depth = depth_attachment_access.?;
|
||||||
const depth_offset = targetSampleOffset(depth.*, x, y, sample_index) orelse continue;
|
const depth_offset = targetSampleOffset(depth.*, x, y, sample_index) orelse continue;
|
||||||
|
|
||||||
depth.mutex.lock(io) catch return VkError.DeviceLost;
|
depth.mutex.lock(io) catch return VkError.DeviceLost;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const RunData = struct {
|
|||||||
stencil_attachment_access: ?*common.RenderTargetAccess,
|
stencil_attachment_access: ?*common.RenderTargetAccess,
|
||||||
front_face: bool,
|
front_face: bool,
|
||||||
has_fragment_shader: bool,
|
has_fragment_shader: bool,
|
||||||
|
early_fragment_tests: bool,
|
||||||
fragment_uses_derivatives: bool,
|
fragment_uses_derivatives: bool,
|
||||||
fragment_uses_sample_id: bool,
|
fragment_uses_sample_id: bool,
|
||||||
fragment_uses_centroid: bool,
|
fragment_uses_centroid: bool,
|
||||||
@@ -70,6 +71,10 @@ pub fn drawTriangle(
|
|||||||
stage.module.module.reflection_infos.needs_derivatives
|
stage.module.module.reflection_infos.needs_derivatives
|
||||||
else
|
else
|
||||||
false;
|
false;
|
||||||
|
const early_fragment_tests = if (fragment_stage) |stage|
|
||||||
|
stage.module.module.reflection_infos.early_fragment_tests
|
||||||
|
else
|
||||||
|
false;
|
||||||
const fragment_uses_sample_id = if (fragment_stage) |stage|
|
const fragment_uses_sample_id = if (fragment_stage) |stage|
|
||||||
stage.module.module.builtins.get(.SampleId) != null
|
stage.module.module.builtins.get(.SampleId) != null
|
||||||
else
|
else
|
||||||
@@ -130,6 +135,7 @@ pub fn drawTriangle(
|
|||||||
.stencil_attachment_access = stencil_attachment_access,
|
.stencil_attachment_access = stencil_attachment_access,
|
||||||
.front_face = front_face,
|
.front_face = front_face,
|
||||||
.has_fragment_shader = fragment_stage != null,
|
.has_fragment_shader = fragment_stage != null,
|
||||||
|
.early_fragment_tests = early_fragment_tests,
|
||||||
.fragment_uses_derivatives = fragment_uses_derivatives,
|
.fragment_uses_derivatives = fragment_uses_derivatives,
|
||||||
.fragment_uses_sample_id = fragment_uses_sample_id,
|
.fragment_uses_sample_id = fragment_uses_sample_id,
|
||||||
.fragment_uses_centroid = fragment_uses_centroid,
|
.fragment_uses_centroid = fragment_uses_centroid,
|
||||||
@@ -235,6 +241,33 @@ fn triangleCoverageMask(data: RunData, x: i32, y: i32, sample_count: usize) vk.S
|
|||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn applyEarlyDepth(data: RunData, coverage_sample_mask: vk.SampleMask, x: i32, y: i32, z: f32, sample_count: usize) VkError!struct {
|
||||||
|
mask: vk.SampleMask,
|
||||||
|
applied: bool,
|
||||||
|
} {
|
||||||
|
if (!data.early_fragment_tests)
|
||||||
|
return .{ .mask = coverage_sample_mask, .applied = false };
|
||||||
|
|
||||||
|
const depth = data.depth_attachment_access orelse return .{ .mask = coverage_sample_mask, .applied = false };
|
||||||
|
const pipeline_data = data.draw_call.renderer.state.pipeline.?.interface.mode.graphics;
|
||||||
|
const io = data.draw_call.renderer.device.interface.io();
|
||||||
|
|
||||||
|
var passed_mask: vk.SampleMask = 0;
|
||||||
|
for (0..sample_count) |sample_index| {
|
||||||
|
if (sample_index >= @bitSizeOf(vk.SampleMask))
|
||||||
|
break;
|
||||||
|
|
||||||
|
const bit = @as(vk.SampleMask, 1) << @as(u5, @intCast(sample_index));
|
||||||
|
if ((coverage_sample_mask & bit) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (try common.depthTestSampleAndUpdate(io, depth, @intCast(x), @intCast(y), sample_index, z, pipeline_data.depth_stencil))
|
||||||
|
passed_mask |= bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .mask = passed_mask, .applied = true };
|
||||||
|
}
|
||||||
|
|
||||||
fn runWrapper(data: RunData) void {
|
fn runWrapper(data: RunData) void {
|
||||||
@call(.always_inline, run, .{data}) catch |err| {
|
@call(.always_inline, run, .{data}) catch |err| {
|
||||||
std.log.scoped(.@"Rasterization stage").err("triangle fill mode catched a '{s}'", .{@errorName(err)});
|
std.log.scoped(.@"Rasterization stage").err("triangle fill mode catched a '{s}'", .{@errorName(err)});
|
||||||
@@ -272,8 +305,12 @@ inline fn run(data: RunData) !void {
|
|||||||
const b2 = w2 / data.area;
|
const b2 = w2 / data.area;
|
||||||
const z = (b0 * data.v0.position[2]) + (b1 * data.v1.position[2]) + (b2 * data.v2.position[2]);
|
const z = (b0 * data.v0.position[2]) + (b1 * data.v1.position[2]) + (b2 * data.v2.position[2]);
|
||||||
const frag_w = (b0 / data.v0.position[3]) + (b1 / data.v1.position[3]) + (b2 / data.v2.position[3]);
|
const frag_w = (b0 / data.v0.position[3]) + (b1 / data.v1.position[3]) + (b2 / data.v2.position[3]);
|
||||||
|
const early_depth = try applyEarlyDepth(data, coverage_sample_mask, x, y, z, sample_count);
|
||||||
|
if (early_depth.mask == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
const interpolation_barycentrics = if (data.fragment_uses_centroid and sample_count > 1) blk: {
|
const interpolation_barycentrics = if (data.fragment_uses_centroid and sample_count > 1) blk: {
|
||||||
const sample_pos = firstCoveredSamplePosition(sample_count, coverage_sample_mask);
|
const sample_pos = firstCoveredSamplePosition(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,
|
||||||
@as(f32, @floatFromInt(y)) + sample_pos.y,
|
@as(f32, @floatFromInt(y)) + sample_pos.y,
|
||||||
@@ -305,7 +342,7 @@ inline fn run(data: RunData) !void {
|
|||||||
|
|
||||||
const bit_index: u5 = @intCast(sample_index);
|
const bit_index: u5 = @intCast(sample_index);
|
||||||
const sample_coverage_mask = @as(vk.SampleMask, 1) << bit_index;
|
const sample_coverage_mask = @as(vk.SampleMask, 1) << bit_index;
|
||||||
if ((coverage_sample_mask & sample_coverage_mask) == 0)
|
if ((early_depth.mask & sample_coverage_mask) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const inputs = try common.interpolateVertexOutputs(data.allocator, &data.v0, &data.v1, &data.v2, &data.provoking_vertex, input_b0, input_b1, input_b2);
|
const inputs = try common.interpolateVertexOutputs(data.allocator, &data.v0, &data.v1, &data.v2, &data.provoking_vertex, input_b0, input_b1, input_b2);
|
||||||
@@ -344,6 +381,7 @@ inline fn run(data: RunData) !void {
|
|||||||
sample_result.depth orelse z,
|
sample_result.depth orelse z,
|
||||||
sample_coverage_mask,
|
sample_coverage_mask,
|
||||||
sample_result.sample_mask,
|
sample_result.sample_mask,
|
||||||
|
early_depth.applied,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -423,8 +461,9 @@ inline fn run(data: RunData) !void {
|
|||||||
@intCast(x),
|
@intCast(x),
|
||||||
@intCast(y),
|
@intCast(y),
|
||||||
fragment_result.depth orelse z,
|
fragment_result.depth orelse z,
|
||||||
coverage_sample_mask,
|
early_depth.mask,
|
||||||
fragment_result.sample_mask,
|
fragment_result.sample_mask,
|
||||||
|
early_depth.applied,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,8 +60,10 @@ inline fn run(data: RunData) !void {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.resetInvocation(data.allocator);
|
rt.resetInvocation(data.allocator);
|
||||||
|
if (rt.specialization_constants.count() != 0)
|
||||||
|
try rt.applySpecializationInvocationLayout(data.allocator);
|
||||||
|
try @import("Device.zig").writeDescriptorSets(data.draw_call.renderer.state, rt);
|
||||||
try rt.populatePushConstants(data.draw_call.renderer.state.push_constant_blob[0..]);
|
try rt.populatePushConstants(data.draw_call.renderer.state.push_constant_blob[0..]);
|
||||||
|
|
||||||
const vertex_index_u32: u32 = if (data.indices) |indices| indices[invocation_index] else @intCast(data.first_vertex + invocation_index);
|
const vertex_index_u32: u32 = if (data.indices) |indices| indices[invocation_index] else @intCast(data.first_vertex + invocation_index);
|
||||||
@@ -107,30 +109,101 @@ inline fn run(data: RunData) !void {
|
|||||||
try readPointSize(rt, &output.point_size);
|
try readPointSize(rt, &output.point_size);
|
||||||
|
|
||||||
for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| {
|
for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| {
|
||||||
for (0..4) |component| {
|
const location_result = rt.getResultByLocation(@intCast(location), .output) catch |err| switch (err) {
|
||||||
const result_word = rt.getResultByLocationComponent(@intCast(location), @intCast(component), .output) catch |err| switch (err) {
|
SpvRuntimeError.NotFound => continue,
|
||||||
|
else => return err,
|
||||||
|
};
|
||||||
|
|
||||||
|
try readVertexOutput(data, output, rt, location, 0, location_result);
|
||||||
|
|
||||||
|
for (1..4) |component| {
|
||||||
|
const component_result = rt.getResultByLocationComponent(@intCast(location), @intCast(component), .output) catch |err| switch (err) {
|
||||||
SpvRuntimeError.NotFound => continue,
|
SpvRuntimeError.NotFound => continue,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
|
|
||||||
const memory_size = try rt.getResultMemorySize(result_word);
|
if (component_result == location_result)
|
||||||
|
continue;
|
||||||
|
|
||||||
const result_is_integer = resultIsInteger(rt, result_word);
|
try readVertexOutput(data, output, rt, location, component, component_result);
|
||||||
|
|
||||||
output.outputs[location][component] = .{
|
|
||||||
.interpolation_type = if (rt.hasResultDecoration(result_word, .Flat) or result_is_integer) .flat else .smooth, // TODO : handle noperspective
|
|
||||||
.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 rt.readOutput(output.outputs[location][component].?.blob, result_word);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try readActiveInterfaceOutputs(data, output, rt, entry);
|
||||||
|
|
||||||
try rt.flushDescriptorSets(data.allocator);
|
try rt.flushDescriptorSets(data.allocator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn readActiveInterfaceOutputs(data: RunData, output: *Renderer.Vertex, rt: *spv.Runtime, entry: spv.SpvWord) !void {
|
||||||
|
if (entry >= rt.mod.entry_points.items.len)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (rt.mod.entry_points.items[entry].globals) |global| {
|
||||||
|
if (global >= rt.results.len)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const variable = switch (rt.results[global].variant orelse continue) {
|
||||||
|
.Variable => |v| v,
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
if (variable.storage_class != .Output)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var location: ?usize = null;
|
||||||
|
var component: usize = 0;
|
||||||
|
for (rt.results[global].decorations.items) |decoration| switch (decoration.rtype) {
|
||||||
|
.Location => location = decoration.literal_1,
|
||||||
|
.Component => component = decoration.literal_1,
|
||||||
|
else => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const target_location = location orelse continue;
|
||||||
|
if (target_location >= spv.SPIRV_MAX_OUTPUT_LOCATIONS or component >= 4)
|
||||||
|
continue;
|
||||||
|
if (output.outputs[target_location][component] != null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try readVertexOutput(data, output, rt, target_location, component, global);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readVertexOutput(data: RunData, output: *Renderer.Vertex, rt: *spv.Runtime, location: usize, component: usize, result_word: spv.SpvWord) !void {
|
||||||
|
const memory_size = try rt.getResultMemorySize(result_word);
|
||||||
|
const interpolation_type = vertexOutputInterpolationType(data, rt, location, component, result_word);
|
||||||
|
|
||||||
|
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 rt.readOutput(output.outputs[location][component].?.blob, result_word);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 fragment_input_word = if (data.pipeline.stages.getPtr(.fragment)) |fragment_shader|
|
||||||
|
fragment_shader.runtimes[0].rt.getResultByLocationComponent(@intCast(location), @intCast(component), .input) catch null
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
const fragment_input_is_flat = if (fragment_input_word) |input_word|
|
||||||
|
data.pipeline.stages.getPtrAssertContains(.fragment).runtimes[0].rt.hasResultOrMemberDecoration(input_word, .Flat)
|
||||||
|
else
|
||||||
|
false;
|
||||||
|
const fragment_input_is_noperspective = if (fragment_input_word) |input_word|
|
||||||
|
data.pipeline.stages.getPtrAssertContains(.fragment).runtimes[0].rt.hasResultOrMemberDecoration(input_word, .NoPerspective)
|
||||||
|
else
|
||||||
|
false;
|
||||||
|
|
||||||
|
if (fragment_input_is_flat or result_is_integer)
|
||||||
|
return .flat;
|
||||||
|
if (fragment_input_is_noperspective)
|
||||||
|
return .noperspective;
|
||||||
|
return .smooth;
|
||||||
|
}
|
||||||
|
|
||||||
fn findBindingDescription(binding_descriptions: []const vk.VertexInputBindingDescription, binding: u32) ?vk.VertexInputBindingDescription {
|
fn findBindingDescription(binding_descriptions: []const vk.VertexInputBindingDescription, binding: u32) ?vk.VertexInputBindingDescription {
|
||||||
for (binding_descriptions) |description| {
|
for (binding_descriptions) |description| {
|
||||||
if (description.binding == binding)
|
if (description.binding == binding)
|
||||||
|
|||||||
Reference in New Issue
Block a user