adding decoration members propagation
This commit is contained in:
+108
-20
@@ -166,6 +166,106 @@ fn pass(self: *Self, allocator: std.mem.Allocator) ModuleError!void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolveConstantWord(self: *const Self, id: SpvWord) ?SpvWord {
|
||||||
|
if (id >= self.results.len) return null;
|
||||||
|
|
||||||
|
const variant = self.results[id].variant orelse return null;
|
||||||
|
return switch (variant) {
|
||||||
|
.Constant => |c| switch (c.value) {
|
||||||
|
.Int => |i| i.value.uint32,
|
||||||
|
else => null,
|
||||||
|
},
|
||||||
|
else => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findAccessChainToMember(self: *const Self, base_id: SpvWord, member_index: SpvWord) ?SpvWord {
|
||||||
|
for (self.results, 0..) |result, id| {
|
||||||
|
const variant = result.variant orelse continue;
|
||||||
|
|
||||||
|
switch (variant) {
|
||||||
|
.AccessChain => |a| {
|
||||||
|
if (a.base != base_id or a.indexes.len == 0) continue;
|
||||||
|
|
||||||
|
const first_index = self.resolveConstantWord(a.indexes[0]) orelse continue;
|
||||||
|
if (first_index == member_index) return @intCast(id);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn applyInterfaceDecoration(
|
||||||
|
self: *Self,
|
||||||
|
storage_class: spv.SpvStorageClass,
|
||||||
|
decoration: Result.Decoration,
|
||||||
|
id: SpvWord,
|
||||||
|
) ModuleError!void {
|
||||||
|
switch (storage_class) {
|
||||||
|
.Input => switch (decoration.rtype) {
|
||||||
|
.BuiltIn => self.builtins.put(
|
||||||
|
std.enums.fromInt(spv.SpvBuiltIn, decoration.literal_1) orelse return ModuleError.InvalidSpirV,
|
||||||
|
id,
|
||||||
|
),
|
||||||
|
.Location => self.input_locations[decoration.literal_1] = id,
|
||||||
|
else => {},
|
||||||
|
},
|
||||||
|
.Output => switch (decoration.rtype) {
|
||||||
|
.BuiltIn => self.builtins.put(
|
||||||
|
std.enums.fromInt(spv.SpvBuiltIn, decoration.literal_1) orelse return ModuleError.InvalidSpirV,
|
||||||
|
id,
|
||||||
|
),
|
||||||
|
.Location => self.output_locations[decoration.literal_1] = id,
|
||||||
|
else => {},
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn applyStructMemberInterfaceDecorations(
|
||||||
|
self: *Self,
|
||||||
|
storage_class: spv.SpvStorageClass,
|
||||||
|
type_word: SpvWord,
|
||||||
|
id: SpvWord,
|
||||||
|
) ModuleError!void {
|
||||||
|
switch (storage_class) {
|
||||||
|
.Input, .Output => {},
|
||||||
|
else => return,
|
||||||
|
}
|
||||||
|
|
||||||
|
const type_result = &self.results[type_word];
|
||||||
|
const target_type_word = if (type_result.variant) |variant| switch (variant) {
|
||||||
|
.Type => |t| switch (t) {
|
||||||
|
.Pointer => |ptr| ptr.target,
|
||||||
|
else => type_word,
|
||||||
|
},
|
||||||
|
else => type_word,
|
||||||
|
} else type_word;
|
||||||
|
|
||||||
|
const target_result = &self.results[target_type_word];
|
||||||
|
if (target_result.variant) |variant| {
|
||||||
|
switch (variant) {
|
||||||
|
.Type => |t| switch (t) {
|
||||||
|
.Structure => {
|
||||||
|
for (target_result.decorations.items) |decoration| {
|
||||||
|
switch (decoration.rtype) {
|
||||||
|
.BuiltIn, .Location => {
|
||||||
|
const member_id = self.findAccessChainToMember(id, decoration.index) orelse continue;
|
||||||
|
try self.applyInterfaceDecoration(storage_class, decoration, member_id);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn applyDecorations(self: *Self) ModuleError!void {
|
fn applyDecorations(self: *Self) ModuleError!void {
|
||||||
for (self.results, 0..) |result, id| {
|
for (self.results, 0..) |result, id| {
|
||||||
if (result.variant == null)
|
if (result.variant == null)
|
||||||
@@ -177,27 +277,9 @@ fn applyDecorations(self: *Self) ModuleError!void {
|
|||||||
for (result.decorations.items) |decoration| {
|
for (result.decorations.items) |decoration| {
|
||||||
switch (result.variant.?) {
|
switch (result.variant.?) {
|
||||||
.Variable => |v| {
|
.Variable => |v| {
|
||||||
|
try self.applyInterfaceDecoration(v.storage_class, decoration, @intCast(id));
|
||||||
|
|
||||||
switch (v.storage_class) {
|
switch (v.storage_class) {
|
||||||
.Input => {
|
|
||||||
switch (decoration.rtype) {
|
|
||||||
.BuiltIn => self.builtins.put(
|
|
||||||
std.enums.fromInt(spv.SpvBuiltIn, decoration.literal_1) orelse return ModuleError.InvalidSpirV,
|
|
||||||
@intCast(id),
|
|
||||||
),
|
|
||||||
.Location => self.input_locations[decoration.literal_1] = @intCast(id),
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.Output => {
|
|
||||||
switch (decoration.rtype) {
|
|
||||||
.BuiltIn => self.builtins.put(
|
|
||||||
std.enums.fromInt(spv.SpvBuiltIn, decoration.literal_1) orelse return ModuleError.InvalidSpirV,
|
|
||||||
@intCast(id),
|
|
||||||
),
|
|
||||||
.Location => self.output_locations[decoration.literal_1] = @intCast(id),
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.StorageBuffer, .Uniform, .UniformConstant => {
|
.StorageBuffer, .Uniform, .UniformConstant => {
|
||||||
switch (decoration.rtype) {
|
switch (decoration.rtype) {
|
||||||
.Binding => binding = decoration.literal_1,
|
.Binding => binding = decoration.literal_1,
|
||||||
@@ -221,6 +303,12 @@ fn applyDecorations(self: *Self) ModuleError!void {
|
|||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (result.variant.?) {
|
||||||
|
.Variable => |v| try self.applyStructMemberInterfaceDecorations(v.storage_class, v.type_word, @intCast(id)),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
if (set != null and binding != null) {
|
if (set != null and binding != null) {
|
||||||
self.bindings[set.?][binding.?] = @intCast(id);
|
self.bindings[set.?][binding.?] = @intCast(id);
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-1
@@ -201,6 +201,8 @@ pub const VariantData = union(Variant) {
|
|||||||
},
|
},
|
||||||
AccessChain: struct {
|
AccessChain: struct {
|
||||||
target: SpvWord,
|
target: SpvWord,
|
||||||
|
base: SpvWord,
|
||||||
|
indexes: []SpvWord,
|
||||||
value: Value,
|
value: Value,
|
||||||
},
|
},
|
||||||
FunctionParameter: struct {
|
FunctionParameter: struct {
|
||||||
@@ -247,7 +249,10 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|||||||
},
|
},
|
||||||
.Constant => |*c| c.value.deinit(allocator),
|
.Constant => |*c| c.value.deinit(allocator),
|
||||||
.Variable => |*v| v.value.deinit(allocator),
|
.Variable => |*v| v.value.deinit(allocator),
|
||||||
.AccessChain => |*a| a.value.deinit(allocator),
|
.AccessChain => |*a| {
|
||||||
|
allocator.free(a.indexes);
|
||||||
|
a.value.deinit(allocator);
|
||||||
|
},
|
||||||
.Function => |f| allocator.free(f.params),
|
.Function => |f| allocator.free(f.params),
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@@ -363,6 +368,14 @@ pub fn dupe(self: *const Self, allocator: std.mem.Allocator) RuntimeError!Self {
|
|||||||
.params = allocator.dupe(SpvWord, f.params) catch return RuntimeError.OutOfMemory,
|
.params = allocator.dupe(SpvWord, f.params) catch return RuntimeError.OutOfMemory,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.AccessChain => |a| break :blk .{
|
||||||
|
.AccessChain = .{
|
||||||
|
.target = a.target,
|
||||||
|
.base = a.base,
|
||||||
|
.indexes = allocator.dupe(SpvWord, a.indexes) catch return RuntimeError.OutOfMemory,
|
||||||
|
.value = try a.value.dupe(allocator),
|
||||||
|
},
|
||||||
|
},
|
||||||
else => break :blk variant,
|
else => break :blk variant,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-4
@@ -242,9 +242,46 @@ pub fn writeDescriptorSet(self: *const Self, input: []const u8, set: SpvWord, bi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn readResultValue(self: *const Self, output: []u8, result: SpvWord) RuntimeError!void {
|
||||||
|
const variant = self.results[result].variant orelse return RuntimeError.InvalidSpirV;
|
||||||
|
switch (variant) {
|
||||||
|
.Variable => |v| _ = try v.value.read(output),
|
||||||
|
.AccessChain => |a| switch (a.value) {
|
||||||
|
.Pointer => |ptr| switch (ptr.ptr) {
|
||||||
|
.common => |value_ptr| _ = try value_ptr.read(output),
|
||||||
|
.f32_ptr => |value_ptr| std.mem.copyForwards(u8, output[0..@sizeOf(f32)], std.mem.asBytes(value_ptr)),
|
||||||
|
.i32_ptr => |value_ptr| std.mem.copyForwards(u8, output[0..@sizeOf(i32)], std.mem.asBytes(value_ptr)),
|
||||||
|
.u32_ptr => |value_ptr| std.mem.copyForwards(u8, output[0..@sizeOf(u32)], std.mem.asBytes(value_ptr)),
|
||||||
|
},
|
||||||
|
else => _ = try a.value.read(output),
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeResultValue(self: *const Self, input: []const u8, result: SpvWord) RuntimeError!void {
|
||||||
|
if (self.results[result].variant) |*variant| {
|
||||||
|
switch (variant.*) {
|
||||||
|
.Variable => |*v| _ = try v.value.writeConst(input),
|
||||||
|
.AccessChain => |*a| switch (a.value) {
|
||||||
|
.Pointer => |ptr| switch (ptr.ptr) {
|
||||||
|
.common => |value_ptr| _ = try value_ptr.writeConst(input),
|
||||||
|
.f32_ptr => |value_ptr| std.mem.copyForwards(u8, std.mem.asBytes(value_ptr), input[0..@sizeOf(f32)]),
|
||||||
|
.i32_ptr => |value_ptr| std.mem.copyForwards(u8, std.mem.asBytes(value_ptr), input[0..@sizeOf(i32)]),
|
||||||
|
.u32_ptr => |value_ptr| std.mem.copyForwards(u8, std.mem.asBytes(value_ptr), input[0..@sizeOf(u32)]),
|
||||||
|
},
|
||||||
|
else => _ = try a.value.writeConst(input),
|
||||||
|
},
|
||||||
|
else => return RuntimeError.InvalidSpirV,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return RuntimeError.InvalidSpirV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn readOutput(self: *const Self, output: []u8, result: SpvWord) RuntimeError!void {
|
pub fn readOutput(self: *const Self, output: []u8, result: SpvWord) RuntimeError!void {
|
||||||
if (std.mem.indexOfScalar(SpvWord, &self.mod.output_locations, result)) |_| {
|
if (std.mem.indexOfScalar(SpvWord, &self.mod.output_locations, result)) |_| {
|
||||||
_ = try self.results[result].variant.?.Variable.value.read(output);
|
try self.readResultValue(output, result);
|
||||||
} else {
|
} else {
|
||||||
return RuntimeError.NotFound;
|
return RuntimeError.NotFound;
|
||||||
}
|
}
|
||||||
@@ -252,7 +289,7 @@ pub fn readOutput(self: *const Self, output: []u8, result: SpvWord) RuntimeError
|
|||||||
|
|
||||||
pub fn readBuiltIn(self: *const Self, output: []u8, builtin: spv.SpvBuiltIn) RuntimeError!void {
|
pub fn readBuiltIn(self: *const Self, output: []u8, builtin: spv.SpvBuiltIn) RuntimeError!void {
|
||||||
if (self.mod.builtins.get(builtin)) |result| {
|
if (self.mod.builtins.get(builtin)) |result| {
|
||||||
_ = try self.results[result].variant.?.Variable.value.read(output);
|
try self.readResultValue(output, result);
|
||||||
} else {
|
} else {
|
||||||
return RuntimeError.NotFound;
|
return RuntimeError.NotFound;
|
||||||
}
|
}
|
||||||
@@ -260,7 +297,7 @@ pub fn readBuiltIn(self: *const Self, output: []u8, builtin: spv.SpvBuiltIn) Run
|
|||||||
|
|
||||||
pub fn writeInput(self: *const Self, input: []const u8, result: SpvWord) RuntimeError!void {
|
pub fn writeInput(self: *const Self, input: []const u8, result: SpvWord) RuntimeError!void {
|
||||||
if (std.mem.indexOfScalar(SpvWord, &self.mod.input_locations, result)) |_| {
|
if (std.mem.indexOfScalar(SpvWord, &self.mod.input_locations, result)) |_| {
|
||||||
_ = try self.results[result].variant.?.Variable.value.writeConst(input);
|
try self.writeResultValue(input, result);
|
||||||
} else {
|
} else {
|
||||||
return RuntimeError.NotFound;
|
return RuntimeError.NotFound;
|
||||||
}
|
}
|
||||||
@@ -268,7 +305,7 @@ pub fn writeInput(self: *const Self, input: []const u8, result: SpvWord) Runtime
|
|||||||
|
|
||||||
pub fn writeBuiltIn(self: *const Self, input: []const u8, builtin: spv.SpvBuiltIn) RuntimeError!void {
|
pub fn writeBuiltIn(self: *const Self, input: []const u8, builtin: spv.SpvBuiltIn) RuntimeError!void {
|
||||||
if (self.mod.builtins.get(builtin)) |result| {
|
if (self.mod.builtins.get(builtin)) |result| {
|
||||||
_ = try self.results[result].variant.?.Variable.value.writeConst(input);
|
try self.writeResultValue(input, result);
|
||||||
} else {
|
} else {
|
||||||
return RuntimeError.NotFound;
|
return RuntimeError.NotFound;
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-8
@@ -88,6 +88,7 @@ pub const SetupDispatcher = block: {
|
|||||||
.AtomicUMax = autoSetupConstant,
|
.AtomicUMax = autoSetupConstant,
|
||||||
.AtomicUMin = autoSetupConstant,
|
.AtomicUMin = autoSetupConstant,
|
||||||
.AtomicXor = autoSetupConstant,
|
.AtomicXor = autoSetupConstant,
|
||||||
|
.AccessChain = setupAccessChain,
|
||||||
.BitCount = autoSetupConstant,
|
.BitCount = autoSetupConstant,
|
||||||
.BitFieldInsert = autoSetupConstant,
|
.BitFieldInsert = autoSetupConstant,
|
||||||
.BitFieldSExtract = autoSetupConstant,
|
.BitFieldSExtract = autoSetupConstant,
|
||||||
@@ -145,6 +146,7 @@ pub const SetupDispatcher = block: {
|
|||||||
.IAddCarry = autoSetupConstant,
|
.IAddCarry = autoSetupConstant,
|
||||||
.IEqual = autoSetupConstant,
|
.IEqual = autoSetupConstant,
|
||||||
.ImageRead = autoSetupConstant,
|
.ImageRead = autoSetupConstant,
|
||||||
|
.InBoundsAccessChain = setupAccessChain,
|
||||||
.IMul = autoSetupConstant,
|
.IMul = autoSetupConstant,
|
||||||
.INotEqual = autoSetupConstant,
|
.INotEqual = autoSetupConstant,
|
||||||
.ISub = autoSetupConstant,
|
.ISub = autoSetupConstant,
|
||||||
@@ -1119,6 +1121,39 @@ fn autoSetupConstant(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) Run
|
|||||||
_ = try setupConstant(allocator, rt);
|
_ = try setupConstant(allocator, rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setupAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
|
||||||
|
const var_type = try rt.it.next();
|
||||||
|
const id = try rt.it.next();
|
||||||
|
const base_id = try rt.it.next();
|
||||||
|
|
||||||
|
const index_count: usize = @intCast(word_count - 3);
|
||||||
|
const indexes = allocator.alloc(SpvWord, index_count) catch return RuntimeError.OutOfMemory;
|
||||||
|
errdefer allocator.free(indexes);
|
||||||
|
|
||||||
|
for (indexes) |*index| {
|
||||||
|
index.* = try rt.it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rt.results[id].variant) |*variant| {
|
||||||
|
switch (variant.*) {
|
||||||
|
.AccessChain => |*a| {
|
||||||
|
allocator.free(a.indexes);
|
||||||
|
a.value.deinit(allocator);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rt.results[id].variant = .{
|
||||||
|
.AccessChain = .{
|
||||||
|
.target = var_type,
|
||||||
|
.base = base_id,
|
||||||
|
.indexes = indexes,
|
||||||
|
.value = try Value.init(allocator, rt.results, var_type, false),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn copyValue(dst: *Value, src: *const Value) RuntimeError!void {
|
fn copyValue(dst: *Value, src: *const Value) RuntimeError!void {
|
||||||
const helpers = struct {
|
const helpers = struct {
|
||||||
inline fn copySlice(dst_slice: []Value, src_slice: []const Value) RuntimeError!void {
|
inline fn copySlice(dst_slice: []Value, src_slice: []const Value) RuntimeError!void {
|
||||||
@@ -1269,25 +1304,39 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
|
|||||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
|
|
||||||
const index_count = word_count - 3;
|
const index_count: usize = @intCast(word_count - 3);
|
||||||
|
|
||||||
if (rt.results[id].variant) |*variant| {
|
const indexes, const free_responsability = blk: {
|
||||||
switch (variant.*) {
|
if (rt.results[id].variant) |*variant| {
|
||||||
.AccessChain => |*a| try a.value.flushPtr(allocator),
|
switch (variant.*) {
|
||||||
else => {},
|
.AccessChain => |*a| {
|
||||||
|
if (a.indexes.len != index_count)
|
||||||
|
return RuntimeError.InvalidSpirV;
|
||||||
|
try a.value.flushPtr(allocator);
|
||||||
|
a.value.deinit(allocator);
|
||||||
|
break :blk .{ a.indexes, false };
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
break :blk .{ allocator.alloc(SpvWord, index_count) catch return RuntimeError.OutOfMemory, true };
|
||||||
|
};
|
||||||
|
errdefer if (free_responsability) allocator.free(indexes);
|
||||||
|
|
||||||
rt.results[id].variant = .{
|
rt.results[id].variant = .{
|
||||||
.AccessChain = .{
|
.AccessChain = .{
|
||||||
.target = var_type,
|
.target = var_type,
|
||||||
|
.base = base_id,
|
||||||
|
.indexes = indexes,
|
||||||
.value = blk: {
|
.value = blk: {
|
||||||
var is_owner_of_uniform_slice = false;
|
var is_owner_of_uniform_slice = false;
|
||||||
var uniform_slice_window: ?[]u8 = null;
|
var uniform_slice_window: ?[]u8 = null;
|
||||||
|
|
||||||
for (0..index_count) |index| {
|
for (0..index_count) |index| {
|
||||||
const is_last = (index == index_count - 1);
|
const is_last = (index == index_count - 1);
|
||||||
const member = &rt.results[try rt.it.next()];
|
const index_id = try rt.it.next();
|
||||||
|
indexes[index] = index_id;
|
||||||
|
const member = &rt.results[index_id];
|
||||||
const member_value = switch ((try member.getVariant()).*) {
|
const member_value = switch ((try member.getVariant()).*) {
|
||||||
.Constant => |c| &c.value,
|
.Constant => |c| &c.value,
|
||||||
.Variable => |v| &v.value,
|
.Variable => |v| &v.value,
|
||||||
@@ -1488,7 +1537,7 @@ fn opCompositeExtract(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Ru
|
|||||||
const res_type = try rt.it.next();
|
const res_type = try rt.it.next();
|
||||||
const id = try rt.it.next();
|
const id = try rt.it.next();
|
||||||
const composite_id = try rt.it.next();
|
const composite_id = try rt.it.next();
|
||||||
const index_count = word_count - 3;
|
const index_count: usize = @intCast(word_count - 3);
|
||||||
|
|
||||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
|
|||||||
Reference in New Issue
Block a user