Files
VulkanDriver/src/vulkan/Pipeline.zig
T
2026-05-12 03:01:17 +02:00

189 lines
7.7 KiB
Zig

const std = @import("std");
const vk = @import("vulkan");
const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable;
const VkError = @import("error_set.zig").VkError;
const Device = @import("Device.zig");
const PipelineCache = @import("PipelineCache.zig");
const PipelineLayout = @import("PipelineLayout.zig");
const Self = @This();
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,
vtable: *const VTable,
bind_point: vk.PipelineBindPoint,
stages: vk.ShaderStageFlags,
layout: *PipelineLayout,
mode: union(enum) {
compute: struct {},
graphics: struct {
input_assembly: struct {
binding_description: ?[]vk.VertexInputBindingDescription,
attribute_description: ?[]vk.VertexInputAttributeDescription,
topology: vk.PrimitiveTopology,
},
viewport_state: struct {
viewports: ?[]vk.Viewport,
scissor: ?[]vk.Rect2D,
},
rasterization: struct {
polygon_mode: vk.PolygonMode,
cull_mode: vk.CullModeFlags,
front_face: vk.FrontFace,
line_width: f32,
},
dynamic_state: DynamicState,
},
},
pub const VTable = struct {
destroy: *const fn (*Self, std.mem.Allocator) void,
};
pub fn initCompute(device: *Device, allocator: std.mem.Allocator, cache: ?*PipelineCache, info: *const vk.ComputePipelineCreateInfo) VkError!Self {
_ = cache;
const layout = try NonDispatchable(PipelineLayout).fromHandleObject(info.layout);
layout.ref();
errdefer layout.unref(allocator);
return .{
.owner = device,
.vtable = undefined,
.bind_point = .compute,
.stages = info.stage.stage,
.layout = layout,
.mode = .{ .compute = .{} },
};
}
pub fn initGraphics(device: *Device, allocator: std.mem.Allocator, cache: ?*PipelineCache, info: *const vk.GraphicsPipelineCreateInfo) VkError!Self {
_ = cache;
const layout = try NonDispatchable(PipelineLayout).fromHandleObject(info.layout);
layout.ref();
errdefer layout.unref(allocator);
var stages: vk.ShaderStageFlags = .{};
if (info.p_stages) |p_stages| {
for (p_stages[0..info.stage_count]) |stage| {
stages = stages.merge(stage.stage);
}
}
return .{
.owner = device,
.vtable = undefined,
.bind_point = .graphics,
.stages = stages,
.layout = layout,
.mode = .{
.graphics = .{
.input_assembly = .{
.binding_description = blk: {
if (info.p_vertex_input_state) |vertex_input_state| {
if (vertex_input_state.p_vertex_binding_descriptions) |vertex_binding_descriptions| {
break :blk allocator.dupe(vk.VertexInputBindingDescription, vertex_binding_descriptions[0..vertex_input_state.vertex_binding_description_count]) catch return VkError.OutOfHostMemory;
}
} else {
return VkError.ValidationFailed;
}
break :blk null;
},
.attribute_description = blk: {
if (info.p_vertex_input_state) |vertex_input_state| {
if (vertex_input_state.p_vertex_attribute_descriptions) |vertex_attribute_descriptions| {
break :blk allocator.dupe(vk.VertexInputAttributeDescription, vertex_attribute_descriptions[0..vertex_input_state.vertex_attribute_description_count]) catch return VkError.OutOfHostMemory;
}
} else {
return VkError.ValidationFailed;
}
break :blk null;
},
.topology = if (info.p_input_assembly_state) |state| state.topology else return VkError.ValidationFailed,
},
.viewport_state = .{
.viewports = blk: {
if (info.p_viewport_state) |viewport_state| {
if (viewport_state.p_viewports) |viewports| {
break :blk allocator.dupe(vk.Viewport, viewports[0..viewport_state.viewport_count]) catch return VkError.OutOfHostMemory;
}
}
break :blk null;
},
.scissor = blk: {
if (info.p_viewport_state) |viewport_state| {
if (viewport_state.p_scissors) |scissors| {
break :blk allocator.dupe(vk.Rect2D, scissors[0..viewport_state.scissor_count]) catch return VkError.OutOfHostMemory;
}
}
break :blk null;
},
},
.rasterization = .{
.polygon_mode = if (info.p_rasterization_state) |state| state.polygon_mode else return VkError.ValidationFailed,
.cull_mode = if (info.p_rasterization_state) |state| state.cull_mode 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,
},
.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;
},
},
},
};
}
pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void {
switch (self.mode) {
.compute => {},
.graphics => |graphics| {
if (graphics.input_assembly.binding_description) |binding_description| {
allocator.free(binding_description);
}
if (graphics.input_assembly.attribute_description) |attribute_description| {
allocator.free(attribute_description);
}
},
}
self.layout.unref(allocator);
self.vtable.destroy(self, allocator);
}