[Soft] removing SPIR-V interpreter fallback on IR interpreter fail
This commit is contained in:
@@ -103,7 +103,7 @@ fn compileStage(allocator: std.mem.Allocator, info: *const vk.PipelineShaderStag
|
||||
.graphics => if (expected_stage == .compute) return VkError.ValidationFailed,
|
||||
}
|
||||
|
||||
const shader_module = base.NonDispatchable(base.ShaderModule).fromHandleObject(info.module) catch |err| return err;
|
||||
const shader_module = try base.NonDispatchable(base.ShaderModule).fromHandleObject(info.module);
|
||||
var module = shader_module.instantiateIr(allocator, .{
|
||||
.entry_point = std.mem.span(info.p_name),
|
||||
.stage = expected_stage,
|
||||
|
||||
@@ -252,7 +252,9 @@ fn launchHostDaemon(instance: *base.Instance, allocator: std.mem.Allocator) VkEr
|
||||
|
||||
const local_path = std.fmt.allocPrint(allocator, "/tmp/ape_phi_device_{d}_{d}.host", .{ process_id, thread_id }) catch return VkError.OutOfHostMemory;
|
||||
defer allocator.free(local_path);
|
||||
errdefer std.Io.Dir.deleteFileAbsolute(io, local_path) catch {};
|
||||
errdefer std.Io.Dir.deleteFileAbsolute(io, local_path) catch |err| {
|
||||
std.log.scoped(.PhiDevice).warn("Failed to remove Phi host daemon after launch error: {s}", .{@errorName(err)});
|
||||
};
|
||||
|
||||
std.Io.Dir.writeFile(.cwd(), io, .{
|
||||
.sub_path = local_path,
|
||||
|
||||
@@ -132,7 +132,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
|
||||
.command_allocator = undefined,
|
||||
.commands = .empty,
|
||||
};
|
||||
self.command_allocator = .init(interface.host_allocator.allocator());
|
||||
self.command_allocator = .init(self.interface.host_allocator.allocator());
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ pub fn create(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo)
|
||||
.requestPhysicalDevices = requestPhysicalDevices,
|
||||
.releasePhysicalDevices = releasePhysicalDevices,
|
||||
.io = io,
|
||||
.enumerate_drm_devices = false,
|
||||
};
|
||||
return &self.interface;
|
||||
}
|
||||
|
||||
@@ -48,13 +48,14 @@ const Runtime = struct {
|
||||
rt: spv.Runtime,
|
||||
};
|
||||
|
||||
const Shader = struct {
|
||||
const SpvShader = struct {
|
||||
module: *SoftShaderModule,
|
||||
runtimes: []Runtime,
|
||||
entry: []const u8,
|
||||
interpreter: ?InterpreterShader,
|
||||
};
|
||||
|
||||
const Shader = if (base.config.soft_ir_interpreter) InterpreterShader else SpvShader;
|
||||
|
||||
const Stages = enum {
|
||||
vertex,
|
||||
tessellation_control,
|
||||
@@ -107,7 +108,10 @@ pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache:
|
||||
};
|
||||
|
||||
self.stages.put(.compute, try createShader(allocator, device_allocator, runtimes_allocator, soft_cache, soft_module, &info.stage, runtimes_count));
|
||||
std.log.scoped(.ComputePipeline).debug("Created {d} runtimes for compute stage", .{runtimes_count});
|
||||
std.log.scoped(.ComputePipeline).debug("Created {d} {s} runtimes for compute stage", .{
|
||||
runtimes_count,
|
||||
if (comptime base.config.soft_ir_interpreter) "IR" else "SPIR-V",
|
||||
});
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -152,7 +156,10 @@ pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache:
|
||||
const soft_module: *SoftShaderModule = @alignCast(@fieldParentPtr("interface", module));
|
||||
const shader = try createShader(allocator, device_allocator, runtimes_allocator, soft_cache, soft_module, &stage, runtimes_count);
|
||||
|
||||
std.log.scoped(.GraphicsPipeline).debug("Created {d} runtimes for:", .{runtimes_count});
|
||||
std.log.scoped(.GraphicsPipeline).debug("Created {d} {s} runtimes for:", .{
|
||||
runtimes_count,
|
||||
if (comptime base.config.soft_ir_interpreter) "IR" else "SPIR-V",
|
||||
});
|
||||
|
||||
if (stage.stage.contains(.{ .vertex_bit = true })) {
|
||||
std.log.scoped(.GraphicsPipeline).debug("> Vertex stage", .{});
|
||||
@@ -183,17 +190,20 @@ pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache:
|
||||
|
||||
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
const device_allocator = interface.owner.device_allocator.allocator();
|
||||
|
||||
var it = self.stages.iterator();
|
||||
if (comptime base.config.soft_ir_interpreter) {
|
||||
while (it.next()) |entry|
|
||||
entry.value.deinit();
|
||||
} else {
|
||||
const device_allocator = interface.owner.device_allocator.allocator();
|
||||
while (it.next()) |entry| {
|
||||
if (entry.value.interpreter) |*interpreter|
|
||||
interpreter.deinit();
|
||||
entry.value.module.unref(allocator);
|
||||
for (entry.value.runtimes) |*runtime| {
|
||||
runtime.rt.function_stack.clearAndFree(device_allocator); // Hacky to avoid leaks
|
||||
}
|
||||
}
|
||||
}
|
||||
self.runtimes_allocator.deinit();
|
||||
allocator.destroy(self);
|
||||
}
|
||||
@@ -207,6 +217,9 @@ fn createShader(
|
||||
stage: *const vk.PipelineShaderStageCreateInfo,
|
||||
runtimes_count: usize,
|
||||
) VkError!Shader {
|
||||
if (comptime base.config.soft_ir_interpreter)
|
||||
return InterpreterShader.compile(runtimes_allocator, module, stage, runtimes_count);
|
||||
|
||||
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;
|
||||
@@ -259,15 +272,11 @@ fn createShader(
|
||||
}
|
||||
}
|
||||
|
||||
var shader: Shader = .{
|
||||
return .{
|
||||
.module = module,
|
||||
.runtimes = runtimes,
|
||||
.entry = runtimes_allocator.dupe(u8, entry) catch return VkError.OutOfDeviceMemory,
|
||||
.interpreter = null,
|
||||
};
|
||||
if (comptime base.config.soft_ir_interpreter)
|
||||
shader.interpreter = try InterpreterShader.compile(runtimes_allocator, module, stage, runtimes_count);
|
||||
return shader;
|
||||
}
|
||||
|
||||
fn initRuntime(allocator: std.mem.Allocator, module: *SoftShaderModule, stage: *const vk.PipelineShaderStageCreateInfo, image_api: spv.Runtime.ImageAPI) VkError!spv.Runtime {
|
||||
|
||||
@@ -71,10 +71,18 @@ 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 shader = pipeline.stages.getPtr(.compute) orelse return VkError.InvalidPipelineDrv;
|
||||
|
||||
const io = self.device.interface.io();
|
||||
const timer = std.Io.Timestamp.now(io, .real);
|
||||
defer if (comptime base.config.logs != .none) {
|
||||
const duration = timer.untilNow(io, .real);
|
||||
const ms: f32 = @floatFromInt(duration.toMicroseconds());
|
||||
std.log.scoped(.ComputeDispatcher).debug("Compute dispatch took {}ms using {s} interpreter", .{ ms / 1000, if (comptime base.config.soft_ir_interpreter) "IR" else "SPIR-V" });
|
||||
};
|
||||
|
||||
if (comptime base.config.soft_ir_interpreter) {
|
||||
if (shader.interpreter) |*interpreter_shader|
|
||||
return ir_compute.dispatch(interpreter_shader, base_group_x, base_group_y, base_group_z, group_count_x, group_count_y, group_count_z);
|
||||
}
|
||||
return ir_compute.dispatch(shader, base_group_x, base_group_y, base_group_z, group_count_x, group_count_y, group_count_z);
|
||||
} else {
|
||||
const spv_module = &shader.module.module;
|
||||
self.batch_size = if (spv_module.reflection_infos.has_atomics) 1 else shader.runtimes.len;
|
||||
|
||||
@@ -85,14 +93,6 @@ pub fn dispatchBase(self: *Self, base_group_x: u32, base_group_y: u32, base_grou
|
||||
|
||||
self.invocation_index.store(0, .monotonic);
|
||||
|
||||
const io = self.device.interface.io();
|
||||
const timer = std.Io.Timestamp.now(io, .real);
|
||||
defer if (comptime base.config.logs != .none) {
|
||||
const duration = timer.untilNow(io, .real);
|
||||
const ms: f32 = @floatFromInt(duration.toMicroseconds());
|
||||
std.log.scoped(.ComputeDispatcher).debug("Compute dispatch took {}ms", .{ms / 1000});
|
||||
};
|
||||
|
||||
var wg: std.Io.Group = .init;
|
||||
for (0..@min(self.batch_size, group_count)) |batch_id| {
|
||||
const run_data: RunData = .{
|
||||
@@ -113,6 +113,7 @@ pub fn dispatchBase(self: *Self, base_group_x: u32, base_group_y: u32, base_grou
|
||||
wg.async(self.device.interface.io(), runWrapper, .{run_data});
|
||||
}
|
||||
wg.await(self.device.interface.io()) catch return VkError.DeviceLost;
|
||||
}
|
||||
}
|
||||
|
||||
fn runWrapper(data: RunData) void {
|
||||
@@ -138,17 +139,9 @@ inline fn run(data: RunData) !void {
|
||||
|
||||
var barrier_runtimes: []spv.Runtime = &.{};
|
||||
var barrier_statuses: []spv.Runtime.EntryPointStatus = &.{};
|
||||
if (uses_control_barrier) {
|
||||
barrier_runtimes = try allocator.alloc(spv.Runtime, data.invocations_per_workgroup);
|
||||
barrier_statuses = try allocator.alloc(spv.Runtime.EntryPointStatus, data.invocations_per_workgroup);
|
||||
for (barrier_runtimes) |*barrier_rt| {
|
||||
barrier_rt.* = try spv.Runtime.init(allocator, rt.mod, rt.image_api);
|
||||
try barrier_rt.copySpecializationConstantsFrom(allocator, rt);
|
||||
}
|
||||
}
|
||||
|
||||
var initialized_barrier_runtimes: usize = 0;
|
||||
defer {
|
||||
for (barrier_runtimes) |*barrier_rt| {
|
||||
for (barrier_runtimes[0..initialized_barrier_runtimes]) |*barrier_rt| {
|
||||
barrier_rt.resetInvocation(allocator);
|
||||
barrier_rt.deinit(allocator);
|
||||
}
|
||||
@@ -156,6 +149,19 @@ inline fn run(data: RunData) !void {
|
||||
allocator.free(barrier_statuses);
|
||||
}
|
||||
|
||||
if (uses_control_barrier) {
|
||||
barrier_runtimes = try allocator.alloc(spv.Runtime, data.invocations_per_workgroup);
|
||||
barrier_statuses = try allocator.alloc(spv.Runtime.EntryPointStatus, data.invocations_per_workgroup);
|
||||
for (barrier_runtimes) |*barrier_rt| {
|
||||
barrier_rt.* = try spv.Runtime.init(allocator, rt.mod, rt.image_api);
|
||||
initialized_barrier_runtimes += 1;
|
||||
try barrier_rt.copySpecializationConstantsFrom(allocator, rt);
|
||||
try prepareRuntime(data.self, barrier_rt);
|
||||
}
|
||||
} else {
|
||||
try prepareRuntime(data.self, rt);
|
||||
}
|
||||
|
||||
var group_index: usize = data.batch_id;
|
||||
while (group_index < data.group_count) : (group_index += data.self.batch_size) {
|
||||
var modulo: usize = group_index;
|
||||
@@ -188,10 +194,6 @@ inline fn run(data: RunData) !void {
|
||||
defer rt.destroyWorkgroupMemory(allocator, workgroup_memory);
|
||||
|
||||
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);
|
||||
|
||||
@@ -228,6 +230,16 @@ inline fn run(data: RunData) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn prepareRuntime(self: *Self, rt: *spv.Runtime) !void {
|
||||
const allocator = self.device.interface.device_allocator.allocator();
|
||||
|
||||
rt.resetInvocation(allocator);
|
||||
if (rt.specialization_constants.count() != 0)
|
||||
try rt.applySpecializationInvocationLayout(allocator);
|
||||
try ExecutionDevice.writeDescriptorSets(self.state, rt);
|
||||
try rt.populatePushConstants(self.state.push_constant_blob[0..]);
|
||||
}
|
||||
|
||||
fn runBarrierWorkgroup(
|
||||
data: RunData,
|
||||
runtimes: []spv.Runtime,
|
||||
@@ -242,10 +254,6 @@ fn runBarrierWorkgroup(
|
||||
defer runtimes[0].destroyWorkgroupMemory(allocator, workgroup_memory);
|
||||
for (runtimes, 0..) |*rt, i| {
|
||||
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, group_id);
|
||||
try setupSubgroupBuiltins(data.self, rt, data.local_size, group_id, i);
|
||||
|
||||
@@ -246,15 +246,17 @@ fn drawCall(self: *Self, bounded_allocator: *BoundedAllocator, vertex_count: usi
|
||||
};
|
||||
|
||||
const pipeline = self.state.pipeline orelse return VkError.InvalidPipelineDrv;
|
||||
if (comptime !base.config.soft_ir_interpreter) {
|
||||
const vertex_shader = pipeline.stages.getPtrAssertContains(.vertex);
|
||||
for (vertex_shader.runtimes[0..]) |*runtime| {
|
||||
for (vertex_shader.runtimes) |*runtime| {
|
||||
ExecutionDevice.writeDescriptorSets(self.state, &runtime.rt) catch return VkError.Unknown;
|
||||
}
|
||||
if (pipeline.stages.getPtr(.fragment)) |fragment_shader| {
|
||||
for (fragment_shader.runtimes[0..]) |*runtime| {
|
||||
for (fragment_shader.runtimes) |*runtime| {
|
||||
ExecutionDevice.writeDescriptorSets(self.state, &runtime.rt) catch return VkError.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.vertexShaderStage(allocator, &draw_call, vertex_count, instance_count, first_vertex, first_instance, indices, primitive_restart) catch |err| {
|
||||
std.log.scoped(.@"Vertex stage").err("catched a '{s}'", .{@errorName(err)});
|
||||
|
||||
@@ -36,6 +36,9 @@ pub fn shaderInvocation(
|
||||
inputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS]VertexInterpolationLocation,
|
||||
derivative_inputs: ?DerivativeInputs,
|
||||
) SpvRuntimeError!InvocationResult {
|
||||
if (comptime base.config.soft_ir_interpreter)
|
||||
return SpvRuntimeError.InvalidSpirV;
|
||||
|
||||
var fragment_inputs = inputs;
|
||||
errdefer freeOwnedInputs(allocator, fragment_inputs);
|
||||
|
||||
|
||||
@@ -447,7 +447,7 @@ fn rasterizeTransformedPoint(
|
||||
const point_min_x = vertex.position[0] - (point_size / 2.0);
|
||||
const point_min_y = vertex.position[1] - (point_size / 2.0);
|
||||
const pipeline = draw_call.renderer.state.pipeline orelse return;
|
||||
const has_fragment_shader = pipeline.stages.getPtr(.fragment) != null;
|
||||
const has_fragment_shader = if (comptime base.config.soft_ir_interpreter) false else pipeline.stages.getPtr(.fragment) != null;
|
||||
|
||||
var py = min_y;
|
||||
while (py <= max_y) : (py += 1) {
|
||||
|
||||
@@ -134,7 +134,12 @@ fn drawLineBresenham(
|
||||
|
||||
const pipeline = draw_call.renderer.state.pipeline orelse return;
|
||||
const fragment_stage = pipeline.stages.getPtr(.fragment);
|
||||
const runtimes_count = if (fragment_stage) |stage| stage.runtimes.len else 1;
|
||||
const runtimes_count = if (comptime base.config.soft_ir_interpreter)
|
||||
1
|
||||
else if (fragment_stage) |stage|
|
||||
stage.runtimes.len
|
||||
else
|
||||
1;
|
||||
if (runtimes_count == 0)
|
||||
return;
|
||||
|
||||
@@ -170,7 +175,7 @@ fn drawLineBresenham(
|
||||
.color_attachment_access = color_attachment_access,
|
||||
.depth_attachment_access = depth_attachment_access,
|
||||
.stencil_attachment_access = stencil_attachment_access,
|
||||
.has_fragment_shader = fragment_stage != null,
|
||||
.has_fragment_shader = if (comptime base.config.soft_ir_interpreter) false else fragment_stage != null,
|
||||
};
|
||||
|
||||
draw_call.rasterizer_wait_group.async(io, runWrapper, .{run_data});
|
||||
@@ -191,7 +196,7 @@ fn drawLineDiamond(
|
||||
) VkError!void {
|
||||
const pipeline = draw_call.renderer.state.pipeline orelse return;
|
||||
const fragment_stage = pipeline.stages.getPtr(.fragment);
|
||||
const has_fragment_shader = fragment_stage != null;
|
||||
const has_fragment_shader = if (comptime base.config.soft_ir_interpreter) false else fragment_stage != null;
|
||||
const batch_id: usize = 0;
|
||||
|
||||
const min_x: i32 = @intFromFloat(@floor(@min(v0.position[0], v1.position[0]) - 1.0));
|
||||
|
||||
@@ -89,24 +89,37 @@ pub fn drawTriangle(
|
||||
}
|
||||
|
||||
const fragment_stage = pipeline.stages.getPtr(.fragment);
|
||||
const fragment_uses_derivatives = if (fragment_stage) |stage|
|
||||
const fragment_uses_derivatives = if (comptime base.config.soft_ir_interpreter)
|
||||
false
|
||||
else if (fragment_stage) |stage|
|
||||
stage.module.module.reflection_infos.needs_derivatives
|
||||
else
|
||||
false;
|
||||
const early_fragment_tests = if (fragment_stage) |stage|
|
||||
const early_fragment_tests = if (comptime base.config.soft_ir_interpreter)
|
||||
false
|
||||
else 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 (comptime base.config.soft_ir_interpreter)
|
||||
false
|
||||
else if (fragment_stage) |stage|
|
||||
stage.module.module.builtins.get(.SampleId) != null
|
||||
else
|
||||
false;
|
||||
const fragment_uses_centroid = if (fragment_stage) |stage|
|
||||
const fragment_uses_centroid = if (comptime base.config.soft_ir_interpreter)
|
||||
false
|
||||
else if (fragment_stage) |stage|
|
||||
fragmentStageUsesInputDecoration(stage, .Centroid)
|
||||
else
|
||||
false;
|
||||
|
||||
const runtimes_count = if (fragment_stage) |stage| stage.runtimes.len else 1;
|
||||
const runtimes_count = if (comptime base.config.soft_ir_interpreter)
|
||||
1
|
||||
else if (fragment_stage) |stage|
|
||||
stage.runtimes.len
|
||||
else
|
||||
1;
|
||||
if (runtimes_count == 0)
|
||||
return;
|
||||
const sample_count = pipeline_data.multisample.rasterization_samples.toInt();
|
||||
@@ -173,7 +186,7 @@ pub fn drawTriangle(
|
||||
.depth_attachment_access = depth_attachment_access,
|
||||
.stencil_attachment_access = stencil_attachment_access,
|
||||
.front_face = front_face,
|
||||
.has_fragment_shader = fragment_stage != null,
|
||||
.has_fragment_shader = if (comptime base.config.soft_ir_interpreter) false else fragment_stage != null,
|
||||
.early_fragment_tests = early_fragment_tests,
|
||||
.fragment_uses_derivatives = fragment_uses_derivatives,
|
||||
.fragment_uses_sample_id = fragment_uses_sample_id,
|
||||
|
||||
@@ -43,14 +43,10 @@ pub fn runWrapper(data: RunData) void {
|
||||
inline fn run(data: RunData) !void {
|
||||
const shader = data.pipeline.stages.getPtrAssertContains(.vertex);
|
||||
if (comptime base.config.soft_ir_interpreter) {
|
||||
// Interpolation decorations are not represented in the common IR yet,
|
||||
// so fragment-linked graphics pipelines retain the SPIR-V path.
|
||||
if (data.pipeline.stages.getPtr(.fragment) == null) {
|
||||
if (shader.interpreter) |*interpreter_shader| {
|
||||
return ir_vertex.run(
|
||||
data.allocator,
|
||||
data.pipeline,
|
||||
interpreter_shader,
|
||||
shader,
|
||||
data.batch_id,
|
||||
data.batch_size,
|
||||
data.vertex_count,
|
||||
@@ -62,8 +58,6 @@ inline fn run(data: RunData) !void {
|
||||
data.draw_call,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
const runtime = &shader.runtimes[data.batch_id];
|
||||
const mutex = &runtime.mutex;
|
||||
const rt = &runtime.rt;
|
||||
|
||||
@@ -47,24 +47,25 @@ interfaces: []const ?InterfaceBinding,
|
||||
pub fn compile(backing_allocator: std.mem.Allocator, module: *const module_ir.Module) !Self {
|
||||
try ir.validator.validate(module);
|
||||
|
||||
var result: Self = undefined;
|
||||
result.arena = std.heap.ArenaAllocator.init(backing_allocator);
|
||||
errdefer result.arena.deinit();
|
||||
var arena = std.heap.ArenaAllocator.init(backing_allocator);
|
||||
errdefer arena.deinit();
|
||||
|
||||
var lowerer = try Lowerer.init(result.arena.allocator(), module);
|
||||
var lowerer = try Lowerer.init(arena.allocator(), module);
|
||||
try lowerer.lower();
|
||||
|
||||
result.stage = module.stage;
|
||||
result.entry_pc = lowerer.entry_pc;
|
||||
result.register_count = lowerer.register_count;
|
||||
result.scratch_count = lowerer.scratch_count;
|
||||
result.code = lowerer.code.items;
|
||||
result.edges = lowerer.edges.items;
|
||||
result.copies = lowerer.copies.items;
|
||||
result.branches = lowerer.branches.items;
|
||||
result.initializers = lowerer.initializers.items;
|
||||
result.interfaces = lowerer.interfaces;
|
||||
return result;
|
||||
return .{
|
||||
.arena = arena,
|
||||
.stage = module.stage,
|
||||
.entry_pc = lowerer.entry_pc,
|
||||
.register_count = lowerer.register_count,
|
||||
.scratch_count = lowerer.scratch_count,
|
||||
.code = lowerer.code.items,
|
||||
.edges = lowerer.edges.items,
|
||||
.copies = lowerer.copies.items,
|
||||
.branches = lowerer.branches.items,
|
||||
.initializers = lowerer.initializers.items,
|
||||
.interfaces = lowerer.interfaces,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
@@ -158,41 +159,32 @@ const Lowerer = struct {
|
||||
|
||||
fn allocate(self: *Lowerer, type_id: ids.TypeId) !bc.Span {
|
||||
const ty = self.module.types.get(type_id) orelse return CompileError.UnsupportedType;
|
||||
var kind: bc.ValueKind = undefined;
|
||||
var components: u8 = 1;
|
||||
|
||||
switch (ty.*) {
|
||||
.boolean => kind = .boolean,
|
||||
.integer => |integer| {
|
||||
if (integer.bits != 32)
|
||||
return CompileError.UnsupportedType;
|
||||
|
||||
kind = if (integer.signedness == .signed) .signed_integer else .unsigned_integer;
|
||||
},
|
||||
.floating => |floating| {
|
||||
if (floating.bits != 32)
|
||||
return CompileError.UnsupportedType;
|
||||
|
||||
kind = .floating;
|
||||
},
|
||||
.vector => |vector| {
|
||||
const kind: bc.ValueKind = switch (ty.*) {
|
||||
.boolean => .boolean,
|
||||
.integer => |integer| if (integer.bits == 32)
|
||||
if (integer.signedness == .signed) .signed_integer else .unsigned_integer
|
||||
else
|
||||
return CompileError.UnsupportedType,
|
||||
.floating => |floating| if (floating.bits == 32)
|
||||
.floating
|
||||
else
|
||||
return CompileError.UnsupportedType,
|
||||
.vector => |vector| blk: {
|
||||
const element = self.module.types.get(vector.element_type) orelse return CompileError.UnsupportedType;
|
||||
components = vector.length;
|
||||
|
||||
kind = switch (element.*) {
|
||||
break :blk switch (element.*) {
|
||||
.boolean => .boolean,
|
||||
.integer => |integer| blk: {
|
||||
if (integer.bits != 32)
|
||||
return CompileError.UnsupportedType;
|
||||
|
||||
break :blk if (integer.signedness == .signed) .signed_integer else .unsigned_integer;
|
||||
},
|
||||
.integer => |integer| if (integer.bits == 32)
|
||||
if (integer.signedness == .signed) .signed_integer else .unsigned_integer
|
||||
else
|
||||
return CompileError.UnsupportedType,
|
||||
.floating => |floating| if (floating.bits == 32) .floating else return CompileError.UnsupportedType,
|
||||
else => return CompileError.UnsupportedType,
|
||||
};
|
||||
},
|
||||
else => return CompileError.UnsupportedType,
|
||||
}
|
||||
};
|
||||
const end = std.math.add(usize, self.register_count, components) catch return CompileError.TooManyRegisters;
|
||||
|
||||
if (end > @as(usize, std.math.maxInt(bc.Register)) + 1)
|
||||
|
||||
@@ -21,17 +21,15 @@ program: Program,
|
||||
runtimes: []RuntimeSlot,
|
||||
workgroup_size: ?[3]u32,
|
||||
|
||||
/// Compiles a stage when the current interpreter can execute its complete
|
||||
/// interface. `null` deliberately selects the existing SPIR-V runtime.
|
||||
pub fn compile(
|
||||
allocator: std.mem.Allocator,
|
||||
module: *SoftShaderModule,
|
||||
stage: *const vk.PipelineShaderStageCreateInfo,
|
||||
runtime_count: usize,
|
||||
) VkError!?Self {
|
||||
const expected_stage = commonStage(stage.stage) orelse return null;
|
||||
if (expected_stage == .fragment)
|
||||
return null;
|
||||
pub fn compile(allocator: std.mem.Allocator, module: *SoftShaderModule, stage: *const vk.PipelineShaderStageCreateInfo, runtime_count: usize) VkError!Self {
|
||||
const expected_stage = commonStage(stage.stage) orelse {
|
||||
std.log.scoped(.IrInterpreter).err("unsupported shader stage", .{});
|
||||
return VkError.ValidationFailed;
|
||||
};
|
||||
if (expected_stage == .fragment) {
|
||||
std.log.scoped(.IrInterpreter).err("fragment shaders are not supported", .{});
|
||||
return VkError.ValidationFailed;
|
||||
}
|
||||
|
||||
const specializations = try specializationValues(allocator, stage.p_specialization_info);
|
||||
defer if (specializations.len != 0) allocator.free(specializations);
|
||||
@@ -43,25 +41,24 @@ pub fn compile(
|
||||
}) catch |err| {
|
||||
if (err == error.OutOfMemory)
|
||||
return VkError.OutOfDeviceMemory;
|
||||
std.log.scoped(.SoftIrInterpreter).debug("IR translation fallback: {s}", .{@errorName(err)});
|
||||
return null;
|
||||
std.log.scoped(.IrInterpreter).err("IR translation failed: {s}", .{@errorName(err)});
|
||||
return VkError.ValidationFailed;
|
||||
};
|
||||
defer module_ir.deinit();
|
||||
|
||||
var program = Program.compile(allocator, &module_ir) catch |err| {
|
||||
if (err == error.OutOfMemory)
|
||||
return VkError.OutOfDeviceMemory;
|
||||
std.log.scoped(.SoftIrInterpreter).debug("bytecode lowering fallback: {s}", .{@errorName(err)});
|
||||
return null;
|
||||
std.log.scoped(.IrInterpreter).err("bytecode lowering failed: {s}", .{@errorName(err)});
|
||||
return VkError.ValidationFailed;
|
||||
};
|
||||
errdefer program.deinit();
|
||||
|
||||
if (!hasCompatibleInterface(&program, expected_stage) or
|
||||
(expected_stage == .compute and module_ir.execution_modes.workgroup_size == null))
|
||||
{
|
||||
std.log.scoped(.SoftIrInterpreter).debug("stage interface or execution modes require the SPIR-V runtime", .{});
|
||||
program.deinit();
|
||||
return null;
|
||||
std.log.scoped(.IrInterpreter).err("unsupported stage interface or execution modes", .{});
|
||||
return VkError.ValidationFailed;
|
||||
}
|
||||
|
||||
const runtimes = allocator.alloc(RuntimeSlot, runtime_count) catch return VkError.OutOfDeviceMemory;
|
||||
@@ -76,7 +73,7 @@ pub fn compile(
|
||||
initialized += 1;
|
||||
}
|
||||
|
||||
std.log.scoped(.SoftIrInterpreter).debug("compiled {s} stage to {d} bytecode instructions", .{
|
||||
std.log.scoped(.IrInterpreter).debug("compiled {s} stage to {d} bytecode instructions", .{
|
||||
@tagName(expected_stage),
|
||||
program.code.len,
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@ const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
const shader_ir = @import("shader_ir");
|
||||
|
||||
const bc = @import("bytecode.zig");
|
||||
const Shader = @import("Shader.zig");
|
||||
const SoftPipeline = @import("../SoftPipeline.zig");
|
||||
const Renderer = @import("../device/Renderer.zig");
|
||||
@@ -58,14 +57,7 @@ pub fn run(
|
||||
}
|
||||
}
|
||||
|
||||
fn populateInputs(
|
||||
runtime: anytype,
|
||||
program: *const @import("Program.zig"),
|
||||
pipeline: *SoftPipeline,
|
||||
draw_call: *Renderer.DrawCall,
|
||||
vertex_index: u32,
|
||||
instance_index: u32,
|
||||
) VkError!void {
|
||||
fn populateInputs(runtime: anytype, program: *const @import("Program.zig"), pipeline: *SoftPipeline, draw_call: *Renderer.DrawCall, vertex_index: u32, instance_index: u32) VkError!void {
|
||||
for (program.interfaces, 0..) |optional_binding, index| {
|
||||
const binding = optional_binding orelse continue;
|
||||
if (binding.direction != .input)
|
||||
@@ -167,7 +159,3 @@ fn findBinding(bindings: []const vk.VertexInputBindingDescription, binding: u32)
|
||||
if (description.binding == binding) return description;
|
||||
return null;
|
||||
}
|
||||
|
||||
comptime {
|
||||
_ = bc;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ pub const VTable = struct {
|
||||
releasePhysicalDevices: *const fn (*Self, std.mem.Allocator) VkError!void,
|
||||
requestPhysicalDevices: *const fn (*Self, std.mem.Allocator, []lib.drm.Card) VkError!void,
|
||||
io: *const fn (*Self) std.Io,
|
||||
enumerate_drm_devices: bool = true,
|
||||
};
|
||||
|
||||
pub const DispatchTable = struct {
|
||||
@@ -154,10 +155,13 @@ pub fn releasePhysicalDevices(self: *Self, allocator: std.mem.Allocator) VkError
|
||||
}
|
||||
|
||||
pub fn requestPhysicalDevices(self: *Self, allocator: std.mem.Allocator) VkError!void {
|
||||
if (self.vtable.enumerate_drm_devices) {
|
||||
const devices = try drm.enumerateDrmPhysicalDevices(allocator, self);
|
||||
defer allocator.free(devices);
|
||||
|
||||
try self.vtable.requestPhysicalDevices(self, allocator, devices);
|
||||
} else {
|
||||
try self.vtable.requestPhysicalDevices(self, allocator, &.{});
|
||||
}
|
||||
|
||||
if (self.physical_devices.items.len == 0) {
|
||||
std.log.scoped(.vkCreateInstance).err("No VkPhysicalDevice found", .{});
|
||||
|
||||
Reference in New Issue
Block a user