implementing proper graphics pipeline creations
This commit is contained in:
@@ -218,7 +218,7 @@ pub fn bindVertexBuffer(interface: *Interface, index: usize, buffer: *base.Buffe
|
||||
|
||||
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
||||
const impl: *Impl = @ptrCast(@alignCast(context));
|
||||
device.renderer.dynamic_state.vertex_buffers[impl.index] = .{
|
||||
device.pipeline_states[ExecutionDevice.GRAPHICS_PIPELINE_STATE].data.graphics.vertex_buffers[impl.index] = .{
|
||||
.buffer = impl.buffer,
|
||||
.offset = impl.offset,
|
||||
.size = 0,
|
||||
@@ -482,8 +482,7 @@ pub fn draw(interface: *Interface, vertex_count: usize, instance_count: usize, f
|
||||
|
||||
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
||||
const impl: *Impl = @ptrCast(@alignCast(context));
|
||||
_ = impl;
|
||||
_ = device;
|
||||
device.renderer.drawPrimitive(impl.vertex_count, impl.instance_count, impl.first_vertex, impl.first_instance);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ pub fn create(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo)
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
self.allocator = std.heap.smp_allocator;
|
||||
self.threaded = std.Io.Threaded.init(self.allocator, .{});
|
||||
self.threaded = if (comptime base.config.single_threaded) .init_single_threaded else std.Io.Threaded.init(self.allocator, .{});
|
||||
self.io_impl = self.threaded.io();
|
||||
|
||||
self.interface = try base.Instance.init(allocator, infos);
|
||||
|
||||
+82
-33
@@ -32,6 +32,7 @@ const Stages = enum {
|
||||
};
|
||||
|
||||
interface: Interface,
|
||||
runtimes_allocator: std.heap.ArenaAllocator,
|
||||
stages: std.EnumMap(Stages, Shader),
|
||||
|
||||
pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache: ?*base.PipelineCache, info: *const vk.ComputePipelineCreateInfo) VkError!*Self {
|
||||
@@ -50,6 +51,10 @@ pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache:
|
||||
|
||||
const device_allocator = soft_device.device_allocator.allocator();
|
||||
|
||||
var runtimes_allocator_arena: std.heap.ArenaAllocator = .init(device_allocator);
|
||||
errdefer runtimes_allocator_arena.deinit();
|
||||
const runtimes_allocator = runtimes_allocator_arena.allocator();
|
||||
|
||||
const instance: *SoftInstance = @alignCast(@fieldParentPtr("interface", device.instance));
|
||||
const runtimes_count = switch (instance.threaded.async_limit) {
|
||||
.nothing => 1,
|
||||
@@ -62,22 +67,17 @@ pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache:
|
||||
|
||||
self.* = .{
|
||||
.interface = interface,
|
||||
.runtimes_allocator = runtimes_allocator_arena,
|
||||
.stages = std.EnumMap(Stages, Shader).init(.{
|
||||
.compute = blk: {
|
||||
var shader: Shader = undefined;
|
||||
soft_module.ref();
|
||||
shader.module = soft_module;
|
||||
|
||||
const runtimes = device_allocator.alloc(spv.Runtime, runtimes_count) catch return VkError.OutOfHostMemory;
|
||||
errdefer {
|
||||
for (runtimes) |*runtime| {
|
||||
runtime.deinit(device_allocator);
|
||||
}
|
||||
device_allocator.free(runtimes);
|
||||
}
|
||||
const runtimes = runtimes_allocator.alloc(spv.Runtime, runtimes_count) catch return VkError.OutOfHostMemory;
|
||||
|
||||
for (runtimes) |*runtime| {
|
||||
runtime.* = spv.Runtime.init(device_allocator, &soft_module.module) catch |err| {
|
||||
runtime.* = spv.Runtime.init(runtimes_allocator, &soft_module.module) catch |err| {
|
||||
std.log.scoped(.SpvRuntimeInit).err("SPIR-V Runtime failed to initialize, {s}", .{@errorName(err)});
|
||||
return VkError.Unknown;
|
||||
};
|
||||
@@ -85,7 +85,7 @@ pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache:
|
||||
if (specialization.p_map_entries) |map| {
|
||||
const data: []const u8 = @as([*]const u8, @ptrCast(@alignCast(specialization.p_data)))[0..specialization.data_size];
|
||||
for (map[0..], 0..specialization.map_entry_count) |entry, _| {
|
||||
runtime.addSpecializationInfo(device_allocator, .{
|
||||
runtime.addSpecializationInfo(runtimes_allocator, .{
|
||||
.id = @intCast(entry.constant_id),
|
||||
.offset = @intCast(entry.offset),
|
||||
.size = @intCast(entry.size),
|
||||
@@ -96,7 +96,9 @@ pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache:
|
||||
}
|
||||
|
||||
shader.runtimes = runtimes;
|
||||
shader.entry = device_allocator.dupe(u8, std.mem.span(info.stage.p_name)) catch return VkError.OutOfHostMemory;
|
||||
shader.entry = runtimes_allocator.dupe(u8, std.mem.span(info.stage.p_name)) catch return VkError.OutOfHostMemory;
|
||||
|
||||
std.log.scoped(.ComputePipeline).debug("Created {d} runtimes for compute stage", .{runtimes_count});
|
||||
break :blk shader;
|
||||
},
|
||||
}),
|
||||
@@ -114,6 +116,13 @@ pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache:
|
||||
.destroy = destroy,
|
||||
};
|
||||
|
||||
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", device));
|
||||
const device_allocator = soft_device.device_allocator.allocator();
|
||||
|
||||
var runtimes_allocator_arena: std.heap.ArenaAllocator = .init(device_allocator);
|
||||
errdefer runtimes_allocator_arena.deinit();
|
||||
const runtimes_allocator = runtimes_allocator_arena.allocator();
|
||||
|
||||
const instance: *SoftInstance = @alignCast(@fieldParentPtr("interface", device.instance));
|
||||
const runtimes_count = switch (instance.threaded.async_limit) {
|
||||
.nothing => 1,
|
||||
@@ -124,36 +133,76 @@ pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache:
|
||||
},
|
||||
};
|
||||
|
||||
const runtimes = allocator.alloc(spv.Runtime, runtimes_count) catch return VkError.OutOfHostMemory;
|
||||
errdefer allocator.free(runtimes);
|
||||
|
||||
//for (runtimes) |*runtime| {
|
||||
// runtime.* = spv.Runtime.init() catch |err| {
|
||||
// std.log.scoped(.SpvRuntimeInit).err("SPIR-V Runtime failed to initialize, {s}", .{@errorName(err)});
|
||||
// return VkError.Unknown;
|
||||
// };
|
||||
//}
|
||||
|
||||
self.* = .{
|
||||
.interface = interface,
|
||||
.stages = std.enums.EnumMap(Stages, Shader).init(.{}),
|
||||
.runtimes_allocator = runtimes_allocator_arena,
|
||||
.stages = std.EnumMap(Stages, Shader).init(.{}),
|
||||
};
|
||||
|
||||
if (info.p_stages) |stages| {
|
||||
for (stages[0..], 0..info.stage_count) |stage, _| {
|
||||
var shader: Shader = undefined;
|
||||
|
||||
const module = try NonDispatchable(ShaderModule).fromHandleObject(stage.module);
|
||||
const soft_module: *SoftShaderModule = @alignCast(@fieldParentPtr("interface", module));
|
||||
soft_module.ref();
|
||||
shader.module = soft_module;
|
||||
|
||||
const runtimes = runtimes_allocator.alloc(spv.Runtime, runtimes_count) catch return VkError.OutOfHostMemory;
|
||||
|
||||
for (runtimes) |*runtime| {
|
||||
runtime.* = spv.Runtime.init(runtimes_allocator, &soft_module.module) catch |err| {
|
||||
std.log.scoped(.SpvRuntimeInit).err("SPIR-V Runtime failed to initialize, {s}", .{@errorName(err)});
|
||||
return VkError.Unknown;
|
||||
};
|
||||
if (stage.p_specialization_info) |specialization| {
|
||||
if (specialization.p_map_entries) |map| {
|
||||
const data: []const u8 = @as([*]const u8, @ptrCast(@alignCast(specialization.p_data)))[0..specialization.data_size];
|
||||
for (map[0..], 0..specialization.map_entry_count) |entry, _| {
|
||||
runtime.addSpecializationInfo(runtimes_allocator, .{
|
||||
.id = @intCast(entry.constant_id),
|
||||
.offset = @intCast(entry.offset),
|
||||
.size = @intCast(entry.size),
|
||||
}, data) catch return VkError.OutOfHostMemory;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shader.runtimes = runtimes;
|
||||
shader.entry = runtimes_allocator.dupe(u8, std.mem.span(stage.p_name)) catch return VkError.OutOfHostMemory;
|
||||
|
||||
std.log.scoped(.GraphicsPipeline).debug("Created {d} runtimes for:", .{runtimes_count});
|
||||
|
||||
if (stage.stage.contains(.{ .vertex_bit = true })) {
|
||||
std.log.scoped(.GraphicsPipeline).debug("> Vertex stage", .{});
|
||||
self.stages.put(.vertex, shader);
|
||||
} else if (stage.stage.contains(.{ .fragment_bit = true })) {
|
||||
std.log.scoped(.GraphicsPipeline).debug("> Fragment stage", .{});
|
||||
self.stages.put(.fragment, shader);
|
||||
} else if (stage.stage.contains(.{ .tessellation_control_bit = true })) {
|
||||
std.log.scoped(.GraphicsPipeline).debug("> Tessellation control stage", .{});
|
||||
self.stages.put(.tessellation_control, shader);
|
||||
} else if (stage.stage.contains(.{ .tessellation_evaluation_bit = true })) {
|
||||
std.log.scoped(.GraphicsPipeline).debug("> Tessellation evaluation stage", .{});
|
||||
self.stages.put(.tessellation_evaluation, shader);
|
||||
} else if (stage.stage.contains(.{ .geometry_bit = true })) {
|
||||
std.log.scoped(.GraphicsPipeline).debug("> Geometry stage", .{});
|
||||
self.stages.put(.geometry, shader);
|
||||
} else {
|
||||
std.log.scoped(.GraphicsPipeline).err("> invalid stage", .{});
|
||||
return VkError.Unknown;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return VkError.ValidationFailed;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
const soft_device: *SoftDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
|
||||
const device_allocator = soft_device.device_allocator.allocator();
|
||||
|
||||
var it = self.stages.iterator();
|
||||
while (it.next()) |stage| {
|
||||
for (stage.value.runtimes) |*runtime| {
|
||||
runtime.deinit(device_allocator);
|
||||
}
|
||||
device_allocator.free(stage.value.runtimes);
|
||||
device_allocator.free(stage.value.entry);
|
||||
stage.value.module.unref(allocator);
|
||||
}
|
||||
self.runtimes_allocator.deinit();
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
||||
@@ -63,33 +63,21 @@ pub fn dispatch(self: *Self, group_count_x: u32, group_count_y: u32, group_count
|
||||
|
||||
var wg: std.Io.Group = .init;
|
||||
for (0..@min(self.batch_size, group_count)) |batch_id| {
|
||||
if (comptime base.config.single_threaded_compute) {
|
||||
runWrapper(
|
||||
RunData{
|
||||
.self = self,
|
||||
.batch_id = batch_id,
|
||||
.group_count = group_count,
|
||||
.group_count_x = @as(usize, @intCast(group_count_x)),
|
||||
.group_count_y = @as(usize, @intCast(group_count_y)),
|
||||
.group_count_z = @as(usize, @intCast(group_count_z)),
|
||||
.invocations_per_workgroup = invocations_per_workgroup,
|
||||
.pipeline = pipeline,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
wg.async(self.device.interface.io(), runWrapper, .{
|
||||
RunData{
|
||||
.self = self,
|
||||
.batch_id = batch_id,
|
||||
.group_count = group_count,
|
||||
.group_count_x = @as(usize, @intCast(group_count_x)),
|
||||
.group_count_y = @as(usize, @intCast(group_count_y)),
|
||||
.group_count_z = @as(usize, @intCast(group_count_z)),
|
||||
.invocations_per_workgroup = invocations_per_workgroup,
|
||||
.pipeline = pipeline,
|
||||
},
|
||||
});
|
||||
}
|
||||
const run_data: RunData = .{
|
||||
.self = self,
|
||||
.batch_id = batch_id,
|
||||
.group_count = group_count,
|
||||
.group_count_x = @as(usize, @intCast(group_count_x)),
|
||||
.group_count_y = @as(usize, @intCast(group_count_y)),
|
||||
.group_count_z = @as(usize, @intCast(group_count_z)),
|
||||
.invocations_per_workgroup = invocations_per_workgroup,
|
||||
.pipeline = pipeline,
|
||||
};
|
||||
|
||||
if (comptime base.config.single_threaded_compute)
|
||||
runWrapper(run_data)
|
||||
else
|
||||
wg.async(self.device.interface.io(), runWrapper, .{run_data});
|
||||
}
|
||||
wg.await(self.device.interface.io()) catch return VkError.DeviceLost;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
const lib = @import("../lib.zig");
|
||||
|
||||
const SoftDescriptorSet = @import("../SoftDescriptorSet.zig");
|
||||
const SoftDevice = @import("../SoftDevice.zig");
|
||||
@@ -15,29 +16,45 @@ const VkError = base.VkError;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub const GRAPHICS_PIPELINE_STATE = 0;
|
||||
pub const COMPUTE_PIPELINE_STATE = 1;
|
||||
|
||||
pub const PipelineState = struct {
|
||||
pipeline: ?*SoftPipeline,
|
||||
sets: [base.VULKAN_MAX_DESCRIPTOR_SETS]?*SoftDescriptorSet,
|
||||
data: union {
|
||||
compute: struct {},
|
||||
graphics: struct {
|
||||
vertex_buffers: [lib.MAX_VERTEX_INPUT_BINDINGS]Renderer.VertexBuffer,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
compute: ComputeDispatcher,
|
||||
renderer: Renderer,
|
||||
|
||||
/// .graphics = 0
|
||||
/// .compute = 1
|
||||
pipeline_states: [2]PipelineState,
|
||||
|
||||
/// Initializating an execution device and
|
||||
/// not creating one to avoid dangling pointers
|
||||
pub fn init(self: *Self, device: *SoftDevice) void {
|
||||
for (self.pipeline_states[0..]) |*state| {
|
||||
for (self.pipeline_states[0..], 0..) |*state, i| {
|
||||
state.* = .{
|
||||
.pipeline = null,
|
||||
.sets = [_]?*SoftDescriptorSet{null} ** base.VULKAN_MAX_DESCRIPTOR_SETS,
|
||||
.data = switch (i) {
|
||||
GRAPHICS_PIPELINE_STATE => .{
|
||||
.graphics = .{
|
||||
.vertex_buffers = undefined,
|
||||
},
|
||||
},
|
||||
COMPUTE_PIPELINE_STATE => .{ .compute = .{} },
|
||||
else => unreachable,
|
||||
},
|
||||
};
|
||||
}
|
||||
self.compute = .init(device, &self.pipeline_states[@intFromEnum(vk.PipelineBindPoint.compute)]);
|
||||
self.renderer = .init();
|
||||
self.renderer = .init(device, &self.pipeline_states[@intFromEnum(vk.PipelineBindPoint.compute)]);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
const zm = @import("zmath");
|
||||
const lib = @import("../lib.zig");
|
||||
|
||||
const F32x4 = zm.F32x4;
|
||||
|
||||
const PipelineState = @import("Device.zig").PipelineState;
|
||||
|
||||
const SoftBuffer = @import("../SoftBuffer.zig");
|
||||
const SoftDescriptorSet = @import("../SoftDescriptorSet.zig");
|
||||
const SoftDevice = @import("../SoftDevice.zig");
|
||||
@@ -42,22 +47,48 @@ pub const DynamicState = struct {
|
||||
|
||||
vertex_input_bindings: [lib.MAX_VERTEX_INPUT_BINDINGS]VertexInputBindingState,
|
||||
vertex_input_attributes: [lib.MAX_VERTEX_INPUT_ATTRIBUTES]VertexInputAttributeState,
|
||||
|
||||
vertex_buffers: [lib.MAX_VERTEX_INPUT_BINDINGS]VertexBuffer,
|
||||
};
|
||||
|
||||
const Vertex = struct {
|
||||
position: F32x4,
|
||||
point_size: f32,
|
||||
index: usize,
|
||||
};
|
||||
|
||||
device: *SoftDevice,
|
||||
state: *PipelineState,
|
||||
|
||||
render_pass: ?*SoftRenderPass,
|
||||
framebuffer: ?*SoftFramebuffer,
|
||||
dynamic_state: DynamicState,
|
||||
|
||||
pub fn init() Self {
|
||||
pub fn init(device: *SoftDevice, state: *PipelineState) Self {
|
||||
return .{
|
||||
.device = device,
|
||||
.state = state,
|
||||
.render_pass = null,
|
||||
.framebuffer = null,
|
||||
.dynamic_state = undefined,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn drawPrimitive(self: *Self, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) void {
|
||||
const allocator = self.device.device_allocator.allocator();
|
||||
|
||||
const vertices = self.fetchVertexInput(allocator, vertex_count, instance_count, first_vertex, first_instance);
|
||||
_ = vertices;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
fn fetchVertexInput(self: *const Self, allocator: std.mem.Allocator, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) []Vertex {
|
||||
_ = self;
|
||||
_ = allocator;
|
||||
_ = vertex_count;
|
||||
_ = instance_count;
|
||||
_ = first_vertex;
|
||||
_ = first_instance;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user