-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[progress #146] replace glslc with shaderc done
- Loading branch information
Showing
13 changed files
with
189 additions
and
251 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
}); |
Oops, something went wrong.