updated spng, theoratest, spng, tracy
This commit is contained in:
parent
de6ccd211b
commit
d738dd2260
|
|
@ -1,2 +0,0 @@
|
|||
zig-cache/
|
||||
zig-out/
|
||||
|
|
@ -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.
|
||||
|
|
@ -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`
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
.{
|
||||
.name = .SpirvReflect,
|
||||
.version = "0.0.0",
|
||||
.dependencies = .{
|
||||
.glslTypes = .{ .path = "glslTypes" },
|
||||
},
|
||||
.paths = .{
|
||||
"",
|
||||
},
|
||||
.fingerprint = 0x8bdf68352d7dc5fa,
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
.{
|
||||
.name = "testing",
|
||||
.version = "0.0.0",
|
||||
|
||||
.dependencies = .{
|
||||
.SpirvReflect = .{ .path = "../" },
|
||||
},
|
||||
|
||||
.paths = .{
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
.{
|
||||
.name = "glslTypes",
|
||||
.version = "0.0.0",
|
||||
.dependencies = .{},
|
||||
.paths = .{
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
.{
|
||||
.name = "glslTypes",
|
||||
.version = "0.0.0",
|
||||
.dependencies = .{},
|
||||
.paths = .{
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
// todo, put some tests here
|
||||
|
|
@ -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"));
|
||||
|
|
|
|||
|
|
@ -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" {
|
||||
|
|
|
|||
|
|
@ -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(.{
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
pub fn main() !void {}
|
||||
|
|
@ -0,0 +1 @@
|
|||
pub fn main() !void {}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue