diff --git a/build.zig b/build.zig index 62c094f..a110653 100644 --- a/build.zig +++ b/build.zig @@ -323,8 +323,6 @@ fn customPhi( const miclib = b.lazyDependency("miclib", .{ .target = target, .optimize = optimize, - .miclib_include = "/usr/local/include", - .miclib_libdir = "/usr/local/lib", .@"use-llvm" = use_llvm, }) orelse return error.UnresolvedDependency; diff --git a/build.zig.zon b/build.zig.zon index d93a9d0..0230448 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -32,8 +32,8 @@ // Soft dependencies .SPIRV_Interpreter = .{ - .url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#9b6f409bffdbb9105d32d73fa3c3025134b0e7f0", - .hash = "SPIRV_Interpreter-0.0.1-ajmpn_U2CQArCKl6BQ5HxvEE9bslrF21gzZVufvTHkJe", + .url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#6fbd386ce40286ca9dcf21c994ccc46814fb9b94", + .hash = "SPIRV_Interpreter-0.0.1-ajmpn0N2CQDo-XU_Lf_Xt140wvHyoxBnzapYANEOgjdH", .lazy = true, }, //.SPIRV_Interpreter = .{ @@ -44,8 +44,8 @@ // Phi dependencies .miclib = .{ - .url = "git+https://git.kbz8.me/kbz_8/miclib-zig.git#9d99ef63bf279c3f464821f8a82b0435c55d56a7", - .hash = "miclib-1.0.0-AbDwS3-6AABd_H8542J7l6p1q6asRusmQ-xdpQZ8bQ71", + .url = "git+https://git.kbz8.me/kbz_8/miclib-zig.git#f46bd2a058db7acbc9012a657f3fbe79d49c017f", + .hash = "miclib-1.0.0-AbDwSzB6AgDVMQ3muWEwaBdfYJBDgm3pJKNf2EEUnmNp", .lazy = true, }, }, diff --git a/src/ape/ApeInstance.zig b/src/ape/ApeInstance.zig index 820affd..8dd8efd 100644 --- a/src/ape/ApeInstance.zig +++ b/src/ape/ApeInstance.zig @@ -62,7 +62,7 @@ fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, _ const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); for (self.backend_instances.items) |backend| { - try appendBackendPhysicalDevices(self, allocator, backend); + appendBackendPhysicalDevices(self, allocator, backend) catch continue; } } diff --git a/src/phi/PhiInstance.zig b/src/phi/PhiInstance.zig index d55ff5f..baa8b91 100644 --- a/src/phi/PhiInstance.zig +++ b/src/phi/PhiInstance.zig @@ -60,6 +60,8 @@ fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); self.threaded.deinit(); allocator.destroy(self); + + mic.unload(); } fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, _: []base.drm.Card) VkError!void { @@ -67,6 +69,11 @@ fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, _ return; } + mic.load() catch |err| { + std.log.scoped(.MIC).err("Failed to load libmicmgmt: {s}", .{@errorName(err)}); + return VkError.InitializationFailed; + }; + var devices = mic.DeviceList.init() catch |err| { std.log.scoped(.MIC).err("Failed to create device list: {s}", .{@errorName(err)}); return VkError.InitializationFailed; diff --git a/src/phi/PhiPhysicalDevice.zig b/src/phi/PhiPhysicalDevice.zig index dc85b75..7ff4743 100644 --- a/src/phi/PhiPhysicalDevice.zig +++ b/src/phi/PhiPhysicalDevice.zig @@ -56,7 +56,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device interface.props.api_version = @bitCast(lib.VULKAN_VERSION); interface.props.driver_version = @bitCast(base.DRIVER_VERSION); - interface.props.device_type = .discrete_gpu; + interface.props.device_type = .other; @memset(interface.props.device_name[0..], 0); diff --git a/src/software/device/fragment.zig b/src/software/device/fragment.zig index 0771d5f..290fcfb 100644 --- a/src/software/device/fragment.zig +++ b/src/software/device/fragment.zig @@ -65,6 +65,13 @@ pub fn shaderInvocation( SpvRuntimeError.NotFound => {}, else => return err, }; + if (rt.getBuiltinResult(.FragCoord)) |frag_coord_word| { + const frag_x: i32 = @intFromFloat(position[0]); + const frag_y: i32 = @intFromFloat(position[1]); + 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)); + } if (point_coord) |coord| { rt.writeBuiltIn(allocator, std.mem.asBytes(&coord), .PointCoord) catch |err| switch (err) { SpvRuntimeError.NotFound => {}, diff --git a/src/software/device/rasterizer/bresenham.zig b/src/software/device/rasterizer/bresenham.zig index 23fa65a..2f2d207 100644 --- a/src/software/device/rasterizer/bresenham.zig +++ b/src/software/device/rasterizer/bresenham.zig @@ -270,6 +270,8 @@ fn diamondCoverage(a: F32x4, b: F32x4, pixel_x: i32, pixel_y: i32, include_last_ const cx = @as(f32, @floatFromInt(pixel_x)) + 0.5; const cy = @as(f32, @floatFromInt(pixel_y)) + 0.5; const clipped = clipSegmentToDiamond(a[0], a[1], b[0], b[1], cx, cy) orelse return null; + if (include_last_endpoint and a[1] == b[1] and clipped.min_t >= clipped.max_t and a[1] < cy) + return null; if (!include_last_endpoint and a[3] == 1.0 and b[3] == 1.0 and clipped.min_t <= 0.0) return null; if (!include_last_endpoint and clipped.min_t >= 1.0) diff --git a/src/software/device/rasterizer/edge_function.zig b/src/software/device/rasterizer/edge_function.zig index ec0778e..40414d0 100644 --- a/src/software/device/rasterizer/edge_function.zig +++ b/src/software/device/rasterizer/edge_function.zig @@ -348,7 +348,7 @@ inline fn run(data: RunData) !void { if (early_depth.mask == 0) continue; - const interpolation_barycentrics = if (data.fragment_uses_centroid and sample_count > 1) blk: { + const interpolation_barycentrics = if (sample_count > 1) blk: { const sample_pos = firstCoveredSamplePosition(sample_count, early_depth.mask); const centroid_p = zm.f32x4( @as(f32, @floatFromInt(x)) + sample_pos.x, diff --git a/src/software/device/vertex_dispatcher.zig b/src/software/device/vertex_dispatcher.zig index a03f278..96b7afb 100644 --- a/src/software/device/vertex_dispatcher.zig +++ b/src/software/device/vertex_dispatcher.zig @@ -192,18 +192,8 @@ fn readVertexOutput(data: RunData, output: *Renderer.Vertex, rt: *spv.Runtime, l 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; + const fragment_input_is_flat = fragmentInputHasDecoration(data, location, component, .Flat); + const fragment_input_is_noperspective = fragmentInputHasDecoration(data, location, component, .NoPerspective); if (fragment_input_is_flat or result_is_integer) return .flat; @@ -212,6 +202,125 @@ fn vertexOutputInterpolationType(data: RunData, rt: *spv.Runtime, location: usiz return .smooth; } +fn fragmentInputHasDecoration(data: RunData, location: usize, component: usize, decoration: anytype) bool { + const fragment_shader = data.pipeline.stages.getPtr(.fragment) orelse return false; + const fragment_rt = &fragment_shader.runtimes[0].rt; + + if (fragment_rt.getResultByLocationComponent(@intCast(location), @intCast(component), .input)) |input_word| { + if (fragment_rt.hasResultDecoration(input_word, decoration)) + return true; + + if (input_word < fragment_rt.results.len) { + const input = fragment_rt.results[input_word]; + if (input.variant) |variant| switch (variant) { + .AccessChain => |access_chain| { + const member_index = firstConstantAccessIndex(fragment_rt, access_chain.indexes) orelse return false; + if (interfaceMemberHasDecoration(fragment_rt, access_chain.base, member_index, decoration)) + return true; + }, + else => {}, + }; + } + } else |_| {} + + return interfaceLocationMemberHasDecoration(fragment_rt, location, decoration); +} + +fn interfaceLocationMemberHasDecoration(rt: *const spv.Runtime, location: usize, decoration: anytype) bool { + for (rt.results, 0..) |result, id| { + const variant = result.variant orelse continue; + const variable = switch (variant) { + .Variable => |v| v, + else => continue, + }; + if (variable.storage_class != .Input) + continue; + + const type_word = pointerTargetType(rt, variable.type_word) orelse continue; + const type_result = rt.results[type_word]; + const type_variant = type_result.variant orelse continue; + switch (type_variant) { + .Type => |t| switch (t) { + .Structure => { + for (type_result.decorations.items) |member_decoration| { + if (member_decoration.rtype == .Location and member_decoration.literal_1 == location) { + if (interfaceMemberHasDecoration(rt, @intCast(id), member_decoration.index, decoration)) + return true; + } + } + }, + else => {}, + }, + else => {}, + } + } + + return false; +} + +fn interfaceMemberHasDecoration(rt: *const spv.Runtime, variable_word: spv.SpvWord, member_index: spv.SpvWord, decoration: anytype) bool { + if (variable_word >= rt.results.len) + return false; + + const variable = switch (rt.results[variable_word].variant orelse return false) { + .Variable => |v| v, + else => return false, + }; + + const type_word = pointerTargetType(rt, variable.type_word) orelse return false; + const type_result = rt.results[type_word]; + const type_variant = type_result.variant orelse return false; + switch (type_variant) { + .Type => |t| switch (t) { + .Structure => { + for (type_result.decorations.items) |member_decoration| { + if (member_decoration.index == member_index and member_decoration.rtype == decoration) + return true; + } + }, + else => {}, + }, + else => {}, + } + + return false; +} + +fn pointerTargetType(rt: *const spv.Runtime, type_word: spv.SpvWord) ?spv.SpvWord { + if (type_word >= rt.results.len) + return null; + + const type_variant = rt.results[type_word].variant orelse return null; + return switch (type_variant) { + .Type => |t| switch (t) { + .Pointer => |ptr| ptr.target, + else => type_word, + }, + else => null, + }; +} + +fn firstConstantAccessIndex(rt: *const spv.Runtime, indexes: []const spv.SpvWord) ?spv.SpvWord { + if (indexes.len == 0) + return null; + + const index_word = indexes[0]; + if (index_word >= rt.results.len) + return null; + + const value = rt.results[index_word].getConstValue() catch return null; + return switch (value.*) { + .Int => |int| switch (int.bit_count) { + 8 => if (int.is_signed) @intCast(int.value.sint8) else @intCast(int.value.uint8), + 16 => if (int.is_signed) @intCast(int.value.sint16) else @intCast(int.value.uint16), + 32 => if (int.is_signed) @intCast(int.value.sint32) else @intCast(int.value.uint32), + 64 => if (int.is_signed) @intCast(int.value.sint64) else @intCast(int.value.uint64), + else => null, + }, + else => null, + }; +} + fn findBindingDescription(binding_descriptions: []const vk.VertexInputBindingDescription, binding: u32) ?vk.VertexInputBindingDescription { for (binding_descriptions) |description| { if (description.binding == binding)