rtengine/src/tools/assetc/shader_processor.c
2024-01-16 16:10:56 +01:00

123 lines
4.7 KiB
C

#include "assetmeta.h"
#include "processing.h"
#include "processing_flags.h"
#include "utils.h"
#include "runtime/buffer_manager.h"
#include <shaderc/shaderc.h>
#include <string.h>
static shaderc_include_result *ResolveInclude(void *user_data,
const char *requested_source,
int type,
const char *requesting_source,
size_t include_depth) {
shaderc_include_result *result = NULL;
return result;
}
static void ReleaseIncludeResult(void *user_data, shaderc_include_result *result) {
}
rt_result rtProcessShaderFile(rt_file_id file,
void *buffer,
size_t size,
uint32_t flags,
rt_processor_output *output) {
/* If we determine that shader compilation takes too long, we can instead
* keep the compiler around */
shaderc_compiler_t compiler = shaderc_compiler_initialize();
if (!compiler) {
rtLog("ASSETC", "Failed to initialize the shaderc compiler.");
return RT_PROCESSING_FAILED;
}
const char *path = rtGetFilePath(file);
shaderc_compile_options_t options = shaderc_compile_options_initialize();
if (!options) {
rtLog("ASSETC", "Failed to initialize shader compile options.");
shaderc_compiler_release(compiler);
return RT_PROCESSING_FAILED;
}
shaderc_compile_options_set_include_callbacks(options,
ResolveInclude,
ReleaseIncludeResult,
NULL);
uint32_t optimize_from_flags = flags & RT_SHADER_FLAG_OPTIMIZE_MASK;
if (optimize_from_flags == RT_SHADER_FLAG_OPTIMIZE_SPEED)
shaderc_compile_options_set_optimization_level(options,
shaderc_optimization_level_performance);
else if (optimize_from_flags == RT_SHADER_FLAG_OPTIMIZE_SIZE)
shaderc_compile_options_set_optimization_level(options, shaderc_optimization_level_size);
else
shaderc_compile_options_set_optimization_level(options, shaderc_optimization_level_zero);
uint32_t type_from_flags = flags & RT_SHADER_FLAG_TYPE_MASK;
shaderc_shader_kind shaderc_kind;
switch (type_from_flags) {
case RT_SHADER_FLAG_VERTEX:
shaderc_kind = shaderc_glsl_vertex_shader;
break;
case RT_SHADER_FLAG_FRAGMENT:
shaderc_kind = shaderc_glsl_fragment_shader;
break;
case RT_SHADER_FLAG_COMPUTE:
shaderc_kind = shaderc_glsl_compute_shader;
break;
default:
rtLog("ASSETC", "Invalid shader stage flag %u", type_from_flags);
shaderc_compile_options_release(options);
shaderc_compiler_release(compiler);
return RT_PROCESSING_FAILED;
}
shaderc_compilation_result_t result = shaderc_compile_into_spv(compiler,
(const char *)buffer,
size,
shaderc_kind,
path,
"main",
options);
shaderc_compilation_status status = shaderc_result_get_compilation_status(result);
if (status != shaderc_compilation_status_success || shaderc_result_get_num_errors(result) > 0) {
rtLog("ASSETC",
"Compilation of %s failed: %s",
path,
shaderc_result_get_error_message(result));
shaderc_result_release(result);
shaderc_compile_options_release(options);
shaderc_compiler_release(compiler);
return RT_PROCESSING_FAILED;
}
size_t output_size = shaderc_result_get_length(result);
output->data = rtAllocBuffer(output_size);
if (!output->data) {
shaderc_result_release(result);
shaderc_compile_options_release(options);
shaderc_compiler_release(compiler);
rtLog("ASSETC", "Failed to allocate %zu bytes for shader compilation output.", output_size);
return RT_PROCESSING_FAILED;
}
const uint32_t *spv_bytes = (uint32_t *)shaderc_result_get_bytes(result);
memcpy(output->data, spv_bytes, output_size);
output->size = output_size;
shaderc_result_release(result);
shaderc_compile_options_release(options);
shaderc_compiler_release(compiler);
output->asset_uid = rtCalculateUID(path);
return RT_SUCCESS;
}