improving robust buffer support
This commit is contained in:
+2
-2
@@ -32,8 +32,8 @@
|
|||||||
|
|
||||||
// Soft dependencies
|
// Soft dependencies
|
||||||
.SPIRV_Interpreter = .{
|
.SPIRV_Interpreter = .{
|
||||||
.url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#fcf303a0c62a66ff32fc92fe9c92ca9294f72caf",
|
.url = "git+https://github.com/Kbz-8/SPIRV-Interpreter#e49383f07ec20d194811a48986f9ffd3483aed2b",
|
||||||
.hash = "SPIRV_Interpreter-0.0.1-ajmpnx3dCAAfuabTUWPWdTVqPGBPeSUCCTI-ncKowi5D",
|
.hash = "SPIRV_Interpreter-0.0.1-ajmpn8gICQCM5IcZkaGnupby40N0Xi7-m6U4jxK8mKoS",
|
||||||
.lazy = true,
|
.lazy = true,
|
||||||
},
|
},
|
||||||
//.SPIRV_Interpreter = .{
|
//.SPIRV_Interpreter = .{
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ pub fn beginRenderPass(interface: *Interface, render_pass: *base.RenderPass, fra
|
|||||||
device.renderer.framebuffer = impl.framebuffer;
|
device.renderer.framebuffer = impl.framebuffer;
|
||||||
device.renderer.render_area = impl.render_area;
|
device.renderer.render_area = impl.render_area;
|
||||||
device.renderer.subpass_index = 0;
|
device.renderer.subpass_index = 0;
|
||||||
|
device.renderer.resetInputAttachmentSnapshots();
|
||||||
|
|
||||||
for (impl.render_pass.interface.attachments, impl.framebuffer.interface.attachments, 0..) |desc, attachment, index| {
|
for (impl.render_pass.interface.attachments, impl.framebuffer.interface.attachments, 0..) |desc, attachment, index| {
|
||||||
if (!attachmentIsReferencedBySubpass(impl.render_pass, @intCast(index)))
|
if (!attachmentIsReferencedBySubpass(impl.render_pass, @intCast(index)))
|
||||||
@@ -1021,6 +1022,7 @@ pub fn endRenderPass(interface: *Interface) VkError!void {
|
|||||||
|
|
||||||
try framebuffer.resolveAttachments(render_pass, device.renderer.subpass_index);
|
try framebuffer.resolveAttachments(render_pass, device.renderer.subpass_index);
|
||||||
|
|
||||||
|
device.renderer.resetInputAttachmentSnapshots();
|
||||||
device.renderer.render_pass = null;
|
device.renderer.render_pass = null;
|
||||||
device.renderer.framebuffer = null;
|
device.renderer.framebuffer = null;
|
||||||
device.renderer.render_area = null;
|
device.renderer.render_area = null;
|
||||||
@@ -1125,6 +1127,7 @@ pub fn nextSubpass(interface: *Interface, _: vk.SubpassContents) VkError!void {
|
|||||||
|
|
||||||
try framebuffer.resolveAttachments(render_pass, device.renderer.subpass_index);
|
try framebuffer.resolveAttachments(render_pass, device.renderer.subpass_index);
|
||||||
|
|
||||||
|
device.renderer.resetInputAttachmentSnapshots();
|
||||||
device.renderer.subpass_index += 1;
|
device.renderer.subpass_index += 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,19 @@ const Device = base.Device;
|
|||||||
const VkError = base.VkError;
|
const VkError = base.VkError;
|
||||||
const SpvRuntimeError = spv.Runtime.RuntimeError;
|
const SpvRuntimeError = spv.Runtime.RuntimeError;
|
||||||
|
|
||||||
|
pub const InputAttachmentSnapshot = struct {
|
||||||
|
image: *base.Image,
|
||||||
|
aspect_mask: vk.ImageAspectFlags,
|
||||||
|
mip_level: u32,
|
||||||
|
array_layer: u32,
|
||||||
|
data: []const u8,
|
||||||
|
row_pitch: usize,
|
||||||
|
slice_pitch: usize,
|
||||||
|
sample_stride: usize,
|
||||||
|
};
|
||||||
|
|
||||||
pub threadlocal var current_fragment_coord: ?vk.Offset3D = null; // Ugly hack
|
pub threadlocal var current_fragment_coord: ?vk.Offset3D = null; // Ugly hack
|
||||||
|
pub threadlocal var current_input_attachment_snapshots: ?[]const InputAttachmentSnapshot = null;
|
||||||
|
|
||||||
const NonDispatchable = base.NonDispatchable;
|
const NonDispatchable = base.NonDispatchable;
|
||||||
const ShaderModule = base.ShaderModule;
|
const ShaderModule = base.ShaderModule;
|
||||||
@@ -336,6 +348,32 @@ fn sampledTexelOffset(image: *SoftImage, offset: vk.Offset3D, subresource: vk.Im
|
|||||||
@as(usize, sample_index) * image.getMipLevelSize(subresource.aspect_mask, subresource.mip_level);
|
@as(usize, sample_index) * image.getMipLevelSize(subresource.aspect_mask, subresource.mip_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sampledSnapshotTexel(snapshot: InputAttachmentSnapshot, offset: vk.Offset3D, format: vk.Format, sample_index: u32) SpvRuntimeError![]const u8 {
|
||||||
|
const texel_size = base.format.texelSize(format);
|
||||||
|
const texel_offset =
|
||||||
|
@as(usize, @intCast(offset.z)) * snapshot.slice_pitch +
|
||||||
|
@as(usize, @intCast(offset.y)) * snapshot.row_pitch +
|
||||||
|
@as(usize, @intCast(offset.x)) * texel_size +
|
||||||
|
@as(usize, sample_index) * snapshot.sample_stride;
|
||||||
|
if (texel_offset > snapshot.data.len or texel_size > snapshot.data.len - texel_offset)
|
||||||
|
return SpvRuntimeError.OutOfBounds;
|
||||||
|
return snapshot.data[texel_offset .. texel_offset + texel_size];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findInputAttachmentSnapshot(image_view: *SoftImageView, subresource: vk.ImageSubresource) ?InputAttachmentSnapshot {
|
||||||
|
const snapshots = current_input_attachment_snapshots orelse return null;
|
||||||
|
for (snapshots) |snapshot| {
|
||||||
|
if (snapshot.image == image_view.interface.image and
|
||||||
|
snapshot.aspect_mask.toInt() == subresource.aspect_mask.toInt() and
|
||||||
|
snapshot.mip_level == subresource.mip_level and
|
||||||
|
snapshot.array_layer == subresource.array_layer)
|
||||||
|
{
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
fn readImageFloat4Sample(image: *SoftImage, offset: vk.Offset3D, subresource: vk.ImageSubresource, format: vk.Format, sample_index: u32) VkError!zm.F32x4 {
|
fn readImageFloat4Sample(image: *SoftImage, offset: vk.Offset3D, subresource: vk.ImageSubresource, format: vk.Format, sample_index: u32) VkError!zm.F32x4 {
|
||||||
if (image.interface.samples.toInt() == 1)
|
if (image.interface.samples.toInt() == 1)
|
||||||
return image.readFloat4(offset, subresource, format);
|
return image.readFloat4(offset, subresource, format);
|
||||||
@@ -356,18 +394,27 @@ fn readImageInt4Sample(image: *SoftImage, offset: vk.Offset3D, subresource: vk.I
|
|||||||
|
|
||||||
fn subpassDataCoord(x: i32, y: i32, z: i32) SpvRuntimeError!vk.Offset3D {
|
fn subpassDataCoord(x: i32, y: i32, z: i32) SpvRuntimeError!vk.Offset3D {
|
||||||
const coord = current_fragment_coord orelse return SpvRuntimeError.Unknown;
|
const coord = current_fragment_coord orelse return SpvRuntimeError.Unknown;
|
||||||
return .{ .x = coord.x + x, .y = coord.y + y, .z = coord.z + z };
|
_ = z;
|
||||||
|
return .{ .x = coord.x + x, .y = coord.y + y, .z = coord.z };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bufferViewRange(buffer_view: *const SoftBufferView) SpvRuntimeError!usize {
|
fn bufferViewRange(buffer_view: *const SoftBufferView) SpvRuntimeError!usize {
|
||||||
const offset: usize = @intCast(buffer_view.interface.offset);
|
const offset: usize = @intCast(buffer_view.interface.offset);
|
||||||
if (offset > buffer_view.interface.buffer.size)
|
const buffer = buffer_view.interface.buffer;
|
||||||
|
const bound_size: usize = if (buffer.memory) |memory| blk: {
|
||||||
|
const buffer_offset: usize = @intCast(buffer.offset);
|
||||||
|
if (buffer_offset >= memory.size)
|
||||||
|
break :blk 0;
|
||||||
|
break :blk @min(@as(usize, @intCast(buffer.size)), @as(usize, @intCast(memory.size - buffer.offset)));
|
||||||
|
} else @intCast(buffer.size);
|
||||||
|
|
||||||
|
if (offset > bound_size)
|
||||||
return SpvRuntimeError.Unknown;
|
return SpvRuntimeError.Unknown;
|
||||||
|
|
||||||
if (buffer_view.interface.range == vk.WHOLE_SIZE)
|
if (buffer_view.interface.range == vk.WHOLE_SIZE)
|
||||||
return @intCast(buffer_view.interface.buffer.size - offset);
|
return bound_size - offset;
|
||||||
|
|
||||||
return @intCast(buffer_view.interface.range);
|
return @min(@as(usize, @intCast(buffer_view.interface.range)), bound_size - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mapBufferViewTexel(buffer_view: *const SoftBufferView, x: i32) SpvRuntimeError![]u8 {
|
fn mapBufferViewTexel(buffer_view: *const SoftBufferView, x: i32) SpvRuntimeError![]u8 {
|
||||||
@@ -400,7 +447,10 @@ fn readImageFloat4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32,
|
|||||||
var pixel = zm.f32x4s(0.0);
|
var pixel = zm.f32x4s(0.0);
|
||||||
if (dim == .Buffer) {
|
if (dim == .Buffer) {
|
||||||
const buffer_view = try bufferViewFromContext(context);
|
const buffer_view = try bufferViewFromContext(context);
|
||||||
pixel = blitter.readFloat4(try mapBufferViewTexel(buffer_view, x), buffer_view.interface.format);
|
pixel = if (mapBufferViewTexel(buffer_view, x)) |texel|
|
||||||
|
blitter.readFloat4(texel, buffer_view.interface.format)
|
||||||
|
else |_|
|
||||||
|
zm.f32x4s(0.0);
|
||||||
} else {
|
} else {
|
||||||
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
|
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
|
||||||
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
|
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
|
||||||
@@ -424,13 +474,14 @@ fn readImageFloat4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32,
|
|||||||
.array_layer = array_layer,
|
.array_layer = array_layer,
|
||||||
};
|
};
|
||||||
const sample_index: u32 = if (image.interface.samples.toInt() > 1) @intCast(z) else 0;
|
const sample_index: u32 = if (image.interface.samples.toInt() > 1) @intCast(z) else 0;
|
||||||
pixel = SoftSampler.swizzleFloat4(readImageFloat4Sample(
|
const format = base.format.fromAspect(image_view.interface.format, aspect_mask);
|
||||||
image,
|
const raw_pixel = if (dim == .SubpassData) blk: {
|
||||||
image_coord,
|
if (findInputAttachmentSnapshot(image_view, subresource)) |snapshot| {
|
||||||
subresource,
|
break :blk blitter.readFloat4(try sampledSnapshotTexel(snapshot, image_coord, format, sample_index), format);
|
||||||
base.format.fromAspect(image_view.interface.format, aspect_mask),
|
}
|
||||||
sample_index,
|
break :blk readImageFloat4Sample(image, image_coord, subresource, format, sample_index) catch return SpvRuntimeError.Unknown;
|
||||||
) catch return SpvRuntimeError.Unknown, image_view.interface.components);
|
} else readImageFloat4Sample(image, image_coord, subresource, format, sample_index) catch return SpvRuntimeError.Unknown;
|
||||||
|
pixel = SoftSampler.swizzleFloat4(raw_pixel, image_view.interface.components);
|
||||||
}
|
}
|
||||||
return .{
|
return .{
|
||||||
.x = pixel[0],
|
.x = pixel[0],
|
||||||
@@ -444,7 +495,10 @@ fn readImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, l
|
|||||||
var pixel = @Vector(4, u32){ 0, 0, 0, 0 };
|
var pixel = @Vector(4, u32){ 0, 0, 0, 0 };
|
||||||
if (dim == .Buffer) {
|
if (dim == .Buffer) {
|
||||||
const buffer_view = try bufferViewFromContext(context);
|
const buffer_view = try bufferViewFromContext(context);
|
||||||
pixel = blitter.readInt4(try mapBufferViewTexel(buffer_view, x), buffer_view.interface.format);
|
pixel = if (mapBufferViewTexel(buffer_view, x)) |texel|
|
||||||
|
blitter.readInt4(texel, buffer_view.interface.format)
|
||||||
|
else |_|
|
||||||
|
@Vector(4, u32){ 0, 0, 0, 0 };
|
||||||
} else {
|
} else {
|
||||||
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
|
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
|
||||||
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
|
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
|
||||||
@@ -468,13 +522,14 @@ fn readImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, l
|
|||||||
.array_layer = array_layer,
|
.array_layer = array_layer,
|
||||||
};
|
};
|
||||||
const sample_index: u32 = if (image.interface.samples.toInt() > 1) @intCast(z) else 0;
|
const sample_index: u32 = if (image.interface.samples.toInt() > 1) @intCast(z) else 0;
|
||||||
pixel = SoftSampler.swizzleInt4(readImageInt4Sample(
|
const format = base.format.fromAspect(image_view.interface.format, aspect_mask);
|
||||||
image,
|
const raw_pixel = if (dim == .SubpassData) blk: {
|
||||||
image_coord,
|
if (findInputAttachmentSnapshot(image_view, subresource)) |snapshot| {
|
||||||
subresource,
|
break :blk blitter.readInt4(try sampledSnapshotTexel(snapshot, image_coord, format, sample_index), format);
|
||||||
base.format.fromAspect(image_view.interface.format, aspect_mask),
|
}
|
||||||
sample_index,
|
break :blk readImageInt4Sample(image, image_coord, subresource, format, sample_index) catch return SpvRuntimeError.Unknown;
|
||||||
) catch return SpvRuntimeError.Unknown, image_view.interface.components);
|
} else readImageInt4Sample(image, image_coord, subresource, format, sample_index) catch return SpvRuntimeError.Unknown;
|
||||||
|
pixel = SoftSampler.swizzleInt4(raw_pixel, image_view.interface.components);
|
||||||
}
|
}
|
||||||
return .{
|
return .{
|
||||||
.x = pixel[0],
|
.x = pixel[0],
|
||||||
@@ -488,7 +543,9 @@ fn writeImageFloat4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32
|
|||||||
const vec_pixel = zm.f32x4(pixel.x, pixel.y, pixel.z, pixel.w);
|
const vec_pixel = zm.f32x4(pixel.x, pixel.y, pixel.z, pixel.w);
|
||||||
if (dim == .Buffer) {
|
if (dim == .Buffer) {
|
||||||
const buffer_view = try bufferViewFromContext(context);
|
const buffer_view = try bufferViewFromContext(context);
|
||||||
blitter.writeFloat4(vec_pixel, try mapBufferViewTexel(buffer_view, x), buffer_view.interface.format);
|
if (mapBufferViewTexel(buffer_view, x)) |texel| {
|
||||||
|
blitter.writeFloat4(vec_pixel, texel, buffer_view.interface.format);
|
||||||
|
} else |_| {}
|
||||||
} else {
|
} else {
|
||||||
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
|
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
|
||||||
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
|
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
|
||||||
@@ -514,7 +571,9 @@ fn writeImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32,
|
|||||||
const vec_pixel = @Vector(4, u32){ pixel.x, pixel.y, pixel.z, pixel.w };
|
const vec_pixel = @Vector(4, u32){ pixel.x, pixel.y, pixel.z, pixel.w };
|
||||||
if (dim == .Buffer) {
|
if (dim == .Buffer) {
|
||||||
const buffer_view = try bufferViewFromContext(context);
|
const buffer_view = try bufferViewFromContext(context);
|
||||||
blitter.writeInt4(vec_pixel, try mapBufferViewTexel(buffer_view, x), buffer_view.interface.format);
|
if (mapBufferViewTexel(buffer_view, x)) |texel| {
|
||||||
|
blitter.writeInt4(vec_pixel, texel, buffer_view.interface.format);
|
||||||
|
} else |_| {}
|
||||||
} else {
|
} else {
|
||||||
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
|
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
|
||||||
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
|
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
|
||||||
@@ -580,14 +639,14 @@ fn sampleImageInt4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sampleImageDref(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, dref: f32, lod: ?f32, offset: spv.Runtime.ImageOffset) SpvRuntimeError!f32 {
|
fn sampleImageDref(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, w: f32, dref: f32, lod: ?f32, offset: spv.Runtime.ImageOffset) SpvRuntimeError!f32 {
|
||||||
if (dim == .Buffer)
|
if (dim == .Buffer)
|
||||||
return SpvRuntimeError.UnsupportedSpirV;
|
return SpvRuntimeError.UnsupportedSpirV;
|
||||||
|
|
||||||
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
|
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
|
||||||
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
|
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
|
||||||
const sampler: *SoftSampler = @ptrCast(@alignCast(context2));
|
const sampler: *SoftSampler = @ptrCast(@alignCast(context2));
|
||||||
return SoftSampler.sampleImageDref(image, image_view, sampler, dim, x, y, z, dref, lod, offset) catch return SpvRuntimeError.Unknown;
|
return SoftSampler.sampleImageDref(image, image_view, sampler, dim, x, y, z, w, dref, lod, offset) catch return SpvRuntimeError.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn queryImageSize(context: *anyopaque, dim: spv.SpvDim, arrayed: bool, lod: ?i32) SpvRuntimeError!spv.Runtime.Vec4(u32) {
|
fn queryImageSize(context: *anyopaque, dim: spv.SpvDim, arrayed: bool, lod: ?i32) SpvRuntimeError!spv.Runtime.Vec4(u32) {
|
||||||
|
|||||||
@@ -422,6 +422,17 @@ fn readSampledFloat4At(context: *const ImageSamplingContext, ix: i32, iy: i32, i
|
|||||||
return swizzleFloat4(color, context.image_view.interface.components);
|
return swizzleFloat4(color, context.image_view.interface.components);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DepthCompareSamplingContext = struct {
|
||||||
|
image_context: ImageSamplingContext,
|
||||||
|
dref: f32,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn readDepthCompareAt(context: *const DepthCompareSamplingContext, ix: i32, iy: i32, iz: i32) VkError!F32x4 {
|
||||||
|
const color = try readSampledFloat4At(&context.image_context, ix, iy, iz);
|
||||||
|
const result: f32 = if (compareDepth(context.image_context.sampler.interface.compare_op, context.dref, color[0])) 1.0 else 0.0;
|
||||||
|
return zm.f32x4s(result);
|
||||||
|
}
|
||||||
|
|
||||||
fn readSampledInt4(
|
fn readSampledInt4(
|
||||||
image: *SoftImage,
|
image: *SoftImage,
|
||||||
image_view: *SoftImageView,
|
image_view: *SoftImageView,
|
||||||
@@ -562,6 +573,70 @@ pub fn sampleImageFloat4(image: *SoftImage, image_view: *SoftImageView, sampler:
|
|||||||
return sampleImageFloat4Level(image, image_view, sampler, dim, x, y, z, sampleMipLevel(image_view, sampler, lod), filter, offset);
|
return sampleImageFloat4Level(image, image_view, sampler, dim, x, y, z, sampleMipLevel(image_view, sampler, lod), filter, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sampleImageDrefLevel(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, w: f32, dref: f32, mip_level: u32, filter: vk.Filter, offset: ImageOffset) VkError!f32 {
|
||||||
|
const extent = image.getMipLevelExtent(mip_level);
|
||||||
|
const coord: CubeCoordinate = switch (image_view.interface.view_type) {
|
||||||
|
.@"1d_array" => .{
|
||||||
|
.u = x,
|
||||||
|
.v = y,
|
||||||
|
.face = 0,
|
||||||
|
},
|
||||||
|
.@"1d" => .{
|
||||||
|
.u = x,
|
||||||
|
.v = 0.0,
|
||||||
|
.face = 0,
|
||||||
|
},
|
||||||
|
.@"2d_array" => .{
|
||||||
|
.u = x,
|
||||||
|
.v = y,
|
||||||
|
.w = z,
|
||||||
|
.face = 0,
|
||||||
|
},
|
||||||
|
.cube => resolveCubeCoordinate(x, y, z),
|
||||||
|
.cube_array => blk: {
|
||||||
|
var coord = resolveCubeCoordinate(x, y, z);
|
||||||
|
coord.w = w;
|
||||||
|
break :blk coord;
|
||||||
|
},
|
||||||
|
else => .{
|
||||||
|
.u = x,
|
||||||
|
.v = y,
|
||||||
|
.w = z,
|
||||||
|
.face = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const scale_u: f32 = if (sampler.interface.unnormalized_coordinates == .true) 1.0 else @floatFromInt(extent.width);
|
||||||
|
const scale_v: f32 = if (sampler.interface.unnormalized_coordinates == .true) 1.0 else @floatFromInt(extent.height);
|
||||||
|
const scale_w: f32 = if (sampler.interface.unnormalized_coordinates == .true) 1.0 else @floatFromInt(extent.depth);
|
||||||
|
const image_context: ImageSamplingContext = .{
|
||||||
|
.image = image,
|
||||||
|
.image_view = image_view,
|
||||||
|
.sampler = sampler,
|
||||||
|
.dim = dim,
|
||||||
|
.coord = coord,
|
||||||
|
.mip_level = mip_level,
|
||||||
|
};
|
||||||
|
const context: DepthCompareSamplingContext = .{
|
||||||
|
.image_context = image_context,
|
||||||
|
.dref = dref,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = try sampleFloat4(
|
||||||
|
*const DepthCompareSamplingContext,
|
||||||
|
&context,
|
||||||
|
zm.f32x4(
|
||||||
|
coord.u * scale_u + @as(f32, @floatFromInt(offset.x)),
|
||||||
|
coord.v * scale_v + @as(f32, @floatFromInt(offset.y)),
|
||||||
|
coord.w * scale_w + @as(f32, @floatFromInt(offset.z)),
|
||||||
|
0.0,
|
||||||
|
),
|
||||||
|
filter,
|
||||||
|
image_view.interface.view_type == .@"3d",
|
||||||
|
readDepthCompareAt,
|
||||||
|
);
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sampleImageInt4(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32, offset: ImageOffset) VkError!U32x4 {
|
pub fn sampleImageInt4(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32, offset: ImageOffset) VkError!U32x4 {
|
||||||
const mip_level = sampleMipLevel(image_view, sampler, lod);
|
const mip_level = sampleMipLevel(image_view, sampler, lod);
|
||||||
const extent = image.getMipLevelExtent(mip_level);
|
const extent = image.getMipLevelExtent(mip_level);
|
||||||
@@ -611,11 +686,33 @@ pub fn sampleImageInt4(image: *SoftImage, image_view: *SoftImageView, sampler: *
|
|||||||
return swizzleInt4(color, image_view.interface.components);
|
return swizzleInt4(color, image_view.interface.components);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sampleImageDref(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, dref: f32, lod: ?f32, offset: ImageOffset) VkError!f32 {
|
pub fn sampleImageDref(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, w: f32, dref: f32, lod: ?f32, offset: ImageOffset) VkError!f32 {
|
||||||
|
if (sampler.interface.compare_enable == .false) {
|
||||||
const color = try sampleImageFloat4(image, image_view, sampler, dim, x, y, z, lod, offset);
|
const color = try sampleImageFloat4(image, image_view, sampler, dim, x, y, z, lod, offset);
|
||||||
if (sampler.interface.compare_enable == .false)
|
|
||||||
return color[0];
|
return color[0];
|
||||||
return if (compareDepth(sampler.interface.compare_op, dref, color[0])) 1.0 else 0.0;
|
}
|
||||||
|
|
||||||
|
const range = image_view.interface.subresource_range;
|
||||||
|
const mip_count = viewMipCount(image_view);
|
||||||
|
const clamped_lod = sampleLod(image_view, sampler, lod);
|
||||||
|
const filter = sampleFilter(sampler, clamped_lod);
|
||||||
|
|
||||||
|
if (mip_count > 1 and sampler.interface.mipmap_mode == .linear) {
|
||||||
|
const lower_lod = @floor(clamped_lod);
|
||||||
|
const upper_lod = @min(lower_lod + 1.0, @as(f32, @floatFromInt(mip_count - 1)));
|
||||||
|
const lower_level = range.base_mip_level + @as(u32, @intFromFloat(lower_lod));
|
||||||
|
const upper_level = range.base_mip_level + @as(u32, @intFromFloat(upper_lod));
|
||||||
|
const lower = try sampleImageDrefLevel(image, image_view, sampler, dim, x, y, z, w, dref, lower_level, filter, offset);
|
||||||
|
|
||||||
|
if (upper_level == lower_level)
|
||||||
|
return lower;
|
||||||
|
|
||||||
|
const upper = try sampleImageDrefLevel(image, image_view, sampler, dim, x, y, z, w, dref, upper_level, filter, offset);
|
||||||
|
const weight = clamped_lod - lower_lod;
|
||||||
|
return lower * (1.0 - weight) + upper * weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sampleImageDrefLevel(image, image_view, sampler, dim, x, y, z, w, dref, sampleMipLevel(image_view, sampler, lod), filter, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sampleFloat4(
|
pub fn sampleFloat4(
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ pub const DrawCall = struct {
|
|||||||
|
|
||||||
color_attachments: []*base.ImageView,
|
color_attachments: []*base.ImageView,
|
||||||
depth_attachment: ?*base.ImageView,
|
depth_attachment: ?*base.ImageView,
|
||||||
|
input_attachment_snapshots: []const SoftPipeline.InputAttachmentSnapshot,
|
||||||
|
|
||||||
render_pass: *SoftRenderPass,
|
render_pass: *SoftRenderPass,
|
||||||
framebuffer: *SoftFramebuffer,
|
framebuffer: *SoftFramebuffer,
|
||||||
@@ -99,6 +100,7 @@ pub const DrawCall = struct {
|
|||||||
.scissor = undefined,
|
.scissor = undefined,
|
||||||
.color_attachments = framebuffer.interface.attachments[0..],
|
.color_attachments = framebuffer.interface.attachments[0..],
|
||||||
.depth_attachment = if (render_pass.interface.subpasses[renderer.subpass_index].depth_stencil_attachments) |desc| framebuffer.interface.attachments[desc.attachment] else null,
|
.depth_attachment = if (render_pass.interface.subpasses[renderer.subpass_index].depth_stencil_attachments) |desc| framebuffer.interface.attachments[desc.attachment] else null,
|
||||||
|
.input_attachment_snapshots = &.{},
|
||||||
.render_pass = render_pass,
|
.render_pass = render_pass,
|
||||||
.framebuffer = framebuffer,
|
.framebuffer = framebuffer,
|
||||||
.rasterizer_wait_group = .init,
|
.rasterizer_wait_group = .init,
|
||||||
@@ -139,6 +141,7 @@ render_pass: ?*SoftRenderPass,
|
|||||||
framebuffer: ?*SoftFramebuffer,
|
framebuffer: ?*SoftFramebuffer,
|
||||||
render_area: ?vk.Rect2D,
|
render_area: ?vk.Rect2D,
|
||||||
dynamic_state: DynamicState,
|
dynamic_state: DynamicState,
|
||||||
|
input_attachment_snapshots: []const SoftPipeline.InputAttachmentSnapshot,
|
||||||
|
|
||||||
subpass_index: usize,
|
subpass_index: usize,
|
||||||
active_occlusion_queries: *std.ArrayList(ExecutionDevice.ActiveOcclusionQuery),
|
active_occlusion_queries: *std.ArrayList(ExecutionDevice.ActiveOcclusionQuery),
|
||||||
@@ -150,6 +153,7 @@ pub fn init(device: *SoftDevice, state: *PipelineState, active_occlusion_queries
|
|||||||
.render_pass = null,
|
.render_pass = null,
|
||||||
.framebuffer = null,
|
.framebuffer = null,
|
||||||
.render_area = null,
|
.render_area = null,
|
||||||
|
.input_attachment_snapshots = &.{},
|
||||||
.dynamic_state = .{
|
.dynamic_state = .{
|
||||||
.viewports = null,
|
.viewports = null,
|
||||||
.scissor = null,
|
.scissor = null,
|
||||||
@@ -167,6 +171,15 @@ pub fn init(device: *SoftDevice, state: *PipelineState, active_occlusion_queries
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resetInputAttachmentSnapshots(self: *Self) void {
|
||||||
|
const allocator = self.device.device_allocator.allocator();
|
||||||
|
for (self.input_attachment_snapshots) |snapshot| {
|
||||||
|
allocator.free(snapshot.data);
|
||||||
|
}
|
||||||
|
allocator.free(self.input_attachment_snapshots);
|
||||||
|
self.input_attachment_snapshots = &.{};
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
||||||
var bounded_allocator: BoundedAllocator = .init(self.device.device_allocator.allocator(), 4 * @"1GiB");
|
var bounded_allocator: BoundedAllocator = .init(self.device.device_allocator.allocator(), 4 * @"1GiB");
|
||||||
try self.drawCall(&bounded_allocator, vertex_count, instance_count, first_vertex, first_instance, null, null);
|
try self.drawCall(&bounded_allocator, vertex_count, instance_count, first_vertex, first_instance, null, null);
|
||||||
|
|||||||
@@ -193,7 +193,12 @@ fn sample(src: []const u8, pos: F32x4, dim: F32x4, slice_bytes: usize, pitch_byt
|
|||||||
const sample_stride = slice_bytes * @as(usize, @intFromFloat(dim[2]));
|
const sample_stride = slice_bytes * @as(usize, @intFromFloat(dim[2]));
|
||||||
color = zm.f32x4s(0.0);
|
color = zm.f32x4s(0.0);
|
||||||
for (0..state.src_samples) |sample_index| {
|
for (0..state.src_samples) |sample_index| {
|
||||||
color += readFloat4(src_map[sample_index * sample_stride ..], state.src_format);
|
var sample_color = readFloat4(src_map[sample_index * sample_stride ..], state.src_format);
|
||||||
|
if (state.allow_srgb_conversion and base.format.isSrgb(state.src_format)) {
|
||||||
|
sample_color = applyScaleAndClamp(sample_color, state, true);
|
||||||
|
apply_srgb_convertion = false;
|
||||||
|
}
|
||||||
|
color += sample_color;
|
||||||
}
|
}
|
||||||
color /= zm.f32x4s(@floatFromInt(state.src_samples));
|
color /= zm.f32x4s(@floatFromInt(state.src_samples));
|
||||||
} else {
|
} else {
|
||||||
@@ -350,7 +355,9 @@ pub fn blitRegionWithFormats(src: *const SoftImage, dst: *SoftImage, region: vk.
|
|||||||
const dst_row_pitch_bytes = dst.getRowPitchMemSizeForMipLevelWithFormat(region.dst_subresource.aspect_mask, region.dst_subresource.mip_level, dst_format);
|
const dst_row_pitch_bytes = dst.getRowPitchMemSizeForMipLevelWithFormat(region.dst_subresource.aspect_mask, region.dst_subresource.mip_level, dst_format);
|
||||||
|
|
||||||
const apply_filter = (filter != .nearest);
|
const apply_filter = (filter != .nearest);
|
||||||
const allow_srgb_conversion = apply_filter or base.format.isSrgb(src_format) != base.format.isSrgb(dst_format);
|
const resolve_srgb = src.interface.samples.toInt() > 1 and dst.interface.samples.toInt() == 1 and
|
||||||
|
base.format.isSrgb(src_format) and base.format.isSrgb(dst_format);
|
||||||
|
const allow_srgb_conversion = apply_filter or resolve_srgb or base.format.isSrgb(src_format) != base.format.isSrgb(dst_format);
|
||||||
|
|
||||||
var src_subresource = vk.ImageSubresource{
|
var src_subresource = vk.ImageSubresource{
|
||||||
.aspect_mask = region.src_subresource.aspect_mask,
|
.aspect_mask = region.src_subresource.aspect_mask,
|
||||||
|
|||||||
@@ -120,8 +120,9 @@ pub fn viewportTransformVertex(viewport: vk.Viewport, vertex: *Vertex) void {
|
|||||||
const o_y = viewport.y + viewport.height / 2.0;
|
const o_y = viewport.y + viewport.height / 2.0;
|
||||||
const o_z = viewport.min_depth;
|
const o_z = viewport.min_depth;
|
||||||
|
|
||||||
const x_screen = ((p_x / 2.0) * x_ndc) + o_x;
|
const subpixel_scale = 16.0;
|
||||||
const y_screen = ((p_y / 2.0) * y_ndc) + o_y;
|
const x_screen = @round((((p_x / 2.0) * x_ndc) + o_x) * subpixel_scale) / subpixel_scale;
|
||||||
|
const y_screen = @round((((p_y / 2.0) * y_ndc) + o_y) * subpixel_scale) / subpixel_scale;
|
||||||
const z_screen = (p_z * z_ndc) + o_z;
|
const z_screen = (p_z * z_ndc) + o_z;
|
||||||
|
|
||||||
vertex.position = zm.f32x4(x_screen, y_screen, z_screen, w);
|
vertex.position = zm.f32x4(x_screen, y_screen, z_screen, w);
|
||||||
|
|||||||
@@ -85,12 +85,15 @@ pub fn shaderInvocation(
|
|||||||
|
|
||||||
const SoftPipeline = @import("../SoftPipeline.zig");
|
const SoftPipeline = @import("../SoftPipeline.zig");
|
||||||
const previous_fragment_coord = SoftPipeline.current_fragment_coord;
|
const previous_fragment_coord = SoftPipeline.current_fragment_coord;
|
||||||
|
const previous_input_attachment_snapshots = SoftPipeline.current_input_attachment_snapshots;
|
||||||
SoftPipeline.current_fragment_coord = .{
|
SoftPipeline.current_fragment_coord = .{
|
||||||
.x = @intFromFloat(position[0]),
|
.x = @intFromFloat(position[0]),
|
||||||
.y = @intFromFloat(position[1]),
|
.y = @intFromFloat(position[1]),
|
||||||
.z = 0,
|
.z = 0,
|
||||||
};
|
};
|
||||||
|
SoftPipeline.current_input_attachment_snapshots = draw_call.input_attachment_snapshots;
|
||||||
defer SoftPipeline.current_fragment_coord = previous_fragment_coord;
|
defer SoftPipeline.current_fragment_coord = previous_fragment_coord;
|
||||||
|
defer SoftPipeline.current_input_attachment_snapshots = previous_input_attachment_snapshots;
|
||||||
|
|
||||||
const entry = try rt.getEntryPointByName(shader.entry);
|
const entry = try rt.getEntryPointByName(shader.entry);
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const Renderer = @import("Renderer.zig");
|
|||||||
const Vertex = Renderer.Vertex;
|
const Vertex = Renderer.Vertex;
|
||||||
const DrawCall = Renderer.DrawCall;
|
const DrawCall = Renderer.DrawCall;
|
||||||
const SoftImage = @import("../SoftImage.zig");
|
const SoftImage = @import("../SoftImage.zig");
|
||||||
|
const SoftPipeline = @import("../SoftPipeline.zig");
|
||||||
|
|
||||||
const VkError = base.VkError;
|
const VkError = base.VkError;
|
||||||
const SpvRuntimeError = spv.Runtime.RuntimeError;
|
const SpvRuntimeError = spv.Runtime.RuntimeError;
|
||||||
@@ -31,11 +32,84 @@ fn renderTargetSubresourceSize(image: *const SoftImage, image_view: *const base.
|
|||||||
return image.getMultiSampledLevelSize(aspect_mask, mip_level);
|
return image.getMultiSampledLevelSize(aspect_mask, mip_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn snapshotInputAttachments(allocator: std.mem.Allocator, draw_call: *DrawCall) VkError![]SoftPipeline.InputAttachmentSnapshot {
|
||||||
|
const subpass = draw_call.render_pass.interface.subpasses[draw_call.renderer.subpass_index];
|
||||||
|
const input_attachments = subpass.input_attachments orelse return &.{};
|
||||||
|
|
||||||
|
var snapshot_count: usize = 0;
|
||||||
|
for (input_attachments) |attachment_ref| {
|
||||||
|
if (attachment_ref.attachment == vk.ATTACHMENT_UNUSED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const image_view = draw_call.framebuffer.interface.attachments[attachment_ref.attachment];
|
||||||
|
if (image_view.image.samples.toInt() == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const range = image_view.subresource_range;
|
||||||
|
if (range.aspect_mask.depth_bit and range.aspect_mask.stencil_bit)
|
||||||
|
snapshot_count += 2
|
||||||
|
else
|
||||||
|
snapshot_count += 1;
|
||||||
|
}
|
||||||
|
if (snapshot_count == 0)
|
||||||
|
return &.{};
|
||||||
|
|
||||||
|
const snapshots = allocator.alloc(SoftPipeline.InputAttachmentSnapshot, snapshot_count) catch return VkError.OutOfDeviceMemory;
|
||||||
|
var snapshot_index: usize = 0;
|
||||||
|
errdefer {
|
||||||
|
for (snapshots[0..snapshot_index]) |snapshot| {
|
||||||
|
allocator.free(snapshot.data);
|
||||||
|
}
|
||||||
|
allocator.free(snapshots);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (input_attachments) |attachment_ref| {
|
||||||
|
if (attachment_ref.attachment == vk.ATTACHMENT_UNUSED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const image_view: *base.ImageView = draw_call.framebuffer.interface.attachments[attachment_ref.attachment];
|
||||||
|
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.image));
|
||||||
|
if (image.interface.samples.toInt() == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const range = image_view.subresource_range;
|
||||||
|
const aspects: []const vk.ImageAspectFlags = if (range.aspect_mask.depth_bit and range.aspect_mask.stencil_bit)
|
||||||
|
&.{ .{ .depth_bit = true }, .{ .stencil_bit = true } }
|
||||||
|
else
|
||||||
|
&.{range.aspect_mask};
|
||||||
|
|
||||||
|
for (aspects) |aspect_mask| {
|
||||||
|
const offset = try image.getSubresourceOffset(aspect_mask, range.base_mip_level, range.base_array_layer);
|
||||||
|
const size = renderTargetSubresourceSize(image, image_view, aspect_mask, range.base_mip_level);
|
||||||
|
const live_data = try image.mapAsSliceWithAddedOffset(u8, offset, size);
|
||||||
|
const data = allocator.dupe(u8, live_data) catch return VkError.OutOfDeviceMemory;
|
||||||
|
|
||||||
|
snapshots[snapshot_index] = .{
|
||||||
|
.image = image_view.image,
|
||||||
|
.aspect_mask = aspect_mask,
|
||||||
|
.mip_level = range.base_mip_level,
|
||||||
|
.array_layer = range.base_array_layer,
|
||||||
|
.data = data,
|
||||||
|
.row_pitch = image.getRowPitchMemSizeForMipLevelWithFormat(aspect_mask, range.base_mip_level, image_view.format),
|
||||||
|
.slice_pitch = image.getSliceMemSizeForMipLevelWithFormat(aspect_mask, range.base_mip_level, image_view.format),
|
||||||
|
.sample_stride = image.getMipLevelSize(aspect_mask, range.base_mip_level),
|
||||||
|
};
|
||||||
|
snapshot_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return snapshots;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocator, draw_call: *DrawCall) VkError!void {
|
pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocator, draw_call: *DrawCall) VkError!void {
|
||||||
const io = draw_call.renderer.device.interface.io();
|
const io = draw_call.renderer.device.interface.io();
|
||||||
|
|
||||||
const pipeline_data = (renderer.state.pipeline orelse return VkError.InvalidHandleDrv).interface.mode.graphics;
|
const pipeline_data = (renderer.state.pipeline orelse return VkError.InvalidHandleDrv).interface.mode.graphics;
|
||||||
const topology = pipeline_data.input_assembly.topology;
|
const topology = pipeline_data.input_assembly.topology;
|
||||||
|
if (renderer.input_attachment_snapshots.len == 0) {
|
||||||
|
renderer.input_attachment_snapshots = try snapshotInputAttachments(renderer.device.device_allocator.allocator(), draw_call);
|
||||||
|
}
|
||||||
|
draw_call.input_attachment_snapshots = renderer.input_attachment_snapshots;
|
||||||
|
|
||||||
const color_attachments = draw_call.render_pass.interface.subpasses[renderer.subpass_index].color_attachments orelse &.{};
|
const color_attachments = draw_call.render_pass.interface.subpasses[renderer.subpass_index].color_attachments orelse &.{};
|
||||||
const color_attachment_access = allocator.alloc(?common.RenderTargetAccess, color_attachments.len) catch return VkError.OutOfDeviceMemory;
|
const color_attachment_access = allocator.alloc(?common.RenderTargetAccess, color_attachments.len) catch return VkError.OutOfDeviceMemory;
|
||||||
|
|||||||
@@ -90,9 +90,16 @@ inline fn run(data: RunData) !void {
|
|||||||
};
|
};
|
||||||
const offset = buffer.interface.offset + vertex_buffer.offset + (binding_info.stride * input_index) + attribute.offset;
|
const offset = buffer.interface.offset + vertex_buffer.offset + (binding_info.stride * input_index) + attribute.offset;
|
||||||
|
|
||||||
const buffer_memory_map: []u8 = try buffer_memory.map(offset, buffer_memory_size);
|
var robust_vertex_bytes: [64]u8 = @splat(0);
|
||||||
|
if (buffer_memory_size > robust_vertex_bytes.len)
|
||||||
|
return VkError.Unknown;
|
||||||
|
if (offset < buffer_memory.size) {
|
||||||
|
const available = @min(buffer_memory_size, @as(usize, @intCast(buffer_memory.size - offset)));
|
||||||
|
const buffer_memory_map: []const u8 = buffer_memory.map(offset, available) catch &.{};
|
||||||
|
@memcpy(robust_vertex_bytes[0..buffer_memory_map.len], buffer_memory_map);
|
||||||
|
}
|
||||||
|
|
||||||
try writeVertexInput(rt, data.allocator, buffer_memory_map, attribute.format, attribute.location);
|
try writeVertexInput(rt, data.allocator, robust_vertex_bytes[0..buffer_memory_size], attribute.format, attribute.location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user