Skip to content

Commit

Permalink
[progress #146] replace glslc with shaderc done
Browse files Browse the repository at this point in the history
  • Loading branch information
tiawl committed Apr 12, 2024
1 parent 2cd0e9e commit e55d411
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 251 deletions.
8 changes: 4 additions & 4 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -231,19 +231,19 @@ fn run_shader_compiler (builder: *std.Build,
.optimize = .Debug,
});

const glslang_dep = builder.dependency ("glslang", .{
const shaderc_dep = builder.dependency ("shaderc", .{
.target = profile.target,
.optimize = profile.optimize,
});
const glslang = glslang_dep.artifact ("glslang");
const shaderc = shaderc_dep.artifact ("shaderc");

const c = builder.createModule (.{
.root_source_file = .{ .path = try builder.build_root.join (
builder.allocator, &.{ "build", "shaders", "raw.zig", }), },
.target = builder.host,
.optimize = .Debug,
});
c.linkLibrary (glslang);
c.linkLibrary (shaderc);
shader_compiler.root_module.addImport ("c", c);

const install_shader_compiler =
Expand All @@ -253,7 +253,7 @@ fn run_shader_compiler (builder: *std.Build,

var self_dependency = std.Build.Dependency { .builder = builder, };

const shaders_module = shaders_compile.Step.compileModule (
const shaders_module = try shaders_compile.Step.compileModule (
&self_dependency, profile.compile_options);

const shader_compile_step = builder.addRunArtifact (shader_compiler);
Expand Down
6 changes: 3 additions & 3 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
.url = "https://github.com/tiawl/glfw.zig/archive/refs/tags/3.4.tar.gz",
.hash = "1220cae93f3e4476db397a438fbfb3aadce9da67feb6bb0e6dd87c75d861fea9257d",
},
.glslang = .{
.url = "https://github.com/tiawl/glslang.zig/archive/refs/tags/1.3.280.tar.gz",
.hash = "1220e85fbf78e71b8005076c5da4d13eddade60450f13c9c01468948db8dbe6be00f",
.shaderc = .{
.url = "https://github.com/tiawl/shaderc.zig/archive/refs/tags/2024.0.0.tar.gz",
.hash = "1220ec8b638d151181ab4d0661824ab21ade02958fb6c24a8f69e321957bc28ee665",
},
.@"zig-datetime" = .{
.url = "https://github.com/frmdstryr/zig-datetime/archive/a9c75242dfc119a305c1381c2352d2fc16b2e0aa.tar.gz",
Expand Down
259 changes: 106 additions & 153 deletions build/shaders/compiler.zig
Original file line number Diff line number Diff line change
@@ -1,196 +1,149 @@
const std = @import ("std");
const c = @import ("c");

const Stage = enum (c.glslang_stage_t)
// // An include result.
// typedef struct shaderc_include_result {
// // The name of the source file. The name should be fully resolved
// // in the sense that it should be a unique name in the context of the
// // includer. For example, if the includer maps source names to files in
// // a filesystem, then this name should be the absolute path of the file.
// // For a failed inclusion, this string is empty.
// const char* source_name;
// size_t source_name_length;
// // The text contents of the source file in the normal case.
// // For a failed inclusion, this contains the error message.
// const char* content;
// size_t content_length;
// // User data to be passed along with this request.
// void* user_data;
// } shaderc_include_result;
//
// // The kinds of include requests.
// enum shaderc_include_type {
// shaderc_include_type_relative, // E.g. #include "source"
// shaderc_include_type_standard // E.g. #include <source>
// };
//
// // An includer callback type for mapping an #include request to an include
// // result. The user_data parameter specifies the client context. The
// // requested_source parameter specifies the name of the source being requested.
// // The type parameter specifies the kind of inclusion request being made.
// // The requesting_source parameter specifies the name of the source containing
// // the #include request. The includer owns the result object and its contents,
// // and both must remain valid until the release callback is called on the result
// // object.
// typedef shaderc_include_result* (*shaderc_include_resolve_fn)(
// void* user_data, const char* requested_source, int type,
// const char* requesting_source, size_t include_depth);
//
// // An includer callback type for destroying an include result.
// typedef void (*shaderc_include_result_release_fn)(
// void* user_data, shaderc_include_result* include_result);
//
// pub const shaderc_include_resolve_fn = ?*const fn (?*anyopaque, [*c]const u8, c_int, [*c]const u8, usize) callconv(.C) [*c]shaderc_include_result;
// pub const shaderc_include_result_release_fn = ?*const fn (?*anyopaque, [*c]shaderc_include_result) callconv(.C) void;

const Stage = enum (c.shaderc_shader_kind)
{
vert = c.GLSLANG_STAGE_VERTEX,
frag = c.GLSLANG_STAGE_FRAGMENT,
vert = c.shaderc_glsl_vertex_shader,
frag = c.shaderc_glsl_fragment_shader,
};

const VulkanEnvVersion = enum (c.glslang_target_client_version_t)
const VulkanEnvVersion = enum (c.shaderc_env_version)
{
@"0" = c.GLSLANG_TARGET_VULKAN_1_0,
@"1" = c.GLSLANG_TARGET_VULKAN_1_1,
@"2" = c.GLSLANG_TARGET_VULKAN_1_2,
@"3" = c.GLSLANG_TARGET_VULKAN_1_3,
@"0" = c.shaderc_env_version_vulkan_1_0,
@"1" = c.shaderc_env_version_vulkan_1_1,
@"2" = c.shaderc_env_version_vulkan_1_2,
@"3" = c.shaderc_env_version_vulkan_1_3,
};

const Optimization = enum
const Optimization = enum (c.shaderc_optimization_level)
{
Zero,
Performance,
Zero = c.shaderc_optimization_level_zero,
Performance = c.shaderc_optimization_level_performance,
};

fn include_local (context: ?*anyopaque, header_name: [*c] const u8,
includer_name: [*c] const u8, include_depth: usize) callconv (.C) [*c] c.glsl_include_result_t
{
const ctx: *const struct { dir: [] const u8, } = @alignCast (@ptrCast (context.?));

const result = std.heap.c_allocator.create (c.glsl_include_result_t) catch @panic ("oom");

const includer_name_span = std.mem.span (@as ([*:0]const u8, @ptrCast (includer_name)));
const header_name_span = std.mem.span (@as ([*:0]const u8, @ptrCast (header_name)));

const includer_dir_relative = std.fs.path.dirname (includer_name_span) orelse "";

const file_path = std.fs.path.join (std.heap.c_allocator,
&.{ ctx.dir, includer_dir_relative, header_name_span, }) catch @panic ("oom");

const relative_to_root = std.fs.path.relative (std.heap.c_allocator,
ctx.dir, file_path) catch @panic ("");

std.log.info ("includer: \"{s}\"", .{ includer_name, });
std.log.info ("includer_depth: {}", .{ include_depth, });
std.log.info ("header_name: \"{s}\"", .{ header_name, });
std.log.info ("relative_to_root: \"{s}\"", .{ relative_to_root, });

const file_contents = std.fs.cwd ().readFileAlloc (std.heap.c_allocator, file_path, std.math.maxInt (u32)) catch return null;

result.header_name = header_name;
result.header_length = file_contents.len;
result.header_data = file_contents.ptr;

return result;
}

fn free_include_result (context: ?*anyopaque, glsl_include_result: [*c] c.glsl_include_result_t) callconv (.C) c_int
{
_ = context;

std.heap.c_allocator.destroy (@as (*c.glsl_include_result_t, @ptrCast (glsl_include_result)));

return 0;
}

pub fn main () !void
{
var arena = std.heap.ArenaAllocator.init (std.heap.page_allocator);
defer arena.deinit ();
const allocator = arena.allocator ();

var it = std.process.args ();
_ = it.next ().?;
const in = it.next ().?;
const out = it.next ().?;
const optimization = std.meta.stringToEnum (Optimization, it.next ().?).?;
var arg = std.process.args ();
_ = arg.next ().?;
const optimization =
@intFromEnum (std.meta.stringToEnum (Optimization, arg.next ().?).?);
const env_version =
@intFromEnum (std.meta.stringToEnum (VulkanEnvVersion, it.next ().?).?);
const stage =
@intFromEnum (std.meta.stringToEnum (Stage, in [in.len - 4 ..]).?);
@intFromEnum (std.meta.stringToEnum (VulkanEnvVersion, arg.next ().?).?);

std.log.info ("Compiling {s} into {s}", .{ in, out, });
var in_dir: std.fs.Dir = undefined;
var out_dir: std.fs.Dir = undefined;

var context = .{ .dir = std.fs.path.dirname (in).?, };
const compiler = c.shaderc_compiler_initialize ();
defer c.shaderc_compiler_release (compiler);

var dir = try std.fs.openDirAbsolute (context.dir, .{});
defer dir.close ();
const options = c.shaderc_compile_options_initialize ();
defer c.shaderc_compile_options_release (options);

const source = try dir.readFileAllocOptions (
allocator, in, std.math.maxInt (usize), null, 1, 0);
c.shaderc_compile_options_set_target_env (options,
c.shaderc_target_env_vulkan, env_version);

if (c.glslang_initialize_process () == 0)
return error.FailedToInitializeProcess;
defer c.glslang_finalize_process ();
c.shaderc_compile_options_set_optimization_level (options, optimization);

var input = c.struct_glslang_input_s
{
.language = c.GLSLANG_SOURCE_GLSL,
.stage = stage,
.client = c.GLSLANG_CLIENT_VULKAN,
.client_version = env_version,
.target_language = c.GLSLANG_TARGET_SPV,
.target_language_version = c.GLSLANG_TARGET_SPV_1_5,
.code = source.ptr,
.default_version = 450,
.default_profile = c.GLSLANG_NO_PROFILE,
.force_default_version_and_profile = @intFromBool (false),
.forward_compatible = @intFromBool (false),
.messages = c.GLSLANG_MSG_DEFAULT_BIT | c.GLSLANG_MSG_DEBUG_INFO_BIT |
c.GLSLANG_MSG_ENHANCED | c.GLSLANG_MSG_CASCADING_ERRORS_BIT,
.resource = c.glslang_default_resource (),
.callbacks = .{
.include_local = &include_local,
.include_system = &include_local,
.free_include_result = &free_include_result,
},
.callbacks_ctx = &context,
};

const shader = c.glslang_shader_create (@ptrCast (&input)) orelse
return error.FailedToCreateShader;
defer c.glslang_shader_delete (shader);

c.glslang_shader_set_options (shader, c.GLSLANG_SHADER_AUTO_MAP_LOCATIONS);

errdefer
{
const info_log = std.mem.span (@as ([*:0] const u8,
@ptrCast (c.glslang_shader_get_info_log (shader))));
//c.shaderc_compile_options_set_include_callbacks (options);

var info_log_lines = std.mem.tokenize (u8, info_log, &.{ '\n', });
var shaders_path: ?[] const u8 = null;

while (info_log_lines.next ()) |info_log_line|
while (arg.next ()) |in|
{
if (shaders_path == null)
{
const error_token: [] const u8 = "ERROR: ";

if (std.mem.startsWith (u8, info_log_line, error_token))
var it = try std.fs.path.componentIterator (in);
var skip = it.last ();
while (skip != null and !std.mem.eql (u8, skip.?.name, "shaders")) skip = it.previous ();
var components = std.ArrayList ([] const u8).init (allocator);
if (skip != null and std.mem.eql (u8, skip.?.name, "shaders"))
{
const error_message = info_log_line [error_token.len ..];

if (std.mem.startsWith (u8, error_message, "0:"))
std.log.err ("{s}:{s}", .{ in, error_message [2 ..], })
else std.log.err ("{s}", .{ error_message, });
}
try components.append (try allocator.dupe (u8, skip.?.name));
while (it.previous ()) |prev| try components.append (try allocator.dupe (u8, prev.name));
std.mem.reverse ([] const u8, components.items);
shaders_path = try std.fs.path.join (allocator, components.items);
} else return error.FailedToBuildShadersPath;
}

const debug_log: ?[*:0] const u8 =
@ptrCast (c.glslang_shader_get_info_debug_log (shader));
const out = arg.next ().?;
const stage = @intFromEnum (std.meta.stringToEnum (Stage,
std.fs.path.extension (in) [1 ..]).?);

if (debug_log != null and std.mem.span (debug_log.?).len != 0)
std.log.debug ("{s}", .{ debug_log.?, });
}
std.log.info ("Compiling {s}", .{ in, });

if (c.glslang_shader_preprocess (shader, @ptrCast (&input)) == 0) return error.CompileFailed;
if (c.glslang_shader_parse (shader, @ptrCast (&input)) == 0) return error.CompileFailed;
in_dir = try std.fs.openDirAbsolute (std.fs.path.dirname (in).?, .{});
defer in_dir.close ();

const program = c.glslang_program_create () orelse return error.FailedToCreateProgram;
defer c.glslang_program_delete (program);
const source = try in_dir.readFileAllocOptions (allocator,
std.fs.path.basename (in), std.math.maxInt (usize), null, 1, 0);

c.glslang_program_add_shader (program, shader);
const relative = try std.fs.path.relative (allocator, shaders_path.?, in);

if (c.glslang_program_link (program, c.GLSLANG_MSG_SPV_RULES_BIT | c.GLSLANG_MSG_VULKAN_RULES_BIT) == 0) return error.LinkFailed;
if (c.glslang_program_map_io (program) == 0) return error.InputOutputMappingFailed;
const result = c.shaderc_compile_into_spv (compiler, source.ptr,
source.len, stage, relative.ptr, std.fs.path.stem (relative).ptr, options);
defer c.shaderc_result_release (result);

//const in_z = try allocator.dupeZ (u8, in);
const status = c.shaderc_result_get_compilation_status (result);

//c.glslang_program_add_source_text (program, stage, source.ptr, source.len);
//c.glslang_program_set_source_file (program, stage, in_z);

var spirv_options = c.glslang_spv_options_t {
.generate_debug_info = optimization != .Performance,
.strip_debug_info = optimization == .Performance,
.disable_optimizer = optimization != .Performance,
.optimize_size = false,
.disassemble = false,
.validate = true,
.emit_nonsemantic_shader_debug_info = optimization != .Performance,
.emit_nonsemantic_shader_debug_source = optimization != .Performance,
};
if (status != c.shaderc_compilation_status_success)
{
std.debug.print ("Shader compilation error for \"{s}\": {s}",
.{ in, c.shaderc_result_get_error_message (result), });
}

c.glslang_program_SPIRV_generate_with_options (program, stage, &spirv_options);
const bytes = c.shaderc_result_get_bytes (result);
const length = c.shaderc_result_get_length (result);

const spirv_messages = c.glslang_program_SPIRV_get_messages (program);
out_dir = try std.fs.openDirAbsolute (std.fs.path.dirname (out).?, .{});
defer out_dir.close ();

if (spirv_messages != null)
{
std.log.err ("{s}", .{ spirv_messages, });
return error.SpirvGenerationFailed;
try out_dir.writeFile (std.fs.path.basename (out),
std.mem.sliceAsBytes (bytes [0 .. length]));
}

const binary_size = c.glslang_program_SPIRV_get_size (program);
const spirv_ptr = c.glslang_program_SPIRV_get_ptr (program);

const spirv_data = spirv_ptr [0 .. binary_size];

try std.fs.cwd ().writeFile (out, std.mem.sliceAsBytes (spirv_data));
}
3 changes: 1 addition & 2 deletions build/shaders/raw.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
pub usingnamespace @cImport ({
@cInclude ("glslang/Public/resource_limits_c.h");
@cInclude ("glslang/Include/glslang_c_interface.h");
@cInclude ("shaderc/shaderc.h");
});
Loading

0 comments on commit e55d411

Please sign in to comment.