updated spng, theoratest, spng, tracy

This commit is contained in:
peterino2 2025-10-13 21:22:18 -07:00
parent de6ccd211b
commit d738dd2260
28 changed files with 33 additions and 1037 deletions

View File

@ -1,2 +0,0 @@
zig-cache/
zig-out/

View File

@ -1,19 +0,0 @@
Copyright (c) peterino2@github.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,45 +0,0 @@
# spirv-reflect-zig
This is a small program meant to reflect out zig compatible data structures from compiled spirv modules.
You can use the program in standalone or use it as part of your build.zig build system.
## As part of a build system
```zig
var spirvCompile = SpirvGenerator.init(b, .{.target = target, .optimize = optimize, .repoPath = "src"});
var myShader = spirvCompile.shader("path/to/shader.glsl", "myShader");
...
myExe.addModule("myShaderTypes", myShader);
```
In your program you can now access all the types defined in the shader
from your zig program via a simple zig import
```zig
const myShaderTypes = @import("myShaderTypes");
const ImageRenderData = myShaderTypes.ImageRenderData; // ImageRenderData conforms to the data layout specified
const gl = myShaderTypes.gl; // glsl base types are available through this node in the module
```
```zig
var mappedBuffer = SomeGpuApi.mapBuffer(...);
var typedBuffer = @ptrCast([*]ImageRenderData, mappedBuffer);
typedBuffer[0] = .{.someXYField = gl.vec2{.x = 42, .y = 42} };
```
## As a standalone CLI
You can generate the standalone CLI from this folder by calling `zig build install`.
This will create `spirv-reflect-zig` in `zig-out/bin`. This will be able to reflect the
contents of a json file generated by `spirv-cross --reflect` into a .zig file
`spirv-cross myshader.glsl --reflect --output myshader.json &&\
spirv-reflect-zig myshader.json -o myshader.zig`

View File

@ -1,133 +0,0 @@
// Copyright (c) peterino2@github.com
const std = @import("std");
const Build = std.Build;
const LazyPath = Build.LazyPath;
// 1. for each vertex/fragment shader file invoke
// glslc --target-env=vulkan1.2 <input file> -o <input file>.spv
//
// 2. for each generated .spv file i want to invoke
// spirv-cross --reflect <input file>.spv --output <input file>.json
//
// 3. compile the reflect program, and invoke it on the json file.
// spirv-reflect-zig <input file>.json
//
// <input file>.zig
pub const SpirvGenerator2 = struct {
b: *Build,
spirv_build: *Build,
glslTypes: *Build.Module,
reflect: *Build.Step.Compile,
const BuildOptions = struct {
importName: []const u8 = "SpirvReflect",
optimize: std.builtin.OptimizeMode = .Debug,
};
fn initFromBuilder(b: *Build, spirv_build: *Build, opts: BuildOptions) SpirvGenerator2 {
const reflect = spirv_build.addExecutable(.{
.name = "spirv-reflect-zig",
.root_source_file = spirv_build.path("src/main.zig"),
.target = spirv_build.graph.host,
.optimize = opts.optimize,
});
const dep = spirv_build.dependency("glslTypes", .{
.target = spirv_build.graph.host,
.optimize = opts.optimize,
});
return .{
.b = b,
.spirv_build = spirv_build,
.reflect = reflect,
.glslTypes = dep.module("glslTypes"),
};
}
pub fn init(b: *Build, opts: BuildOptions) SpirvGenerator2 {
const dep = b.dependency(opts.importName, .{});
return initFromBuilder(b, dep.builder, opts);
}
pub fn createShader(
self: SpirvGenerator2,
shaderPath: Build.LazyPath,
shaderName: []const u8,
) struct { mod: *Build.Module, spvArtifactInstall: *Build.Step } {
const importSpv = self.b.fmt("{s}.spv", .{shaderName});
const finalSpv = self.b.fmt("shaders/{s}.spv", .{shaderName});
const finalJson = self.b.fmt("shaders/{s}.json", .{shaderName});
const finalZig = self.b.fmt("reflectedTypes/{s}.zig", .{shaderName});
const shaderCompile = self.b.addSystemCommand(&[_][]const u8{"glslc"});
shaderCompile.addFileArg(shaderPath);
shaderCompile.addArg("--target-env=vulkan1.2");
shaderCompile.addArg("-o");
const spvOutputFile = shaderCompile.addOutputFileArg(finalSpv);
const spvOutputArtifact = self.b.addInstallFile(spvOutputFile, finalSpv);
const jsonReflectStep = self.spirv_build.addSystemCommand(&[_][]const u8{"spirv-cross"});
jsonReflectStep.addFileArg(spvOutputFile);
jsonReflectStep.addArg("--reflect");
jsonReflectStep.addArg("--output");
const outputJson = jsonReflectStep.addOutputFileArg(finalJson);
const run_cmd = self.b.addRunArtifact(self.reflect);
run_cmd.addFileArg(outputJson);
run_cmd.addArg("-e");
run_cmd.addArg(importSpv);
run_cmd.addArg("-o");
const outputZigFile = run_cmd.addOutputFileArg(finalZig);
const module = self.spirv_build.createModule(.{
.root_source_file = outputZigFile,
});
module.addAnonymousImport(importSpv, .{
.root_source_file = spvOutputFile,
});
module.addImport("glslTypes", self.glslTypes);
return .{ .mod = module, .spvArtifactInstall = &spvOutputArtifact.step };
}
// creates a shader and immediately adds it to the executable
pub fn addShader(
self: SpirvGenerator2,
module: *Build.Module,
shaderPath: LazyPath,
shaderName: []const u8,
) void {
const results = self.createShader(shaderPath, shaderName);
module.addImport(shaderName, results.mod);
}
pub fn addShaderInstallRef(self: *SpirvGenerator2, exe: *Build.Step.Compile, shader_path: LazyPath, shader_name: []const u8) void {
const results = self.createShader(shader_path, shader_name);
exe.step.dependOn(results.spvArtifactInstall);
}
};
pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const target = b.standardTargetOptions(.{});
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
_ = static_build;
const test_step = b.step("test", "");
const tests = b.addTest(.{
.target = target,
.optimize = optimize,
.root_source_file = b.path("src/test.zig"),
.link_libc = true,
});
const runArtifact = b.addRunArtifact(tests);
test_step.dependOn(&runArtifact.step);
}

View File

@ -1,11 +0,0 @@
.{
.name = .SpirvReflect,
.version = "0.0.0",
.dependencies = .{
.glslTypes = .{ .path = "glslTypes" },
},
.paths = .{
"",
},
.fingerprint = 0x8bdf68352d7dc5fa,
}

View File

@ -1,25 +0,0 @@
const std = @import("std");
const SpirvReflect = @import("SpirvReflect");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const spirvGen = SpirvReflect.SpirvGenerator2.init(b, .{});
b.installArtifact(spirvGen.reflect);
const test_vk = spirvGen.createShader(.{ .path = "../shaders/test_vk.vert" }, "test_vk");
const exe = b.addExecutable(.{
.name = "example",
.root_source_file = .{ .path = "main.zig" },
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("test_vk", test_vk);
spirvGen.addShader(&exe.root_module, "../shaders/test_vk.vert", "test_vk2");
b.installArtifact(exe);
}

View File

@ -1,12 +0,0 @@
.{
.name = "testing",
.version = "0.0.0",
.dependencies = .{
.SpirvReflect = .{ .path = "../" },
},
.paths = .{
"",
},
}

View File

@ -1,9 +0,0 @@
const std = @import("std");
const test_vk = @import("test_vk");
const test_vk2 = @import("test_vk2");
pub fn main() !void {
std.debug.print("hello world {d}\n", .{@sizeOf(test_vk.ImageRenderData)});
std.debug.print("hello world {d}\n", .{@sizeOf(test_vk2.ImageRenderData)});
return;
}

View File

@ -1,19 +0,0 @@
// Copyright (c) peterino2@github.com
const std = @import("std");
const test_vk = @import("test_vk");
pub fn main() !void {
const stdout_file = std.io.getStdOut().writer();
var bw = std.io.bufferedWriter(stdout_file);
const zout = bw.writer();
try zout.print("\n\nHello World!\n\nThis is a sample program using reflected type info from\n", .{});
try zout.print("the shader in `test_shaders/test_vk.vert`\n\n", .{});
try zout.print("sizeOf {s} == {d}\n", .{ @typeName(test_vk.ImageRenderData), @sizeOf(test_vk.ImageRenderData) });
try zout.print("The following fields, types and offsets are in {s}:\n", .{@typeName(test_vk.ImageRenderData)});
for (test_vk.ImageRenderData.FieldDetails) |field| {
try zout.print(" name={s}, offset={d}, size={d}\n", .{ field.name, field.offset, field.size });
}
try bw.flush();
}

View File

@ -1,14 +0,0 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const mod = b.addModule("glslTypes", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("glslTypes.zig"),
});
_ = mod;
}

View File

@ -1,8 +0,0 @@
.{
.name = "glslTypes",
.version = "0.0.0",
.dependencies = .{},
.paths = .{
"",
},
}

View File

@ -1,92 +0,0 @@
// Copyright (c) peterino2@github.com
const std = @import("std");
pub const vec2 = extern struct {
x: f32,
y: f32,
pub fn from(o: anytype) @This() {
return .{
.x = o.x,
.y = o.y,
};
}
};
pub const int = i32;
pub const uint = u32;
pub const u8vec4 = [4]u8;
pub const vec3 = extern struct {
x: f32,
y: f32,
z: f32,
pub fn from(o: anytype) @This() {
return .{
.x = o.x,
.y = o.y,
.z = o.z,
.pad = 0,
};
}
};
pub const vec4 = extern struct {
x: f32,
y: f32,
z: f32,
w: f32,
pub fn from(o: anytype) @This() {
return .{
.x = o.x,
.y = o.y,
.z = o.z,
.w = o.w,
};
}
};
pub const mat4 = [4][4]f32;
pub const float = f32;
pub fn CheckFieldDetails(
comptime T: type,
comptime fieldName: []const u8,
expectedOffset: usize,
expectedSize: usize,
) void {
const offset = @offsetOf(T, fieldName);
const size = @sizeOf(@TypeOf(@field(std.mem.zeroes(T), fieldName)));
if (offset != expectedOffset) {
const msg = std.fmt.comptimePrint(
"Unexpected field offset, {s} was expected at offset {d} but found at offset {d}",
.{ fieldName, expectedOffset, offset },
);
@compileError(msg);
}
if (size != expectedSize) {
const msg = std.fmt.comptimePrint(
"Unexpected field size, '{s}' was expected with size {d} but found at size {d}",
.{ fieldName, expectedSize, size },
);
@compileError(msg);
}
}
pub fn ValidateGeneratedStruct(comptime T: type) void {
for (@field(T, "FieldDetails")) |detail| {
CheckFieldDetails(T, detail.name, detail.offset, detail.size);
}
}
pub const FieldDetail = struct {
name: []const u8,
size: usize,
offset: usize,
};

View File

@ -1,14 +0,0 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const mod = b.addModule("glslTypes", .{
.target = target,
.optimize = optimize,
.root_source_file = b.path("glslTypes.zig"),
});
_ = mod;
}

View File

@ -1,8 +0,0 @@
.{
.name = "glslTypes",
.version = "0.0.0",
.dependencies = .{},
.paths = .{
"",
},
}

View File

