adding pipeline dynamic state and vertex output interpollation
This commit is contained in:
@@ -61,7 +61,7 @@ vkCmdCopyImageToBuffer | ✅ Implemented
|
|||||||
vkCmdCopyQueryPoolResults | ⚙️ WIP
|
vkCmdCopyQueryPoolResults | ⚙️ WIP
|
||||||
vkCmdDispatch | ✅ Implemented
|
vkCmdDispatch | ✅ Implemented
|
||||||
vkCmdDispatchIndirect | ✅ Implemented
|
vkCmdDispatchIndirect | ✅ Implemented
|
||||||
vkCmdDraw | ⚙️ WIP
|
vkCmdDraw | ✅ Implemented
|
||||||
vkCmdDrawIndexed | ⚙️ WIP
|
vkCmdDrawIndexed | ⚙️ WIP
|
||||||
vkCmdDrawIndexedIndirect | ⚙️ WIP
|
vkCmdDrawIndexedIndirect | ⚙️ WIP
|
||||||
vkCmdDrawIndirect | ⚙️ WIP
|
vkCmdDrawIndirect | ⚙️ WIP
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const ImplementationDesc = struct {
|
|||||||
name: []const u8,
|
name: []const u8,
|
||||||
root_source_file: []const u8,
|
root_source_file: []const u8,
|
||||||
vulkan_version: std.SemanticVersion,
|
vulkan_version: std.SemanticVersion,
|
||||||
custom: ?*const fn (*std.Build, *std.Build.Step.Compile, *std.Build.Step.Options) anyerror!void = null,
|
custom: ?*const fn (*std.Build, *std.Build.Step.Compile, *std.Build.Step.Options, bool) anyerror!void = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const implementations = [_]ImplementationDesc{
|
const implementations = [_]ImplementationDesc{
|
||||||
@@ -76,7 +76,7 @@ pub fn build(b: *std.Build) !void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (impl.custom) |custom| {
|
if (impl.custom) |custom| {
|
||||||
custom(b, lib, options) catch continue;
|
custom(b, lib, options, use_llvm) catch continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const icd_file = b.addWriteFile(
|
const icd_file = b.addWriteFile(
|
||||||
@@ -143,7 +143,7 @@ pub fn build(b: *std.Build) !void {
|
|||||||
docs_step.dependOn(&install_docs.step);
|
docs_step.dependOn(&install_docs.step);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn customSoft(b: *std.Build, lib: *std.Build.Step.Compile, options: *std.Build.Step.Options) !void {
|
fn customSoft(b: *std.Build, lib: *std.Build.Step.Compile, options: *std.Build.Step.Options, use_llvm: bool) !void {
|
||||||
const cpuinfo = b.lazyDependency("cpuinfo", .{}) orelse return error.UnresolvedDependency;
|
const cpuinfo = b.lazyDependency("cpuinfo", .{}) orelse return error.UnresolvedDependency;
|
||||||
lib.root_module.addSystemIncludePath(cpuinfo.path("include"));
|
lib.root_module.addSystemIncludePath(cpuinfo.path("include"));
|
||||||
lib.root_module.linkLibrary(cpuinfo.artifact("cpuinfo"));
|
lib.root_module.linkLibrary(cpuinfo.artifact("cpuinfo"));
|
||||||
@@ -151,7 +151,7 @@ fn customSoft(b: *std.Build, lib: *std.Build.Step.Compile, options: *std.Build.S
|
|||||||
const spv = b.lazyDependency("SPIRV_Interpreter", .{
|
const spv = b.lazyDependency("SPIRV_Interpreter", .{
|
||||||
.@"no-example" = true,
|
.@"no-example" = true,
|
||||||
.@"no-test" = true,
|
.@"no-test" = true,
|
||||||
.@"use-llvm" = true,
|
.@"use-llvm" = use_llvm,
|
||||||
}) orelse return error.UnresolvedDependency;
|
}) orelse return error.UnresolvedDependency;
|
||||||
lib.root_module.addImport("spv", spv.module("spv"));
|
lib.root_module.addImport("spv", spv.module("spv"));
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -31,10 +31,14 @@
|
|||||||
.hash = "zmath-0.11.0-dev-wjwivdMsAwD-xaLj76YHUq3t9JDH-X16xuMTmnDzqbu2",
|
.hash = "zmath-0.11.0-dev-wjwivdMsAwD-xaLj76YHUq3t9JDH-X16xuMTmnDzqbu2",
|
||||||
},
|
},
|
||||||
.SPIRV_Interpreter = .{
|
.SPIRV_Interpreter = .{
|
||||||
.url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#5b7380eea014dce11587597d44681640a3a3583b",
|
.url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#9cdb683f3f24cf82774f1bf31b8c51d3863a9cfe",
|
||||||
.hash = "SPIRV_Interpreter-0.0.1-ajmpnwaZBAA5PJz7wTcWkWPywJAJF672vYjuCZKO4t9j",
|
.hash = "SPIRV_Interpreter-0.0.1-ajmpn1SyBAC5RYKryNkL2llgGFKcLPFGhCmxcraJ2eSL",
|
||||||
.lazy = true,
|
.lazy = true,
|
||||||
},
|
},
|
||||||
|
//.SPIRV_Interpreter = .{
|
||||||
|
// .path = "../SPIRV-Interpreter",
|
||||||
|
// .lazy = true,
|
||||||
|
//},
|
||||||
},
|
},
|
||||||
|
|
||||||
.paths = .{
|
.paths = .{
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
|
|||||||
.reset = reset,
|
.reset = reset,
|
||||||
.resetEvent = resetEvent,
|
.resetEvent = resetEvent,
|
||||||
.setEvent = setEvent,
|
.setEvent = setEvent,
|
||||||
|
.setViewport = setViewport,
|
||||||
.waitEvents = waitEvents,
|
.waitEvents = waitEvents,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -621,6 +622,31 @@ pub fn setEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineSta
|
|||||||
_ = stage;
|
_ = stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setViewport(interface: *Interface, first: u32, viewports: []const vk.Viewport) VkError!void {
|
||||||
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||||
|
const allocator = self.command_allocator.allocator();
|
||||||
|
|
||||||
|
const CommandImpl = struct {
|
||||||
|
const Impl = @This();
|
||||||
|
|
||||||
|
first: u32,
|
||||||
|
viewports: []const vk.Viewport,
|
||||||
|
|
||||||
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
||||||
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
||||||
|
device.renderer.dynamic_state.viewports = impl.viewports; // Unsafe
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
||||||
|
errdefer allocator.destroy(cmd);
|
||||||
|
cmd.* = .{
|
||||||
|
.first = first,
|
||||||
|
.viewports = allocator.dupe(vk.Viewport, viewports) catch return VkError.OutOfHostMemory, // Will be freed on cmdbuf reset or destroy
|
||||||
|
};
|
||||||
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn waitEvents(interface: *Interface, events: []*const base.Event, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void {
|
pub fn waitEvents(interface: *Interface, events: []*const base.Event, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void {
|
||||||
// No-op
|
// No-op
|
||||||
_ = interface;
|
_ = interface;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const vk = @import("vulkan");
|
|||||||
const base = @import("base");
|
const base = @import("base");
|
||||||
const zm = base.zm;
|
const zm = base.zm;
|
||||||
const lib = @import("../lib.zig");
|
const lib = @import("../lib.zig");
|
||||||
|
const spv = @import("spv");
|
||||||
|
|
||||||
pub const F32x4 = zm.F32x4;
|
pub const F32x4 = zm.F32x4;
|
||||||
|
|
||||||
@@ -32,18 +33,24 @@ pub const VertexBuffer = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const DynamicState = struct {
|
pub const DynamicState = struct {
|
||||||
viewport: vk.Viewport,
|
viewports: ?[]const vk.Viewport,
|
||||||
scissor: vk.Rect2D,
|
scissor: ?[]vk.Rect2D,
|
||||||
line_width: f32,
|
line_width: ?f32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Vertex = struct {
|
||||||
|
position: F32x4,
|
||||||
|
outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS]?[]u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Fragment = struct {
|
pub const Fragment = struct {
|
||||||
position: F32x4,
|
position: F32x4,
|
||||||
color: F32x4,
|
color: F32x4,
|
||||||
|
inputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][]u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const DrawCall = struct {
|
pub const DrawCall = struct {
|
||||||
vertices: []F32x4,
|
vertices: []Vertex,
|
||||||
fragments: []Fragment,
|
fragments: []Fragment,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -60,11 +67,17 @@ pub fn init(device: *SoftDevice, state: *PipelineState) Self {
|
|||||||
.state = state,
|
.state = state,
|
||||||
.render_pass = null,
|
.render_pass = null,
|
||||||
.framebuffer = null,
|
.framebuffer = null,
|
||||||
.dynamic_state = undefined,
|
.dynamic_state = .{
|
||||||
|
.viewports = null,
|
||||||
|
.scissor = null,
|
||||||
|
.line_width = null,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
const io = self.device.interface.io();
|
||||||
|
|
||||||
const render_target_view: *base.ImageView = (self.framebuffer orelse return).interface.attachments[0];
|
const render_target_view: *base.ImageView = (self.framebuffer orelse return).interface.attachments[0];
|
||||||
const render_target: *SoftImage = @alignCast(@fieldParentPtr("interface", render_target_view.image));
|
const render_target: *SoftImage = @alignCast(@fieldParentPtr("interface", render_target_view.image));
|
||||||
const render_target_memory = if (render_target.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv;
|
const render_target_memory = if (render_target.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv;
|
||||||
@@ -73,20 +86,32 @@ pub fn draw(self: *Self, vertex_count: usize, instance_count: usize, first_verte
|
|||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const allocator = arena.allocator();
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
|
const timer = std.Io.Timestamp.now(io, .real);
|
||||||
|
defer if (comptime base.config.logs) {
|
||||||
|
const duration = timer.untilNow(io, .real);
|
||||||
|
const ms = duration.toMicroseconds();
|
||||||
|
std.log.scoped(.SoftwareRenderer).debug("Drawcall stats:\n> Took {d}us\n> Allocated {d} KB", .{ ms, @divTrunc(arena.queryCapacity(), 1000) });
|
||||||
|
};
|
||||||
|
|
||||||
var draw_call: DrawCall = .{
|
var draw_call: DrawCall = .{
|
||||||
.vertices = allocator.alloc(F32x4, vertex_count * instance_count) catch return VkError.OutOfDeviceMemory,
|
.vertices = allocator.alloc(Vertex, vertex_count * instance_count) catch return VkError.OutOfDeviceMemory,
|
||||||
.fragments = undefined,
|
.fragments = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.vertexShaderStage(&draw_call, vertex_count, instance_count) catch |err| {
|
for (draw_call.vertices) |*vertex| {
|
||||||
|
vertex.outputs = [_]?[]u8{null} ** spv.SPIRV_MAX_OUTPUT_LOCATIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.vertexShaderStage(allocator, &draw_call, vertex_count, instance_count) catch |err| {
|
||||||
std.log.scoped(.@"Vertex stage").err("catched a '{s}'", .{@errorName(err)});
|
std.log.scoped(.@"Vertex stage").err("catched a '{s}'", .{@errorName(err)});
|
||||||
if (@errorReturnTrace()) |trace| {
|
if (@errorReturnTrace()) |trace| {
|
||||||
std.debug.dumpErrorReturnTrace(trace);
|
std.debug.dumpErrorReturnTrace(trace);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.primitiveAssemblyStage(&draw_call);
|
try self.primitiveAssemblyStage(&draw_call);
|
||||||
try self.rasterizationStage(allocator, &draw_call);
|
try self.rasterizationStage(allocator, &draw_call);
|
||||||
|
|
||||||
self.fragmentShaderStage(&draw_call) catch |err| {
|
self.fragmentShaderStage(&draw_call) catch |err| {
|
||||||
std.log.scoped(.@"Fragment stage").err("catched a '{s}'", .{@errorName(err)});
|
std.log.scoped(.@"Fragment stage").err("catched a '{s}'", .{@errorName(err)});
|
||||||
if (@errorReturnTrace()) |trace| {
|
if (@errorReturnTrace()) |trace| {
|
||||||
@@ -121,7 +146,7 @@ pub fn deinit(self: *Self) void {
|
|||||||
_ = self;
|
_ = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vertexShaderStage(self: *Self, draw_call: *DrawCall, vertex_count: usize, instance_count: usize) !void {
|
fn vertexShaderStage(self: *Self, allocator: std.mem.Allocator, draw_call: *DrawCall, vertex_count: usize, instance_count: usize) !void {
|
||||||
const pipeline = self.state.pipeline orelse return;
|
const pipeline = self.state.pipeline orelse return;
|
||||||
const batch_size = (pipeline.stages.getPtr(.vertex) orelse return).runtimes.len;
|
const batch_size = (pipeline.stages.getPtr(.vertex) orelse return).runtimes.len;
|
||||||
|
|
||||||
@@ -129,6 +154,7 @@ fn vertexShaderStage(self: *Self, draw_call: *DrawCall, vertex_count: usize, ins
|
|||||||
for (0..instance_count) |instance_index| {
|
for (0..instance_count) |instance_index| {
|
||||||
for (0..@min(batch_size, vertex_count)) |batch_id| {
|
for (0..@min(batch_size, vertex_count)) |batch_id| {
|
||||||
const run_data: vertex_dispatcher.RunData = .{
|
const run_data: vertex_dispatcher.RunData = .{
|
||||||
|
.allocator = allocator,
|
||||||
.renderer = self,
|
.renderer = self,
|
||||||
.pipeline = pipeline,
|
.pipeline = pipeline,
|
||||||
.batch_id = batch_id,
|
.batch_id = batch_id,
|
||||||
@@ -144,14 +170,23 @@ fn vertexShaderStage(self: *Self, draw_call: *DrawCall, vertex_count: usize, ins
|
|||||||
wg.await(self.device.interface.io()) catch return VkError.DeviceLost;
|
wg.await(self.device.interface.io()) catch return VkError.DeviceLost;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primitiveAssemblyStage(self: *Self, draw_call: *DrawCall) void {
|
fn primitiveAssemblyStage(self: *Self, draw_call: *DrawCall) VkError!void {
|
||||||
const viewport = (self.state.pipeline orelse return).interface.mode.graphics.viewport_state.viewports[0];
|
const viewport = blk: {
|
||||||
|
const pipeline_data = &(self.state.pipeline orelse return VkError.InvalidPipelineDrv).interface.mode.graphics;
|
||||||
|
if (pipeline_data.dynamic_state.viewport) {
|
||||||
|
if (self.dynamic_state.viewports) |viewports|
|
||||||
|
break :blk viewports[0];
|
||||||
|
}
|
||||||
|
if (pipeline_data.viewport_state.viewports) |viewports|
|
||||||
|
break :blk viewports[0];
|
||||||
|
return VkError.Unknown;
|
||||||
|
};
|
||||||
|
|
||||||
for (draw_call.vertices) |*vertex| {
|
for (draw_call.vertices) |*vertex| {
|
||||||
const x = vertex[0];
|
const x = vertex.position[0];
|
||||||
const y = vertex[1];
|
const y = vertex.position[1];
|
||||||
const z = vertex[2];
|
const z = vertex.position[2];
|
||||||
const w = vertex[3];
|
const w = vertex.position[3];
|
||||||
|
|
||||||
// Perspective division.
|
// Perspective division.
|
||||||
const x_ndc = x / w;
|
const x_ndc = x / w;
|
||||||
@@ -170,7 +205,7 @@ fn primitiveAssemblyStage(self: *Self, draw_call: *DrawCall) void {
|
|||||||
const y_screen = ((p_y / 2.0) * y_ndc) + o_y;
|
const y_screen = ((p_y / 2.0) * y_ndc) + o_y;
|
||||||
const z_screen = (p_z * z_ndc) + o_z;
|
const z_screen = (p_z * z_ndc) + o_z;
|
||||||
|
|
||||||
vertex.* = zm.f32x4(x_screen, y_screen, z_screen, 1.0);
|
vertex.position = zm.f32x4(x_screen, y_screen, z_screen, 1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,9 +217,9 @@ fn rasterizationStage(self: *Self, allocator: std.mem.Allocator, draw_call: *Dra
|
|||||||
switch (topology) {
|
switch (topology) {
|
||||||
.triangle_list => for (0..@divExact(draw_call.vertices.len, 3)) |triangle_index| {
|
.triangle_list => for (0..@divExact(draw_call.vertices.len, 3)) |triangle_index| {
|
||||||
const first_vertex = triangle_index * 3;
|
const first_vertex = triangle_index * 3;
|
||||||
const v0 = draw_call.vertices[first_vertex + 0];
|
const v0 = &draw_call.vertices[first_vertex + 0];
|
||||||
const v1 = draw_call.vertices[first_vertex + 1];
|
const v1 = &draw_call.vertices[first_vertex + 1];
|
||||||
const v2 = draw_call.vertices[first_vertex + 2];
|
const v2 = &draw_call.vertices[first_vertex + 2];
|
||||||
|
|
||||||
switch (pipeline_data.rasterization.polygon_mode) {
|
switch (pipeline_data.rasterization.polygon_mode) {
|
||||||
.fill => try rasterizer.drawTriangleFilled(allocator, &fragments, v0, v1, v2),
|
.fill => try rasterizer.drawTriangleFilled(allocator, &fragments, v0, v1, v2),
|
||||||
|
|||||||
@@ -41,6 +41,18 @@ inline fn run(data: RunData) !void {
|
|||||||
|
|
||||||
var invocation_index: usize = data.batch_id;
|
var invocation_index: usize = data.batch_id;
|
||||||
while (invocation_index < data.fragment_count) : (invocation_index += data.batch_size) {
|
while (invocation_index < data.fragment_count) : (invocation_index += data.batch_size) {
|
||||||
|
const fragment: *Renderer.Fragment = &data.draw_call.fragments[invocation_index];
|
||||||
|
|
||||||
|
for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| {
|
||||||
|
const result_word = rt.getResultByLocation(@intCast(location), .input) catch |err| switch (err) {
|
||||||
|
SpvRuntimeError.NotFound => continue,
|
||||||
|
else => return err,
|
||||||
|
};
|
||||||
|
if (result_word != 0) {
|
||||||
|
try rt.writeInput(fragment.inputs[location], result_word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rt.callEntryPoint(allocator, entry) catch |err| switch (err) {
|
rt.callEntryPoint(allocator, entry) catch |err| switch (err) {
|
||||||
// Some errors can be safely ignored
|
// Some errors can be safely ignored
|
||||||
SpvRuntimeError.OutOfBounds,
|
SpvRuntimeError.OutOfBounds,
|
||||||
@@ -49,8 +61,7 @@ inline fn run(data: RunData) !void {
|
|||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
|
|
||||||
const output: *F32x4 = &data.draw_call.fragments[invocation_index].color;
|
try rt.readOutput(std.mem.asBytes(&fragment.color), output_result);
|
||||||
try rt.readOutput(std.mem.asBytes(output), output_result);
|
fragment.color = std.math.clamp(fragment.color, zm.f32x4s(0.0), zm.f32x4s(1.0));
|
||||||
output.* = std.math.clamp(output.*, zm.f32x4s(0.0), zm.f32x4s(1.0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,76 @@ const VkError = base.VkError;
|
|||||||
const lib = @import("../lib.zig");
|
const lib = @import("../lib.zig");
|
||||||
|
|
||||||
const Renderer = @import("Renderer.zig");
|
const Renderer = @import("Renderer.zig");
|
||||||
|
const spv = @import("spv");
|
||||||
|
|
||||||
pub const F32x4 = zm.F32x4;
|
pub const F32x4 = zm.F32x4;
|
||||||
|
|
||||||
pub fn drawLineBresenham(allocator: std.mem.Allocator, fragments: *std.ArrayList(Renderer.Fragment), v0: F32x4, v1: F32x4) VkError!void {
|
fn writePacked(comptime T: type, bytes: []u8, value: T) void {
|
||||||
var x0: i32 = @intFromFloat(v0[0]);
|
const raw: [@sizeOf(T)]u8 = @bitCast(value);
|
||||||
var y0: i32 = @intFromFloat(v0[1]);
|
@memcpy(bytes[0..@sizeOf(T)], raw[0..]);
|
||||||
var x1: i32 = @intFromFloat(v1[0]);
|
}
|
||||||
var y1: i32 = @intFromFloat(v1[1]);
|
|
||||||
|
fn interpolateF32x4(value0: F32x4, value1: F32x4, value2: F32x4, b0: f32, b1: f32, b2: f32) F32x4 {
|
||||||
|
return (value0 * @as(F32x4, @splat(b0))) + (value1 * @as(F32x4, @splat(b1))) + (value2 * @as(F32x4, @splat(b2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interpolateVertexOutputs(
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
v0: *const Renderer.Vertex,
|
||||||
|
v1: *const Renderer.Vertex,
|
||||||
|
v2: *const Renderer.Vertex,
|
||||||
|
b0: f32,
|
||||||
|
b1: f32,
|
||||||
|
b2: f32,
|
||||||
|
) VkError![spv.SPIRV_MAX_OUTPUT_LOCATIONS][]u8 {
|
||||||
|
var inputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][]u8 = undefined;
|
||||||
|
|
||||||
|
for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| {
|
||||||
|
const out0 = v0.outputs[location] orelse continue;
|
||||||
|
const out1 = v1.outputs[location] orelse continue;
|
||||||
|
const out2 = v2.outputs[location] orelse continue;
|
||||||
|
|
||||||
|
if (out0.len == 0) {
|
||||||
|
inputs[location] = out0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const len = @min(out0.len, out1.len, out2.len);
|
||||||
|
const input = allocator.alloc(u8, len) catch return VkError.OutOfDeviceMemory;
|
||||||
|
|
||||||
|
var byte_index: usize = 0;
|
||||||
|
while (byte_index + @sizeOf(F32x4) <= len) : (byte_index += @sizeOf(F32x4)) {
|
||||||
|
const value0 = std.mem.bytesToValue(F32x4, out0[byte_index..]);
|
||||||
|
const value1 = std.mem.bytesToValue(F32x4, out1[byte_index..]);
|
||||||
|
const value2 = std.mem.bytesToValue(F32x4, out2[byte_index..]);
|
||||||
|
writePacked(F32x4, input[byte_index..], interpolateF32x4(value0, value1, value2, b0, b1, b2));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (byte_index + @sizeOf(f32) <= len) : (byte_index += @sizeOf(f32)) {
|
||||||
|
const value0 = std.mem.bytesToValue(f32, out0[byte_index..]);
|
||||||
|
const value1 = std.mem.bytesToValue(f32, out1[byte_index..]);
|
||||||
|
const value2 = std.mem.bytesToValue(f32, out2[byte_index..]);
|
||||||
|
writePacked(f32, input[byte_index..], (value0 * b0) + (value1 * b1) + (value2 * b2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte_index < len)
|
||||||
|
@memcpy(input[byte_index..], out0[byte_index..len]);
|
||||||
|
|
||||||
|
inputs[location] = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interpolateLineOutputs(allocator: std.mem.Allocator, v0: *const Renderer.Vertex, v1: *const Renderer.Vertex, t: f32) VkError![spv.SPIRV_MAX_OUTPUT_LOCATIONS][]u8 {
|
||||||
|
return interpolateVertexOutputs(allocator, v0, v1, v0, 1.0 - t, t, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawLineBresenham(allocator: std.mem.Allocator, fragments: *std.ArrayList(Renderer.Fragment), v0: *Renderer.Vertex, v1: *Renderer.Vertex) VkError!void {
|
||||||
|
var x0: i32 = @intFromFloat(v0.position[0]);
|
||||||
|
var y0: i32 = @intFromFloat(v0.position[1]);
|
||||||
|
var x1: i32 = @intFromFloat(v1.position[0]);
|
||||||
|
var y1: i32 = @intFromFloat(v1.position[1]);
|
||||||
|
|
||||||
const steep = blk: {
|
const steep = blk: {
|
||||||
if (@abs(y1 - y0) > @abs(x1 - x0)) {
|
if (@abs(y1 - y0) > @abs(x1 - x0)) {
|
||||||
@@ -26,9 +88,12 @@ pub fn drawLineBresenham(allocator: std.mem.Allocator, fragments: *std.ArrayList
|
|||||||
break :blk false;
|
break :blk false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var start_vertex = v0;
|
||||||
|
var end_vertex = v1;
|
||||||
if (x0 > x1) {
|
if (x0 > x1) {
|
||||||
std.mem.swap(i32, &x0, &x1);
|
std.mem.swap(i32, &x0, &x1);
|
||||||
std.mem.swap(i32, &y0, &y1);
|
std.mem.swap(i32, &y0, &y1);
|
||||||
|
std.mem.swap(*Renderer.Vertex, &start_vertex, &end_vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
const d_err = @abs(y1 - y0);
|
const d_err = @abs(y1 - y0);
|
||||||
@@ -42,10 +107,14 @@ pub fn drawLineBresenham(allocator: std.mem.Allocator, fragments: *std.ArrayList
|
|||||||
while (x <= x1) : (x += 1) {
|
while (x <= x1) : (x += 1) {
|
||||||
const x_fragment: f32 = @floatFromInt(if (steep) y else x);
|
const x_fragment: f32 = @floatFromInt(if (steep) y else x);
|
||||||
const y_fragment: f32 = @floatFromInt(if (steep) x else y);
|
const y_fragment: f32 = @floatFromInt(if (steep) x else y);
|
||||||
|
const t = @as(f32, @floatFromInt(x - x0)) / @as(f32, @floatFromInt(@max(d_x, 1)));
|
||||||
|
|
||||||
|
const z = ((1.0 - t) * start_vertex.position[2]) + (t * end_vertex.position[2]);
|
||||||
|
|
||||||
fragments.append(allocator, .{
|
fragments.append(allocator, .{
|
||||||
.position = zm.f32x4(x_fragment, y_fragment, 0.0, 1.0),
|
.position = zm.f32x4(x_fragment, y_fragment, z, 1.0),
|
||||||
.color = zm.f32x4(1.0, 1.0, 1.0, 1.0),
|
.color = zm.f32x4(1.0, 1.0, 1.0, 1.0),
|
||||||
|
.inputs = try interpolateLineOutputs(allocator, start_vertex, end_vertex, t),
|
||||||
}) catch return VkError.OutOfDeviceMemory;
|
}) catch return VkError.OutOfDeviceMemory;
|
||||||
|
|
||||||
err -= @intCast(d_err);
|
err -= @intCast(d_err);
|
||||||
@@ -60,14 +129,15 @@ fn edgeFunction(a: F32x4, b: F32x4, p: F32x4) f32 {
|
|||||||
return ((p[0] - a[0]) * (b[1] - a[1])) - ((p[1] - a[1]) * (b[0] - a[0]));
|
return ((p[0] - a[0]) * (b[1] - a[1])) - ((p[1] - a[1]) * (b[0] - a[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawTriangleFilled(allocator: std.mem.Allocator, fragments: *std.ArrayList(Renderer.Fragment), v0: F32x4, v1: F32x4, v2: F32x4) VkError!void {
|
pub fn drawTriangleFilled(allocator: std.mem.Allocator, fragments: *std.ArrayList(Renderer.Fragment), v0: *Renderer.Vertex, v1: *Renderer.Vertex, v2: *Renderer.Vertex) VkError!void {
|
||||||
const min_x: i32 = @intFromFloat(@floor(@min(v0[0], @min(v1[0], v2[0]))));
|
const min_x: i32 = @intFromFloat(@floor(@min(v0.position[0], v1.position[0], v2.position[0])));
|
||||||
const max_x: i32 = @intFromFloat(@ceil(@max(v0[0], @max(v1[0], v2[0]))));
|
const max_x: i32 = @intFromFloat(@ceil(@max(v0.position[0], v1.position[0], v2.position[0])));
|
||||||
const min_y: i32 = @intFromFloat(@floor(@min(v0[1], @min(v1[1], v2[1]))));
|
const min_y: i32 = @intFromFloat(@floor(@min(v0.position[1], v1.position[1], v2.position[1])));
|
||||||
const max_y: i32 = @intFromFloat(@ceil(@max(v0[1], @max(v1[1], v2[1]))));
|
const max_y: i32 = @intFromFloat(@ceil(@max(v0.position[1], v1.position[1], v2.position[1])));
|
||||||
|
|
||||||
const area = edgeFunction(v0, v1, v2);
|
const area = edgeFunction(v0.position, v1.position, v2.position);
|
||||||
if (area == 0.0) return;
|
if (area == 0.0)
|
||||||
|
return;
|
||||||
|
|
||||||
var y = min_y;
|
var y = min_y;
|
||||||
while (y <= max_y) : (y += 1) {
|
while (y <= max_y) : (y += 1) {
|
||||||
@@ -75,25 +145,27 @@ pub fn drawTriangleFilled(allocator: std.mem.Allocator, fragments: *std.ArrayLis
|
|||||||
while (x <= max_x) : (x += 1) {
|
while (x <= max_x) : (x += 1) {
|
||||||
const p = zm.f32x4(@as(f32, @floatFromInt(x)) + 0.5, @as(f32, @floatFromInt(y)) + 0.5, 0.0, 1.0);
|
const p = zm.f32x4(@as(f32, @floatFromInt(x)) + 0.5, @as(f32, @floatFromInt(y)) + 0.5, 0.0, 1.0);
|
||||||
|
|
||||||
const w0 = edgeFunction(v1, v2, p);
|
const w0 = edgeFunction(v1.position, v2.position, p);
|
||||||
const w1 = edgeFunction(v2, v0, p);
|
const w1 = edgeFunction(v2.position, v0.position, p);
|
||||||
const w2 = edgeFunction(v0, v1, p);
|
const w2 = edgeFunction(v0.position, v1.position, p);
|
||||||
|
|
||||||
const inside = if (area > 0.0)
|
const inside = if (area > 0.0)
|
||||||
w0 >= 0.0 and w1 >= 0.0 and w2 >= 0.0
|
w0 >= 0.0 and w1 >= 0.0 and w2 >= 0.0
|
||||||
else
|
else
|
||||||
w0 <= 0.0 and w1 <= 0.0 and w2 <= 0.0;
|
w0 <= 0.0 and w1 <= 0.0 and w2 <= 0.0;
|
||||||
|
|
||||||
if (!inside) continue;
|
if (!inside)
|
||||||
|
continue;
|
||||||
|
|
||||||
const b0 = w0 / area;
|
const b0 = w0 / area;
|
||||||
const b1 = w1 / area;
|
const b1 = w1 / area;
|
||||||
const b2 = w2 / area;
|
const b2 = w2 / area;
|
||||||
const z = (b0 * v0[2]) + (b1 * v1[2]) + (b2 * v2[2]);
|
const z = (b0 * v0.position[2]) + (b1 * v1.position[2]) + (b2 * v2.position[2]);
|
||||||
|
|
||||||
fragments.append(allocator, .{
|
fragments.append(allocator, .{
|
||||||
.position = zm.f32x4(@floatFromInt(x), @floatFromInt(y), z, 1.0),
|
.position = zm.f32x4(@floatFromInt(x), @floatFromInt(y), z, 1.0),
|
||||||
.color = zm.f32x4(1.0, 1.0, 1.0, 1.0),
|
.color = zm.f32x4(1.0, 1.0, 1.0, 1.0),
|
||||||
|
.inputs = try interpolateVertexOutputs(allocator, v0, v1, v2, b0, b1, b2),
|
||||||
}) catch return VkError.OutOfDeviceMemory;
|
}) catch return VkError.OutOfDeviceMemory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const SoftPipeline = @import("../SoftPipeline.zig");
|
|||||||
const VkError = base.VkError;
|
const VkError = base.VkError;
|
||||||
|
|
||||||
pub const RunData = struct {
|
pub const RunData = struct {
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
renderer: *Renderer,
|
renderer: *Renderer,
|
||||||
pipeline: *SoftPipeline,
|
pipeline: *SoftPipeline,
|
||||||
batch_id: usize,
|
batch_id: usize,
|
||||||
@@ -45,20 +46,22 @@ inline fn run(data: RunData) !void {
|
|||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (data.pipeline.interface.mode.graphics.input_assembly.attribute_description orelse return) |attribute| {
|
if (data.pipeline.interface.mode.graphics.input_assembly.attribute_description) |attributes| {
|
||||||
const location_result = try rt.getResultByLocation(attribute.location, .input);
|
for (attributes) |attribute| {
|
||||||
|
const location_result = try rt.getResultByLocation(attribute.location, .input);
|
||||||
|
|
||||||
const binding_info = (data.pipeline.interface.mode.graphics.input_assembly.binding_description orelse return)[attribute.binding];
|
const binding_info = (data.pipeline.interface.mode.graphics.input_assembly.binding_description orelse return)[attribute.binding];
|
||||||
|
|
||||||
const vertex_buffer = data.renderer.state.data.graphics.vertex_buffers[attribute.binding];
|
const vertex_buffer = data.renderer.state.data.graphics.vertex_buffers[attribute.binding];
|
||||||
const buffer = vertex_buffer.buffer;
|
const buffer = vertex_buffer.buffer;
|
||||||
const buffer_memory_size = base.format.texelSize(attribute.format);
|
const buffer_memory_size = base.format.texelSize(attribute.format);
|
||||||
const buffer_memory = if (buffer.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv;
|
const buffer_memory = if (buffer.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv;
|
||||||
const offset = buffer.interface.offset + (binding_info.stride * invocation_index) + attribute.offset;
|
const offset = buffer.interface.offset + (binding_info.stride * invocation_index) + attribute.offset;
|
||||||
|
|
||||||
const buffer_memory_map: []u8 = @as([*]u8, @ptrCast(@alignCast(try buffer_memory.map(offset, buffer_memory_size))))[0..buffer_memory_size];
|
const buffer_memory_map: []u8 = @as([*]u8, @ptrCast(@alignCast(try buffer_memory.map(offset, buffer_memory_size))))[0..buffer_memory_size];
|
||||||
|
|
||||||
try rt.writeInput(buffer_memory_map, location_result);
|
try rt.writeInput(buffer_memory_map, location_result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.callEntryPoint(allocator, entry) catch |err| switch (err) {
|
rt.callEntryPoint(allocator, entry) catch |err| switch (err) {
|
||||||
@@ -69,8 +72,21 @@ inline fn run(data: RunData) !void {
|
|||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
|
|
||||||
const output: *F32x4 = &data.draw_call.vertices[(data.instance_index * data.vertex_count) + invocation_index];
|
const output: *Renderer.Vertex = &data.draw_call.vertices[(data.instance_index * data.vertex_count) + invocation_index];
|
||||||
try rt.readBuiltIn(std.mem.asBytes(output), .Position);
|
try rt.readBuiltIn(std.mem.asBytes(&output.position), .Position);
|
||||||
|
|
||||||
|
for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| {
|
||||||
|
const result_word = rt.getResultByLocation(@intCast(location), .output) catch |err| switch (err) {
|
||||||
|
SpvRuntimeError.NotFound => continue,
|
||||||
|
else => return err,
|
||||||
|
};
|
||||||
|
if (result_word == 0)
|
||||||
|
continue;
|
||||||
|
const value = rt.results[result_word].getConstValue() catch continue;
|
||||||
|
const needed_size = try value.getPlainMemorySize();
|
||||||
|
output.outputs[location] = data.allocator.alloc(u8, needed_size) catch return VkError.OutOfDeviceMemory;
|
||||||
|
try rt.readOutput(output.outputs[location].?, result_word);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ pub const DispatchTable = struct {
|
|||||||
reset: *const fn (*Self, vk.CommandBufferResetFlags) VkError!void,
|
reset: *const fn (*Self, vk.CommandBufferResetFlags) VkError!void,
|
||||||
resetEvent: *const fn (*Self, *Event, vk.PipelineStageFlags) VkError!void,
|
resetEvent: *const fn (*Self, *Event, vk.PipelineStageFlags) VkError!void,
|
||||||
setEvent: *const fn (*Self, *Event, vk.PipelineStageFlags) VkError!void,
|
setEvent: *const fn (*Self, *Event, vk.PipelineStageFlags) VkError!void,
|
||||||
|
setViewport: *const fn (*Self, u32, []const vk.Viewport) VkError!void,
|
||||||
waitEvents: *const fn (*Self, []*const Event, vk.PipelineStageFlags, vk.PipelineStageFlags, []const vk.MemoryBarrier, []const vk.BufferMemoryBarrier, []const vk.ImageMemoryBarrier) VkError!void,
|
waitEvents: *const fn (*Self, []*const Event, vk.PipelineStageFlags, vk.PipelineStageFlags, []const vk.MemoryBarrier, []const vk.BufferMemoryBarrier, []const vk.ImageMemoryBarrier) VkError!void,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -227,6 +228,10 @@ pub inline fn setEvent(self: *Self, event: *Event, stage: vk.PipelineStageFlags)
|
|||||||
try self.dispatch_table.setEvent(self, event, stage);
|
try self.dispatch_table.setEvent(self, event, stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn setViewport(self: *Self, first: u32, viewports: []const vk.Viewport) VkError!void {
|
||||||
|
try self.dispatch_table.setViewport(self, first, viewports);
|
||||||
|
}
|
||||||
|
|
||||||
pub inline fn waitEvents(self: *Self, events: []*const Event, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void {
|
pub inline fn waitEvents(self: *Self, events: []*const Event, src_stage: vk.PipelineStageFlags, dst_stage: vk.PipelineStageFlags, memory_barriers: []const vk.MemoryBarrier, buffer_barriers: []const vk.BufferMemoryBarrier, image_barriers: []const vk.ImageMemoryBarrier) VkError!void {
|
||||||
try self.dispatch_table.waitEvents(self, events, src_stage, dst_stage, memory_barriers, buffer_barriers, image_barriers);
|
try self.dispatch_table.waitEvents(self, events, src_stage, dst_stage, memory_barriers, buffer_barriers, image_barriers);
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-4
@@ -11,6 +11,18 @@ const PipelineCache = @import("PipelineCache.zig");
|
|||||||
const Self = @This();
|
const Self = @This();
|
||||||
pub const ObjectType: vk.ObjectType = .pipeline;
|
pub const ObjectType: vk.ObjectType = .pipeline;
|
||||||
|
|
||||||
|
const DynamicState = struct {
|
||||||
|
viewport: bool = false,
|
||||||
|
scissor: bool = false,
|
||||||
|
line_width: bool = false,
|
||||||
|
depth_bias: bool = false,
|
||||||
|
blend_constants: bool = false,
|
||||||
|
depth_bounds: bool = false,
|
||||||
|
stencil_compare_mask: bool = false,
|
||||||
|
stencil_write_mask: bool = false,
|
||||||
|
stencil_reference: bool = false,
|
||||||
|
};
|
||||||
|
|
||||||
owner: *Device,
|
owner: *Device,
|
||||||
|
|
||||||
vtable: *const VTable,
|
vtable: *const VTable,
|
||||||
@@ -25,8 +37,8 @@ mode: union(enum) {
|
|||||||
topology: vk.PrimitiveTopology,
|
topology: vk.PrimitiveTopology,
|
||||||
},
|
},
|
||||||
viewport_state: struct {
|
viewport_state: struct {
|
||||||
viewports: []vk.Viewport,
|
viewports: ?[]vk.Viewport,
|
||||||
scissor: []vk.Rect2D,
|
scissor: ?[]vk.Rect2D,
|
||||||
},
|
},
|
||||||
rasterization: struct {
|
rasterization: struct {
|
||||||
polygon_mode: vk.PolygonMode,
|
polygon_mode: vk.PolygonMode,
|
||||||
@@ -34,6 +46,7 @@ mode: union(enum) {
|
|||||||
front_face: vk.FrontFace,
|
front_face: vk.FrontFace,
|
||||||
line_width: f32,
|
line_width: f32,
|
||||||
},
|
},
|
||||||
|
dynamic_state: DynamicState,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -101,7 +114,7 @@ pub fn initGraphics(device: *Device, allocator: std.mem.Allocator, cache: ?*Pipe
|
|||||||
break :blk allocator.dupe(vk.Viewport, viewports[0..viewport_state.viewport_count]) catch return VkError.OutOfHostMemory;
|
break :blk allocator.dupe(vk.Viewport, viewports[0..viewport_state.viewport_count]) catch return VkError.OutOfHostMemory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return VkError.ValidationFailed;
|
break :blk null;
|
||||||
},
|
},
|
||||||
.scissor = blk: {
|
.scissor = blk: {
|
||||||
if (info.p_viewport_state) |viewport_state| {
|
if (info.p_viewport_state) |viewport_state| {
|
||||||
@@ -109,7 +122,7 @@ pub fn initGraphics(device: *Device, allocator: std.mem.Allocator, cache: ?*Pipe
|
|||||||
break :blk allocator.dupe(vk.Rect2D, scissors[0..viewport_state.scissor_count]) catch return VkError.OutOfHostMemory;
|
break :blk allocator.dupe(vk.Rect2D, scissors[0..viewport_state.scissor_count]) catch return VkError.OutOfHostMemory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return VkError.ValidationFailed;
|
break :blk null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.rasterization = .{
|
.rasterization = .{
|
||||||
@@ -118,6 +131,30 @@ pub fn initGraphics(device: *Device, allocator: std.mem.Allocator, cache: ?*Pipe
|
|||||||
.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,
|
||||||
.line_width = if (info.p_rasterization_state) |state| state.line_width else return VkError.ValidationFailed,
|
.line_width = if (info.p_rasterization_state) |state| state.line_width else return VkError.ValidationFailed,
|
||||||
},
|
},
|
||||||
|
.dynamic_state = blk: {
|
||||||
|
var state: DynamicState = .{};
|
||||||
|
|
||||||
|
if (info.p_dynamic_state) |dynamic_state| {
|
||||||
|
if (dynamic_state.p_dynamic_states) |states| {
|
||||||
|
for (states[0..], 0..dynamic_state.dynamic_state_count) |info_state, _| {
|
||||||
|
switch (info_state) {
|
||||||
|
.viewport => state.viewport = true,
|
||||||
|
.scissor => state.scissor = true,
|
||||||
|
.line_width => state.line_width = true,
|
||||||
|
.depth_bias => state.depth_bias = true,
|
||||||
|
.blend_constants => state.blend_constants = true,
|
||||||
|
.depth_bounds => state.depth_bounds = true,
|
||||||
|
.stencil_compare_mask => state.stencil_compare_mask = true,
|
||||||
|
.stencil_write_mask => state.stencil_write_mask = true,
|
||||||
|
.stencil_reference => state.stencil_reference = true,
|
||||||
|
else => return VkError.Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break :blk state;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -856,7 +856,12 @@ pub export fn strollCreateGraphicsPipelines(p_device: vk.Device, p_cache: vk.Pip
|
|||||||
// error code. The implementation will attempt to create all pipelines, and
|
// error code. The implementation will attempt to create all pipelines, and
|
||||||
// only return VK_NULL_HANDLE values for those that actually failed."
|
// only return VK_NULL_HANDLE values for those that actually failed."
|
||||||
p_pipeline.*, const local_res = blk: {
|
p_pipeline.*, const local_res = blk: {
|
||||||
const pipeline = device.createGraphicsPipeline(allocator, cache, info) catch |err| break :blk .{ .null_handle, toVkResult(err) };
|
const pipeline = device.createGraphicsPipeline(allocator, cache, info) catch |err| {
|
||||||
|
if (@errorReturnTrace()) |trace| {
|
||||||
|
std.debug.dumpErrorReturnTrace(trace);
|
||||||
|
}
|
||||||
|
break :blk .{ .null_handle, toVkResult(err) };
|
||||||
|
};
|
||||||
const handle = NonDispatchable(Pipeline).wrap(allocator, pipeline) catch |err| {
|
const handle = NonDispatchable(Pipeline).wrap(allocator, pipeline) catch |err| {
|
||||||
pipeline.destroy(allocator);
|
pipeline.destroy(allocator);
|
||||||
break :blk .{ .null_handle, toVkResult(err) };
|
break :blk .{ .null_handle, toVkResult(err) };
|
||||||
@@ -2133,13 +2138,7 @@ pub export fn strollCmdSetViewport(p_cmd: vk.CommandBuffer, first: u32, count: u
|
|||||||
defer entryPointEndLogTrace();
|
defer entryPointEndLogTrace();
|
||||||
|
|
||||||
const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err);
|
const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err);
|
||||||
|
cmd.setViewport(first, viewports[0..count]) catch |err| return errorLogger(err);
|
||||||
notImplementedWarning();
|
|
||||||
|
|
||||||
_ = cmd;
|
|
||||||
_ = first;
|
|
||||||
_ = count;
|
|
||||||
_ = viewports;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub export fn strollCmdUpdateBuffer(p_cmd: vk.CommandBuffer, p_buffer: vk.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: *const anyopaque) callconv(vk.vulkan_call_conv) void {
|
pub export fn strollCmdUpdateBuffer(p_cmd: vk.CommandBuffer, p_buffer: vk.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: *const anyopaque) callconv(vk.vulkan_call_conv) void {
|
||||||
|
|||||||
+10
-9
@@ -55,12 +55,13 @@ pub fn log(comptime level: std.log.Level, comptime scope: @EnumLiteral(), compti
|
|||||||
file.lock(io, .exclusive) catch {};
|
file.lock(io, .exclusive) catch {};
|
||||||
defer file.unlock(io);
|
defer file.unlock(io);
|
||||||
|
|
||||||
const now = std.Io.Timestamp.now(io, .cpu_process).toMilliseconds();
|
const now = std.Io.Timestamp.now(io, .cpu_process).toMicroseconds();
|
||||||
|
|
||||||
const now_ms: u16 = @intCast(@mod(now, std.time.ms_per_s));
|
const now_us: u16 = @intCast(@mod(now, 1000));
|
||||||
const now_sec: u8 = @intCast(@mod(@divTrunc(now, std.time.ms_per_s), std.time.s_per_min));
|
const now_ms: u16 = @intCast(@mod(@divTrunc(now, 1000), std.time.ms_per_s));
|
||||||
const now_min: u8 = @intCast(@mod(@divTrunc(now, std.time.ms_per_min), 60));
|
const now_sec: u8 = @intCast(@mod(@divTrunc(now, std.time.us_per_s), std.time.s_per_min));
|
||||||
const now_hour: u8 = @intCast(@mod(@divTrunc(now, std.time.ms_per_hour), 24));
|
const now_min: u8 = @intCast(@mod(@divTrunc(now, std.time.us_per_min), 60));
|
||||||
|
const now_hour: u8 = @intCast(@mod(@divTrunc(now, std.time.us_per_hour), 24));
|
||||||
|
|
||||||
var fmt_buffer = std.mem.zeroes([4096]u8);
|
var fmt_buffer = std.mem.zeroes([4096]u8);
|
||||||
var fmt_writer = std.Io.Writer.fixed(&fmt_buffer);
|
var fmt_writer = std.Io.Writer.fixed(&fmt_buffer);
|
||||||
@@ -82,15 +83,15 @@ pub fn log(comptime level: std.log.Level, comptime scope: @EnumLiteral(), compti
|
|||||||
};
|
};
|
||||||
|
|
||||||
term.setColor(.magenta) catch {};
|
term.setColor(.magenta) catch {};
|
||||||
writer.print("[StrollDriver ", .{}) catch continue;
|
writer.writeAll("[StrollDriver") catch continue;
|
||||||
if (!builtin.is_test) {
|
if (!builtin.is_test) {
|
||||||
term.setColor(.cyan) catch {};
|
term.setColor(.cyan) catch {};
|
||||||
writer.print(root.DRIVER_NAME, .{}) catch continue;
|
writer.writeAll(" " ++ root.DRIVER_NAME ++ " ") catch continue;
|
||||||
}
|
}
|
||||||
term.setColor(.yellow) catch {};
|
term.setColor(.yellow) catch {};
|
||||||
writer.print(" {d}:{d}:{d}.{d:0>3}", .{ now_hour, now_min, now_sec, now_ms }) catch continue;
|
writer.print("{d}:{d}:{d}.{d:0>3}.{d:0>3}", .{ now_hour, now_min, now_sec, now_ms, now_us }) catch continue;
|
||||||
term.setColor(.magenta) catch {};
|
term.setColor(.magenta) catch {};
|
||||||
writer.print("]", .{}) catch continue;
|
writer.writeAll("]") catch continue;
|
||||||
|
|
||||||
term.setColor(.cyan) catch {};
|
term.setColor(.cyan) catch {};
|
||||||
writer.print("[Thread {d: >8}]", .{std.Thread.getCurrentId()}) catch continue;
|
writer.print("[Thread {d: >8}]", .{std.Thread.getCurrentId()}) catch continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user