adding primitive restart, integer texture sampling and mip/lod management in sampling
Test / build_and_test (push) Successful in 49s
Build / build (push) Successful in 1m0s

This commit is contained in:
2026-06-05 22:16:28 +02:00
parent b1279bde60
commit c7a298978a
10 changed files with 469 additions and 113 deletions
+4 -4
View File
@@ -22,12 +22,12 @@
.hash = "zmath-0.11.0-dev-wjwivdMsAwD-xaLj76YHUq3t9JDH-X16xuMTmnDzqbu2", .hash = "zmath-0.11.0-dev-wjwivdMsAwD-xaLj76YHUq3t9JDH-X16xuMTmnDzqbu2",
}, },
.cts_bin = .{ .cts_bin = .{
.url = "git+https://git.kbz8.me/kbz_8/Vulkan-CTS-bin.git#a5f787d80f14f136e3cb3e1185c35e298846c1d7", .url = "git+https://git.kbz8.me/kbz_8/Vulkan-CTS-bin.git#b316a134bc0aa7ac21d9c57a1df588809824dcdc",
.hash = "N-V-__8AAMpOQxkHCKTw9i-NwmmQ3ks1ndFDXcVLlic4KjK3", .hash = "N-V-__8AAF9uOh0I4P_99za7N822J3JwsDaqONrFVrcEQo59",
}, },
.SPIRV_Interpreter = .{ .SPIRV_Interpreter = .{
.url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#fb6e5beefffe3608173bdda62dc0a922f02ba447", .url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#7c6da62e3cc6e58260527abef6e2e161e45d7f84",
.hash = "SPIRV_Interpreter-0.0.1-ajmpn3cFBgALga_tgLo12tFEVRlR8m6fIjFIv41KVCcn", .hash = "SPIRV_Interpreter-0.0.1-ajmpnzALBgCxqYfFMsc_moezDHsaeKyImzHXuJ7dYffX",
.lazy = true, .lazy = true,
}, },
//.SPIRV_Interpreter = .{ //.SPIRV_Interpreter = .{
+28 -2
View File
@@ -102,6 +102,7 @@ pub fn createCompute(device: *base.Device, allocator: std.mem.Allocator, cache:
.writeImageFloat4 = writeImageFloat4, .writeImageFloat4 = writeImageFloat4,
.writeImageInt4 = writeImageInt4, .writeImageInt4 = writeImageInt4,
.sampleImageFloat4 = sampleImageFloat4, .sampleImageFloat4 = sampleImageFloat4,
.sampleImageInt4 = sampleImageInt4,
.queryImageSize = queryImageSize, .queryImageSize = queryImageSize,
}, },
) catch |err| { ) catch |err| {
@@ -188,6 +189,7 @@ pub fn createGraphics(device: *base.Device, allocator: std.mem.Allocator, cache:
.writeImageFloat4 = writeImageFloat4, .writeImageFloat4 = writeImageFloat4,
.writeImageInt4 = writeImageInt4, .writeImageInt4 = writeImageInt4,
.sampleImageFloat4 = sampleImageFloat4, .sampleImageFloat4 = sampleImageFloat4,
.sampleImageInt4 = sampleImageInt4,
.queryImageSize = queryImageSize, .queryImageSize = queryImageSize,
}, },
) catch |err| { ) catch |err| {
@@ -378,7 +380,7 @@ fn writeImageInt4(context: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32,
} }
} }
fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32) SpvRuntimeError!spv.Runtime.Vec4(f32) { fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32) SpvRuntimeError!spv.Runtime.Vec4(f32) {
var pixel = zm.f32x4s(0.0); var pixel = zm.f32x4s(0.0);
if (dim == .Buffer) { if (dim == .Buffer) {
@@ -391,7 +393,31 @@ fn sampleImageFloat4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim,
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));
pixel = SoftSampler.sampleImageFloat4(image, image_view, sampler, dim, x, y, z) catch return SpvRuntimeError.Unknown; pixel = SoftSampler.sampleImageFloat4(image, image_view, sampler, dim, x, y, z, lod) catch return SpvRuntimeError.Unknown;
}
return .{
.x = pixel[0],
.y = pixel[1],
.z = pixel[2],
.w = pixel[3],
};
}
fn sampleImageInt4(context: *anyopaque, context2: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32) SpvRuntimeError!spv.Runtime.Vec4(u32) {
var pixel = @Vector(4, u32){ 0, 0, 0, 0 };
if (dim == .Buffer) {
const buffer_view: *SoftBufferView = @ptrCast(@alignCast(context));
const buffer: *SoftBuffer = @alignCast(@fieldParentPtr("interface", buffer_view.interface.buffer));
const map = buffer.mapAsSliceWithOffset(u8, buffer_view.interface.offset, buffer_view.interface.range) catch return SpvRuntimeError.Unknown;
_ = map;
} else {
const image_view: *SoftImageView = @ptrCast(@alignCast(context));
const image: *SoftImage = @alignCast(@fieldParentPtr("interface", image_view.interface.image));
const sampler: *SoftSampler = @ptrCast(@alignCast(context2));
pixel = SoftSampler.sampleImageInt4(image, image_view, sampler, dim, x, y, z, lod) catch return SpvRuntimeError.Unknown;
} }
return .{ return .{
+251 -18
View File
@@ -3,10 +3,12 @@ const vk = @import("vulkan");
const base = @import("base"); const base = @import("base");
const spv = @import("spv"); const spv = @import("spv");
const zm = base.zm; const zm = base.zm;
const blitter = @import("device/blitter.zig");
const VkError = base.VkError; const VkError = base.VkError;
const Device = base.Device; const Device = base.Device;
const F32x4 = zm.F32x4; const F32x4 = zm.F32x4;
const U32x4 = blitter.U32x4;
const SoftImage = @import("SoftImage.zig"); const SoftImage = @import("SoftImage.zig");
const SoftImageView = @import("SoftImageView.zig"); const SoftImageView = @import("SoftImageView.zig");
@@ -27,6 +29,7 @@ const ImageSamplingContext = struct {
sampler: *Self, sampler: *Self,
dim: spv.SpvDim, dim: spv.SpvDim,
coord: CubeCoordinate, coord: CubeCoordinate,
mip_level: u32,
}; };
interface: Interface, interface: Interface,
@@ -138,12 +141,52 @@ fn sampleAddressOrBorder(coord: i32, extent: u32, mode: vk.SamplerAddressMode) ?
}; };
} }
fn samplerBorderColor(sampler: *Self) F32x4 { fn samplerBorderColor(sampler: *Self, format: vk.Format) F32x4 {
return switch (sampler.interface.border_color) { var color: F32x4 = switch (sampler.interface.border_color) {
.float_opaque_white, .int_opaque_white => .{ 1.0, 1.0, 1.0, 1.0 }, .float_opaque_white, .int_opaque_white => .{ 1.0, 1.0, 1.0, 1.0 },
.float_opaque_black, .int_opaque_black => .{ 0.0, 0.0, 0.0, 1.0 }, .float_opaque_black, .int_opaque_black => .{ 0.0, 0.0, 0.0, 1.0 },
else => .{ 0.0, 0.0, 0.0, 0.0 }, else => .{ 0.0, 0.0, 0.0, 0.0 },
}; };
switch (base.format.componentCount(format)) {
1 => {
color[1] = 0.0;
color[2] = 0.0;
color[3] = 1.0;
},
2 => {
color[2] = 0.0;
color[3] = 1.0;
},
3 => color[3] = 1.0,
else => {},
}
return color;
}
fn samplerBorderColorInt(sampler: *Self, format: vk.Format) U32x4 {
var color: U32x4 = switch (sampler.interface.border_color) {
.float_opaque_white, .int_opaque_white => .{ 1, 1, 1, 1 },
.float_opaque_black, .int_opaque_black => .{ 0, 0, 0, 1 },
else => .{ 0, 0, 0, 0 },
};
switch (base.format.componentCount(format)) {
1 => {
color[1] = 0;
color[2] = 0;
color[3] = 1;
},
2 => {
color[2] = 0;
color[3] = 1;
},
3 => color[3] = 1,
else => {},
}
return color;
} }
fn viewLayerCount(image: *SoftImage, range: vk.ImageSubresourceRange) u32 { fn viewLayerCount(image: *SoftImage, range: vk.ImageSubresourceRange) u32 {
@@ -153,23 +196,100 @@ fn viewLayerCount(image: *SoftImage, range: vk.ImageSubresourceRange) u32 {
range.layer_count; range.layer_count;
} }
fn viewMipCount(image: *SoftImage, range: vk.ImageSubresourceRange) u32 {
return if (range.level_count == vk.REMAINING_MIP_LEVELS)
image.interface.mip_levels - range.base_mip_level
else
range.level_count;
}
fn sampleMipLevel(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, lod: ?f32) u32 {
const range = image_view.interface.subresource_range;
const mip_count = viewMipCount(image, range);
if (mip_count <= 1)
return range.base_mip_level;
const requested_lod = if (lod) |explicit_lod|
explicit_lod + sampler.interface.mip_lod_bias
else
sampler.interface.min_lod;
const clamped_lod = std.math.clamp(requested_lod, sampler.interface.min_lod, sampler.interface.max_lod);
const level_float = switch (sampler.interface.mipmap_mode) {
.nearest => @round(clamped_lod),
else => @floor(clamped_lod),
};
const level: u32 = @intFromFloat(std.math.clamp(level_float, 0.0, @as(f32, @floatFromInt(mip_count - 1))));
return range.base_mip_level + level;
}
fn sampleArrayLayer(coord: f32, layer_count: u32) u32 { fn sampleArrayLayer(coord: f32, layer_count: u32) u32 {
const layer_coord: i32 = @intFromFloat(@floor(coord + 0.5)); const layer_coord: i32 = @intFromFloat(@floor(coord + 0.5));
return @intCast(sampleAddress(layer_coord, layer_count, .clamp_to_edge)); return @intCast(sampleAddress(layer_coord, layer_count, .clamp_to_edge));
} }
fn sampledFormat(image_view: *SoftImageView) vk.Format {
const range = image_view.interface.subresource_range;
return base.format.fromAspect(image_view.interface.format, range.aspect_mask);
}
fn swizzleFloatComponent(color: F32x4, swizzle: vk.ComponentSwizzle, comptime identity_index: usize) f32 {
return switch (swizzle) {
.identity => color[identity_index],
.zero => 0.0,
.one => 1.0,
.r => color[0],
.g => color[1],
.b => color[2],
.a => color[3],
else => color[identity_index],
};
}
fn swizzleFloat4(color: F32x4, components: vk.ComponentMapping) F32x4 {
return .{
swizzleFloatComponent(color, components.r, 0),
swizzleFloatComponent(color, components.g, 1),
swizzleFloatComponent(color, components.b, 2),
swizzleFloatComponent(color, components.a, 3),
};
}
fn swizzleIntComponent(color: U32x4, swizzle: vk.ComponentSwizzle, comptime identity_index: usize) u32 {
return switch (swizzle) {
.identity => color[identity_index],
.zero => 0,
.one => 1,
.r => color[0],
.g => color[1],
.b => color[2],
.a => color[3],
else => color[identity_index],
};
}
fn swizzleInt4(color: U32x4, components: vk.ComponentMapping) U32x4 {
return .{
swizzleIntComponent(color, components.r, 0),
swizzleIntComponent(color, components.g, 1),
swizzleIntComponent(color, components.b, 2),
swizzleIntComponent(color, components.a, 3),
};
}
fn readSampledFloat4( fn readSampledFloat4(
image: *SoftImage, image: *SoftImage,
image_view: *SoftImageView, image_view: *SoftImageView,
sampler: *Self, sampler: *Self,
dim: spv.SpvDim, dim: spv.SpvDim,
coord: CubeCoordinate, coord: CubeCoordinate,
mip_level: u32,
ix: i32, ix: i32,
iy: i32, iy: i32,
iz: i32, iz: i32,
) VkError!F32x4 { ) VkError!F32x4 {
const range = image_view.interface.subresource_range; const range = image_view.interface.subresource_range;
const extent = image.getMipLevelExtent(range.base_mip_level); const format = sampledFormat(image_view);
const extent = image.getMipLevelExtent(mip_level);
const width_f: f32 = @floatFromInt(extent.width); const width_f: f32 = @floatFromInt(extent.width);
const height_f: f32 = @floatFromInt(extent.height); const height_f: f32 = @floatFromInt(extent.height);
@@ -186,7 +306,7 @@ fn readSampledFloat4(
.@"1d_array" => .{ 0, range.base_array_layer + sampleArrayLayer(coord.v, viewLayerCount(image, range)) }, .@"1d_array" => .{ 0, range.base_array_layer + sampleArrayLayer(coord.v, viewLayerCount(image, range)) },
.@"2d_array" => .{ 0, range.base_array_layer + sampleArrayLayer(coord.w, viewLayerCount(image, range)) }, .@"2d_array" => .{ 0, range.base_array_layer + sampleArrayLayer(coord.w, viewLayerCount(image, range)) },
.cube_array => .{ 0, range.base_array_layer + sampleArrayLayer(coord.w, @divTrunc(viewLayerCount(image, range), 6)) * 6 + texel.face }, .cube_array => .{ 0, range.base_array_layer + sampleArrayLayer(coord.w, @divTrunc(viewLayerCount(image, range), 6)) * 6 + texel.face },
.@"3d" => .{ sampleAddressOrBorder(iz, extent.depth, sampler.interface.address_mode_w) orelse return samplerBorderColor(sampler), range.base_array_layer }, .@"3d" => .{ sampleAddressOrBorder(iz, extent.depth, sampler.interface.address_mode_w) orelse return samplerBorderColor(sampler, format), range.base_array_layer },
.cube => .{ 0, range.base_array_layer + texel.face }, .cube => .{ 0, range.base_array_layer + texel.face },
else => .{ 0, range.base_array_layer }, else => .{ 0, range.base_array_layer },
}; };
@@ -194,13 +314,13 @@ fn readSampledFloat4(
const sx = if (dim == .Cube) const sx = if (dim == .Cube)
std.math.clamp(@as(i32, @intFromFloat(texel.u * width_f)), 0, @as(i32, @intCast(extent.width)) - 1) std.math.clamp(@as(i32, @intFromFloat(texel.u * width_f)), 0, @as(i32, @intCast(extent.width)) - 1)
else else
sampleAddressOrBorder(ix, extent.width, sampler.interface.address_mode_u) orelse return samplerBorderColor(sampler); sampleAddressOrBorder(ix, extent.width, sampler.interface.address_mode_u) orelse return samplerBorderColor(sampler, format);
const sy = if (dim == .Cube) const sy = if (dim == .Cube)
std.math.clamp(@as(i32, @intFromFloat(texel.v * height_f)), 0, @as(i32, @intCast(extent.height)) - 1) std.math.clamp(@as(i32, @intFromFloat(texel.v * height_f)), 0, @as(i32, @intCast(extent.height)) - 1)
else else
sampleAddressOrBorder(iy, extent.height, sampler.interface.address_mode_v) orelse return samplerBorderColor(sampler); sampleAddressOrBorder(iy, extent.height, sampler.interface.address_mode_v) orelse return samplerBorderColor(sampler, format);
return image.readFloat4( const color = try image.readFloat4(
.{ .{
.x = sx, .x = sx,
.y = sy, .y = sy,
@@ -208,28 +328,91 @@ fn readSampledFloat4(
}, },
.{ .{
.aspect_mask = range.aspect_mask, .aspect_mask = range.aspect_mask,
.mip_level = range.base_mip_level, .mip_level = mip_level,
.array_layer = layer, .array_layer = layer,
}, },
image_view.interface.format, format,
); );
return if (base.format.isSrgb(format)) zm.srgbToRgb(color) else color;
} }
fn readSampledFloat4At(context: *const ImageSamplingContext, ix: i32, iy: i32, iz: i32) VkError!F32x4 { fn readSampledFloat4At(context: *const ImageSamplingContext, ix: i32, iy: i32, iz: i32) VkError!F32x4 {
return readSampledFloat4( const color = try readSampledFloat4(
context.image, context.image,
context.image_view, context.image_view,
context.sampler, context.sampler,
context.dim, context.dim,
context.coord, context.coord,
context.mip_level,
ix, ix,
iy, iy,
iz, iz,
); );
return swizzleFloat4(color, context.image_view.interface.components);
} }
pub fn sampleImageFloat4(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32) VkError!F32x4 { fn readSampledInt4(
const extent = image.getMipLevelExtent(image_view.interface.subresource_range.base_mip_level); image: *SoftImage,
image_view: *SoftImageView,
sampler: *Self,
dim: spv.SpvDim,
coord: CubeCoordinate,
mip_level: u32,
ix: i32,
iy: i32,
iz: i32,
) VkError!U32x4 {
const range = image_view.interface.subresource_range;
const format = sampledFormat(image_view);
const extent = image.getMipLevelExtent(mip_level);
const width_f: f32 = @floatFromInt(extent.width);
const height_f: f32 = @floatFromInt(extent.height);
const texel = if (dim == .Cube) blk: {
const dir = cubeDirection(
coord.face,
(@as(f32, @floatFromInt(ix)) + 0.5) / width_f,
(@as(f32, @floatFromInt(iy)) + 0.5) / height_f,
);
break :blk resolveCubeCoordinate(dir.x, dir.y, dir.z);
} else coord;
const z: i32, const layer: u32 = switch (image_view.interface.view_type) {
.@"1d_array" => .{ 0, range.base_array_layer + sampleArrayLayer(coord.v, viewLayerCount(image, range)) },
.@"2d_array" => .{ 0, range.base_array_layer + sampleArrayLayer(coord.w, viewLayerCount(image, range)) },
.cube_array => .{ 0, range.base_array_layer + sampleArrayLayer(coord.w, @divTrunc(viewLayerCount(image, range), 6)) * 6 + texel.face },
.@"3d" => .{ sampleAddressOrBorder(iz, extent.depth, sampler.interface.address_mode_w) orelse return samplerBorderColorInt(sampler, format), range.base_array_layer },
.cube => .{ 0, range.base_array_layer + texel.face },
else => .{ 0, range.base_array_layer },
};
const sx = if (dim == .Cube)
std.math.clamp(@as(i32, @intFromFloat(texel.u * width_f)), 0, @as(i32, @intCast(extent.width)) - 1)
else
sampleAddressOrBorder(ix, extent.width, sampler.interface.address_mode_u) orelse return samplerBorderColorInt(sampler, format);
const sy = if (dim == .Cube)
std.math.clamp(@as(i32, @intFromFloat(texel.v * height_f)), 0, @as(i32, @intCast(extent.height)) - 1)
else
sampleAddressOrBorder(iy, extent.height, sampler.interface.address_mode_v) orelse return samplerBorderColorInt(sampler, format);
return image.readInt4(
.{
.x = sx,
.y = sy,
.z = z,
},
.{
.aspect_mask = range.aspect_mask,
.mip_level = mip_level,
.array_layer = layer,
},
format,
);
}
pub fn sampleImageFloat4(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32) VkError!F32x4 {
const mip_level = sampleMipLevel(image, image_view, sampler, lod);
const extent = image.getMipLevelExtent(mip_level);
const coord: CubeCoordinate = switch (image_view.interface.view_type) { const coord: CubeCoordinate = switch (image_view.interface.view_type) {
.@"1d_array" => .{ .@"1d_array" => .{
.u = x, .u = x,
@@ -255,21 +438,25 @@ pub fn sampleImageFloat4(image: *SoftImage, image_view: *SoftImageView, sampler:
.face = 0, .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 context: ImageSamplingContext = .{ const context: ImageSamplingContext = .{
.image = image, .image = image,
.image_view = image_view, .image_view = image_view,
.sampler = sampler, .sampler = sampler,
.dim = dim, .dim = dim,
.coord = coord, .coord = coord,
.mip_level = mip_level,
}; };
return sampleFloat4( return sampleFloat4(
*const ImageSamplingContext, *const ImageSamplingContext,
&context, &context,
zm.f32x4( zm.f32x4(
coord.u * @as(f32, @floatFromInt(extent.width)), coord.u * scale_u,
coord.v * @as(f32, @floatFromInt(extent.height)), coord.v * scale_v,
coord.w * @as(f32, @floatFromInt(extent.depth)), coord.w * scale_w,
0.0, 0.0,
), ),
switch (sampler.interface.mag_filter) { switch (sampler.interface.mag_filter) {
@@ -281,6 +468,52 @@ pub fn sampleImageFloat4(image: *SoftImage, image_view: *SoftImageView, sampler:
); );
} }
pub fn sampleImageInt4(image: *SoftImage, image_view: *SoftImageView, sampler: *Self, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32) VkError!U32x4 {
const mip_level = sampleMipLevel(image, image_view, sampler, lod);
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, .cube_array => resolveCubeCoordinate(x, y, z),
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 color = try readSampledInt4(
image,
image_view,
sampler,
dim,
coord,
mip_level,
@intFromFloat(@floor(coord.u * scale_u)),
@intFromFloat(@floor(coord.v * scale_v)),
@intFromFloat(@floor(coord.w * scale_w)),
);
return swizzleInt4(color, image_view.interface.components);
}
pub fn sampleFloat4( pub fn sampleFloat4(
comptime Context: type, comptime Context: type,
context: Context, context: Context,
@@ -292,9 +525,9 @@ pub fn sampleFloat4(
if (filter == .nearest) { if (filter == .nearest) {
return read( return read(
context, context,
@intFromFloat(pos[0]), @intFromFloat(@floor(pos[0])),
@intFromFloat(pos[1]), @intFromFloat(@floor(pos[1])),
@intFromFloat(pos[2]), @intFromFloat(@floor(pos[2])),
); );
} }
+42 -10
View File
@@ -53,6 +53,7 @@ pub const DynamicState = struct {
}; };
pub const Vertex = struct { pub const Vertex = struct {
primitive_restart: bool,
position: F32x4, position: F32x4,
outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][4]?struct { outputs: [spv.SPIRV_MAX_OUTPUT_LOCATIONS][4]?struct {
interpolation_type: enum { smooth, flat, noperspective }, interpolation_type: enum { smooth, flat, noperspective },
@@ -100,6 +101,7 @@ pub const DrawCall = struct {
}; };
for (self.vertices) |*vertex| { for (self.vertices) |*vertex| {
vertex.primitive_restart = false;
for (&vertex.outputs) |*location| { for (&vertex.outputs) |*location| {
@memset(location, null); @memset(location, null);
} }
@@ -157,19 +159,19 @@ pub fn init(device: *SoftDevice, state: *PipelineState, active_occlusion_queries
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(), @"1GiB"); var bounded_allocator: BoundedAllocator = .init(self.device.device_allocator.allocator(), @"1GiB");
try self.drawCall(&bounded_allocator, vertex_count, instance_count, first_vertex, first_instance, null); try self.drawCall(&bounded_allocator, vertex_count, instance_count, first_vertex, first_instance, null, null);
} }
pub fn drawIndexed(self: *Self, index_count: usize, instance_count: usize, first_index: usize, first_instance: usize, vertex_offset: i32) VkError!void { pub fn drawIndexed(self: *Self, index_count: usize, instance_count: usize, first_index: usize, first_instance: usize, vertex_offset: i32) VkError!void {
var bounded_allocator: BoundedAllocator = .init(self.device.device_allocator.allocator(), @"1GiB"); var bounded_allocator: BoundedAllocator = .init(self.device.device_allocator.allocator(), @"1GiB");
const allocator = bounded_allocator.allocator(); const allocator = bounded_allocator.allocator();
const indices = try self.readIndexBuffer(allocator, index_count, first_index, vertex_offset); const indexed_draw = try self.readIndexBuffer(allocator, index_count, first_index, vertex_offset);
try self.drawCall(&bounded_allocator, index_count, instance_count, 0, first_instance, indices); try self.drawCall(&bounded_allocator, index_count, instance_count, 0, first_instance, indexed_draw.indices, indexed_draw.primitive_restart);
} }
fn drawCall(self: *Self, bounded_allocator: *BoundedAllocator, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize, indices: ?[]const i32) VkError!void { fn drawCall(self: *Self, bounded_allocator: *BoundedAllocator, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize, indices: ?[]const u32, primitive_restart: ?[]const bool) VkError!void {
const io = self.device.interface.io(); const io = self.device.interface.io();
const allocator = bounded_allocator.allocator(); const allocator = bounded_allocator.allocator();
@@ -215,7 +217,7 @@ fn drawCall(self: *Self, bounded_allocator: *BoundedAllocator, vertex_count: usi
} }
} }
self.vertexShaderStage(allocator, &draw_call, vertex_count, instance_count, first_vertex, first_instance, indices) catch |err| { self.vertexShaderStage(allocator, &draw_call, vertex_count, instance_count, first_vertex, first_instance, indices, primitive_restart) catch |err| {
std.log.scoped(.@"Vertex stage").err("catched a '{s}'", .{@errorName(err)}); std.log.scoped(.@"Vertex stage").err("catched a '{s}'", .{@errorName(err)});
if (comptime base.config.logs == .verbose) { if (comptime base.config.logs == .verbose) {
if (@errorReturnTrace()) |trace| { if (@errorReturnTrace()) |trace| {
@@ -232,7 +234,7 @@ fn drawCall(self: *Self, bounded_allocator: *BoundedAllocator, vertex_count: usi
try rasterizer.processThenFragmentStage(self, allocator, &draw_call); try rasterizer.processThenFragmentStage(self, allocator, &draw_call);
} }
fn vertexShaderStage(self: *Self, allocator: std.mem.Allocator, draw_call: *DrawCall, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize, indices: ?[]const i32) !void { fn vertexShaderStage(self: *Self, allocator: std.mem.Allocator, draw_call: *DrawCall, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize, indices: ?[]const u32, primitive_restart: ?[]const bool) !void {
const pipeline = self.state.pipeline orelse return; const pipeline = self.state.pipeline orelse return;
const batch_size = (pipeline.stages.getPtr(.vertex) orelse return).runtimes.len; const batch_size = (pipeline.stages.getPtr(.vertex) orelse return).runtimes.len;
@@ -248,6 +250,7 @@ fn vertexShaderStage(self: *Self, allocator: std.mem.Allocator, draw_call: *Draw
.first_vertex = first_vertex, .first_vertex = first_vertex,
.first_instance = first_instance, .first_instance = first_instance,
.indices = indices, .indices = indices,
.primitive_restart = primitive_restart,
.instance_index = instance_index, .instance_index = instance_index,
.draw_call = draw_call, .draw_call = draw_call,
}; };
@@ -258,7 +261,12 @@ fn vertexShaderStage(self: *Self, allocator: std.mem.Allocator, draw_call: *Draw
wg.await(self.device.interface.io()) catch return VkError.DeviceLost; wg.await(self.device.interface.io()) catch return VkError.DeviceLost;
} }
fn readIndexBuffer(self: *Self, allocator: std.mem.Allocator, index_count: usize, first_index: usize, vertex_offset: i32) VkError![]i32 { const IndexedDrawData = struct {
indices: []u32,
primitive_restart: ?[]bool,
};
fn readIndexBuffer(self: *Self, allocator: std.mem.Allocator, index_count: usize, first_index: usize, vertex_offset: i32) VkError!IndexedDrawData {
const index_buffer = self.state.data.graphics.index_buffer; const index_buffer = self.state.data.graphics.index_buffer;
const buffer = index_buffer.buffer; const buffer = index_buffer.buffer;
const buffer_memory = if (buffer.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv; const buffer_memory = if (buffer.interface.memory) |memory| memory else return VkError.InvalidDeviceMemoryDrv;
@@ -271,7 +279,11 @@ fn readIndexBuffer(self: *Self, allocator: std.mem.Allocator, index_count: usize
const byte_size = index_count * index_size; const byte_size = index_count * index_size;
const index_memory: []const u8 = try buffer_memory.map(byte_offset, byte_size); const index_memory: []const u8 = try buffer_memory.map(byte_offset, byte_size);
const indices = allocator.alloc(i32, index_count) catch return VkError.OutOfDeviceMemory; const indices = allocator.alloc(u32, index_count) catch return VkError.OutOfDeviceMemory;
const restart_enabled = (self.state.pipeline orelse return VkError.InvalidPipelineDrv).interface.mode.graphics.input_assembly.primitive_restart_enable == .true;
const restart_index = primitiveRestartIndex(index_buffer.index_type);
const primitive_restart = if (restart_enabled) allocator.alloc(bool, index_count) catch return VkError.OutOfDeviceMemory else null;
for (indices, 0..) |*index, i| { for (indices, 0..) |*index, i| {
const offset = i * index_size; const offset = i * index_size;
const raw_index: u32 = switch (index_size) { const raw_index: u32 = switch (index_size) {
@@ -280,10 +292,21 @@ fn readIndexBuffer(self: *Self, allocator: std.mem.Allocator, index_count: usize
4 => @intCast(std.mem.readInt(u32, index_memory[offset..][0..4], .little)), 4 => @intCast(std.mem.readInt(u32, index_memory[offset..][0..4], .little)),
else => unreachable, else => unreachable,
}; };
index.* = vertex_offset + @as(i32, @intCast(raw_index)); if (primitive_restart) |restart| {
restart[i] = raw_index == restart_index;
if (restart[i]) {
index.* = 0;
continue;
}
}
const shifted = @as(i64, raw_index) + @as(i64, vertex_offset);
index.* = @as(u32, @truncate(@as(u64, @bitCast(shifted))));
} }
return indices; return .{
.indices = indices,
.primitive_restart = primitive_restart,
};
} }
fn indexTypeSize(index_type: vk.IndexType) ?usize { fn indexTypeSize(index_type: vk.IndexType) ?usize {
@@ -295,6 +318,15 @@ fn indexTypeSize(index_type: vk.IndexType) ?usize {
}; };
} }
fn primitiveRestartIndex(index_type: vk.IndexType) u32 {
return switch (index_type) {
.uint8 => std.math.maxInt(u8),
.uint16 => std.math.maxInt(u16),
.uint32 => std.math.maxInt(u32),
else => unreachable,
};
}
fn resolveViewport(self: *Self, viewport_index: usize) VkError!vk.Viewport { fn resolveViewport(self: *Self, viewport_index: usize) VkError!vk.Viewport {
const pipeline_data = const pipeline_data =
&(self.state.pipeline orelse return VkError.InvalidPipelineDrv).interface.mode.graphics; &(self.state.pipeline orelse return VkError.InvalidPipelineDrv).interface.mode.graphics;
+1
View File
@@ -169,6 +169,7 @@ fn interpolateBlob(allocator: std.mem.Allocator, a: []const u8, b: []const u8, s
fn interpolateVertexForClipping(allocator: std.mem.Allocator, a: *const Vertex, b: *const Vertex, t: f32) VkError!Vertex { fn interpolateVertexForClipping(allocator: std.mem.Allocator, a: *const Vertex, b: *const Vertex, t: f32) VkError!Vertex {
var result: Vertex = .{ var result: Vertex = .{
.primitive_restart = false,
.position = a.position + ((b.position - a.position) * zm.f32x4s(t)), .position = a.position + ((b.position - a.position) * zm.f32x4s(t)),
.outputs = undefined, .outputs = undefined,
}; };
+99 -62
View File
@@ -121,6 +121,9 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
switch (topology) { switch (topology) {
.point_list => for (draw_call.vertices) |*vertex| { .point_list => for (draw_call.vertices) |*vertex| {
if (vertex.primitive_restart)
continue;
try clipTransformAndRasterizePoint( try clipTransformAndRasterizePoint(
allocator, allocator,
draw_call, draw_call,
@@ -148,56 +151,71 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
if (stencil_attachment_access) |*access| access else null, if (stencil_attachment_access) |*access| access else null,
); );
}, },
.triangle_fan => if (draw_call.vertices.len >= 3) { .triangle_fan => {
const v0 = &draw_call.vertices[0]; var segment_start = firstNonRestart(draw_call, 0);
for (1..(draw_call.vertices.len - 1)) |vertex_index| { while (segment_start < draw_call.vertices.len) {
const v1 = &draw_call.vertices[vertex_index]; const segment_end = nextRestart(draw_call, segment_start);
const v2 = &draw_call.vertices[vertex_index + 1]; if (segment_end - segment_start >= 3) {
const v0 = &draw_call.vertices[segment_start];
for ((segment_start + 1)..(segment_end - 1)) |vertex_index| {
const v1 = &draw_call.vertices[vertex_index];
const v2 = &draw_call.vertices[vertex_index + 1];
try clipTransformAndRasterizeTriangle( try clipTransformAndRasterizeTriangle(
renderer, renderer,
allocator, allocator,
draw_call, draw_call,
v0, v0,
v1, v1,
v2, v2,
color_attachment_access, color_attachment_access,
if (depth_attachment_access) |*access| access else null, if (depth_attachment_access) |*access| access else null,
if (stencil_attachment_access) |*access| access else null, if (stencil_attachment_access) |*access| access else null,
); );
}
}
segment_start = firstNonRestart(draw_call, segment_end + 1);
} }
}, },
.triangle_strip => if (draw_call.vertices.len >= 3) { .triangle_strip => {
for (0..(draw_call.vertices.len - 2)) |vertex_index| { var segment_start = firstNonRestart(draw_call, 0);
const v0 = &draw_call.vertices[vertex_index + 0]; while (segment_start < draw_call.vertices.len) {
const v1 = &draw_call.vertices[vertex_index + 1]; const segment_end = nextRestart(draw_call, segment_start);
const v2 = &draw_call.vertices[vertex_index + 2]; if (segment_end - segment_start >= 3) {
for (segment_start..(segment_end - 2)) |vertex_index| {
const local_index = vertex_index - segment_start;
const v0 = &draw_call.vertices[vertex_index + 0];
const v1 = &draw_call.vertices[vertex_index + 1];
const v2 = &draw_call.vertices[vertex_index + 2];
if ((vertex_index & 1) == 0) { if ((local_index & 1) == 0) {
try clipTransformAndRasterizeTriangle( try clipTransformAndRasterizeTriangle(
renderer, renderer,
allocator, allocator,
draw_call, draw_call,
v0, v0,
v1, v1,
v2, v2,
color_attachment_access, color_attachment_access,
if (depth_attachment_access) |*access| access else null, if (depth_attachment_access) |*access| access else null,
if (stencil_attachment_access) |*access| access else null, if (stencil_attachment_access) |*access| access else null,
); );
} else { } else {
try clipTransformAndRasterizeTriangle( try clipTransformAndRasterizeTriangle(
renderer, renderer,
allocator, allocator,
draw_call, draw_call,
v1, v1,
v0, v0,
v2, v2,
color_attachment_access, color_attachment_access,
if (depth_attachment_access) |*access| access else null, if (depth_attachment_access) |*access| access else null,
if (stencil_attachment_access) |*access| access else null, if (stencil_attachment_access) |*access| access else null,
); );
}
}
} }
segment_start = firstNonRestart(draw_call, segment_end + 1);
} }
}, },
.line_list => for (0..@divTrunc(draw_call.vertices.len, 2)) |line_index| { .line_list => for (0..@divTrunc(draw_call.vertices.len, 2)) |line_index| {
@@ -215,20 +233,27 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
if (stencil_attachment_access) |*access| access else null, if (stencil_attachment_access) |*access| access else null,
); );
}, },
.line_strip => if (draw_call.vertices.len >= 2) { .line_strip => {
for (0..(draw_call.vertices.len - 1)) |vertex_index| { var segment_start = firstNonRestart(draw_call, 0);
const v0 = &draw_call.vertices[vertex_index + 0]; while (segment_start < draw_call.vertices.len) {
const v1 = &draw_call.vertices[vertex_index + 1]; const segment_end = nextRestart(draw_call, segment_start);
if (segment_end - segment_start >= 2) {
for (segment_start..(segment_end - 1)) |vertex_index| {
const v0 = &draw_call.vertices[vertex_index + 0];
const v1 = &draw_call.vertices[vertex_index + 1];
try clipTransformAndRasterizeLine( try clipTransformAndRasterizeLine(
allocator, allocator,
draw_call, draw_call,
v0, v0,
v1, v1,
color_attachment_access, color_attachment_access,
if (depth_attachment_access) |*access| access else null, if (depth_attachment_access) |*access| access else null,
if (stencil_attachment_access) |*access| access else null, if (stencil_attachment_access) |*access| access else null,
); );
}
}
segment_start = firstNonRestart(draw_call, segment_end + 1);
} }
}, },
else => base.unsupported("primitive topology {any}", .{topology}), else => base.unsupported("primitive topology {any}", .{topology}),
@@ -237,6 +262,18 @@ pub fn processThenFragmentStage(renderer: *Renderer, allocator: std.mem.Allocato
draw_call.rasterizer_wait_group.await(io) catch return VkError.DeviceLost; draw_call.rasterizer_wait_group.await(io) catch return VkError.DeviceLost;
} }
fn firstNonRestart(draw_call: *const DrawCall, start: usize) usize {
var index = start;
while (index < draw_call.vertices.len and draw_call.vertices[index].primitive_restart) : (index += 1) {}
return index;
}
fn nextRestart(draw_call: *const DrawCall, start: usize) usize {
var index = start;
while (index < draw_call.vertices.len and !draw_call.vertices[index].primitive_restart) : (index += 1) {}
return index;
}
fn clipTransformAndRasterizePoint( fn clipTransformAndRasterizePoint(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
draw_call: *DrawCall, draw_call: *DrawCall,
@@ -253,10 +290,10 @@ fn clipTransformAndRasterizePoint(
clip.viewportTransformVertex(draw_call.viewport, &transformed); clip.viewportTransformVertex(draw_call.viewport, &transformed);
const point_size = 1.0; const point_size = 1.0;
const min_x: i32 = @intFromFloat(@floor(transformed.position[0] - (point_size / 2.0))); const min_x: i32 = @intFromFloat(@ceil(transformed.position[0] - (point_size / 2.0) - 0.5));
const max_x: i32 = @intFromFloat(@ceil(transformed.position[0] + (point_size / 2.0)) - 1.0); const max_x: i32 = @intFromFloat(@ceil(transformed.position[0] + (point_size / 2.0) - 0.5) - 1.0);
const min_y: i32 = @intFromFloat(@floor(transformed.position[1] - (point_size / 2.0))); const min_y: i32 = @intFromFloat(@ceil(transformed.position[1] - (point_size / 2.0) - 0.5));
const max_y: i32 = @intFromFloat(@ceil(transformed.position[1] + (point_size / 2.0)) - 1.0); const max_y: i32 = @intFromFloat(@ceil(transformed.position[1] + (point_size / 2.0) - 0.5) - 1.0);
const pipeline = draw_call.renderer.state.pipeline orelse return; const pipeline = draw_call.renderer.state.pipeline orelse return;
const has_fragment_shader = pipeline.stages.getPtr(.fragment) != null; const has_fragment_shader = pipeline.stages.getPtr(.fragment) != null;
+17 -10
View File
@@ -268,27 +268,34 @@ inline fn blendOp(op: vk.BlendOp, src: F32x4, dst: F32x4) F32x4 {
}; };
} }
inline fn blendColor(src: F32x4, dst: F32x4, state: vk.PipelineColorBlendAttachmentState, constants: [4]f32) F32x4 { inline fn blendColor(src: F32x4, dst: F32x4, state: vk.PipelineColorBlendAttachmentState, constants: [4]f32, format: vk.Format) F32x4 {
if (state.blend_enable == .false) if (state.blend_enable == .false)
return src; return src;
const constant = F32x4{ constants[0], constants[1], constants[2], constants[3] }; const min_value = zm.f32x4s(base.format.minElementValue(format));
const color_src = if (state.color_blend_op == .min or state.color_blend_op == .max) const max_value = zm.f32x4s(base.format.maxElementValue(format));
src const clamped_src = if (base.format.isFloat(format)) src else std.math.clamp(src, min_value, max_value);
const constant = if (base.format.isFloat(format))
F32x4{ constants[0], constants[1], constants[2], constants[3] }
else else
src * blendFactor(state.src_color_blend_factor, src, dst, constant); std.math.clamp(F32x4{ constants[0], constants[1], constants[2], constants[3] }, min_value, max_value);
const color_src = if (state.color_blend_op == .min or state.color_blend_op == .max)
clamped_src
else
clamped_src * blendFactor(state.src_color_blend_factor, clamped_src, dst, constant);
const color_dst = if (state.color_blend_op == .min or state.color_blend_op == .max) const color_dst = if (state.color_blend_op == .min or state.color_blend_op == .max)
dst dst
else else
dst * blendFactor(state.dst_color_blend_factor, src, dst, constant); dst * blendFactor(state.dst_color_blend_factor, clamped_src, dst, constant);
const alpha_src = if (state.alpha_blend_op == .min or state.alpha_blend_op == .max) const alpha_src = if (state.alpha_blend_op == .min or state.alpha_blend_op == .max)
src clamped_src
else else
src * blendFactor(state.src_alpha_blend_factor, src, dst, constant); clamped_src * blendFactor(state.src_alpha_blend_factor, clamped_src, dst, constant);
const alpha_dst = if (state.alpha_blend_op == .min or state.alpha_blend_op == .max) const alpha_dst = if (state.alpha_blend_op == .min or state.alpha_blend_op == .max)
dst dst
else else
dst * blendFactor(state.dst_alpha_blend_factor, src, dst, constant); dst * blendFactor(state.dst_alpha_blend_factor, clamped_src, dst, constant);
var blended = blendOp(state.color_blend_op, color_src, color_dst); var blended = blendOp(state.color_blend_op, color_src, color_dst);
blended[3] = blendOp(state.alpha_blend_op, alpha_src, alpha_dst)[3]; blended[3] = blendOp(state.alpha_blend_op, alpha_src, alpha_dst)[3];
@@ -389,7 +396,7 @@ pub fn writeToTargets(
if (location >= attachments.len) if (location >= attachments.len)
break :blk src; break :blk src;
const constants = draw_call.renderer.dynamic_state.blend_constants orelse pipeline_data.color_blend.constants; const constants = draw_call.renderer.dynamic_state.blend_constants orelse pipeline_data.color_blend.constants;
const blended = blendColor(src, dst, attachments[location], constants); const blended = blendColor(src, dst, attachments[location], constants, color.format);
break :blk applyColorWriteMask(blended, dst, attachments[location].color_write_mask); break :blk applyColorWriteMask(blended, dst, attachments[location].color_write_mask);
} else src; } else src;
const encoded_color = if (base.format.isSrgb(color.format)) zm.rgbToSrgb(final_color) else final_color; const encoded_color = if (base.format.isSrgb(color.format)) zm.rgbToSrgb(final_color) else final_color;
+14 -6
View File
@@ -21,7 +21,8 @@ pub const RunData = struct {
vertex_count: usize, vertex_count: usize,
first_vertex: usize, first_vertex: usize,
first_instance: usize, first_instance: usize,
indices: ?[]const i32, indices: ?[]const u32,
primitive_restart: ?[]const bool,
instance_index: usize, instance_index: usize,
draw_call: *Renderer.DrawCall, draw_call: *Renderer.DrawCall,
}; };
@@ -51,13 +52,22 @@ inline fn run(data: RunData) !void {
var invocation_index: usize = data.batch_id; var invocation_index: usize = data.batch_id;
while (invocation_index < data.vertex_count) : (invocation_index += data.batch_size) { while (invocation_index < data.vertex_count) : (invocation_index += data.batch_size) {
const output: *Renderer.Vertex = &data.draw_call.vertices[(data.instance_index * data.vertex_count) + invocation_index];
if (data.primitive_restart) |primitive_restart| {
if (primitive_restart[invocation_index]) {
output.primitive_restart = true;
continue;
}
}
rt.resetInvocation(data.allocator); rt.resetInvocation(data.allocator);
try rt.populatePushConstants(data.draw_call.renderer.state.push_constant_blob[0..]); try rt.populatePushConstants(data.draw_call.renderer.state.push_constant_blob[0..]);
const vertex_index: usize = if (data.indices) |indices| @intCast(indices[invocation_index]) else data.first_vertex + invocation_index; const vertex_index_u32: u32 = if (data.indices) |indices| indices[invocation_index] else @intCast(data.first_vertex + invocation_index);
const vertex_index: usize = vertex_index_u32;
const instance_index = data.first_instance + data.instance_index; const instance_index = data.first_instance + data.instance_index;
setupBuiltins(rt, vertex_index, instance_index) catch |err| switch (err) { setupBuiltins(rt, vertex_index_u32, instance_index) catch |err| switch (err) {
SpvRuntimeError.NotFound => {}, SpvRuntimeError.NotFound => {},
else => return err, else => return err,
}; };
@@ -88,7 +98,6 @@ inline fn run(data: RunData) !void {
else => return err, else => return err,
}; };
const output: *Renderer.Vertex = &data.draw_call.vertices[(data.instance_index * data.vertex_count) + invocation_index];
try rt.readBuiltIn(std.mem.asBytes(&output.position), .Position); try rt.readBuiltIn(std.mem.asBytes(&output.position), .Position);
for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| { for (0..spv.SPIRV_MAX_OUTPUT_LOCATIONS) |location| {
@@ -112,8 +121,7 @@ inline fn run(data: RunData) !void {
} }
} }
fn setupBuiltins(rt: *spv.Runtime, vertex_index: usize, instance_index: usize) !void { fn setupBuiltins(rt: *spv.Runtime, vertex_index_u32: u32, instance_index: usize) !void {
const vertex_index_u32: u32 = @intCast(vertex_index);
const instance_index_u32: u32 = @intCast(instance_index); const instance_index_u32: u32 = @intCast(instance_index);
try rt.writeBuiltIn(std.mem.asBytes(&vertex_index_u32), .VertexIndex); try rt.writeBuiltIn(std.mem.asBytes(&vertex_index_u32), .VertexIndex);
+3 -1
View File
@@ -37,6 +37,7 @@ mode: union(enum) {
binding_description: ?[]vk.VertexInputBindingDescription, binding_description: ?[]vk.VertexInputBindingDescription,
attribute_description: ?[]vk.VertexInputAttributeDescription, attribute_description: ?[]vk.VertexInputAttributeDescription,
topology: vk.PrimitiveTopology, topology: vk.PrimitiveTopology,
primitive_restart_enable: vk.Bool32,
}, },
viewport_state: struct { viewport_state: struct {
viewports: ?[]vk.Viewport, viewports: ?[]vk.Viewport,
@@ -122,6 +123,7 @@ pub fn initGraphics(device: *Device, allocator: std.mem.Allocator, cache: ?*Pipe
break :blk null; break :blk null;
}, },
.topology = if (info.p_input_assembly_state) |state| state.topology else return VkError.ValidationFailed, .topology = if (info.p_input_assembly_state) |state| state.topology else return VkError.ValidationFailed,
.primitive_restart_enable = if (info.p_input_assembly_state) |state| state.primitive_restart_enable else return VkError.ValidationFailed,
}, },
.viewport_state = .{ .viewport_state = .{
.viewports = blk: { .viewports = blk: {
@@ -169,7 +171,7 @@ pub fn initGraphics(device: *Device, allocator: std.mem.Allocator, cache: ?*Pipe
if (info.p_dynamic_state) |dynamic_state| { if (info.p_dynamic_state) |dynamic_state| {
if (dynamic_state.p_dynamic_states) |states| { if (dynamic_state.p_dynamic_states) |states| {
for (states[0..], 0..dynamic_state.dynamic_state_count) |info_state, _| { for (states[0..dynamic_state.dynamic_state_count]) |info_state| {
switch (info_state) { switch (info_state) {
.viewport => state.viewport = true, .viewport => state.viewport = true,
.scissor => state.scissor = true, .scissor => state.scissor = true,
+10
View File
@@ -13,10 +13,15 @@ pub const ObjectType: vk.ObjectType = .sampler;
owner: *Device, owner: *Device,
mag_filter: vk.Filter, mag_filter: vk.Filter,
min_filter: vk.Filter, min_filter: vk.Filter,
mipmap_mode: vk.SamplerMipmapMode,
address_mode_u: vk.SamplerAddressMode, address_mode_u: vk.SamplerAddressMode,
address_mode_v: vk.SamplerAddressMode, address_mode_v: vk.SamplerAddressMode,
address_mode_w: vk.SamplerAddressMode, address_mode_w: vk.SamplerAddressMode,
mip_lod_bias: f32,
min_lod: f32,
max_lod: f32,
border_color: vk.BorderColor, border_color: vk.BorderColor,
unnormalized_coordinates: vk.Bool32,
vtable: *const VTable, vtable: *const VTable,
@@ -30,10 +35,15 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Sampl
.owner = device, .owner = device,
.mag_filter = info.mag_filter, .mag_filter = info.mag_filter,
.min_filter = info.min_filter, .min_filter = info.min_filter,
.mipmap_mode = info.mipmap_mode,
.address_mode_u = info.address_mode_u, .address_mode_u = info.address_mode_u,
.address_mode_v = info.address_mode_v, .address_mode_v = info.address_mode_v,
.address_mode_w = info.address_mode_w, .address_mode_w = info.address_mode_w,
.mip_lod_bias = info.mip_lod_bias,
.min_lod = info.min_lod,
.max_lod = info.max_lod,
.border_color = info.border_color, .border_color = info.border_color,
.unnormalized_coordinates = info.unnormalized_coordinates,
.vtable = undefined, .vtable = undefined,
}; };
} }