@ -1,92 +0,0 @@
// Copyright (c) peterino2@github.com
const std = @import("std");
pub const vec2 = extern struct {
x: f32,
y: f32,
pub fn from(o: anytype) @This() {
return .{
.x = o.x,
.y = o.y,
};
}
};
pub const int = i32;
pub const uint = u32;
pub const u8vec4 = [4]u8;
pub const vec3 = extern struct {
x: f32,
y: f32,
z: f32,
pub fn from(o: anytype) @This() {
return .{
.x = o.x,
.y = o.y,
.z = o.z,
.pad = 0,
};
}
};
pub const vec4 = extern struct {
x: f32,
y: f32,
z: f32,
w: f32,
pub fn from(o: anytype) @This() {
return .{
.x = o.x,
.y = o.y,
.z = o.z,
.w = o.w,
};
}
};
pub const mat4 = [4][4]f32;
pub const float = f32;
pub fn CheckFieldDetails(
comptime T: type,
comptime fieldName: []const u8,
expectedOffset: usize,
expectedSize: usize,
) void {
const offset = @offsetOf(T, fieldName);
const size = @sizeOf(@TypeOf(@field(std.mem.zeroes(T), fieldName)));
if (offset != expectedOffset) {
const msg = std.fmt.comptimePrint(
"Unexpected field offset, {s} was expected at offset {d} but found at offset {d}",
.{ fieldName, expectedOffset, offset },
);
@compileError(msg);
}
if (size != expectedSize) {
const msg = std.fmt.comptimePrint(
"Unexpected field size, '{s}' was expected with size {d} but found at size {d}",
.{ fieldName, expectedSize, size },
);
@compileError(msg);
}
}
pub fn ValidateGeneratedStruct(comptime T: type) void {
for (@field(T, "FieldDetails")) |detail| {
CheckFieldDetails(T, detail.name, detail.offset, detail.size);
}
}
pub const FieldDetail = struct {
name: []const u8,
size: usize,
offset: usize,
};

View File

@ -1,60 +0,0 @@
// Copyright (c) peterino2@github.com
#version 460
layout (location = 0) in vec3 vPosition;
layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec4 vColor;
layout (location = 3) in vec2 vTexCoord;
layout (location = 0) out vec4 outColor;
layout (location = 1) out vec2 texCoord;
struct ImageRenderData {
vec2 imagePosition;
vec2 imageSize;
vec2 anchorPoint;
vec2 scale;
float alpha;
vec4 baseColor;
float zLevel;
};
struct ImageRenderData2{
ImageRenderData ird;
float someFloat;
vec2 someVec2;
};
layout(std140, set = 0, binding = 0) readonly buffer ImageBufferObjects {
ImageRenderData2 objects[];
} objectBuffer;
layout (push_constant) uniform constants
{
vec2 extent;
} PushConstants;
void main()
{
vec2 imagePosition = objectBuffer.objects[gl_BaseInstance].ird.imagePosition;
vec2 imageSize = objectBuffer.objects[gl_BaseInstance].ird.imageSize;
vec2 anchor = objectBuffer.objects[gl_BaseInstance].ird.anchorPoint;
vec2 scale = objectBuffer.objects[gl_BaseInstance].ird.scale;
float alpha = objectBuffer.objects[gl_BaseInstance].ird.alpha;
vec4 baseColor = objectBuffer.objects[gl_BaseInstance].ird.baseColor;
vec2 finalSize = (imageSize / PushConstants.extent);
vec2 finalPos = ((imagePosition / PushConstants.extent) * 2 - 1) - anchor * finalSize * scale;
outColor = baseColor;
gl_Position = vec4(
finalPos.x + ( vPosition.x * finalSize.x ),
finalPos.y + (-vPosition.y * finalSize.y ),
vPosition.z, 1.0
);
texCoord = vec2(1 - vTexCoord.x, vTexCoord.y);
}

View File

