diff --git a/Sources/api.h b/Sources/api.h new file mode 100644 index 0000000..31f790a --- /dev/null +++ b/Sources/api.h @@ -0,0 +1,3 @@ +#pragma once + +typedef enum api_kind { API_UNKNOWN, API_DIRECT3D9, API_DIRECT3D11, API_DIRECT3D12, API_OPENGL, API_METAL, API_WEBGPU, API_VULKAN } api_kind; diff --git a/Sources/backends/hlsl.c b/Sources/backends/hlsl.c index b0509f3..05b8a77 100644 --- a/Sources/backends/hlsl.c +++ b/Sources/backends/hlsl.c @@ -474,7 +474,7 @@ static void write_functions(char *hlsl, size_t *offset, shader_stage stage, func } } -static void hlsl_export_vertex(char *directory, Direct3D d3d, function *main) { +static void hlsl_export_vertex(char *directory, api_kind d3d, function *main) { char *hlsl = (char *)calloc(1024 * 1024, 1); size_t offset = 0; @@ -495,14 +495,15 @@ static void hlsl_export_vertex(char *directory, Direct3D d3d, function *main) { size_t output_size; int result = 1; switch (d3d) { - case DIRECT3D_9: + case API_DIRECT3D9: result = compile_hlsl_to_d3d9(hlsl, &output, &output_size, SHADER_STAGE_VERTEX, false); break; - case DIRECT3D_11: + case API_DIRECT3D11: + case API_DIRECT3D12: result = compile_hlsl_to_d3d11(hlsl, &output, &output_size, SHADER_STAGE_VERTEX, false); break; default: - error(context, "Unknown Direct3D version"); + error(context, "Unsupported API for HLSL"); } check(result == 0, context, "HLSL compilation failed"); @@ -517,7 +518,7 @@ static void hlsl_export_vertex(char *directory, Direct3D d3d, function *main) { write_bytecode(hlsl, directory, filename, var_name, output, output_size); } -static void hlsl_export_fragment(char *directory, Direct3D d3d, function *main) { +static void hlsl_export_fragment(char *directory, api_kind d3d, function *main) { char *hlsl = (char *)calloc(1024 * 1024, 1); size_t offset = 0; @@ -536,14 +537,15 @@ static void hlsl_export_fragment(char *directory, Direct3D d3d, function *main) size_t output_size; int result = 1; switch (d3d) { - case DIRECT3D_9: + case API_DIRECT3D9: result = compile_hlsl_to_d3d9(hlsl, &output, &output_size, SHADER_STAGE_FRAGMENT, false); break; - case DIRECT3D_11: + case API_DIRECT3D11: + case API_DIRECT3D12: result = compile_hlsl_to_d3d11(hlsl, &output, &output_size, SHADER_STAGE_FRAGMENT, false); break; default: - error(context, "Unknown Direct3D version"); + error(context, "Unsupported API for HLSL"); } check(result == 0, context, "HLSL compilation failed"); @@ -558,7 +560,7 @@ static void hlsl_export_fragment(char *directory, Direct3D d3d, function *main) write_bytecode(hlsl, directory, filename, var_name, output, output_size); } -void hlsl_export(char *directory, Direct3D d3d) { +void hlsl_export(char *directory, api_kind d3d) { int cbuffer_index = 0; int texture_index = 0; int sampler_index = 0; diff --git a/Sources/backends/hlsl.h b/Sources/backends/hlsl.h index 736ff05..fe2df6e 100644 --- a/Sources/backends/hlsl.h +++ b/Sources/backends/hlsl.h @@ -1,7 +1,7 @@ #pragma once -#include +#include "../api.h" -typedef enum Direct3D { DIRECT3D_9, DIRECT3D_11 } Direct3D; +#include -void hlsl_export(char *directory, Direct3D d3d); +void hlsl_export(char *directory, api_kind d3d); diff --git a/Sources/backends/wgsl.c b/Sources/backends/wgsl.c index 5b33e26..7f923f6 100644 --- a/Sources/backends/wgsl.c +++ b/Sources/backends/wgsl.c @@ -41,11 +41,52 @@ static char *function_string(name_id func) { static void write_code(char *wgsl, char *directory, const char *filename) { char full_filename[512]; - sprintf(full_filename, "%s/%s.c", directory, filename); - FILE *file = fopen(full_filename, "wb"); - fprintf(file, "%s", wgsl); - fclose(file); + { + sprintf(full_filename, "%s/%s.h", directory, filename); + FILE *file = fopen(full_filename, "wb"); + fprintf(file, "#include \n\n"); + fprintf(file, "extern const char *wgsl;\n"); + fprintf(file, "extern size_t wgsl_size;\n"); + fclose(file); + } + + { + sprintf(full_filename, "%s/%s.c", directory, filename); + FILE *file = fopen(full_filename, "wb"); + + fprintf(file, "#include \"%s.h\"\n\n", filename); + + fprintf(file, "const char *wgsl = \""); + + size_t length = strlen(wgsl); + + for (size_t i = 0; i < length; ++i) { + if (wgsl[i] == '\n') { + fprintf(file, "\\n"); + } + else if (wgsl[i] == '\r') { + fprintf(file, "\\r"); + } + else if (wgsl[i] == '\t') { + fprintf(file, "\\t"); + } + else if (wgsl[i] == '"') { + fprintf(file, "\\\""); + } + else { + fprintf(file, "%c", wgsl[i]); + } + } + + fprintf(file, "\";\n\n"); + + fprintf(file, "size_t wgsl_size = %" PRIu64 ";\n\n", length); + + fprintf(file, "/*\n%s*/\n", wgsl); + + fclose(file); + } } static void find_referenced_functions(function *f, function **functions, size_t *functions_size) { diff --git a/Sources/integrations/c.c b/Sources/integrations/c.c index 888a02d..cc8c534 100644 --- a/Sources/integrations/c.c +++ b/Sources/integrations/c.c @@ -51,7 +51,7 @@ static const char *structure_type(type_id type) { static int global_register_indices[512]; -void c_export(char *directory) { +void c_export(char *directory, api_kind api) { int cbuffer_index = 0; int texture_index = 0; int sampler_index = 0; @@ -192,18 +192,23 @@ void c_export(char *directory) { fprintf(output, "#include \"kong.h\"\n\n"); - for (type_id i = 0; get_type(i) != NULL; ++i) { - type *t = get_type(i); - if (!t->built_in && t->attribute == add_name("pipe")) { - for (size_t j = 0; j < t->members.size; ++j) { - debug_context context = {0}; - if (t->members.m[j].name == add_name("vertex")) { - check(t->members.m[j].value.kind == TOKEN_IDENTIFIER, context, "vertex expects an identifier"); - fprintf(output, "#include \"kong_%s.h\"\n", get_name(t->members.m[j].value.identifier)); - } - else if (t->members.m[j].name == add_name("fragment")) { - check(t->members.m[j].value.kind == TOKEN_IDENTIFIER, context, "fragment expects an identifier"); - fprintf(output, "#include \"kong_%s.h\"\n", get_name(t->members.m[j].value.identifier)); + if (api == API_WEBGPU) { + fprintf(output, "#include \"wgsl.h\"\n"); + } + else { + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *t = get_type(i); + if (!t->built_in && t->attribute == add_name("pipe")) { + for (size_t j = 0; j < t->members.size; ++j) { + debug_context context = {0}; + if (t->members.m[j].name == add_name("vertex")) { + check(t->members.m[j].value.kind == TOKEN_IDENTIFIER, context, "vertex expects an identifier"); + fprintf(output, "#include \"kong_%s.h\"\n", get_name(t->members.m[j].value.identifier)); + } + else if (t->members.m[j].name == add_name("fragment")) { + check(t->members.m[j].value.kind == TOKEN_IDENTIFIER, context, "fragment expects an identifier"); + fprintf(output, "#include \"kong_%s.h\"\n", get_name(t->members.m[j].value.identifier)); + } } } } @@ -293,7 +298,16 @@ void c_export(char *directory) { } } + if (api == API_WEBGPU) { + fprintf(output, "\nvoid kinc_g5_internal_webgpu_create_shader_module(const void *source, size_t length);\n"); + } + fprintf(output, "\nvoid kong_init(void) {\n"); + + if (api == API_WEBGPU) { + fprintf(output, "\tkinc_g5_internal_webgpu_create_shader_module(wgsl, wgsl_size);\n\n"); + } + for (type_id i = 0; get_type(i) != NULL; ++i) { type *t = get_type(i); if (!t->built_in && t->attribute == add_name("pipe")) { @@ -303,16 +317,28 @@ void c_export(char *directory) { for (size_t j = 0; j < t->members.size; ++j) { if (t->members.m[j].name == add_name("vertex")) { - fprintf(output, "\tkinc_g4_shader_init(&%s, %s_code, %s_code_size, KINC_G4_SHADER_TYPE_VERTEX);\n", - get_name(t->members.m[j].value.identifier), get_name(t->members.m[j].value.identifier), - get_name(t->members.m[j].value.identifier)); + if (api == API_WEBGPU) { + fprintf(output, "\tkinc_g4_shader_init(&%s, \"%s\", 0, KINC_G4_SHADER_TYPE_VERTEX);\n", get_name(t->members.m[j].value.identifier), + get_name(t->members.m[j].value.identifier)); + } + else { + fprintf(output, "\tkinc_g4_shader_init(&%s, %s_code, %s_code_size, KINC_G4_SHADER_TYPE_VERTEX);\n", + get_name(t->members.m[j].value.identifier), get_name(t->members.m[j].value.identifier), + get_name(t->members.m[j].value.identifier)); + } fprintf(output, "\t%s.vertex_shader = &%s;\n\n", get_name(t->name), get_name(t->members.m[j].value.identifier)); vertex_shader_name = t->members.m[j].value.identifier; } else if (t->members.m[j].name == add_name("fragment")) { - fprintf(output, "\tkinc_g4_shader_init(&%s, %s_code, %s_code_size, KINC_G4_SHADER_TYPE_FRAGMENT);\n", - get_name(t->members.m[j].value.identifier), get_name(t->members.m[j].value.identifier), - get_name(t->members.m[j].value.identifier)); + if (api == API_WEBGPU) { + fprintf(output, "\tkinc_g4_shader_init(&%s, \"%s\", 0, KINC_G4_SHADER_TYPE_FRAGMENT);\n", + get_name(t->members.m[j].value.identifier), get_name(t->members.m[j].value.identifier)); + } + else { + fprintf(output, "\tkinc_g4_shader_init(&%s, %s_code, %s_code_size, KINC_G4_SHADER_TYPE_FRAGMENT);\n", + get_name(t->members.m[j].value.identifier), get_name(t->members.m[j].value.identifier), + get_name(t->members.m[j].value.identifier)); + } fprintf(output, "\t%s.fragment_shader = &%s;\n\n", get_name(t->name), get_name(t->members.m[j].value.identifier)); } else if (t->members.m[j].name == add_name("depth_write")) { diff --git a/Sources/integrations/c.h b/Sources/integrations/c.h index bee8962..f4bf354 100644 --- a/Sources/integrations/c.h +++ b/Sources/integrations/c.h @@ -1,5 +1,7 @@ #pragma once +#include "../api.h" + #include -void c_export(char *directory); +void c_export(char *directory, api_kind api); diff --git a/Sources/kong.c b/Sources/kong.c index 5739514..478fa84 100644 --- a/Sources/kong.c +++ b/Sources/kong.c @@ -386,7 +386,7 @@ int main(int argc, char **argv) { char *inputs[256] = {0}; size_t inputs_size = 0; char *platform = NULL; - char *api = NULL; + api_kind api = API_UNKNOWN; char *output = NULL; for (int i = 1; i < argc; ++i) { @@ -465,7 +465,31 @@ int main(int argc, char **argv) { break; } case MODE_API: { - api = argv[i]; + if (strcmp(argv[i], "direct3d9") == 0) { + api = API_DIRECT3D9; + } + else if (strcmp(argv[i], "direct3d11") == 0) { + api = API_DIRECT3D11; + } + else if (strcmp(argv[i], "direct3d12") == 0) { + api = API_DIRECT3D12; + } + else if (strcmp(argv[i], "opengl") == 0) { + api = API_OPENGL; + } + else if (strcmp(argv[i], "metal") == 0) { + api = API_METAL; + } + else if (strcmp(argv[i], "webgpu") == 0) { + api = API_WEBGPU; + } + else if (strcmp(argv[i], "vulkan") == 0) { + api = API_VULKAN; + } + else { + debug_context context = {0}; + error(context, "Unknown API %s", argv[i]); + } mode = MODE_MODECHECK; break; } @@ -477,7 +501,7 @@ int main(int argc, char **argv) { check(inputs_size > 0, context, "no input parameters found"); check(output != NULL, context, "output parameter not found"); check(platform != NULL, context, "platform parameter not found"); - check(api != NULL, context, "api parameter not found"); + check(api != API_UNKNOWN, context, "api parameter not found"); names_init(); types_init(); @@ -522,27 +546,32 @@ int main(int argc, char **argv) { convert_function_block(&get_function(i)->code, get_function(i)->block); } - if (strcmp(api, "direct3d9") == 0) { - hlsl_export(output, DIRECT3D_9); - } - else if (strcmp(api, "direct3d11") == 0 || strcmp(api, "direct3d12") == 0) { - hlsl_export(output, DIRECT3D_11); - } - else if (strcmp(api, "opengl") == 0) { + switch (api) { + case API_DIRECT3D9: + case API_DIRECT3D11: + case API_DIRECT3D12: + hlsl_export(output, api); + break; + case API_OPENGL: glsl_export(output); - } - else if (strcmp(api, "metal") == 0) { + break; + case API_METAL: metal_export(output); - } - else if (strcmp(api, "webgpu") == 0) { + break; + case API_WEBGPU: wgsl_export(output); + break; + case API_VULKAN: { + debug_context context = {0}; + error(context, "SPIRV not yet supported"); } - else { + default: { debug_context context = {0}; error(context, "Unknown API"); } + } - c_export(output); + c_export(output, api); return 0; }