1373 lines
56 KiB
Zig
1373 lines
56 KiB
Zig
const std = @import("std");
|
|
const vk = @import("vulkan");
|
|
const base = @import("base");
|
|
const lib = @import("lib.zig");
|
|
|
|
const Device = base.Device;
|
|
const VkError = base.VkError;
|
|
|
|
const SoftBuffer = @import("SoftBuffer.zig");
|
|
const SoftDescriptorSet = @import("SoftDescriptorSet.zig");
|
|
const SoftFramebuffer = @import("SoftFramebuffer.zig");
|
|
const SoftImage = @import("SoftImage.zig");
|
|
const SoftPipeline = @import("SoftPipeline.zig");
|
|
const SoftRenderPass = @import("SoftRenderPass.zig");
|
|
|
|
const ExecutionDevice = @import("device/Device.zig");
|
|
const blitter = @import("device/blitter.zig");
|
|
|
|
const Self = @This();
|
|
pub const Interface = base.CommandBuffer;
|
|
|
|
const Command = struct {
|
|
const VTable = struct {
|
|
execute: *const fn (*anyopaque, *ExecutionDevice) VkError!void,
|
|
};
|
|
|
|
ptr: *anyopaque,
|
|
vtable: *const VTable,
|
|
};
|
|
|
|
interface: Interface,
|
|
|
|
command_allocator: std.heap.ArenaAllocator,
|
|
commands: std.ArrayList(Command),
|
|
|
|
pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.CommandBufferAllocateInfo) VkError!*Self {
|
|
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(self);
|
|
|
|
var interface = try Interface.init(device, allocator, info);
|
|
|
|
interface.vtable = &.{
|
|
.destroy = destroy,
|
|
};
|
|
|
|
interface.dispatch_table = &.{
|
|
.begin = begin,
|
|
.beginQuery = beginQuery,
|
|
.beginRenderPass = beginRenderPass,
|
|
.bindDescriptorSets = bindDescriptorSets,
|
|
.bindPipeline = bindPipeline,
|
|
.bindIndexBuffer = bindIndexBuffer,
|
|
.bindVertexBuffer = bindVertexBuffer,
|
|
.blitImage = blitImage,
|
|
.clearAttachment = clearAttachment,
|
|
.clearColorImage = clearColorImage,
|
|
.clearDepthStencilImage = clearDepthStencilImage,
|
|
.copyBuffer = copyBuffer,
|
|
.copyBufferToImage = copyBufferToImage,
|
|
.copyImage = copyImage,
|
|
.copyImageToBuffer = copyImageToBuffer,
|
|
.copyQueryPoolResults = copyQueryPoolResults,
|
|
.dispatch = dispatch,
|
|
.dispatchBase = dispatchBase,
|
|
.dispatchIndirect = dispatchIndirect,
|
|
.draw = draw,
|
|
.drawIndexed = drawIndexed,
|
|
.drawIndexedIndirect = drawIndexedIndirect,
|
|
.drawIndirect = drawIndirect,
|
|
.end = end,
|
|
.endQuery = endQuery,
|
|
.endRenderPass = endRenderPass,
|
|
.executeCommands = executeCommands,
|
|
.fillBuffer = fillBuffer,
|
|
.nextSubpass = nextSubpass,
|
|
.pipelineBarrier = pipelineBarrier,
|
|
.pushConstants = pushConstants,
|
|
.reset = reset,
|
|
.resetQueryPool = resetQueryPool,
|
|
.resetEvent = resetEvent,
|
|
.resolveImage = resolveImage,
|
|
.setEvent = setEvent,
|
|
.setBlendConstants = setBlendConstants,
|
|
.setDeviceMask = setDeviceMask,
|
|
.setScissor = setScissor,
|
|
.setStencilCompareMask = setStencilCompareMask,
|
|
.setStencilReference = setStencilReference,
|
|
.setStencilWriteMask = setStencilWriteMask,
|
|
.setViewport = setViewport,
|
|
.updateBuffer = updateBuffer,
|
|
.waitEvent = waitEvent,
|
|
};
|
|
|
|
self.* = .{
|
|
.interface = interface,
|
|
.command_allocator = undefined,
|
|
.commands = .empty,
|
|
};
|
|
self.command_allocator = .init(self.interface.host_allocator.allocator());
|
|
return self;
|
|
}
|
|
|
|
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
_ = self.command_allocator.reset(.free_all);
|
|
allocator.destroy(self);
|
|
}
|
|
|
|
pub fn execute(self: *Self, device: *ExecutionDevice) VkError!void {
|
|
try self.interface.submit();
|
|
defer self.interface.finish() catch {};
|
|
|
|
for (self.commands.items) |command| {
|
|
command.vtable.execute(@ptrCast(command.ptr), device) catch |err| {
|
|
base.errors.errorLoggerContext(err, "the software execution device");
|
|
if (comptime base.config.logs == .verbose) {
|
|
if (@errorReturnTrace()) |trace| {
|
|
std.debug.dumpErrorReturnTrace(trace);
|
|
}
|
|
}
|
|
return VkError.DeviceLost;
|
|
};
|
|
}
|
|
}
|
|
|
|
pub fn begin(interface: *Interface, _: *const vk.CommandBufferBeginInfo) VkError!void {
|
|
// No-op
|
|
_ = interface;
|
|
}
|
|
|
|
pub fn end(interface: *Interface) VkError!void {
|
|
// No-op
|
|
_ = interface;
|
|
}
|
|
|
|
pub fn reset(interface: *Interface, _: vk.CommandBufferResetFlags) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
self.commands.clearAndFree(self.command_allocator.allocator());
|
|
_ = self.command_allocator.reset(.free_all);
|
|
}
|
|
|
|
// Commands ====================================================================================================
|
|
|
|
pub fn beginQuery(interface: *Interface, pool: *base.QueryPool, query: u32, _: vk.QueryControlFlags) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
pool: *base.QueryPool,
|
|
query: u32,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try impl.pool.begin(impl.query);
|
|
if (impl.pool.query_type == .occlusion) {
|
|
for (device.active_occlusion_queries.items) |active| {
|
|
if (active.pool == impl.pool and active.query == impl.query)
|
|
return;
|
|
}
|
|
device.active_occlusion_queries.append(device.renderer.device.device_allocator.allocator(), .{
|
|
.pool = impl.pool,
|
|
.query = impl.query,
|
|
}) catch return VkError.OutOfDeviceMemory;
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.pool = pool,
|
|
.query = query,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn endQuery(interface: *Interface, pool: *base.QueryPool, query: u32) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
pool: *base.QueryPool,
|
|
query: u32,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try impl.pool.end(impl.query);
|
|
|
|
var i: usize = 0;
|
|
while (i < device.active_occlusion_queries.items.len) {
|
|
const active = device.active_occlusion_queries.items[i];
|
|
if (active.pool == impl.pool and active.query == impl.query) {
|
|
_ = device.active_occlusion_queries.swapRemove(i);
|
|
continue;
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.pool = pool,
|
|
.query = query,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn resetQueryPool(interface: *Interface, pool: *base.QueryPool, first: u32, count: u32) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
pool: *base.QueryPool,
|
|
first: u32,
|
|
count: u32,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try impl.pool.reset(impl.first, impl.count);
|
|
|
|
var i: usize = 0;
|
|
while (i < device.active_occlusion_queries.items.len) {
|
|
const active = device.active_occlusion_queries.items[i];
|
|
if (active.pool == impl.pool and
|
|
active.query >= impl.first and
|
|
active.query < impl.first + impl.count)
|
|
{
|
|
_ = device.active_occlusion_queries.swapRemove(i);
|
|
continue;
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.pool = pool,
|
|
.first = first,
|
|
.count = count,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn beginRenderPass(interface: *Interface, render_pass: *base.RenderPass, framebuffer: *base.Framebuffer, render_area: vk.Rect2D, clear_values: ?[]const vk.ClearValue) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
render_pass: *SoftRenderPass,
|
|
framebuffer: *SoftFramebuffer,
|
|
render_area: vk.Rect2D,
|
|
clear_values: ?[]const vk.ClearValue,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
device.renderer.render_pass = impl.render_pass;
|
|
device.renderer.framebuffer = impl.framebuffer;
|
|
device.renderer.subpass_index = 0;
|
|
|
|
for (impl.render_pass.interface.attachments, impl.framebuffer.interface.attachments, 0..) |desc, attachment, index| {
|
|
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", attachment.image));
|
|
var clear_mask: vk.ImageAspectFlags = .{};
|
|
|
|
switch (desc.load_op) {
|
|
.clear => clear_mask = .{ .color_bit = true, .depth_bit = true },
|
|
else => {},
|
|
}
|
|
|
|
switch (desc.stencil_load_op) {
|
|
.clear => clear_mask.stencil_bit = true,
|
|
else => {},
|
|
}
|
|
|
|
clear_mask = clear_mask.intersect(base.format.toAspect(attachment.format));
|
|
|
|
if (clear_mask.toInt() != 0) {
|
|
if (clear_mask.color_bit) {
|
|
try blitter.clear(
|
|
(impl.clear_values orelse return VkError.Unknown)[index],
|
|
try SoftImage.getClearFormatFor(attachment.format),
|
|
image,
|
|
attachment.format,
|
|
attachment.subresource_range,
|
|
null,
|
|
);
|
|
} else {
|
|
var subresource_range = attachment.subresource_range;
|
|
|
|
if (clear_mask.depth_bit) {
|
|
subresource_range.aspect_mask = .{ .depth_bit = true };
|
|
try blitter.clear(
|
|
(impl.clear_values orelse return VkError.Unknown)[index],
|
|
.d32_sfloat,
|
|
image,
|
|
attachment.format,
|
|
subresource_range,
|
|
null,
|
|
);
|
|
}
|
|
|
|
if (clear_mask.stencil_bit) {
|
|
subresource_range.aspect_mask = .{ .stencil_bit = true };
|
|
try blitter.clear(
|
|
(impl.clear_values orelse return VkError.Unknown)[index],
|
|
.s8_uint,
|
|
image,
|
|
attachment.format,
|
|
subresource_range,
|
|
null,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.render_pass = @alignCast(@fieldParentPtr("interface", render_pass)),
|
|
.framebuffer = @alignCast(@fieldParentPtr("interface", framebuffer)),
|
|
.render_area = render_area,
|
|
.clear_values = if (clear_values) |values| allocator.dupe(vk.ClearValue, values) catch return VkError.OutOfHostMemory else null, // Will be freed on cmdbuf reset or destroy
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn bindDescriptorSets(interface: *Interface, bind_point: vk.PipelineBindPoint, first_set: u32, sets: [base.VULKAN_MAX_DESCRIPTOR_SETS]?*base.DescriptorSet, dynamic_offsets: []const u32) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
bind_point: vk.PipelineBindPoint,
|
|
first_set: u32,
|
|
sets: [base.VULKAN_MAX_DESCRIPTOR_SETS]?*base.DescriptorSet,
|
|
dynamic_offsets: []const u32,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
var dynamic_offset_index: usize = 0;
|
|
for (impl.first_set.., impl.sets[0..]) |i, set| {
|
|
if (set == null)
|
|
break;
|
|
const state = &device.pipeline_states[@intCast(@intFromEnum(impl.bind_point))];
|
|
const soft_set: *SoftDescriptorSet = @alignCast(@fieldParentPtr("interface", set.?));
|
|
state.sets[i] = soft_set;
|
|
|
|
const dynamic_count = soft_set.interface.layout.dynamic_descriptor_count;
|
|
if (dynamic_count > ExecutionDevice.MAX_DYNAMIC_DESCRIPTORS_PER_SET or
|
|
dynamic_offset_index + dynamic_count > impl.dynamic_offsets.len)
|
|
{
|
|
return VkError.ValidationFailed;
|
|
}
|
|
@memcpy(
|
|
state.dynamic_offsets[i][0..dynamic_count],
|
|
impl.dynamic_offsets[dynamic_offset_index .. dynamic_offset_index + dynamic_count],
|
|
);
|
|
dynamic_offset_index += dynamic_count;
|
|
}
|
|
}
|
|
};
|
|
|
|
const dynamic_offsets_copy = allocator.dupe(u32, dynamic_offsets) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.free(dynamic_offsets_copy);
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.bind_point = bind_point,
|
|
.first_set = first_set,
|
|
.sets = sets,
|
|
.dynamic_offsets = dynamic_offsets_copy,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn bindPipeline(interface: *Interface, bind_point: vk.PipelineBindPoint, pipeline: *base.Pipeline) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
bind_point: vk.PipelineBindPoint,
|
|
pipeline: *SoftPipeline,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
device.pipeline_states[@intCast(@intFromEnum(impl.bind_point))].pipeline = impl.pipeline;
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.bind_point = bind_point,
|
|
.pipeline = @alignCast(@fieldParentPtr("interface", pipeline)),
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn bindIndexBuffer(interface: *Interface, buffer: *base.Buffer, offset: usize, index_type: vk.IndexType) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
buffer: *const SoftBuffer,
|
|
offset: usize,
|
|
index_type: vk.IndexType,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
device.pipeline_states[ExecutionDevice.GRAPHICS_PIPELINE_STATE].data.graphics.index_buffer = .{
|
|
.buffer = impl.buffer,
|
|
.offset = impl.offset,
|
|
.index_type = impl.index_type,
|
|
};
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.buffer = @alignCast(@fieldParentPtr("interface", buffer)),
|
|
.offset = offset,
|
|
.index_type = index_type,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn bindVertexBuffer(interface: *Interface, index: usize, buffer: *base.Buffer, offset: usize) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
buffer: *const SoftBuffer,
|
|
offset: usize,
|
|
index: usize,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
device.pipeline_states[ExecutionDevice.GRAPHICS_PIPELINE_STATE].data.graphics.vertex_buffers[impl.index] = .{
|
|
.buffer = impl.buffer,
|
|
.offset = impl.offset,
|
|
.size = 0,
|
|
};
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.buffer = @alignCast(@fieldParentPtr("interface", buffer)),
|
|
.offset = offset,
|
|
.index = index,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn blitImage(interface: *Interface, src: *base.Image, _: vk.ImageLayout, dst: *base.Image, _: vk.ImageLayout, regions: []const vk.ImageBlit, filter: vk.Filter) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
src: *const SoftImage,
|
|
dst: *SoftImage,
|
|
regions: []const vk.ImageBlit,
|
|
filter: vk.Filter,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
for (impl.regions[0..]) |region| {
|
|
try blitter.blitRegion(impl.src, impl.dst, region, impl.filter);
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.src = @alignCast(@fieldParentPtr("interface", src)),
|
|
.dst = @alignCast(@fieldParentPtr("interface", dst)),
|
|
.regions = allocator.dupe(vk.ImageBlit, regions) catch return VkError.OutOfHostMemory, // Will be freed on cmdbuf reset or destroy
|
|
.filter = filter,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn clearAttachment(interface: *Interface, attachment: vk.ClearAttachment, rect: vk.ClearRect) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
attachment: vk.ClearAttachment,
|
|
rect: vk.ClearRect,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
|
|
const framebuffer = device.renderer.framebuffer orelse return;
|
|
const render_pass = device.renderer.render_pass orelse return;
|
|
const subpass = render_pass.interface.subpasses[device.renderer.subpass_index];
|
|
|
|
const image_view = blk: {
|
|
if (impl.attachment.aspect_mask.toInt() == (vk.ImageAspectFlags{ .color_bit = true }).toInt()) {
|
|
const fb_attachment_index = (subpass.color_attachments orelse return)[impl.attachment.color_attachment].attachment;
|
|
|
|
if (fb_attachment_index != vk.ATTACHMENT_UNUSED)
|
|
break :blk framebuffer.interface.attachments[impl.attachment.color_attachment];
|
|
} else if (impl.attachment.aspect_mask.depth_bit or impl.attachment.aspect_mask.stencil_bit) {
|
|
if (render_pass.interface.subpasses[device.renderer.subpass_index].depth_stencil_attachments) |desc| {
|
|
if (desc.attachment != vk.ATTACHMENT_UNUSED)
|
|
break :blk framebuffer.interface.attachments[desc.attachment];
|
|
}
|
|
}
|
|
return;
|
|
};
|
|
|
|
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.image));
|
|
const clear_format = try SoftImage.getClearFormatFor(image_view.format);
|
|
|
|
const range: vk.ImageSubresourceRange = .{
|
|
.aspect_mask = impl.attachment.aspect_mask,
|
|
.base_mip_level = image_view.subresource_range.base_mip_level,
|
|
.level_count = image_view.subresource_range.level_count,
|
|
.base_array_layer = impl.rect.base_array_layer + image_view.subresource_range.base_array_layer,
|
|
.layer_count = impl.rect.layer_count,
|
|
};
|
|
|
|
try blitter.clear(
|
|
impl.attachment.clear_value,
|
|
clear_format,
|
|
image,
|
|
image_view.format,
|
|
range,
|
|
impl.rect.rect,
|
|
);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.attachment = attachment,
|
|
.rect = rect,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn clearColorImage(interface: *Interface, image: *base.Image, _: vk.ImageLayout, color: *const vk.ClearColorValue, range: vk.ImageSubresourceRange) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
image: *SoftImage,
|
|
clear_color: vk.ClearColorValue,
|
|
range: vk.ImageSubresourceRange,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
const clear_format = try impl.image.getClearFormat();
|
|
try blitter.clear(.{ .color = impl.clear_color }, clear_format, impl.image, impl.image.interface.format, impl.range, null);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.image = @alignCast(@fieldParentPtr("interface", image)),
|
|
.clear_color = color.*,
|
|
.range = range,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn clearDepthStencilImage(interface: *Interface, image: *base.Image, _: vk.ImageLayout, value: *const vk.ClearDepthStencilValue, range: vk.ImageSubresourceRange) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
image: *SoftImage,
|
|
value: vk.ClearDepthStencilValue,
|
|
range: vk.ImageSubresourceRange,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
const clear_format = try impl.image.getClearFormat();
|
|
try blitter.clear(.{ .depth_stencil = impl.value }, clear_format, impl.image, impl.image.interface.format, impl.range, null);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.image = @alignCast(@fieldParentPtr("interface", image)),
|
|
.value = value.*,
|
|
.range = range,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn copyBuffer(interface: *Interface, src: *base.Buffer, dst: *base.Buffer, regions: []const vk.BufferCopy) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
src: *const SoftBuffer,
|
|
dst: *SoftBuffer,
|
|
regions: []const vk.BufferCopy,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try impl.src.copyBuffer(impl.dst, impl.regions);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.src = @alignCast(@fieldParentPtr("interface", src)),
|
|
.dst = @alignCast(@fieldParentPtr("interface", dst)),
|
|
.regions = allocator.dupe(vk.BufferCopy, regions) 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 copyBufferToImage(interface: *Interface, src: *base.Buffer, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.BufferImageCopy) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
src: *const SoftBuffer,
|
|
dst: *SoftImage,
|
|
dst_layout: vk.ImageLayout,
|
|
regions: []const vk.BufferImageCopy,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
for (impl.regions[0..]) |region| {
|
|
try impl.dst.copyFromBuffer(impl.src, region);
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.src = @alignCast(@fieldParentPtr("interface", src)),
|
|
.dst_layout = dst_layout,
|
|
.dst = @alignCast(@fieldParentPtr("interface", dst)),
|
|
.regions = allocator.dupe(vk.BufferImageCopy, regions) 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 copyImage(interface: *Interface, src: *base.Image, _: vk.ImageLayout, dst: *base.Image, _: vk.ImageLayout, regions: []const vk.ImageCopy) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
src: *const SoftImage,
|
|
dst: *SoftImage,
|
|
regions: []const vk.ImageCopy,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
for (impl.regions[0..]) |region| {
|
|
try impl.src.copyToImage(impl.dst, region);
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.src = @alignCast(@fieldParentPtr("interface", src)),
|
|
.dst = @alignCast(@fieldParentPtr("interface", dst)),
|
|
.regions = allocator.dupe(vk.ImageCopy, regions) 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 copyImageToBuffer(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Buffer, regions: []const vk.BufferImageCopy) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
src: *const SoftImage,
|
|
src_layout: vk.ImageLayout,
|
|
dst: *SoftBuffer,
|
|
regions: []const vk.BufferImageCopy,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
for (impl.regions[0..]) |region| {
|
|
try impl.src.copyToBuffer(impl.dst, region);
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.src = @alignCast(@fieldParentPtr("interface", src)),
|
|
.src_layout = src_layout,
|
|
.dst = @alignCast(@fieldParentPtr("interface", dst)),
|
|
.regions = allocator.dupe(vk.BufferImageCopy, regions) 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 copyQueryPoolResults(interface: *Interface, pool: *base.QueryPool, first: u32, count: u32, dst: *base.Buffer, offset: vk.DeviceSize, stride: vk.DeviceSize, flags: vk.QueryResultFlags) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
pool: *base.QueryPool,
|
|
dst: *SoftBuffer,
|
|
first: u32,
|
|
count: u32,
|
|
offset: vk.DeviceSize,
|
|
stride: vk.DeviceSize,
|
|
flags: vk.QueryResultFlags,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
const value_size: vk.DeviceSize = if (impl.flags.@"64_bit") 8 else 4;
|
|
const item_size = value_size * (1 + @as(vk.DeviceSize, @intFromBool(impl.flags.with_availability_bit)));
|
|
const byte_size = if (impl.count == 0) 0 else (impl.count - 1) * impl.stride + item_size;
|
|
const map = try impl.dst.mapAsSliceWithAddedOffset(u8, impl.offset, byte_size);
|
|
try impl.pool.copyResults(impl.first, impl.count, map, impl.stride, impl.flags);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.pool = pool,
|
|
.dst = @alignCast(@fieldParentPtr("interface", dst)),
|
|
.first = first,
|
|
.count = count,
|
|
.offset = offset,
|
|
.stride = stride,
|
|
.flags = flags,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn dispatch(interface: *Interface, group_count_x: u32, group_count_y: u32, group_count_z: u32) VkError!void {
|
|
try dispatchBase(interface, 0, 0, 0, group_count_x, group_count_y, group_count_z);
|
|
}
|
|
|
|
pub fn dispatchBase(interface: *Interface, base_group_x: u32, base_group_y: u32, base_group_z: u32, group_count_x: u32, group_count_y: u32, group_count_z: u32) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
base_group_x: u32,
|
|
base_group_y: u32,
|
|
base_group_z: u32,
|
|
group_count_x: u32,
|
|
group_count_y: u32,
|
|
group_count_z: u32,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try device.compute.dispatchBase(impl.base_group_x, impl.base_group_y, impl.base_group_z, impl.group_count_x, impl.group_count_y, impl.group_count_z);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.base_group_x = base_group_x,
|
|
.base_group_y = base_group_y,
|
|
.base_group_z = base_group_z,
|
|
.group_count_x = group_count_x,
|
|
.group_count_y = group_count_y,
|
|
.group_count_z = group_count_z,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn setDeviceMask(_: *Interface, device_mask: u32) VkError!void {
|
|
if (device_mask != 1) return VkError.ValidationFailed;
|
|
}
|
|
|
|
pub fn dispatchIndirect(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
buffer: *SoftBuffer,
|
|
offset: vk.DeviceSize,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
const command = try impl.buffer.mapToWithAddedOffset(vk.DispatchIndirectCommand, impl.offset);
|
|
try device.compute.dispatch(command.x, command.y, command.z);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.buffer = @alignCast(@fieldParentPtr("interface", buffer)),
|
|
.offset = offset,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn draw(interface: *Interface, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
vertex_count: usize,
|
|
first_vertex: usize,
|
|
instance_count: usize,
|
|
first_instance: usize,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try device.renderer.draw(impl.vertex_count, impl.instance_count, impl.first_vertex, impl.first_instance);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.vertex_count = vertex_count,
|
|
.first_vertex = first_vertex,
|
|
.instance_count = instance_count,
|
|
.first_instance = first_instance,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn drawIndexed(interface: *Interface, index_count: usize, instance_count: usize, first_index: usize, vertex_offset: i32, first_instance: usize) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
index_count: usize,
|
|
first_index: usize,
|
|
instance_count: usize,
|
|
first_instance: usize,
|
|
vertex_offset: i32,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try device.renderer.drawIndexed(impl.index_count, impl.instance_count, impl.first_index, impl.first_instance, impl.vertex_offset);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.index_count = index_count,
|
|
.first_index = first_index,
|
|
.instance_count = instance_count,
|
|
.first_instance = first_instance,
|
|
.vertex_offset = vertex_offset,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn drawIndexedIndirect(interface: *Interface, buffer: *base.Buffer, offset: usize, count: usize, stride: usize) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
buffer: *SoftBuffer,
|
|
offset: usize,
|
|
count: usize,
|
|
stride: usize,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
for (0..impl.count) |index| {
|
|
const command = try impl.buffer.mapToWithAddedOffset(vk.DrawIndexedIndirectCommand, impl.offset + index * impl.stride);
|
|
try device.renderer.drawIndexed(command.index_count, command.instance_count, command.first_index, command.first_instance, command.vertex_offset);
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.buffer = @alignCast(@fieldParentPtr("interface", buffer)),
|
|
.offset = offset,
|
|
.count = count,
|
|
.stride = stride,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn drawIndirect(interface: *Interface, buffer: *base.Buffer, offset: usize, count: usize, stride: usize) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
buffer: *SoftBuffer,
|
|
offset: usize,
|
|
count: usize,
|
|
stride: usize,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
for (0..impl.count) |index| {
|
|
const command = try impl.buffer.mapToWithAddedOffset(vk.DrawIndirectCommand, impl.offset + index * impl.stride);
|
|
try device.renderer.draw(command.vertex_count, command.instance_count, command.first_vertex, command.first_instance);
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.buffer = @alignCast(@fieldParentPtr("interface", buffer)),
|
|
.offset = offset,
|
|
.count = count,
|
|
.stride = stride,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn endRenderPass(interface: *Interface) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
pub fn execute(_: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const framebuffer = device.renderer.framebuffer orelse return;
|
|
const render_pass = device.renderer.render_pass orelse return;
|
|
|
|
try framebuffer.resolveAttachments(render_pass, device.renderer.subpass_index);
|
|
|
|
device.renderer.render_pass = null;
|
|
device.renderer.framebuffer = null;
|
|
}
|
|
};
|
|
|
|
self.commands.append(allocator, .{ .ptr = undefined, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn executeCommands(interface: *Interface, commands: *Interface) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
cmd: *Self,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try impl.cmd.execute(device);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.cmd = @alignCast(@fieldParentPtr("interface", commands)),
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn fillBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
buffer: *SoftBuffer,
|
|
offset: vk.DeviceSize,
|
|
size: vk.DeviceSize,
|
|
data: u32,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try impl.buffer.fillBuffer(impl.offset, impl.size, impl.data);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.buffer = @alignCast(@fieldParentPtr("interface", buffer)),
|
|
.offset = offset,
|
|
.size = size,
|
|
.data = data,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn updateBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, data: []const u8) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
buffer: *SoftBuffer,
|
|
offset: vk.DeviceSize,
|
|
data: []const u8,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
const map = try impl.buffer.mapAsSliceWithAddedOffset(u8, impl.offset, impl.data.len);
|
|
@memcpy(map, impl.data);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
|
|
const data_copy = allocator.dupe(u8, data) catch return VkError.OutOfHostMemory;
|
|
cmd.* = .{
|
|
.buffer = @alignCast(@fieldParentPtr("interface", buffer)),
|
|
.offset = offset,
|
|
.data = data_copy,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn nextSubpass(interface: *Interface, _: vk.SubpassContents) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
pub fn execute(_: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const framebuffer = device.renderer.framebuffer orelse return;
|
|
const render_pass = device.renderer.render_pass orelse return;
|
|
|
|
try framebuffer.resolveAttachments(render_pass, device.renderer.subpass_index);
|
|
|
|
device.renderer.subpass_index += 1;
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn pipelineBarrier(_: *Interface, _: vk.PipelineStageFlags, _: vk.PipelineStageFlags, _: vk.DependencyFlags, _: []const vk.MemoryBarrier, _: []const vk.BufferMemoryBarrier, _: []const vk.ImageMemoryBarrier) VkError!void {
|
|
// No-op
|
|
}
|
|
|
|
pub fn pushConstants(interface: *Interface, stages: vk.ShaderStageFlags, offset: u32, blob: []const u8) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
stages: vk.ShaderStageFlags,
|
|
offset: u32,
|
|
blob: []const u8,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
|
|
const state = &device.pipeline_states[
|
|
if (impl.stages.vertex_bit or impl.stages.fragment_bit)
|
|
ExecutionDevice.GRAPHICS_PIPELINE_STATE
|
|
else
|
|
ExecutionDevice.COMPUTE_PIPELINE_STATE
|
|
];
|
|
|
|
const size = @min(lib.PUSH_CONSTANT_SIZE - impl.offset, impl.blob.len);
|
|
@memcpy(state.push_constant_blob[impl.offset .. impl.offset + size], impl.blob[0..size]);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.stages = stages,
|
|
.offset = offset,
|
|
.blob = allocator.dupe(u8, blob) 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 resetEvent(interface: *Interface, event: *base.Event, _: vk.PipelineStageFlags) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
event: *base.Event,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try impl.event.reset();
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.event = event,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn resolveImage(interface: *Interface, src: *base.Image, _: vk.ImageLayout, dst: *base.Image, _: vk.ImageLayout, region: vk.ImageResolve) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
src: *const SoftImage,
|
|
dst: *SoftImage,
|
|
region: vk.ImageResolve,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try blitter.resolve(impl.src, impl.dst, impl.region);
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.src = @alignCast(@fieldParentPtr("interface", src)),
|
|
.dst = @alignCast(@fieldParentPtr("interface", dst)),
|
|
.region = region,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn setEvent(interface: *Interface, event: *base.Event, stage: vk.PipelineStageFlags) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
_ = stage;
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
event: *base.Event,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try impl.event.signal();
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.event = event,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn setScissor(interface: *Interface, first: u32, scissor: []const vk.Rect2D) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
first: u32,
|
|
scissor: []const vk.Rect2D,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
device.renderer.dynamic_state.scissor = impl.scissor; // Unsafe
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.first = first,
|
|
.scissor = allocator.dupe(vk.Rect2D, scissor) 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 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 setBlendConstants(interface: *Interface, constants: [4]f32) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
constants: [4]f32,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
device.renderer.dynamic_state.blend_constants = impl.constants;
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{ .constants = constants };
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn setStencilCompareMask(interface: *Interface, face_mask: vk.StencilFaceFlags, compare_mask: u32) VkError!void {
|
|
try setStencilDynamicState(interface, face_mask, compare_mask, .compare_mask);
|
|
}
|
|
|
|
pub fn setStencilReference(interface: *Interface, face_mask: vk.StencilFaceFlags, reference: u32) VkError!void {
|
|
try setStencilDynamicState(interface, face_mask, reference, .reference);
|
|
}
|
|
|
|
pub fn setStencilWriteMask(interface: *Interface, face_mask: vk.StencilFaceFlags, write_mask: u32) VkError!void {
|
|
try setStencilDynamicState(interface, face_mask, write_mask, .write_mask);
|
|
}
|
|
|
|
fn setStencilDynamicState(interface: *Interface, face_mask: vk.StencilFaceFlags, value: u32, comptime kind: enum { compare_mask, reference, write_mask }) VkError!void {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
face_mask: vk.StencilFaceFlags,
|
|
value: u32,
|
|
|
|
pub fn execute(context: *anyopaque, device: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
if (!impl.face_mask.front_bit and !impl.face_mask.back_bit)
|
|
return;
|
|
switch (kind) {
|
|
.compare_mask => {
|
|
if (impl.face_mask.front_bit)
|
|
device.renderer.dynamic_state.stencil_front_compare_mask = impl.value;
|
|
if (impl.face_mask.back_bit)
|
|
device.renderer.dynamic_state.stencil_back_compare_mask = impl.value;
|
|
},
|
|
.reference => {
|
|
if (impl.face_mask.front_bit)
|
|
device.renderer.dynamic_state.stencil_front_reference = impl.value;
|
|
if (impl.face_mask.back_bit)
|
|
device.renderer.dynamic_state.stencil_back_reference = impl.value;
|
|
},
|
|
.write_mask => {
|
|
if (impl.face_mask.front_bit)
|
|
device.renderer.dynamic_state.stencil_front_write_mask = impl.value;
|
|
if (impl.face_mask.back_bit)
|
|
device.renderer.dynamic_state.stencil_back_write_mask = impl.value;
|
|
},
|
|
}
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.face_mask = face_mask,
|
|
.value = value,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|
|
|
|
pub fn waitEvent(interface: *Interface, event: *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 {
|
|
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
|
const allocator = self.command_allocator.allocator();
|
|
|
|
_ = src_stage;
|
|
_ = dst_stage;
|
|
_ = memory_barriers;
|
|
_ = buffer_barriers;
|
|
_ = image_barriers;
|
|
|
|
const CommandImpl = struct {
|
|
const Impl = @This();
|
|
|
|
event: *base.Event,
|
|
|
|
pub fn execute(context: *anyopaque, _: *ExecutionDevice) VkError!void {
|
|
const impl: *Impl = @ptrCast(@alignCast(context));
|
|
try impl.event.wait();
|
|
}
|
|
};
|
|
|
|
const cmd = allocator.create(CommandImpl) catch return VkError.OutOfHostMemory;
|
|
errdefer allocator.destroy(cmd);
|
|
cmd.* = .{
|
|
.event = event,
|
|
};
|
|
self.commands.append(allocator, .{ .ptr = cmd, .vtable = &.{ .execute = CommandImpl.execute } }) catch return VkError.OutOfHostMemory;
|
|
}
|