@ -1,288 +0,0 @@
// Copyright (c) peterino2@github.com
const std = @import("std");
arena: std.heap.ArenaAllocator,
allocator: std.mem.Allocator,
fileName: []const u8,
typeIdNames: std.StringArrayHashMap([]const u8),
reflectedTypes: std.StringArrayHashMap(ReflectedTypeInfo),
// some runtime options
opts: Options,
const Options = struct {
verbose: bool = false,
embedFile: ?[]const u8 = null,
};
pub const ReflectedField = struct {
name: []u8,
typeName: []u8,
size: usize,
offset: usize,
};
pub const ReflectedTypeInfo = struct {
name: []u8,
fields: std.ArrayList(ReflectedField),
size: usize,
};
pub fn err(_: @This(), comptime fmt: []const u8, args: anytype) void {
std.debug.print("[ERROR ]:" ++ fmt ++ "\n", args);
}
pub fn warn(_: @This(), comptime fmt: []const u8, args: anytype) void {
std.debug.print("[WARNING]:" ++ fmt ++ "\n", args);
}
pub fn logv(self: @This(), comptime fmt: []const u8, args: anytype) void {
if (self.opts.verbose) {
std.debug.print("[VERBOSE]:" ++ fmt ++ "\n", args);
}
}
pub fn reflect(allocator: std.mem.Allocator, fileName: []const u8, opts: Options) !@This() {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
const arenaAlloc = arena.allocator();
var self = @This(){
.arena = arena,
.allocator = arenaAlloc,
.fileName = fileName,
.typeIdNames = std.StringArrayHashMap([]const u8).init(arenaAlloc),
.reflectedTypes = std.StringArrayHashMap(ReflectedTypeInfo).init(arenaAlloc),
.opts = opts,
};
var file = try std.fs.cwd().openFile(fileName, .{});
const fileContents = try file.readToEndAlloc(allocator, 10000000);
defer allocator.free(fileContents);
var tree = try std.json.parseFromSlice(std.json.Value, allocator, fileContents, .{});
defer tree.deinit();
//var tree = try parser.parseFromSlice(fileContents);
var root = tree.value.object;
//defer tree.deinit();
if (root.get("types")) |maybe| {
const typesRef = maybe.object;
for (typesRef.keys(), typesRef.values()) |k, v| {
const reflectedType = self.generateReflectedTypeInfo(v.object) catch |e| {
if (e == error.DummyObject) {
continue;
} else {
return e;
}
};
try self.reflectedTypes.put(try dupeString(self.allocator, k), reflectedType);
}
try self.updateReflectedSizes();
}
if (root.get("ssbos")) |maybe| {
const ssbos = maybe.array;
for (ssbos.items) |ssboObject| {
self.logv("ssbo {s}", .{ssboObject.object.get("name").?.string});
}
}
return self;
}
fn dupeString(allocator: std.mem.Allocator, str: []const u8) ![]u8 {
return try std.fmt.allocPrint(allocator, "{s}", .{str});
}
fn updateReflectedSize(self: *@This(), typeToUpdate: []const u8) void {
var reflected = self.reflectedTypes.getPtr(typeToUpdate).?;
if (reflected.size != 0)
return;
// get the last element
if (reflected.fields.items.len > 0) {
const lastField = reflected.fields.items[reflected.fields.items.len - 1];
if (lastField.typeName[0] == '_') {
self.updateReflectedSize(lastField.typeName);
reflected.size = lastField.offset + self.reflectedTypes.get(lastField.typeName).?.size;
} else {
// TODO: apply some padding rules
reflected.size = lastField.offset + lastField.size;
}
}
}
fn updateReflectedSizes(self: *@This()) !void {
for (self.reflectedTypes.keys()) |key| {
self.updateReflectedSize(key);
}
for (self.reflectedTypes.values()) |*v| {
for (v.fields.items) |*field| {
if (field.typeName[0] == '_') {
field.size = self.reflectedTypes.get(field.typeName).?.size;
}
}
}
}
fn generateReflectedTypeInfo(self: @This(), typeObject: std.json.ObjectMap) !ReflectedTypeInfo {
var info = ReflectedTypeInfo{
.fields = std.ArrayList(ReflectedField).init(self.allocator),
.name = try dupeString(self.allocator, typeObject.get("name").?.string),
.size = 0,
};
for (typeObject.get("members").?.array.items) |member| {
var reflectedField = ReflectedField{
.name = try dupeString(self.allocator, member.object.get("name").?.string),
.typeName = try dupeString(self.allocator, member.object.get("type").?.string),
.size = 0,
.offset = 0,
};
if (member.object.get("offset")) |offset| {
reflectedField.offset = @as(usize, @intCast(offset.integer));
} else {
return error.DummyObject;
}
// determine size
//
if (std.mem.eql(u8, reflectedField.typeName, "int"))
reflectedField.size = 4;
if (std.mem.eql(u8, reflectedField.typeName, "uint"))
reflectedField.size = 4;
if (std.mem.eql(u8, reflectedField.typeName, "vec2"))
reflectedField.size = 8;
if (std.mem.eql(u8, reflectedField.typeName, "vec4"))
reflectedField.size = 16;
if (std.mem.eql(u8, reflectedField.typeName, "float"))
reflectedField.size = 4;
if (std.mem.eql(u8, reflectedField.typeName, "mat4"))
reflectedField.size = 64;
if (std.mem.eql(u8, reflectedField.typeName, "vec3")) {
self.warn("vec3 usage detected, this is poorly supported by many vendors", .{});
reflectedField.size = 16;
}
if (std.mem.eql(u8, reflectedField.typeName, "u8vec4")) {
reflectedField.size = 4;
}
try info.fields.append(reflectedField);
}
return info;
}
pub fn deinit(self: *@This()) void {
self.arena.deinit();
}
pub fn render(self: *@This(), allocator: std.mem.Allocator) ![]u8 {
var ostring = std.ArrayList(u8).init(allocator);
defer ostring.deinit();
var writer = ostring.writer();
var validateChunk = std.ArrayList(u8).init(allocator);
defer validateChunk.deinit();
var validate = validateChunk.writer();
try validate.writeAll("comptime {");
// write the preamble
try writer.writeAll("// This file is automatically generated\n");
try writer.writeAll("const gl = @import(\"glslTypes\");\n\n");
if (self.opts.embedFile) |embedFile| {
// std.debug.print("embedFile = {s}\n", .{embedFile});
try writer.print("pub const spirv_raw = @embedFile(\"{s}\");\n", .{embedFile});
try writer.print("pub const spirv: *const[spirv_raw.len: 0] u8 align(4) = spirv_raw;\n", .{});
try writer.print("pub fn spv() []const u32 {{ var p: []const u32 = undefined; p.ptr = @alignCast(@ptrCast(spirv.ptr)); p.len = spirv.len / 4; return p; }}", .{});
// try writer.print("pub fn spv() []const u32 {{ " ++
// "var p: []const u32; " ++
// "p.ptr = @ptrCast(spirv.ptr);" ++
// "p.len = spirv.len >> 2; return p; }} ", .{});
// std.debug.print("{s}", .{ostring.items});
}
try writer.writeAll("const vec2 = gl.vec2;\n");
try writer.writeAll("const vec3 = gl.vec3;\n");
try writer.writeAll("const vec4 = gl.vec4;\n");
try writer.writeAll("const mat4 = gl.mat4;\n");
try writer.writeAll("const float = gl.float;\n");
try writer.writeAll("const u8vec4 = gl.u8vec4;\n");
try writer.writeAll("const uint = gl.uint;\n");
try writer.writeAll("const int = gl.int;\n");
for (self.reflectedTypes.values()) |reflected| {
if (std.mem.eql(u8, reflected.name, "gl_PerVertex")) {
continue;
}
var testChunk = std.ArrayList(u8).init(allocator);
defer testChunk.deinit();
var testChunkWriter = testChunk.writer();
try validate.print("gl.ValidateGeneratedStruct({s});", .{reflected.name});
try testChunkWriter.writeAll("\npub const FieldDetails: []const gl.FieldDetail = &.{\n");
try writer.print("\npub const {s} = extern struct {{ \n", .{reflected.name});
var currentOffset: usize = 0;
var padCount: usize = 0;
for (reflected.fields.items) |field| {
const expected: usize = field.offset;
try testChunkWriter.print(".{{ .name = \"{s}\", .offset = {d}, .size = {d} }},\n", .{ field.name, expected, field.size });
if (currentOffset != expected) {
if (currentOffset > expected) {
self.err(
"`{s}` has field `{s}` with invalid offsets. Expected to be at `{d}` but current offset is already `{d}`",
.{
reflected.name,
field.name,
expected,
currentOffset,
},
);
}
try writer.print("pad{d}:[{d}]u8,\n", .{ padCount, expected - currentOffset });
currentOffset += expected - currentOffset;
padCount += 1;
}
if (field.typeName[0] != '_') {
try writer.print("{s}: {s}, \n", .{ field.name, field.typeName });
} else {
const refTypeName = self.reflectedTypes.get(field.typeName).?.name;
try writer.print("{s}: {s}, \n", .{ field.name, refTypeName });
}
currentOffset += field.size;
}
try testChunkWriter.writeAll("};\n");
try writer.writeAll(testChunk.items);
try writer.writeAll("};\n\n");
}
try validate.writeAll("}");
try writer.writeAll(validateChunk.items);
try ostring.append(0);
var ast = try std.zig.Ast.parse(allocator, @as([:0]const u8, @ptrCast(ostring.items[0 .. ostring.items.len - 1])), .zig);
std.debug.print("output={s}", .{ostring.items[0 .. ostring.items.len - 1]});
defer ast.deinit(allocator);
const out = try ast.render(allocator);
return out;
}

