Skip to content

Commit 0901328

Browse files
committed
spirv: write error value in an storage buffer
1 parent fca5f36 commit 0901328

File tree

6 files changed

+96
-75
lines changed

6 files changed

+96
-75
lines changed

lib/std/Target.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2014,7 +2014,7 @@ pub const Cpu = struct {
20142014
.global, .local, .shared => is_gpu,
20152015
.constant => is_gpu and (context == null or context == .constant),
20162016
.param => is_nvptx,
2017-
.input, .output, .uniform, .push_constant, .storage_buffer => is_spirv,
2017+
.input, .output, .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => is_spirv,
20182018
};
20192019
}
20202020
};

lib/std/Target/spirv.zig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub const Feature = enum {
2121
generic_pointer,
2222
vector16,
2323
shader,
24+
variable_pointers,
2425
physical_storage_buffer,
2526
};
2627

@@ -129,6 +130,11 @@ pub const all_features = blk: {
129130
.description = "Enable SPV_KHR_physical_storage_buffer extension and the PhysicalStorageBufferAddresses capability",
130131
.dependencies = featureSet(&[_]Feature{.v1_0}),
131132
};
133+
result[@intFromEnum(Feature.variable_pointers)] = .{
134+
.llvm_name = null,
135+
.description = "Enable SPV_KHR_variable_pointers extension and the (VariablePointers, VariablePointersStorageBuffer) capabilities",
136+
.dependencies = featureSet(&[_]Feature{.v1_0}),
137+
};
132138
const ti = @typeInfo(Feature);
133139
for (&result, 0..) |*elem, i| {
134140
elem.index = i;
@@ -147,7 +153,7 @@ pub const cpu = struct {
147153
pub const vulkan_v1_2: CpuModel = .{
148154
.name = "vulkan_v1_2",
149155
.llvm_name = null,
150-
.features = featureSet(&[_]Feature{ .v1_5, .shader, .physical_storage_buffer }),
156+
.features = featureSet(&[_]Feature{ .v1_5, .shader }),
151157
};
152158

153159
pub const opencl_v2: CpuModel = .{

lib/std/builtin.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ pub const AddressSpace = enum(u5) {
531531
uniform,
532532
push_constant,
533533
storage_buffer,
534+
physical_storage_buffer,
534535

535536
// AVR address spaces.
536537
flash,

src/codegen/spirv.zig

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,10 @@ pub const Object = struct {
169169
/// via the usual `intern_map` mechanism.
170170
ptr_types: PtrTypeMap = .{},
171171

172-
/// For test declarations for Vulkan, we have to add a push constant with a pointer to a
173-
/// buffer that we can use. We only need to generate this once, this holds the link information
172+
/// For test declarations for Vulkan, we have to add a buffer.
173+
/// We only need to generate this once, this holds the link information
174174
/// related to that.
175-
error_push_constant: ?struct {
176-
push_constant_ptr: SpvModule.Decl.Index,
177-
} = null,
175+
error_buffer: ?SpvModule.Decl.Index = null,
178176

179177
pub fn init(gpa: Allocator, target: std.Target) Object {
180178
return .{
@@ -1739,15 +1737,34 @@ const NavGen = struct {
17391737
fn spvStorageClass(self: *NavGen, as: std.builtin.AddressSpace) StorageClass {
17401738
return switch (as) {
17411739
.generic => if (self.spv.hasFeature(.generic_pointer)) .Generic else .Function,
1740+
.global => {
1741+
if (self.spv.hasFeature(.kernel)) return .CrossWorkgroup;
1742+
return .StorageBuffer;
1743+
},
1744+
.push_constant => {
1745+
assert(self.spv.hasFeature(.shader));
1746+
return .PushConstant;
1747+
},
1748+
.output => {
1749+
assert(self.spv.hasFeature(.shader));
1750+
return .Output;
1751+
},
1752+
.uniform => {
1753+
assert(self.spv.hasFeature(.shader));
1754+
return .Uniform;
1755+
},
1756+
.storage_buffer => {
1757+
assert(self.spv.hasFeature(.shader));
1758+
return .StorageBuffer;
1759+
},
1760+
.physical_storage_buffer => {
1761+
assert(self.spv.hasFeature(.physical_storage_buffer));
1762+
return .PhysicalStorageBuffer;
1763+
},
1764+
.constant => .UniformConstant,
17421765
.shared => .Workgroup,
17431766
.local => .Function,
1744-
.global => if (self.spv.hasFeature(.shader)) .PhysicalStorageBuffer else .CrossWorkgroup,
1745-
.constant => .UniformConstant,
1746-
.push_constant => .PushConstant,
17471767
.input => .Input,
1748-
.output => .Output,
1749-
.uniform => .Uniform,
1750-
.storage_buffer => .StorageBuffer,
17511768
.gs,
17521769
.fs,
17531770
.ss,
@@ -2713,38 +2730,32 @@ const NavGen = struct {
27132730
});
27142731
},
27152732
.vulkan, .opengl => {
2716-
const ptr_ptr_anyerror_ty_id = self.spv.allocId();
2717-
try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypePointer, .{
2718-
.id_result = ptr_ptr_anyerror_ty_id,
2719-
.storage_class = .PushConstant,
2720-
.type = ptr_anyerror_ty_id,
2721-
});
2722-
2723-
if (self.object.error_push_constant == null) {
2733+
if (self.object.error_buffer == null) {
27242734
const spv_err_decl_index = try self.spv.allocDecl(.global);
27252735
try self.spv.declareDeclDeps(spv_err_decl_index, &.{});
27262736

2727-
const push_constant_struct_ty_id = self.spv.allocId();
2728-
try self.spv.structType(push_constant_struct_ty_id, &.{ptr_anyerror_ty_id}, &.{"error_out_ptr"});
2729-
try self.spv.decorate(push_constant_struct_ty_id, .Block);
2730-
try self.spv.decorateMember(push_constant_struct_ty_id, 0, .{ .Offset = .{ .byte_offset = 0 } });
2737+
const buffer_struct_ty_id = self.spv.allocId();
2738+
try self.spv.structType(buffer_struct_ty_id, &.{anyerror_ty_id}, &.{"error_out"});
2739+
try self.spv.decorate(buffer_struct_ty_id, .Block);
2740+
try self.spv.decorateMember(buffer_struct_ty_id, 0, .{ .Offset = .{ .byte_offset = 0 } });
27312741

2732-
const ptr_push_constant_struct_ty_id = self.spv.allocId();
2742+
const ptr_buffer_struct_ty_id = self.spv.allocId();
27332743
try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypePointer, .{
2734-
.id_result = ptr_push_constant_struct_ty_id,
2735-
.storage_class = .PushConstant,
2736-
.type = push_constant_struct_ty_id,
2744+
.id_result = ptr_buffer_struct_ty_id,
2745+
.storage_class = self.spvStorageClass(.global),
2746+
.type = buffer_struct_ty_id,
27372747
});
27382748

2749+
const buffer_struct_id = self.spv.declPtr(spv_err_decl_index).result_id;
27392750
try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpVariable, .{
2740-
.id_result_type = ptr_push_constant_struct_ty_id,
2741-
.id_result = self.spv.declPtr(spv_err_decl_index).result_id,
2742-
.storage_class = .PushConstant,
2751+
.id_result_type = ptr_buffer_struct_ty_id,
2752+
.id_result = buffer_struct_id,
2753+
.storage_class = self.spvStorageClass(.global),
27432754
});
2755+
try self.spv.decorate(buffer_struct_id, .{ .DescriptorSet = .{ .descriptor_set = 0 } });
2756+
try self.spv.decorate(buffer_struct_id, .{ .Binding = .{ .binding_point = 0 } });
27442757

2745-
self.object.error_push_constant = .{
2746-
.push_constant_ptr = spv_err_decl_index,
2747-
};
2758+
self.object.error_buffer = spv_err_decl_index;
27482759
}
27492760

27502761
try self.spv.sections.execution_modes.emit(self.spv.gpa, .OpExecutionMode, .{
@@ -2767,24 +2778,16 @@ const NavGen = struct {
27672778
.id_result = self.spv.allocId(),
27682779
});
27692780

2770-
const spv_err_decl_index = self.object.error_push_constant.?.push_constant_ptr;
2771-
const push_constant_id = self.spv.declPtr(spv_err_decl_index).result_id;
2781+
const spv_err_decl_index = self.object.error_buffer.?;
2782+
const buffer_id = self.spv.declPtr(spv_err_decl_index).result_id;
27722783
try decl_deps.append(spv_err_decl_index);
27732784

27742785
const zero_id = try self.constInt(Type.u32, 0);
2775-
// We cannot use OpInBoundsAccessChain to dereference cross-storage class, so we have to use
2776-
// a load.
2777-
const tmp = self.spv.allocId();
27782786
try section.emit(self.spv.gpa, .OpInBoundsAccessChain, .{
2779-
.id_result_type = ptr_ptr_anyerror_ty_id,
2780-
.id_result = tmp,
2781-
.base = push_constant_id,
2782-
.indexes = &.{zero_id},
2783-
});
2784-
try section.emit(self.spv.gpa, .OpLoad, .{
27852787
.id_result_type = ptr_anyerror_ty_id,
27862788
.id_result = p_error_id,
2787-
.pointer = tmp,
2789+
.base = buffer_id,
2790+
.indexes = &.{zero_id},
27882791
});
27892792
},
27902793
else => unreachable,
@@ -4562,7 +4565,8 @@ const NavGen = struct {
45624565
const field_int_id = blk: {
45634566
if (field_ty.isPtrAtRuntime(zcu)) {
45644567
assert(self.spv.hasFeature(.addresses) or
4565-
(self.spv.hasFeature(.physical_storage_buffer) and field_ty.ptrAddressSpace(zcu) == .storage_buffer));
4568+
(self.spv.hasFeature(.physical_storage_buffer) and
4569+
field_ty.ptrAddressSpace(zcu) == .storage_buffer));
45664570
break :blk try self.intFromPtr(field_id);
45674571
}
45684572
break :blk try self.bitCast(field_int_ty, field_ty, field_id);
@@ -4969,13 +4973,16 @@ const NavGen = struct {
49694973
if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
49704974
const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, .Function, .indirect);
49714975
const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
4972-
const active_pl_ptr_ty_id = try self.ptrType(payload_ty, .Function, .indirect);
4973-
const active_pl_ptr_id = self.spv.allocId();
4974-
try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
4975-
.id_result_type = active_pl_ptr_ty_id,
4976-
.id_result = active_pl_ptr_id,
4977-
.operand = pl_ptr_id,
4978-
});
4976+
const active_pl_ptr_id = if (!layout.payload_ty.eql(payload_ty, zcu)) blk: {
4977+
const active_pl_ptr_ty_id = try self.ptrType(payload_ty, .Function, .indirect);
4978+
const active_pl_ptr_id = self.spv.allocId();
4979+
try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
4980+
.id_result_type = active_pl_ptr_ty_id,
4981+
.id_result = active_pl_ptr_id,
4982+
.operand = pl_ptr_id,
4983+
});
4984+
break :blk active_pl_ptr_id;
4985+
} else pl_ptr_id;
49794986

49804987
try self.store(payload_ty, active_pl_ptr_id, payload.?, .{});
49814988
} else {

src/codegen/spirv/Module.zig

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,11 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word {
350350
.vector16 => try self.addCapability(.Vector16),
351351
// Shader
352352
.shader => try self.addCapability(.Shader),
353+
.variable_pointers => {
354+
try self.addExtension("SPV_KHR_variable_pointers");
355+
try self.addCapability(.VariablePointersStorageBuffer);
356+
try self.addCapability(.VariablePointers);
357+
},
353358
.physical_storage_buffer => {
354359
try self.addExtension("SPV_KHR_physical_storage_buffer");
355360
try self.addCapability(.PhysicalStorageBufferAddresses);
@@ -364,20 +369,17 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word {
364369
// Emit memory model
365370
const addressing_model: spec.AddressingModel = blk: {
366371
if (self.hasFeature(.shader)) {
367-
break :blk switch (self.target.cpu.arch) {
368-
.spirv32 => .Logical, // TODO: I don't think this will ever be implemented.
369-
.spirv64 => .PhysicalStorageBuffer64,
370-
else => unreachable,
371-
};
372-
} else if (self.hasFeature(.kernel)) {
373-
break :blk switch (self.target.cpu.arch) {
374-
.spirv32 => .Physical32,
375-
.spirv64 => .Physical64,
376-
else => unreachable,
377-
};
372+
assert(self.target.cpu.arch == .spirv64);
373+
if (self.hasFeature(.physical_storage_buffer)) break :blk .PhysicalStorageBuffer64;
374+
break :blk .Logical;
378375
}
379376

380-
unreachable;
377+
assert(self.hasFeature(.kernel));
378+
break :blk switch (self.target.cpu.arch) {
379+
.spirv32 => .Physical32,
380+
.spirv64 => .Physical64,
381+
else => unreachable,
382+
};
381383
};
382384
try self.sections.memory_model.emit(self.gpa, .OpMemoryModel, .{
383385
.addressing_model = addressing_model,

src/target.zig

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -501,21 +501,26 @@ pub fn addrSpaceCastIsValid(
501501
/// part of a merge (result of a branch) and may not be stored in memory at all. This function returns
502502
/// for a particular architecture and address space wether such pointers are logical.
503503
pub fn arePointersLogical(target: std.Target, as: AddressSpace) bool {
504-
if (target.os.tag != .vulkan) {
505-
return false;
506-
}
504+
if (target.os.tag != .vulkan) return false;
507505

508506
return switch (as) {
509507
// TODO: Vulkan doesn't support pointers in the generic address space, we
510508
// should remove this case but this requires a change in defaultAddressSpace().
511509
// For now, at least disable them from being regarded as physical.
512510
.generic => true,
513-
// For now, all global pointers are represented using PhysicalStorageBuffer, so these are real
514-
// pointers.
511+
// For now, all global pointers are represented using StorageBuffer or CrossWorkgroup,
512+
// so these are real pointers.
515513
.global => false,
516-
// TODO: Allowed with VK_KHR_variable_pointers.
517-
.shared => true,
518-
.constant, .local, .input, .output, .uniform, .push_constant, .storage_buffer => true,
514+
.physical_storage_buffer => false,
515+
.shared => !target.cpu.features.isEnabled(@intFromEnum(std.Target.spirv.Feature.variable_pointers)),
516+
.constant,
517+
.local,
518+
.input,
519+
.output,
520+
.uniform,
521+
.push_constant,
522+
.storage_buffer,
523+
=> true,
519524
else => unreachable,
520525
};
521526
}

0 commit comments

Comments
 (0)