implementing queries
This commit is contained in:
@@ -21,6 +21,11 @@ pub const GRAPHICS_PIPELINE_STATE = 0;
|
||||
pub const COMPUTE_PIPELINE_STATE = 1;
|
||||
pub const MAX_DYNAMIC_DESCRIPTORS_PER_SET = 64;
|
||||
|
||||
pub const ActiveOcclusionQuery = struct {
|
||||
pool: *base.QueryPool,
|
||||
query: u32,
|
||||
};
|
||||
|
||||
pub const PipelineState = struct {
|
||||
pipeline: ?*SoftPipeline,
|
||||
sets: [base.VULKAN_MAX_DESCRIPTOR_SETS]?*SoftDescriptorSet,
|
||||
@@ -39,6 +44,7 @@ compute: ComputeDispatcher,
|
||||
renderer: Renderer,
|
||||
|
||||
pipeline_states: [2]PipelineState,
|
||||
active_occlusion_queries: std.ArrayList(ActiveOcclusionQuery),
|
||||
|
||||
/// Initializating an execution device and
|
||||
/// not creating one to avoid dangling pointers
|
||||
@@ -61,8 +67,13 @@ pub fn setup(self: *Self, device: *SoftDevice) void {
|
||||
},
|
||||
};
|
||||
}
|
||||
self.active_occlusion_queries = .empty;
|
||||
self.compute = .init(device, &self.pipeline_states[@intFromEnum(vk.PipelineBindPoint.compute)]);
|
||||
self.renderer = .init(device, &self.pipeline_states[@intFromEnum(vk.PipelineBindPoint.graphics)]);
|
||||
self.renderer = .init(device, &self.pipeline_states[@intFromEnum(vk.PipelineBindPoint.graphics)], &self.active_occlusion_queries);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
||||
self.active_occlusion_queries.deinit(allocator);
|
||||
}
|
||||
|
||||
pub fn writeDescriptorSets(state: *PipelineState, rt: *spv.Runtime) !void {
|
||||
|
||||
@@ -74,7 +74,6 @@ pub const DrawCall = struct {
|
||||
render_pass: *SoftRenderPass,
|
||||
framebuffer: *SoftFramebuffer,
|
||||
|
||||
allocator_mutex: std.Io.Mutex,
|
||||
rasterizer_wait_group: std.Io.Group,
|
||||
|
||||
stats: struct {
|
||||
@@ -94,7 +93,6 @@ pub const DrawCall = struct {
|
||||
.depth_attachment = if (render_pass.interface.subpasses[renderer.subpass_index].depth_stencil_attachments) |desc| framebuffer.interface.attachments[desc.attachment] else null,
|
||||
.render_pass = render_pass,
|
||||
.framebuffer = framebuffer,
|
||||
.allocator_mutex = .init,
|
||||
.rasterizer_wait_group = .init,
|
||||
.stats = .{
|
||||
.polygons_drawn = 0,
|
||||
@@ -132,8 +130,9 @@ framebuffer: ?*SoftFramebuffer,
|
||||
dynamic_state: DynamicState,
|
||||
|
||||
subpass_index: usize,
|
||||
active_occlusion_queries: *std.ArrayList(ExecutionDevice.ActiveOcclusionQuery),
|
||||
|
||||
pub fn init(device: *SoftDevice, state: *PipelineState) Self {
|
||||
pub fn init(device: *SoftDevice, state: *PipelineState, active_occlusion_queries: *std.ArrayList(ExecutionDevice.ActiveOcclusionQuery)) Self {
|
||||
return .{
|
||||
.device = device,
|
||||
.state = state,
|
||||
@@ -152,6 +151,7 @@ pub fn init(device: *SoftDevice, state: *PipelineState) Self {
|
||||
.stencil_back_reference = null,
|
||||
},
|
||||
.subpass_index = 0,
|
||||
.active_occlusion_queries = active_occlusion_queries,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -574,7 +574,12 @@ pub fn readFloat4(map: []const u8, src_format: vk.Format) F32x4 {
|
||||
=> c[0] = normalizedI8(map[0]),
|
||||
|
||||
.r16_snorm => c[0] = normalizedI16(std.mem.bytesToValue(u16, map)),
|
||||
.r16_unorm => c[0] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map))) / std.math.maxInt(u16),
|
||||
.r16_unorm,
|
||||
.d16_unorm,
|
||||
=> c[0] = @as(f32, @floatFromInt(std.mem.bytesToValue(u16, map))) / std.math.maxInt(u16),
|
||||
.x8_d24_unorm_pack32,
|
||||
.d24_unorm_s8_uint,
|
||||
=> c[0] = @as(f32, @floatFromInt(std.mem.bytesToValue(u32, map) & 0x00ff_ffff)) / @as(f32, @floatFromInt(0x00ff_ffff)),
|
||||
|
||||
.r8g8b8a8_sint,
|
||||
.r8g8b8a8_uint,
|
||||
@@ -856,6 +861,14 @@ pub fn writeFloat4(c: F32x4, map: []u8, dst_format: vk.Format) void {
|
||||
.d16_unorm,
|
||||
=> std.mem.bytesAsValue(u16, map).* = @intFromFloat(@round(color[0] * std.math.maxInt(u16))),
|
||||
|
||||
.x8_d24_unorm_pack32,
|
||||
.d24_unorm_s8_uint,
|
||||
=> {
|
||||
const depth: u32 = @intFromFloat(@round(color[0] * @as(f32, @floatFromInt(0x00ff_ffff))));
|
||||
const preserved: u32 = std.mem.bytesToValue(u32, map) & 0xff00_0000;
|
||||
std.mem.bytesAsValue(u32, map).* = preserved | depth;
|
||||
},
|
||||
|
||||
.r16_sfloat => std.mem.bytesAsValue(f16, map).* = @floatCast(color[0]),
|
||||
|
||||
.r32_sint,
|
||||
|
||||
@@ -72,9 +72,12 @@ pub fn shaderInvocation(
|
||||
|
||||
rt.callEntryPoint(allocator, entry) catch |err| switch (err) {
|
||||
// Some errors can be safely ignored
|
||||
SpvRuntimeError.OutOfBounds,
|
||||
SpvRuntimeError.Killed,
|
||||
=> {},
|
||||
SpvRuntimeError.OutOfBounds => {},
|
||||
SpvRuntimeError.Killed => {
|
||||
try rt.flushDescriptorSets(allocator);
|
||||
freeOwnedInputs(allocator, fragment_inputs);
|
||||
return undefined; // FIXME
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
|
||||
|
||||
@@ -173,6 +173,16 @@ inline fn run(data: RunData) !void {
|
||||
};
|
||||
}
|
||||
|
||||
try common.writeToTargets(outputs, data.draw_call, data.color_attachment_access, data.depth_attachment_access, data.stencil_attachment_access, true, @intCast(pixel_x), @intCast(pixel_y), z);
|
||||
try common.writeToTargets(
|
||||
outputs,
|
||||
data.draw_call,
|
||||
data.color_attachment_access,
|
||||
data.depth_attachment_access,
|
||||
data.stencil_attachment_access,
|
||||
true,
|
||||
@intCast(pixel_x),
|
||||
@intCast(pixel_y),
|
||||
z,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,13 +98,7 @@ fn updateStencilValue(stencil: *RenderTargetAccess, offset: usize, state: vk.Ste
|
||||
blitter.writeInt4(@splat(new_value), stencil.base[offset..], stencil.format);
|
||||
}
|
||||
|
||||
pub fn stencilTestAndUpdate(
|
||||
stencil: *RenderTargetAccess,
|
||||
x: usize,
|
||||
y: usize,
|
||||
state: vk.StencilOpState,
|
||||
depth_passed: ?bool,
|
||||
) bool {
|
||||
pub fn stencilTestAndUpdate(stencil: *RenderTargetAccess, x: usize, y: usize, state: vk.StencilOpState, depth_passed: ?bool) bool {
|
||||
const offset = targetOffset(stencil.*, x, y) orelse return false;
|
||||
const current = blitter.readInt4(stencil.base[offset..], stencil.format)[0] & std.math.maxInt(u8);
|
||||
const reference = state.reference & std.math.maxInt(u8);
|
||||
@@ -132,15 +126,27 @@ fn stencilTest(stencil: *RenderTargetAccess, offset: usize, state: vk.StencilOpS
|
||||
return compare(u32, state.compare_op, reference & compare_mask, current & compare_mask);
|
||||
}
|
||||
|
||||
fn quantizeDepthForFormat(format: vk.Format, z: f32) f32 {
|
||||
const clamped = std.math.clamp(z, 0.0, 1.0);
|
||||
return switch (format) {
|
||||
.d16_unorm => @as(f32, @floatFromInt(@as(u16, @intFromFloat(@round(clamped * std.math.maxInt(u16)))))) / std.math.maxInt(u16),
|
||||
.x8_d24_unorm_pack32,
|
||||
.d24_unorm_s8_uint,
|
||||
=> @as(f32, @floatFromInt(@as(u32, @intFromFloat(@round(clamped * @as(f32, @floatFromInt(0x00ff_ffff))))))) / @as(f32, @floatFromInt(0x00ff_ffff)),
|
||||
else => z,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn depthTestAndUpdate(depth: *RenderTargetAccess, x: usize, y: usize, z: f32, state: vk.PipelineDepthStencilStateCreateInfo) bool {
|
||||
if (state.depth_test_enable == .false)
|
||||
return true;
|
||||
|
||||
const offset = targetOffset(depth.*, x, y) orelse return false;
|
||||
const reference = quantizeDepthForFormat(depth.format, z);
|
||||
const depth_value = blitter.readFloat4(depth.base[offset..], depth.format);
|
||||
const passed = compare(f32, state.depth_compare_op, z, depth_value[0]);
|
||||
const passed = compare(f32, state.depth_compare_op, reference, depth_value[0]);
|
||||
if (passed and state.depth_write_enable == .true)
|
||||
blitter.writeFloat4(zm.f32x4s(z), depth.base[offset..], depth.format);
|
||||
blitter.writeFloat4(zm.f32x4s(reference), depth.base[offset..], depth.format);
|
||||
return passed;
|
||||
}
|
||||
|
||||
@@ -312,6 +318,9 @@ pub fn writeToTargets(
|
||||
const io = draw_call.renderer.device.interface.io();
|
||||
const depth_stencil_state = draw_call.renderer.state.pipeline.?.interface.mode.graphics.depth_stencil;
|
||||
|
||||
if (x >= draw_call.framebuffer.interface.width or y >= draw_call.framebuffer.interface.height)
|
||||
return;
|
||||
|
||||
var stencil_state: ?vk.StencilOpState = null;
|
||||
var stencil_offset: ?usize = null;
|
||||
if (stencil_attachment_access) |stencil| {
|
||||
@@ -361,6 +370,10 @@ pub fn writeToTargets(
|
||||
}
|
||||
}
|
||||
|
||||
for (draw_call.renderer.active_occlusion_queries.items) |active| {
|
||||
try active.pool.addSamples(active.query, 1);
|
||||
}
|
||||
|
||||
for (color_attachment_access, 0..) |maybe_color, location| {
|
||||
const color = maybe_color orelse continue;
|
||||
const color_offset = targetOffset(color, x, y) orelse continue;
|
||||
|
||||
@@ -191,7 +191,17 @@ inline fn run(data: RunData) !void {
|
||||
};
|
||||
}
|
||||
|
||||
try common.writeToTargets(outputs, data.draw_call, data.color_attachment_access, data.depth_attachment_access, data.stencil_attachment_access, data.front_face, @intCast(x), @intCast(y), z);
|
||||
try common.writeToTargets(
|
||||
outputs,
|
||||
data.draw_call,
|
||||
data.color_attachment_access,
|
||||
data.depth_attachment_access,
|
||||
data.stencil_attachment_access,
|
||||
data.front_face,
|
||||
@intCast(x),
|
||||
@intCast(y),
|
||||
z,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,16 +39,18 @@ pub fn runWrapper(data: RunData) void {
|
||||
|
||||
inline fn run(data: RunData) !void {
|
||||
const shader = data.pipeline.stages.getPtrAssertContains(.vertex);
|
||||
const rt = &shader.runtimes[data.batch_id].rt;
|
||||
const runtime = &shader.runtimes[data.batch_id];
|
||||
const mutex = &runtime.mutex;
|
||||
const rt = &runtime.rt;
|
||||
|
||||
const io = data.draw_call.renderer.device.interface.io();
|
||||
mutex.lock(io) catch return VkError.DeviceLost;
|
||||
defer mutex.unlock(io);
|
||||
|
||||
const entry = try rt.getEntryPointByName(shader.entry);
|
||||
|
||||
var invocation_index: usize = data.batch_id;
|
||||
while (invocation_index < data.vertex_count) : (invocation_index += data.batch_size) {
|
||||
const io = data.draw_call.renderer.device.interface.io();
|
||||
data.draw_call.allocator_mutex.lock(io) catch return VkError.DeviceLost;
|
||||
defer data.draw_call.allocator_mutex.unlock(io);
|
||||
|
||||
rt.resetInvocation(data.allocator);
|
||||
try rt.populatePushConstants(data.draw_call.renderer.state.push_constant_blob[0..]);
|
||||
|
||||
@@ -78,9 +80,11 @@ inline fn run(data: RunData) !void {
|
||||
|
||||
rt.callEntryPoint(data.allocator, entry) catch |err| switch (err) {
|
||||
// Some errors can be safely ignored
|
||||
SpvRuntimeError.OutOfBounds,
|
||||
SpvRuntimeError.Killed,
|
||||
=> {},
|
||||
SpvRuntimeError.OutOfBounds => {},
|
||||
SpvRuntimeError.Killed => {
|
||||
try rt.flushDescriptorSets(data.allocator);
|
||||
return;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
|
||||
@@ -95,7 +99,7 @@ inline fn run(data: RunData) !void {
|
||||
};
|
||||
const memory_size = try rt.getResultMemorySize(result_word);
|
||||
output.outputs[location][component] = .{
|
||||
.interpolation_type = if (rt.hasResultDecoration(result_word, .Flat) or resultIsInteger(rt, result_word)) .flat else .smooth, // TODO : handle noperspective
|
||||
.interpolation_type = if (rt.hasResultDecoration(result_word, .Flat) or rt.resultIsInteger(result_word)) .flat else .smooth, // TODO : handle noperspective
|
||||
.blob = data.allocator.alloc(u8, memory_size + INTERFACE_BLOB_PADDING) catch return VkError.OutOfDeviceMemory,
|
||||
.size = memory_size,
|
||||
};
|
||||
@@ -116,32 +120,7 @@ fn setupBuiltins(rt: *spv.Runtime, vertex_index: usize, instance_index: usize) !
|
||||
try rt.writeBuiltIn(std.mem.asBytes(&instance_index_u32), .InstanceIndex);
|
||||
}
|
||||
|
||||
fn resultIsInteger(rt: *spv.Runtime, result_word: spv.SpvWord) bool {
|
||||
const value = rt.results[result_word].getConstValue() catch return false;
|
||||
return switch (value.*) {
|
||||
.Int,
|
||||
.Vector2i32,
|
||||
.Vector3i32,
|
||||
.Vector4i32,
|
||||
.Vector2u32,
|
||||
.Vector3u32,
|
||||
.Vector4u32,
|
||||
=> true,
|
||||
.Vector => |lanes| lanes.len != 0 and switch (lanes[0]) {
|
||||
.Int => true,
|
||||
else => false,
|
||||
},
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
fn writeVertexInput(
|
||||
rt: *spv.Runtime,
|
||||
allocator: std.mem.Allocator,
|
||||
raw_input: []const u8,
|
||||
format: vk.Format,
|
||||
location: u32,
|
||||
) !void {
|
||||
fn writeVertexInput(rt: *spv.Runtime, allocator: std.mem.Allocator, raw_input: []const u8, format: vk.Format, location: u32) !void {
|
||||
var has_split_components = false;
|
||||
for (1..4) |component| {
|
||||
_ = rt.getResultByLocationComponent(location, @intCast(component), .input) catch |err| switch (err) {
|
||||
|
||||
Reference in New Issue
Block a user