View File

@ -1,153 +0,0 @@
// Copyright (c) peterino2@github.com
const std = @import("std");
const ReflectedJsonInfo = @import("ReflectedJsonInfo.zig");
const ProgramOptions = struct {
outputFile: []u8,
verbose: bool = false,
sourceFile: ?[]u8 = null,
errorMsg: ?[]u8 = null,
embedFile: ?[]u8 = null,
pub fn deinit(self: @This(), allocator: std.mem.Allocator) void {
allocator.free(self.outputFile);
if (self.sourceFile) |src| {
allocator.free(src);
}
if (self.errorMsg) |msg| {
allocator.free(msg);
}
if (self.embedFile) |embedFile| {
allocator.free(embedFile);
}
}
};
fn matchArgOpt(arg: []const u8, long: []const u8, short: ?[]const u8) bool {
if (arg.len < 2) {
return false;
}
if (arg[0] == '-') {
if (arg[1] == '-') {
return std.mem.eql(u8, arg[2..], long);
} else if (short) |s| {
return arg[1] == s[0];
}
}
return false;
}
fn dupe(allocator: std.mem.Allocator, str: []const u8) ![]u8 {
return try std.fmt.allocPrint(allocator, "{s}", .{str});
}
fn parseArgs(allocator: std.mem.Allocator) !ProgramOptions {
const ParseState = enum {
zero,
default,
output,
embed,
};
var state: ParseState = .zero;
var opts: ProgramOptions = .{
.outputFile = try dupe(allocator, "reflected_spirv.zig"),
};
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
for (args) |arg| {
switch (state) {
.zero => {
state = .default;
},
.default => {
if (arg[0] == '-') {
if (matchArgOpt(arg, "embed", "e"))
state = .embed;
if (matchArgOpt(arg, "output", "o"))
state = .output;
if (matchArgOpt(arg, "verbose", "v"))
opts.verbose = true;
} else {
if (opts.sourceFile) |src| {
allocator.free(src);
opts.sourceFile = null;
opts.errorMsg = try dupe(allocator, "Too many source files, this is not supported");
return opts;
}
opts.sourceFile = try dupe(allocator, arg);
}
},
.output => {
allocator.free(opts.outputFile);
opts.outputFile = try dupe(allocator, arg);
state = .default;
},
.embed => {
const embedFile = try dupe(allocator, arg);
const replacements = std.mem.replace(u8, arg, "\\", "/", embedFile);
_ = replacements;
if (opts.embedFile != null)
allocator.free(opts.embedFile.?);
opts.embedFile = embedFile;
state = .default;
},
}
}
return opts;
}
fn usage() void {
std.debug.print("usage: spirv-reflect <input file> [-o or --output] <output file>\n", .{});
std.debug.print("the input file is the json file which is the result from running spirv-cross --reflect\n", .{});
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
defer _ = gpa.deinit();
const opts = try parseArgs(allocator);
defer opts.deinit(allocator);
if (opts.errorMsg) |msg| {
std.debug.print("{s}\n", .{msg});
return;
}
if (opts.sourceFile == null) {
std.debug.print("Missing Source file. \n", .{});
usage();
return;
}
if (opts.verbose)
std.debug.print("parsing: {s} >> {s}\n", .{ opts.sourceFile.?, opts.outputFile });
var reflectedJson = try ReflectedJsonInfo.reflect(
allocator,
opts.sourceFile.?,
.{
.verbose = opts.verbose,
.embedFile = opts.embedFile,
},
);
defer reflectedJson.deinit();
const rendered = try reflectedJson.render(allocator);
defer allocator.free(rendered);
try std.fs.cwd().writeFile(.{
.sub_path = opts.outputFile,
.data = rendered,
});
}

View File

@ -1 +0,0 @@
// todo, put some tests here

37
lib/spng/build.zig vendored
View File

@ -6,24 +6,15 @@ pub fn build(b: *std.Build) void {
const static_build = b.option(bool, "static_build", "builds backlog dependencies for static linking") orelse false;
const spng_c = if (static_build)
b.addStaticLibrary(
.{
.optimize = optimize,
.target = target,
.name = "spng_c",
.link_libc = true,
},
)
else
b.addSharedLibrary(
.{
.optimize = optimize,
.target = target,
.name = "spng_c",
.link_libc = true,
},
);
const spng_c = b.addLibrary(.{
.linkage = if (static_build) .static else .dynamic,
.name = "spng_c",
.root_module = b.createModule(.{
.optimize = optimize,
.target = target,
.link_libc = true,
}),
});
spng_c.addCSourceFile(.{ .file = b.path("spng/spng.c") });
spng_c.addCSourceFile(.{ .file = b.path("miniz.c") });
@ -46,10 +37,12 @@ pub fn build(b: *std.Build) void {
const test_step = b.step("test", "run unit tests for spng");
const tests = b.addTest(.{
.target = target,
.optimize = optimize,
.root_source_file = b.path("src/spng.zig"),
.link_libc = true,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.root_source_file = b.path("src/spng.zig"),
.link_libc = true,
}),
});
tests.root_module.linkLibrary(spng_c);
tests.root_module.addIncludePath(b.path("spng"));

View File

@ -126,9 +126,7 @@ pub const SpngContext = struct {
pub fn loadFileAlloc(filename: []const u8, allocator: std.mem.Allocator) ![]u8 {
var file = try std.fs.cwd().openFile(filename, .{});
const filesize = (try file.stat()).size;
const buffer: []u8 = try allocator.alignedAlloc(u8, 8, filesize);
try file.reader().readNoEof(buffer);
return buffer;
return file.readToEndAlloc(allocator, filesize);
}
test "spngtest" {

View File

@ -98,9 +98,12 @@ pub fn build(b: *std.Build) void {
const test_step = b.step("test", "run unit tests for sdl3");
const tests = b.addExecutable(.{
.name = "test",
.target = target,
.optimize = optimize,
.link_libc = true,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libc = true,
.root_source_file = b.path("sdl3test/sdl3test.zig"),
}),
});
tests.addCSourceFile(.{

View File

@ -64,6 +64,7 @@ static const GLchar *GLFrag =
"const vec3 Rcoeff = vec3(1.164, 0.000, 1.793);\n"
"const vec3 Gcoeff = vec3(1.164, -0.213, -0.533);\n"
"const vec3 Bcoeff = vec3(1.164, 2.112, 0.000);\n"
"void main() {\n"
" vec2 tcoord;\n"
" vec3 yuv, rgb;\n"

1
lib/theoratest/sdl3test/sdl3test.zig vendored Normal file
View File

@ -0,0 +1 @@
pub fn main() !void {}

1
lib/theoratest/sdl3test/test.zig vendored Normal file
View File

@ -0,0 +1 @@
pub fn main() !void {}

8
lib/tracy/build.zig vendored
View File

@ -54,9 +54,11 @@ pub fn build(b: *std.Build) void {
// ========== tests =============
const test_step = b.step("test", "run unit tests for tracy");
const tests = b.addTest(.{
.target = target,
.optimize = optimize,
.root_source_file = b.path("tracy_test.zig"),
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.root_source_file = b.path("tracy_test.zig"),
}),
});
tests.root_module.addImport("tracy", mod);
const runArtifact = b.addRunArtifact(tests);

2
lib/tracy/tracy.zig vendored
View File

@ -7,7 +7,7 @@ pub const enabled = @import("build_options").tracy_enabled;
const debug_verify_stack_order = true;
pub usingnamespace if (enabled) tracy_full else tracy_stub;
pub const t = if (enabled) tracy_full else tracy_stub;
const tracy_stub = struct {
pub const ZoneCtx = struct {

View File

@ -3,5 +3,7 @@ const tracy = @import("tracy");
const std = @import("std");
test "test-tracy-integration" {
const z = tracy.t.ZoneNC(@src(), "hello", 0xaaaaaa);
std.debug.print("tracy integration testing enabled = {any}", .{tracy.enabled});
z.End();
}