diff --git a/base/project.js b/base/project.js index 4fd59c40..06ef31a0 100644 --- a/base/project.js +++ b/base/project.js @@ -51,6 +51,7 @@ if (!flags.lite) { project.add_tsfiles("sources/ts/nodes"); project.add_shaders("shaders/*.glsl"); project.add_shaders("shaders/draw/*.glsl"); + project.add_shaders("shaders/draw/*.kong"); project.add_assets("assets/*", { destination: "data/{name}" }); project.add_assets("assets/locale/*", { destination: "data/locale/{name}" }); project.add_assets("assets/licenses/**", { destination: "data/licenses/{name}" }); diff --git a/base/shaders/draw/draw_colored.kong_ b/base/shaders/draw/draw_colored.kong_ new file mode 100644 index 00000000..87a8ab48 --- /dev/null +++ b/base/shaders/draw/draw_colored.kong_ @@ -0,0 +1,31 @@ + +const constants: { + P: float4x4; +}; + +struct vert_in { + pos: float3; + col: float4; +} + +struct vert_out { + pos: float4; + col: float4; +} + +fun draw_colored_vert(input: vert_in): vert_out { + var output: vert_out; + output.pos = constants.P * float4(input.pos, 1.0); + output.col = input.col; + return output; +} + +fun draw_colored_frag(input: vert_out): float4 { + return input.col; +} + +#[pipe] +struct pipe { + vertex = draw_colored_vert; + fragment = draw_colored_frag; +} diff --git a/base/sources/libs/kong/license.txt b/base/sources/libs/kong/license.txt new file mode 100644 index 00000000..87a5c324 --- /dev/null +++ b/base/sources/libs/kong/license.txt @@ -0,0 +1,19 @@ +Copyright (c) 2022 the Kongruent development team + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. diff --git a/base/sources/libs/kong/project.js b/base/sources/libs/kong/project.js new file mode 100644 index 00000000..e4a16073 --- /dev/null +++ b/base/sources/libs/kong/project.js @@ -0,0 +1,16 @@ +let project = new Project('Kongruent'); + +// project.add_define('KONG_LIBRARY'); +project.add_cfiles('sources/libs/*.c'); +project.add_cfiles('sources/*.c'); +project.add_cfiles('sources/backends/*.c'); +project.add_cfiles('sources/backends/*.cpp'); + +if (platform === "windows") { + project.add_define('_CRT_SECURE_NO_WARNINGS'); + project.add_lib('d3dcompiler'); + project.add_include_dir('sources/libs/dxc/inc'); + project.add_lib('sources/libs/dxc/lib/x64/dxcompiler'); +} + +return project; diff --git a/base/sources/libs/kong/readme.md b/base/sources/libs/kong/readme.md new file mode 100644 index 00000000..69a5c635 --- /dev/null +++ b/base/sources/libs/kong/readme.md @@ -0,0 +1,3 @@ +Kongruent by RobDangerous revision d1fecec8fd4cd8936d8e1fb1942b89c57c475a74. + +Do not modify, create pull request at https://github.com/Kode/Kongruent instead. diff --git a/base/sources/libs/kong/sources/analyzer.c b/base/sources/libs/kong/sources/analyzer.c new file mode 100644 index 00000000..5a1912d0 --- /dev/null +++ b/base/sources/libs/kong/sources/analyzer.c @@ -0,0 +1,720 @@ +#include "analyzer.h" + +#include "array.h" +#include "errors.h" + +#include + +static render_pipelines all_render_pipelines; +// a pipeline group is a collection of pipelines that share shaders +static render_pipeline_groups all_render_pipeline_groups; + +static compute_shaders all_compute_shaders; + +static raytracing_pipelines all_raytracing_pipelines; +// a pipeline group is a collection of pipelines that share shaders +static raytracing_pipeline_groups all_raytracing_pipeline_groups; + +static void find_referenced_global_for_var(variable v, global_id *globals, size_t *globals_size) { + for (global_id j = 0; get_global(j) != NULL && get_global(j)->type != NO_TYPE; ++j) { + global *g = get_global(j); + if (v.index == g->var_index) { + bool found = false; + for (size_t k = 0; k < *globals_size; ++k) { + if (globals[k] == j) { + found = true; + break; + } + } + if (!found) { + globals[*globals_size] = j; + *globals_size += 1; + } + return; + } + } +} + +void find_referenced_globals(function *f, global_id *globals, size_t *globals_size) { + if (f->block == NULL) { + // built-in + return; + } + + function *functions[256]; + size_t functions_size = 0; + + functions[functions_size] = f; + functions_size += 1; + + find_referenced_functions(f, functions, &functions_size); + + for (size_t l = 0; l < functions_size; ++l) { + uint8_t *data = functions[l]->code.o; + size_t size = functions[l]->code.size; + + size_t index = 0; + while (index < size) { + opcode *o = (opcode *)&data[index]; + switch (o->type) { + case OPCODE_MULTIPLY: + case OPCODE_DIVIDE: + case OPCODE_ADD: + case OPCODE_SUB: + case OPCODE_EQUALS: + case OPCODE_NOT_EQUALS: + case OPCODE_GREATER: + case OPCODE_GREATER_EQUAL: + case OPCODE_LESS: + case OPCODE_LESS_EQUAL: { + find_referenced_global_for_var(o->op_binary.left, globals, globals_size); + find_referenced_global_for_var(o->op_binary.right, globals, globals_size); + break; + } + case OPCODE_LOAD_MEMBER: { + find_referenced_global_for_var(o->op_load_member.from, globals, globals_size); + break; + } + case OPCODE_STORE_MEMBER: + case OPCODE_SUB_AND_STORE_MEMBER: + case OPCODE_ADD_AND_STORE_MEMBER: + case OPCODE_DIVIDE_AND_STORE_MEMBER: + case OPCODE_MULTIPLY_AND_STORE_MEMBER: { + find_referenced_global_for_var(o->op_store_member.to, globals, globals_size); + break; + } + case OPCODE_CALL: { + for (uint8_t i = 0; i < o->op_call.parameters_size; ++i) { + find_referenced_global_for_var(o->op_call.parameters[i], globals, globals_size); + } + break; + } + default: + break; + } + + index += o->size; + } + } +} + +void find_referenced_functions(function *f, function **functions, size_t *functions_size) { + if (f->block == NULL) { + // built-in + return; + } + + uint8_t *data = f->code.o; + size_t size = f->code.size; + + size_t index = 0; + while (index < size) { + opcode *o = (opcode *)&data[index]; + switch (o->type) { + case OPCODE_CALL: { + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (f->name == o->op_call.func) { + if (f->block == NULL) { + // built-in + break; + } + + bool found = false; + for (size_t j = 0; j < *functions_size; ++j) { + if (functions[j]->name == o->op_call.func) { + found = true; + break; + } + } + if (!found) { + functions[*functions_size] = f; + *functions_size += 1; + find_referenced_functions(f, functions, functions_size); + } + break; + } + } + break; + } + default: + break; + } + + index += o->size; + } +} + +static void add_found_type(type_id t, type_id *types, size_t *types_size) { + for (size_t i = 0; i < *types_size; ++i) { + if (types[i] == t) { + return; + } + } + + types[*types_size] = t; + *types_size += 1; +} + +void find_referenced_types(function *f, type_id *types, size_t *types_size) { + if (f->block == NULL) { + // built-in + return; + } + + function *functions[256]; + size_t functions_size = 0; + + functions[functions_size] = f; + functions_size += 1; + + find_referenced_functions(f, functions, &functions_size); + + for (size_t function_index = 0; function_index < functions_size; ++function_index) { + function *func = functions[function_index]; + debug_context context = {0}; + for (uint8_t parameter_index = 0; parameter_index < func->parameters_size; ++parameter_index) { + check(func->parameter_types[parameter_index].type != NO_TYPE, context, "Function parameter type not found"); + add_found_type(func->parameter_types[parameter_index].type, types, types_size); + } + check(func->return_type.type != NO_TYPE, context, "Function return type missing"); + add_found_type(func->return_type.type, types, types_size); + + uint8_t *data = functions[function_index]->code.o; + size_t size = functions[function_index]->code.size; + + size_t index = 0; + while (index < size) { + opcode *o = (opcode *)&data[index]; + switch (o->type) { + case OPCODE_VAR: + add_found_type(o->op_var.var.type.type, types, types_size); + break; + default: + break; + } + + index += o->size; + } + } +} + +static bool has_set(descriptor_sets *sets, descriptor_set *set) { + for (size_t set_index = 0; set_index < sets->size; ++set_index) { + if (sets->values[set_index] == set) { + return true; + } + } + + return false; +} + +static void add_set(descriptor_sets *sets, descriptor_set *set) { + if (has_set(sets, set)) { + return; + } + + static_array_push_p(sets, set); +} + +static void find_referenced_sets(global_id *globals, size_t globals_size, descriptor_sets *sets) { + for (size_t global_index = 0; global_index < globals_size; ++global_index) { + global *g = get_global(globals[global_index]); + + if (g->sets_count == 0) { + continue; + } + + if (g->sets_count == 1) { + add_set(sets, g->sets[0]); + continue; + } + } + + for (size_t global_index = 0; global_index < globals_size; ++global_index) { + global *g = get_global(globals[global_index]); + + if (g->sets_count < 2) { + continue; + } + + bool found = false; + + for (size_t set_index = 0; set_index < g->sets_count; ++set_index) { + descriptor_set *set = g->sets[set_index]; + + if (has_set(sets, set)) { + found = true; + break; + } + } + + if (!found) { + debug_context context = {0}; + error(context, "Global %s could be used from multiple descriptor sets.", get_name(g->name)); + } + } +} + +static render_pipeline extract_render_pipeline_from_type(type *t) { + name_id vertex_shader_name = NO_NAME; + name_id amplification_shader_name = NO_NAME; + name_id mesh_shader_name = NO_NAME; + name_id fragment_shader_name = NO_NAME; + + for (size_t j = 0; j < t->members.size; ++j) { + if (t->members.m[j].name == add_name("vertex")) { + vertex_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("amplification")) { + amplification_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("mesh")) { + mesh_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("fragment")) { + fragment_shader_name = t->members.m[j].value.identifier; + } + } + + debug_context context = {0}; + check(vertex_shader_name != NO_NAME || mesh_shader_name != NO_NAME, context, "vertex or mesh shader missing"); + check(fragment_shader_name != NO_NAME, context, "fragment shader missing"); + + render_pipeline pipeline = {0}; + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (vertex_shader_name != NO_NAME && f->name == vertex_shader_name) { + pipeline.vertex_shader = f; + } + if (amplification_shader_name != NO_NAME && f->name == amplification_shader_name) { + pipeline.amplification_shader = f; + } + if (mesh_shader_name != NO_NAME && f->name == mesh_shader_name) { + pipeline.mesh_shader = f; + } + if (f->name == fragment_shader_name) { + pipeline.fragment_shader = f; + } + } + + return pipeline; +} + +static void find_all_render_pipelines(void) { + static_array_init(all_render_pipelines); + + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *t = get_type(i); + if (!t->built_in && has_attribute(&t->attributes, add_name("pipe"))) { + static_array_push(all_render_pipelines, extract_render_pipeline_from_type(t)); + } + } +} + +static void find_render_pipeline_groups(void) { + static_array_init(all_render_pipeline_groups); + + render_pipeline_indices remaining_pipelines; + static_array_init(remaining_pipelines); + + for (uint32_t index = 0; index < all_render_pipelines.size; ++index) { + static_array_push(remaining_pipelines, index); + } + + while (remaining_pipelines.size > 0) { + render_pipeline_indices next_remaining_pipelines; + static_array_init(next_remaining_pipelines); + + render_pipeline_group group; + static_array_init(group); + + static_array_push(group, remaining_pipelines.values[0]); + + for (size_t index = 1; index < remaining_pipelines.size; ++index) { + uint32_t pipeline_index = remaining_pipelines.values[index]; + render_pipeline *pipeline = &all_render_pipelines.values[pipeline_index]; + + bool found = false; + + for (size_t index_in_bucket = 0; index_in_bucket < group.size; ++index_in_bucket) { + render_pipeline *pipeline_in_group = &all_render_pipelines.values[group.values[index_in_bucket]]; + if (pipeline->vertex_shader == pipeline_in_group->vertex_shader || pipeline->amplification_shader == pipeline_in_group->amplification_shader || + pipeline->mesh_shader == pipeline_in_group->mesh_shader || pipeline->fragment_shader == pipeline_in_group->fragment_shader) { + found = true; + break; + } + } + + if (found) { + static_array_push(group, pipeline_index); + } + else { + static_array_push(next_remaining_pipelines, pipeline_index); + } + } + + remaining_pipelines = next_remaining_pipelines; + static_array_push(all_render_pipeline_groups, group); + } +} + +static void find_all_compute_shaders(void) { + static_array_init(all_compute_shaders); + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (has_attribute(&f->attributes, add_name("compute"))) { + static_array_push(all_compute_shaders, f); + } + } +} + +static raytracing_pipeline extract_raytracing_pipeline_from_type(type *t) { + name_id gen_shader_name = NO_NAME; + name_id miss_shader_name = NO_NAME; + name_id closest_shader_name = NO_NAME; + name_id intersection_shader_name = NO_NAME; + name_id any_shader_name = NO_NAME; + + for (size_t j = 0; j < t->members.size; ++j) { + if (t->members.m[j].name == add_name("gen")) { + gen_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("miss")) { + miss_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("closest")) { + closest_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("intersection")) { + intersection_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("any")) { + any_shader_name = t->members.m[j].value.identifier; + } + } + + raytracing_pipeline pipeline = {0}; + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (gen_shader_name != NO_NAME && f->name == gen_shader_name) { + pipeline.gen_shader = f; + } + if (miss_shader_name != NO_NAME && f->name == miss_shader_name) { + pipeline.miss_shader = f; + } + if (closest_shader_name != NO_NAME && f->name == closest_shader_name) { + pipeline.closest_shader = f; + } + if (intersection_shader_name != NO_NAME && f->name == intersection_shader_name) { + pipeline.intersection_shader = f; + } + if (any_shader_name != NO_NAME && f->name == any_shader_name) { + pipeline.any_shader = f; + } + } + + return pipeline; +} + +static void find_all_raytracing_pipelines(void) { + static_array_init(all_raytracing_pipelines); + + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *t = get_type(i); + if (!t->built_in && has_attribute(&t->attributes, add_name("raypipe"))) { + + static_array_push(all_raytracing_pipelines, extract_raytracing_pipeline_from_type(t)); + } + } +} + +static void find_raytracing_pipeline_groups(void) { + static_array_init(all_raytracing_pipeline_groups); + + raytracing_pipeline_indices remaining_pipelines; + static_array_init(remaining_pipelines); + + for (uint32_t index = 0; index < all_raytracing_pipelines.size; ++index) { + static_array_push(remaining_pipelines, index); + } + + while (remaining_pipelines.size > 0) { + raytracing_pipeline_indices next_remaining_pipelines; + static_array_init(next_remaining_pipelines); + + raytracing_pipeline_group group; + static_array_init(group); + + static_array_push(group, remaining_pipelines.values[0]); + + for (size_t index = 1; index < remaining_pipelines.size; ++index) { + uint32_t pipeline_index = remaining_pipelines.values[index]; + raytracing_pipeline *pipeline = &all_raytracing_pipelines.values[pipeline_index]; + + bool found = false; + + for (size_t index_in_bucket = 0; index_in_bucket < group.size; ++index_in_bucket) { + raytracing_pipeline *pipeline_in_group = &all_raytracing_pipelines.values[group.values[index_in_bucket]]; + if (pipeline->gen_shader == pipeline_in_group->gen_shader || pipeline->miss_shader == pipeline_in_group->miss_shader || + pipeline->closest_shader == pipeline_in_group->closest_shader || pipeline->intersection_shader == pipeline_in_group->intersection_shader || + pipeline->any_shader == pipeline_in_group->any_shader) { + found = true; + break; + } + } + + if (found) { + static_array_push(group, pipeline_index); + } + else { + static_array_push(next_remaining_pipelines, pipeline_index); + } + } + + remaining_pipelines = next_remaining_pipelines; + static_array_push(all_raytracing_pipeline_groups, group); + } +} + +static void check_globals_in_descriptor_set_group(descriptor_set_group *group) { + static_array(global_id, globals, 256); + + globals set_globals; + static_array_init(set_globals); + + for (size_t set_index = 0; set_index < group->size; ++set_index) { + descriptor_set *set = group->values[set_index]; + for (size_t definition_index = 0; definition_index < set->definitions_count; ++definition_index) { + global_id g = set->definitions[definition_index].global; + + for (size_t global_index = 0; global_index < set_globals.size; ++global_index) { + if (set_globals.values[global_index] == g) { + debug_context context = {0}; + error(context, "Global used from more than one descriptor set in one descriptor set group"); + } + } + + static_array_push(set_globals, g); + } + } +} + +static descriptor_set_groups all_descriptor_set_groups; + +descriptor_set_group *get_descriptor_set_group(uint32_t descriptor_set_group_index) { + assert(descriptor_set_group_index < all_descriptor_set_groups.size); + return &all_descriptor_set_groups.values[descriptor_set_group_index]; +} + +static void assign_descriptor_set_group_index(function *f, uint32_t descriptor_set_group_index) { + assert(f->descriptor_set_group_index == UINT32_MAX || f->descriptor_set_group_index == descriptor_set_group_index); + f->descriptor_set_group_index = descriptor_set_group_index; +} + +static void find_descriptor_set_groups(void) { + static_array_init(all_descriptor_set_groups); + + for (size_t pipeline_group_index = 0; pipeline_group_index < all_render_pipeline_groups.size; ++pipeline_group_index) { + descriptor_set_group group; + static_array_init(group); + + global_id function_globals[256]; + size_t function_globals_size = 0; + + render_pipeline_group *pipeline_group = &all_render_pipeline_groups.values[pipeline_group_index]; + for (size_t pipeline_index = 0; pipeline_index < pipeline_group->size; ++pipeline_index) { + render_pipeline *pipeline = &all_render_pipelines.values[pipeline_group->values[pipeline_index]]; + + if (pipeline->vertex_shader != NULL) { + find_referenced_globals(pipeline->vertex_shader, function_globals, &function_globals_size); + } + if (pipeline->amplification_shader != NULL) { + find_referenced_globals(pipeline->amplification_shader, function_globals, &function_globals_size); + } + if (pipeline->mesh_shader != NULL) { + find_referenced_globals(pipeline->mesh_shader, function_globals, &function_globals_size); + } + if (pipeline->fragment_shader != NULL) { + find_referenced_globals(pipeline->fragment_shader, function_globals, &function_globals_size); + } + } + + find_referenced_sets(function_globals, function_globals_size, &group); + + check_globals_in_descriptor_set_group(&group); + + uint32_t descriptor_set_group_index = (uint32_t)all_descriptor_set_groups.size; + static_array_push(all_descriptor_set_groups, group); + + for (size_t pipeline_index = 0; pipeline_index < pipeline_group->size; ++pipeline_index) { + render_pipeline *pipeline = &all_render_pipelines.values[pipeline_group->values[pipeline_index]]; + + if (pipeline->vertex_shader != NULL) { + assign_descriptor_set_group_index(pipeline->vertex_shader, descriptor_set_group_index); + } + if (pipeline->amplification_shader != NULL) { + assign_descriptor_set_group_index(pipeline->amplification_shader, descriptor_set_group_index); + } + if (pipeline->mesh_shader != NULL) { + assign_descriptor_set_group_index(pipeline->mesh_shader, descriptor_set_group_index); + } + if (pipeline->fragment_shader != NULL) { + assign_descriptor_set_group_index(pipeline->fragment_shader, descriptor_set_group_index); + } + } + } + + for (size_t compute_shader_index = 0; compute_shader_index < all_compute_shaders.size; ++compute_shader_index) { + descriptor_set_group group; + static_array_init(group); + + global_id function_globals[256]; + size_t function_globals_size = 0; + + find_referenced_globals(all_compute_shaders.values[compute_shader_index], function_globals, &function_globals_size); + + find_referenced_sets(function_globals, function_globals_size, &group); + + check_globals_in_descriptor_set_group(&group); + + uint32_t descriptor_set_group_index = (uint32_t)all_descriptor_set_groups.size; + static_array_push(all_descriptor_set_groups, group); + + for (size_t compute_shader_index = 0; compute_shader_index < all_compute_shaders.size; ++compute_shader_index) { + assign_descriptor_set_group_index(all_compute_shaders.values[compute_shader_index], descriptor_set_group_index); + } + } + + for (size_t pipeline_group_index = 0; pipeline_group_index < all_raytracing_pipeline_groups.size; ++pipeline_group_index) { + descriptor_set_group group; + static_array_init(group); + + global_id function_globals[256]; + size_t function_globals_size = 0; + + raytracing_pipeline_group *pipeline_group = &all_raytracing_pipeline_groups.values[pipeline_group_index]; + for (size_t pipeline_index = 0; pipeline_index < pipeline_group->size; ++pipeline_index) { + raytracing_pipeline *pipeline = &all_raytracing_pipelines.values[pipeline_group->values[pipeline_index]]; + + if (pipeline->gen_shader != NULL) { + find_referenced_globals(pipeline->gen_shader, function_globals, &function_globals_size); + } + if (pipeline->miss_shader != NULL) { + find_referenced_globals(pipeline->miss_shader, function_globals, &function_globals_size); + } + if (pipeline->closest_shader != NULL) { + find_referenced_globals(pipeline->closest_shader, function_globals, &function_globals_size); + } + if (pipeline->intersection_shader != NULL) { + find_referenced_globals(pipeline->intersection_shader, function_globals, &function_globals_size); + } + if (pipeline->any_shader != NULL) { + find_referenced_globals(pipeline->any_shader, function_globals, &function_globals_size); + } + } + + find_referenced_sets(function_globals, function_globals_size, &group); + + check_globals_in_descriptor_set_group(&group); + + uint32_t descriptor_set_group_index = (uint32_t)all_descriptor_set_groups.size; + static_array_push(all_descriptor_set_groups, group); + + for (size_t pipeline_index = 0; pipeline_index < pipeline_group->size; ++pipeline_index) { + raytracing_pipeline *pipeline = &all_raytracing_pipelines.values[pipeline_group->values[pipeline_index]]; + + if (pipeline->gen_shader != NULL) { + assign_descriptor_set_group_index(pipeline->gen_shader, descriptor_set_group_index); + } + if (pipeline->miss_shader != NULL) { + assign_descriptor_set_group_index(pipeline->miss_shader, descriptor_set_group_index); + } + if (pipeline->closest_shader != NULL) { + assign_descriptor_set_group_index(pipeline->closest_shader, descriptor_set_group_index); + } + if (pipeline->intersection_shader != NULL) { + assign_descriptor_set_group_index(pipeline->intersection_shader, descriptor_set_group_index); + } + if (pipeline->any_shader != NULL) { + assign_descriptor_set_group_index(pipeline->any_shader, descriptor_set_group_index); + } + } + } +} + +descriptor_set_group *find_descriptor_set_group_for_type(type *t) { + if (!t->built_in && has_attribute(&t->attributes, add_name("pipe"))) { + render_pipeline pipeline = extract_render_pipeline_from_type(t); + + if (pipeline.vertex_shader->descriptor_set_group_index != UINT32_MAX) { + return &all_descriptor_set_groups.values[pipeline.vertex_shader->descriptor_set_group_index]; + } + + if (pipeline.amplification_shader->descriptor_set_group_index != UINT32_MAX) { + return &all_descriptor_set_groups.values[pipeline.amplification_shader->descriptor_set_group_index]; + } + + if (pipeline.mesh_shader->descriptor_set_group_index != UINT32_MAX) { + return &all_descriptor_set_groups.values[pipeline.mesh_shader->descriptor_set_group_index]; + } + + if (pipeline.fragment_shader->descriptor_set_group_index != UINT32_MAX) { + return &all_descriptor_set_groups.values[pipeline.fragment_shader->descriptor_set_group_index]; + } + + return NULL; + } + + if (!t->built_in && has_attribute(&t->attributes, add_name("raypipe"))) { + raytracing_pipeline pipeline = extract_raytracing_pipeline_from_type(t); + + if (pipeline.gen_shader->descriptor_set_group_index != UINT32_MAX) { + return &all_descriptor_set_groups.values[pipeline.gen_shader->descriptor_set_group_index]; + } + + if (pipeline.miss_shader->descriptor_set_group_index != UINT32_MAX) { + return &all_descriptor_set_groups.values[pipeline.miss_shader->descriptor_set_group_index]; + } + + if (pipeline.closest_shader->descriptor_set_group_index != UINT32_MAX) { + return &all_descriptor_set_groups.values[pipeline.closest_shader->descriptor_set_group_index]; + } + + if (pipeline.intersection_shader->descriptor_set_group_index != UINT32_MAX) { + return &all_descriptor_set_groups.values[pipeline.intersection_shader->descriptor_set_group_index]; + } + + if (pipeline.any_shader->descriptor_set_group_index != UINT32_MAX) { + return &all_descriptor_set_groups.values[pipeline.any_shader->descriptor_set_group_index]; + } + + return NULL; + } + + return NULL; +} + +descriptor_set_group *find_descriptor_set_group_for_function(function *f) { + if (f->descriptor_set_group_index != UINT32_MAX) { + return &all_descriptor_set_groups.values[f->descriptor_set_group_index]; + } + else { + return NULL; + } +} + +void analyze(void) { + find_all_render_pipelines(); + find_render_pipeline_groups(); + + find_all_compute_shaders(); + + find_all_raytracing_pipelines(); + find_raytracing_pipeline_groups(); + + find_descriptor_set_groups(); +} diff --git a/base/sources/libs/kong/sources/analyzer.h b/base/sources/libs/kong/sources/analyzer.h new file mode 100644 index 00000000..38dfd5fb --- /dev/null +++ b/base/sources/libs/kong/sources/analyzer.h @@ -0,0 +1,63 @@ +#ifndef KONG_ANALYZER_HEADER +#define KONG_ANALYZER_HEADER + +#include "array.h" +#include "functions.h" +#include "globals.h" +#include "sets.h" + +#include + +typedef struct render_pipeline { + function *vertex_shader; + function *amplification_shader; + function *mesh_shader; + function *fragment_shader; +} render_pipeline; + +static_array(render_pipeline, render_pipelines, 256); + +static_array(uint32_t, render_pipeline_indices, 256); + +typedef render_pipeline_indices render_pipeline_group; + +static_array(render_pipeline_group, render_pipeline_groups, 64); + +static_array(function *, compute_shaders, 256); + +static_array(uint32_t, compute_shader_indices, 256); + +typedef struct raytracing_pipeline { + function *gen_shader; + function *miss_shader; + function *closest_shader; + function *intersection_shader; + function *any_shader; +} raytracing_pipeline; + +static_array(raytracing_pipeline, raytracing_pipelines, 256); + +static_array(uint32_t, raytracing_pipeline_indices, 256); + +typedef raytracing_pipeline_indices raytracing_pipeline_group; + +static_array(raytracing_pipeline_group, raytracing_pipeline_groups, 64); + +static_array(descriptor_set *, descriptor_sets, 256); + +typedef descriptor_sets descriptor_set_group; + +static_array(descriptor_set_group, descriptor_set_groups, 256); + +void find_referenced_functions(function *f, function **functions, size_t *functions_size); +void find_referenced_types(function *f, type_id *types, size_t *types_size); +void find_referenced_globals(function *f, global_id *globals, size_t *globals_size); + +descriptor_set_group *get_descriptor_set_group(uint32_t descriptor_set_group_index); + +descriptor_set_group *find_descriptor_set_group_for_type(type *t); +descriptor_set_group *find_descriptor_set_group_for_function(function *f); + +void analyze(void); + +#endif diff --git a/base/sources/libs/kong/sources/api.h b/base/sources/libs/kong/sources/api.h new file mode 100644 index 00000000..dbb9bea2 --- /dev/null +++ b/base/sources/libs/kong/sources/api.h @@ -0,0 +1,3 @@ +#pragma once + +typedef enum api_kind { API_DEFAULT, API_DIRECT3D9, API_DIRECT3D11, API_DIRECT3D12, API_OPENGL, API_METAL, API_WEBGPU, API_VULKAN } api_kind; diff --git a/base/sources/libs/kong/sources/array.h b/base/sources/libs/kong/sources/array.h new file mode 100644 index 00000000..027a9625 --- /dev/null +++ b/base/sources/libs/kong/sources/array.h @@ -0,0 +1,38 @@ +#ifndef KONG_ARRAY_HEADER +#define KONG_ARRAY_HEADER + +#define static_array(type, name, max_size) \ + typedef struct name { \ + type values[max_size]; \ + size_t size; \ + size_t max; \ + } name; + +/*#define static_array_with_init(type, name, max_size) \ + struct { \ + type values[max_size]; \ + size_t size; \ + size_t max; \ + } name; \ + name.size = 0; \ + name.max = max_size;*/ + +#define static_array_init(array) \ + array.size = 0; \ + array.max = sizeof(array.values) / sizeof(array.values[0]) + +#define static_array_push(array, value) \ + if (array.size >= array.max) { \ + debug_context context = {0}; \ + error(context, "Array overflow"); \ + } \ + array.values[array.size++] = value; + +#define static_array_push_p(array, value) \ + if (array->size >= array->max) { \ + debug_context context = {0}; \ + error(context, "Array overflow"); \ + } \ + array->values[array->size++] = value; + +#endif diff --git a/base/sources/libs/kong/sources/backends/cstyle.c b/base/sources/libs/kong/sources/backends/cstyle.c new file mode 100644 index 00000000..98e7d7aa --- /dev/null +++ b/base/sources/libs/kong/sources/backends/cstyle.c @@ -0,0 +1,243 @@ +#include "cstyle.h" + +#include "../errors.h" +#include "util.h" + +#include +#include +#include +#include + +// static char *function_string(name_id func) { +// return get_name(func); +// } + +void cstyle_write_opcode(char *code, size_t *offset, opcode *o, type_string_func type_string, int *indentation) { + switch (o->type) { + case OPCODE_VAR: + indent(code, offset, *indentation); + if (get_type(o->op_var.var.type.type)->array_size > 0) { + *offset += sprintf(&code[*offset], "%s _%" PRIu64 "[%i];\n", type_string(o->op_var.var.type.type), o->op_var.var.index, + get_type(o->op_var.var.type.type)->array_size); + } + else { + *offset += sprintf(&code[*offset], "%s _%" PRIu64 ";\n", type_string(o->op_var.var.type.type), o->op_var.var.index); + } + break; + case OPCODE_NOT: + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = !_%" PRIu64 ";\n", type_string(o->op_not.to.type.type), o->op_not.to.index, o->op_not.from.index); + break; + case OPCODE_STORE_VARIABLE: + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "_%" PRIu64 " = _%" PRIu64 ";\n", o->op_store_var.to.index, o->op_store_var.from.index); + break; + case OPCODE_SUB_AND_STORE_VARIABLE: + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "_%" PRIu64 " -= _%" PRIu64 ";\n", o->op_store_var.to.index, o->op_store_var.from.index); + break; + case OPCODE_ADD_AND_STORE_VARIABLE: + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "_%" PRIu64 " += _%" PRIu64 ";\n", o->op_store_var.to.index, o->op_store_var.from.index); + break; + case OPCODE_DIVIDE_AND_STORE_VARIABLE: + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "_%" PRIu64 " /= _%" PRIu64 ";\n", o->op_store_var.to.index, o->op_store_var.from.index); + break; + case OPCODE_MULTIPLY_AND_STORE_VARIABLE: + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "_%" PRIu64 " *= _%" PRIu64 ";\n", o->op_store_var.to.index, o->op_store_var.from.index); + break; + case OPCODE_STORE_MEMBER: + case OPCODE_SUB_AND_STORE_MEMBER: + case OPCODE_ADD_AND_STORE_MEMBER: + case OPCODE_DIVIDE_AND_STORE_MEMBER: + case OPCODE_MULTIPLY_AND_STORE_MEMBER: + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "_%" PRIu64, o->op_store_member.to.index); + + type *s = get_type(o->op_store_member.to.type.type); + + for (size_t i = 0; i < o->op_store_member.member_indices_size; ++i) { + bool is_array = s->array_size > 0 || o->op_store_member.to.type.type == tex2d_type_id; + + if (is_array) { + if (o->op_store_member.dynamic_member[i]) { + *offset += sprintf(&code[*offset], "[_%" PRIu64 "]", o->op_store_member.dynamic_member_indices[i].index); + } + else { + *offset += sprintf(&code[*offset], "[%i]", o->op_store_member.static_member_indices[i]); + } + + s = get_type(s->base); + } + else { + debug_context context = {0}; + check(!o->op_store_member.dynamic_member[i], context, "Unexpected dynamic member"); + check(o->op_store_member.static_member_indices[i] < s->members.size, context, "Member index out of bounds"); + + *offset += sprintf(&code[*offset], ".%s", get_name(s->members.m[o->op_store_member.static_member_indices[i]].name)); + + s = get_type(s->members.m[o->op_store_member.static_member_indices[i]].type.type); + } + } + switch (o->type) { + case OPCODE_STORE_MEMBER: + *offset += sprintf(&code[*offset], " = _%" PRIu64 ";\n", o->op_store_member.from.index); + break; + case OPCODE_SUB_AND_STORE_MEMBER: + *offset += sprintf(&code[*offset], " -= _%" PRIu64 ";\n", o->op_store_member.from.index); + break; + case OPCODE_ADD_AND_STORE_MEMBER: + *offset += sprintf(&code[*offset], " += _%" PRIu64 ";\n", o->op_store_member.from.index); + break; + case OPCODE_DIVIDE_AND_STORE_MEMBER: + *offset += sprintf(&code[*offset], " /= _%" PRIu64 ";\n", o->op_store_member.from.index); + break; + case OPCODE_MULTIPLY_AND_STORE_MEMBER: + *offset += sprintf(&code[*offset], " *= _%" PRIu64 ";\n", o->op_store_member.from.index); + break; + default: + assert(false); + break; + } + break; + case OPCODE_LOAD_FLOAT_CONSTANT: + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = %f;\n", type_string(o->op_load_float_constant.to.type.type), o->op_load_float_constant.to.index, + o->op_load_float_constant.number); + break; + case OPCODE_LOAD_INT_CONSTANT: + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = %i;\n", type_string(o->op_load_int_constant.to.type.type), o->op_load_int_constant.to.index, + o->op_load_int_constant.number); + break; + case OPCODE_LOAD_BOOL_CONSTANT: + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = %s;\n", type_string(o->op_load_bool_constant.to.type.type), o->op_load_bool_constant.to.index, + o->op_load_bool_constant.boolean ? "true" : "false"); + break; + case OPCODE_ADD: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " + _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_SUB: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " - _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_MULTIPLY: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " * _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_DIVIDE: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " / _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_MOD: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " %% _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_EQUALS: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " == _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_NOT_EQUALS: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " != _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_GREATER: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " > _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_GREATER_EQUAL: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " >= _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_LESS: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " < _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_LESS_EQUAL: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " <= _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_AND: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " && _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_OR: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " || _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_XOR: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 " ^ _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_IF: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "if (_%" PRIu64 ")\n", o->op_if.condition.index); + break; + } + case OPCODE_WHILE_START: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "while (true)\n"); + *offset += sprintf(&code[*offset], "{\n"); + break; + } + case OPCODE_WHILE_CONDITION: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "if (!_%" PRIu64 ") break;\n", o->op_while.condition.index); + break; + } + case OPCODE_WHILE_END: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "}\n"); + break; + } + case OPCODE_BLOCK_START: { + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "{\n"); + *indentation += 1; + break; + } + case OPCODE_BLOCK_END: { + *indentation -= 1; + indent(code, offset, *indentation); + *offset += sprintf(&code[*offset], "}\n"); + break; + } + default: { + debug_context context = {0}; + error(context, "Unknown opcode"); + break; + } + } +} diff --git a/base/sources/libs/kong/sources/backends/cstyle.h b/base/sources/libs/kong/sources/backends/cstyle.h new file mode 100644 index 00000000..a8482988 --- /dev/null +++ b/base/sources/libs/kong/sources/backends/cstyle.h @@ -0,0 +1,7 @@ +#pragma once + +#include "../compiler.h" + +typedef char *(*type_string_func)(type_id type); + +void cstyle_write_opcode(char *code, size_t *offset, opcode *o, type_string_func type_string, int *indentation); diff --git a/base/sources/libs/kong/sources/backends/d3d12.cpp b/base/sources/libs/kong/sources/backends/d3d12.cpp new file mode 100644 index 00000000..0fe50cae --- /dev/null +++ b/base/sources/libs/kong/sources/backends/d3d12.cpp @@ -0,0 +1,133 @@ +#include "d3d12.h" + +#include "../errors.h" + +#ifdef _WIN32 + +#include "../log.h" + +#ifdef noreturn +#undef noreturn +#endif + +#include +#include + +#endif + +#ifdef _WIN32 +static const wchar_t *shader_string(shader_stage stage) { + switch (stage) { + case SHADER_STAGE_VERTEX: + return L"vs_6_0"; + case SHADER_STAGE_FRAGMENT: + return L"ps_6_0"; + case SHADER_STAGE_COMPUTE: + return L"cs_6_0"; + case SHADER_STAGE_RAY_GENERATION: + return L"lib_6_3"; + case SHADER_STAGE_AMPLIFICATION: + return L"as_6_5"; + case SHADER_STAGE_MESH: + return L"ms_6_5"; + default: { + debug_context context = {0}; + error(context, "Unsupported shader stage/version combination"); + return L"unsupported"; + } + } +} +#endif + +int compile_hlsl_to_d3d12(const char *source, uint8_t **output, size_t *outputlength, shader_stage stage, bool debug) { +#ifdef _WIN32 + CComPtr compiler; + DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&compiler)); + + LPCWSTR compiler_args[] = { + // L"myshader.hlsl", // optional shader source file name for error reporting and for PIX shader source view + L"-E", L"main", // entry point + L"-T", shader_string(stage), // target + L"-Zi", // enable debug info + // L"-D", L"MYDEFINE=1", // a single define + // L"-Fo", L"myshader.bin", // optional. stored in the pdb. + // L"-Fd", L"myshader.pdb", // the file name of the pdb. This must either be supplied or the auto generated file name must be used + // L"-D", L"__XBOX_STRIP_DXIL", // strip DXIL + // L"-Qstrip_reflect", // strip reflection into a seperate blob + }; + + DxcBuffer source_buffer; + source_buffer.Ptr = source; + source_buffer.Size = strlen(source); + source_buffer.Encoding = DXC_CP_ACP; // assume BOM says UTF8 or UTF16 or this is ANSI text + + CComPtr compiler_result; + compiler->Compile(&source_buffer, // source buffer + compiler_args, // Array of pointers to arguments + _countof(compiler_args), // Number of arguments + NULL, // user-provided interface to handle #include directives (optional) + IID_PPV_ARGS(&compiler_result) // Compiler output status, buffer, and errors + ); + + CComPtr errors = nullptr; + compiler_result->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&errors), nullptr); + // note that d3dcompiler would return null if no errors or warnings are present. + // IDxcCompiler3::Compile will always return an error buffer but it's length will be zero if there are no warnings or errors + if (errors != nullptr && errors->GetStringLength() != 0) { + kong_log(LOG_LEVEL_INFO, "Warnings and Errors:\n%s", errors->GetStringPointer()); + } + + HRESULT result; + compiler_result->GetStatus(&result); + + if (result == S_OK) { + CComPtr shader_buffer = nullptr; + CComPtr shader_name = nullptr; + compiler_result->GetOutput(DXC_OUT_OBJECT, IID_PPV_ARGS(&shader_buffer), &shader_name); + if (shader_buffer == nullptr) { + return 1; + } + else { + *outputlength = shader_buffer->GetBufferSize(); + *output = (uint8_t *)malloc(*outputlength); + memcpy(*output, shader_buffer->GetBufferPointer(), shader_buffer->GetBufferSize()); + } + + /* + // + // save pdb + // + CComPtr pPDB = nullptr; + CComPtr pPDBName = nullptr; + pResults->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pPDB), &pPDBName); + { + FILE* fp = NULL; + + // note that if you do not specifiy -Fd a pdb name will be automatically generated. Use this filename to save the pdb so that PIX can find + it quickly _wfopen_s(&fp, pPDBName->GetStringPointer(), L"wb"); fwrite(pPDB->GetBufferPointer(), pPDB->GetBufferSize(), 1, fp); fclose(fp); + } + + // + // print hash + // + CComPtr pHash = nullptr; + pResults->GetOutput(DXC_OUT_SHADER_HASH, IID_PPV_ARGS(&pHash), nullptr); + if (pHash != nullptr) + { + wprintf(L"Hash: "); + DxcShaderHash* pHashBuf = (DxcShaderHash*)pHash->GetBufferPointer(); + for (int i = 0; i < _countof(pHashBuf->HashDigest); i++) + wprintf(L"%x", pHashBuf->HashDigest[i]); + wprintf(L"\n"); + } + */ + + return 0; + } + else { + return 1; + } +#else + return 1; +#endif +} diff --git a/base/sources/libs/kong/sources/backends/d3d12.h b/base/sources/libs/kong/sources/backends/d3d12.h new file mode 100644 index 00000000..f826e4ac --- /dev/null +++ b/base/sources/libs/kong/sources/backends/d3d12.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../shader_stage.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int compile_hlsl_to_d3d12(const char *source, uint8_t **output, size_t *outputlength, shader_stage stage, bool debug); + +#ifdef __cplusplus +} +#endif diff --git a/base/sources/libs/kong/sources/backends/hlsl.c b/base/sources/libs/kong/sources/backends/hlsl.c new file mode 100644 index 00000000..2207cc43 --- /dev/null +++ b/base/sources/libs/kong/sources/backends/hlsl.c @@ -0,0 +1,1930 @@ +#include "hlsl.h" + +#include "../analyzer.h" +#include "../array.h" +#include "../compiler.h" +#include "../errors.h" +#include "../functions.h" +#include "../parser.h" +#include "../sets.h" +#include "../shader_stage.h" +#include "../types.h" +#include "cstyle.h" +// #include "d3d11.h" +#include "d3d12.h" +// #include "d3d9.h" +#include "util.h" + +#include +#include +#include +#include +#include +#include + +static char *member_string(type *parent_type, name_id member_name) { + if (parent_type == get_type(ray_type_id)) { + if (member_name == add_name("origin")) { + return "Origin"; + } + else if (member_name == add_name("direction")) { + return "Direction"; + } + else if (member_name == add_name("min")) { + return "TMin"; + } + else if (member_name == add_name("max")) { + return "TMax"; + } + else { + return get_name(member_name); + } + } + else { + return get_name(member_name); + } +} + +static char *type_string(type_id type) { + if (type == float_id) { + return "float"; + } + if (type == float2_id) { + return "float2"; + } + if (type == float3_id) { + return "float3"; + } + if (type == float4_id) { + return "float4"; + } + if (type == float4x4_id) { + return "float4x4"; + } + if (type == ray_type_id) { + return "RayDesc"; + } + if (type == bvh_type_id) { + return "RaytracingAccelerationStructure"; + } + if (type == tex2d_type_id) { + return "Texture2D"; + } + return get_name(get_type(type)->name); +} + +static void type_arr(type_ref t_ref, char *arr) { + type *t = get_type(t_ref.type); + if (t->array_size == 0) { + arr[0] = 0; + } + else if (t->array_size == UINT32_MAX) { + strcpy(arr, "[]"); + } + else { + sprintf(arr, "[%i]", t->array_size); + } +} + +static char *function_string(name_id func) { + return get_name(func); +} + +static void write_bytecode(char *hlsl, char *directory, const char *filename, const char *name, uint8_t *output, size_t output_size) { + char full_filename[512]; + + { + sprintf(full_filename, "%s/%s.h", directory, filename); + FILE *file = fopen(full_filename, "wb"); + + if (file == NULL) { + debug_context context = {0}; + error(context, "Could not open file %s.", full_filename); + } + + fprintf(file, "#ifndef KONG_%s_HEADER\n", name); + fprintf(file, "#define KONG_%s_HEADER\n\n", name); + + fprintf(file, "#include \n"); + fprintf(file, "#include \n\n"); + + fprintf(file, "#ifdef __cplusplus\n"); + fprintf(file, "extern \"C\" {\n"); + fprintf(file, "#endif\n\n"); + + fprintf(file, "extern uint8_t *%s;\n", name); + fprintf(file, "extern size_t %s_size;\n", name); + + fprintf(file, "\n#ifdef __cplusplus\n"); + fprintf(file, "}\n"); + fprintf(file, "#endif\n\n"); + + fprintf(file, "#endif\n"); + + fclose(file); + } + + { + sprintf(full_filename, "%s/%s.c", directory, filename); + + FILE *file = fopen(full_filename, "wb"); + + if (file == NULL) { + debug_context context = {0}; + error(context, "Could not open file %s.", full_filename); + } + + fprintf(file, "#include \"%s.h\"\n\n", filename); + + fprintf(file, "uint8_t *%s = \"", name); + for (size_t i = 0; i < output_size; ++i) { + // based on the encoding described in https://github.com/adobe/bin2c + if (output[i] == '!' || output[i] == '#' || (output[i] >= '%' && output[i] <= '>') || (output[i] >= 'A' && output[i] <= '[') || + (output[i] >= ']' && output[i] <= '~')) { + fprintf(file, "%c", output[i]); + } + else if (output[i] == '\a') { + fprintf(file, "\\a"); + } + else if (output[i] == '\b') { + fprintf(file, "\\b"); + } + else if (output[i] == '\t') { + fprintf(file, "\\t"); + } + else if (output[i] == '\v') { + fprintf(file, "\\v"); + } + else if (output[i] == '\f') { + fprintf(file, "\\f"); + } + else if (output[i] == '\r') { + fprintf(file, "\\r"); + } + else if (output[i] == '\"') { + fprintf(file, "\\\""); + } + else if (output[i] == '\\') { + fprintf(file, "\\\\"); + } + else { + fprintf(file, "\\%03o", output[i]); + } + } + fprintf(file, "\";\n"); + + fprintf(file, "size_t %s_size = %zu;\n\n", name, output_size); + + fprintf(file, "/*\n%s*/\n", hlsl); + + fclose(file); + } +} + +static bool is_input(type_id t, type_id inputs[64], size_t inputs_count) { + for (size_t input_index = 0; input_index < inputs_count; ++input_index) { + if (inputs[input_index] == t) { + return true; + } + } + return false; +} + +static void write_types(char *hlsl, size_t *offset, shader_stage stage, type_id inputs[64], size_t inputs_count, type_id output, function *main, + function **rayshaders, size_t rayshaders_count) { + type_id types[256]; + size_t types_size = 0; + if (main != NULL) { + find_referenced_types(main, types, &types_size); + } + for (size_t rayshader_index = 0; rayshader_index < rayshaders_count; ++rayshader_index) { + find_referenced_types(rayshaders[rayshader_index], types, &types_size); + } + + size_t input_offsets[64]; + input_offsets[0] = 0; + + if (inputs_count > 0) { + for (size_t input_index = 0; input_index < inputs_count - 1; ++input_index) { + type *t = get_type(inputs[input_index]); + input_offsets[input_index + 1] = input_offsets[input_index] + t->members.size; + } + } + + for (size_t i = 0; i < types_size; ++i) { + type *t = get_type(types[i]); + + bool built_in = t->built_in || (get_type(t->base) != NULL && get_type(t->base)->built_in); + + if (!built_in && !has_attribute(&t->attributes, add_name("pipe"))) { + *offset += sprintf(&hlsl[*offset], "struct %s {\n", get_name(t->name)); + + if (stage == SHADER_STAGE_VERTEX && is_input(types[i], inputs, inputs_count)) { + size_t input_offset = 0; + for (size_t input_index = 0; input_index < inputs_count; ++input_index) { + if (types[i] == inputs[input_index]) { + input_offset = input_offsets[input_index]; + break; + } + } + + for (size_t j = 0; j < t->members.size; ++j) { + *offset += sprintf(&hlsl[*offset], "\t%s %s : TEXCOORD%zu;\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name), + j + input_offset); + } + } + else if (stage == SHADER_STAGE_VERTEX && types[i] == output) { + for (size_t j = 0; j < t->members.size; ++j) { + if (j == 0) { + *offset += sprintf(&hlsl[*offset], "\t%s %s : SV_POSITION;\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name)); + } + else { + *offset += + sprintf(&hlsl[*offset], "\t%s %s : TEXCOORD%zu;\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name), j - 1); + } + } + } + else if (stage == SHADER_STAGE_MESH && types[i] == output) { + for (size_t j = 0; j < t->members.size; ++j) { + if (j == 0) { + *offset += sprintf(&hlsl[*offset], "\t%s %s : SV_POSITION;\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name)); + } + else { + *offset += + sprintf(&hlsl[*offset], "\t%s %s : TEXCOORD%zu;\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name), j - 1); + } + } + } + else if (stage == SHADER_STAGE_FRAGMENT && types[i] == inputs[0]) { + for (size_t j = 0; j < t->members.size; ++j) { + if (j == 0) { + *offset += sprintf(&hlsl[*offset], "\t%s %s : SV_POSITION;\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name)); + } + else { + *offset += + sprintf(&hlsl[*offset], "\t%s %s : TEXCOORD%zu;\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name), j - 1); + } + } + } + else { + for (size_t j = 0; j < t->members.size; ++j) { + *offset += sprintf(&hlsl[*offset], "\t%s %s;\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name)); + } + } + *offset += sprintf(&hlsl[*offset], "};\n\n"); + } + } +} + +static void assign_register_indices(uint32_t *register_indices, function *shader) { + uint32_t cbv_index = 0; + uint32_t srv_index = 0; + uint32_t uav_index = 0; + uint32_t sampler_index = 0; + + descriptor_set_group *set_group = get_descriptor_set_group(shader->descriptor_set_group_index); + + for (size_t group_index = 0; group_index < set_group->size; ++group_index) { + descriptor_set *set = set_group->values[group_index]; + + if (set->name == add_name("root_constants")) { + if (set->definitions_count != 1) { + debug_context context = {0}; + error(context, "More than one root constants struct found"); + } + + uint32_t size = 0; + global_id g = UINT32_MAX; + for (size_t definition_index = 0; definition_index < set->definitions_count; ++definition_index) { + definition *def = &set->definitions[definition_index]; + + switch (def->kind) { + case DEFINITION_CONST_CUSTOM: + size += struct_size(get_global(def->global)->type); + g = def->global; + break; + default: { + debug_context context = {0}; + error(context, "Unsupported type for a root constant"); + break; + } + } + } + + register_indices[g] = srv_index; + srv_index += 1; + + continue; + } + + for (size_t definition_index = 0; definition_index < set->definitions_count; ++definition_index) { + global_id global_index = set->definitions[definition_index].global; + + global *g = get_global(global_index); + + type *t = get_type(g->type); + type_id base_type = t->array_size > 0 ? t->base : g->type; + + if (base_type == sampler_type_id) { + register_indices[global_index] = sampler_index; + sampler_index += 1; + } + else if (base_type == tex2d_type_id) { + if (t->array_size == UINT32_MAX) { + register_indices[global_index] = 0; + } + else if (has_attribute(&g->attributes, add_name("write"))) { + register_indices[global_index] = uav_index; + uav_index += 1; + } + else { + register_indices[global_index] = srv_index; + srv_index += 1; + } + } + else if (base_type == texcube_type_id || base_type == tex2darray_type_id || base_type == bvh_type_id) { + register_indices[global_index] = srv_index; + srv_index += 1; + } + else if (get_type(g->type)->built_in) { + if (get_type(g->type)->array_size > 0) { + register_indices[global_index] = uav_index; + uav_index += 1; + } + } + else { + if (get_type(g->type)->array_size > 0) { + register_indices[global_index] = uav_index; + uav_index += 1; + } + else { + register_indices[global_index] = cbv_index; + cbv_index += 1; + } + } + } + } +} + +static void write_globals(char *hlsl, size_t *offset, function *main, function **rayshaders, size_t rayshaders_count) { + uint32_t register_indices[512] = {0}; + assign_register_indices(register_indices, main); + + global_id globals[256]; + size_t globals_size = 0; + if (main != NULL) { + find_referenced_globals(main, globals, &globals_size); + } + for (size_t rayshader_index = 0; rayshader_index < rayshaders_count; ++rayshader_index) { + find_referenced_globals(rayshaders[rayshader_index], globals, &globals_size); + } + + for (size_t i = 0; i < globals_size; ++i) { + global *g = get_global(globals[i]); + int register_index = register_indices[globals[i]]; + + type *t = get_type(g->type); + type_id base_type = t->array_size > 0 ? t->base : g->type; + + if (base_type == sampler_type_id) { + *offset += sprintf(&hlsl[*offset], "SamplerState _%" PRIu64 " : register(s%i);\n\n", g->var_index, register_index); + } + else if (base_type == tex2d_type_id) { + if (has_attribute(&g->attributes, add_name("write"))) { + *offset += sprintf(&hlsl[*offset], "RWTexture2D _%" PRIu64 " : register(u%i);\n\n", g->var_index, register_index); + } + else { + if (t->array_size > 0 && t->array_size == UINT32_MAX) { + *offset += sprintf(&hlsl[*offset], "Texture2D _%" PRIu64 "[] : register(t%i, space1);\n\n", g->var_index, register_index); + } + else { + *offset += sprintf(&hlsl[*offset], "Texture2D _%" PRIu64 " : register(t%i);\n\n", g->var_index, register_index); + } + } + } + else if (base_type == tex2darray_type_id) { + *offset += sprintf(&hlsl[*offset], "Texture2DArray _%" PRIu64 " : register(t%i);\n\n", g->var_index, register_index); + } + else if (base_type == texcube_type_id) { + *offset += sprintf(&hlsl[*offset], "TextureCube _%" PRIu64 " : register(t%i);\n\n", g->var_index, register_index); + } + else if (base_type == bvh_type_id) { + *offset += sprintf(&hlsl[*offset], "RaytracingAccelerationStructure _%" PRIu64 " : register(t%i);\n\n", g->var_index, register_index); + } + else if (base_type == float_id) { + *offset += sprintf(&hlsl[*offset], "static const float _%" PRIu64 " = %f;\n\n", g->var_index, g->value.value.floats[0]); + } + else if (base_type == float2_id) { + *offset += sprintf(&hlsl[*offset], "static const float2 _%" PRIu64 " = float2(%f, %f);\n\n", g->var_index, g->value.value.floats[0], + g->value.value.floats[1]); + } + else if (base_type == float3_id) { + *offset += sprintf(&hlsl[*offset], "static const float3 _%" PRIu64 " = float3(%f, %f, %f);\n\n", g->var_index, g->value.value.floats[0], + g->value.value.floats[1], g->value.value.floats[2]); + } + else if (base_type == float4_id) { + if (t->array_size > 0) { + *offset += sprintf(&hlsl[*offset], "struct _%llu_type { float4 data; };\n", g->var_index); + *offset += sprintf(&hlsl[*offset], "RWStructuredBuffer<_%llu_type> _%llu : register(u%i);\n", g->var_index, g->var_index, register_index); + } + else { + *offset += sprintf(&hlsl[*offset], "static const float4 _%" PRIu64 " = float4(%f, %f, %f, %f);\n\n", g->var_index, g->value.value.floats[0], + g->value.value.floats[1], g->value.value.floats[2], g->value.value.floats[3]); + } + } + else { + *offset += sprintf(&hlsl[*offset], "cbuffer _%" PRIu64 " : register(b%i) {\n", g->var_index, register_index); + type *t = get_type(g->type); + for (size_t i = 0; i < t->members.size; ++i) { + char arr[16]; + type_arr(t->members.m[i].type, arr); + *offset += sprintf(&hlsl[*offset], "\t%s _%" PRIu64 "_%s%s;\n", type_string(t->members.m[i].type.type), g->var_index, + get_name(t->members.m[i].name), arr); + } + *offset += sprintf(&hlsl[*offset], "}\n\n"); + } + } +} + +static function *raygen_shaders[256]; +static size_t raygen_shaders_size = 0; + +static function *raymiss_shaders[256]; +static size_t raymiss_shaders_size = 0; + +static function *rayclosesthit_shaders[256]; +static size_t rayclosesthit_shaders_size = 0; + +static function *rayintersection_shaders[256]; +static size_t rayintersection_shaders_size = 0; + +static function *rayanyhit_shaders[256]; +static size_t rayanyhit_shaders_size = 0; + +static bool is_raygen_shader(function *f) { + for (size_t rayshader_index = 0; rayshader_index < raygen_shaders_size; ++rayshader_index) { + if (f == raygen_shaders[rayshader_index]) { + return true; + } + } + return false; +} + +static bool is_raymiss_shader(function *f) { + for (size_t rayshader_index = 0; rayshader_index < raymiss_shaders_size; ++rayshader_index) { + if (f == raymiss_shaders[rayshader_index]) { + return true; + } + } + return false; +} + +static bool is_rayclosesthit_shader(function *f) { + for (size_t rayshader_index = 0; rayshader_index < rayclosesthit_shaders_size; ++rayshader_index) { + if (f == rayclosesthit_shaders[rayshader_index]) { + return true; + } + } + return false; +} + +static bool is_rayintersection_shader(function *f) { + for (size_t rayshader_index = 0; rayshader_index < rayintersection_shaders_size; ++rayshader_index) { + if (f == rayintersection_shaders[rayshader_index]) { + return true; + } + } + return false; +} + +static bool is_rayanyhit_shader(function *f) { + for (size_t rayshader_index = 0; rayshader_index < rayanyhit_shaders_size; ++rayshader_index) { + if (f == rayanyhit_shaders[rayshader_index]) { + return true; + } + } + return false; +} + +static descriptor_set *all_descriptor_sets[256]; +static size_t all_descriptor_sets_count = 0; + +static void write_root_signature(function *main, char *hlsl, size_t *offset) { + uint32_t register_indices[512] = {0}; + assign_register_indices(register_indices, main); + + *offset += sprintf(&hlsl[*offset], "[RootSignature(\"RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)"); + + descriptor_set_group *set_group = get_descriptor_set_group(main->descriptor_set_group_index); + + for (size_t group_index = 0; group_index < set_group->size; ++group_index) { + descriptor_set *set = set_group->values[group_index]; + + if (set->name == add_name("root_constants")) { + if (set->definitions_count != 1) { + debug_context context = {0}; + error(context, "More than one root constants struct found"); + } + + uint32_t size = 0; + global_id g = UINT32_MAX; + for (size_t definition_index = 0; definition_index < set->definitions_count; ++definition_index) { + definition *def = &set->definitions[definition_index]; + + switch (def->kind) { + case DEFINITION_CONST_CUSTOM: + size += struct_size(get_global(def->global)->type); + g = def->global; + break; + default: { + debug_context context = {0}; + error(context, "Unsupported type for a root constant"); + break; + } + } + } + + *offset += sprintf(&hlsl[*offset], "\\\n, RootConstants(num32BitConstants=%i, b%i)", size / 4, register_indices[g]); + + continue; + } + + bool has_sampler = false; + bool has_other = false; + bool has_dynamic = false; + bool has_boundless = false; + + for (size_t definition_index = 0; definition_index < set->definitions_count; ++definition_index) { + definition *def = &set->definitions[definition_index]; + + switch (def->kind) { + case DEFINITION_CONST_CUSTOM: { + if (has_attribute(&get_global(def->global)->attributes, add_name("indexed"))) { + has_dynamic = true; + } + else { + has_other = true; + } + break; + } + case DEFINITION_TEX2D: + case DEFINITION_TEX2DARRAY: + case DEFINITION_TEXCUBE: { + type *t = get_type(get_global(def->global)->type); + if (t->array_size == UINT32_MAX) { + has_boundless = true; + } + else { + has_other = true; + } + break; + } + case DEFINITION_SAMPLER: + has_sampler = true; + break; + case DEFINITION_CONST_BASIC: { + type *t = get_type(get_global(def->global)->type); + if (t->array_size > 0) { + has_other = true; + } + break; + } + default: + break; + } + } + + if (has_other) { + *offset += sprintf(&hlsl[*offset], "\\\n, DescriptorTable("); + + bool first = true; + for (size_t definition_index = 0; definition_index < set->definitions_count; ++definition_index) { + definition *def = &set->definitions[definition_index]; + + switch (def->kind) { + case DEFINITION_CONST_CUSTOM: + if (!has_attribute(&get_global(def->global)->attributes, add_name("indexed"))) { + if (first) { + first = false; + } + else { + *offset += sprintf(&hlsl[*offset], ", "); + } + + *offset += sprintf(&hlsl[*offset], "CBV(b%i)", register_indices[def->global]); + } + break; + case DEFINITION_TEX2D: + case DEFINITION_TEX2DARRAY: + case DEFINITION_TEXCUBE: { + attribute *write_attribute = find_attribute(&get_global(def->global)->attributes, add_name("write")); + + if (first) { + first = false; + } + else { + *offset += sprintf(&hlsl[*offset], ", "); + } + + if (write_attribute != NULL) { + *offset += sprintf(&hlsl[*offset], "UAV(u%i)", register_indices[def->global]); + } + else { + *offset += sprintf(&hlsl[*offset], "SRV(t%i)", register_indices[def->global]); + } + break; + } + case DEFINITION_CONST_BASIC: { + type *t = get_type(get_global(def->global)->type); + if (t->array_size > 0) { + if (first) { + first = false; + } + else { + *offset += sprintf(&hlsl[*offset], ", "); + } + + *offset += sprintf(&hlsl[*offset], "UAV(u%i)", register_indices[def->global]); + } + } + default: + break; + } + } + + *offset += sprintf(&hlsl[*offset], ")"); + } + + if (has_dynamic) { + *offset += sprintf(&hlsl[*offset], "\\\n, DescriptorTable("); + + bool first = true; + for (size_t definition_index = 0; definition_index < set->definitions_count; ++definition_index) { + definition *def = &set->definitions[definition_index]; + + switch (def->kind) { + case DEFINITION_CONST_CUSTOM: + if (has_attribute(&get_global(def->global)->attributes, add_name("indexed"))) { + if (first) { + first = false; + } + else { + *offset += sprintf(&hlsl[*offset], ", "); + } + *offset += sprintf(&hlsl[*offset], "CBV(b%i)", register_indices[def->global]); + } + break; + default: + break; + } + } + + *offset += sprintf(&hlsl[*offset], ")"); + } + + if (has_boundless) { + uint32_t boundless_space = 1; + for (size_t definition_index = 0; definition_index < set->definitions_count; ++definition_index) { + definition *def = &set->definitions[definition_index]; + + switch (def->kind) { + case DEFINITION_TEX2D: + case DEFINITION_TEX2DARRAY: + case DEFINITION_TEXCUBE: { + type *t = get_type(get_global(def->global)->type); + + if (t->array_size == UINT32_MAX) { + *offset += sprintf(&hlsl[*offset], "\\\n, DescriptorTable(SRV(t0, space = %i, numDescriptors = unbounded))", boundless_space); + boundless_space += 1; + } + + break; + } + default: + break; + } + } + } + + if (has_sampler) { + *offset += sprintf(&hlsl[*offset], "\\\n, DescriptorTable("); + + bool first = true; + for (size_t definition_index = 0; definition_index < set->definitions_count; ++definition_index) { + definition *def = &set->definitions[definition_index]; + + switch (def->kind) { + case DEFINITION_SAMPLER: + if (first) { + first = false; + } + else { + *offset += sprintf(&hlsl[*offset], ", "); + } + *offset += sprintf(&hlsl[*offset], "Sampler(s%i)", register_indices[def->global]); + break; + default: + break; + } + } + + *offset += sprintf(&hlsl[*offset], ")"); + } + } + + *offset += sprintf(&hlsl[*offset], "\")]\n"); +} + +static type_id payload_types[256]; +static size_t payload_types_count = 0; + +static bool is_payload_type(type_id t) { + for (size_t payload_index = 0; payload_index < payload_types_count; ++payload_index) { + if (payload_types[payload_index] == t) { + return true; + } + } + return false; +} + +static void write_functions(char *hlsl, size_t *offset, shader_stage stage, function *main, function **rayshaders, size_t rayshaders_count) { + function *functions[256]; + size_t functions_size = 0; + + if (main != NULL) { + functions[functions_size] = main; + functions_size += 1; + + find_referenced_functions(main, functions, &functions_size); + } + + for (size_t rayshader_index = 0; rayshader_index < rayshaders_count; ++rayshader_index) { + functions[functions_size] = rayshaders[rayshader_index]; + functions_size += 1; + find_referenced_functions(rayshaders[rayshader_index], functions, &functions_size); + } + + // find payloads + for (size_t i = 0; i < functions_size; ++i) { + function *f = functions[i]; + + uint8_t *data = f->code.o; + size_t size = f->code.size; + + size_t index = 0; + while (index < size) { + opcode *o = (opcode *)&data[index]; + switch (o->type) { + case OPCODE_CALL: { + if (o->op_call.func == add_name("trace_ray")) { + debug_context context = {0}; + check(o->op_call.parameters_size == 3, context, "trace_ray requires three parameters"); + + type_id payload_type = o->op_call.parameters[2].type.type; + + bool found = false; + for (size_t payload_index = 0; payload_index < payload_types_count; ++payload_index) { + if (payload_types[payload_index] == payload_type) { + found = true; + break; + } + } + + if (!found) { + payload_types[payload_types_count] = payload_type; + payload_types_count += 1; + } + } + } + default: + break; + } + index += o->size; + } + } + + // function declarations + for (size_t i = 0; i < functions_size; ++i) { + function *f = functions[i]; + + if (f != main && !is_raygen_shader(f) && !is_raymiss_shader(f) && !is_rayclosesthit_shader(f) && !is_rayintersection_shader(f) && + !is_rayanyhit_shader(f)) { + + uint64_t parameter_ids[256] = {0}; + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + for (size_t i = 0; i < f->block->block.vars.size; ++i) { + if (f->parameter_names[parameter_index] == f->block->block.vars.v[i].name) { + parameter_ids[parameter_index] = f->block->block.vars.v[i].variable_id; + break; + } + } + } + + *offset += sprintf(&hlsl[*offset], "%s %s(", type_string(f->return_type.type), get_name(f->name)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + char *payload_prefix = ""; + if (is_payload_type(f->parameter_types[parameter_index].type)) { + payload_prefix = "inout "; + } + + if (parameter_index == 0) { + + *offset += sprintf(&hlsl[*offset], "%s%s _%" PRIu64, payload_prefix, type_string(f->parameter_types[parameter_index].type), + parameter_ids[parameter_index]); + } + else { + *offset += sprintf(&hlsl[*offset], ", %s%s _%" PRIu64, payload_prefix, type_string(f->parameter_types[parameter_index].type), + parameter_ids[parameter_index]); + } + } + *offset += sprintf(&hlsl[*offset], ");\n"); + } + } + + *offset += sprintf(&hlsl[*offset], "\n"); + + for (size_t i = 0; i < functions_size; ++i) { + function *f = functions[i]; + assert(f != NULL); + + debug_context context = {0}; + check(f->block != NULL, context, "Function block missing"); + + uint8_t *data = f->code.o; + size_t size = f->code.size; + + uint64_t parameter_ids[256] = {0}; + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + for (size_t i = 0; i < f->block->block.vars.size; ++i) { + if (f->parameter_names[parameter_index] == f->block->block.vars.v[i].name) { + parameter_ids[parameter_index] = f->block->block.vars.v[i].variable_id; + break; + } + } + } + + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + check(parameter_ids[parameter_index] != 0, context, "Parameter not found"); + } + + if (f == main) { + if (stage == SHADER_STAGE_VERTEX) { + write_root_signature(f, hlsl, offset); + *offset += sprintf(&hlsl[*offset], "%s main(", type_string(f->return_type.type)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += + sprintf(&hlsl[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + *offset += sprintf(&hlsl[*offset], ") {\n"); + } + else if (stage == SHADER_STAGE_FRAGMENT) { + if (get_type(f->return_type.type)->array_size > 0) { + *offset += sprintf(&hlsl[*offset], "struct _kong_colors_out {\n"); + for (uint32_t j = 0; j < get_type(f->return_type.type)->array_size; ++j) { + *offset += sprintf(&hlsl[*offset], "\t%s _%i : SV_Target%i;\n", type_string(f->return_type.type), j, j); + } + *offset += sprintf(&hlsl[*offset], "};\n\n"); + + write_root_signature(f, hlsl, offset); + + *offset += sprintf(&hlsl[*offset], "_kong_colors_out main("); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + *offset += sprintf(&hlsl[*offset], ") {\n"); + } + else { + write_root_signature(f, hlsl, offset); + *offset += sprintf(&hlsl[*offset], "%s main(", type_string(f->return_type.type)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += sprintf(&hlsl[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), + parameter_ids[parameter_index]); + } + } + *offset += sprintf(&hlsl[*offset], ") : SV_Target0 {\n"); + } + } + else if (stage == SHADER_STAGE_COMPUTE) { + attribute *threads_attribute = find_attribute(&f->attributes, add_name("threads")); + if (threads_attribute == NULL || threads_attribute->paramters_count != 3) { + debug_context context = {0}; + error(context, "Compute function requires a threads attribute with three parameters"); + } + + write_root_signature(f, hlsl, offset); + *offset += sprintf(&hlsl[*offset], "[numthreads(%i, %i, %i)]\n%s main(", (int)threads_attribute->parameters[0], + (int)threads_attribute->parameters[1], (int)threads_attribute->parameters[2], type_string(f->return_type.type)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += + sprintf(&hlsl[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + if (f->parameters_size > 0) { + *offset += sprintf(&hlsl[*offset], ", "); + } + *offset += sprintf(&hlsl[*offset], "in uint3 _kong_group_id : SV_GroupID, in uint3 _kong_group_thread_id : SV_GroupThreadID, in uint3 " + "_kong_dispatch_thread_id : SV_DispatchThreadID, in uint _kong_group_index : SV_GroupIndex) {\n"); + } + else if (stage == SHADER_STAGE_AMPLIFICATION) { + attribute *threads_attribute = find_attribute(&f->attributes, add_name("threads")); + if (threads_attribute == NULL || threads_attribute->paramters_count != 3) { + debug_context context = {0}; + error(context, "Compute function requires a threads attribute with three parameters"); + } + + *offset += sprintf(&hlsl[*offset], "[numthreads(%i, %i, %i)] %s main(", (int)threads_attribute->parameters[0], + (int)threads_attribute->parameters[1], (int)threads_attribute->parameters[2], type_string(f->return_type.type)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += + sprintf(&hlsl[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + if (f->parameters_size > 0) { + *offset += sprintf(&hlsl[*offset], ", "); + } + *offset += sprintf(&hlsl[*offset], "in uint3 _kong_group_id : SV_GroupID, in uint3 _kong_group_thread_id : SV_GroupThreadID, in uint3 " + "_kong_dispatch_thread_id : SV_DispatchThreadID, in uint _kong_group_index : SV_GroupIndex) {\n"); + } + else if (stage == SHADER_STAGE_MESH) { + attribute *topology_attribute = find_attribute(&f->attributes, add_name("topology")); + if (topology_attribute == NULL || topology_attribute->paramters_count != 1 || topology_attribute->parameters[0] != 0) { + debug_context context = {0}; + error(context, "Mesh function requires a threads attribute with one parameter which has to be \"triangle\""); + } + + attribute *threads_attribute = find_attribute(&f->attributes, add_name("threads")); + if (threads_attribute == NULL || threads_attribute->paramters_count != 3) { + debug_context context = {0}; + error(context, "Mesh function requires a threads attribute with three parameters"); + } + + attribute *tris_attribute = find_attribute(&f->attributes, add_name("tris")); + if (tris_attribute == NULL || tris_attribute->paramters_count != 1) { + debug_context context = {0}; + error(context, "Mesh function requires a tris attribute with one parameter"); + } + + attribute *vertices_attribute = find_attribute(&f->attributes, add_name("vertices")); + if (vertices_attribute == NULL || vertices_attribute->paramters_count != 2) { + debug_context context = {0}; + error(context, "Mesh function requires a vertices attribute with two parameters"); + } + + type_id vertex_type = (type_id)vertices_attribute->parameters[1]; + char *vertex_name = get_name(get_type(vertex_type)->name); + + *offset += sprintf(&hlsl[*offset], "[outputtopology(\"triangle\")][numthreads(%i, %i, %i)] %s main(", (int)threads_attribute->parameters[0], + (int)threads_attribute->parameters[1], (int)threads_attribute->parameters[2], type_string(f->return_type.type)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += + sprintf(&hlsl[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + if (f->parameters_size > 0) { + *offset += sprintf(&hlsl[*offset], ", "); + } + *offset += + sprintf(&hlsl[*offset], + "out indices uint3 _kong_mesh_tris[%i], out vertices %s _kong_mesh_vertices[%i], in uint3 _kong_group_id : SV_GroupID, in uint3 " + "_kong_group_thread_id : SV_GroupThreadID, in uint3 " + "_kong_dispatch_thread_id : SV_DispatchThreadID, in uint _kong_group_index : SV_GroupIndex) {\n", + (int)tris_attribute->parameters[0], vertex_name, (int)vertices_attribute->parameters[0]); + } + else { + debug_context context = {0}; + error(context, "Unsupported shader stage"); + } + } + else if (is_raygen_shader(f)) { + *offset += sprintf(&hlsl[*offset], "[shader(\"raygeneration\")]\n"); + + *offset += sprintf(&hlsl[*offset], "%s %s(", type_string(f->return_type.type), get_name(f->name)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += sprintf(&hlsl[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + *offset += sprintf(&hlsl[*offset], ") {\n"); + } + else if (is_raymiss_shader(f)) { + *offset += sprintf(&hlsl[*offset], "[shader(\"miss\")]\n"); + + *offset += sprintf(&hlsl[*offset], "%s %s(", type_string(f->return_type.type), get_name(f->name)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&hlsl[*offset], "inout %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += sprintf(&hlsl[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + *offset += sprintf(&hlsl[*offset], ") {\n"); + } + else if (is_rayclosesthit_shader(f)) { + debug_context context = {0}; + check(f->parameters_size == 2, context, "rayclosesthit shader requires two arguments"); + check(f->parameter_types[1].type == float2_id, context, "Second parameter of a rayclosesthit shader needs to be a float2"); + + *offset += sprintf(&hlsl[*offset], "[shader(\"closesthit\")]\n"); + + *offset += sprintf(&hlsl[*offset], "%s %s(", type_string(f->return_type.type), get_name(f->name)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&hlsl[*offset], "inout %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else if (parameter_index == 1) { + *offset += sprintf(&hlsl[*offset], ", BuiltInTriangleIntersectionAttributes _kong_triangle_intersection_attributes"); + } + else { + *offset += sprintf(&hlsl[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + *offset += sprintf(&hlsl[*offset], ") {\n"); + *offset += sprintf(&hlsl[*offset], "\t%s _%" PRIu64 " = _kong_triangle_intersection_attributes.barycentrics;\n", + type_string(f->parameter_types[1].type), parameter_ids[1]); + } + else if (is_rayintersection_shader(f)) { + debug_context context = {0}; + check(f->parameters_size == 0, context, "intersection shader can not have any parameters"); + + *offset += sprintf(&hlsl[*offset], "[shader(\"intersection\")]\n"); + + *offset += sprintf(&hlsl[*offset], "%s %s() {\n", type_string(f->return_type.type), get_name(f->name)); + } + else if (is_rayanyhit_shader(f)) { + debug_context context = {0}; + check(f->parameters_size == 2, context, "anyhit shader requires two arguments"); + check(f->parameter_types[1].type == float2_id, context, "Second parameter of a rayanyhit shader needs to be a float2"); + + *offset += sprintf(&hlsl[*offset], "[shader(\"anyhit\")]\n"); + + *offset += sprintf(&hlsl[*offset], "%s %s(", type_string(f->return_type.type), get_name(f->name)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&hlsl[*offset], "inout %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else if (parameter_index == 1) { + *offset += sprintf(&hlsl[*offset], ", BuiltInTriangleIntersectionAttributes _kong_triangle_intersection_attributes"); + } + else { + *offset += sprintf(&hlsl[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + *offset += sprintf(&hlsl[*offset], ") {\n"); + *offset += sprintf(&hlsl[*offset], "\t%s _%" PRIu64 " = _kong_triangle_intersection_attributes.barycentrics;\n", + type_string(f->parameter_types[1].type), parameter_ids[1]); + } + else { + *offset += sprintf(&hlsl[*offset], "%s %s(", type_string(f->return_type.type), get_name(f->name)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + char *payload_prefix = ""; + if (is_payload_type(f->parameter_types[parameter_index].type)) { + payload_prefix = "inout "; + } + + if (parameter_index == 0) { + *offset += sprintf(&hlsl[*offset], "%s%s _%" PRIu64, payload_prefix, type_string(f->parameter_types[parameter_index].type), + parameter_ids[parameter_index]); + } + else { + *offset += sprintf(&hlsl[*offset], ", %s%s _%" PRIu64, payload_prefix, type_string(f->parameter_types[parameter_index].type), + parameter_ids[parameter_index]); + } + } + *offset += sprintf(&hlsl[*offset], ") {\n"); + } + + int indentation = 1; + + size_t index = 0; + while (index < size) { + opcode *o = (opcode *)&data[index]; + switch (o->type) { + case OPCODE_LOAD_MEMBER: { + uint64_t global_var_index = 0; + global *g = NULL; + for (global_id j = 0; get_global(j) != NULL && get_global(j)->type != NO_TYPE; ++j) { + g = get_global(j); + if (o->op_load_member.from.index == g->var_index) { + global_var_index = g->var_index; + if (get_type(g->type)->built_in) { + global_var_index = 0; + } + break; + } + } + + indent(hlsl, offset, indentation); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = _%" PRIu64, type_string(o->op_load_member.to.type.type), o->op_load_member.to.index, + o->op_load_member.from.index); + type *s = get_type(o->op_load_member.member_parent_type); + for (size_t i = 0; i < o->op_load_member.member_indices_size; ++i) { + if (o->op_load_member.dynamic_member[i]) { + type *from_type = get_type(o->op_load_member.from.type.type); + + if (global_var_index != 0 && i == 0 && get_type(from_type->base)->built_in) { + *offset += sprintf(&hlsl[*offset], "[_%" PRIu64 "].data", o->op_load_member.dynamic_member_indices[i].index); + } + else if (from_type->array_size == UINT32_MAX && from_type->base == tex2d_type_id) { + *offset += sprintf(&hlsl[*offset], "[NonUniformResourceIndex(_%" PRIu64 ")]", o->op_load_member.dynamic_member_indices[i].index); + } + else { + *offset += sprintf(&hlsl[*offset], "[_%" PRIu64 "]", o->op_load_member.dynamic_member_indices[i].index); + } + + s = get_type(o->op_load_member.dynamic_member_indices[i].type.type); + } + else { + if (global_var_index != 0 && i == 0) { + *offset += sprintf(&hlsl[*offset], "_%s", get_name(s->members.m[o->op_load_member.static_member_indices[i]].name)); + } + else { + *offset += sprintf(&hlsl[*offset], ".%s", get_name(s->members.m[o->op_load_member.static_member_indices[i]].name)); + } + + s = get_type(s->members.m[o->op_load_member.static_member_indices[i]].type.type); + } + } + *offset += sprintf(&hlsl[*offset], ";\n"); + break; + } + case OPCODE_STORE_MEMBER: + case OPCODE_SUB_AND_STORE_MEMBER: + case OPCODE_ADD_AND_STORE_MEMBER: + case OPCODE_DIVIDE_AND_STORE_MEMBER: + case OPCODE_MULTIPLY_AND_STORE_MEMBER: { + uint64_t global_var_index = 0; + global *g = NULL; + for (global_id j = 0; get_global(j) != NULL && get_global(j)->type != NO_TYPE; ++j) { + g = get_global(j); + if (o->op_store_member.to.index == g->var_index) { + global_var_index = g->var_index; + if (get_type(g->type)->built_in) { + global_var_index = 0; + } + break; + } + } + + indent(hlsl, offset, indentation); + *offset += sprintf(&hlsl[*offset], "_%" PRIu64, o->op_store_member.to.index); + + type *s = get_type(o->op_store_member.to.type.type); + + for (size_t i = 0; i < o->op_store_member.member_indices_size; ++i) { + bool is_array = s->array_size > 0 || o->op_store_member.to.type.type == tex2d_type_id; + + if (is_array) { + type *from_type = get_type(s->base); + + if (global_var_index != 0 && i == 0 && get_type(from_type->base)->built_in) { + if (o->op_store_member.dynamic_member[i]) { + *offset += sprintf(&hlsl[*offset], "[_%" PRIu64 "].data", o->op_store_member.dynamic_member_indices[i].index); + } + else { + *offset += sprintf(&hlsl[*offset], "[%i].data", o->op_store_member.static_member_indices[i]); + } + } + else if (o->op_store_member.dynamic_member[i]) { + *offset += sprintf(&hlsl[*offset], "[_%" PRIu64 "]", o->op_store_member.dynamic_member_indices[i].index); + } + else { + *offset += sprintf(&hlsl[*offset], "[%i]", o->op_store_member.static_member_indices[i]); + } + + s = from_type; + } + else { + debug_context context = {0}; + check(!o->op_store_member.dynamic_member[i], context, "Unexpected dynamic member"); + check(o->op_store_member.static_member_indices[i] < s->members.size, context, "Member index out of bounds"); + + *offset += sprintf(&hlsl[*offset], ".%s", member_string(s, s->members.m[o->op_store_member.static_member_indices[i]].name)); + + s = get_type(s->members.m[o->op_store_member.static_member_indices[i]].type.type); + } + } + + switch (o->type) { + case OPCODE_STORE_MEMBER: + *offset += sprintf(&hlsl[*offset], " = _%" PRIu64 ";\n", o->op_store_member.from.index); + break; + case OPCODE_SUB_AND_STORE_MEMBER: + *offset += sprintf(&hlsl[*offset], " -= _%" PRIu64 ";\n", o->op_store_member.from.index); + break; + case OPCODE_ADD_AND_STORE_MEMBER: + *offset += sprintf(&hlsl[*offset], " += _%" PRIu64 ";\n", o->op_store_member.from.index); + break; + case OPCODE_DIVIDE_AND_STORE_MEMBER: + *offset += sprintf(&hlsl[*offset], " /= _%" PRIu64 ";\n", o->op_store_member.from.index); + break; + case OPCODE_MULTIPLY_AND_STORE_MEMBER: + *offset += sprintf(&hlsl[*offset], " *= _%" PRIu64 ";\n", o->op_store_member.from.index); + break; + default: + assert(false); + break; + } + break; + } + case OPCODE_RETURN: { + if (o->size > offsetof(opcode, op_return)) { + if (f == main && stage == SHADER_STAGE_FRAGMENT && get_type(f->return_type.type)->array_size > 0) { + indent(hlsl, offset, indentation); + *offset += sprintf(&hlsl[*offset], "{\n"); + indent(hlsl, offset, indentation + 1); + *offset += sprintf(&hlsl[*offset], "_kong_colors_out _kong_colors;\n"); + for (uint32_t j = 0; j < get_type(f->return_type.type)->array_size; ++j) { + *offset += sprintf(&hlsl[*offset], "\t\t_kong_colors._%i = _%" PRIu64 "[%i];\n", j, o->op_return.var.index, j); + } + indent(hlsl, offset, indentation + 1); + *offset += sprintf(&hlsl[*offset], "return _kong_colors;\n"); + indent(hlsl, offset, indentation); + *offset += sprintf(&hlsl[*offset], "}\n"); + } + else { + indent(hlsl, offset, indentation); + *offset += sprintf(&hlsl[*offset], "return _%" PRIu64 ";\n", o->op_return.var.index); + } + } + else { + indent(hlsl, offset, indentation); + *offset += sprintf(&hlsl[*offset], "return;\n"); + } + break; + } + case OPCODE_MULTIPLY: { + if (o->op_binary.left.type.type == float4x4_id || o->op_binary.left.type.type == float3x3_id) { + indent(hlsl, offset, indentation); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = mul(_%" PRIu64 ", _%" PRIu64 ");\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.right.index, o->op_binary.left.index); + } + else { + indent(hlsl, offset, indentation); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = _%" PRIu64 " * _%" PRIu64 ";\n", type_string(o->op_binary.result.type.type), + o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + } + break; + } + case OPCODE_CALL: { + indent(hlsl, offset, indentation); + debug_context context = {0}; + if (o->op_call.func == add_name("sample")) { + check(o->op_call.parameters_size == 3, context, "sample requires three parameters"); + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64 " = _%" PRIu64 ".Sample(_%" PRIu64 ", _%" PRIu64 ");\n", type_string(o->op_call.var.type.type), + o->op_call.var.index, o->op_call.parameters[0].index, o->op_call.parameters[1].index, o->op_call.parameters[2].index); + } + else if (o->op_call.func == add_name("sample_lod")) { + check(o->op_call.parameters_size == 4, context, "sample_lod requires four parameters"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = _%" PRIu64 ".SampleLevel(_%" PRIu64 ", _%" PRIu64 ", _%" PRIu64 ");\n", + type_string(o->op_call.var.type.type), o->op_call.var.index, o->op_call.parameters[0].index, + o->op_call.parameters[1].index, o->op_call.parameters[2].index, o->op_call.parameters[3].index); + } + else if (o->op_call.func == add_name("group_id")) { + check(o->op_call.parameters_size == 0, context, "group_id can not have a parameter"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = _kong_group_id;\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("group_thread_id")) { + check(o->op_call.parameters_size == 0, context, "group_thread_id can not have a parameter"); + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64 " = _kong_group_thread_id;\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("dispatch_thread_id")) { + check(o->op_call.parameters_size == 0, context, "dispatch_thread_id can not have a parameter"); + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64 " = _kong_dispatch_thread_id;\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("group_index")) { + check(o->op_call.parameters_size == 0, context, "group_index can not have a parameter"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = _kong_group_index;\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("instance_id")) { + check(o->op_call.parameters_size == 0, context, "instance_id can not have a parameter"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = InstanceID();\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("world_ray_direction")) { + check(o->op_call.parameters_size == 0, context, "world_ray_direction can not have a parameter"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = WorldRayDirection();\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("world_ray_origin")) { + check(o->op_call.parameters_size == 0, context, "world_ray_origin can not have a parameter"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = WorldRayOrigin();\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("ray_length")) { + check(o->op_call.parameters_size == 0, context, "ray_length can not have a parameter"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = RayTCurrent();\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("ray_index")) { + check(o->op_call.parameters_size == 0, context, "ray_index can not have a parameter"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = DispatchRaysIndex();\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("ray_dimensions")) { + check(o->op_call.parameters_size == 0, context, "ray_dimensions can not have a parameter"); + *offset += + sprintf(&hlsl[*offset], "%s _%" PRIu64 " = DispatchRaysDimensions();\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("object_to_world3x3")) { + check(o->op_call.parameters_size == 0, context, "object_to_world3x3 can not have a parameter"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = (float3x3)ObjectToWorld4x3();\n", type_string(o->op_call.var.type.type), + o->op_call.var.index); + } + else if (o->op_call.func == add_name("primitive_index")) { + check(o->op_call.parameters_size == 0, context, "primitive_index can not have a parameter"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = PrimitiveIndex();\n", type_string(o->op_call.var.type.type), o->op_call.var.index); + } + else if (o->op_call.func == add_name("saturate3")) { + check(o->op_call.parameters_size == 1, context, "saturate3 requires one parameter"); + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = saturate(_%" PRIu64 ");\n", type_string(o->op_call.var.type.type), + o->op_call.var.index, o->op_call.parameters[0].index); + } + else if (o->op_call.func == add_name("trace_ray")) { + check(o->op_call.parameters_size == 3, context, "trace_ray requires three parameters"); + *offset += sprintf(&hlsl[*offset], "TraceRay(_%" PRIu64 ", RAY_FLAG_NONE, 0xFF, 0, 0, 0, _%" PRIu64 ", _%" PRIu64 ");\n", + o->op_call.parameters[0].index, o->op_call.parameters[1].index, o->op_call.parameters[2].index); + } + else if (o->op_call.func == add_name("dispatch_mesh")) { + check(o->op_call.parameters_size == 4, context, "dispatch_mesh requires four parameters"); + *offset += + sprintf(&hlsl[*offset], "DispatchMesh(_%" PRIu64 ", _%" PRIu64 ", _%" PRIu64 ", _%" PRIu64 ");\n", o->op_call.parameters[0].index, + o->op_call.parameters[1].index, o->op_call.parameters[2].index, o->op_call.parameters[3].index); + } + else if (o->op_call.func == add_name("set_mesh_output_counts")) { + check(o->op_call.parameters_size == 2, context, "set_mesh_output_counts requires two parameters"); + *offset += sprintf(&hlsl[*offset], "SetMeshOutputCounts(_%" PRIu64 ", _%" PRIu64 ");\n", o->op_call.parameters[0].index, + o->op_call.parameters[1].index); + } + else if (o->op_call.func == add_name("set_mesh_triangle")) { + check(o->op_call.parameters_size == 2, context, "set_mesh_triangle requires two parameters"); + *offset += sprintf(&hlsl[*offset], "_kong_mesh_tris[_%" PRIu64 "] = _%" PRIu64 ";\n", o->op_call.parameters[0].index, + o->op_call.parameters[1].index); + } + else if (o->op_call.func == add_name("set_mesh_vertex")) { + check(o->op_call.parameters_size == 2, context, "set_mesh_vertex requires two parameters"); + *offset += sprintf(&hlsl[*offset], "_kong_mesh_vertices[_%" PRIu64 "] = _%" PRIu64 ";\n", o->op_call.parameters[0].index, + o->op_call.parameters[1].index); + } + else { + if (o->op_call.var.type.type == void_id) { + *offset += sprintf(&hlsl[*offset], "%s(", function_string(o->op_call.func)); + } + else { + *offset += sprintf(&hlsl[*offset], "%s _%" PRIu64 " = %s(", type_string(o->op_call.var.type.type), o->op_call.var.index, + function_string(o->op_call.func)); + } + if (o->op_call.parameters_size > 0) { + *offset += sprintf(&hlsl[*offset], "_%" PRIu64, o->op_call.parameters[0].index); + for (uint8_t i = 1; i < o->op_call.parameters_size; ++i) { + *offset += sprintf(&hlsl[*offset], ", _%" PRIu64, o->op_call.parameters[i].index); + } + } + *offset += sprintf(&hlsl[*offset], ");\n"); + } + break; + } + default: + cstyle_write_opcode(hlsl, offset, o, type_string, &indentation); + break; + } + + index += o->size; + } + + *offset += sprintf(&hlsl[*offset], "}\n\n"); + } +} + +static void hlsl_export_vertex(char *directory, api_kind d3d, function *main) { + char *hlsl = (char *)calloc(1024 * 1024, 1); + size_t offset = 0; + + assert(main->parameters_size > 0); + type_id vertex_inputs[64]; + for (size_t input_index = 0; input_index < main->parameters_size; ++input_index) { + vertex_inputs[input_index] = main->parameter_types[input_index].type; + } + type_id vertex_output = main->return_type.type; + + debug_context context = {0}; + check(main->parameters_size > 0, context, "vertex input missing"); + check(vertex_output != NO_TYPE, context, "vertex output missing"); + + write_types(hlsl, &offset, SHADER_STAGE_VERTEX, vertex_inputs, main->parameters_size, vertex_output, main, NULL, 0); + + write_globals(hlsl, &offset, main, NULL, 0); + + write_functions(hlsl, &offset, SHADER_STAGE_VERTEX, main, NULL, 0); + + uint8_t *output = NULL; + size_t output_size = 0; + int result = 1; + switch (d3d) { + case API_DIRECT3D9: + // result = compile_hlsl_to_d3d9(hlsl, &output, &output_size, SHADER_STAGE_VERTEX, false); + break; + case API_DIRECT3D11: + // result = compile_hlsl_to_d3d11(hlsl, &output, &output_size, SHADER_STAGE_VERTEX, false); + break; + case API_DIRECT3D12: + result = compile_hlsl_to_d3d12(hlsl, &output, &output_size, SHADER_STAGE_VERTEX, false); + break; + default: + error(context, "Unsupported API for HLSL"); + } + check(result == 0, context, "HLSL compilation failed"); + + char *name = get_name(main->name); + + char filename[512]; + sprintf(filename, "kong_%s", name); + + char var_name[256]; + sprintf(var_name, "%s_code", name); + + write_bytecode(hlsl, directory, filename, var_name, output, output_size); +} + +static void hlsl_export_amplification(char *directory, function *main) { + char *hlsl = (char *)calloc(1024 * 1024, 1); + size_t offset = 0; + + write_types(hlsl, &offset, SHADER_STAGE_AMPLIFICATION, NULL, 0, NO_TYPE, main, NULL, 0); + + write_globals(hlsl, &offset, main, NULL, 0); + + write_functions(hlsl, &offset, SHADER_STAGE_AMPLIFICATION, main, NULL, 0); + + uint8_t *output = NULL; + size_t output_size = 0; + int result = compile_hlsl_to_d3d12(hlsl, &output, &output_size, SHADER_STAGE_AMPLIFICATION, false); + + debug_context context = {0}; + check(result == 0, context, "HLSL compilation failed"); + + char *name = get_name(main->name); + + char filename[512]; + sprintf(filename, "kong_%s", name); + + char var_name[256]; + sprintf(var_name, "%s_code", name); + + write_bytecode(hlsl, directory, filename, var_name, output, output_size); +} + +static void hlsl_export_mesh(char *directory, function *main) { + char *hlsl = (char *)calloc(1024 * 1024, 1); + size_t offset = 0; + + attribute *vertices_attribute = find_attribute(&main->attributes, add_name("vertices")); + if (vertices_attribute == NULL || vertices_attribute->paramters_count != 2) { + debug_context context = {0}; + error(context, "Mesh function requires a vertices attribute with two parameters"); + } + assert(vertices_attribute != NULL); + type_id vertex_output = (type_id)vertices_attribute->parameters[1]; + + write_types(hlsl, &offset, SHADER_STAGE_MESH, NULL, 0, vertex_output, main, NULL, 0); + + write_globals(hlsl, &offset, main, NULL, 0); + + write_functions(hlsl, &offset, SHADER_STAGE_MESH, main, NULL, 0); + + uint8_t *output = NULL; + size_t output_size = 0; + int result = compile_hlsl_to_d3d12(hlsl, &output, &output_size, SHADER_STAGE_MESH, false); + + debug_context context = {0}; + check(result == 0, context, "HLSL compilation failed"); + + char *name = get_name(main->name); + + char filename[512]; + sprintf(filename, "kong_%s", name); + + char var_name[256]; + sprintf(var_name, "%s_code", name); + + write_bytecode(hlsl, directory, filename, var_name, output, output_size); +} + +static void hlsl_export_fragment(char *directory, api_kind d3d, function *main) { + char *hlsl = (char *)calloc(1024 * 1024, 1); + size_t offset = 0; + + assert(main->parameters_size > 0); + type_id pixel_input = main->parameter_types[0].type; + + debug_context context = {0}; + check(pixel_input != NO_TYPE, context, "fragment input missing"); + + write_types(hlsl, &offset, SHADER_STAGE_FRAGMENT, &pixel_input, 1, NO_TYPE, main, NULL, 0); + + write_globals(hlsl, &offset, main, NULL, 0); + + write_functions(hlsl, &offset, SHADER_STAGE_FRAGMENT, main, NULL, 0); + + uint8_t *output = NULL; + size_t output_size = 0; + int result = 1; + switch (d3d) { + case API_DIRECT3D9: + // result = compile_hlsl_to_d3d9(hlsl, &output, &output_size, SHADER_STAGE_FRAGMENT, false); + break; + case API_DIRECT3D11: + // result = compile_hlsl_to_d3d11(hlsl, &output, &output_size, SHADER_STAGE_FRAGMENT, false); + break; + case API_DIRECT3D12: + result = compile_hlsl_to_d3d12(hlsl, &output, &output_size, SHADER_STAGE_FRAGMENT, false); + break; + default: + error(context, "Unsupported API for HLSL"); + } + check(result == 0, context, "HLSL compilation failed"); + + char *name = get_name(main->name); + + char filename[512]; + sprintf(filename, "kong_%s", name); + + char var_name[256]; + sprintf(var_name, "%s_code", name); + + write_bytecode(hlsl, directory, filename, var_name, output, output_size); +} + +static void hlsl_export_compute(char *directory, api_kind d3d, function *main) { + char *hlsl = (char *)calloc(1024 * 1024, 1); + size_t offset = 0; + + write_types(hlsl, &offset, SHADER_STAGE_COMPUTE, NULL, 0, NO_TYPE, main, NULL, 0); + + write_globals(hlsl, &offset, main, NULL, 0); + + write_functions(hlsl, &offset, SHADER_STAGE_COMPUTE, main, NULL, 0); + + debug_context context = {0}; + + uint8_t *output = NULL; + size_t output_size = 0; + int result = 1; + switch (d3d) { + case API_DIRECT3D9: + error(context, "Compute shaders are not supported in Direct3D 9"); + break; + case API_DIRECT3D11: + // result = compile_hlsl_to_d3d11(hlsl, &output, &output_size, SHADER_STAGE_COMPUTE, false); + break; + case API_DIRECT3D12: + result = compile_hlsl_to_d3d12(hlsl, &output, &output_size, SHADER_STAGE_COMPUTE, false); + break; + default: + error(context, "Unsupported API for HLSL"); + } + check(result == 0, context, "HLSL compilation failed"); + + char *name = get_name(main->name); + + char filename[512]; + sprintf(filename, "kong_%s", name); + + char var_name[256]; + sprintf(var_name, "%s_code", name); + + write_bytecode(hlsl, directory, filename, var_name, output, output_size); +} + +static void hlsl_export_all_ray_shaders(char *directory) { + char *hlsl = (char *)calloc(1024 * 1024, 1); + debug_context context = {0}; + check(hlsl != NULL, context, "Could not allocate the hlsl string"); + size_t offset = 0; + + function *all_rayshaders[256 * 3]; + size_t all_rayshaders_size = 0; + for (size_t rayshader_index = 0; rayshader_index < raygen_shaders_size; ++rayshader_index) { + all_rayshaders[all_rayshaders_size] = raygen_shaders[rayshader_index]; + all_rayshaders_size += 1; + } + for (size_t rayshader_index = 0; rayshader_index < raymiss_shaders_size; ++rayshader_index) { + all_rayshaders[all_rayshaders_size] = raymiss_shaders[rayshader_index]; + all_rayshaders_size += 1; + } + for (size_t rayshader_index = 0; rayshader_index < rayclosesthit_shaders_size; ++rayshader_index) { + all_rayshaders[all_rayshaders_size] = rayclosesthit_shaders[rayshader_index]; + all_rayshaders_size += 1; + } + for (size_t rayshader_index = 0; rayshader_index < rayintersection_shaders_size; ++rayshader_index) { + all_rayshaders[all_rayshaders_size] = rayintersection_shaders[rayshader_index]; + all_rayshaders_size += 1; + } + for (size_t rayshader_index = 0; rayshader_index < rayanyhit_shaders_size; ++rayshader_index) { + all_rayshaders[all_rayshaders_size] = rayanyhit_shaders[rayshader_index]; + all_rayshaders_size += 1; + } + + if (all_rayshaders_size == 0) { + char *name = "ray"; + + char filename[512]; + sprintf(filename, "kong_%s", name); + + char full_filename[512]; + + sprintf(full_filename, "%s/%s.h", directory, filename); + FILE *file = fopen(full_filename, "wb"); + + fprintf(file, "#ifndef KONG_%s_HEADER\n", name); + fprintf(file, "#define KONG_%s_HEADER\n\n", name); + + fprintf(file, "#define KONG_HAS_NO_RAY_SHADERS\n\n"); + + fprintf(file, "#endif\n"); + + fclose(file); + + return; + } + + write_types(hlsl, &offset, SHADER_STAGE_RAY_GENERATION, NULL, 0, NO_TYPE, NULL, all_rayshaders, all_rayshaders_size); + + write_globals(hlsl, &offset, NULL, all_rayshaders, all_rayshaders_size); + + write_functions(hlsl, &offset, SHADER_STAGE_RAY_GENERATION, NULL, all_rayshaders, all_rayshaders_size); + + uint8_t *output = NULL; + size_t output_size = 0; + int result = compile_hlsl_to_d3d12(hlsl, &output, &output_size, SHADER_STAGE_RAY_GENERATION, false); + check(result == 0, context, "HLSL compilation failed"); + + char *name = "ray"; + + char filename[512]; + sprintf(filename, "kong_%s", name); + + char var_name[256]; + sprintf(var_name, "%s_code", name); + + write_bytecode(hlsl, directory, filename, var_name, output, output_size); +} + +void hlsl_export(char *directory, api_kind d3d) { + static_array(function *, shaders, 256); + + shaders vertex_shaders; + shaders amplification_shaders; + shaders mesh_shaders; + shaders fragment_shaders; + + static_array_init(vertex_shaders); + static_array_init(amplification_shaders); + static_array_init(mesh_shaders); + static_array_init(fragment_shaders); + + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *t = get_type(i); + if (!t->built_in && has_attribute(&t->attributes, add_name("pipe"))) { + name_id vertex_shader_name = NO_NAME; + name_id amplification_shader_name = NO_NAME; + name_id mesh_shader_name = NO_NAME; + name_id fragment_shader_name = NO_NAME; + + for (size_t j = 0; j < t->members.size; ++j) { + if (t->members.m[j].name == add_name("vertex")) { + vertex_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("amplification")) { + amplification_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("mesh")) { + mesh_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("fragment")) { + fragment_shader_name = t->members.m[j].value.identifier; + } + } + + debug_context context = {0}; + check(vertex_shader_name != NO_NAME || mesh_shader_name != NO_NAME, context, "vertex or mesh shader missing"); + check(fragment_shader_name != NO_NAME, context, "fragment shader missing"); + + function *vertex_shader = NULL; + function *amplification_shader = NULL; + function *mesh_shader = NULL; + function *fragment_shader = NULL; + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (vertex_shader_name != NO_NAME && f->name == vertex_shader_name) { + vertex_shader = f; + static_array_push(vertex_shaders, f); + } + if (amplification_shader_name != NO_NAME && f->name == amplification_shader_name) { + amplification_shader = f; + static_array_push(amplification_shaders, f); + } + if (mesh_shader_name != NO_NAME && f->name == mesh_shader_name) { + mesh_shader = f; + static_array_push(mesh_shaders, f); + } + if (f->name == fragment_shader_name) { + fragment_shader = f; + static_array_push(fragment_shaders, f); + } + } + + global_id all_globals[256]; + size_t all_globals_size = 0; + + if (vertex_shader != NULL) { + find_referenced_globals(vertex_shader, all_globals, &all_globals_size); + } + if (amplification_shader != NULL) { + find_referenced_globals(amplification_shader, all_globals, &all_globals_size); + } + if (mesh_shader != NULL) { + find_referenced_globals(mesh_shader, all_globals, &all_globals_size); + } + if (fragment_shader != NULL) { + find_referenced_globals(fragment_shader, all_globals, &all_globals_size); + } + + for (size_t global_index = 0; global_index < all_globals_size; ++global_index) { + global *g = get_global(all_globals[global_index]); + for (size_t set_index = 0; set_index < g->sets_count; ++set_index) { + bool found = false; + + for (size_t all_sets_index = 0; all_sets_index < all_descriptor_sets_count; ++all_sets_index) { + if (all_descriptor_sets[all_sets_index] == g->sets[set_index]) { + found = true; + break; + } + } + + if (!found) { + all_descriptor_sets[all_descriptor_sets_count] = g->sets[set_index]; + all_descriptor_sets_count += 1; + } + } + } + } + } + + function *compute_shaders[256]; + size_t compute_shaders_size = 0; + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (has_attribute(&f->attributes, add_name("compute"))) { + global_id all_globals[256]; + size_t all_globals_size = 0; + + find_referenced_globals(f, all_globals, &all_globals_size); + + for (size_t global_index = 0; global_index < all_globals_size; ++global_index) { + global *g = get_global(all_globals[global_index]); + for (size_t set_index = 0; set_index < g->sets_count; ++set_index) { + bool found = false; + + for (size_t all_sets_index = 0; all_sets_index < all_descriptor_sets_count; ++all_sets_index) { + if (all_descriptor_sets[all_sets_index] == g->sets[set_index]) { + found = true; + break; + } + } + + if (!found) { + all_descriptor_sets[all_descriptor_sets_count] = g->sets[set_index]; + all_descriptor_sets_count += 1; + } + } + } + + compute_shaders[compute_shaders_size] = f; + compute_shaders_size += 1; + } + } + + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *t = get_type(i); + if (!t->built_in && has_attribute(&t->attributes, add_name("raypipe"))) { + name_id raygen_shader_name = NO_NAME; + name_id raymiss_shader_name = NO_NAME; + name_id rayclosesthit_shader_name = NO_NAME; + name_id rayintersection_shader_name = NO_NAME; + name_id rayanyhit_shader_name = NO_NAME; + + for (size_t j = 0; j < t->members.size; ++j) { + if (t->members.m[j].name == add_name("gen")) { + raygen_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("miss")) { + raymiss_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("closest")) { + rayclosesthit_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("intersection")) { + rayintersection_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("any")) { + rayanyhit_shader_name = t->members.m[j].value.identifier; + } + } + + debug_context context = {0}; + check(raygen_shader_name != NO_NAME, context, "Ray generation shader missing"); + check(raymiss_shader_name != NO_NAME, context, "Miss shader missing"); + check(rayclosesthit_shader_name != NO_NAME, context, "Closest hit shader missing"); + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (f->name == raygen_shader_name) { + raygen_shaders[raygen_shaders_size] = f; + raygen_shaders_size += 1; + } + else if (f->name == raymiss_shader_name) { + raymiss_shaders[raymiss_shaders_size] = f; + raymiss_shaders_size += 1; + } + else if (f->name == rayclosesthit_shader_name) { + rayclosesthit_shaders[rayclosesthit_shaders_size] = f; + rayclosesthit_shaders_size += 1; + } + else if (f->name == rayintersection_shader_name) { + rayintersection_shaders[rayintersection_shaders_size] = f; + rayintersection_shaders_size += 1; + } + else if (f->name == rayanyhit_shader_name) { + rayanyhit_shaders[rayanyhit_shaders_size] = f; + rayanyhit_shaders_size += 1; + } + } + } + } + + for (size_t i = 0; i < vertex_shaders.size; ++i) { + hlsl_export_vertex(directory, d3d, vertex_shaders.values[i]); + } + + if (d3d == API_DIRECT3D12) { + for (size_t i = 0; i < amplification_shaders.size; ++i) { + hlsl_export_amplification(directory, amplification_shaders.values[i]); + } + + for (size_t i = 0; i < mesh_shaders.size; ++i) { + hlsl_export_mesh(directory, mesh_shaders.values[i]); + } + } + + for (size_t i = 0; i < fragment_shaders.size; ++i) { + hlsl_export_fragment(directory, d3d, fragment_shaders.values[i]); + } + + for (size_t i = 0; i < compute_shaders_size; ++i) { + hlsl_export_compute(directory, d3d, compute_shaders[i]); + } + + if (d3d == API_DIRECT3D12) { + hlsl_export_all_ray_shaders(directory); + } +} diff --git a/base/sources/libs/kong/sources/backends/hlsl.h b/base/sources/libs/kong/sources/backends/hlsl.h new file mode 100644 index 00000000..fe2df6e3 --- /dev/null +++ b/base/sources/libs/kong/sources/backends/hlsl.h @@ -0,0 +1,7 @@ +#pragma once + +#include "../api.h" + +#include + +void hlsl_export(char *directory, api_kind d3d); diff --git a/base/sources/libs/kong/sources/backends/metal.c b/base/sources/libs/kong/sources/backends/metal.c new file mode 100644 index 00000000..e0037c99 --- /dev/null +++ b/base/sources/libs/kong/sources/backends/metal.c @@ -0,0 +1,454 @@ +#include "metal.h" + +#include "../analyzer.h" +#include "../compiler.h" +#include "../errors.h" +#include "../functions.h" +#include "../parser.h" +#include "../shader_stage.h" +#include "../types.h" +#include "cstyle.h" +#include "util.h" + +#include +#include +#include +#include +#include +#include + +static char *type_string(type_id type) { + if (type == float_id) { + return "float"; + } + if (type == float2_id) { + return "float2"; + } + if (type == float3_id) { + return "float3"; + } + if (type == float4_id) { + return "float4"; + } + if (type == float4x4_id) { + return "float4x4"; + } + return get_name(get_type(type)->name); +} + +static char *function_string(name_id func) { + return get_name(func); +} + +static void write_code(char *metal, char *directory, const char *filename) { + char full_filename[512]; + sprintf(full_filename, "%s/%s.metal", directory, filename); + + FILE *file = fopen(full_filename, "wb"); + fprintf(file, "%s", metal); + fclose(file); +} + +static type_id vertex_inputs[256]; +static size_t vertex_inputs_size = 0; +static type_id fragment_inputs[256]; +static size_t fragment_inputs_size = 0; + +static bool is_vertex_input(type_id t) { + for (size_t i = 0; i < vertex_inputs_size; ++i) { + if (t == vertex_inputs[i]) { + return true; + } + } + return false; +} + +static bool is_fragment_input(type_id t) { + for (size_t i = 0; i < fragment_inputs_size; ++i) { + if (t == fragment_inputs[i]) { + return true; + } + } + return false; +} + +static void write_types(char *metal, size_t *offset) { + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *t = get_type(i); + + if (!t->built_in && !has_attribute(&t->attributes, add_name("pipe"))) { + if (t->name == NO_NAME) { + char name[256]; + + bool found = false; + for (global_id j = 0; get_global(j)->type != NO_TYPE; ++j) { + global *g = get_global(j); + if (g->type == i) { + sprintf(name, "_%" PRIu64, g->var_index); + found = true; + break; + } + } + + if (!found) { + strcpy(name, "Unknown"); + } + + *offset += sprintf(&metal[*offset], "struct %s_type {\n", name); + } + else { + *offset += sprintf(&metal[*offset], "struct %s {\n", get_name(t->name)); + } + + if (is_vertex_input(i)) { + for (size_t j = 0; j < t->members.size; ++j) { + *offset += + sprintf(&metal[*offset], "\t%s %s [[attribute(%zu)]];\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name), j); + } + } + else if (is_fragment_input(i)) { + for (size_t j = 0; j < t->members.size; ++j) { + if (j == 0) { + *offset += sprintf(&metal[*offset], "\t%s %s [[position]];\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name)); + } + else { + *offset += sprintf(&metal[*offset], "\t%s %s [[user(locn%zu)]];\n", type_string(t->members.m[j].type.type), + get_name(t->members.m[j].name), j - 1); + } + } + } + else { + for (size_t j = 0; j < t->members.size; ++j) { + *offset += sprintf(&metal[*offset], "\t%s %s;\n", type_string(t->members.m[j].type.type), get_name(t->members.m[j].name)); + } + } + *offset += sprintf(&metal[*offset], "};\n\n"); + } + } +} + +static int global_register_indices[512]; + +static function_id vertex_functions[256]; +static size_t vertex_functions_size = 0; +static function_id fragment_functions[256]; +static size_t fragment_functions_size = 0; + +static bool is_vertex_function(function_id f) { + for (size_t i = 0; i < vertex_functions_size; ++i) { + if (f == vertex_functions[i]) { + return true; + } + } + return false; +} + +static bool is_fragment_function(function_id f) { + for (size_t i = 0; i < fragment_functions_size; ++i) { + if (f == fragment_functions[i]) { + return true; + } + } + return false; +} + +static void write_functions(char *code, size_t *offset) { + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + + if (f->block == NULL) { + continue; + } + + uint8_t *data = f->code.o; + size_t size = f->code.size; + + uint64_t parameter_ids[256] = {0}; + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + for (size_t i = 0; i < f->block->block.vars.size; ++i) { + if (f->parameter_names[parameter_index] == f->block->block.vars.v[i].name) { + parameter_ids[parameter_index] = f->block->block.vars.v[i].variable_id; + break; + } + } + } + + debug_context context = {0}; + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + check(parameter_ids[parameter_index] != 0, context, "Parameter not found"); + } + + char buffers[1024]; + strcpy(buffers, ""); + if (is_vertex_function(i) || is_fragment_function(i)) { + global_id globals[256]; + size_t globals_size = 0; + find_referenced_globals(f, globals, &globals_size); + + size_t buffers_offset = 0; + + for (size_t i = 0; i < globals_size; ++i) { + global *g = get_global(globals[i]); + int register_index = global_register_indices[globals[i]]; + + if (g->type == sampler_type_id) { + buffers_offset += sprintf(&buffers[buffers_offset], ", sampler _%" PRIu64 " [[sampler(%i)]]", g->var_index, register_index); + } + else if (g->type == tex2d_type_id) { + buffers_offset += sprintf(&buffers[buffers_offset], ", texture2d _%" PRIu64 " [[texture(%i)]]", g->var_index, register_index); + } + else if (g->type == texcube_type_id) { + buffers_offset += sprintf(&buffers[buffers_offset], ", texturecube _%" PRIu64 " [[texture(%i)]]", g->var_index, register_index); + } + else if (g->type == float_id) { + } + else { + buffers_offset += sprintf(&buffers[buffers_offset], ", constant _%" PRIu64 "_type& _%" PRIu64 " [[buffer(%i)]]", g->var_index, g->var_index, + register_index); + } + } + } + + if (is_vertex_function(i)) { + *offset += sprintf(&code[*offset], "vertex %s %s(%s _%" PRIu64 " [[stage_in]]", type_string(f->return_type.type), get_name(f->name), + type_string(f->parameter_types[0].type), parameter_ids[0]); + for (uint8_t parameter_index = 1; parameter_index < f->parameters_size; ++parameter_index) { + *offset += sprintf(&code[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[0].type), parameter_ids[0]); + } + *offset += sprintf(&code[*offset], "%s) {\n", buffers); + } + else if (is_fragment_function(i)) { + if (get_type(f->return_type.type)->array_size > 0) { + *offset += sprintf(&code[*offset], "struct _kong_colors_out {\n"); + for (uint32_t j = 0; j < get_type(f->return_type.type)->array_size; ++j) { + *offset += sprintf(&code[*offset], "\t%s _%i [[color(%i)]];\n", type_string(f->return_type.type), j, j); + } + *offset += sprintf(&code[*offset], "};\n\n"); + + *offset += sprintf(&code[*offset], "fragment _kong_colors_out %s(%s _%" PRIu64 " [[stage_in]]", get_name(f->name), + type_string(f->parameter_types[0].type), parameter_ids[0]); + for (uint8_t parameter_index = 1; parameter_index < f->parameters_size; ++parameter_index) { + *offset += sprintf(&code[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + *offset += sprintf(&code[*offset], "%s) {\n", buffers); + } + else { + *offset += sprintf(&code[*offset], "fragment _kong_color_out %s(%s _%" PRIu64 " [[stage_in]]", get_name(f->name), + type_string(f->parameter_types[0].type), parameter_ids[0]); + for (uint8_t parameter_index = 1; parameter_index < f->parameters_size; ++parameter_index) { + *offset += sprintf(&code[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + *offset += sprintf(&code[*offset], "%s) {\n", buffers); + } + } + + else { + *offset += sprintf(&code[*offset], "%s %s(", type_string(f->return_type.type), get_name(f->name)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += sprintf(&code[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += sprintf(&code[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + *offset += sprintf(&code[*offset], ") {\n"); + } + + int indentation = 1; + + size_t index = 0; + while (index < size) { + opcode *o = (opcode *)&data[index]; + switch (o->type) { + case OPCODE_LOAD_MEMBER: { + uint64_t global_var_index = 0; + for (global_id j = 0; get_global(j) != NULL && get_global(j)->type != NO_TYPE; ++j) { + global *g = get_global(j); + if (o->op_load_member.from.index == g->var_index) { + global_var_index = g->var_index; + break; + } + } + + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64, type_string(o->op_load_member.to.type.type), o->op_load_member.to.index, + o->op_load_member.from.index); + type *s = get_type(o->op_load_member.member_parent_type); + for (size_t i = 0; i < o->op_load_member.member_indices_size; ++i) { + *offset += sprintf(&code[*offset], ".%s", get_name(s->members.m[o->op_load_member.static_member_indices[i]].name)); + s = get_type(s->members.m[o->op_load_member.static_member_indices[i]].type.type); + } + *offset += sprintf(&code[*offset], ";\n"); + break; + } + case OPCODE_RETURN: { + if (o->size > offsetof(opcode, op_return)) { + if (is_fragment_function(i) && get_type(f->return_type.type)->array_size > 0) { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "{\n"); + indent(code, offset, indentation + 1); + *offset += sprintf(&code[*offset], "_kong_colors_out _kong_colors;\n"); + for (uint32_t j = 0; j < get_type(f->return_type.type)->array_size; ++j) { + indent(code, offset, indentation + 1); + *offset += sprintf(&code[*offset], "_kong_colors._%i = _%" PRIu64 "[%i];\n", j, o->op_return.var.index, j); + } + indent(code, offset, indentation + 1); + *offset += sprintf(&code[*offset], "return _kong_colors;\n"); + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "}\n"); + } + else if (is_fragment_function(i)) { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "{\n"); + indent(code, offset, indentation + 1); + *offset += sprintf(&code[*offset], "_kong_color_out _kong_color;\n"); + indent(code, offset, indentation + 1); + *offset += sprintf(&code[*offset], "_kong_color._0 = _%" PRIu64 ";\n", o->op_return.var.index); + indent(code, offset, indentation + 1); + *offset += sprintf(&code[*offset], "return _kong_color;\n"); + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "}\n"); + } + else { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "return _%" PRIu64 ";\n", o->op_return.var.index); + } + } + else { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "return;\n"); + } + break; + } + case OPCODE_CALL: { + debug_context context = {0}; + if (o->op_call.func == add_name("sample")) { + check(o->op_call.parameters_size == 3, context, "sample requires three parameters"); + indent(code, offset, indentation); + *offset += + sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 ".sample(_%" PRIu64 ", _%" PRIu64 ");\n", type_string(o->op_call.var.type.type), + o->op_call.var.index, o->op_call.parameters[0].index, o->op_call.parameters[1].index, o->op_call.parameters[2].index); + } + else if (o->op_call.func == add_name("sample_lod")) { + check(o->op_call.parameters_size == 4, context, "sample_lod requires four parameters"); + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = _%" PRIu64 ".sample(_%" PRIu64 ", _%" PRIu64 ", level(_%" PRIu64 "));\n", + type_string(o->op_call.var.type.type), o->op_call.var.index, o->op_call.parameters[0].index, + o->op_call.parameters[1].index, o->op_call.parameters[2].index, o->op_call.parameters[3].index); + } + else { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "%s _%" PRIu64 " = %s(", type_string(o->op_call.var.type.type), o->op_call.var.index, + function_string(o->op_call.func)); + if (o->op_call.parameters_size > 0) { + *offset += sprintf(&code[*offset], "_%" PRIu64, o->op_call.parameters[0].index); + for (uint8_t i = 1; i < o->op_call.parameters_size; ++i) { + *offset += sprintf(&code[*offset], ", _%" PRIu64, o->op_call.parameters[i].index); + } + } + *offset += sprintf(&code[*offset], ");\n"); + } + break; + } + default: + cstyle_write_opcode(code, offset, o, type_string, &indentation); + break; + } + + index += o->size; + } + + *offset += sprintf(&code[*offset], "}\n\n"); + } +} + +static void metal_export_everything(char *directory) { + char *metal = (char *)calloc(1024 * 1024, 1); + debug_context context = {0}; + check(metal != NULL, context, "Could not allocate Metal string"); + size_t offset = 0; + + offset += sprintf(&metal[offset], "#include \n"); + offset += sprintf(&metal[offset], "#include \n\n"); + offset += sprintf(&metal[offset], "using namespace metal;\n\n"); + + offset += sprintf(&metal[offset], "struct _kong_color_out {\n"); + offset += sprintf(&metal[offset], "\tfloat4 _0 [[color(0)]];\n"); + offset += sprintf(&metal[offset], "};\n\n"); + + write_types(metal, &offset); + + write_functions(metal, &offset); + + write_code(metal, directory, "kong"); +} + +void metal_export(char *directory) { + int cbuffer_index = 0; + int texture_index = 0; + int sampler_index = 0; + + memset(global_register_indices, 0, sizeof(global_register_indices)); + + for (global_id i = 0; get_global(i) != NULL && get_global(i)->type != NO_TYPE; ++i) { + global *g = get_global(i); + if (g->type == sampler_type_id) { + global_register_indices[i] = sampler_index; + sampler_index += 1; + } + else if (g->type == tex2d_type_id || g->type == texcube_type_id) { + global_register_indices[i] = texture_index; + texture_index += 1; + } + else if (g->type == float_id) { + } + else { + global_register_indices[i] = cbuffer_index; + cbuffer_index += 1; + } + } + + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *t = get_type(i); + if (!t->built_in && has_attribute(&t->attributes, add_name("pipe"))) { + name_id vertex_shader_name = NO_NAME; + name_id fragment_shader_name = NO_NAME; + + for (size_t j = 0; j < t->members.size; ++j) { + if (t->members.m[j].name == add_name("vertex")) { + vertex_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("fragment")) { + fragment_shader_name = t->members.m[j].value.identifier; + } + } + + debug_context context = {0}; + check(vertex_shader_name != NO_NAME, context, "vertex shader missing"); + check(fragment_shader_name != NO_NAME, context, "fragment shader missing"); + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (f->name == vertex_shader_name) { + vertex_functions[vertex_functions_size] = i; + vertex_functions_size += 1; + + assert(f->parameters_size > 0); + vertex_inputs[vertex_inputs_size] = f->parameter_types[0].type; + vertex_inputs_size += 1; + } + else if (f->name == fragment_shader_name) { + fragment_functions[fragment_functions_size] = i; + fragment_functions_size += 1; + + assert(f->parameters_size > 0); + fragment_inputs[fragment_inputs_size] = f->parameter_types[0].type; + fragment_inputs_size += 1; + } + } + } + } + + metal_export_everything(directory); +} diff --git a/base/sources/libs/kong/sources/backends/metal.h b/base/sources/libs/kong/sources/backends/metal.h new file mode 100644 index 00000000..ae52e8ab --- /dev/null +++ b/base/sources/libs/kong/sources/backends/metal.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void metal_export(char *directory); diff --git a/base/sources/libs/kong/sources/backends/spirv.c b/base/sources/libs/kong/sources/backends/spirv.c new file mode 100644 index 00000000..ebabd45d --- /dev/null +++ b/base/sources/libs/kong/sources/backends/spirv.c @@ -0,0 +1,1542 @@ +#include "spirv.h" + +#include "../analyzer.h" +#include "../compiler.h" +#include "../errors.h" +#include "../functions.h" +#include "../parser.h" +#include "../shader_stage.h" +#include "../types.h" + +#include "../libs/stb_ds.h" + +#include "util.h" + +#include +#include +#include +#include + +typedef struct spirv_id { + uint32_t id; +} spirv_id; + +typedef struct instructions_buffer { + uint32_t *instructions; + size_t offset; +} instructions_buffer; + +static void write_buffer(FILE *file, uint8_t *output, size_t output_size) { + for (size_t i = 0; i < output_size; ++i) { + // based on the encoding described in https://github.com/adobe/bin2c + if (output[i] == '!' || output[i] == '#' || (output[i] >= '%' && output[i] <= '>') || (output[i] >= 'A' && output[i] <= '[') || + (output[i] >= ']' && output[i] <= '~')) { + fprintf(file, "%c", output[i]); + } + else if (output[i] == '\a') { + fprintf(file, "\\a"); + } + else if (output[i] == '\b') { + fprintf(file, "\\b"); + } + else if (output[i] == '\t') { + fprintf(file, "\\t"); + } + else if (output[i] == '\v') { + fprintf(file, "\\v"); + } + else if (output[i] == '\f') { + fprintf(file, "\\f"); + } + else if (output[i] == '\r') { + fprintf(file, "\\r"); + } + else if (output[i] == '\"') { + fprintf(file, "\\\""); + } + else if (output[i] == '\\') { + fprintf(file, "\\\\"); + } + else { + fprintf(file, "\\%03o", output[i]); + } + } +} + +static void write_bytecode(char *directory, const char *filename, const char *name, instructions_buffer *header, instructions_buffer *decorations, + instructions_buffer *constants, instructions_buffer *instructions) { + uint8_t *output_header = (uint8_t *)header->instructions; + size_t output_header_size = header->offset * 4; + + uint8_t *output_decorations = (uint8_t *)decorations->instructions; + size_t output_decorations_size = decorations->offset * 4; + + uint8_t *output_constants = (uint8_t *)constants->instructions; + size_t output_constants_size = constants->offset * 4; + + uint8_t *output_instructions = (uint8_t *)instructions->instructions; + size_t output_instructions_size = instructions->offset * 4; + + char full_filename[512]; + + { + // sprintf(full_filename, "%s/%s.h", directory, filename); + // FILE *file = fopen(full_filename, "wb"); + // fprintf(file, "#include \n"); + // fprintf(file, "#include \n\n"); + // fprintf(file, "extern uint8_t *%s;\n", name); + // fprintf(file, "extern size_t %s_size;\n", name); + // 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, "uint8_t *%s = \"", name); + // write_buffer(file, output_header, output_header_size); + // write_buffer(file, output_decorations, output_decorations_size); + // write_buffer(file, output_constants, output_constants_size); + // write_buffer(file, output_instructions, output_instructions_size); + // fprintf(file, "\";\n"); + + // fprintf(file, "size_t %s_size = %zu;\n\n", name, output_header_size + output_decorations_size + output_constants_size + output_instructions_size); + + // fclose(file); + } + +// #ifndef NDEBUG + { + sprintf(full_filename, "%s/%s.spirv", directory, filename); + + full_filename[strlen(full_filename) - 11] = '.'; //// _frag -> .frag + + FILE *file = fopen(full_filename, "wb"); + fwrite(output_header, 1, output_header_size, file); + fwrite(output_decorations, 1, output_decorations_size, file); + fwrite(output_constants, 1, output_constants_size, file); + fwrite(output_instructions, 1, output_instructions_size, file); + fclose(file); + } +// #endif +} + +typedef enum spirv_opcode { + SPIRV_OPCODE_EXT_INST_IMPORT = 11, + SPIRV_OPCODE_MEMORY_MODEL = 14, + SPIRV_OPCODE_ENTRY_POINT = 15, + SPIRV_OPCODE_EXECUTION_MODE = 16, + SPIRV_OPCODE_CAPABILITY = 17, + SPIRV_OPCODE_TYPE_VOID = 19, + SPIRV_OPCODE_TYPE_BOOL = 20, + SPIRV_OPCODE_TYPE_INT = 21, + SPIRV_OPCODE_TYPE_FLOAT = 22, + SPIRV_OPCODE_TYPE_VECTOR = 23, + SPIRV_OPCODE_TYPE_MATRIX = 24, + SPIRV_OPCODE_TYPE_STRUCT = 30, + SPIRV_OPCODE_TYPE_POINTER = 32, + SPIRV_OPCODE_TYPE_FUNCTION = 33, + SPIRV_OPCODE_CONSTANT = 43, + SPIRV_OPCODE_FUNCTION = 54, + SPIRV_OPCODE_FUNCTION_END = 56, + SPIRV_OPCODE_VARIABLE = 59, + SPIRV_OPCODE_LOAD = 61, + SPIRV_OPCODE_STORE = 62, + SPIRV_OPCODE_ACCESS_CHAIN = 65, + SPIRV_OPCODE_DECORATE = 71, + SPIRV_OPCODE_MEMBER_DECORATE = 72, + SPIRV_OPCODE_COMPOSITE_CONSTRUCT = 80, + SPIRV_OPCODE_F_MUL = 133, + SPIRV_OPCODE_F_ORD_LESS_THAN = 184, + SPIRV_OPCODE_LOOP_MERGE = 246, + SPIRV_OPCODE_SELECTION_MERGE = 247, + SPIRV_OPCODE_LABEL = 248, + SPIRV_OPCODE_BRANCH = 249, + SPIRV_OPCODE_BRANCH_CONDITIONAL = 250, + SPIRV_OPCODE_RETURN = 253, +} spirv_opcode; + +static type_id find_access_type(int *indices, int indices_size, type_id base_type) { + if (indices_size == 1) { + if (base_type == float2_id || base_type == float3_id || base_type == float4_id) { + return float_id; + } + else { + type *t = get_type(base_type); + assert(indices[0] < t->members.size); + return t->members.m[indices[0]].type.type; + } + } + else { + type *t = get_type(base_type); + assert(indices[0] < t->members.size); + return find_access_type(&indices[1], indices_size - 1, t->members.m[indices[0]].type.type); + } +} + +static void vector_member_indices(int *input_indices, int *output_indices, int indices_size, type_id base_type) { + if (base_type == float2_id || base_type == float3_id || base_type == float4_id) { + type *t = get_type(base_type); + + if (strcmp(get_name(t->members.m[input_indices[0]].name), "x") == 0 || strcmp(get_name(t->members.m[input_indices[0]].name), "r") == 0) { + output_indices[0] = 0; + } + else if (strcmp(get_name(t->members.m[input_indices[0]].name), "y") == 0 || strcmp(get_name(t->members.m[input_indices[0]].name), "g") == 0) { + output_indices[0] = 1; + } + else if (strcmp(get_name(t->members.m[input_indices[0]].name), "z") == 0 || strcmp(get_name(t->members.m[input_indices[0]].name), "b") == 0) { + output_indices[0] = 2; + } + else if (strcmp(get_name(t->members.m[input_indices[0]].name), "w") == 0 || strcmp(get_name(t->members.m[input_indices[0]].name), "a") == 0) { + output_indices[0] = 3; + } + else { + // assert(false); + output_indices[0] = 0; // TODO + } + } + else { + output_indices[0] = input_indices[0]; + } + + if (indices_size > 1) { + type *t = get_type(base_type); + assert(input_indices[0] < t->members.size); + vector_member_indices(&input_indices[1], &output_indices[1], indices_size - 1, t->members.m[input_indices[0]].type.type); + } +} + +typedef enum addressing_model { ADDRESSING_MODEL_LOGICAL = 0 } addressing_model; + +typedef enum memory_model { MEMORY_MODEL_SIMPLE = 0, MEMORY_MODEL_GLSL450 = 1 } memory_model; + +typedef enum capability { CAPABILITY_SHADER = 1 } capability; + +typedef enum execution_model { EXECUTION_MODEL_VERTEX = 0, EXECUTION_MODEL_FRAGMENT = 4 } execution_model; + +typedef enum decoration { DECORATION_BLOCK = 2, DECORATION_BUILTIN = 11, DECORATION_LOCATION = 30 } decoration; + +typedef enum builtin { BUILTIN_POSITION = 0 } builtin; + +typedef enum storage_class { + STORAGE_CLASS_INPUT = 1, + STORAGE_CLASS_UNIFORM = 2, + STORAGE_CLASS_OUTPUT = 3, + STORAGE_CLASS_FUNCTION = 7, + STORAGE_CLASS_NONE = 9999 +} storage_class; + +typedef enum selection_control { SELECTION_CONTROL_NONE = 0, SELCTION_CONTROL_FLATTEN = 1, SELECTION_CONTROL_DONT_FLATTEN = 2 } selection_control; + +typedef enum loop_control { LOOP_CONTROL_NONE = 0, LOOP_CONTROL_UNROLL = 1, LOOP_CONTROL_DONT_UNROLL = 2 } loop_control; + +typedef enum function_control { FUNCTION_CONTROL_NONE } function_control; + +typedef enum execution_mode { EXECUTION_MODE_ORIGIN_UPPER_LEFT = 7 } execution_mode; + +static uint32_t operands_buffer[4096]; + +static void write_simple_instruction(instructions_buffer *instructions, spirv_opcode o) { + instructions->instructions[instructions->offset++] = (1 << 16) | (uint16_t)o; +} + +static void write_instruction(instructions_buffer *instructions, uint16_t word_count, spirv_opcode o, uint32_t *operands) { + instructions->instructions[instructions->offset++] = (word_count << 16) | (uint16_t)o; + for (uint16_t i = 0; i < word_count - 1; ++i) { + instructions->instructions[instructions->offset++] = operands[i]; + } +} + +static void write_magic_number(instructions_buffer *instructions) { + instructions->instructions[instructions->offset++] = 0x07230203; +} + +static void write_version_number(instructions_buffer *instructions) { + instructions->instructions[instructions->offset++] = 0x00010000; +} + +static void write_generator_magic_number(instructions_buffer *instructions) { + instructions->instructions[instructions->offset++] = 44; +} + +static uint32_t next_index = 1; + +static void write_bound(instructions_buffer *instructions) { + instructions->instructions[instructions->offset++] = next_index; +} + +static void write_instruction_schema(instructions_buffer *instructions) { + instructions->instructions[instructions->offset++] = 0; // reserved in SPIR-V for later use, currently always zero +} + +static void write_capability(instructions_buffer *instructions, capability c) { + uint32_t operand = (uint32_t)c; + write_instruction(instructions, 2, SPIRV_OPCODE_CAPABILITY, &operand); +} + +static spirv_id allocate_index(void) { + uint32_t result = next_index; + ++next_index; + + spirv_id id; + id.id = result; + return id; +} + +static uint16_t write_string(uint32_t *operands, const char *string) { + uint16_t length = (uint16_t)strlen(string); + memcpy(&operands[0], string, length + 1); + return (length + 1) / 4 + 1; +} + +static spirv_id write_op_ext_inst_import(instructions_buffer *instructions, const char *name) { + spirv_id result = allocate_index(); + + operands_buffer[0] = result.id; + + uint32_t name_length = write_string(&operands_buffer[1], name); + + write_instruction(instructions, 2 + name_length, SPIRV_OPCODE_EXT_INST_IMPORT, operands_buffer); + + return result; +} + +static void write_op_memory_model(instructions_buffer *instructions, uint32_t addressing_model, uint32_t memory_model) { + uint32_t args[2] = {addressing_model, memory_model}; + write_instruction(instructions, 3, SPIRV_OPCODE_MEMORY_MODEL, args); +} + +static void write_op_entry_point(instructions_buffer *instructions, execution_model em, spirv_id entry_point, const char *name, spirv_id *interfaces, + uint16_t interfaces_size) { + operands_buffer[0] = (uint32_t)em; + operands_buffer[1] = entry_point.id; + + uint32_t name_length = write_string(&operands_buffer[2], name); + + for (uint16_t i = 0; i < interfaces_size; ++i) { + operands_buffer[2 + name_length + i] = interfaces[i].id; + } + + write_instruction(instructions, 3 + name_length + interfaces_size, SPIRV_OPCODE_ENTRY_POINT, operands_buffer); +} + +static void write_op_execution_mode(instructions_buffer *instructions, spirv_id entry_point, execution_mode mode) { + operands_buffer[0] = entry_point.id; + operands_buffer[1] = (uint32_t)mode; + + write_instruction(instructions, 3, SPIRV_OPCODE_EXECUTION_MODE, operands_buffer); +} + +static void write_capabilities(instructions_buffer *instructions) { + write_capability(instructions, CAPABILITY_SHADER); +} + +static spirv_id write_type_void(instructions_buffer *instructions) { + spirv_id void_type = allocate_index(); + write_instruction(instructions, 2, SPIRV_OPCODE_TYPE_VOID, &void_type.id); + return void_type; +} + +#define WORD_COUNT(operands) (1 + sizeof(operands) / 4) + +static spirv_id write_type_function(instructions_buffer *instructions, spirv_id return_type, spirv_id *parameter_types, uint16_t parameter_types_size) { + spirv_id function_type = allocate_index(); + + operands_buffer[0] = function_type.id; + operands_buffer[1] = return_type.id; + for (uint16_t i = 0; i < parameter_types_size; ++i) { + operands_buffer[i + 2] = parameter_types[0].id; + } + write_instruction(instructions, 3 + parameter_types_size, SPIRV_OPCODE_TYPE_FUNCTION, operands_buffer); + return function_type; +} + +static spirv_id write_type_float(instructions_buffer *instructions, uint32_t width) { + spirv_id float_type = allocate_index(); + + uint32_t operands[] = {float_type.id, width}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_TYPE_FLOAT, operands); + return float_type; +} + +// static spirv_id write_type_vector(instructions_buffer *instructions, spirv_id component_type, uint32_t component_count) { +// spirv_id vector_type = allocate_index(); +// +// uint32_t operands[] = {vector_type.id, component_type.id, component_count}; +// write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_TYPE_VECTOR, operands); +// return vector_type; +// } + +static spirv_id write_type_vector_preallocated(instructions_buffer *instructions, spirv_id component_type, uint32_t component_count, spirv_id vector_type) { + uint32_t operands[] = {vector_type.id, component_type.id, component_count}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_TYPE_VECTOR, operands); + return vector_type; +} + +static spirv_id write_type_matrix(instructions_buffer *instructions, spirv_id column_type, uint32_t column_count) { + spirv_id matrix_type = allocate_index(); + + uint32_t operands[] = {matrix_type.id, column_type.id, column_count}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_TYPE_MATRIX, operands); + return matrix_type; +} + +static spirv_id write_type_int(instructions_buffer *instructions, uint32_t width, bool signedness) { + spirv_id int_type = allocate_index(); + + uint32_t operands[] = {int_type.id, width, signedness ? 1 : 0}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_TYPE_INT, operands); + return int_type; +} + +static spirv_id write_type_bool(instructions_buffer *instructions) { + spirv_id bool_type = allocate_index(); + + uint32_t operands[] = {bool_type.id}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_TYPE_BOOL, operands); + return bool_type; +} + +static spirv_id write_type_struct(instructions_buffer *instructions, spirv_id *types, uint16_t types_size) { + spirv_id struct_type = allocate_index(); + + operands_buffer[0] = struct_type.id; + for (uint16_t i = 0; i < types_size; ++i) { + operands_buffer[i + 1] = types[i].id; + } + write_instruction(instructions, 2 + types_size, SPIRV_OPCODE_TYPE_STRUCT, operands_buffer); + return struct_type; +} + +static spirv_id write_type_pointer(instructions_buffer *instructions, storage_class storage, spirv_id type) { + spirv_id pointer_type = allocate_index(); + + uint32_t operands[] = {pointer_type.id, (uint32_t)storage, type.id}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_TYPE_POINTER, operands); + return pointer_type; +} + +static spirv_id write_type_pointer_preallocated(instructions_buffer *instructions, storage_class storage, spirv_id type, spirv_id pointer_type) { + uint32_t operands[] = {pointer_type.id, (uint32_t)storage, type.id}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_TYPE_POINTER, operands); + return pointer_type; +} + +static spirv_id void_type; +static spirv_id void_function_type; +static spirv_id spirv_float_type; +static spirv_id spirv_int_type; +static spirv_id spirv_uint_type; +static spirv_id spirv_float2_type; +static spirv_id spirv_float3_type; +static spirv_id spirv_float4_type; +static spirv_id spirv_bool_type; + +typedef struct complex_type { + type_id type; + uint16_t pointer; + uint16_t storage; +} complex_type; + +static struct { + complex_type key; + spirv_id value; +} *type_map = NULL; + +static spirv_id convert_type_to_spirv_id(type_id type) { + complex_type ct; + ct.type = type; + ct.pointer = (uint16_t) false; + ct.storage = (uint16_t)STORAGE_CLASS_NONE; + + spirv_id spirv_index = hmget(type_map, ct); + if (spirv_index.id == 0) { + spirv_index = allocate_index(); + hmput(type_map, ct, spirv_index); + } + return spirv_index; +} + +static spirv_id convert_pointer_type_to_spirv_id(type_id type, storage_class storage) { + complex_type ct; + ct.type = type; + ct.pointer = (uint16_t) true; + ct.storage = (uint16_t)storage; + + spirv_id spirv_index = hmget(type_map, ct); + if (spirv_index.id == 0) { + spirv_index = allocate_index(); + hmput(type_map, ct, spirv_index); + } + return spirv_index; +} + +static spirv_id output_struct_pointer_type = {0}; + +static void write_base_type(instructions_buffer *constants_block, type_id type, spirv_id spirv_type) { + complex_type ct; + ct.pointer = (uint16_t) false; + ct.storage = (uint16_t)STORAGE_CLASS_NONE; + ct.type = type; + + hmput(type_map, ct, spirv_type); +} + +static void write_base_types(instructions_buffer *constants_block) { + void_type = write_type_void(constants_block); + + void_function_type = write_type_function(constants_block, void_type, NULL, 0); + + complex_type ct; + ct.pointer = (uint16_t) false; + ct.storage = (uint16_t)STORAGE_CLASS_NONE; + + spirv_float_type = write_type_float(constants_block, 32); + write_base_type(constants_block, float_id, spirv_float_type); + + spirv_float2_type = convert_type_to_spirv_id(float2_id); + write_type_vector_preallocated(constants_block, spirv_float_type, 2, spirv_float2_type); + write_base_type(constants_block, float2_id, spirv_float2_type); + + spirv_float3_type = convert_type_to_spirv_id(float3_id); + write_type_vector_preallocated(constants_block, spirv_float_type, 3, spirv_float3_type); + write_base_type(constants_block, float3_id, spirv_float3_type); + + spirv_float4_type = convert_type_to_spirv_id(float4_id); + write_type_vector_preallocated(constants_block, spirv_float_type, 4, spirv_float4_type); + write_base_type(constants_block, float4_id, spirv_float4_type); + + spirv_uint_type = write_type_int(constants_block, 32, false); + write_base_type(constants_block, uint_id, spirv_uint_type); + + spirv_int_type = write_type_int(constants_block, 32, true); + write_base_type(constants_block, int_id, spirv_int_type); + + spirv_bool_type = write_type_bool(constants_block); + write_base_type(constants_block, bool_id, spirv_bool_type); + + write_base_type(constants_block, float3x3_id, write_type_matrix(constants_block, spirv_float3_type, 3)); + write_base_type(constants_block, float4x4_id, write_type_matrix(constants_block, spirv_float4_type, 4)); +} + +static void write_types(instructions_buffer *constants, function *main) { + type_id types[256]; + size_t types_size = 0; + find_referenced_types(main, types, &types_size); + + for (size_t i = 0; i < types_size; ++i) { + type *t = get_type(types[i]); + + if (!t->built_in && !has_attribute(&t->attributes, add_name("pipe"))) { + spirv_id member_types[256]; + uint16_t member_types_size = 0; + for (size_t j = 0; j < t->members.size; ++j) { + member_types[member_types_size] = convert_type_to_spirv_id(t->members.m[j].type.type); + member_types_size += 1; + assert(member_types_size < 256); + } + spirv_id struct_type = write_type_struct(constants, member_types, member_types_size); + + complex_type ct; + ct.type = types[i]; + ct.pointer = (uint16_t) false; + ct.storage = (uint16_t)STORAGE_CLASS_NONE; + hmput(type_map, ct, struct_type); + } + } + + size_t size = hmlenu(type_map); + for (size_t i = 0; i < size; ++i) { + complex_type type = type_map[i].key; + if (type.pointer && type.storage != STORAGE_CLASS_UNIFORM) { + write_type_pointer_preallocated(constants, type.storage, convert_type_to_spirv_id(type.type), type_map[i].value); + } + } +} + +static spirv_id write_constant(instructions_buffer *instructions, spirv_id type, spirv_id value_id, uint32_t value) { + uint32_t operands[] = {type.id, value_id.id, value}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_CONSTANT, operands); + return value_id; +} + +static spirv_id write_constant_int(instructions_buffer *instructions, spirv_id value_id, int32_t value) { + uint32_t uint32_value = *(uint32_t *)&value; + return write_constant(instructions, spirv_int_type, value_id, uint32_value); +} + +static spirv_id write_constant_float(instructions_buffer *instructions, spirv_id value_id, float value) { + uint32_t uint32_value = *(uint32_t *)&value; + return write_constant(instructions, spirv_float_type, value_id, uint32_value); +} + +static spirv_id write_constant_bool(instructions_buffer *instructions, spirv_id value_id, bool value) { + uint32_t uint32_value = *(uint32_t *)&value; + return write_constant(instructions, spirv_bool_type, value_id, uint32_value); +} + +static void write_vertex_output_decorations(instructions_buffer *instructions, spirv_id output_struct) { + { + uint32_t operands[] = {output_struct.id, 0, (uint32_t)DECORATION_BUILTIN, (uint32_t)BUILTIN_POSITION}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_MEMBER_DECORATE, operands); + } + + { + uint32_t operands[] = {output_struct.id, (uint32_t)DECORATION_BLOCK}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_DECORATE, operands); + } +} + +static void write_vertex_input_decorations(instructions_buffer *instructions, spirv_id *inputs, uint32_t inputs_size) { + for (uint32_t i = 0; i < inputs_size; ++i) { + uint32_t operands[] = {inputs[i].id, (uint32_t)DECORATION_LOCATION, i}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_DECORATE, operands); + } +} + +static void write_fragment_output_decorations(instructions_buffer *instructions, spirv_id output) { + uint32_t operands[] = {output.id, (uint32_t)DECORATION_LOCATION, 0}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_DECORATE, operands); +} + +static spirv_id write_op_function_preallocated(instructions_buffer *instructions, spirv_id result_type, function_control control, spirv_id function_type, + spirv_id result) { + uint32_t operands[] = {result_type.id, result.id, (uint32_t)control, function_type.id}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_FUNCTION, operands); + return result; +} + +// static spirv_id write_op_function(instructions_buffer *instructions, spirv_id result_type, function_control control, spirv_id function_type) { +// spirv_id result = allocate_index(); +// write_op_function_preallocated(instructions, result_type, control, function_type, result); +// return result; +// } + +static spirv_id write_op_label(instructions_buffer *instructions) { + spirv_id result = allocate_index(); + + uint32_t operands[] = {result.id}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_LABEL, operands); + return result; +} + +static void write_op_label_preallocated(instructions_buffer *instructions, spirv_id result) { + uint32_t operands[] = {result.id}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_LABEL, operands); +} + +static void write_op_branch(instructions_buffer *instructions, spirv_id target) { + uint32_t operands[] = {target.id}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_BRANCH, operands); +} + +static void write_op_loop_merge(instructions_buffer *instructions, spirv_id merge_block, spirv_id continue_target, loop_control control) { + uint32_t operands[] = {merge_block.id, continue_target.id, (uint32_t)control}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_LOOP_MERGE, operands); +} + +static void write_op_return(instructions_buffer *instructions) { + write_simple_instruction(instructions, SPIRV_OPCODE_RETURN); +} + +static void write_op_function_end(instructions_buffer *instructions) { + write_simple_instruction(instructions, SPIRV_OPCODE_FUNCTION_END); +} + +static struct { + int key; + spirv_id value; +} *int_constants = NULL; + +static spirv_id get_int_constant(int value) { + spirv_id index = hmget(int_constants, value); + if (index.id == 0) { + index = allocate_index(); + hmput(int_constants, value, index); + } + return index; +} + +static struct { + float key; + spirv_id value; +} *float_constants = NULL; + +static spirv_id get_float_constant(float value) { + spirv_id index = hmget(float_constants, value); + if (index.id == 0) { + index = allocate_index(); + hmput(float_constants, value, index); + } + return index; +} + +static struct { + bool key; + spirv_id value; +} *bool_constants = NULL; + +static spirv_id get_bool_constant(bool value) { + spirv_id index = hmget(bool_constants, value); + if (index.id == 0) { + index = allocate_index(); + hmput(bool_constants, value, index); + } + return index; +} + +static spirv_id write_op_access_chain(instructions_buffer *instructions, spirv_id result_type, spirv_id base, int *indices, uint16_t indices_size) { + spirv_id pointer = allocate_index(); + + operands_buffer[0] = result_type.id; + operands_buffer[1] = pointer.id; + operands_buffer[2] = base.id; + for (uint16_t i = 0; i < indices_size; ++i) { + operands_buffer[i + 3] = get_int_constant(indices[i]).id; + } + + write_instruction(instructions, 4 + indices_size, SPIRV_OPCODE_ACCESS_CHAIN, operands_buffer); + return pointer; +} + +static spirv_id write_op_load(instructions_buffer *instructions, spirv_id result_type, spirv_id pointer) { + spirv_id result = allocate_index(); + + uint32_t operands[] = {result_type.id, result.id, pointer.id}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_LOAD, operands); + return result; +} + +static void write_op_store(instructions_buffer *instructions, spirv_id pointer, spirv_id object) { + uint32_t operands[] = {pointer.id, object.id}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_STORE, operands); +} + +static spirv_id write_op_composite_construct(instructions_buffer *instructions, spirv_id type, spirv_id *constituents, uint16_t constituents_size) { + spirv_id result = allocate_index(); + + operands_buffer[0] = type.id; + operands_buffer[1] = result.id; + for (uint16_t i = 0; i < constituents_size; ++i) { + operands_buffer[i + 2] = constituents[i].id; + } + write_instruction(instructions, 3 + constituents_size, SPIRV_OPCODE_COMPOSITE_CONSTRUCT, operands_buffer); + return result; +} + +static spirv_id write_op_f_ord_less_than(instructions_buffer *instructions, spirv_id type, spirv_id operand1, spirv_id operand2) { + spirv_id result = allocate_index(); + + uint32_t operands[] = {type.id, result.id, operand1.id, operand2.id}; + + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_F_ORD_LESS_THAN, operands); + + return result; +} + +static spirv_id write_op_f_mul(instructions_buffer *instructions, spirv_id type, spirv_id operand1, spirv_id operand2) { + spirv_id result = allocate_index(); + + uint32_t operands[] = {type.id, result.id, operand1.id, operand2.id}; + + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_F_MUL, operands); + + return result; +} + +static void write_op_selection_merge(instructions_buffer *instructions, spirv_id merge_block, selection_control control) { + uint32_t operands[] = {merge_block.id, (uint32_t)control}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_SELECTION_MERGE, operands); +} + +static void write_op_branch_conditional(instructions_buffer *instructions, spirv_id condition, spirv_id pass, spirv_id fail) { + uint32_t operands[] = {condition.id, pass.id, fail.id}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_BRANCH_CONDITIONAL, operands); +} + +static spirv_id write_op_variable(instructions_buffer *instructions, spirv_id result_type, storage_class storage) { + spirv_id result = allocate_index(); + + uint32_t operands[] = {result_type.id, result.id, (uint32_t)storage}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_VARIABLE, operands); + return result; +} + +static spirv_id write_op_variable_preallocated(instructions_buffer *instructions, spirv_id result_type, spirv_id result, storage_class storage) { + uint32_t operands[] = {result_type.id, result.id, (uint32_t)storage}; + write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_VARIABLE, operands); + return result; +} + +// static spirv_id write_op_variable_with_initializer(instructions_buffer *instructions, uint32_t result_type, storage_class storage, uint32_t initializer) { +// spirv_id result = allocate_index(); +// +// uint32_t operands[] = {result_type, result.id, (uint32_t)storage, initializer}; +// write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_VARIABLE, operands); +// return result; +// } + +static struct { + uint64_t key; + spirv_id value; +} *index_map = NULL; + +static spirv_id convert_kong_index_to_spirv_id(uint64_t index) { + spirv_id id = hmget(index_map, index); + if (id.id == 0) { + id = allocate_index(); + hmput(index_map, index, id); + } + return id; +} + +static spirv_id output_var = {0}; +static spirv_id input_vars[256] = {0}; +static type_id input_types[256] = {0}; +static size_t input_vars_count = 0; + +static void write_function(instructions_buffer *instructions, function *f, spirv_id function_id, shader_stage stage, bool main, type_id input, type_id output) { + write_op_function_preallocated(instructions, void_type, FUNCTION_CONTROL_NONE, void_function_type, function_id); + write_op_label(instructions); + + debug_context context = {0}; + check(f->block != NULL, context, "Function block missing"); + + uint8_t *data = f->code.o; + size_t size = f->code.size; + + uint64_t parameter_ids[256] = {0}; + type_id parameter_types[256] = {0}; + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + for (size_t i = 0; i < f->block->block.vars.size; ++i) { + if (f->parameter_names[parameter_index] == f->block->block.vars.v[i].name) { + parameter_ids[parameter_index] = f->block->block.vars.v[i].variable_id; + parameter_types[parameter_index] = f->block->block.vars.v[i].type.type; + break; + } + } + } + + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + check(parameter_ids[parameter_index] != 0, context, "Parameter not found"); + } + + // create variable for the input parameter + spirv_id spirv_parameter_id = convert_kong_index_to_spirv_id(parameter_ids[0]); + write_op_variable_preallocated(instructions, convert_pointer_type_to_spirv_id(parameter_types[0], STORAGE_CLASS_FUNCTION), spirv_parameter_id, + STORAGE_CLASS_FUNCTION); + + // all vars have to go first + size_t index = 0; + while (index < size) { + opcode *o = (opcode *)&data[index]; + switch (o->type) { + case OPCODE_VAR: { + spirv_id result = + write_op_variable(instructions, convert_pointer_type_to_spirv_id(o->op_var.var.type.type, STORAGE_CLASS_FUNCTION), STORAGE_CLASS_FUNCTION); + hmput(index_map, o->op_var.var.index, result); + break; + } + default: + break; + } + + index += o->size; + } + + // transfer input values into the input variable + for (size_t i = 0; i < input_vars_count; ++i) { + int index = (int)i; + spirv_id loaded = write_op_load(instructions, convert_type_to_spirv_id(input_types[i]), input_vars[i]); + spirv_id pointer = + write_op_access_chain(instructions, convert_pointer_type_to_spirv_id(input_types[i], STORAGE_CLASS_FUNCTION), spirv_parameter_id, &index, 1); + write_op_store(instructions, pointer, loaded); + } + + bool ends_with_return = false; + + index = 0; + while (index < size) { + ends_with_return = false; + opcode *o = (opcode *)&data[index]; + switch (o->type) { + case OPCODE_VAR: { + break; + } + case OPCODE_LOAD_MEMBER: { + int indices[256]; + uint16_t indices_size = o->op_load_member.member_indices_size; + for (size_t i = 0; i < indices_size; ++i) { + indices[i] = (int)o->op_load_member.static_member_indices[i]; + } + + storage_class storage; + if (o->op_load_member.from.index == parameter_ids[0]) { + storage = STORAGE_CLASS_FUNCTION; + } + else { + if (o->op_load_member.from.kind == VARIABLE_GLOBAL) { + storage = STORAGE_CLASS_UNIFORM; + } + else { + storage = STORAGE_CLASS_INPUT; + } + } + spirv_id pointer = write_op_access_chain(instructions, convert_pointer_type_to_spirv_id(o->op_load_member.from.type.type, storage), + convert_kong_index_to_spirv_id(o->op_load_member.from.index), indices, indices_size); + + spirv_id value = write_op_load(instructions, convert_type_to_spirv_id(o->op_load_member.to.type.type), pointer); + hmput(index_map, o->op_load_member.to.index, value); + + break; + } + case OPCODE_LOAD_FLOAT_CONSTANT: { + spirv_id id = get_float_constant(o->op_load_float_constant.number); + hmput(index_map, o->op_load_float_constant.to.index, id); + break; + } + case OPCODE_LOAD_BOOL_CONSTANT: { + spirv_id id = get_bool_constant(o->op_load_bool_constant.boolean); + hmput(index_map, o->op_load_bool_constant.to.index, id); + break; + } + case OPCODE_CALL: { + if (o->op_call.func == add_name("sample")) { + } + else if (o->op_call.func == add_name("sample_lod")) { + } + else { + if (o->op_call.func == add_name("float2")) { + spirv_id constituents[2]; + for (int i = 0; i < o->op_call.parameters_size; ++i) { + constituents[i] = convert_kong_index_to_spirv_id(o->op_call.parameters[i].index); + } + spirv_id id = write_op_composite_construct(instructions, spirv_float2_type, constituents, o->op_call.parameters_size); + hmput(index_map, o->op_call.var.index, id); + } + else if (o->op_call.func == add_name("float3")) { + spirv_id constituents[3]; + for (int i = 0; i < o->op_call.parameters_size; ++i) { + constituents[i] = convert_kong_index_to_spirv_id(o->op_call.parameters[i].index); + } + spirv_id id = write_op_composite_construct(instructions, spirv_float3_type, constituents, o->op_call.parameters_size); + hmput(index_map, o->op_call.var.index, id); + } + else if (o->op_call.func == add_name("float4")) { + spirv_id constituents[4]; + for (int i = 0; i < o->op_call.parameters_size; ++i) { + constituents[i] = convert_kong_index_to_spirv_id(o->op_call.parameters[i].index); + } + spirv_id id = write_op_composite_construct(instructions, spirv_float4_type, constituents, o->op_call.parameters_size); + hmput(index_map, o->op_call.var.index, id); + } + else { + } + + /**offset += sprintf(&code[*offset], "\t%s _%" PRIu64 " = %s(", type_string(o->op_call.var.type.type), o->op_call.var.index, + function_string(o->op_call.func)); + if (o->op_call.parameters_size > 0) { + *offset += sprintf(&code[*offset], "_%" PRIu64, o->op_call.parameters[0].index); + for (uint8_t i = 1; i < o->op_call.parameters_size; ++i) { + *offset += sprintf(&code[*offset], ", _%" PRIu64, o->op_call.parameters[i].index); + } + }*/ + } + break; + } + case OPCODE_STORE_MEMBER: { + int indices[256]; + uint16_t indices_size = o->op_store_member.member_indices_size; + for (size_t i = 0; i < indices_size; ++i) { + check(!o->op_store_member.dynamic_member[i], context, "TODO"); + indices[i] = (int)o->op_store_member.static_member_indices[i]; + } + + type_id access_kong_type = find_access_type(indices, indices_size, o->op_store_member.to.type.type); + + spirv_id access_type = {0}; + + switch (o->op_store_member.to.kind) { + case VARIABLE_LOCAL: + access_type = convert_pointer_type_to_spirv_id(access_kong_type, STORAGE_CLASS_FUNCTION); + break; + case VARIABLE_GLOBAL: + access_type = convert_pointer_type_to_spirv_id(access_kong_type, STORAGE_CLASS_OUTPUT); + break; + } + + int spirv_indices[256]; + vector_member_indices(indices, spirv_indices, indices_size, o->op_store_member.to.type.type); + + spirv_id pointer = + write_op_access_chain(instructions, access_type, convert_kong_index_to_spirv_id(o->op_store_member.to.index), spirv_indices, indices_size); + write_op_store(instructions, pointer, convert_kong_index_to_spirv_id(o->op_store_member.from.index)); + break; + } + case OPCODE_STORE_VARIABLE: { + write_op_store(instructions, convert_kong_index_to_spirv_id(o->op_store_var.to.index), convert_kong_index_to_spirv_id(o->op_store_var.from.index)); + break; + } + case OPCODE_RETURN: { + if (stage == SHADER_STAGE_VERTEX && main) { + type *output_type = get_type(output); + + for (size_t i = 0; i < output_type->members.size; ++i) { + member m = output_type->members.m[i]; + if (m.type.type == float2_id) { + int indices = (int)i; + + spirv_id load_pointer = write_op_access_chain(instructions, convert_pointer_type_to_spirv_id(float2_id, STORAGE_CLASS_FUNCTION), + convert_kong_index_to_spirv_id(o->op_return.var.index), &indices, 1); + spirv_id value = write_op_load(instructions, spirv_float2_type, load_pointer); + + spirv_id store_pointer = + write_op_access_chain(instructions, convert_pointer_type_to_spirv_id(float2_id, STORAGE_CLASS_OUTPUT), output_var, &indices, 1); + write_op_store(instructions, store_pointer, value); + } + else if (m.type.type == float3_id) { + int indices = (int)i; + + spirv_id load_pointer = write_op_access_chain(instructions, convert_pointer_type_to_spirv_id(float3_id, STORAGE_CLASS_FUNCTION), + convert_kong_index_to_spirv_id(o->op_return.var.index), &indices, 1); + spirv_id value = write_op_load(instructions, spirv_float3_type, load_pointer); + + spirv_id store_pointer = + write_op_access_chain(instructions, convert_pointer_type_to_spirv_id(float3_id, STORAGE_CLASS_OUTPUT), output_var, &indices, 1); + write_op_store(instructions, store_pointer, value); + } + else if (m.type.type == float4_id) { + int indices = (int)i; + + spirv_id load_pointer = write_op_access_chain(instructions, convert_pointer_type_to_spirv_id(float4_id, STORAGE_CLASS_FUNCTION), + convert_kong_index_to_spirv_id(o->op_return.var.index), &indices, 1); + spirv_id value = write_op_load(instructions, spirv_float4_type, load_pointer); + + spirv_id store_pointer = + write_op_access_chain(instructions, convert_pointer_type_to_spirv_id(float4_id, STORAGE_CLASS_OUTPUT), output_var, &indices, 1); + write_op_store(instructions, store_pointer, value); + } + else { + debug_context context = {0}; + error(context, "Type unsupported for input in SPIR-V"); + } + } + write_op_return(instructions); + } + else if (stage == SHADER_STAGE_FRAGMENT && main) { + if (false /*TODO*/) { + spirv_id object = write_op_load(instructions, convert_type_to_spirv_id(o->op_return.var.type.type), + convert_kong_index_to_spirv_id(o->op_return.var.index)); + write_op_store(instructions, output_var, object); + } + else { + write_op_store(instructions, output_var, convert_kong_index_to_spirv_id(o->op_return.var.index)); + } + write_op_return(instructions); + } + ends_with_return = true; + break; + } + case OPCODE_LESS: { + spirv_id result = write_op_f_ord_less_than(instructions, spirv_bool_type, convert_kong_index_to_spirv_id(o->op_binary.left.index), + convert_kong_index_to_spirv_id(o->op_binary.right.index)); + hmput(index_map, o->op_binary.result.index, result); + break; + } + case OPCODE_MULTIPLY: { + spirv_id result = write_op_f_mul(instructions, convert_type_to_spirv_id(o->op_binary.result.type.type), + convert_kong_index_to_spirv_id(o->op_binary.left.index), convert_kong_index_to_spirv_id(o->op_binary.right.index)); + hmput(index_map, o->op_binary.result.index, result); + break; + } + case OPCODE_IF: { + write_op_selection_merge(instructions, convert_kong_index_to_spirv_id(o->op_if.end_id), SELECTION_CONTROL_NONE); + + write_op_branch_conditional(instructions, convert_kong_index_to_spirv_id(o->op_if.condition.index), + convert_kong_index_to_spirv_id(o->op_if.start_id), convert_kong_index_to_spirv_id(o->op_if.end_id)); + + break; + } + case OPCODE_WHILE_START: { + spirv_id while_start_label = convert_kong_index_to_spirv_id(o->op_while_start.start_id); + spirv_id while_continue_label = convert_kong_index_to_spirv_id(o->op_while_start.continue_id); + spirv_id while_end_label = convert_kong_index_to_spirv_id(o->op_while_start.end_id); + + write_op_branch(instructions, while_start_label); + write_op_label_preallocated(instructions, while_start_label); + + write_op_loop_merge(instructions, while_end_label, while_continue_label, LOOP_CONTROL_NONE); + + spirv_id loop_start_id = allocate_index(); + write_op_branch(instructions, loop_start_id); + write_op_label_preallocated(instructions, loop_start_id); + break; + } + case OPCODE_WHILE_CONDITION: { + spirv_id while_end_label = convert_kong_index_to_spirv_id(o->op_while.end_id); + + spirv_id pass = allocate_index(); + + write_op_branch_conditional(instructions, convert_kong_index_to_spirv_id(o->op_while.condition.index), pass, while_end_label); + + write_op_label_preallocated(instructions, pass); + break; + } + case OPCODE_WHILE_END: { + spirv_id while_start_label = convert_kong_index_to_spirv_id(o->op_while_end.start_id); + spirv_id while_continue_label = convert_kong_index_to_spirv_id(o->op_while_end.continue_id); + spirv_id while_end_label = convert_kong_index_to_spirv_id(o->op_while_end.end_id); + + write_op_branch(instructions, while_continue_label); + write_op_label_preallocated(instructions, while_continue_label); + + write_op_branch(instructions, while_start_label); + write_op_label_preallocated(instructions, while_end_label); + break; + } + case OPCODE_BLOCK_START: + case OPCODE_BLOCK_END: { + write_op_label_preallocated(instructions, convert_kong_index_to_spirv_id(o->op_block.id)); + break; + } + default: { + debug_context context = {0}; + error(context, "Opcode not implemented for SPIR-V"); + break; + } + } + + index += o->size; + } + + if (!ends_with_return) { + if (main) { + // TODO + } + else { + write_op_return(instructions); + } + } + write_op_function_end(instructions); +} + +static void write_functions(instructions_buffer *instructions, function *main, spirv_id entry_point, shader_stage stage, type_id input, type_id output) { + write_function(instructions, main, entry_point, stage, true, input, output); +} + +static void write_constants(instructions_buffer *instructions) { + size_t size = hmlenu(int_constants); + for (size_t i = 0; i < size; ++i) { + write_constant_int(instructions, int_constants[i].value, int_constants[i].key); + } + + size = hmlenu(float_constants); + for (size_t i = 0; i < size; ++i) { + write_constant_float(instructions, float_constants[i].value, float_constants[i].key); + } + + size = hmlenu(bool_constants); + for (size_t i = 0; i < size; ++i) { + write_constant_bool(instructions, bool_constants[i].value, bool_constants[i].key); + } +} + +static int global_register_indices[512]; + +static void write_globals(instructions_buffer *instructions_block, function *main) { + global_id globals[256]; + size_t globals_size = 0; + + if (main != NULL) { + find_referenced_globals(main, globals, &globals_size); + } + + for (size_t i = 0; i < globals_size; ++i) { + global *g = get_global(globals[i]); + int register_index = global_register_indices[globals[i]]; + + type *t = get_type(g->type); + type_id base_type = t->array_size > 0 ? t->base : g->type; + + if (base_type == sampler_type_id) { + //*offset += sprintf(&hlsl[*offset], "SamplerState _%" PRIu64 " : register(s%i);\n\n", g->var_index, register_index); + } + else if (base_type == tex2d_type_id) { + if (has_attribute(&g->attributes, add_name("write"))) { + //*offset += sprintf(&hlsl[*offset], "RWTexture2D _%" PRIu64 " : register(u%i);\n\n", g->var_index, register_index); + } + else { + if (t->array_size == UINT32_MAX) { + //*offset += sprintf(&hlsl[*offset], "Texture2D _%" PRIu64 "[] : register(t%i, space1);\n\n", g->var_index, register_index); + } + else { + //*offset += sprintf(&hlsl[*offset], "Texture2D _%" PRIu64 " : register(t%i);\n\n", g->var_index, register_index); + } + } + } + else if (base_type == tex2darray_type_id) { + //*offset += sprintf(&hlsl[*offset], "Texture2DArray _%" PRIu64 " : register(t%i);\n\n", g->var_index, register_index); + } + else if (base_type == texcube_type_id) { + //*offset += sprintf(&hlsl[*offset], "TextureCube _%" PRIu64 " : register(t%i);\n\n", g->var_index, register_index); + } + else if (base_type == bvh_type_id) { + //*offset += sprintf(&hlsl[*offset], "RaytracingAccelerationStructure _%" PRIu64 " : register(t%i);\n\n", g->var_index, register_index); + } + else if (base_type == float_id) { + //*offset += sprintf(&hlsl[*offset], "static const float _%" PRIu64 " = %f;\n\n", g->var_index, g->value.value.floats[0]); + } + else if (base_type == float2_id) { + //*offset += sprintf(&hlsl[*offset], "static const float2 _%" PRIu64 " = float2(%f, %f);\n\n", g->var_index, g->value.value.floats[0], + // g->value.value.floats[1]); + } + else if (base_type == float3_id) { + //*offset += sprintf(&hlsl[*offset], "static const float3 _%" PRIu64 " = float3(%f, %f, %f);\n\n", g->var_index, g->value.value.floats[0], + // g->value.value.floats[1], g->value.value.floats[2]); + } + else if (base_type == float4_id) { + //*offset += sprintf(&hlsl[*offset], "static const float4 _%" PRIu64 " = float4(%f, %f, %f, %f);\n\n", g->var_index, g->value.value.floats[0], + // g->value.value.floats[1], g->value.value.floats[2], g->value.value.floats[3]); + } + else { + /**offset += sprintf(&hlsl[*offset], "cbuffer _%" PRIu64 " : register(b%i) {\n", g->var_index, register_index); + type *t = get_type(g->type); + for (size_t i = 0; i < t->members.size; ++i) { + *offset += + sprintf(&hlsl[*offset], "\t%s _%" PRIu64 "_%s;\n", type_string(t->members.m[i].type.type), g->var_index, get_name(t->members.m[i].name)); + } + *offset += sprintf(&hlsl[*offset], "}\n\n");*/ + + type *t = get_type(g->type); + + spirv_id member_types[256]; + uint16_t member_types_size = 0; + for (size_t j = 0; j < t->members.size; ++j) { + member_types[member_types_size] = convert_type_to_spirv_id(t->members.m[j].type.type); + member_types_size += 1; + assert(member_types_size < 256); + } + spirv_id struct_type = write_type_struct(instructions_block, member_types, member_types_size); + + complex_type ct; + ct.type = g->type; + ct.pointer = (uint16_t) false; + ct.storage = (uint16_t)STORAGE_CLASS_NONE; + hmput(type_map, ct, struct_type); + + spirv_id struct_pointer_type = write_type_pointer(instructions_block, STORAGE_CLASS_UNIFORM, struct_type); + + ct.type = g->type; + ct.pointer = (uint16_t) true; + ct.storage = (uint16_t)STORAGE_CLASS_UNIFORM; + hmput(type_map, ct, struct_pointer_type); + + spirv_id spirv_var_id = convert_kong_index_to_spirv_id(g->var_index); + write_op_variable_preallocated(instructions_block, struct_pointer_type, spirv_var_id, STORAGE_CLASS_UNIFORM); + } + } +} + +static void init_index_map(void) { + spirv_id default_id = {0}; + hmdefault(index_map, default_id); + size_t size = hmlenu(index_map); + for (size_t i = 0; i < size; ++i) { + hmdel(index_map, index_map[i].key); + } +} + +static void init_type_map(void) { + spirv_id default_id = {0}; + hmdefault(type_map, default_id); + size_t size = hmlenu(type_map); + for (size_t i = 0; i < size; ++i) { + hmdel(type_map, type_map[i].key); + } +} + +static void init_int_constants(void) { + spirv_id default_id = {0}; + hmdefault(int_constants, default_id); + size_t size = hmlenu(int_constants); + for (size_t i = 0; i < size; ++i) { + hmdel(int_constants, int_constants[i].key); + } +} + +static void init_float_constants(void) { + spirv_id default_id = {0}; + hmdefault(float_constants, default_id); + size_t size = hmlenu(float_constants); + for (size_t i = 0; i < size; ++i) { + hmdel(float_constants, float_constants[i].key); + } +} + +void init_maps(void) { + init_index_map(); + init_type_map(); + init_int_constants(); + init_float_constants(); +} + +static void spirv_export_vertex(char *directory, function *main) { + init_maps(); + + instructions_buffer instructions = {0}; + instructions.instructions = (uint32_t *)calloc(1024 * 1024, 1); + + instructions_buffer header = {0}; + header.instructions = (uint32_t *)calloc(1024 * 1024, 1); + + instructions_buffer decorations = {0}; + decorations.instructions = (uint32_t *)calloc(1024 * 1024, 1); + + instructions_buffer constants = {0}; + constants.instructions = (uint32_t *)calloc(1024 * 1024, 1); + + assert(main->parameters_size > 0); + type_id vertex_input = main->parameter_types[0].type; + type_id vertex_output = main->return_type.type; + + debug_context context = {0}; + check(vertex_input != NO_TYPE, context, "vertex input missing"); + check(vertex_output != NO_TYPE, context, "vertex output missing"); + + write_capabilities(&decorations); + write_op_ext_inst_import(&decorations, "GLSL.std.450"); + write_op_memory_model(&decorations, ADDRESSING_MODEL_LOGICAL, MEMORY_MODEL_GLSL450); + + type *input = get_type(vertex_input); + + spirv_id entry_point = allocate_index(); + output_var = allocate_index(); + + input_vars_count = input->members.size; + for (size_t input_var_index = 0; input_var_index < input_vars_count; ++input_var_index) { + input_vars[input_var_index] = allocate_index(); + } + spirv_id interfaces[256]; + interfaces[0] = output_var; + for (size_t input_var_index = 0; input_var_index < input_vars_count; ++input_var_index) { + interfaces[input_var_index + 1] = input_vars[input_var_index]; + } + write_op_entry_point(&decorations, EXECUTION_MODEL_VERTEX, entry_point, "main", interfaces, (uint16_t)(input_vars_count + 1)); + + write_vertex_input_decorations(&decorations, input_vars, (uint32_t)input_vars_count); + + write_base_types(&constants); + + write_globals(&constants, main); + + spirv_id types[] = {spirv_float4_type}; + spirv_id output_struct = write_type_struct(&constants, types, 1); + write_vertex_output_decorations(&decorations, output_struct); + + output_struct_pointer_type = write_type_pointer(&constants, STORAGE_CLASS_OUTPUT, output_struct); + write_op_variable_preallocated(&instructions, output_struct_pointer_type, output_var, STORAGE_CLASS_OUTPUT); + + for (size_t i = 0; i < input->members.size; ++i) { + member m = input->members.m[i]; + input_types[i] = m.type.type; + + if (m.type.type == float2_id) { + write_op_variable_preallocated(&instructions, convert_pointer_type_to_spirv_id(float2_id, STORAGE_CLASS_INPUT), input_vars[i], STORAGE_CLASS_INPUT); + } + else if (m.type.type == float3_id) { + write_op_variable_preallocated(&instructions, convert_pointer_type_to_spirv_id(float3_id, STORAGE_CLASS_INPUT), input_vars[i], STORAGE_CLASS_INPUT); + } + else if (m.type.type == float4_id) { + write_op_variable_preallocated(&instructions, convert_pointer_type_to_spirv_id(float4_id, STORAGE_CLASS_INPUT), input_vars[i], STORAGE_CLASS_INPUT); + } + else { + debug_context context = {0}; + error(context, "Type unsupported for input in SPIR-V"); + } + } + + write_functions(&instructions, main, entry_point, SHADER_STAGE_VERTEX, vertex_input, vertex_output); + + write_types(&constants, main); + + // header + write_magic_number(&header); + write_version_number(&header); + write_generator_magic_number(&header); + write_bound(&header); + write_instruction_schema(&header); + + write_constants(&constants); + + char *name = get_name(main->name); + + char filename[512]; + // sprintf(filename, "kong_%s", name); //// + sprintf(filename, "%s", name); + + char var_name[256]; + sprintf(var_name, "%s_code", name); + + write_bytecode(directory, filename, var_name, &header, &decorations, &constants, &instructions); +} + +static void spirv_export_fragment(char *directory, function *main) { + init_maps(); + + instructions_buffer instructions = {0}; + instructions.instructions = (uint32_t *)calloc(1024 * 1024, 1); + + instructions_buffer header = {0}; + header.instructions = (uint32_t *)calloc(1024 * 1024, 1); + + instructions_buffer decorations = {0}; + decorations.instructions = (uint32_t *)calloc(1024 * 1024, 1); + + instructions_buffer constants = {0}; + constants.instructions = (uint32_t *)calloc(1024 * 1024, 1); + + assert(main->parameters_size > 0); + type_id pixel_input = main->parameter_types[0].type; + + debug_context context = {0}; + check(pixel_input != NO_TYPE, context, "fragment input missing"); + + write_capabilities(&decorations); + write_op_ext_inst_import(&decorations, "GLSL.std.450"); + write_op_memory_model(&decorations, ADDRESSING_MODEL_LOGICAL, MEMORY_MODEL_GLSL450); + spirv_id entry_point = allocate_index(); + output_var = allocate_index(); + // input_var = allocate_index(); + spirv_id interfaces[] = {output_var /*, input_var*/}; + write_op_entry_point(&decorations, EXECUTION_MODEL_FRAGMENT, entry_point, "main", interfaces, sizeof(interfaces) / 4); + write_op_execution_mode(&decorations, entry_point, EXECUTION_MODE_ORIGIN_UPPER_LEFT); + + write_fragment_output_decorations(&decorations, output_var); + + /*uint32_t output_struct = allocate_index(); + write_vertex_output_decorations(&decorations, output_struct); + + uint32_t inputs[256]; + inputs[0] = allocate_index(); + write_vertex_input_decorations(&decorations, inputs, 1);*/ + + write_base_types(&constants); + + write_op_variable_preallocated(&instructions, convert_pointer_type_to_spirv_id(float4_id, STORAGE_CLASS_OUTPUT), output_var, STORAGE_CLASS_OUTPUT); + + write_functions(&instructions, main, entry_point, SHADER_STAGE_FRAGMENT, pixel_input, NO_TYPE); + + write_types(&constants, main); + + // header + write_magic_number(&header); + write_version_number(&header); + write_generator_magic_number(&header); + write_bound(&header); + write_instruction_schema(&header); + + write_constants(&constants); + + char *name = get_name(main->name); + + char filename[512]; + // sprintf(filename, "kong_%s", name); //// + sprintf(filename, "%s", name); + + char var_name[256]; + sprintf(var_name, "%s_code", name); + + write_bytecode(directory, filename, var_name, &header, &decorations, &constants, &instructions); +} + +void spirv_export(char *directory) { + int register_index = 0; + + memset(global_register_indices, 0, sizeof(global_register_indices)); + + for (global_id i = 0; get_global(i) != NULL && get_global(i)->type != NO_TYPE; ++i) { + global *g = get_global(i); + + type *t = get_type(g->type); + type_id base_type = t->array_size > 0 ? t->base : g->type; + + if (base_type == sampler_type_id) { + global_register_indices[i] = register_index; + register_index += 1; + } + else if (base_type == tex2d_type_id) { + if (t->array_size == UINT32_MAX) { + global_register_indices[i] = 0; + } + else if (has_attribute(&g->attributes, add_name("write"))) { + global_register_indices[i] = register_index; + register_index += 1; + } + else { + global_register_indices[i] = register_index; + register_index += 1; + } + } + else if (base_type == texcube_type_id || base_type == tex2darray_type_id || base_type == bvh_type_id) { + global_register_indices[i] = register_index; + register_index += 1; + } + else if (get_type(g->type)->built_in) { + } + else { + global_register_indices[i] = register_index; + register_index += 1; + } + } + + function *vertex_shaders[256]; + size_t vertex_shaders_size = 0; + + function *fragment_shaders[256]; + size_t fragment_shaders_size = 0; + + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *t = get_type(i); + if (!t->built_in && has_attribute(&t->attributes, add_name("pipe"))) { + name_id vertex_shader_name = NO_NAME; + name_id fragment_shader_name = NO_NAME; + + for (size_t j = 0; j < t->members.size; ++j) { + if (t->members.m[j].name == add_name("vertex")) { + vertex_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("fragment")) { + fragment_shader_name = t->members.m[j].value.identifier; + } + } + + debug_context context = {0}; + check(vertex_shader_name != NO_NAME, context, "vertex shader missing"); + check(fragment_shader_name != NO_NAME, context, "fragment shader missing"); + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (f->name == vertex_shader_name) { + vertex_shaders[vertex_shaders_size] = f; + vertex_shaders_size += 1; + } + else if (f->name == fragment_shader_name) { + fragment_shaders[fragment_shaders_size] = f; + fragment_shaders_size += 1; + } + } + } + } + + for (size_t i = 0; i < vertex_shaders_size; ++i) { + input_vars_count = 0; + spirv_export_vertex(directory, vertex_shaders[i]); + } + + for (size_t i = 0; i < fragment_shaders_size; ++i) { + input_vars_count = 0; + spirv_export_fragment(directory, fragment_shaders[i]); + } +} diff --git a/base/sources/libs/kong/sources/backends/spirv.h b/base/sources/libs/kong/sources/backends/spirv.h new file mode 100644 index 00000000..27b854dd --- /dev/null +++ b/base/sources/libs/kong/sources/backends/spirv.h @@ -0,0 +1,3 @@ +#pragma once + +void spirv_export(char *directory); diff --git a/base/sources/libs/kong/sources/backends/util.c b/base/sources/libs/kong/sources/backends/util.c new file mode 100644 index 00000000..6adfac9e --- /dev/null +++ b/base/sources/libs/kong/sources/backends/util.c @@ -0,0 +1,74 @@ +#include "util.h" + +#include "../array.h" +#include "../errors.h" + +#include + +void indent(char *code, size_t *offset, int indentation) { + indentation = indentation < 15 ? indentation : 15; + char str[16]; + memset(str, '\t', sizeof(str)); + str[indentation] = 0; + *offset += sprintf(&code[*offset], "%s", str); +} + +uint32_t base_type_size(type_id type) { + if (type == float_id) { + return 4; + } + if (type == float2_id) { + return 4 * 2; + } + if (type == float3_id) { + return 4 * 3; + } + if (type == float4_id) { + return 4 * 4; + } + if (type == float4x4_id) { + return 4 * 4 * 4; + } + if (type == float3x3_id) { + return 3 * 4 * 4; + } + + if (type == uint_id) { + return 4; + } + if (type == uint2_id) { + return 4 * 2; + } + if (type == uint3_id) { + return 4 * 3; + } + if (type == uint4_id) { + return 4 * 4; + } + + if (type == int_id) { + return 4; + } + if (type == int2_id) { + return 4 * 2; + } + if (type == int3_id) { + return 4 * 3; + } + if (type == int4_id) { + return 4 * 4; + } + + debug_context context = {0}; + error(context, "Unknown type %s for structure", get_name(get_type(type)->name)); + return 1; +} + +uint32_t struct_size(type_id id) { + uint32_t size = 0; + type *t = get_type(id); + for (size_t member_index = 0; member_index < t->members.size; ++member_index) { + size += base_type_size(t->members.m[member_index].type.type); + } + return size; +} diff --git a/base/sources/libs/kong/sources/backends/util.h b/base/sources/libs/kong/sources/backends/util.h new file mode 100644 index 00000000..dd508e43 --- /dev/null +++ b/base/sources/libs/kong/sources/backends/util.h @@ -0,0 +1,14 @@ +#ifndef KONG_BACKENDS_UTIL_HEADER +#define KONG_BACKENDS_UTIL_HEADER + +#include "../types.h" + +#include + +void indent(char *code, size_t *offset, int indentation); + +uint32_t base_type_size(type_id type); + +uint32_t struct_size(type_id id); + +#endif diff --git a/base/sources/libs/kong/sources/backends/wgsl.c b/base/sources/libs/kong/sources/backends/wgsl.c new file mode 100644 index 00000000..7eae68bb --- /dev/null +++ b/base/sources/libs/kong/sources/backends/wgsl.c @@ -0,0 +1,671 @@ +#include "wgsl.h" + +#include "../compiler.h" +#include "../errors.h" +#include "../functions.h" +#include "../parser.h" +#include "../shader_stage.h" +#include "../types.h" +#include "cstyle.h" +// #include "d3d11.h" +#include "util.h" + +#include +#include +#include +#include +#include +#include + +static char *type_string(type_id type) { + if (type == float_id) { + return "f32"; + } + if (type == float2_id) { + return "vec2"; + } + if (type == float3_id) { + return "vec3"; + } + if (type == float4_id) { + return "vec4"; + } + if (type == float4x4_id) { + return "mat4x4"; + } + return get_name(get_type(type)->name); +} + +// static char *function_string(name_id func) { +// return get_name(func); +// } + +static void write_code(char *wgsl, char *directory, const char *filename) { + char full_filename[512]; + + { + 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 = %zu;\n\n", length); + + fprintf(file, "/*\n%s*/\n", wgsl); + + fclose(file); + } +} + +static type_id vertex_inputs[256]; +static size_t vertex_inputs_size = 0; +static type_id fragment_inputs[256]; +static size_t fragment_inputs_size = 0; + +static bool is_vertex_input(type_id t) { + for (size_t i = 0; i < vertex_inputs_size; ++i) { + if (t == vertex_inputs[i]) { + return true; + } + } + return false; +} + +static bool is_fragment_input(type_id t) { + for (size_t i = 0; i < fragment_inputs_size; ++i) { + if (t == fragment_inputs[i]) { + return true; + } + } + return false; +} + +static void write_types(char *wgsl, size_t *offset) { + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *t = get_type(i); + + if (!t->built_in && !has_attribute(&t->attributes, add_name("pipe"))) { + if (t->name == NO_NAME) { + char name[256]; + + bool found = false; + for (global_id j = 0; get_global(j)->type != NO_TYPE; ++j) { + global *g = get_global(j); + if (g->type == i) { + sprintf(name, "_%" PRIu64, g->var_index); + found = true; + break; + } + } + + if (!found) { + strcpy(name, "Unknown"); + } + + *offset += sprintf(&wgsl[*offset], "struct %s_type {\n", name); + } + else { + *offset += sprintf(&wgsl[*offset], "struct %s {\n", get_name(t->name)); + } + + if (is_vertex_input(i)) { + for (size_t j = 0; j < t->members.size; ++j) { + *offset += sprintf(&wgsl[*offset], "\t@location(%zu) %s: %s,\n", j, get_name(t->members.m[j].name), type_string(t->members.m[j].type.type)); + } + } + else if (is_fragment_input(i)) { + for (size_t j = 0; j < t->members.size; ++j) { + if (j == 0) { + *offset += + sprintf(&wgsl[*offset], "\t@builtin(position) %s: %s,\n", get_name(t->members.m[j].name), type_string(t->members.m[j].type.type)); + } + else { + *offset += sprintf(&wgsl[*offset], "\t@location(%zu) %s: %s,\n", j - 1, get_name(t->members.m[j].name), + type_string(t->members.m[j].type.type)); + } + } + } + else { + for (size_t j = 0; j < t->members.size; ++j) { + *offset += sprintf(&wgsl[*offset], "\t%s: %s,\n", get_name(t->members.m[j].name), type_string(t->members.m[j].type.type)); + } + } + *offset += sprintf(&wgsl[*offset], "};\n\n"); + } + } +} + +static int global_register_indices[512]; + +static void write_globals(char *wgsl, size_t *offset) { + for (global_id i = 0; get_global(i) != NULL && get_global(i)->type != NO_TYPE; ++i) { + global *g = get_global(i); + int register_index = global_register_indices[i]; + + if (g->type == sampler_type_id) { + *offset += sprintf(&wgsl[*offset], "@group(0) @binding(%i) var _%" PRIu64 ": sampler;\n\n", register_index, g->var_index); + } + else if (g->type == tex2d_type_id) { + *offset += sprintf(&wgsl[*offset], "@group(0) @binding(%i) var _%" PRIu64 ": texture_2d;\n\n", register_index, g->var_index); + } + else if (g->type == texcube_type_id) { + *offset += sprintf(&wgsl[*offset], "@group(0) @binding(%i) var _%" PRIu64 ": texture_cube;\n\n", register_index, g->var_index); + } + else if (g->type == float_id) { + } + else if (g->type == uint_id) { + } + else { + type *t = get_type(g->type); + char type_name[256]; + if (t->name != NO_NAME) { + strcpy(type_name, get_name(t->name)); + } + else { + sprintf(type_name, "_%" PRIu64 "_type", g->var_index); + } + *offset += sprintf(&wgsl[*offset], "@group(0) @binding(%i) var _%" PRIu64 ": %s;\n\n", register_index, g->var_index, type_name); + } + } +} + +static function_id vertex_functions[256]; +static size_t vertex_functions_size = 0; +static function_id fragment_functions[256]; +static size_t fragment_functions_size = 0; + +static bool is_vertex_function(function_id f) { + for (size_t i = 0; i < vertex_functions_size; ++i) { + if (f == vertex_functions[i]) { + return true; + } + } + return false; +} + +static bool is_fragment_function(function_id f) { + for (size_t i = 0; i < fragment_functions_size; ++i) { + if (f == fragment_functions[i]) { + return true; + } + } + return false; +} + +static void write_functions(char *code, size_t *offset) { + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + + if (f->block == NULL) { + continue; + } + + uint8_t *data = f->code.o; + size_t size = f->code.size; + + uint64_t parameter_ids[256] = {0}; + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + for (size_t i = 0; i < f->block->block.vars.size; ++i) { + if (f->parameter_names[parameter_index] == f->block->block.vars.v[i].name) { + parameter_ids[parameter_index] = f->block->block.vars.v[i].variable_id; + break; + } + } + } + + debug_context context = {0}; + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + check(parameter_ids[parameter_index] != 0, context, "Parameter not found"); + } + + if (is_vertex_function(i)) { + *offset += sprintf(&code[*offset], "@vertex fn %s(", get_name(f->name)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&code[*offset], "_%" PRIu64 ": %s", parameter_ids[parameter_index], type_string(f->parameter_types[parameter_index].type)); + } + else { + *offset += + sprintf(&code[*offset], ", _%" PRIu64 ": %s", parameter_ids[parameter_index], type_string(f->parameter_types[parameter_index].type)); + } + } + *offset += sprintf(&code[*offset], ") -> %s {\n", type_string(f->return_type.type)); + } + else if (is_fragment_function(i)) { + if (get_type(f->return_type.type)->array_size > 0) { + *offset += sprintf(&code[*offset], "struct _kong_colors_out {\n"); + for (uint32_t j = 0; j < get_type(f->return_type.type)->array_size; ++j) { + *offset += sprintf(&code[*offset], "\t%s _%i : SV_Target%i;\n", type_string(f->return_type.type), j, j); + } + *offset += sprintf(&code[*offset], "};\n\n"); + + *offset += sprintf(&code[*offset], "_kong_colors_out main("); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&code[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += + sprintf(&code[*offset], ", %s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + *offset += sprintf(&code[*offset], ") {\n"); + } + else { + *offset += sprintf(&code[*offset], "@fragment fn %s(", get_name(f->name)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += + sprintf(&code[*offset], "_%" PRIu64 ": %s", parameter_ids[parameter_index], type_string(f->parameter_types[parameter_index].type)); + } + else { + *offset += sprintf(&code[*offset], ", _%" PRIu64 ": %s", parameter_ids[parameter_index], + type_string(f->parameter_types[parameter_index].type)); + } + } + *offset += sprintf(&code[*offset], ") -> @location(0) %s {\n", type_string(f->return_type.type)); + } + } + + else { + *offset += sprintf(&code[*offset], "%s %s(", type_string(f->return_type.type), get_name(f->name)); + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (parameter_index == 0) { + *offset += sprintf(&code[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + else { + *offset += sprintf(&code[*offset], "%s _%" PRIu64, type_string(f->parameter_types[parameter_index].type), parameter_ids[parameter_index]); + } + } + *offset += sprintf(&code[*offset], ") {\n"); + } + + int indentation = 1; + + size_t index = 0; + while (index < size) { + opcode *o = (opcode *)&data[index]; + switch (o->type) { + case OPCODE_VAR: + indent(code, offset, indentation); + if (get_type(o->op_var.var.type.type)->array_size > 0) { + *offset += sprintf(&code[*offset], "%s _%" PRIu64 "[%i];\n", type_string(o->op_var.var.type.type), o->op_var.var.index, + get_type(o->op_var.var.type.type)->array_size); + } + else { + *offset += sprintf(&code[*offset], "var _%" PRIu64 ": %s;\n", o->op_var.var.index, type_string(o->op_var.var.type.type)); + } + break; + case OPCODE_LOAD_MEMBER: { + uint64_t global_var_index = 0; + for (global_id j = 0; get_global(j) != NULL && get_global(j)->type != NO_TYPE; ++j) { + global *g = get_global(j); + if (o->op_load_member.from.index == g->var_index) { + global_var_index = g->var_index; + break; + } + } + + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "var _%" PRIu64 ": %s = _%" PRIu64, o->op_load_member.to.index, type_string(o->op_load_member.to.type.type), + o->op_load_member.from.index); + type *s = get_type(o->op_load_member.member_parent_type); + for (size_t i = 0; i < o->op_load_member.member_indices_size; ++i) { + *offset += sprintf(&code[*offset], ".%s", get_name(s->members.m[o->op_load_member.static_member_indices[i]].name)); + s = get_type(s->members.m[o->op_load_member.static_member_indices[i]].type.type); + } + *offset += sprintf(&code[*offset], ";\n"); + break; + } + case OPCODE_STORE_MEMBER: { + type *s = get_type(o->op_store_member.to.type.type); + + if (o->op_store_member.member_indices_size > 1) { + type_id last_type = NO_TYPE; + type_id last_last_type = NO_TYPE; + char *last_member_name = NULL; + for (size_t i = 0; i < o->op_store_member.member_indices_size; ++i) { + if (i == o->op_store_member.member_indices_size - 1) { + if (!o->op_store_member.dynamic_member[i]) { + last_member_name = get_name(s->members.m[o->op_store_member.static_member_indices[i]].name); + } + } + + if (!o->op_store_member.dynamic_member[i]) { + type_id t = s->members.m[o->op_store_member.static_member_indices[i]].type.type; + s = get_type(t); + + if (i == o->op_store_member.member_indices_size - 2) { + last_last_type = t; + } + else if (i == o->op_store_member.member_indices_size - 1) { + last_type = t; + } + } + } + + debug_context context = {0}; + check(last_last_type != NO_TYPE, context, "last_last_type not found"); + check(last_type != NO_TYPE, context, "last_type not found"); + check(last_member_name != NULL, context, "last_member_name not found"); + + if ((last_last_type == float2_id || last_last_type == float3_id || last_last_type == float4_id) && + (last_type == float2_id || last_type == float3_id || last_type == float4_id)) { + { + int count = 1; + if (last_type == float2_id) { + count = 2; + } + else if (last_type == float3_id) { + count = 3; + } + else if (last_type == float4_id) { + count = 4; + } + + for (int element = 0; element < count; ++element) { + *offset += sprintf(&code[*offset], "\t_%" PRIu64, o->op_store_member.to.index); + + s = get_type(o->op_store_member.to.type.type); + + for (size_t i = 0; i < o->op_store_member.member_indices_size; ++i) { + bool is_array = s->array_size > 0 || o->op_store_member.to.type.type == tex2d_type_id; + + if (is_array) { + if (o->op_store_member.dynamic_member[i]) { + *offset += sprintf(&code[*offset], "[_%" PRIu64 "]", o->op_store_member.dynamic_member_indices[i].index); + } + else { + *offset += sprintf(&code[*offset], "[%i]", o->op_store_member.static_member_indices[i]); + } + is_array = false; + + s = get_type(s->base); + } + else { + debug_context context = {0}; + check(!o->op_store_member.dynamic_member[i], context, "Unexpected dynamic member"); + check(o->op_store_member.static_member_indices[i] < s->members.size, context, "Member index out of bounds"); + + if (i == o->op_store_member.member_indices_size - 1) { + *offset += sprintf(&code[*offset], ".%c", last_member_name[element]); + } + else { + *offset += sprintf(&code[*offset], ".%s", get_name(s->members.m[o->op_store_member.static_member_indices[i]].name)); + } + + s = get_type(s->members.m[o->op_store_member.static_member_indices[i]].type.type); + } + } + *offset += sprintf(&code[*offset], " = _%" PRIu64 ".%c;\n", o->op_store_member.from.index, last_member_name[element]); + } + } + + break; + } + } + + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "_%" PRIu64, o->op_store_member.to.index); + + s = get_type(o->op_store_member.to.type.type); + + for (size_t i = 0; i < o->op_store_member.member_indices_size; ++i) { + bool is_array = s->array_size > 0 || o->op_store_member.to.type.type == tex2d_type_id; + + if (is_array) { + if (o->op_store_member.dynamic_member[i]) { + *offset += sprintf(&code[*offset], "[_%" PRIu64 "]", o->op_store_member.dynamic_member_indices[i].index); + } + else { + *offset += sprintf(&code[*offset], "[%i]", o->op_store_member.static_member_indices[i]); + } + is_array = false; + + s = get_type(s->base); + } + else { + debug_context context = {0}; + check(!o->op_store_member.dynamic_member[i], context, "Unexpected dynamic member"); + check(o->op_store_member.static_member_indices[i] < s->members.size, context, "Member index out of bounds"); + + *offset += sprintf(&code[*offset], ".%s", get_name(s->members.m[o->op_store_member.static_member_indices[i]].name)); + + s = get_type(s->members.m[o->op_store_member.static_member_indices[i]].type.type); + } + } + + *offset += sprintf(&code[*offset], " = _%" PRIu64 ";\n", o->op_store_member.from.index); + + break; + } + case OPCODE_RETURN: { + if (o->size > offsetof(opcode, op_return)) { + if (is_fragment_function(i) && get_type(f->return_type.type)->array_size > 0) { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "{\n"); + indent(code, offset, indentation + 1); + *offset += sprintf(&code[*offset], "_kong_colors_out _kong_colors;\n"); + for (uint32_t j = 0; j < get_type(f->return_type.type)->array_size; ++j) { + indent(code, offset, indentation + 1); + *offset += sprintf(&code[*offset], "_kong_colors._%i = _%" PRIu64 "[%i];\n", j, o->op_return.var.index, j); + } + indent(code, offset, indentation + 1); + *offset += sprintf(&code[*offset], "return _kong_colors;\n"); + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "}\n"); + } + else { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "return _%" PRIu64 ";\n", o->op_return.var.index); + } + } + else { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "return;\n"); + } + break; + } + case OPCODE_MULTIPLY: { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "var _%" PRIu64 ": %s = _%" PRIu64 " * _%" PRIu64 ";\n", o->op_binary.result.index, + type_string(o->op_binary.result.type.type), o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_DIVIDE: { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "var _%" PRIu64 ": %s = _%" PRIu64 " / _%" PRIu64 ";\n", o->op_binary.result.index, + type_string(o->op_binary.result.type.type), o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_ADD: { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "var _%" PRIu64 ": %s = _%" PRIu64 " + _%" PRIu64 ";\n", o->op_binary.result.index, + type_string(o->op_binary.result.type.type), o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_SUB: { + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "var _%" PRIu64 ": %s = _%" PRIu64 " - _%" PRIu64 ";\n", o->op_binary.result.index, + type_string(o->op_binary.result.type.type), o->op_binary.left.index, o->op_binary.right.index); + break; + } + case OPCODE_LOAD_FLOAT_CONSTANT: + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "var _%" PRIu64 ": %s = %f;\n", o->op_load_float_constant.to.index, + type_string(o->op_load_float_constant.to.type.type), o->op_load_float_constant.number); + break; + case OPCODE_LOAD_BOOL_CONSTANT: + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "var _%" PRIu64 ": %s = %s;\n", o->op_load_bool_constant.to.index, + type_string(o->op_load_bool_constant.to.type.type), o->op_load_bool_constant.boolean ? "true" : "false"); + break; + case OPCODE_CALL: { + debug_context context = {0}; + if (o->op_call.func == add_name("sample")) { + check(o->op_call.parameters_size == 3, context, "sample requires three arguments"); + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "var _%" PRIu64 ": %s = textureSample(_%" PRIu64 ", _%" PRIu64 ", _%" PRIu64 ");\n", + o->op_call.var.index, type_string(o->op_call.var.type.type), o->op_call.parameters[0].index, + o->op_call.parameters[1].index, o->op_call.parameters[2].index); + } + else if (o->op_call.func == add_name("sample_lod")) { + check(o->op_call.parameters_size == 4, context, "sample_lod requires four arguments"); + indent(code, offset, indentation); + *offset += sprintf(&code[*offset], "var _%" PRIu64 ": %s = textureSample(_%" PRIu64 ",_%" PRIu64 ", _%" PRIu64 ", _%" PRIu64 ");\n", + o->op_call.var.index, type_string(o->op_call.var.type.type), o->op_call.parameters[0].index, + o->op_call.parameters[1].index, o->op_call.parameters[2].index, o->op_call.parameters[3].index); + } + else { + const char *function_name = get_name(o->op_call.func); + if (o->op_call.func == add_name("float2")) { + function_name = "vec2"; + } + else if (o->op_call.func == add_name("float3")) { + function_name = "vec3"; + } + else if (o->op_call.func == add_name("float4")) { + function_name = "vec4"; + } + + indent(code, offset, indentation); + *offset += + sprintf(&code[*offset], "var _%" PRIu64 ": %s = %s(", o->op_call.var.index, type_string(o->op_call.var.type.type), function_name); + if (o->op_call.parameters_size > 0) { + *offset += sprintf(&code[*offset], "_%" PRIu64, o->op_call.parameters[0].index); + for (uint8_t i = 1; i < o->op_call.parameters_size; ++i) { + *offset += sprintf(&code[*offset], ", _%" PRIu64, o->op_call.parameters[i].index); + } + } + *offset += sprintf(&code[*offset], ");\n"); + } + break; + } + default: + cstyle_write_opcode(code, offset, o, type_string, &indentation); + break; + } + + index += o->size; + } + + *offset += sprintf(&code[*offset], "}\n\n"); + } +} + +static void wgsl_export_everything(char *directory) { + char *wgsl = (char *)calloc(1024 * 1024, 1); + debug_context context = {0}; + check(wgsl != NULL, context, "Could not allocate the wgsl string"); + size_t offset = 0; + + write_types(wgsl, &offset); + + write_globals(wgsl, &offset); + + write_functions(wgsl, &offset); + + write_code(wgsl, directory, "wgsl"); +} + +void wgsl_export(char *directory) { + int binding_index = 0; + + memset(global_register_indices, 0, sizeof(global_register_indices)); + + for (global_id i = 0; get_global(i) != NULL && get_global(i)->type != NO_TYPE; ++i) { + global *g = get_global(i); + if (g->type == sampler_type_id) { + global_register_indices[i] = binding_index; + binding_index += 1; + } + else if (g->type == tex2d_type_id || g->type == texcube_type_id) { + global_register_indices[i] = binding_index; + binding_index += 1; + } + else if (g->type == float_id) { + } + else { + global_register_indices[i] = binding_index; + binding_index += 1; + } + } + + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *t = get_type(i); + if (!t->built_in && has_attribute(&t->attributes, add_name("pipe"))) { + name_id vertex_shader_name = NO_NAME; + name_id fragment_shader_name = NO_NAME; + + for (size_t j = 0; j < t->members.size; ++j) { + if (t->members.m[j].name == add_name("vertex")) { + vertex_shader_name = t->members.m[j].value.identifier; + } + else if (t->members.m[j].name == add_name("fragment")) { + fragment_shader_name = t->members.m[j].value.identifier; + } + } + + debug_context context = {0}; + check(vertex_shader_name != NO_NAME, context, "vertex shader not found"); + check(fragment_shader_name != NO_NAME, context, "fragment shader not found"); + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (f->name == vertex_shader_name) { + vertex_functions[vertex_functions_size] = i; + vertex_functions_size += 1; + + assert(f->parameters_size > 0); + vertex_inputs[vertex_inputs_size] = f->parameter_types[0].type; + vertex_inputs_size += 1; + } + else if (f->name == fragment_shader_name) { + fragment_functions[fragment_functions_size] = i; + fragment_functions_size += 1; + + assert(f->parameters_size > 0); + fragment_inputs[fragment_inputs_size] = f->parameter_types[0].type; + fragment_inputs_size += 1; + } + } + } + } + + wgsl_export_everything(directory); +} diff --git a/base/sources/libs/kong/sources/backends/wgsl.h b/base/sources/libs/kong/sources/backends/wgsl.h new file mode 100644 index 00000000..a2f4722d --- /dev/null +++ b/base/sources/libs/kong/sources/backends/wgsl.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void wgsl_export(char *directory); diff --git a/base/sources/libs/kong/sources/compiler.c b/base/sources/libs/kong/sources/compiler.c new file mode 100644 index 00000000..f2e4eee2 --- /dev/null +++ b/base/sources/libs/kong/sources/compiler.c @@ -0,0 +1,936 @@ +#include "compiler.h" + +#include "errors.h" +#include "parser.h" + +#include +#include +#include + +typedef struct allocated_global { + global *g; + uint64_t variable_id; +} allocated_global; + +static allocated_global allocated_globals[1024]; +static size_t allocated_globals_size = 0; + +allocated_global find_allocated_global(name_id name) { + for (size_t i = 0; i < allocated_globals_size; ++i) { + if (name == allocated_globals[i].g->name) { + return allocated_globals[i]; + } + } + + allocated_global a; + a.g = NULL; + a.variable_id = 0; + return a; +} + +variable find_local_var(block *b, name_id name) { + if (b == NULL) { + variable var; + var.index = 0; + init_type_ref(&var.type, NO_NAME); + return var; + } + + for (size_t i = 0; i < b->vars.size; ++i) { + if (b->vars.v[i].name == name) { + debug_context context = {0}; + check(b->vars.v[i].type.type != NO_TYPE, context, "Local variable does not have a type"); + variable var; + var.index = b->vars.v[i].variable_id; + var.type = b->vars.v[i].type; + var.kind = VARIABLE_LOCAL; + return var; + } + } + + return find_local_var(b->parent, name); +} + +variable find_variable(block *parent, name_id name) { + variable local_var = find_local_var(parent, name); + if (local_var.index == 0) { + allocated_global global = find_allocated_global(name); + if (global.g->type != NO_TYPE && global.variable_id != 0) { + variable v; + init_type_ref(&v.type, NO_NAME); + v.type.type = global.g->type; + v.index = global.variable_id; + v.kind = VARIABLE_GLOBAL; + return v; + } + else { + debug_context context = {0}; + error(context, "Variable %s not found", get_name(name)); + + variable v; + v.index = 0; + return v; + } + } + else { + return local_var; + } +} + +const char all_names[1024 * 1024]; + +static uint64_t next_variable_id = 1; + +variable all_variables[1024 * 1024]; + +variable allocate_variable(type_ref type, variable_kind kind) { + variable v; + v.index = next_variable_id; + v.type = type; + v.kind = kind; + all_variables[v.index] = v; + ++next_variable_id; + return v; +} + +opcode *emit_op(opcodes *code, opcode *o) { + assert(code->size + o->size < OPCODES_SIZE); + + uint8_t *location = &code->o[code->size]; + + memcpy(&code->o[code->size], o, o->size); + + code->size += o->size; + + return (opcode *)location; +} + +#define OP_SIZE(op, opmember) offsetof(opcode, opmember) + sizeof(o.opmember) + +variable emit_expression(opcodes *code, block *parent, expression *e) { + switch (e->kind) { + case EXPRESSION_BINARY: { + expression *left = e->binary.left; + expression *right = e->binary.right; + + debug_context context = {0}; + + switch (e->binary.op) { + case OPERATOR_EQUALS: + case OPERATOR_NOT_EQUALS: + case OPERATOR_GREATER: + case OPERATOR_GREATER_EQUAL: + case OPERATOR_LESS: + case OPERATOR_LESS_EQUAL: + case OPERATOR_AND: + case OPERATOR_OR: + case OPERATOR_XOR: { + variable right_var = emit_expression(code, parent, right); + variable left_var = emit_expression(code, parent, left); + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = bool_id; + variable result_var = allocate_variable(t, VARIABLE_LOCAL); + + opcode o; + switch (e->binary.op) { + case OPERATOR_EQUALS: + o.type = OPCODE_EQUALS; + break; + case OPERATOR_NOT_EQUALS: + o.type = OPCODE_NOT_EQUALS; + break; + case OPERATOR_GREATER: + o.type = OPCODE_GREATER; + break; + case OPERATOR_GREATER_EQUAL: + o.type = OPCODE_GREATER_EQUAL; + break; + case OPERATOR_LESS: + o.type = OPCODE_LESS; + break; + case OPERATOR_LESS_EQUAL: + o.type = OPCODE_LESS_EQUAL; + break; + case OPERATOR_AND: + o.type = OPCODE_AND; + break; + case OPERATOR_OR: + o.type = OPCODE_OR; + break; + case OPERATOR_XOR: + o.type = OPCODE_XOR; + break; + default: { + error(context, "Unexpected operator"); + } + } + o.size = OP_SIZE(o, op_binary); + o.op_binary.right = right_var; + o.op_binary.left = left_var; + o.op_binary.result = result_var; + emit_op(code, &o); + + return result_var; + } + case OPERATOR_MINUS: + case OPERATOR_PLUS: + case OPERATOR_DIVIDE: + case OPERATOR_MULTIPLY: + case OPERATOR_MOD: { + variable right_var = emit_expression(code, parent, right); + variable left_var = emit_expression(code, parent, left); + variable result_var = allocate_variable(e->type, VARIABLE_LOCAL); + + opcode o; + switch (e->binary.op) { + case OPERATOR_MINUS: + o.type = OPCODE_SUB; + break; + case OPERATOR_PLUS: + o.type = OPCODE_ADD; + break; + case OPERATOR_DIVIDE: + o.type = OPCODE_DIVIDE; + break; + case OPERATOR_MULTIPLY: + o.type = OPCODE_MULTIPLY; + break; + case OPERATOR_MOD: + o.type = OPCODE_MOD; + break; + default: { + error(context, "Unexpected operator"); + } + } + o.size = OP_SIZE(o, op_binary); + o.op_binary.right = right_var; + o.op_binary.left = left_var; + o.op_binary.result = result_var; + emit_op(code, &o); + + return result_var; + } + case OPERATOR_NOT: { + error(context, "! is not a binary operator"); + } + case OPERATOR_ASSIGN: + case OPERATOR_MINUS_ASSIGN: + case OPERATOR_PLUS_ASSIGN: + case OPERATOR_DIVIDE_ASSIGN: + case OPERATOR_MULTIPLY_ASSIGN: { + variable v = emit_expression(code, parent, right); + + switch (left->kind) { + case EXPRESSION_VARIABLE: { + opcode o; + switch (e->binary.op) { + case OPERATOR_ASSIGN: + o.type = OPCODE_STORE_VARIABLE; + break; + case OPERATOR_MINUS_ASSIGN: + o.type = OPCODE_SUB_AND_STORE_VARIABLE; + break; + case OPERATOR_PLUS_ASSIGN: + o.type = OPCODE_ADD_AND_STORE_VARIABLE; + break; + case OPERATOR_DIVIDE_ASSIGN: + o.type = OPCODE_DIVIDE_AND_STORE_VARIABLE; + break; + case OPERATOR_MULTIPLY_ASSIGN: + o.type = OPCODE_MULTIPLY_AND_STORE_VARIABLE; + break; + default: { + error(context, "Unexpected operator"); + } + } + o.size = OP_SIZE(o, op_store_var); + o.op_store_var.from = v; + o.op_store_var.to = find_variable(parent, left->variable); + emit_op(code, &o); + break; + } + case EXPRESSION_STATIC_MEMBER: + case EXPRESSION_DYNAMIC_MEMBER: { + variable member_var = emit_expression(code, parent, left->member.left); + + opcode o; + switch (e->binary.op) { + case OPERATOR_ASSIGN: + o.type = OPCODE_STORE_MEMBER; + break; + case OPERATOR_MINUS_ASSIGN: + o.type = OPCODE_SUB_AND_STORE_MEMBER; + break; + case OPERATOR_PLUS_ASSIGN: + o.type = OPCODE_ADD_AND_STORE_MEMBER; + break; + case OPERATOR_DIVIDE_ASSIGN: + o.type = OPCODE_DIVIDE_AND_STORE_MEMBER; + break; + case OPERATOR_MULTIPLY_ASSIGN: + o.type = OPCODE_MULTIPLY_AND_STORE_MEMBER; + break; + default: { + error(context, "Unexpected operator"); + } + } + o.size = OP_SIZE(o, op_store_member); + o.op_store_member.from = v; + o.op_store_member.to = member_var; + // o.op_store_member.member = left->member.right; + + o.op_store_member.member_indices_size = 0; + expression *right = left->member.right; + type_id prev_struct = left->member.left->type.type; + type *prev_s = get_type(prev_struct); + + bool parent_dynamic = left->kind == EXPRESSION_DYNAMIC_MEMBER; + + while (right->kind == EXPRESSION_STATIC_MEMBER || right->kind == EXPRESSION_DYNAMIC_MEMBER) { + debug_context context = {0}; + check(right->type.type != NO_TYPE, context, "Part of the member does not have a type"); + + if (right->member.left->kind == EXPRESSION_VARIABLE && !parent_dynamic) { + bool found = false; + for (size_t i = 0; i < prev_s->members.size; ++i) { + if (prev_s->members.m[i].name == right->member.left->variable) { + o.op_store_member.dynamic_member[o.op_store_member.member_indices_size] = false; + o.op_store_member.static_member_indices[o.op_store_member.member_indices_size] = (uint16_t)i; + ++o.op_store_member.member_indices_size; + found = true; + break; + } + } + check(found, context, "Variable for a member not found"); + } + else if (right->member.left->kind == EXPRESSION_INDEX) { + o.op_store_member.dynamic_member[o.op_store_member.member_indices_size] = false; + o.op_store_member.static_member_indices[o.op_store_member.member_indices_size] = (uint16_t)right->member.left->index; + ++o.op_store_member.member_indices_size; + } + else { + variable sub_expression = emit_expression(code, parent, right->member.left); + o.op_store_member.dynamic_member[o.op_store_member.member_indices_size] = true; + o.op_store_member.dynamic_member_indices[o.op_store_member.member_indices_size] = sub_expression; + ++o.op_store_member.member_indices_size; + } + + prev_struct = right->member.left->type.type; + prev_s = get_type(prev_struct); + parent_dynamic = right->kind == EXPRESSION_DYNAMIC_MEMBER; + right = right->member.right; + } + + { + debug_context context = {0}; + check(right->type.type != NO_TYPE, context, "Part of the member does not have a type"); + if (right->kind == EXPRESSION_VARIABLE && !parent_dynamic) { + bool found = false; + for (size_t i = 0; i < prev_s->members.size; ++i) { + if (prev_s->members.m[i].name == right->variable) { + o.op_store_member.dynamic_member[o.op_store_member.member_indices_size] = false; + o.op_store_member.static_member_indices[o.op_store_member.member_indices_size] = (uint16_t)i; + ++o.op_store_member.member_indices_size; + found = true; + break; + } + } + check(found, context, "Member not found"); + } + else if (right->kind == EXPRESSION_INDEX) { + o.op_store_member.dynamic_member[o.op_store_member.member_indices_size] = false; + o.op_store_member.static_member_indices[o.op_store_member.member_indices_size] = (uint16_t)right->index; + ++o.op_store_member.member_indices_size; + } + else { + variable sub_expression = emit_expression(code, parent, right); + o.op_store_member.dynamic_member[o.op_store_member.member_indices_size] = true; + o.op_store_member.dynamic_member_indices[o.op_store_member.member_indices_size] = sub_expression; + ++o.op_store_member.member_indices_size; + } + } + + emit_op(code, &o); + break; + } + default: { + debug_context context = {0}; + error(context, "Expected a variable or a member"); + } + } + + return v; + } + } + break; + } + case EXPRESSION_UNARY: { + debug_context context = {0}; + switch (e->unary.op) { + case OPERATOR_EQUALS: + error(context, "not implemented"); + case OPERATOR_NOT_EQUALS: + error(context, "not implemented"); + case OPERATOR_GREATER: + error(context, "not implemented"); + case OPERATOR_GREATER_EQUAL: + error(context, "not implemented"); + case OPERATOR_LESS: + error(context, "not implemented"); + case OPERATOR_LESS_EQUAL: + error(context, "not implemented"); + case OPERATOR_MINUS: + error(context, "not implemented"); + case OPERATOR_PLUS: + error(context, "not implemented"); + case OPERATOR_DIVIDE: + error(context, "not implemented"); + case OPERATOR_MULTIPLY: + error(context, "not implemented"); + case OPERATOR_NOT: { + variable v = emit_expression(code, parent, e->unary.right); + opcode o; + o.type = OPCODE_NOT; + o.size = OP_SIZE(o, op_not); + o.op_not.from = v; + o.op_not.to = allocate_variable(v.type, VARIABLE_LOCAL); + emit_op(code, &o); + return o.op_not.to; + } + case OPERATOR_OR: + error(context, "not implemented"); + case OPERATOR_XOR: + error(context, "not implemented"); + case OPERATOR_AND: + error(context, "not implemented"); + case OPERATOR_MOD: + error(context, "not implemented"); + case OPERATOR_ASSIGN: + error(context, "not implemented"); + case OPERATOR_PLUS_ASSIGN: + case OPERATOR_MINUS_ASSIGN: + case OPERATOR_MULTIPLY_ASSIGN: + case OPERATOR_DIVIDE_ASSIGN: + error(context, "not implemented"); + } + } + case EXPRESSION_BOOLEAN: { + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = float_id; + variable v = allocate_variable(t, VARIABLE_LOCAL); + + opcode o; + o.type = OPCODE_LOAD_BOOL_CONSTANT; + o.size = OP_SIZE(o, op_load_bool_constant); + o.op_load_bool_constant.boolean = e->boolean; + o.op_load_bool_constant.to = v; + emit_op(code, &o); + + return v; + } + case EXPRESSION_FLOAT: { + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = float_id; + variable v = allocate_variable(t, VARIABLE_LOCAL); + + opcode o; + o.type = OPCODE_LOAD_FLOAT_CONSTANT; + o.size = OP_SIZE(o, op_load_float_constant); + o.op_load_float_constant.number = (float)e->number; + o.op_load_float_constant.to = v; + emit_op(code, &o); + + return v; + } + case EXPRESSION_INT: { + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = int_id; + variable v = allocate_variable(t, VARIABLE_LOCAL); + + opcode o; + o.type = OPCODE_LOAD_INT_CONSTANT; + o.size = OP_SIZE(o, op_load_float_constant); + o.op_load_int_constant.number = (int)e->number; + o.op_load_int_constant.to = v; + emit_op(code, &o); + + return v; + } + // case EXPRESSION_STRING: + // error("not implemented", 0, 0); + case EXPRESSION_VARIABLE: { + return find_variable(parent, e->variable); + } + case EXPRESSION_GROUPING: { + return emit_expression(code, parent, e->grouping); + } + case EXPRESSION_CALL: { + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = e->type.type; + variable v = allocate_variable(t, VARIABLE_LOCAL); + + opcode o; + o.type = OPCODE_CALL; + o.size = OP_SIZE(o, op_call); + o.op_call.func = e->call.func_name; + o.op_call.var = v; + + debug_context context = {0}; + check(e->call.parameters.size <= sizeof(o.op_call.parameters) / sizeof(variable), context, "Call parameters missized"); + for (size_t i = 0; i < e->call.parameters.size; ++i) { + o.op_call.parameters[i] = emit_expression(code, parent, e->call.parameters.e[i]); + } + o.op_call.parameters_size = (uint8_t)e->call.parameters.size; + + emit_op(code, &o); + + return v; + } + case EXPRESSION_STATIC_MEMBER: + case EXPRESSION_DYNAMIC_MEMBER: { + variable v = allocate_variable(e->type, VARIABLE_LOCAL); + + opcode o; + o.type = OPCODE_LOAD_MEMBER; + o.size = OP_SIZE(o, op_load_member); + + debug_context context = {0}; + if (e->member.left->kind == EXPRESSION_VARIABLE) { + o.op_load_member.from = find_variable(parent, e->member.left->variable); + } + else { + o.op_load_member.from = emit_expression(code, parent, e->member.left); + } + + check(o.op_load_member.from.index != 0, context, "Load var is broken"); + o.op_load_member.to = v; + + o.op_load_member.member_indices_size = 0; + expression *right = e->member.right; + type_id prev_struct = e->member.left->type.type; + type *prev_s = get_type(prev_struct); + o.op_load_member.member_parent_type = prev_struct; + o.op_load_member.member_parent_array = get_type(e->member.left->type.type)->array_size > 0 || e->member.left->type.type == tex2d_type_id; + + bool parent_dynamic = e->kind == EXPRESSION_DYNAMIC_MEMBER; + + while (right->kind == EXPRESSION_STATIC_MEMBER || right->kind == EXPRESSION_DYNAMIC_MEMBER) { + debug_context context = {0}; + check(right->type.type != NO_TYPE, context, "Part of the member does not have a type"); + + if (right->member.left->kind == EXPRESSION_VARIABLE && !parent_dynamic) { + bool found = false; + for (size_t i = 0; i < prev_s->members.size; ++i) { + if (prev_s->members.m[i].name == right->member.left->variable) { + o.op_load_member.dynamic_member[o.op_load_member.member_indices_size] = false; + o.op_load_member.static_member_indices[o.op_load_member.member_indices_size] = (uint16_t)i; + ++o.op_load_member.member_indices_size; + found = true; + break; + } + } + check(found, context, "Variable for a member not found"); + } + else if (right->member.left->kind == EXPRESSION_INDEX) { + o.op_load_member.dynamic_member[o.op_load_member.member_indices_size] = false; + o.op_load_member.static_member_indices[o.op_load_member.member_indices_size] = (uint16_t)right->member.left->index; + ++o.op_load_member.member_indices_size; + } + else { + variable sub_expression = emit_expression(code, parent, right->member.left); + o.op_load_member.dynamic_member[o.op_load_member.member_indices_size] = true; + o.op_load_member.dynamic_member_indices[o.op_load_member.member_indices_size] = sub_expression; + ++o.op_load_member.member_indices_size; + } + + prev_struct = right->member.left->type.type; + prev_s = get_type(prev_struct); + parent_dynamic = right->kind == EXPRESSION_DYNAMIC_MEMBER; + right = right->member.right; + } + + { + debug_context context = {0}; + check(right->type.type != NO_TYPE, context, "Part of the member does not have a type"); + if (right->kind == EXPRESSION_VARIABLE && !parent_dynamic) { + bool found = false; + for (size_t i = 0; i < prev_s->members.size; ++i) { + if (prev_s->members.m[i].name == right->variable) { + o.op_load_member.dynamic_member[o.op_load_member.member_indices_size] = false; + o.op_load_member.static_member_indices[o.op_load_member.member_indices_size] = (uint16_t)i; + ++o.op_load_member.member_indices_size; + found = true; + break; + } + } + check(found, context, "Member not found"); + } + else if (right->kind == EXPRESSION_INDEX) { + o.op_load_member.dynamic_member[o.op_load_member.member_indices_size] = false; + o.op_load_member.static_member_indices[o.op_load_member.member_indices_size] = (uint16_t)right->index; + ++o.op_load_member.member_indices_size; + } + else { + variable sub_expression = emit_expression(code, parent, right); + o.op_load_member.dynamic_member[o.op_load_member.member_indices_size] = true; + o.op_load_member.dynamic_member_indices[o.op_load_member.member_indices_size] = sub_expression; + ++o.op_load_member.member_indices_size; + } + } + + emit_op(code, &o); + + return v; + } + case EXPRESSION_CONSTRUCTOR: { + debug_context context = {0}; + error(context, "not implemented"); + } + default: { + debug_context context = {0}; + error(context, "not implemented"); + } + } + + { + debug_context context = {0}; + error(context, "Supposedly unreachable code reached"); + variable v; + v.index = 0; + return v; + } +} + +typedef struct block_ids { + uint64_t start; + uint64_t end; +} block_ids; + +static block_ids emit_statement(opcodes *code, block *parent, statement *statement) { + switch (statement->kind) { + case STATEMENT_EXPRESSION: + emit_expression(code, parent, statement->expression); + break; + case STATEMENT_RETURN_EXPRESSION: { + opcode o; + o.type = OPCODE_RETURN; + variable v = emit_expression(code, parent, statement->expression); + if (v.index == 0) { + o.size = offsetof(opcode, op_return); + } + else { + o.size = OP_SIZE(o, op_return); + o.op_return.var = v; + } + emit_op(code, &o); + break; + } + case STATEMENT_IF: { + struct previous_condition { + variable condition; + variable summed_condition; + }; + struct previous_condition previous_conditions[64] = {0}; + uint8_t previous_conditions_size = 0; + + { + opcode o; + o.type = OPCODE_IF; + o.size = OP_SIZE(o, op_if); + + variable initial_condition = emit_expression(code, parent, statement->iffy.test); + + o.op_if.condition = initial_condition; + + opcode *written_opcode = emit_op(code, &o); + + previous_conditions[previous_conditions_size].condition = initial_condition; + previous_conditions_size += 1; + + block_ids ids = emit_statement(code, parent, statement->iffy.if_block); + + written_opcode->op_if.start_id = ids.start; + written_opcode->op_if.end_id = ids.end; + } + + for (uint16_t i = 0; i < statement->iffy.else_size; ++i) { + variable current_condition; + { + opcode o; + o.type = OPCODE_NOT; + o.size = OP_SIZE(o, op_not); + o.op_not.from = previous_conditions[previous_conditions_size - 1].condition; + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = bool_id; + current_condition = allocate_variable(t, VARIABLE_LOCAL); + o.op_not.to = current_condition; + emit_op(code, &o); + } + + variable summed_condition; + if (previous_conditions_size == 1) { + summed_condition = previous_conditions[0].summed_condition = current_condition; + } + else { + opcode o; + o.type = OPCODE_AND; + o.size = OP_SIZE(o, op_binary); + o.op_binary.left = previous_conditions[previous_conditions_size - 2].summed_condition; + o.op_binary.right = current_condition; + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = bool_id; + summed_condition = allocate_variable(t, VARIABLE_LOCAL); + o.op_binary.result = summed_condition; + emit_op(code, &o); + } + + opcode o; + o.type = OPCODE_IF; + o.size = OP_SIZE(o, op_if); + + if (statement->iffy.else_tests[i] != NULL) { + variable v = emit_expression(code, parent, statement->iffy.else_tests[i]); + + variable else_test; + { + opcode o; + o.type = OPCODE_AND; + o.size = OP_SIZE(o, op_binary); + o.op_binary.left = summed_condition; + o.op_binary.right = v; + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = bool_id; + else_test = allocate_variable(t, VARIABLE_LOCAL); + o.op_binary.result = else_test; + emit_op(code, &o); + } + + o.op_if.condition = else_test; + + previous_conditions[previous_conditions_size].condition = v; + previous_conditions_size += 1; + } + else { + o.op_if.condition = summed_condition; + } + + { + opcode *written_opcode = emit_op(code, &o); + + block_ids ids = emit_statement(code, parent, statement->iffy.else_blocks[i]); + + written_opcode->op_if.start_id = ids.start; + written_opcode->op_if.end_id = ids.end; + } + } + + break; + } + case STATEMENT_WHILE: { + uint64_t start_id = next_variable_id; + ++next_variable_id; + uint64_t continue_id = next_variable_id; + ++next_variable_id; + uint64_t end_id = next_variable_id; + ++next_variable_id; + + { + opcode o; + o.type = OPCODE_WHILE_START; + o.op_while_start.start_id = start_id; + o.op_while_start.continue_id = continue_id; + o.op_while_start.end_id = end_id; + o.size = OP_SIZE(o, op_while_start); + emit_op(code, &o); + } + + { + opcode o; + o.type = OPCODE_WHILE_CONDITION; + o.size = OP_SIZE(o, op_while); + + variable v = emit_expression(code, parent, statement->whiley.test); + + o.op_while.condition = v; + o.op_while.end_id = end_id; + + emit_op(code, &o); + } + + emit_statement(code, parent, statement->whiley.while_block); + + { + opcode o; + o.type = OPCODE_WHILE_END; + o.op_while_end.start_id = start_id; + o.op_while_end.continue_id = continue_id; + o.op_while_end.end_id = end_id; + o.size = OP_SIZE(o, op_while_end); + emit_op(code, &o); + } + + break; + } + case STATEMENT_DO_WHILE: { + uint64_t start_id = next_variable_id; + ++next_variable_id; + uint64_t continue_id = next_variable_id; + ++next_variable_id; + uint64_t end_id = next_variable_id; + ++next_variable_id; + + { + opcode o; + o.type = OPCODE_WHILE_START; + o.op_while_start.start_id = start_id; + o.op_while_start.continue_id = continue_id; + o.op_while_start.end_id = end_id; + o.size = OP_SIZE(o, op_while_start); + emit_op(code, &o); + } + + emit_statement(code, parent, statement->whiley.while_block); + + { + opcode o; + o.type = OPCODE_WHILE_CONDITION; + o.size = OP_SIZE(o, op_while); + + variable v = emit_expression(code, parent, statement->whiley.test); + + o.op_while.condition = v; + o.op_while.end_id = end_id; + + emit_op(code, &o); + } + + { + opcode o; + o.type = OPCODE_WHILE_END; + o.op_while_end.start_id = start_id; + o.op_while_end.continue_id = continue_id; + o.op_while_end.end_id = end_id; + o.size = OP_SIZE(o, op_while_end); + emit_op(code, &o); + } + + break; + } + case STATEMENT_BLOCK: { + for (size_t i = 0; i < statement->block.vars.size; ++i) { + variable var = allocate_variable(statement->block.vars.v[i].type, VARIABLE_LOCAL); + statement->block.vars.v[i].variable_id = var.index; + } + + uint64_t start_block_id = next_variable_id; + ++next_variable_id; + + uint64_t end_block_id = next_variable_id; + ++next_variable_id; + + { + opcode o; + o.type = OPCODE_BLOCK_START; + o.op_block.id = start_block_id; + o.size = OP_SIZE(o, op_block); + emit_op(code, &o); + } + + for (size_t i = 0; i < statement->block.statements.size; ++i) { + emit_statement(code, &statement->block, statement->block.statements.s[i]); + } + + { + opcode o; + o.type = OPCODE_BLOCK_END; + o.op_block.id = end_block_id; + o.size = OP_SIZE(o, op_block); + emit_op(code, &o); + } + + block_ids ids; + ids.start = start_block_id; + ids.end = end_block_id; + return ids; + } + case STATEMENT_LOCAL_VARIABLE: { + opcode o; + o.type = OPCODE_VAR; + o.size = OP_SIZE(o, op_var); + + variable init_var = {0}; + if (statement->local_variable.init != NULL) { + init_var = emit_expression(code, parent, statement->local_variable.init); + } + + variable local_var = find_local_var(parent, statement->local_variable.var.name); + statement->local_variable.var.variable_id = local_var.index; + o.op_var.var.index = statement->local_variable.var.variable_id; + debug_context context = {0}; + check(statement->local_variable.var.type.type != NO_TYPE, context, "Local var has no type"); + o.op_var.var.type = statement->local_variable.var.type; + emit_op(code, &o); + + if (statement->local_variable.init != NULL) { + opcode o; + o.type = OPCODE_STORE_VARIABLE; + o.size = OP_SIZE(o, op_store_var); + + o.op_store_var.from = init_var; + o.op_store_var.to = local_var; + + emit_op(code, &o); + } + + break; + } + } + + block_ids ids; + ids.start = 0; + ids.end = 0; + return ids; +} + +void allocate_globals(void) { + for (global_id i = 0; get_global(i) != NULL && get_global(i)->type != NO_TYPE; ++i) { + global *g = get_global(i); + + type_ref t; + init_type_ref(&t, NO_NAME); + t.type = g->type; + variable v = allocate_variable(t, VARIABLE_GLOBAL); + allocated_globals[allocated_globals_size].g = g; + allocated_globals[allocated_globals_size].variable_id = v.index; + allocated_globals_size += 1; + + assign_global_var(i, v.index); + } +} + +void compile_function_block(opcodes *code, struct statement *block) { + if (block == NULL) { + // built-in + return; + } + + if (block->kind != STATEMENT_BLOCK) { + debug_context context = {0}; + error(context, "Expected a block"); + } + for (size_t i = 0; i < block->block.vars.size; ++i) { + variable var = allocate_variable(block->block.vars.v[i].type, VARIABLE_LOCAL); + block->block.vars.v[i].variable_id = var.index; + } + for (size_t i = 0; i < block->block.statements.size; ++i) { + emit_statement(code, &block->block, block->block.statements.s[i]); + } +} diff --git a/base/sources/libs/kong/sources/compiler.h b/base/sources/libs/kong/sources/compiler.h new file mode 100644 index 00000000..c82201f9 --- /dev/null +++ b/base/sources/libs/kong/sources/compiler.h @@ -0,0 +1,162 @@ +#pragma once + +#include "names.h" +#include "types.h" + +#include +#include + +typedef enum variable_kind { VARIABLE_GLOBAL, VARIABLE_LOCAL } variable_kind; + +typedef struct variable { + variable_kind kind; + uint64_t index; + type_ref type; +} variable; + +typedef struct opcode { + enum { + OPCODE_VAR, + OPCODE_NOT, + OPCODE_STORE_VARIABLE, + OPCODE_SUB_AND_STORE_VARIABLE, + OPCODE_ADD_AND_STORE_VARIABLE, + OPCODE_DIVIDE_AND_STORE_VARIABLE, + OPCODE_MULTIPLY_AND_STORE_VARIABLE, + OPCODE_STORE_MEMBER, + OPCODE_SUB_AND_STORE_MEMBER, + OPCODE_ADD_AND_STORE_MEMBER, + OPCODE_DIVIDE_AND_STORE_MEMBER, + OPCODE_MULTIPLY_AND_STORE_MEMBER, + OPCODE_LOAD_FLOAT_CONSTANT, + OPCODE_LOAD_INT_CONSTANT, + OPCODE_LOAD_BOOL_CONSTANT, + OPCODE_LOAD_MEMBER, + OPCODE_RETURN, + OPCODE_CALL, + OPCODE_MULTIPLY, + OPCODE_DIVIDE, + OPCODE_MOD, + OPCODE_ADD, + OPCODE_SUB, + OPCODE_EQUALS, + OPCODE_NOT_EQUALS, + OPCODE_GREATER, + OPCODE_GREATER_EQUAL, + OPCODE_LESS, + OPCODE_LESS_EQUAL, + OPCODE_AND, + OPCODE_OR, + OPCODE_XOR, + OPCODE_IF, + OPCODE_WHILE_START, + OPCODE_WHILE_CONDITION, + OPCODE_WHILE_END, + OPCODE_WHILE_BODY, + OPCODE_BLOCK_START, + OPCODE_BLOCK_END + } type; + uint32_t size; + + union { + struct { + variable var; + } op_var; + struct { + variable from; + variable to; + } op_not; + struct { + variable from; + variable to; + } op_store_var; + struct { + variable from; + variable to; + + bool dynamic_member[64]; + variable dynamic_member_indices[64]; + + uint32_t static_member_indices[64]; + + uint8_t member_indices_size; + } op_store_member; + struct { + float number; + variable to; + } op_load_float_constant; + struct { + int number; + variable to; + } op_load_int_constant; + struct { + bool boolean; + variable to; + } op_load_bool_constant; + struct { + variable from; + variable to; + + bool dynamic_member[64]; + variable dynamic_member_indices[64]; + + uint32_t static_member_indices[64]; + type_id member_parent_type; + bool member_parent_array; + + uint8_t member_indices_size; + } op_load_member; + struct { + variable var; + } op_return; + struct { + variable var; + name_id func; + variable parameters[64]; + uint8_t parameters_size; + } op_call; + struct { + variable right; + variable left; + variable result; + } op_binary; + struct { + variable condition; + uint64_t start_id; + uint64_t end_id; + } op_if; + struct { + uint64_t start_id; + uint64_t continue_id; + uint64_t end_id; + } op_while_start; + struct { + uint64_t start_id; + uint64_t continue_id; + uint64_t end_id; + } op_while_end; + struct { + variable condition; + uint64_t end_id; + } op_while; + struct { + uint64_t id; + } op_block; + struct { + uint8_t nothing; + } op_nothing; + }; +} opcode; + +#define OPCODES_SIZE (256 * 1024) + +typedef struct opcodes { + uint8_t o[OPCODES_SIZE]; + size_t size; +} opcodes; + +void allocate_globals(void); + +struct statement; + +void compile_function_block(opcodes *code, struct statement *block); diff --git a/base/sources/libs/kong/sources/dir.c b/base/sources/libs/kong/sources/dir.c new file mode 100644 index 00000000..9e89d64e --- /dev/null +++ b/base/sources/libs/kong/sources/dir.c @@ -0,0 +1,78 @@ +#include "dir.h" + +#include "log.h" + +#include +#include + +#ifdef _WIN32 + +#include + +directory open_dir(const char *dirname) { + char pattern[1024]; + strcpy(pattern, dirname); + strcat(pattern, "\\*"); + + WIN32_FIND_DATAA data; + directory dir; + dir.handle = FindFirstFileA(pattern, &data); + if (dir.handle == INVALID_HANDLE_VALUE) { + kong_log(LOG_LEVEL_ERROR, "FindFirstFile failed (%d)\n", GetLastError()); + exit(1); + } + FindNextFileA(dir.handle, &data); + return dir; +} + +file read_next_file(directory *dir) { + WIN32_FIND_DATAA data; + file file; + file.valid = FindNextFileA(dir->handle, &data) != 0; + if (file.valid) { + strcpy(file.name, data.cFileName); + } + else { + file.name[0] = 0; + } + return file; +} + +void close_dir(directory *dir) { + FindClose(dir->handle); +} + +#else + +#include + +#include +#include +#include + +directory open_dir(const char *dirname) { + directory dir; + dir.handle = opendir(dirname); + return dir; +} + +file read_next_file(directory *dir) { + struct dirent *entry = readdir(dir->handle); + + while (entry != NULL && (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)) { + entry = readdir(dir->handle); + } + + file f; + f.valid = entry != NULL; + + if (f.valid) { + strcpy(f.name, entry->d_name); + } + + return f; +} + +void close_dir(directory *dir) {} + +#endif diff --git a/base/sources/libs/kong/sources/dir.h b/base/sources/libs/kong/sources/dir.h new file mode 100644 index 00000000..d5f9f5ef --- /dev/null +++ b/base/sources/libs/kong/sources/dir.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +typedef struct directory { + void *handle; +} directory; + +typedef struct file { + bool valid; + char name[256]; +} file; + +directory open_dir(const char *dirname); +file read_next_file(directory *dir); +void close_dir(directory *dir); diff --git a/base/sources/libs/kong/sources/disasm.c b/base/sources/libs/kong/sources/disasm.c new file mode 100644 index 00000000..56d03895 --- /dev/null +++ b/base/sources/libs/kong/sources/disasm.c @@ -0,0 +1,208 @@ +#include "disasm.h" + +#include "compiler.h" +#include "errors.h" +#include "functions.h" +#include "log.h" +#include "parser.h" +#include "sets.h" +#include "shader_stage.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include + +static char *type_string(type_id type) { + if (type == float_id) { + return "float"; + } + if (type == float2_id) { + return "float2"; + } + if (type == float3_id) { + return "float3"; + } + if (type == float4_id) { + return "float4"; + } + if (type == float4x4_id) { + return "float4x4"; + } + if (type == ray_type_id) { + return "RayDesc"; + } + if (type == bvh_type_id) { + return "RaytracingAccelerationStructure"; + } + if (type == tex2d_type_id) { + return "Texture2D"; + } + return get_name(get_type(type)->name); +} + +static void write_functions(void) { + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + + if (f->block == NULL) { + continue; + } + + kong_log(LOG_LEVEL_INFO, "Function: %s", get_name(f->name)); + + uint8_t *data = f->code.o; + size_t size = f->code.size; + + size_t index = 0; + while (index < size) { + opcode *o = (opcode *)&data[index]; + switch (o->type) { + case OPCODE_RETURN: + kong_log(LOG_LEVEL_INFO, "RETURN $%zu", o->op_return.var.index); + break; + case OPCODE_LOAD_MEMBER: { + char indices[256]; + int offset = 0; + + for (int i = 0; i < o->op_load_member.member_indices_size; ++i) { + if (o->op_load_member.dynamic_member[i]) { + offset += sprintf(&indices[offset], "$%zu", o->op_load_member.dynamic_member_indices[i].index); + } + else { + offset += sprintf(&indices[offset], "%i", o->op_load_member.static_member_indices[i]); + } + + if (i < o->op_load_member.member_indices_size - 1) { + offset += sprintf(&indices[offset], ", "); + } + } + + kong_log(LOG_LEVEL_INFO, "$%zu = LOAD_MEMBER $%zu[%s]", o->op_load_member.to.index, o->op_load_member.from.index, indices); + break; + } + case OPCODE_CALL: { + char parameters[256]; + int offset = 0; + + for (int i = 0; i < o->op_call.parameters_size; ++i) { + offset += sprintf(¶meters[offset], "$%zu", o->op_call.parameters[i].index); + + if (i < o->op_call.parameters_size - 1) { + offset += sprintf(¶meters[offset], ", "); + } + } + + kong_log(LOG_LEVEL_INFO, "$%zu = CALL %s(%s)", o->op_call.var.index, get_name(o->op_call.func), parameters); + break; + } + case OPCODE_VAR: + break; + case OPCODE_NOT: + break; + case OPCODE_STORE_VARIABLE: + kong_log(LOG_LEVEL_INFO, "$%zu = STORE_VARIABLE $%zu", o->op_store_var.to.index, o->op_store_var.from.index); + break; + case OPCODE_SUB_AND_STORE_VARIABLE: + break; + case OPCODE_ADD_AND_STORE_VARIABLE: + break; + case OPCODE_DIVIDE_AND_STORE_VARIABLE: + break; + case OPCODE_MULTIPLY_AND_STORE_VARIABLE: + break; + case OPCODE_STORE_MEMBER: { + char indices[256]; + int offset = 0; + + for (int i = 0; i < o->op_store_member.member_indices_size; ++i) { + if (o->op_store_member.dynamic_member[i]) { + offset += sprintf(&indices[offset], "$%zu", o->op_store_member.dynamic_member_indices[i].index); + } + else { + offset += sprintf(&indices[offset], "%i", o->op_store_member.static_member_indices[i]); + } + + if (i < o->op_store_member.member_indices_size - 1) { + offset += sprintf(&indices[offset], ", "); + } + } + + kong_log(LOG_LEVEL_INFO, "$%zu[%s] = STORE_MEMBER $%zu", o->op_store_member.to.index, indices, o->op_store_member.from.index); + break; + } + case OPCODE_SUB_AND_STORE_MEMBER: + break; + case OPCODE_ADD_AND_STORE_MEMBER: + break; + case OPCODE_DIVIDE_AND_STORE_MEMBER: + break; + case OPCODE_MULTIPLY_AND_STORE_MEMBER: + break; + case OPCODE_LOAD_FLOAT_CONSTANT: + kong_log(LOG_LEVEL_INFO, "$%zu = LOAD_FLOAT_CONSTANT %f", o->op_load_float_constant.to.index, o->op_load_float_constant.number); + break; + case OPCODE_LOAD_INT_CONSTANT: + break; + case OPCODE_LOAD_BOOL_CONSTANT: + break; + case OPCODE_ADD: + break; + case OPCODE_SUB: + break; + case OPCODE_MULTIPLY: + kong_log(LOG_LEVEL_INFO, "$%zu = MULTIPLY $%zu, $%zu", o->op_binary.result.index, o->op_binary.left.index, o->op_binary.right.index); + break; + case OPCODE_DIVIDE: + break; + case OPCODE_MOD: + break; + case OPCODE_EQUALS: + break; + case OPCODE_NOT_EQUALS: + break; + case OPCODE_GREATER: + break; + case OPCODE_GREATER_EQUAL: + break; + case OPCODE_LESS: + break; + case OPCODE_LESS_EQUAL: + break; + case OPCODE_AND: + break; + case OPCODE_OR: + break; + case OPCODE_XOR: + break; + case OPCODE_IF: + break; + case OPCODE_WHILE_START: + break; + case OPCODE_WHILE_CONDITION: + break; + case OPCODE_WHILE_END: + break; + case OPCODE_BLOCK_START: + break; + case OPCODE_BLOCK_END: + break; + default: { + debug_context context = {0}; + error(context, "Unknown opcode"); + break; + } + } + index += o->size; + } + + kong_log(LOG_LEVEL_INFO, ""); + } +} + +void disassemble(void) { + write_functions(); +} diff --git a/base/sources/libs/kong/sources/disasm.h b/base/sources/libs/kong/sources/disasm.h new file mode 100644 index 00000000..535b4f21 --- /dev/null +++ b/base/sources/libs/kong/sources/disasm.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void disassemble(void); diff --git a/base/sources/libs/kong/sources/errors.c b/base/sources/libs/kong/sources/errors.c new file mode 100644 index 00000000..5d4f223c --- /dev/null +++ b/base/sources/libs/kong/sources/errors.c @@ -0,0 +1,58 @@ +#include "errors.h" + +#include "log.h" + +#include +#include + +void error_args(debug_context context, const char *message, va_list args) { + char buffer[4096]; + + if (context.filename != NULL) { + sprintf(buffer, "In column %i at line %i in %s: ", context.column + 1, context.line + 1, context.filename); + } + else { + sprintf(buffer, "In column %i at line %i: ", context.column + 1, context.line + 1); + } + + strcat(buffer, message); + + kong_log_args(LOG_LEVEL_ERROR, buffer, args); + + exit(1); +} + +void error_args_no_context(const char *message, va_list args) { + kong_log_args(LOG_LEVEL_ERROR, message, args); + + exit(1); +} + +void error(debug_context context, const char *message, ...) { + va_list args; + va_start(args, message); + error_args(context, message, args); + va_end(args); +} + +void error_no_context(const char *message, ...) { + va_list args; + va_start(args, message); + error_args_no_context(message, args); + va_end(args); +} + +void check_args(bool test, debug_context context, const char *message, va_list args) { + if (!test) { + error_args(context, message, args); + } +} + +void check_function(bool test, debug_context context, const char *message, ...) { + if (!test) { + va_list args; + va_start(args, message); + error_args(context, message, args); + va_end(args); + } +} diff --git a/base/sources/libs/kong/sources/errors.h b/base/sources/libs/kong/sources/errors.h new file mode 100644 index 00000000..5fb66f44 --- /dev/null +++ b/base/sources/libs/kong/sources/errors.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include +#include //// + +#ifdef __cplusplus +extern "C" { +#endif + +#if (__STDC_VERSION__ >= 201112L) +#define noreturn _Noreturn +#else +#define noreturn +#endif + +typedef struct debug_context { + const char *filename; + uint32_t column; + uint32_t line; +} debug_context; + +noreturn void error(debug_context context, const char *message, ...); +noreturn void error_no_context(const char *message, ...); +noreturn void error_args(debug_context context, const char *message, va_list args); +noreturn void error_args_no_context(const char *message, va_list args); +void check_function(bool test, debug_context context, const char *message, ...); +#define check(test, context, message, ...) \ + assert(test); \ + check_function(test, context, message, ##__VA_ARGS__) +void check_args(bool test, debug_context context, const char *message, va_list args); + +// V_ASSERT_CONTRACT, assertMacro:check + +#ifdef __cplusplus +} +#endif diff --git a/base/sources/libs/kong/sources/functions.c b/base/sources/libs/kong/sources/functions.c new file mode 100644 index 00000000..2cf8c1d6 --- /dev/null +++ b/base/sources/libs/kong/sources/functions.c @@ -0,0 +1,685 @@ +#include "functions.h" + +#include "errors.h" + +#include +#include +#include + +static function *functions = NULL; +static function_id functions_size = 1024; +static function_id next_function_index = 0; + +static void add_func_int(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("int")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameters_size = 0; + f->block = NULL; +} + +static void add_func_float3_float_float_float(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float3")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameter_names[0] = add_name("a"); + f->parameter_names[1] = add_name("b"); + f->parameter_names[2] = add_name("c"); + for (int i = 0; i < 3; ++i) { + init_type_ref(&f->parameter_types[0], add_name("float")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + } + f->parameters_size = 3; + f->block = NULL; +} + +static void add_func_float(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameters_size = 0; + f->block = NULL; +} + +static void add_func_float3(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float3")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameters_size = 0; + f->block = NULL; +} + +static void add_func_float3x3(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float3x3")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameters_size = 0; + f->block = NULL; +} + +static void add_func_uint(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("uint")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameters_size = 0; + f->block = NULL; +} + +static void add_func_uint3(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("uint3")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameters_size = 0; + f->block = NULL; +} + +static void add_func_float_float(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameter_names[0] = add_name("a"); + init_type_ref(&f->parameter_types[0], add_name("float")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + f->parameters_size = 1; + f->block = NULL; +} + +static void add_func_float_float2(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameter_names[0] = add_name("a"); + init_type_ref(&f->parameter_types[0], add_name("float2")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + f->parameters_size = 1; + f->block = NULL; +} + +static void add_func_float3_float3(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float3")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameter_names[0] = add_name("a"); + init_type_ref(&f->parameter_types[0], add_name("float3")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + f->parameters_size = 1; + f->block = NULL; +} + +static void add_func_float3_float3_float3(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float3")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("a"); + init_type_ref(&f->parameter_types[0], add_name("float3")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("b"); + init_type_ref(&f->parameter_types[1], add_name("float3")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameters_size = 2; + f->block = NULL; +} + +static void add_func_void_uint_uint(char *name) { + function_id func = add_function(add_name(name)); + function *f = get_function(func); + + init_type_ref(&f->return_type, add_name("void")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("a"); + f->parameter_names[1] = add_name("b"); + for (int i = 0; i < 2; ++i) { + init_type_ref(&f->parameter_types[0], add_name("uint")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + } + f->parameters_size = 2; + + f->block = NULL; +} + +void functions_init(void) { + function *new_functions = realloc(functions, functions_size * sizeof(function)); + debug_context context = {0}; + check(new_functions != NULL, context, "Could not allocate functions"); + functions = new_functions; + next_function_index = 0; + + { + function_id func = add_function(add_name("sample")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float4")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameter_names[0] = add_name("tex_coord"); + init_type_ref(&f->parameter_types[0], add_name("float2")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + f->parameters_size = 1; + f->block = NULL; + } + + { + function_id func = add_function(add_name("sample_lod")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float4")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameter_names[0] = add_name("tex_coord"); + init_type_ref(&f->parameter_types[0], add_name("float2")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + f->parameters_size = 1; + f->block = NULL; + } + + { + function_id func = add_function(add_name("float")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("float")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameters_size = 1; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("float2")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float2")); + f->return_type.type = find_type_by_ref(&f->return_type); + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("float")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("float")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameters_size = 2; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("float3")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float3")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("float")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("float")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameter_names[2] = add_name("z"); + init_type_ref(&f->parameter_types[2], add_name("float")); + f->parameter_types[2].type = find_type_by_ref(&f->parameter_types[2]); + + f->parameters_size = 3; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("float4")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("float4")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("float")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("float")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameter_names[2] = add_name("z"); + init_type_ref(&f->parameter_types[2], add_name("float")); + f->parameter_types[2].type = find_type_by_ref(&f->parameter_types[2]); + + f->parameter_names[3] = add_name("w"); + init_type_ref(&f->parameter_types[3], add_name("float")); + f->parameter_types[3].type = find_type_by_ref(&f->parameter_types[3]); + + f->parameters_size = 4; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("int")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("int")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("int")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameters_size = 1; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("int2")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("int2")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("int")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("int")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameters_size = 2; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("int3")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("int3")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("int")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("int")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameter_names[2] = add_name("z"); + init_type_ref(&f->parameter_types[2], add_name("int")); + f->parameter_types[2].type = find_type_by_ref(&f->parameter_types[2]); + + f->parameters_size = 3; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("int4")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("int4")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("int")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("int")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameter_names[2] = add_name("z"); + init_type_ref(&f->parameter_types[2], add_name("int")); + f->parameter_types[2].type = find_type_by_ref(&f->parameter_types[2]); + + f->parameter_names[3] = add_name("w"); + init_type_ref(&f->parameter_types[3], add_name("int")); + f->parameter_types[3].type = find_type_by_ref(&f->parameter_types[3]); + + f->parameters_size = 4; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("uint")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("uint")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("uint")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameters_size = 1; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("uint2")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("uint2")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("uint")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("uint")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameters_size = 2; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("uint3")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("uint3")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("uint")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("uint")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameter_names[2] = add_name("z"); + init_type_ref(&f->parameter_types[2], add_name("uint")); + f->parameter_types[2].type = find_type_by_ref(&f->parameter_types[2]); + + f->parameters_size = 3; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("uint4")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("uint4")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("uint")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("uint")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameter_names[2] = add_name("z"); + init_type_ref(&f->parameter_types[2], add_name("uint")); + f->parameter_types[2].type = find_type_by_ref(&f->parameter_types[2]); + + f->parameter_names[3] = add_name("w"); + init_type_ref(&f->parameter_types[3], add_name("uint")); + f->parameter_types[3].type = find_type_by_ref(&f->parameter_types[3]); + + f->parameters_size = 4; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("bool")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("bool")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("bool")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameters_size = 1; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("bool2")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("bool2")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("bool")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("bool")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameters_size = 2; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("bool3")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("bool3")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("bool")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("bool")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameter_names[2] = add_name("z"); + init_type_ref(&f->parameter_types[2], add_name("bool")); + f->parameter_types[2].type = find_type_by_ref(&f->parameter_types[2]); + + f->parameters_size = 3; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("bool4")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("bool4")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("bool")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("bool")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameter_names[2] = add_name("z"); + init_type_ref(&f->parameter_types[2], add_name("bool")); + f->parameter_types[2].type = find_type_by_ref(&f->parameter_types[2]); + + f->parameter_names[3] = add_name("w"); + init_type_ref(&f->parameter_types[3], add_name("bool")); + f->parameter_types[3].type = find_type_by_ref(&f->parameter_types[3]); + + f->parameters_size = 4; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("trace_ray")); + function *f = get_function(func); + + init_type_ref(&f->return_type, add_name("void")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("scene"); + init_type_ref(&f->parameter_types[0], add_name("bvh")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + f->parameters_size += 1; + + f->parameter_names[1] = add_name("ray"); + init_type_ref(&f->parameter_types[1], add_name("ray")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + f->parameters_size += 1; + + f->parameter_names[2] = add_name("payload"); + init_type_ref(&f->parameter_types[2], add_name("void")); + f->parameter_types[2].type = find_type_by_ref(&f->parameter_types[2]); + f->parameters_size += 1; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("dispatch_mesh")); + function *f = get_function(func); + + init_type_ref(&f->return_type, add_name("void")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("uint")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + f->parameters_size += 1; + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("uint")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + f->parameters_size += 1; + + f->parameter_names[2] = add_name("z"); + init_type_ref(&f->parameter_types[2], add_name("uint")); + f->parameter_types[2].type = find_type_by_ref(&f->parameter_types[2]); + f->parameters_size += 1; + + f->parameter_names[3] = add_name("payload"); + init_type_ref(&f->parameter_types[3], add_name("void")); + f->parameter_types[3].type = find_type_by_ref(&f->parameter_types[3]); + f->parameters_size += 1; + + f->block = NULL; + } + + add_func_uint3("group_id"); + add_func_uint3("group_thread_id"); + add_func_uint3("dispatch_thread_id"); + add_func_int("group_index"); + add_func_int("instance_id"); + + add_func_float3_float_float_float("lerp"); + add_func_float3("world_ray_origin"); + add_func_float3("world_ray_direction"); + add_func_float("ray_length"); + add_func_float3_float3("normalize"); + add_func_float_float("sin"); + add_func_float_float("cos"); + add_func_float_float2("length"); + add_func_uint3("ray_index"); + add_func_float3("ray_dimensions"); + add_func_float_float("frac"); + add_func_float3x3("object_to_world3x3"); + add_func_float3_float3_float3("reflect"); + add_func_uint("primitive_index"); + add_func_float3_float3("abs"); + add_func_float3_float3_float3("dot"); + add_func_float3_float3("saturate3"); + add_func_float_float("saturate"); + + add_func_void_uint_uint("set_mesh_output_counts"); + + { + function_id func = add_function(add_name("set_mesh_triangle")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("void")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("uint")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("uint3")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameters_size = 2; + + f->block = NULL; + } + + { + function_id func = add_function(add_name("set_mesh_vertex")); + function *f = get_function(func); + init_type_ref(&f->return_type, add_name("void")); + f->return_type.type = find_type_by_ref(&f->return_type); + + f->parameter_names[0] = add_name("x"); + init_type_ref(&f->parameter_types[0], add_name("uint")); + f->parameter_types[0].type = find_type_by_ref(&f->parameter_types[0]); + + f->parameter_names[1] = add_name("y"); + init_type_ref(&f->parameter_types[1], add_name("void")); + f->parameter_types[1].type = find_type_by_ref(&f->parameter_types[1]); + + f->parameters_size = 2; + + f->block = NULL; + } +} + +static void grow_if_needed(uint64_t size) { + while (size >= functions_size) { + functions_size *= 2; + function *new_functions = realloc(functions, functions_size * sizeof(function)); + debug_context context = {0}; + check(new_functions != NULL, context, "Could not allocate functions"); + functions = new_functions; + } +} + +function_id add_function(name_id name) { + grow_if_needed(next_function_index + 1); + + function_id f = next_function_index; + ++next_function_index; + + functions[f].name = name; + functions[f].attributes.attributes_count = 0; + init_type_ref(&functions[f].return_type, NO_NAME); + functions[f].parameters_size = 0; + memset(functions[f].parameter_attributes, 0, sizeof(functions[f].parameter_attributes)); + functions[f].block = NULL; + memset(functions[f].code.o, 0, sizeof(functions[f].code.o)); + functions[f].code.size = 0; + functions[f].descriptor_set_group_index = UINT32_MAX; + + return f; +} + +function_id find_function(name_id name) { + for (function_id i = 0; i < next_function_index; ++i) { + if (functions[i].name == name) { + return i; + } + } + + return NO_FUNCTION; +} + +function *get_function(function_id function) { + if (function >= next_function_index) { + return NULL; + } + return &functions[function]; +} diff --git a/base/sources/libs/kong/sources/functions.h b/base/sources/libs/kong/sources/functions.h new file mode 100644 index 00000000..5373faac --- /dev/null +++ b/base/sources/libs/kong/sources/functions.h @@ -0,0 +1,34 @@ +#pragma once + +#include "compiler.h" +#include "names.h" +#include "types.h" + +#define NO_FUNCTION 0xFFFFFFFF + +typedef uint32_t function_id; + +struct statement; + +typedef struct function { + attribute_list attributes; + name_id name; + type_ref return_type; + name_id parameter_names[256]; + type_ref parameter_types[256]; + name_id parameter_attributes[256]; + uint8_t parameters_size; + struct statement *block; + + uint32_t descriptor_set_group_index; + + opcodes code; +} function; + +void functions_init(void); + +function_id add_function(name_id name); + +function_id find_function(name_id name); + +function *get_function(function_id function); diff --git a/base/sources/libs/kong/sources/globals.c b/base/sources/libs/kong/sources/globals.c new file mode 100644 index 00000000..c2440bbd --- /dev/null +++ b/base/sources/libs/kong/sources/globals.c @@ -0,0 +1,204 @@ +#include "globals.h" + +#include "errors.h" + +#include + +static global globals[1024]; +static global_id globals_size = 0; + +void globals_init(void) { + global_value int_value; + int_value.kind = GLOBAL_VALUE_INT; + + attribute_list attributes = {0}; + + int_value.value.ints[0] = 0; + add_global_with_value(float_id, attributes, add_name("COMPARE_ALWAYS"), int_value); + int_value.value.ints[0] = 1; + add_global_with_value(float_id, attributes, add_name("COMPARE_NEVER"), int_value); + int_value.value.ints[0] = 2; + add_global_with_value(float_id, attributes, add_name("COMPARE_EQUAL"), int_value); + int_value.value.ints[0] = 3; + add_global_with_value(float_id, attributes, add_name("COMPARE_NOT_EQUAL"), int_value); + int_value.value.ints[0] = 4; + add_global_with_value(float_id, attributes, add_name("COMPARE_LESS"), int_value); + int_value.value.ints[0] = 5; + add_global_with_value(float_id, attributes, add_name("COMPARE_LESS_EQUAL"), int_value); + int_value.value.ints[0] = 6; + add_global_with_value(float_id, attributes, add_name("COMPARE_GREATER"), int_value); + int_value.value.ints[0] = 7; + add_global_with_value(float_id, attributes, add_name("COMPARE_GREATER_EQUAL"), int_value); + + int_value.value.ints[0] = 0; + add_global_with_value(float_id, attributes, add_name("BLEND_ONE"), int_value); + int_value.value.ints[0] = 1; + add_global_with_value(float_id, attributes, add_name("BLEND_ZERO"), int_value); + int_value.value.ints[0] = 2; + add_global_with_value(float_id, attributes, add_name("BLEND_SOURCE_ALPHA"), int_value); + int_value.value.ints[0] = 3; + add_global_with_value(float_id, attributes, add_name("BLEND_DEST_ALPHA"), int_value); + int_value.value.ints[0] = 4; + add_global_with_value(float_id, attributes, add_name("BLEND_INV_SOURCE_ALPHA"), int_value); + int_value.value.ints[0] = 5; + add_global_with_value(float_id, attributes, add_name("BLEND_INV_DEST_ALPHA"), int_value); + int_value.value.ints[0] = 6; + add_global_with_value(float_id, attributes, add_name("BLEND_SOURCE_COLOR"), int_value); + int_value.value.ints[0] = 7; + add_global_with_value(float_id, attributes, add_name("BLEND_DEST_COLOR"), int_value); + int_value.value.ints[0] = 8; + add_global_with_value(float_id, attributes, add_name("BLEND_INV_SOURCE_COLOR"), int_value); + int_value.value.ints[0] = 9; + add_global_with_value(float_id, attributes, add_name("BLEND_INV_DEST_COLOR"), int_value); + int_value.value.ints[0] = 10; + add_global_with_value(float_id, attributes, add_name("BLEND_CONSTANT"), int_value); + int_value.value.ints[0] = 11; + add_global_with_value(float_id, attributes, add_name("BLEND_INV_CONSTANT"), int_value); + + int_value.value.ints[0] = 0; + add_global_with_value(float_id, attributes, add_name("BLENDOP_ADD"), int_value); + int_value.value.ints[0] = 1; + add_global_with_value(float_id, attributes, add_name("BLENDOP_SUBTRACT"), int_value); + int_value.value.ints[0] = 2; + add_global_with_value(float_id, attributes, add_name("BLENDOP_REVERSE_SUBTRACT"), int_value); + int_value.value.ints[0] = 3; + add_global_with_value(float_id, attributes, add_name("BLENDOP_MIN"), int_value); + int_value.value.ints[0] = 4; + add_global_with_value(float_id, attributes, add_name("BLENDOP_MAX"), int_value); + + global_value uint_value; + uint_value.kind = GLOBAL_VALUE_UINT; + + uint_value.value.uints[0] = 0; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_R8_UNORM"), uint_value); + uint_value.value.uints[0] = 1; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_R8_SNORM"), uint_value); + uint_value.value.uints[0] = 2; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_R8_UINT"), uint_value); + uint_value.value.uints[0] = 3; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_R8_SINT"), uint_value); + uint_value.value.uints[0] = 4; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_R16_UINT"), uint_value); + uint_value.value.uints[0] = 5; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_R16_SINT"), uint_value); + uint_value.value.uints[0] = 6; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_R16_FLOAT"), uint_value); + uint_value.value.uints[0] = 7; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG8_UNORM"), uint_value); + uint_value.value.uints[0] = 8; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG8_SNORM"), uint_value); + uint_value.value.uints[0] = 9; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG8_UINT"), uint_value); + uint_value.value.uints[0] = 10; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG8_SINT"), uint_value); + uint_value.value.uints[0] = 11; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_R32_UINT"), uint_value); + uint_value.value.uints[0] = 12; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_R32_SINT"), uint_value); + uint_value.value.uints[0] = 13; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_R32_FLOAT"), uint_value); + uint_value.value.uints[0] = 14; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG16_UINT"), uint_value); + uint_value.value.uints[0] = 15; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG16_SINT"), uint_value); + uint_value.value.uints[0] = 16; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG16_FLOAT"), uint_value); + uint_value.value.uints[0] = 17; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA8_UNORM"), uint_value); + uint_value.value.uints[0] = 18; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA8_UNORM_SRGB"), uint_value); + uint_value.value.uints[0] = 19; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA8_SNORM"), uint_value); + uint_value.value.uints[0] = 20; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA8_UINT"), uint_value); + uint_value.value.uints[0] = 21; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA8_SINT"), uint_value); + uint_value.value.uints[0] = 22; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_BGRA8_UNORM"), uint_value); + uint_value.value.uints[0] = 23; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_BGRA8_UNORM_SRGB"), uint_value); + uint_value.value.uints[0] = 24; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGB9E5U_FLOAT"), uint_value); + uint_value.value.uints[0] = 25; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGB10A2_UINT"), uint_value); + uint_value.value.uints[0] = 26; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGB10A2_UNORM"), uint_value); + uint_value.value.uints[0] = 27; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG11B10U_FLOAT"), uint_value); + uint_value.value.uints[0] = 28; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG32_UINT"), uint_value); + uint_value.value.uints[0] = 29; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG32_SINT"), uint_value); + uint_value.value.uints[0] = 30; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RG32_FLOAT"), uint_value); + uint_value.value.uints[0] = 31; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA16_UINT"), uint_value); + uint_value.value.uints[0] = 32; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA16_SINT"), uint_value); + uint_value.value.uints[0] = 33; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA16_FLOAT"), uint_value); + uint_value.value.uints[0] = 34; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA32_UINT"), uint_value); + uint_value.value.uints[0] = 35; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA32_SINT"), uint_value); + uint_value.value.uints[0] = 36; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_RGBA32_FLOAT"), uint_value); + uint_value.value.uints[0] = 37; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_DEPTH16_UNORM"), uint_value); + uint_value.value.uints[0] = 38; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_DEPTH24PLUS_NOTHING8"), uint_value); + uint_value.value.uints[0] = 39; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_DEPTH24PLUS_STENCIL8"), uint_value); + uint_value.value.uints[0] = 40; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_DEPTH32FLOAT"), uint_value); + uint_value.value.uints[0] = 41; + add_global_with_value(uint_id, attributes, add_name("TEXTURE_FORMAT_DEPTH32FLOAT_STENCIL8_NOTHING24"), uint_value); +} + +global_id add_global(type_id type, attribute_list attributes, name_id name) { + uint32_t index = globals_size; + globals[index].name = name; + globals[index].type = type; + globals[index].var_index = 0; + globals[index].value.kind = GLOBAL_VALUE_NONE; + globals[index].attributes = attributes; + globals[index].sets_count = 0; + globals_size += 1; + return index; +} + +global_id add_global_with_value(type_id type, attribute_list attributes, name_id name, global_value value) { + uint32_t index = globals_size; + globals[index].name = name; + globals[index].type = type; + globals[index].var_index = 0; + globals[index].value = value; + globals[index].attributes = attributes; + globals[index].sets_count = 0; + globals_size += 1; + return index; +} + +global *find_global(name_id name) { + for (uint32_t i = 0; i < globals_size; ++i) { + if (globals[i].name == name) { + return &globals[i]; + } + } + + return NULL; +} + +global *get_global(global_id id) { + if (id >= globals_size) { + return NULL; + } + + return &globals[id]; +} + +void assign_global_var(global_id id, uint64_t var_index) { + debug_context context = {0}; + check(id < globals_size, context, "Encountered a global with a weird id"); + globals[id].var_index = var_index; +} diff --git a/base/sources/libs/kong/sources/globals.h b/base/sources/libs/kong/sources/globals.h new file mode 100644 index 00000000..aa40f849 --- /dev/null +++ b/base/sources/libs/kong/sources/globals.h @@ -0,0 +1,54 @@ +#pragma once + +#include "names.h" +#include "types.h" + +typedef uint32_t global_id; + +typedef struct global_value { + enum { + GLOBAL_VALUE_FLOAT, + GLOBAL_VALUE_FLOAT2, + GLOBAL_VALUE_FLOAT3, + GLOBAL_VALUE_FLOAT4, + GLOBAL_VALUE_INT, + GLOBAL_VALUE_INT2, + GLOBAL_VALUE_INT3, + GLOBAL_VALUE_INT4, + GLOBAL_VALUE_UINT, + GLOBAL_VALUE_UINT2, + GLOBAL_VALUE_UINT3, + GLOBAL_VALUE_UINT4, + GLOBAL_VALUE_BOOL, + GLOBAL_VALUE_NONE + } kind; + union { + float floats[4]; + int ints[4]; + unsigned uints[4]; + bool b; + } value; +} global_value; + +struct descriptor_set; + +typedef struct global { + name_id name; + type_id type; + uint64_t var_index; + global_value value; + attribute_list attributes; + struct descriptor_set *sets[64]; + size_t sets_count; +} global; + +void globals_init(void); + +global_id add_global(type_id type, attribute_list attributes, name_id name); +global_id add_global_with_value(type_id type, attribute_list attributes, name_id name, global_value value); + +global *find_global(name_id name); + +global *get_global(global_id id); + +void assign_global_var(global_id id, uint64_t var_index); diff --git a/base/sources/libs/kong/sources/libs/dxc/LICENSE-LLVM.txt b/base/sources/libs/kong/sources/libs/dxc/LICENSE-LLVM.txt new file mode 100644 index 00000000..f7d5c8ee --- /dev/null +++ b/base/sources/libs/kong/sources/libs/dxc/LICENSE-LLVM.txt @@ -0,0 +1,43 @@ +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +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: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +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 +CONTRIBUTORS 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 WITH THE +SOFTWARE. diff --git a/base/sources/libs/kong/sources/libs/dxc/LICENSE-MIT.txt b/base/sources/libs/kong/sources/libs/dxc/LICENSE-MIT.txt new file mode 100644 index 00000000..44378268 --- /dev/null +++ b/base/sources/libs/kong/sources/libs/dxc/LICENSE-MIT.txt @@ -0,0 +1,21 @@ +Copyright (c) Microsoft Corporation. + +MIT License + +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. \ No newline at end of file diff --git a/base/sources/libs/kong/sources/libs/dxc/LICENSE-MS.txt b/base/sources/libs/kong/sources/libs/dxc/LICENSE-MS.txt new file mode 100644 index 00000000..384b174e --- /dev/null +++ b/base/sources/libs/kong/sources/libs/dxc/LICENSE-MS.txt @@ -0,0 +1,158 @@ +MICROSOFT SOFTWARE LICENSE TERMS + +MICROSOFT DIRECTX SHADER COMPILER + +These license terms are an agreement between you and Microsoft +Corporation (or one of its affiliates). They apply to the software named +above and any Microsoft services or software updates (except to the +extent such services or updates are accompanied by new or additional +terms, in which case those different terms apply prospectively and do +not alter your or Microsoft’s rights relating to pre-updated software or +services). IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS +BELOW. BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. + +INSTALLATION AND USE RIGHTS. + +General. Subject to the terms of this agreement, you may install and use any number of copies of the software, and solely for use on Windows. + +Included Microsoft Applications. The software may include other Microsoft applications. These license terms apply to those included applications, if any, unless other license terms are provided with the other Microsoft applications. + +Microsoft Platforms. The software may include components from Microsoft Windows. These components are governed by separate agreements and their own product support policies, as described in the license terms found in the installation directory for that component or in the “Licenses” folder accompanying the software. + +Third Party Components. The software may include third party components with separate legal notices or governed by other agreements, as may be described in the ThirdPartyNotices file(s) accompanying the software. + +DATA. + +Data Collection. The software may collect information about you and your use of the software, and send that to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may opt-out of many of these scenarios, but not all, as described in the product documentation.  There are also some features in the software that may enable you to collect data from users of your applications. If you use these features to enable data collection in your applications, you must comply with applicable law, including providing appropriate notices to users of your applications. You can learn more about data collection and use in the help documentation and the privacy statement at https://aka.ms/privacy. Your use of the software operates as your consent to these practices. + +Processing of Personal Data. To the extent Microsoft is a processor or subprocessor of personal data in connection with the software, Microsoft makes the commitments in the European Union General Data Protection Regulation Terms of the Online Services Terms to all customers effective May 25, 2018, at https://docs.microsoft.com/en-us/legal/gdpr. + +DISTRIBUTABLE CODE. The software may contain code you are permitted to distribute (i.e. make available for third parties) in applications you develop, as described in this Section. + +Distribution Rights. The code and test files described below are distributable if included with the software. + +Distributables. You may copy and distribute the object code form of the software listed in the distributables file list in the software; and + +Third Party Distribution. You may permit distributors of your applications to copy and distribute any of this distributable code you elect to distribute with your applications. + +Distribution Requirements. For any code you distribute, you must: + +add significant primary functionality to it in your applications; + +i. require distributors and external end users to agree to terms that protect it and Microsoft at least as much as this agreement; and + +ii. indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, related to the distribution or use of your applications, except to the extent that any claim is based solely on the unmodified distributable code. + +Distribution Restrictions. You may not: + +use Microsoft’s trademarks or trade dress in your application in any way that suggests your application comes from or is endorsed by Microsoft; or modify or distribute the source code of any distributable code so that any part of it becomes subject to any license that requires that the distributable code, any other part of the software, or any of Microsoft’s other intellectual property be disclosed or distributed in source code form, or that others have the right to modify it. + +SCOPE OF LICENSE. The software is licensed, not sold. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you will not (and have no right to): + +work around any technical limitations in the software that only allow you to use it in certain ways; + +reverse engineer, decompile or disassemble the software, or otherwise attempt to derive the source code for the software, except and to the extent required by third party licensing terms governing use of certain open source components that may be included in the software; + +remove, minimize, block, or modify any notices of Microsoft or its suppliers in the software; + +use the software in any way that is against the law or to create or propagate malware; or + +share, publish, distribute, or lease the software (except for any distributable code, subject to the terms above), provide the software as a stand-alone offering for others to use, or transfer the software or this agreement to any third party. + +EXPORT RESTRICTIONS. You must comply with all domestic and international export laws and regulations that apply to the software, which include restrictions on destinations, end users, and end use. For further information on export restrictions, visit https://aka.ms/exporting. + +SUPPORT SERVICES. Microsoft is not obligated under this agreement to provide any support services for the software. Any support provided is “as is”, “with all faults”, and without warranty of any kind. + +UPDATES. The software may periodically check for updates, and download and install them for you. You may obtain updates only from Microsoft or authorized sources. Microsoft may need to update your system to provide you with updates. You agree to receive these automatic updates without any additional notice. Updates may not include or support all existing software features, services, or peripheral devices. + +ENTIRE AGREEMENT. This agreement, and any other terms Microsoft may provide for supplements, updates, or third-party applications, is the entire agreement for the software. + +APPLICABLE LAW AND PLACE TO RESOLVE DISPUTES. If you acquired the software in the United States or Canada, the laws of the state or province where you live (or, if a business, where your principal place of business is located) govern the interpretation of this agreement, claims for its breach, and all other claims (including consumer protection, unfair competition, and tort claims), regardless of conflict of laws principles. If you acquired the software in any other country, its laws apply. If U.S. federal jurisdiction exists, you and Microsoft consent to exclusive jurisdiction and venue in the federal court in King County, Washington for all disputes heard in court. If not, you and Microsoft consent to exclusive jurisdiction and venue in the Superior Court of King County, Washington for all disputes heard in court. + +CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal rights. You may have other rights, including consumer rights, under the laws of your state or country. Separate and apart from your relationship with Microsoft, you may also have rights with respect to the party from which you acquired the software. This agreement does not change those other rights if the laws of your state or country do not permit it to do so. For example, if you acquired the software in one of the below regions, or mandatory country law applies, then the following provisions apply to you: + +a. Australia. You have statutory guarantees under the Australian + Consumer Law and nothing in this agreement is intended to affect + those rights. + +b. Canada. If you acquired this software in Canada, you may stop + receiving updates by turning off the automatic update feature, + disconnecting your device from the Internet (if and when you + re-connect to the Internet, however, the software will resume + checking for and installing updates), or uninstalling the software. + The product documentation, if any, may also specify how to turn off + updates for your specific device or software. + +c. Germany and Austria. + + i. Warranty. The properly licensed software will perform substantially + as described in any Microsoft materials that accompany the software. + However, Microsoft gives no contractual guarantee in relation to the + licensed software. + + ii. Limitation of Liability. In case of intentional conduct, gross + negligence, claims based on the Product Liability Act, as well as, in + case of death or personal or physical injury, Microsoft is liable + according to the statutory law. + +Subject to the foregoing clause ii., Microsoft will only be liable for slight negligence if Microsoft is in breach of such material contractual obligations, the fulfillment of which facilitate the due performance of this agreement, the breach of which would endanger the purpose of this agreement and the compliance with which a party may constantly trust in (so-called "cardinal obligations"). In other cases of slight negligence, Microsoft will not be liable for slight negligence. + +DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS IS.” YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES, OR CONDITIONS. TO THE EXTENT PERMITTED UNDER APPLICABLE LAWS, MICROSOFT EXCLUDES ALL IMPLIED WARRANTIES, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + +LIMITATION ON AND EXCLUSION OF DAMAGES. IF YOU HAVE ANY BASIS FOR RECOVERING DAMAGES DESPITE THE PRECEDING DISCLAIMER OF WARRANTY, YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT, OR INCIDENTAL DAMAGES. + +This limitation applies to (a) anything related to the software, +services, content (including code) on third party Internet sites, or +third party applications; and (b) claims for breach of contract, +warranty, guarantee, or condition; strict liability, negligence, or +other tort; or any other claim; in each case to the extent permitted by +applicable law. + +It also applies even if Microsoft knew or should have known about the +possibility of the damages. The above limitation or exclusion may not +apply to you because your state, province, or country may not allow the +exclusion or limitation of incidental, consequential, or other damages. + +Please note: As this software is distributed in Canada, some of the +clauses in this agreement are provided below in French. + +Remarque: Ce logiciel étant distribué au Canada, certaines des clauses +dans ce contrat sont fournies ci-dessous en français. + +EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « +tel quel ». Toute utilisation de ce logiciel est à votre seule risque et +péril. Microsoft n’accorde aucune autre garantie expresse. Vous pouvez +bénéficier de droits additionnels en vertu du droit local sur la +protection des consommateurs, que ce contrat ne peut modifier. La ou +elles sont permises par le droit locale, les garanties implicites de +qualité marchande, d’adéquation à un usage particulier et d’absence de +contrefaçon sont exclues. + +LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES +DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une +indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ +US. Vous ne pouvez prétendre à aucune indemnisation pour les autres +dommages, y compris les dommages spéciaux, indirects ou accessoires et +pertes de bénéfices. + +Cette limitation concerne: + +• tout ce qui est relié au logiciel, aux services ou au contenu (y +compris le code) figurant sur des sites Internet tiers ou dans des +programmes tiers; et + +• les réclamations au titre de violation de contrat ou de garantie, ou +au titre de responsabilité stricte, de négligence ou d’une autre faute +dans la limite autorisée par la loi en vigueur. + +Elle s’applique également, même si Microsoft connaissait ou devrait +connaître l’éventualité d’un tel dommage. Si votre pays n’autorise pas +l’exclusion ou la limitation de responsabilité pour les dommages +indirects, accessoires ou de quelque nature que ce soit, il se peut que +la limitation ou l’exclusion ci-dessus ne s’appliquera pas à votre +égard. + +EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. +Vous pourriez avoir d’autres droits prévus par les lois de votre pays. +Le présent contrat ne modifie pas les droits que vous confèrent les lois +de votre pays si celles-ci ne le permettent pas. diff --git a/base/sources/libs/kong/sources/libs/dxc/README.md b/base/sources/libs/kong/sources/libs/dxc/README.md new file mode 100644 index 00000000..b29f4d40 --- /dev/null +++ b/base/sources/libs/kong/sources/libs/dxc/README.md @@ -0,0 +1,149 @@ +# DirectX Shader Compiler Redistributable Package + +This package contains a copy of the DirectX Shader Compiler redistributable and its associated development headers. + +For help getting started, please see: + +https://github.com/microsoft/DirectXShaderCompiler/wiki + +## Licenses + +The included licenses apply to the following files: + +| License file | Applies to | +|---|---| +|LICENSE-MS.txt |dxil.dll (if included in package)| +|LICENSE-MIT.txt |d3d12shader.h| +|LICENSE-LLVM.txt |all other files| + +## Changelog + +### Version 1.8.2405 + +DX Compiler Relase for May 2024 + +This release includes two major new elements: +- The introduction of the first component of HLSL 202x +- The inclusion of clang-built Windows binaries + +See [the official blog post](https://devblogs.microsoft.com/directx/dxc-1-8-2405-available) for a more detailed description of this release. + +HLSL 202x is a placeholder designation for what will ultimately be a new language version that further aligns HLSL with modern language features. It is intended to serve as a bridge to help transition to the expected behavior of the modernized compiler. + +To experiment with 202x, use the `-HV 202x` flag. We recommend enabling these warnings as well to catch potential changes in behavior: `-Wconversion -Wdouble-promotion -Whlsl-legacy-literal`. + +The first feature available in 202x updates HLSL's treatment of literals to better conform with C/C++. In previous versions, un-suffixed literal types targeted the highest possible precision. This feature revises that to mostly conform with C/C++ behavior. See the above blog post for details. + +Clang-built Windows binaries are included in addition to the MSVC-built binaries that have always been shipped before. The clang-built compiler is expected to improve HLSL compile times in many cases. We are eager for feedback about this build positive or negative, related to compile times or correctness. + +### Version 1.8.2403.2 + +DX Compiler Release for March 2024 - Patch 2 + +- Fix regression: [#6426](https://github.com/microsoft/DirectXShaderCompiler/issues/6426) Regression, SIGSEGV instead of diagnostics when encountering bool operator==(const T&, const T&). + +### Version 1.8.2403.1 + +DX Compiler Release for March 2024 - Patch 1 + +- Fix regression: [#6419](https://github.com/microsoft/DirectXShaderCompiler/issues/6419) crash when using literal arguments with `fmod`. + +### Version 1.8.2403 + +DX Compiler release for March 2024 + +- Shader Model 6.8 is fully supported + - Work Graphs allow node shaders with user-defined input and output payloads + - New Barrier builtin functions with specific memory types and semantics + - Expanded Comparison sampler intrinsics: SampleCmpBias, SampleCmpGrad, and CalculateLevelOfDetail + - StartVertexLocation and StartInstanceLocation semantics + - WaveSizeRange entry point attribute allows specifying a range of supported wave sizes +- Improved compile-time validation and runtime validation information +- Various stability improvements including numerous address sanitation fixes +- Several Diagnostic improvements + - Many diagnostics are generated earlier and with more detailed information + - Library profile diagnostic improvements + - No longer infer library shader type when not specified + - More helpful diagnostics for numthreads and other entry point attributes + - Validation errors more accurately determine usage by the entry point +- Improve debug info generation +- Further improvements to Linux build quality + + +### Version 1.7.2308 + +DX Compiler release for August 2023 + +- HLSL 2021 is now enabled by default +- Various HLSL 2021 fixes have been made to + - Operator overloading fixes + - Templates fixes + - Select() with samplers + - Bitfields show in reflections + - Bitfields can be used on enums + - Allow function template default params +- Issues with loading and using Linux binaries have been resolved +- Support #pragma region/endregion +- Various stability and diagnostic improvements +- Dxcapi.h inline documentation is improved +- Linking of libraries created by different compilers is disallowed to prevent interface Issues +- Inout parameter correctness improved + + +The package includes dxc.exe, dxcompiler.dll, corresponding lib and headers, and dxil.dll for x64 and arm64 platforms on Windows. +The package also includes Linux version of the compiler with corresponding executable, libdxcompiler.so, corresponding headers, and libdxil.so for x64 platforms. + +The new DirectX 12 Agility SDK (Microsoft.Direct3D.D3D12 nuget package) and a hardware driver with appropriate support +are required to run shader model 6.7 shaders. Please see https://aka.ms/directx12agility for details. + +The SPIR-V backend of the compiler has been enabled in this release. + +### Version 1.7.2212 + +DX Compiler release for December 2022. + +- Includes full support of HLSL 2021 for SPIRV generation as well as many HLSL 2021 fixes and enhancements: + - HLSL 2021's `and`, `or` and `select` intrinsics are now exposed in all language modes. This was done to ease porting codebases to HLSL2021, but may cause name conflicts in existing code. + - Improved template utility with user-defined types + - Many additional bug fixes +- Linux binaries are now included. + This includes the compiler executable, the dynamic library, and the dxil signing library. +- New flags for inspecting compile times: + - `-ftime-report` flag prints a high level summary of compile time broken down by major phase or pass in the compiler. The DXC +command line will print the output to stdout. + - `-ftime-trace` flag prints a Chrome trace json file. The output can be routed to a specific file by providing a filename to +the arguent using the format `-ftime-trace=`. Chrome trace files can be opened in Chrome by loading the built-in tracing tool +at chrome://tracing. The trace file captures hierarchial timing data with additional context enabling a much more in-depth profiling +experience. + - Both new options are supported via the DXC API using the `DXC_OUT_TIME_REPORT` and `DXC_OUT_TIME_TRACE` output kinds respectively. +- IDxcPdbUtils2 enables reading new PDB container part +- `-P` flag will now behave as it does with cl using the file specified by `-Fi` or a default +- Unbound multidimensional resource arrays are allowed +- Diagnostic improvements +- Reflection support on non-Windows platforms; minor updates adding RequiredFeatureFlags to library function reflection and thread group size for AS and MS. + +The package includes dxc.exe, dxcompiler.dll, corresponding lib and headers, and dxil.dll for x64 and arm64 platforms on Windows. +For the first time the package also includes Linux version of the compiler with corresponding executable, libdxcompiler.so, corresponding headers, and libdxil.so for x64 platforms. + +The new DirectX 12 Agility SDK (Microsoft.Direct3D.D3D12 nuget package) and a hardware driver with appropriate support +are required to run shader model 6.7 shaders. Please see https://aka.ms/directx12agility for details. + +The SPIR-V backend of the compiler has been enabled in this release. Please note that Microsoft does not perform testing/verification of the SPIR-V backend. + + +### Version 1.7.2207 + +DX Compiler release for July 2022. Contains shader model 6.7 and many bug fixes and improvements, such as: + +- Features: Shader Model 6.7 includes support for Raw Gather, Programmable Offsets, QuadAny/QuadAll, WaveOpsIncludeHelperLanes, and more! +- Platforms: ARM64 support +- HLSL 2021 : Enable “using” keyword +- Optimizations: Loop unrolling and dead code elimination improvements +- Developer tools: Improved disassembly output + +The package includes dxc.exe, dxcompiler.dll, corresponding lib and headers, and dxil.dll for x64 and, for the first time, arm64 platforms! + +The new DirectX 12 Agility SDK (Microsoft.Direct3D.D3D12 nuget package) and a hardware driver with appropriate support +are required to run shader model 6.7 shaders. Please see https://aka.ms/directx12agility for details. + +The SPIR-V backend of the compiler has been enabled in this release. Please note that Microsoft does not perform testing/verification of the SPIR-V backend. diff --git a/base/sources/libs/kong/sources/libs/dxc/inc/d3d12shader.h b/base/sources/libs/kong/sources/libs/dxc/inc/d3d12shader.h new file mode 100644 index 00000000..808bfc0c --- /dev/null +++ b/base/sources/libs/kong/sources/libs/dxc/inc/d3d12shader.h @@ -0,0 +1,487 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// +// File: D3D12Shader.h +// Content: D3D12 Shader Types and APIs +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __D3D12SHADER_H__ +#define __D3D12SHADER_H__ + +#include "d3dcommon.h" + +typedef enum D3D12_SHADER_VERSION_TYPE +{ + D3D12_SHVER_PIXEL_SHADER = 0, + D3D12_SHVER_VERTEX_SHADER = 1, + D3D12_SHVER_GEOMETRY_SHADER = 2, + + // D3D11 Shaders + D3D12_SHVER_HULL_SHADER = 3, + D3D12_SHVER_DOMAIN_SHADER = 4, + D3D12_SHVER_COMPUTE_SHADER = 5, + + // D3D12 Shaders + D3D12_SHVER_LIBRARY = 6, + + D3D12_SHVER_RAY_GENERATION_SHADER = 7, + D3D12_SHVER_INTERSECTION_SHADER = 8, + D3D12_SHVER_ANY_HIT_SHADER = 9, + D3D12_SHVER_CLOSEST_HIT_SHADER = 10, + D3D12_SHVER_MISS_SHADER = 11, + D3D12_SHVER_CALLABLE_SHADER = 12, + + D3D12_SHVER_MESH_SHADER = 13, + D3D12_SHVER_AMPLIFICATION_SHADER = 14, + + D3D12_SHVER_RESERVED0 = 0xFFF0, +} D3D12_SHADER_VERSION_TYPE; + +#define D3D12_SHVER_GET_TYPE(_Version) \ + (((_Version) >> 16) & 0xffff) +#define D3D12_SHVER_GET_MAJOR(_Version) \ + (((_Version) >> 4) & 0xf) +#define D3D12_SHVER_GET_MINOR(_Version) \ + (((_Version) >> 0) & 0xf) + +// Slot ID for library function return +#define D3D_RETURN_PARAMETER_INDEX (-1) + +typedef D3D_RESOURCE_RETURN_TYPE D3D12_RESOURCE_RETURN_TYPE; + +typedef D3D_CBUFFER_TYPE D3D12_CBUFFER_TYPE; + + +typedef struct _D3D12_SIGNATURE_PARAMETER_DESC +{ + LPCSTR SemanticName; // Name of the semantic + UINT SemanticIndex; // Index of the semantic + UINT Register; // Number of member variables + D3D_NAME SystemValueType;// A predefined system value, or D3D_NAME_UNDEFINED if not applicable + D3D_REGISTER_COMPONENT_TYPE ComponentType; // Scalar type (e.g. uint, float, etc.) + BYTE Mask; // Mask to indicate which components of the register + // are used (combination of D3D10_COMPONENT_MASK values) + BYTE ReadWriteMask; // Mask to indicate whether a given component is + // never written (if this is an output signature) or + // always read (if this is an input signature). + // (combination of D3D_MASK_* values) + UINT Stream; // Stream index + D3D_MIN_PRECISION MinPrecision; // Minimum desired interpolation precision +} D3D12_SIGNATURE_PARAMETER_DESC; + +typedef struct _D3D12_SHADER_BUFFER_DESC +{ + LPCSTR Name; // Name of the constant buffer + D3D_CBUFFER_TYPE Type; // Indicates type of buffer content + UINT Variables; // Number of member variables + UINT Size; // Size of CB (in bytes) + UINT uFlags; // Buffer description flags +} D3D12_SHADER_BUFFER_DESC; + +typedef struct _D3D12_SHADER_VARIABLE_DESC +{ + LPCSTR Name; // Name of the variable + UINT StartOffset; // Offset in constant buffer's backing store + UINT Size; // Size of variable (in bytes) + UINT uFlags; // Variable flags + LPVOID DefaultValue; // Raw pointer to default value + UINT StartTexture; // First texture index (or -1 if no textures used) + UINT TextureSize; // Number of texture slots possibly used. + UINT StartSampler; // First sampler index (or -1 if no textures used) + UINT SamplerSize; // Number of sampler slots possibly used. +} D3D12_SHADER_VARIABLE_DESC; + +typedef struct _D3D12_SHADER_TYPE_DESC +{ + D3D_SHADER_VARIABLE_CLASS Class; // Variable class (e.g. object, matrix, etc.) + D3D_SHADER_VARIABLE_TYPE Type; // Variable type (e.g. float, sampler, etc.) + UINT Rows; // Number of rows (for matrices, 1 for other numeric, 0 if not applicable) + UINT Columns; // Number of columns (for vectors & matrices, 1 for other numeric, 0 if not applicable) + UINT Elements; // Number of elements (0 if not an array) + UINT Members; // Number of members (0 if not a structure) + UINT Offset; // Offset from the start of structure (0 if not a structure member) + LPCSTR Name; // Name of type, can be NULL +} D3D12_SHADER_TYPE_DESC; + +typedef D3D_TESSELLATOR_DOMAIN D3D12_TESSELLATOR_DOMAIN; + +typedef D3D_TESSELLATOR_PARTITIONING D3D12_TESSELLATOR_PARTITIONING; + +typedef D3D_TESSELLATOR_OUTPUT_PRIMITIVE D3D12_TESSELLATOR_OUTPUT_PRIMITIVE; + +typedef struct _D3D12_SHADER_DESC +{ + UINT Version; // Shader version + LPCSTR Creator; // Creator string + UINT Flags; // Shader compilation/parse flags + + UINT ConstantBuffers; // Number of constant buffers + UINT BoundResources; // Number of bound resources + UINT InputParameters; // Number of parameters in the input signature + UINT OutputParameters; // Number of parameters in the output signature + + UINT InstructionCount; // Number of emitted instructions + UINT TempRegisterCount; // Number of temporary registers used + UINT TempArrayCount; // Number of temporary arrays used + UINT DefCount; // Number of constant defines + UINT DclCount; // Number of declarations (input + output) + UINT TextureNormalInstructions; // Number of non-categorized texture instructions + UINT TextureLoadInstructions; // Number of texture load instructions + UINT TextureCompInstructions; // Number of texture comparison instructions + UINT TextureBiasInstructions; // Number of texture bias instructions + UINT TextureGradientInstructions; // Number of texture gradient instructions + UINT FloatInstructionCount; // Number of floating point arithmetic instructions used + UINT IntInstructionCount; // Number of signed integer arithmetic instructions used + UINT UintInstructionCount; // Number of unsigned integer arithmetic instructions used + UINT StaticFlowControlCount; // Number of static flow control instructions used + UINT DynamicFlowControlCount; // Number of dynamic flow control instructions used + UINT MacroInstructionCount; // Number of macro instructions used + UINT ArrayInstructionCount; // Number of array instructions used + UINT CutInstructionCount; // Number of cut instructions used + UINT EmitInstructionCount; // Number of emit instructions used + D3D_PRIMITIVE_TOPOLOGY GSOutputTopology; // Geometry shader output topology + UINT GSMaxOutputVertexCount; // Geometry shader maximum output vertex count + D3D_PRIMITIVE InputPrimitive; // GS/HS input primitive + UINT PatchConstantParameters; // Number of parameters in the patch constant signature + UINT cGSInstanceCount; // Number of Geometry shader instances + UINT cControlPoints; // Number of control points in the HS->DS stage + D3D_TESSELLATOR_OUTPUT_PRIMITIVE HSOutputPrimitive; // Primitive output by the tessellator + D3D_TESSELLATOR_PARTITIONING HSPartitioning; // Partitioning mode of the tessellator + D3D_TESSELLATOR_DOMAIN TessellatorDomain; // Domain of the tessellator (quad, tri, isoline) + // instruction counts + UINT cBarrierInstructions; // Number of barrier instructions in a compute shader + UINT cInterlockedInstructions; // Number of interlocked instructions + UINT cTextureStoreInstructions; // Number of texture writes +} D3D12_SHADER_DESC; + +typedef struct _D3D12_SHADER_INPUT_BIND_DESC +{ + LPCSTR Name; // Name of the resource + D3D_SHADER_INPUT_TYPE Type; // Type of resource (e.g. texture, cbuffer, etc.) + UINT BindPoint; // Starting bind point + UINT BindCount; // Number of contiguous bind points (for arrays) + + UINT uFlags; // Input binding flags + D3D_RESOURCE_RETURN_TYPE ReturnType; // Return type (if texture) + D3D_SRV_DIMENSION Dimension; // Dimension (if texture) + UINT NumSamples; // Number of samples (0 if not MS texture) + UINT Space; // Register space + UINT uID; // Range ID in the bytecode +} D3D12_SHADER_INPUT_BIND_DESC; + +#define D3D_SHADER_REQUIRES_DOUBLES 0x00000001 +#define D3D_SHADER_REQUIRES_EARLY_DEPTH_STENCIL 0x00000002 +#define D3D_SHADER_REQUIRES_UAVS_AT_EVERY_STAGE 0x00000004 +#define D3D_SHADER_REQUIRES_64_UAVS 0x00000008 +#define D3D_SHADER_REQUIRES_MINIMUM_PRECISION 0x00000010 +#define D3D_SHADER_REQUIRES_11_1_DOUBLE_EXTENSIONS 0x00000020 +#define D3D_SHADER_REQUIRES_11_1_SHADER_EXTENSIONS 0x00000040 +#define D3D_SHADER_REQUIRES_LEVEL_9_COMPARISON_FILTERING 0x00000080 +#define D3D_SHADER_REQUIRES_TILED_RESOURCES 0x00000100 +#define D3D_SHADER_REQUIRES_STENCIL_REF 0x00000200 +#define D3D_SHADER_REQUIRES_INNER_COVERAGE 0x00000400 +#define D3D_SHADER_REQUIRES_TYPED_UAV_LOAD_ADDITIONAL_FORMATS 0x00000800 +#define D3D_SHADER_REQUIRES_ROVS 0x00001000 +#define D3D_SHADER_REQUIRES_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER 0x00002000 +#define D3D_SHADER_REQUIRES_WAVE_OPS 0x00004000 +#define D3D_SHADER_REQUIRES_INT64_OPS 0x00008000 +#define D3D_SHADER_REQUIRES_VIEW_ID 0x00010000 +#define D3D_SHADER_REQUIRES_BARYCENTRICS 0x00020000 +#define D3D_SHADER_REQUIRES_NATIVE_16BIT_OPS 0x00040000 +#define D3D_SHADER_REQUIRES_SHADING_RATE 0x00080000 +#define D3D_SHADER_REQUIRES_RAYTRACING_TIER_1_1 0x00100000 +#define D3D_SHADER_REQUIRES_SAMPLER_FEEDBACK 0x00200000 +#define D3D_SHADER_REQUIRES_ATOMIC_INT64_ON_TYPED_RESOURCE 0x00400000 +#define D3D_SHADER_REQUIRES_ATOMIC_INT64_ON_GROUP_SHARED 0x00800000 +#define D3D_SHADER_REQUIRES_DERIVATIVES_IN_MESH_AND_AMPLIFICATION_SHADERS 0x01000000 +#define D3D_SHADER_REQUIRES_RESOURCE_DESCRIPTOR_HEAP_INDEXING 0x02000000 +#define D3D_SHADER_REQUIRES_SAMPLER_DESCRIPTOR_HEAP_INDEXING 0x04000000 +#define D3D_SHADER_REQUIRES_WAVE_MMA 0x08000000 +#define D3D_SHADER_REQUIRES_ATOMIC_INT64_ON_DESCRIPTOR_HEAP_RESOURCE 0x10000000 + +typedef struct _D3D12_LIBRARY_DESC +{ + LPCSTR Creator; // The name of the originator of the library. + UINT Flags; // Compilation flags. + UINT FunctionCount; // Number of functions exported from the library. +} D3D12_LIBRARY_DESC; + +typedef struct _D3D12_FUNCTION_DESC +{ + UINT Version; // Shader version + LPCSTR Creator; // Creator string + UINT Flags; // Shader compilation/parse flags + + UINT ConstantBuffers; // Number of constant buffers + UINT BoundResources; // Number of bound resources + + UINT InstructionCount; // Number of emitted instructions + UINT TempRegisterCount; // Number of temporary registers used + UINT TempArrayCount; // Number of temporary arrays used + UINT DefCount; // Number of constant defines + UINT DclCount; // Number of declarations (input + output) + UINT TextureNormalInstructions; // Number of non-categorized texture instructions + UINT TextureLoadInstructions; // Number of texture load instructions + UINT TextureCompInstructions; // Number of texture comparison instructions + UINT TextureBiasInstructions; // Number of texture bias instructions + UINT TextureGradientInstructions; // Number of texture gradient instructions + UINT FloatInstructionCount; // Number of floating point arithmetic instructions used + UINT IntInstructionCount; // Number of signed integer arithmetic instructions used + UINT UintInstructionCount; // Number of unsigned integer arithmetic instructions used + UINT StaticFlowControlCount; // Number of static flow control instructions used + UINT DynamicFlowControlCount; // Number of dynamic flow control instructions used + UINT MacroInstructionCount; // Number of macro instructions used + UINT ArrayInstructionCount; // Number of array instructions used + UINT MovInstructionCount; // Number of mov instructions used + UINT MovcInstructionCount; // Number of movc instructions used + UINT ConversionInstructionCount; // Number of type conversion instructions used + UINT BitwiseInstructionCount; // Number of bitwise arithmetic instructions used + D3D_FEATURE_LEVEL MinFeatureLevel; // Min target of the function byte code + UINT64 RequiredFeatureFlags; // Required feature flags + + LPCSTR Name; // Function name + INT FunctionParameterCount; // Number of logical parameters in the function signature (not including return) + BOOL HasReturn; // TRUE, if function returns a value, false - it is a subroutine + BOOL Has10Level9VertexShader; // TRUE, if there is a 10L9 VS blob + BOOL Has10Level9PixelShader; // TRUE, if there is a 10L9 PS blob +} D3D12_FUNCTION_DESC; + +typedef struct _D3D12_PARAMETER_DESC +{ + LPCSTR Name; // Parameter name. + LPCSTR SemanticName; // Parameter semantic name (+index). + D3D_SHADER_VARIABLE_TYPE Type; // Element type. + D3D_SHADER_VARIABLE_CLASS Class; // Scalar/Vector/Matrix. + UINT Rows; // Rows are for matrix parameters. + UINT Columns; // Components or Columns in matrix. + D3D_INTERPOLATION_MODE InterpolationMode; // Interpolation mode. + D3D_PARAMETER_FLAGS Flags; // Parameter modifiers. + + UINT FirstInRegister; // The first input register for this parameter. + UINT FirstInComponent; // The first input register component for this parameter. + UINT FirstOutRegister; // The first output register for this parameter. + UINT FirstOutComponent; // The first output register component for this parameter. +} D3D12_PARAMETER_DESC; + + +////////////////////////////////////////////////////////////////////////////// +// Interfaces //////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +typedef interface ID3D12ShaderReflectionType ID3D12ShaderReflectionType; +typedef interface ID3D12ShaderReflectionType *LPD3D12SHADERREFLECTIONTYPE; + +typedef interface ID3D12ShaderReflectionVariable ID3D12ShaderReflectionVariable; +typedef interface ID3D12ShaderReflectionVariable *LPD3D12SHADERREFLECTIONVARIABLE; + +typedef interface ID3D12ShaderReflectionConstantBuffer ID3D12ShaderReflectionConstantBuffer; +typedef interface ID3D12ShaderReflectionConstantBuffer *LPD3D12SHADERREFLECTIONCONSTANTBUFFER; + +typedef interface ID3D12ShaderReflection ID3D12ShaderReflection; +typedef interface ID3D12ShaderReflection *LPD3D12SHADERREFLECTION; + +typedef interface ID3D12LibraryReflection ID3D12LibraryReflection; +typedef interface ID3D12LibraryReflection *LPD3D12LIBRARYREFLECTION; + +typedef interface ID3D12FunctionReflection ID3D12FunctionReflection; +typedef interface ID3D12FunctionReflection *LPD3D12FUNCTIONREFLECTION; + +typedef interface ID3D12FunctionParameterReflection ID3D12FunctionParameterReflection; +typedef interface ID3D12FunctionParameterReflection *LPD3D12FUNCTIONPARAMETERREFLECTION; + + +// {E913C351-783D-48CA-A1D1-4F306284AD56} +interface DECLSPEC_UUID("E913C351-783D-48CA-A1D1-4F306284AD56") ID3D12ShaderReflectionType; +DEFINE_GUID(IID_ID3D12ShaderReflectionType, +0xe913c351, 0x783d, 0x48ca, 0xa1, 0xd1, 0x4f, 0x30, 0x62, 0x84, 0xad, 0x56); + +#undef INTERFACE +#define INTERFACE ID3D12ShaderReflectionType + +DECLARE_INTERFACE(ID3D12ShaderReflectionType) +{ + STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_SHADER_TYPE_DESC *pDesc) PURE; + + STDMETHOD_(ID3D12ShaderReflectionType*, GetMemberTypeByIndex)(THIS_ _In_ UINT Index) PURE; + STDMETHOD_(ID3D12ShaderReflectionType*, GetMemberTypeByName)(THIS_ _In_ LPCSTR Name) PURE; + STDMETHOD_(LPCSTR, GetMemberTypeName)(THIS_ _In_ UINT Index) PURE; + + STDMETHOD(IsEqual)(THIS_ _In_ ID3D12ShaderReflectionType* pType) PURE; + STDMETHOD_(ID3D12ShaderReflectionType*, GetSubType)(THIS) PURE; + STDMETHOD_(ID3D12ShaderReflectionType*, GetBaseClass)(THIS) PURE; + STDMETHOD_(UINT, GetNumInterfaces)(THIS) PURE; + STDMETHOD_(ID3D12ShaderReflectionType*, GetInterfaceByIndex)(THIS_ _In_ UINT uIndex) PURE; + STDMETHOD(IsOfType)(THIS_ _In_ ID3D12ShaderReflectionType* pType) PURE; + STDMETHOD(ImplementsInterface)(THIS_ _In_ ID3D12ShaderReflectionType* pBase) PURE; +}; + +// {8337A8A6-A216-444A-B2F4-314733A73AEA} +interface DECLSPEC_UUID("8337A8A6-A216-444A-B2F4-314733A73AEA") ID3D12ShaderReflectionVariable; +DEFINE_GUID(IID_ID3D12ShaderReflectionVariable, +0x8337a8a6, 0xa216, 0x444a, 0xb2, 0xf4, 0x31, 0x47, 0x33, 0xa7, 0x3a, 0xea); + +#undef INTERFACE +#define INTERFACE ID3D12ShaderReflectionVariable + +DECLARE_INTERFACE(ID3D12ShaderReflectionVariable) +{ + STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_SHADER_VARIABLE_DESC *pDesc) PURE; + + STDMETHOD_(ID3D12ShaderReflectionType*, GetType)(THIS) PURE; + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer*, GetBuffer)(THIS) PURE; + + STDMETHOD_(UINT, GetInterfaceSlot)(THIS_ _In_ UINT uArrayIndex) PURE; +}; + +// {C59598B4-48B3-4869-B9B1-B1618B14A8B7} +interface DECLSPEC_UUID("C59598B4-48B3-4869-B9B1-B1618B14A8B7") ID3D12ShaderReflectionConstantBuffer; +DEFINE_GUID(IID_ID3D12ShaderReflectionConstantBuffer, +0xc59598b4, 0x48b3, 0x4869, 0xb9, 0xb1, 0xb1, 0x61, 0x8b, 0x14, 0xa8, 0xb7); + +#undef INTERFACE +#define INTERFACE ID3D12ShaderReflectionConstantBuffer + +DECLARE_INTERFACE(ID3D12ShaderReflectionConstantBuffer) +{ + STDMETHOD(GetDesc)(THIS_ D3D12_SHADER_BUFFER_DESC *pDesc) PURE; + + STDMETHOD_(ID3D12ShaderReflectionVariable*, GetVariableByIndex)(THIS_ _In_ UINT Index) PURE; + STDMETHOD_(ID3D12ShaderReflectionVariable*, GetVariableByName)(THIS_ _In_ LPCSTR Name) PURE; +}; + +// The ID3D12ShaderReflection IID may change from SDK version to SDK version +// if the reflection API changes. This prevents new code with the new API +// from working with an old binary. Recompiling with the new header +// will pick up the new IID. + +// {5A58797D-A72C-478D-8BA2-EFC6B0EFE88E} +interface DECLSPEC_UUID("5A58797D-A72C-478D-8BA2-EFC6B0EFE88E") ID3D12ShaderReflection; +DEFINE_GUID(IID_ID3D12ShaderReflection, +0x5a58797d, 0xa72c, 0x478d, 0x8b, 0xa2, 0xef, 0xc6, 0xb0, 0xef, 0xe8, 0x8e); + +#undef INTERFACE +#define INTERFACE ID3D12ShaderReflection + +DECLARE_INTERFACE_(ID3D12ShaderReflection, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ _In_ REFIID iid, + _Out_ LPVOID *ppv) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_SHADER_DESC *pDesc) PURE; + + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer*, GetConstantBufferByIndex)(THIS_ _In_ UINT Index) PURE; + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer*, GetConstantBufferByName)(THIS_ _In_ LPCSTR Name) PURE; + + STDMETHOD(GetResourceBindingDesc)(THIS_ _In_ UINT ResourceIndex, + _Out_ D3D12_SHADER_INPUT_BIND_DESC *pDesc) PURE; + + STDMETHOD(GetInputParameterDesc)(THIS_ _In_ UINT ParameterIndex, + _Out_ D3D12_SIGNATURE_PARAMETER_DESC *pDesc) PURE; + STDMETHOD(GetOutputParameterDesc)(THIS_ _In_ UINT ParameterIndex, + _Out_ D3D12_SIGNATURE_PARAMETER_DESC *pDesc) PURE; + STDMETHOD(GetPatchConstantParameterDesc)(THIS_ _In_ UINT ParameterIndex, + _Out_ D3D12_SIGNATURE_PARAMETER_DESC *pDesc) PURE; + + STDMETHOD_(ID3D12ShaderReflectionVariable*, GetVariableByName)(THIS_ _In_ LPCSTR Name) PURE; + + STDMETHOD(GetResourceBindingDescByName)(THIS_ _In_ LPCSTR Name, + _Out_ D3D12_SHADER_INPUT_BIND_DESC *pDesc) PURE; + + STDMETHOD_(UINT, GetMovInstructionCount)(THIS) PURE; + STDMETHOD_(UINT, GetMovcInstructionCount)(THIS) PURE; + STDMETHOD_(UINT, GetConversionInstructionCount)(THIS) PURE; + STDMETHOD_(UINT, GetBitwiseInstructionCount)(THIS) PURE; + + STDMETHOD_(D3D_PRIMITIVE, GetGSInputPrimitive)(THIS) PURE; + STDMETHOD_(BOOL, IsSampleFrequencyShader)(THIS) PURE; + + STDMETHOD_(UINT, GetNumInterfaceSlots)(THIS) PURE; + STDMETHOD(GetMinFeatureLevel)(THIS_ _Out_ enum D3D_FEATURE_LEVEL* pLevel) PURE; + + STDMETHOD_(UINT, GetThreadGroupSize)(THIS_ + _Out_opt_ UINT* pSizeX, + _Out_opt_ UINT* pSizeY, + _Out_opt_ UINT* pSizeZ) PURE; + + STDMETHOD_(UINT64, GetRequiresFlags)(THIS) PURE; +}; + +// {8E349D19-54DB-4A56-9DC9-119D87BDB804} +interface DECLSPEC_UUID("8E349D19-54DB-4A56-9DC9-119D87BDB804") ID3D12LibraryReflection; +DEFINE_GUID(IID_ID3D12LibraryReflection, +0x8e349d19, 0x54db, 0x4a56, 0x9d, 0xc9, 0x11, 0x9d, 0x87, 0xbd, 0xb8, 0x4); + +#undef INTERFACE +#define INTERFACE ID3D12LibraryReflection + +DECLARE_INTERFACE_(ID3D12LibraryReflection, IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ _In_ REFIID iid, _Out_ LPVOID * ppv) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_LIBRARY_DESC * pDesc) PURE; + + STDMETHOD_(ID3D12FunctionReflection *, GetFunctionByIndex)(THIS_ _In_ INT FunctionIndex) PURE; +}; + +// {1108795C-2772-4BA9-B2A8-D464DC7E2799} +interface DECLSPEC_UUID("1108795C-2772-4BA9-B2A8-D464DC7E2799") ID3D12FunctionReflection; +DEFINE_GUID(IID_ID3D12FunctionReflection, +0x1108795c, 0x2772, 0x4ba9, 0xb2, 0xa8, 0xd4, 0x64, 0xdc, 0x7e, 0x27, 0x99); + +#undef INTERFACE +#define INTERFACE ID3D12FunctionReflection + +DECLARE_INTERFACE(ID3D12FunctionReflection) +{ + STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_FUNCTION_DESC * pDesc) PURE; + + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByIndex)(THIS_ _In_ UINT BufferIndex) PURE; + STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByName)(THIS_ _In_ LPCSTR Name) PURE; + + STDMETHOD(GetResourceBindingDesc)(THIS_ _In_ UINT ResourceIndex, + _Out_ D3D12_SHADER_INPUT_BIND_DESC * pDesc) PURE; + + STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByName)(THIS_ _In_ LPCSTR Name) PURE; + + STDMETHOD(GetResourceBindingDescByName)(THIS_ _In_ LPCSTR Name, + _Out_ D3D12_SHADER_INPUT_BIND_DESC * pDesc) PURE; + + // Use D3D_RETURN_PARAMETER_INDEX to get description of the return value. + STDMETHOD_(ID3D12FunctionParameterReflection *, GetFunctionParameter)(THIS_ _In_ INT ParameterIndex) PURE; +}; + +// {EC25F42D-7006-4F2B-B33E-02CC3375733F} +interface DECLSPEC_UUID("EC25F42D-7006-4F2B-B33E-02CC3375733F") ID3D12FunctionParameterReflection; +DEFINE_GUID(IID_ID3D12FunctionParameterReflection, +0xec25f42d, 0x7006, 0x4f2b, 0xb3, 0x3e, 0x2, 0xcc, 0x33, 0x75, 0x73, 0x3f); + +#undef INTERFACE +#define INTERFACE ID3D12FunctionParameterReflection + +DECLARE_INTERFACE(ID3D12FunctionParameterReflection) +{ + STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_PARAMETER_DESC * pDesc) PURE; +}; + + +////////////////////////////////////////////////////////////////////////////// +// APIs ////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif //__D3D12SHADER_H__ + diff --git a/base/sources/libs/kong/sources/libs/dxc/inc/dxcapi.h b/base/sources/libs/kong/sources/libs/dxc/inc/dxcapi.h new file mode 100644 index 00000000..5481de9c --- /dev/null +++ b/base/sources/libs/kong/sources/libs/dxc/inc/dxcapi.h @@ -0,0 +1,1309 @@ + +/////////////////////////////////////////////////////////////////////////////// +// // +// dxcapi.h // +// Copyright (C) Microsoft Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +// Provides declarations for the DirectX Compiler API entry point. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#ifndef __DXC_API__ +#define __DXC_API__ + +#ifdef _WIN32 +#ifndef DXC_API_IMPORT +#define DXC_API_IMPORT __declspec(dllimport) +#endif +#else +#ifndef DXC_API_IMPORT +#define DXC_API_IMPORT __attribute__((visibility("default"))) +#endif +#endif + +#ifdef _WIN32 + +#ifndef CROSS_PLATFORM_UUIDOF +// Warning: This macro exists in WinAdapter.h as well +#define CROSS_PLATFORM_UUIDOF(interface, spec) \ + struct __declspec(uuid(spec)) interface; +#endif + +#else + +#include "WinAdapter.h" +#include +#endif + +struct IMalloc; + +struct IDxcIncludeHandler; + +/// \brief Typedef for DxcCreateInstance function pointer. +/// +/// This can be used with GetProcAddress to get the DxcCreateInstance function. +typedef HRESULT(__stdcall *DxcCreateInstanceProc)(_In_ REFCLSID rclsid, + _In_ REFIID riid, + _Out_ LPVOID *ppv); + +/// \brief Typedef for DxcCreateInstance2 function pointer. +/// +/// This can be used with GetProcAddress to get the DxcCreateInstance2 function. +typedef HRESULT(__stdcall *DxcCreateInstance2Proc)(_In_ IMalloc *pMalloc, + _In_ REFCLSID rclsid, + _In_ REFIID riid, + _Out_ LPVOID *ppv); + +/// \brief Creates a single uninitialized object of the class associated with a +/// specified CLSID. +/// +/// \param rclsid The CLSID associated with the data and code that will be used +/// to create the object. +/// +/// \param riid A reference to the identifier of the interface to be used to +/// communicate with the object. +/// +/// \param ppv Address of pointer variable that receives the interface pointer +/// requested in riid. Upon successful return, *ppv contains the requested +/// interface pointer. Upon failure, *ppv contains NULL. +/// +/// While this function is similar to CoCreateInstance, there is no COM +/// involvement. +extern "C" DXC_API_IMPORT + HRESULT __stdcall DxcCreateInstance(_In_ REFCLSID rclsid, _In_ REFIID riid, + _Out_ LPVOID *ppv); + +/// \brief Version of DxcCreateInstance that takes an IMalloc interface. +/// +/// This can be used to create an instance of the compiler with a custom memory +/// allocator. +extern "C" DXC_API_IMPORT + HRESULT __stdcall DxcCreateInstance2(_In_ IMalloc *pMalloc, + _In_ REFCLSID rclsid, _In_ REFIID riid, + _Out_ LPVOID *ppv); + +// For convenience, equivalent definitions to CP_UTF8 and CP_UTF16. +#define DXC_CP_UTF8 65001 +#define DXC_CP_UTF16 1200 +#define DXC_CP_UTF32 12000 +// Use DXC_CP_ACP for: Binary; ANSI Text; Autodetect UTF with BOM +#define DXC_CP_ACP 0 + +/// Codepage for "wide" characters - UTF16 on Windows, UTF32 on other platforms. +#ifdef _WIN32 +#define DXC_CP_WIDE DXC_CP_UTF16 +#else +#define DXC_CP_WIDE DXC_CP_UTF32 +#endif + +/// Indicates that the shader hash was computed taking into account source +/// information (-Zss). +#define DXC_HASHFLAG_INCLUDES_SOURCE 1 + +/// Hash digest type for ShaderHash. +typedef struct DxcShaderHash { + UINT32 Flags; ///< DXC_HASHFLAG_* + BYTE HashDigest[16]; ///< The hash digest +} DxcShaderHash; + +#define DXC_FOURCC(ch0, ch1, ch2, ch3) \ + ((UINT32)(UINT8)(ch0) | (UINT32)(UINT8)(ch1) << 8 | \ + (UINT32)(UINT8)(ch2) << 16 | (UINT32)(UINT8)(ch3) << 24) +#define DXC_PART_PDB DXC_FOURCC('I', 'L', 'D', 'B') +#define DXC_PART_PDB_NAME DXC_FOURCC('I', 'L', 'D', 'N') +#define DXC_PART_PRIVATE_DATA DXC_FOURCC('P', 'R', 'I', 'V') +#define DXC_PART_ROOT_SIGNATURE DXC_FOURCC('R', 'T', 'S', '0') +#define DXC_PART_DXIL DXC_FOURCC('D', 'X', 'I', 'L') +#define DXC_PART_REFLECTION_DATA DXC_FOURCC('S', 'T', 'A', 'T') +#define DXC_PART_SHADER_HASH DXC_FOURCC('H', 'A', 'S', 'H') +#define DXC_PART_INPUT_SIGNATURE DXC_FOURCC('I', 'S', 'G', '1') +#define DXC_PART_OUTPUT_SIGNATURE DXC_FOURCC('O', 'S', 'G', '1') +#define DXC_PART_PATCH_CONSTANT_SIGNATURE DXC_FOURCC('P', 'S', 'G', '1') + +// Some option arguments are defined here for continuity with D3DCompile +// interface. +#define DXC_ARG_DEBUG L"-Zi" +#define DXC_ARG_SKIP_VALIDATION L"-Vd" +#define DXC_ARG_SKIP_OPTIMIZATIONS L"-Od" +#define DXC_ARG_PACK_MATRIX_ROW_MAJOR L"-Zpr" +#define DXC_ARG_PACK_MATRIX_COLUMN_MAJOR L"-Zpc" +#define DXC_ARG_AVOID_FLOW_CONTROL L"-Gfa" +#define DXC_ARG_PREFER_FLOW_CONTROL L"-Gfp" +#define DXC_ARG_ENABLE_STRICTNESS L"-Ges" +#define DXC_ARG_ENABLE_BACKWARDS_COMPATIBILITY L"-Gec" +#define DXC_ARG_IEEE_STRICTNESS L"-Gis" +#define DXC_ARG_OPTIMIZATION_LEVEL0 L"-O0" +#define DXC_ARG_OPTIMIZATION_LEVEL1 L"-O1" +#define DXC_ARG_OPTIMIZATION_LEVEL2 L"-O2" +#define DXC_ARG_OPTIMIZATION_LEVEL3 L"-O3" +#define DXC_ARG_WARNINGS_ARE_ERRORS L"-WX" +#define DXC_ARG_RESOURCES_MAY_ALIAS L"-res_may_alias" +#define DXC_ARG_ALL_RESOURCES_BOUND L"-all_resources_bound" +#define DXC_ARG_DEBUG_NAME_FOR_SOURCE L"-Zss" +#define DXC_ARG_DEBUG_NAME_FOR_BINARY L"-Zsb" + +CROSS_PLATFORM_UUIDOF(IDxcBlob, "8BA5FB08-5195-40e2-AC58-0D989C3A0102") +/// \brief A sized buffer that can be passed in and out of DXC APIs. +/// +/// This is an alias of ID3D10Blob and ID3DBlob. +struct IDxcBlob : public IUnknown { +public: + /// \brief Retrieves a pointer to the blob's data. + virtual LPVOID STDMETHODCALLTYPE GetBufferPointer(void) = 0; + + /// \brief Retrieves the size, in bytes, of the blob's data. + virtual SIZE_T STDMETHODCALLTYPE GetBufferSize(void) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcBlobEncoding, "7241d424-2646-4191-97c0-98e96e42fc68") +/// \brief A blob that might have a known encoding. +struct IDxcBlobEncoding : public IDxcBlob { +public: + /// \brief Retrieve the encoding for this blob. + /// + /// \param pKnown Pointer to a variable that will be set to TRUE if the + /// encoding is known. + /// + /// \param pCodePage Pointer to variable that will be set to the encoding used + /// for this blog. + /// + /// If the encoding is not known then pCodePage will be set to CP_ACP. + virtual HRESULT STDMETHODCALLTYPE GetEncoding(_Out_ BOOL *pKnown, + _Out_ UINT32 *pCodePage) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcBlobWide, "A3F84EAB-0FAA-497E-A39C-EE6ED60B2D84") +/// \brief A blob containing a null-terminated wide string. +/// +/// This uses the native wide character encoding (utf16 on Windows, utf32 on +/// Linux). +/// +/// The value returned by GetBufferSize() is the size of the buffer, in bytes, +/// including the null-terminator. +/// +/// This interface is used to return output name strings DXC. Other string +/// output blobs, such as errors/warnings, preprocessed HLSL, or other text are +/// returned using encodings based on the -encoding option passed to the +/// compiler. +struct IDxcBlobWide : public IDxcBlobEncoding { +public: + /// \brief Retrieves a pointer to the string stored in this blob. + virtual LPCWSTR STDMETHODCALLTYPE GetStringPointer(void) = 0; + + /// \brief Retrieves the length of the string stored in this blob, in + /// characters, excluding the null-terminator. + virtual SIZE_T STDMETHODCALLTYPE GetStringLength(void) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcBlobUtf8, "3DA636C9-BA71-4024-A301-30CBF125305B") +/// \brief A blob containing a UTF-8 encoded string. +/// +/// The value returned by GetBufferSize() is the size of the buffer, in bytes, +/// including the null-terminator. +/// +/// Depending on the -encoding option passed to the compiler, this interface is +/// used to return string output blobs, such as errors/warnings, preprocessed +/// HLSL, or other text. Output name strings always use IDxcBlobWide. +struct IDxcBlobUtf8 : public IDxcBlobEncoding { +public: + /// \brief Retrieves a pointer to the string stored in this blob. + virtual LPCSTR STDMETHODCALLTYPE GetStringPointer(void) = 0; + + /// \brief Retrieves the length of the string stored in this blob, in + /// characters, excluding the null-terminator. + virtual SIZE_T STDMETHODCALLTYPE GetStringLength(void) = 0; +}; + +#ifdef _WIN32 +/// IDxcBlobUtf16 is a legacy alias for IDxcBlobWide on Win32. +typedef IDxcBlobWide IDxcBlobUtf16; +#endif + +CROSS_PLATFORM_UUIDOF(IDxcIncludeHandler, + "7f61fc7d-950d-467f-b3e3-3c02fb49187c") +/// \brief Interface for handling include directives. +/// +/// This interface can be implemented to customize handling of include +/// directives. +/// +/// Use IDxcUtils::CreateDefaultIncludeHandler to create a default +/// implementation that reads include files from the filesystem. +/// +struct IDxcIncludeHandler : public IUnknown { + /// \brief Load a source file to be included by the compiler. + /// + /// \param pFilename Candidate filename. + /// + /// \param ppIncludeSource Resultant source object for included file, nullptr + /// if not found. + virtual HRESULT STDMETHODCALLTYPE + LoadSource(_In_z_ LPCWSTR pFilename, + _COM_Outptr_result_maybenull_ IDxcBlob **ppIncludeSource) = 0; +}; + +/// \brief Structure for supplying bytes or text input to Dxc APIs. +typedef struct DxcBuffer { + /// \brief Pointer to the start of the buffer. + LPCVOID Ptr; + + /// \brief Size of the buffer in bytes. + SIZE_T Size; + + /// \brief Encoding of the buffer. + /// + /// Use Encoding = 0 for non-text bytes, ANSI text, or unknown with BOM. + UINT Encoding; +} DxcText; + +/// \brief Structure for supplying defines to Dxc APIs. +struct DxcDefine { + LPCWSTR Name; ///< The define name. + _Maybenull_ LPCWSTR Value; ///< Optional value for the define. +}; + +CROSS_PLATFORM_UUIDOF(IDxcCompilerArgs, "73EFFE2A-70DC-45F8-9690-EFF64C02429D") +/// \brief Interface for managing arguments passed to DXC. +/// +/// Use IDxcUtils::BuildArguments to create an instance of this interface. +struct IDxcCompilerArgs : public IUnknown { + /// \brief Retrieve the array of arguments. + /// + /// This can be passed directly to the pArguments parameter of the Compile() + /// method. + virtual LPCWSTR *STDMETHODCALLTYPE GetArguments() = 0; + + /// \brief Retrieve the number of arguments. + /// + /// This can be passed directly to the argCount parameter of the Compile() + /// method. + virtual UINT32 STDMETHODCALLTYPE GetCount() = 0; + + /// \brief Add additional arguments to this list of compiler arguments. + virtual HRESULT STDMETHODCALLTYPE AddArguments( + _In_opt_count_(argCount) + LPCWSTR *pArguments, ///< Array of pointers to arguments to add. + _In_ UINT32 argCount ///< Number of arguments to add. + ) = 0; + + /// \brief Add additional UTF-8 encoded arguments to this list of compiler + /// arguments. + virtual HRESULT STDMETHODCALLTYPE AddArgumentsUTF8( + _In_opt_count_(argCount) + LPCSTR *pArguments, ///< Array of pointers to UTF-8 arguments to add. + _In_ UINT32 argCount ///< Number of arguments to add. + ) = 0; + + /// \brief Add additional defines to this list of compiler arguments. + virtual HRESULT STDMETHODCALLTYPE AddDefines( + _In_count_(defineCount) const DxcDefine *pDefines, ///< Array of defines. + _In_ UINT32 defineCount ///< Number of defines. + ) = 0; +}; + +////////////////////////// +// Legacy Interfaces +///////////////////////// + +CROSS_PLATFORM_UUIDOF(IDxcLibrary, "e5204dc7-d18c-4c3c-bdfb-851673980fe7") +/// \deprecated IDxcUtils replaces IDxcLibrary; please use IDxcUtils insted. +struct IDxcLibrary : public IUnknown { + /// \deprecated + virtual HRESULT STDMETHODCALLTYPE SetMalloc(_In_opt_ IMalloc *pMalloc) = 0; + + /// \deprecated + virtual HRESULT STDMETHODCALLTYPE + CreateBlobFromBlob(_In_ IDxcBlob *pBlob, UINT32 offset, UINT32 length, + _COM_Outptr_ IDxcBlob **ppResult) = 0; + + /// \deprecated + virtual HRESULT STDMETHODCALLTYPE + CreateBlobFromFile(_In_z_ LPCWSTR pFileName, _In_opt_ UINT32 *codePage, + _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0; + + /// \deprecated + virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingFromPinned( + _In_bytecount_(size) LPCVOID pText, UINT32 size, UINT32 codePage, + _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0; + + /// \deprecated + virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingOnHeapCopy( + _In_bytecount_(size) LPCVOID pText, UINT32 size, UINT32 codePage, + _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0; + + /// \deprecated + virtual HRESULT STDMETHODCALLTYPE CreateBlobWithEncodingOnMalloc( + _In_bytecount_(size) LPCVOID pText, IMalloc *pIMalloc, UINT32 size, + UINT32 codePage, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0; + + /// \deprecated + virtual HRESULT STDMETHODCALLTYPE + CreateIncludeHandler(_COM_Outptr_ IDxcIncludeHandler **ppResult) = 0; + + /// \deprecated + virtual HRESULT STDMETHODCALLTYPE CreateStreamFromBlobReadOnly( + _In_ IDxcBlob *pBlob, _COM_Outptr_ IStream **ppStream) = 0; + + /// \deprecated + virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf8( + _In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0; + + // Renamed from GetBlobAsUtf16 to GetBlobAsWide + /// \deprecated + virtual HRESULT STDMETHODCALLTYPE GetBlobAsWide( + _In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) = 0; + +#ifdef _WIN32 + // Alias to GetBlobAsWide on Win32 + /// \deprecated + inline HRESULT GetBlobAsUtf16(_In_ IDxcBlob *pBlob, + _COM_Outptr_ IDxcBlobEncoding **pBlobEncoding) { + return this->GetBlobAsWide(pBlob, pBlobEncoding); + } +#endif +}; + +CROSS_PLATFORM_UUIDOF(IDxcOperationResult, + "CEDB484A-D4E9-445A-B991-CA21CA157DC2") +/// \brief The results of a DXC operation. +/// +/// Note: IDxcResult replaces IDxcOperationResult and should be used wherever +/// possible. +struct IDxcOperationResult : public IUnknown { + /// \brief Retrieve the overall status of the operation. + virtual HRESULT STDMETHODCALLTYPE GetStatus(_Out_ HRESULT *pStatus) = 0; + + /// \brief Retrieve the primary output of the operation. + /// + /// This corresponds to: + /// * DXC_OUT_OBJECT - Compile() with shader or library target + /// * DXC_OUT_DISASSEMBLY - Disassemble() + /// * DXC_OUT_HLSL - Compile() with -P + /// * DXC_OUT_ROOT_SIGNATURE - Compile() with rootsig_* target + virtual HRESULT STDMETHODCALLTYPE + GetResult(_COM_Outptr_result_maybenull_ IDxcBlob **ppResult) = 0; + + /// \brief Retrieves the error buffer from the operation, if there is one. + /// + // This corresponds to calling IDxcResult::GetOutput() with DXC_OUT_ERRORS. + virtual HRESULT STDMETHODCALLTYPE + GetErrorBuffer(_COM_Outptr_result_maybenull_ IDxcBlobEncoding **ppErrors) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcCompiler, "8c210bf3-011f-4422-8d70-6f9acb8db617") +/// \deprecated Please use IDxcCompiler3 instead. +struct IDxcCompiler : public IUnknown { + /// \brief Compile a single entry point to the target shader model. + /// + /// \deprecated Please use IDxcCompiler3::Compile() instead. + virtual HRESULT STDMETHODCALLTYPE Compile( + _In_ IDxcBlob *pSource, // Source text to compile. + _In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in + // errors and include handlers. + _In_opt_z_ LPCWSTR pEntryPoint, // Entry point name. + _In_z_ LPCWSTR pTargetProfile, // Shader profile to compile. + _In_opt_count_(argCount) + LPCWSTR *pArguments, // Array of pointers to arguments. + _In_ UINT32 argCount, // Number of arguments. + _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines. + _In_ UINT32 defineCount, // Number of defines. + _In_opt_ IDxcIncludeHandler + *pIncludeHandler, // User-provided interface to handle #include + // directives (optional). + _COM_Outptr_ IDxcOperationResult * + *ppResult // Compiler output status, buffer, and errors. + ) = 0; + + /// \brief Preprocess source text. + /// + /// \deprecated Please use IDxcCompiler3::Compile() with the "-P" argument + /// instead. + virtual HRESULT STDMETHODCALLTYPE Preprocess( + _In_ IDxcBlob *pSource, // Source text to preprocess. + _In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in + // errors and include handlers. + _In_opt_count_(argCount) + LPCWSTR *pArguments, // Array of pointers to arguments. + _In_ UINT32 argCount, // Number of arguments. + _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines. + _In_ UINT32 defineCount, // Number of defines. + _In_opt_ IDxcIncludeHandler + *pIncludeHandler, // user-provided interface to handle #include + // directives (optional). + _COM_Outptr_ IDxcOperationResult * + *ppResult // Preprocessor output status, buffer, and errors. + ) = 0; + + /// \brief Disassemble a program. + /// + /// \deprecated Please use IDxcCompiler3::Disassemble() instead. + virtual HRESULT STDMETHODCALLTYPE Disassemble( + _In_ IDxcBlob *pSource, // Program to disassemble. + _COM_Outptr_ IDxcBlobEncoding **ppDisassembly // Disassembly text. + ) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcCompiler2, "A005A9D9-B8BB-4594-B5C9-0E633BEC4D37") +/// \deprecated Please use IDxcCompiler3 instead. +struct IDxcCompiler2 : public IDxcCompiler { + /// \brief Compile a single entry point to the target shader model with debug + /// information. + /// + /// \deprecated Please use IDxcCompiler3::Compile() instead. + virtual HRESULT STDMETHODCALLTYPE CompileWithDebug( + _In_ IDxcBlob *pSource, // Source text to compile. + _In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in + // errors and include handlers. + _In_opt_z_ LPCWSTR pEntryPoint, // Entry point name. + _In_z_ LPCWSTR pTargetProfile, // Shader profile to compile. + _In_opt_count_(argCount) + LPCWSTR *pArguments, // Array of pointers to arguments. + _In_ UINT32 argCount, // Number of arguments. + _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines. + _In_ UINT32 defineCount, // Number of defines. + _In_opt_ IDxcIncludeHandler + *pIncludeHandler, // user-provided interface to handle #include + // directives (optional). + _COM_Outptr_ IDxcOperationResult * + *ppResult, // Compiler output status, buffer, and errors. + _Outptr_opt_result_z_ LPWSTR + *ppDebugBlobName, // Suggested file name for debug blob. Must be + // CoTaskMemFree()'d. + _COM_Outptr_opt_ IDxcBlob **ppDebugBlob // Debug blob. + ) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcLinker, "F1B5BE2A-62DD-4327-A1C2-42AC1E1E78E6") +/// \brief DXC linker interface. +/// +/// Use DxcCreateInstance with CLSID_DxcLinker to obtain an instance of this +/// interface. +struct IDxcLinker : public IUnknown { +public: + /// \brief Register a library with name to reference it later. + virtual HRESULT + RegisterLibrary(_In_opt_ LPCWSTR pLibName, ///< Name of the library. + _In_ IDxcBlob *pLib ///< Library blob. + ) = 0; + + /// \brief Links the shader and produces a shader blob that the Direct3D + /// runtime can use. + virtual HRESULT STDMETHODCALLTYPE Link( + _In_opt_ LPCWSTR pEntryName, ///< Entry point name. + _In_ LPCWSTR pTargetProfile, ///< shader profile to link. + _In_count_(libCount) + const LPCWSTR *pLibNames, ///< Array of library names to link. + _In_ UINT32 libCount, ///< Number of libraries to link. + _In_opt_count_(argCount) + const LPCWSTR *pArguments, ///< Array of pointers to arguments. + _In_ UINT32 argCount, ///< Number of arguments. + _COM_Outptr_ IDxcOperationResult * + *ppResult ///< Linker output status, buffer, and errors. + ) = 0; +}; + +///////////////////////// +// Latest interfaces. Please use these. +//////////////////////// + +CROSS_PLATFORM_UUIDOF(IDxcUtils, "4605C4CB-2019-492A-ADA4-65F20BB7D67F") +/// \brief Various utility functions for DXC. +/// +/// Use DxcCreateInstance with CLSID_DxcUtils to obtain an instance of this +/// interface. +/// +/// IDxcUtils replaces IDxcLibrary. +struct IDxcUtils : public IUnknown { + /// \brief Create a sub-blob that holds a reference to the outer blob and + /// points to its memory. + /// + /// \param pBlob The outer blob. + /// + /// \param offset The offset inside the outer blob. + /// + /// \param length The size, in bytes, of the buffer to reference from the + /// output blob. + /// + /// \param ppResult Address of the pointer that receives a pointer to the + /// newly created blob. + virtual HRESULT STDMETHODCALLTYPE + CreateBlobFromBlob(_In_ IDxcBlob *pBlob, UINT32 offset, UINT32 length, + _COM_Outptr_ IDxcBlob **ppResult) = 0; + + // For codePage, use 0 (or DXC_CP_ACP) for raw binary or ANSI code page. + + /// \brief Create a blob referencing existing memory, with no copy. + /// + /// \param pData Pointer to buffer containing the contents of the new blob. + /// + /// \param size The size of the pData buffer, in bytes. + /// + /// \param codePage The code page to use if the blob contains text. Use + /// DXC_CP_ACP for binary or ANSI code page. + /// + /// \param ppBlobEncoding Address of the pointer that receives a pointer to + /// the newly created blob. + /// + /// The user must manage the memory lifetime separately. + /// + /// This replaces IDxcLibrary::CreateBlobWithEncodingFromPinned. + virtual HRESULT STDMETHODCALLTYPE CreateBlobFromPinned( + _In_bytecount_(size) LPCVOID pData, UINT32 size, UINT32 codePage, + _COM_Outptr_ IDxcBlobEncoding **ppBlobEncoding) = 0; + + /// \brief Create a blob, taking ownership of memory allocated with the + /// supplied allocator. + /// + /// \param pData Pointer to buffer containing the contents of the new blob. + /// + /// \param pIMalloc The memory allocator to use. + /// + /// \param size The size of thee pData buffer, in bytes. + /// + /// \param codePage The code page to use if the blob contains text. Use + /// DXC_CP_ACP for binary or ANSI code page. + /// + /// \param ppBlobEncoding Address of the pointer that receives a pointer to + /// the newly created blob. + /// + /// This replaces IDxcLibrary::CreateBlobWithEncodingOnMalloc. + virtual HRESULT STDMETHODCALLTYPE MoveToBlob( + _In_bytecount_(size) LPCVOID pData, IMalloc *pIMalloc, UINT32 size, + UINT32 codePage, _COM_Outptr_ IDxcBlobEncoding **ppBlobEncoding) = 0; + + /// \brief Create a blob containing a copy of the existing data. + /// + /// \param pData Pointer to buffer containing the contents of the new blob. + /// + /// \param size The size of thee pData buffer, in bytes. + /// + /// \param codePage The code page to use if the blob contains text. Use + /// DXC_CP_ACP for binary or ANSI code page. + /// + /// \param ppBlobEncoding Address of the pointer that receives a pointer to + /// the newly created blob. + /// + /// The new blob and its contents are allocated with the current allocator. + /// This replaces IDxcLibrary::CreateBlobWithEncodingOnHeapCopy. + virtual HRESULT STDMETHODCALLTYPE + CreateBlob(_In_bytecount_(size) LPCVOID pData, UINT32 size, UINT32 codePage, + _COM_Outptr_ IDxcBlobEncoding **ppBlobEncoding) = 0; + + /// \brief Create a blob with data loaded from a file. + /// + /// \param pFileName The name of the file to load from. + /// + /// \param pCodePage Optional code page to use if the blob contains text. Pass + /// NULL for binary data. + /// + /// \param ppBlobEncoding Address of the pointer that receives a pointer to + /// the newly created blob. + /// + /// The new blob and its contents are allocated with the current allocator. + /// This replaces IDxcLibrary::CreateBlobFromFile. + virtual HRESULT STDMETHODCALLTYPE + LoadFile(_In_z_ LPCWSTR pFileName, _In_opt_ UINT32 *pCodePage, + _COM_Outptr_ IDxcBlobEncoding **ppBlobEncoding) = 0; + + /// \brief Create a stream that reads data from a blob. + /// + /// \param pBlob The blob to read from. + /// + /// \param ppStream Address of the pointer that receives a pointer to the + /// newly created stream. + virtual HRESULT STDMETHODCALLTYPE CreateReadOnlyStreamFromBlob( + _In_ IDxcBlob *pBlob, _COM_Outptr_ IStream **ppStream) = 0; + + /// \brief Create default file-based include handler. + /// + /// \param ppResult Address of the pointer that receives a pointer to the + /// newly created include handler. + virtual HRESULT STDMETHODCALLTYPE + CreateDefaultIncludeHandler(_COM_Outptr_ IDxcIncludeHandler **ppResult) = 0; + + /// \brief Convert or return matching encoded text blob as UTF-8. + /// + /// \param pBlob The blob to convert. + /// + /// \param ppBlobEncoding Address of the pointer that receives a pointer to + /// the newly created blob. + virtual HRESULT STDMETHODCALLTYPE GetBlobAsUtf8( + _In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobUtf8 **ppBlobEncoding) = 0; + + /// \brief Convert or return matching encoded text blob as UTF-16. + /// + /// \param pBlob The blob to convert. + /// + /// \param ppBlobEncoding Address of the pointer that receives a pointer to + /// the newly created blob. + virtual HRESULT STDMETHODCALLTYPE GetBlobAsWide( + _In_ IDxcBlob *pBlob, _COM_Outptr_ IDxcBlobWide **ppBlobEncoding) = 0; + +#ifdef _WIN32 + /// \brief Convert or return matching encoded text blob as UTF-16. + /// + /// \param pBlob The blob to convert. + /// + /// \param ppBlobEncoding Address of the pointer that receives a pointer to + /// the newly created blob. + /// + /// Alias to GetBlobAsWide on Win32. + inline HRESULT GetBlobAsUtf16(_In_ IDxcBlob *pBlob, + _COM_Outptr_ IDxcBlobWide **ppBlobEncoding) { + return this->GetBlobAsWide(pBlob, ppBlobEncoding); + } +#endif + + /// \brief Retrieve a single part from a DXIL container. + /// + /// \param pShader The shader to retrieve the part from. + /// + /// \param DxcPart The part to retrieve (eg DXC_PART_ROOT_SIGNATURE). + /// + /// \param ppPartData Address of the pointer that receives a pointer to the + /// part. + /// + /// \param pPartSizeInBytes Address of the pointer that receives the size of + /// the part. + /// + /// The returned pointer points inside the buffer passed in pShader. + virtual HRESULT STDMETHODCALLTYPE + GetDxilContainerPart(_In_ const DxcBuffer *pShader, _In_ UINT32 DxcPart, + _Outptr_result_nullonfailure_ void **ppPartData, + _Out_ UINT32 *pPartSizeInBytes) = 0; + + /// \brief Create reflection interface from serialized DXIL container or the + /// DXC_OUT_REFLECTION blob contents. + /// + /// \param pData The source data. + /// + /// \param iid The interface ID of the reflection interface to create. + /// + /// \param ppvReflection Address of the pointer that receives a pointer to the + /// newly created reflection interface. + /// + /// Use this with interfaces such as ID3D12ShaderReflection. + virtual HRESULT STDMETHODCALLTYPE CreateReflection( + _In_ const DxcBuffer *pData, REFIID iid, void **ppvReflection) = 0; + + /// \brief Build arguments that can be passed to the Compile method. + virtual HRESULT STDMETHODCALLTYPE BuildArguments( + _In_opt_z_ LPCWSTR pSourceName, ///< Optional file name for pSource. Used + ///< in errors and include handlers. + _In_opt_z_ LPCWSTR pEntryPoint, ///< Entry point name (-E). + _In_z_ LPCWSTR pTargetProfile, ///< Shader profile to compile (-T). + _In_opt_count_(argCount) + LPCWSTR *pArguments, ///< Array of pointers to arguments. + _In_ UINT32 argCount, ///< Number of arguments. + _In_count_(defineCount) const DxcDefine *pDefines, ///< Array of defines. + _In_ UINT32 defineCount, ///< Number of defines. + _COM_Outptr_ IDxcCompilerArgs * + *ppArgs ///< Arguments you can use with Compile() method. + ) = 0; + + /// \brief Retrieve the hash and contents of a shader PDB. + /// + /// \param pPDBBlob The blob containing the PDB. + /// + /// \param ppHash Address of the pointer that receives a pointer to the hash + /// blob. + /// + /// \param ppContainer Address of the pointer that receives a pointer to the + /// bloc containing the contents of the PDB. + /// + virtual HRESULT STDMETHODCALLTYPE + GetPDBContents(_In_ IDxcBlob *pPDBBlob, _COM_Outptr_ IDxcBlob **ppHash, + _COM_Outptr_ IDxcBlob **ppContainer) = 0; +}; + +/// \brief Specifies the kind of output to retrieve from a IDxcResult. +/// +/// Note: text outputs returned from version 2 APIs are UTF-8 or UTF-16 based on +/// the -encoding option passed to the compiler. +typedef enum DXC_OUT_KIND { + DXC_OUT_NONE = 0, ///< No output. + DXC_OUT_OBJECT = 1, ///< IDxcBlob - Shader or library object. + DXC_OUT_ERRORS = 2, ///< IDxcBlobUtf8 or IDxcBlobWide. + DXC_OUT_PDB = 3, ///< IDxcBlob. + DXC_OUT_SHADER_HASH = 4, ///< IDxcBlob - DxcShaderHash of shader or shader + ///< with source info (-Zsb/-Zss). + DXC_OUT_DISASSEMBLY = 5, ///< IDxcBlobUtf8 or IDxcBlobWide - from Disassemble. + DXC_OUT_HLSL = + 6, ///< IDxcBlobUtf8 or IDxcBlobWide - from Preprocessor or Rewriter. + DXC_OUT_TEXT = 7, ///< IDxcBlobUtf8 or IDxcBlobWide - other text, such as + ///< -ast-dump or -Odump. + DXC_OUT_REFLECTION = 8, ///< IDxcBlob - RDAT part with reflection data. + DXC_OUT_ROOT_SIGNATURE = 9, ///< IDxcBlob - Serialized root signature output. + DXC_OUT_EXTRA_OUTPUTS = 10, ///< IDxcExtraOutputs - Extra outputs. + DXC_OUT_REMARKS = + 11, ///< IDxcBlobUtf8 or IDxcBlobWide - text directed at stdout. + DXC_OUT_TIME_REPORT = + 12, ///< IDxcBlobUtf8 or IDxcBlobWide - text directed at stdout. + DXC_OUT_TIME_TRACE = + 13, ///< IDxcBlobUtf8 or IDxcBlobWide - text directed at stdout. + + DXC_OUT_LAST = DXC_OUT_TIME_TRACE, ///< Last value for a counter. + + DXC_OUT_NUM_ENUMS, + DXC_OUT_FORCE_DWORD = 0xFFFFFFFF +} DXC_OUT_KIND; + +static_assert(DXC_OUT_NUM_ENUMS == DXC_OUT_LAST + 1, + "DXC_OUT_* Enum added and last value not updated."); + +CROSS_PLATFORM_UUIDOF(IDxcResult, "58346CDA-DDE7-4497-9461-6F87AF5E0659") +/// \brief Result of a DXC operation. +/// +/// DXC operations may have multiple outputs, such as a shader object and +/// errors. This interface provides access to the outputs. +struct IDxcResult : public IDxcOperationResult { + /// \brief Determines whether or not this result has the specified output. + /// + /// \param dxcOutKind The kind of output to check for. + virtual BOOL STDMETHODCALLTYPE HasOutput(_In_ DXC_OUT_KIND dxcOutKind) = 0; + + /// \brief Retrieves the specified output. + /// + /// \param dxcOutKind The kind of output to retrieve. + /// + /// \param iid The interface ID of the output interface. + /// + /// \param ppvObject Address of the pointer that receives a pointer to the + /// output. + /// + /// \param ppOutputName Optional address of a pointer to receive the name + /// blob, if there is one. + virtual HRESULT STDMETHODCALLTYPE + GetOutput(_In_ DXC_OUT_KIND dxcOutKind, _In_ REFIID iid, + _COM_Outptr_opt_result_maybenull_ void **ppvObject, + _COM_Outptr_ IDxcBlobWide **ppOutputName) = 0; + + /// \brief Retrieves the number of outputs available in this result. + virtual UINT32 GetNumOutputs() = 0; + + /// \brief Retrieves the output kind at the specified index. + virtual DXC_OUT_KIND GetOutputByIndex(UINT32 Index) = 0; + + /// \brief Retrieves the primary output kind for this result. + /// + /// See IDxcOperationResult::GetResult() for more information on the primary + /// output kinds. + virtual DXC_OUT_KIND PrimaryOutput() = 0; +}; + +// Special names for extra output that should get written to specific streams. +#define DXC_EXTRA_OUTPUT_NAME_STDOUT L"*stdout*" +#define DXC_EXTRA_OUTPUT_NAME_STDERR L"*stderr*" + +CROSS_PLATFORM_UUIDOF(IDxcExtraOutputs, "319b37a2-a5c2-494a-a5de-4801b2faf989") +/// \brief Additional outputs from a DXC operation. +/// +/// This can be used to obtain outputs that don't have an explicit DXC_OUT_KIND. +/// Use DXC_OUT_EXTRA_OUTPUTS to obtain instances of this. +struct IDxcExtraOutputs : public IUnknown { + /// \brief Retrieves the number of outputs available + virtual UINT32 STDMETHODCALLTYPE GetOutputCount() = 0; + + /// \brief Retrieves the specified output. + /// + /// \param uIndex The index of the output to retrieve. + /// + /// \param iid The interface ID of the output interface. + /// + /// \param ppvObject Optional address of the pointer that receives a pointer + /// to the output if there is one. + /// + /// \param ppOutputType Optional address of the pointer that receives the + /// output type name blob if there is one. + /// + /// \param ppOutputName Optional address of the pointer that receives the + /// output name blob if there is one. + virtual HRESULT STDMETHODCALLTYPE + GetOutput(_In_ UINT32 uIndex, _In_ REFIID iid, + _COM_Outptr_opt_result_maybenull_ void **ppvObject, + _COM_Outptr_opt_result_maybenull_ IDxcBlobWide **ppOutputType, + _COM_Outptr_opt_result_maybenull_ IDxcBlobWide **ppOutputName) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcCompiler3, "228B4687-5A6A-4730-900C-9702B2203F54") +/// \brief Interface to the DirectX Shader Compiler. +/// +/// Use DxcCreateInstance with CLSID_DxcCompiler to obtain an instance of this +/// interface. +struct IDxcCompiler3 : public IUnknown { + /// \brief Compile a shader. + /// + /// IDxcUtils::BuildArguments can be used to assist building the pArguments + /// and argCount parameters. + /// + /// Depending on the arguments, this method can be used to: + /// + /// * Compile a single entry point to the target shader model, + /// * Compile a library to a library target (-T lib_*) + /// * Compile a root signature (-T rootsig_*), + /// * Preprocess HLSL source (-P). + virtual HRESULT STDMETHODCALLTYPE Compile( + _In_ const DxcBuffer *pSource, ///< Source text to compile. + _In_opt_count_(argCount) + LPCWSTR *pArguments, ///< Array of pointers to arguments. + _In_ UINT32 argCount, ///< Number of arguments. + _In_opt_ IDxcIncludeHandler + *pIncludeHandler, ///< user-provided interface to handle include + ///< directives (optional). + _In_ REFIID riid, ///< Interface ID for the result. + _Out_ LPVOID *ppResult ///< IDxcResult: status, buffer, and errors. + ) = 0; + + /// \brief Disassemble a program. + virtual HRESULT STDMETHODCALLTYPE Disassemble( + _In_ const DxcBuffer + *pObject, ///< Program to disassemble: dxil container or bitcode. + _In_ REFIID riid, ///< Interface ID for the result. + _Out_ LPVOID + *ppResult ///< IDxcResult: status, disassembly text, and errors. + ) = 0; +}; + +static const UINT32 DxcValidatorFlags_Default = 0; +static const UINT32 DxcValidatorFlags_InPlaceEdit = + 1; // Validator is allowed to update shader blob in-place. +static const UINT32 DxcValidatorFlags_RootSignatureOnly = 2; +static const UINT32 DxcValidatorFlags_ModuleOnly = 4; +static const UINT32 DxcValidatorFlags_ValidMask = 0x7; + +CROSS_PLATFORM_UUIDOF(IDxcValidator, "A6E82BD2-1FD7-4826-9811-2857E797F49A") +/// \brief Interface to DXC shader validator. +/// +/// Use DxcCreateInstance with CLSID_DxcValidator to obtain an instance of this. +struct IDxcValidator : public IUnknown { + /// \brief Validate a shader. + virtual HRESULT STDMETHODCALLTYPE Validate( + _In_ IDxcBlob *pShader, ///< Shader to validate. + _In_ UINT32 Flags, ///< Validation flags. + _COM_Outptr_ IDxcOperationResult * + *ppResult ///< Validation output status, buffer, and errors. + ) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcValidator2, "458e1fd1-b1b2-4750-a6e1-9c10f03bed92") +/// \brief Interface to DXC shader validator. +/// +/// Use DxcCreateInstance with CLSID_DxcValidator to obtain an instance of this. +struct IDxcValidator2 : public IDxcValidator { + /// \brief Validate a shader with optional debug bitcode. + virtual HRESULT STDMETHODCALLTYPE ValidateWithDebug( + _In_ IDxcBlob *pShader, ///< Shader to validate. + _In_ UINT32 Flags, ///< Validation flags. + _In_opt_ DxcBuffer *pOptDebugBitcode, ///< Optional debug module bitcode + ///< to provide line numbers. + _COM_Outptr_ IDxcOperationResult * + *ppResult ///< Validation output status, buffer, and errors. + ) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcContainerBuilder, + "334b1f50-2292-4b35-99a1-25588d8c17fe") +/// \brief Interface to DXC container builder. +/// +/// Use DxcCreateInstance with CLSID_DxcContainerBuilder to obtain an instance +/// of this. +struct IDxcContainerBuilder : public IUnknown { + /// \brief Load a DxilContainer to the builder. + virtual HRESULT STDMETHODCALLTYPE + Load(_In_ IDxcBlob *pDxilContainerHeader) = 0; + + /// \brief Add a part to the container. + /// + /// \param fourCC The part identifier (eg DXC_PART_PDB). + /// + /// \param pSource The source blob. + virtual HRESULT STDMETHODCALLTYPE AddPart(_In_ UINT32 fourCC, + _In_ IDxcBlob *pSource) = 0; + + /// \brief Remove a part from the container. + /// + /// \param fourCC The part identifier (eg DXC_PART_PDB). + /// + /// \return S_OK on success, DXC_E_MISSING_PART if the part was not found, or + /// other standard HRESULT error code. + virtual HRESULT STDMETHODCALLTYPE RemovePart(_In_ UINT32 fourCC) = 0; + + /// \brief Build the container. + /// + /// \param ppResult Pointer to variable to receive the result. + virtual HRESULT STDMETHODCALLTYPE + SerializeContainer(_Out_ IDxcOperationResult **ppResult) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcAssembler, "091f7a26-1c1f-4948-904b-e6e3a8a771d5") +/// \brief Interface to DxcAssembler. +/// +/// Use DxcCreateInstance with CLSID_DxcAssembler to obtain an instance of this. +struct IDxcAssembler : public IUnknown { + /// \brief Assemble DXIL in LL or LLVM bitcode to DXIL container. + virtual HRESULT STDMETHODCALLTYPE AssembleToContainer( + _In_ IDxcBlob *pShader, ///< Shader to assemble. + _COM_Outptr_ IDxcOperationResult * + *ppResult ///< Assembly output status, buffer, and errors. + ) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcContainerReflection, + "d2c21b26-8350-4bdc-976a-331ce6f4c54c") +/// \brief Interface to DxcContainerReflection. +/// +/// Use DxcCreateInstance with CLSID_DxcContainerReflection to obtain an +/// instance of this. +struct IDxcContainerReflection : public IUnknown { + /// \brief Choose the container to perform reflection on + /// + /// \param pContainer The container to load. If null is passed then this + /// instance will release any held resources. + virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pContainer) = 0; + + /// \brief Retrieves the number of parts in the container. + /// + /// \param pResult Pointer to variable to receive the result. + /// + /// \return S_OK on success, E_NOT_VALID_STATE if a container has not been + /// loaded using Load(), or other standard HRESULT error codes. + virtual HRESULT STDMETHODCALLTYPE GetPartCount(_Out_ UINT32 *pResult) = 0; + + /// \brief Retrieve the kind of a specified part. + /// + /// \param idx The index of the part to retrieve the kind of. + /// + /// \param pResult Pointer to variable to receive the result. + /// + /// \return S_OK on success, E_NOT_VALID_STATE if a container has not been + /// loaded using Load(), E_BOUND if idx is out of bounds, or other standard + /// HRESULT error codes. + virtual HRESULT STDMETHODCALLTYPE GetPartKind(UINT32 idx, + _Out_ UINT32 *pResult) = 0; + + /// \brief Retrieve the content of a specified part. + /// + /// \param idx The index of the part to retrieve. + /// + /// \param ppResult Pointer to variable to receive the result. + /// + /// \return S_OK on success, E_NOT_VALID_STATE if a container has not been + /// loaded using Load(), E_BOUND if idx is out of bounds, or other standard + /// HRESULT error codes. + virtual HRESULT STDMETHODCALLTYPE + GetPartContent(UINT32 idx, _COM_Outptr_ IDxcBlob **ppResult) = 0; + + /// \brief Retrieve the index of the first part with the specified kind. + /// + /// \param kind The kind to search for. + /// + /// \param pResult Pointer to variable to receive the index of the matching + /// part. + /// + /// \return S_OK on success, E_NOT_VALID_STATE if a container has not been + /// loaded using Load(), HRESULT_FROM_WIN32(ERROR_NOT_FOUND) if there is no + /// part with the specified kind, or other standard HRESULT error codes. + virtual HRESULT STDMETHODCALLTYPE + FindFirstPartKind(UINT32 kind, _Out_ UINT32 *pResult) = 0; + + /// \brief Retrieve the reflection interface for a specified part. + /// + /// \param idx The index of the part to retrieve the reflection interface of. + /// + /// \param iid The IID of the interface to retrieve. + /// + /// \param ppvObject Pointer to variable to receive the result. + /// + /// Use this with interfaces such as ID3D12ShaderReflection. + /// + /// \return S_OK on success, E_NOT_VALID_STATE if a container has not been + /// loaded using Load(), E_BOUND if idx is out of bounds, or other standard + /// HRESULT error codes. + virtual HRESULT STDMETHODCALLTYPE GetPartReflection(UINT32 idx, REFIID iid, + void **ppvObject) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcOptimizerPass, "AE2CD79F-CC22-453F-9B6B-B124E7A5204C") +/// \brief An optimizer pass. +/// +/// Instances of this can be obtained via IDxcOptimizer::GetAvailablePass. +struct IDxcOptimizerPass : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + GetOptionName(_COM_Outptr_ LPWSTR *ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetDescription(_COM_Outptr_ LPWSTR *ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetOptionArgCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetOptionArgName(UINT32 argIndex, _COM_Outptr_ LPWSTR *ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetOptionArgDescription(UINT32 argIndex, _COM_Outptr_ LPWSTR *ppResult) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcOptimizer, "25740E2E-9CBA-401B-9119-4FB42F39F270") +/// \brief Interface to DxcOptimizer. +/// +/// Use DxcCreateInstance with CLSID_DxcOptimizer to obtain an instance of this. +struct IDxcOptimizer : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + GetAvailablePassCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetAvailablePass(UINT32 index, _COM_Outptr_ IDxcOptimizerPass **ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + RunOptimizer(IDxcBlob *pBlob, _In_count_(optionCount) LPCWSTR *ppOptions, + UINT32 optionCount, _COM_Outptr_ IDxcBlob **pOutputModule, + _COM_Outptr_opt_ IDxcBlobEncoding **ppOutputText) = 0; +}; + +static const UINT32 DxcVersionInfoFlags_None = 0; +static const UINT32 DxcVersionInfoFlags_Debug = 1; // Matches VS_FF_DEBUG +static const UINT32 DxcVersionInfoFlags_Internal = + 2; // Internal Validator (non-signing) + +CROSS_PLATFORM_UUIDOF(IDxcVersionInfo, "b04f5b50-2059-4f12-a8ff-a1e0cde1cc7e") +/// \brief PDB Version information. +/// +/// Use IDxcPdbUtils2::GetVersionInfo to obtain an instance of this. +struct IDxcVersionInfo : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE GetVersion(_Out_ UINT32 *pMajor, + _Out_ UINT32 *pMinor) = 0; + virtual HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcVersionInfo2, "fb6904c4-42f0-4b62-9c46-983af7da7c83") +/// \brief PDB Version Information. +/// +/// Use IDxcPdbUtils2::GetVersionInfo to obtain a IDxcVersionInfo interface, and +/// then use QueryInterface to obtain an instance of this interface from it. +struct IDxcVersionInfo2 : public IDxcVersionInfo { + virtual HRESULT STDMETHODCALLTYPE GetCommitInfo( + _Out_ UINT32 *pCommitCount, ///< The total number commits. + _Outptr_result_z_ char **pCommitHash ///< The SHA of the latest commit. + ///< Must be CoTaskMemFree()'d. + ) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcVersionInfo3, "5e13e843-9d25-473c-9ad2-03b2d0b44b1e") +/// \brief PDB Version Information. +/// +/// Use IDxcPdbUtils2::GetVersionInfo to obtain a IDxcVersionInfo interface, and +/// then use QueryInterface to obtain an instance of this interface from it. +struct IDxcVersionInfo3 : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE GetCustomVersionString( + _Outptr_result_z_ char * + *pVersionString ///< Custom version string for compiler. Must be + ///< CoTaskMemFree()'d. + ) = 0; +}; + +struct DxcArgPair { + const WCHAR *pName; + const WCHAR *pValue; +}; + +CROSS_PLATFORM_UUIDOF(IDxcPdbUtils, "E6C9647E-9D6A-4C3B-B94C-524B5A6C343D") +/// \deprecated Please use IDxcPdbUtils2 instead. +struct IDxcPdbUtils : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pPdbOrDxil) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetSourceCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetSource(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobEncoding **ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetSourceName(_In_ UINT32 uIndex, _Outptr_result_z_ BSTR *pResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFlagCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetFlag(_In_ UINT32 uIndex, _Outptr_result_z_ BSTR *pResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetArgCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE GetArg(_In_ UINT32 uIndex, + _Outptr_result_z_ BSTR *pResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetArgPairCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetArgPair(_In_ UINT32 uIndex, _Outptr_result_z_ BSTR *pName, + _Outptr_result_z_ BSTR *pValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDefineCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetDefine(_In_ UINT32 uIndex, _Outptr_result_z_ BSTR *pResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE + GetTargetProfile(_Outptr_result_z_ BSTR *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetEntryPoint(_Outptr_result_z_ BSTR *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetMainFileName(_Outptr_result_z_ BSTR *pResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE + GetHash(_COM_Outptr_ IDxcBlob **ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetName(_Outptr_result_z_ BSTR *pResult) = 0; + + virtual BOOL STDMETHODCALLTYPE IsFullPDB() = 0; + virtual HRESULT STDMETHODCALLTYPE + GetFullPDB(_COM_Outptr_ IDxcBlob **ppFullPDB) = 0; + + virtual HRESULT STDMETHODCALLTYPE + GetVersionInfo(_COM_Outptr_ IDxcVersionInfo **ppVersionInfo) = 0; + + virtual HRESULT STDMETHODCALLTYPE + SetCompiler(_In_ IDxcCompiler3 *pCompiler) = 0; + virtual HRESULT STDMETHODCALLTYPE + CompileForFullPDB(_COM_Outptr_ IDxcResult **ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE OverrideArgs(_In_ DxcArgPair *pArgPairs, + UINT32 uNumArgPairs) = 0; + virtual HRESULT STDMETHODCALLTYPE + OverrideRootSignature(_In_ const WCHAR *pRootSignature) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcPdbUtils2, "4315D938-F369-4F93-95A2-252017CC3807") +/// \brief DxcPdbUtils interface. +/// +/// Use DxcCreateInstance with CLSID_DxcPdbUtils to create an instance of this. +struct IDxcPdbUtils2 : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pPdbOrDxil) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetSourceCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetSource(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobEncoding **ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetSourceName(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobWide **ppResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetLibraryPDBCount(UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE GetLibraryPDB( + _In_ UINT32 uIndex, _COM_Outptr_ IDxcPdbUtils2 **ppOutPdbUtils, + _COM_Outptr_opt_result_maybenull_ IDxcBlobWide **ppLibraryName) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFlagCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetFlag(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobWide **ppResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetArgCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetArg(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobWide **ppResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetArgPairCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE GetArgPair( + _In_ UINT32 uIndex, _COM_Outptr_result_maybenull_ IDxcBlobWide **ppName, + _COM_Outptr_result_maybenull_ IDxcBlobWide **ppValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDefineCount(_Out_ UINT32 *pCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetDefine(_In_ UINT32 uIndex, _COM_Outptr_ IDxcBlobWide **ppResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE + GetTargetProfile(_COM_Outptr_result_maybenull_ IDxcBlobWide **ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetEntryPoint(_COM_Outptr_result_maybenull_ IDxcBlobWide **ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetMainFileName(_COM_Outptr_result_maybenull_ IDxcBlobWide **ppResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE + GetHash(_COM_Outptr_result_maybenull_ IDxcBlob **ppResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetName(_COM_Outptr_result_maybenull_ IDxcBlobWide **ppResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetVersionInfo( + _COM_Outptr_result_maybenull_ IDxcVersionInfo **ppVersionInfo) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCustomToolchainID(_Out_ UINT32 *pID) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetCustomToolchainData(_COM_Outptr_result_maybenull_ IDxcBlob **ppBlob) = 0; + + virtual HRESULT STDMETHODCALLTYPE + GetWholeDxil(_COM_Outptr_result_maybenull_ IDxcBlob **ppResult) = 0; + + virtual BOOL STDMETHODCALLTYPE IsFullPDB() = 0; + virtual BOOL STDMETHODCALLTYPE IsPDBRef() = 0; +}; + +// Note: __declspec(selectany) requires 'extern' +// On Linux __declspec(selectany) is removed and using 'extern' results in link +// error. +#ifdef _MSC_VER +#define CLSID_SCOPE __declspec(selectany) extern +#else +#define CLSID_SCOPE +#endif + +CLSID_SCOPE const CLSID CLSID_DxcCompiler = { + 0x73e22d93, + 0xe6ce, + 0x47f3, + {0xb5, 0xbf, 0xf0, 0x66, 0x4f, 0x39, 0xc1, 0xb0}}; + +// {EF6A8087-B0EA-4D56-9E45-D07E1A8B7806} +CLSID_SCOPE const GUID CLSID_DxcLinker = { + 0xef6a8087, + 0xb0ea, + 0x4d56, + {0x9e, 0x45, 0xd0, 0x7e, 0x1a, 0x8b, 0x78, 0x6}}; + +// {CD1F6B73-2AB0-484D-8EDC-EBE7A43CA09F} +CLSID_SCOPE const CLSID CLSID_DxcDiaDataSource = { + 0xcd1f6b73, + 0x2ab0, + 0x484d, + {0x8e, 0xdc, 0xeb, 0xe7, 0xa4, 0x3c, 0xa0, 0x9f}}; + +// {3E56AE82-224D-470F-A1A1-FE3016EE9F9D} +CLSID_SCOPE const CLSID CLSID_DxcCompilerArgs = { + 0x3e56ae82, + 0x224d, + 0x470f, + {0xa1, 0xa1, 0xfe, 0x30, 0x16, 0xee, 0x9f, 0x9d}}; + +// {6245D6AF-66E0-48FD-80B4-4D271796748C} +CLSID_SCOPE const GUID CLSID_DxcLibrary = { + 0x6245d6af, + 0x66e0, + 0x48fd, + {0x80, 0xb4, 0x4d, 0x27, 0x17, 0x96, 0x74, 0x8c}}; + +CLSID_SCOPE const GUID CLSID_DxcUtils = CLSID_DxcLibrary; + +// {8CA3E215-F728-4CF3-8CDD-88AF917587A1} +CLSID_SCOPE const GUID CLSID_DxcValidator = { + 0x8ca3e215, + 0xf728, + 0x4cf3, + {0x8c, 0xdd, 0x88, 0xaf, 0x91, 0x75, 0x87, 0xa1}}; + +// {D728DB68-F903-4F80-94CD-DCCF76EC7151} +CLSID_SCOPE const GUID CLSID_DxcAssembler = { + 0xd728db68, + 0xf903, + 0x4f80, + {0x94, 0xcd, 0xdc, 0xcf, 0x76, 0xec, 0x71, 0x51}}; + +// {b9f54489-55b8-400c-ba3a-1675e4728b91} +CLSID_SCOPE const GUID CLSID_DxcContainerReflection = { + 0xb9f54489, + 0x55b8, + 0x400c, + {0xba, 0x3a, 0x16, 0x75, 0xe4, 0x72, 0x8b, 0x91}}; + +// {AE2CD79F-CC22-453F-9B6B-B124E7A5204C} +CLSID_SCOPE const GUID CLSID_DxcOptimizer = { + 0xae2cd79f, + 0xcc22, + 0x453f, + {0x9b, 0x6b, 0xb1, 0x24, 0xe7, 0xa5, 0x20, 0x4c}}; + +// {94134294-411f-4574-b4d0-8741e25240d2} +CLSID_SCOPE const GUID CLSID_DxcContainerBuilder = { + 0x94134294, + 0x411f, + 0x4574, + {0xb4, 0xd0, 0x87, 0x41, 0xe2, 0x52, 0x40, 0xd2}}; + +// {54621dfb-f2ce-457e-ae8c-ec355faeec7c} +CLSID_SCOPE const GUID CLSID_DxcPdbUtils = { + 0x54621dfb, + 0xf2ce, + 0x457e, + {0xae, 0x8c, 0xec, 0x35, 0x5f, 0xae, 0xec, 0x7c}}; + +#endif diff --git a/base/sources/libs/kong/sources/libs/dxc/inc/dxcerrors.h b/base/sources/libs/kong/sources/libs/dxc/inc/dxcerrors.h new file mode 100644 index 00000000..04591a96 --- /dev/null +++ b/base/sources/libs/kong/sources/libs/dxc/inc/dxcerrors.h @@ -0,0 +1,30 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// dxcerror.h // +// Copyright (C) Microsoft Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +// Provides definition of error codes. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#ifndef __DXC_ERRORS__ +#define __DXC_ERRORS__ + +#ifndef FACILITY_GRAPHICS +#define FACILITY_GRAPHICS 36 +#endif + +#define DXC_EXCEPTION_CODE(name, status) \ + static constexpr DWORD EXCEPTION_##name = \ + (0xc0000000u | (FACILITY_GRAPHICS << 16) | \ + (0xff00u | (status & 0xffu))); + +DXC_EXCEPTION_CODE(LOAD_LIBRARY_FAILED, 0x00u) +DXC_EXCEPTION_CODE(NO_HMODULE, 0x01u) +DXC_EXCEPTION_CODE(GET_PROC_FAILED, 0x02u) + +#undef DXC_EXCEPTION_CODE + +#endif diff --git a/base/sources/libs/kong/sources/libs/dxc/inc/dxcisense.h b/base/sources/libs/kong/sources/libs/dxc/inc/dxcisense.h new file mode 100644 index 00000000..b7735151 --- /dev/null +++ b/base/sources/libs/kong/sources/libs/dxc/inc/dxcisense.h @@ -0,0 +1,959 @@ +/////////////////////////////////////////////////////////////////////////////// +// // +// dxcisense.h // +// Copyright (C) Microsoft Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +// Provides declarations for the DirectX Compiler IntelliSense component. // +// // +/////////////////////////////////////////////////////////////////////////////// + +#ifndef __DXC_ISENSE__ +#define __DXC_ISENSE__ + +#include "dxcapi.h" +#ifndef _WIN32 +#include "WinAdapter.h" +#endif + +typedef enum DxcGlobalOptions { + DxcGlobalOpt_None = 0x0, + DxcGlobalOpt_ThreadBackgroundPriorityForIndexing = 0x1, + DxcGlobalOpt_ThreadBackgroundPriorityForEditing = 0x2, + DxcGlobalOpt_ThreadBackgroundPriorityForAll = + DxcGlobalOpt_ThreadBackgroundPriorityForIndexing | + DxcGlobalOpt_ThreadBackgroundPriorityForEditing +} DxcGlobalOptions; + +typedef enum DxcTokenKind { + DxcTokenKind_Punctuation = + 0, // A token that contains some kind of punctuation. + DxcTokenKind_Keyword = 1, // A language keyword. + DxcTokenKind_Identifier = 2, // An identifier (that is not a keyword). + DxcTokenKind_Literal = 3, // A numeric, string, or character literal. + DxcTokenKind_Comment = 4, // A comment. + DxcTokenKind_Unknown = + 5, // An unknown token (possibly known to a future version). + DxcTokenKind_BuiltInType = 6, // A built-in type like int, void or float3. +} DxcTokenKind; + +typedef enum DxcTypeKind { + DxcTypeKind_Invalid = + 0, // Reprents an invalid type (e.g., where no type is available). + DxcTypeKind_Unexposed = + 1, // A type whose specific kind is not exposed via this interface. + // Builtin types + DxcTypeKind_Void = 2, + DxcTypeKind_Bool = 3, + DxcTypeKind_Char_U = 4, + DxcTypeKind_UChar = 5, + DxcTypeKind_Char16 = 6, + DxcTypeKind_Char32 = 7, + DxcTypeKind_UShort = 8, + DxcTypeKind_UInt = 9, + DxcTypeKind_ULong = 10, + DxcTypeKind_ULongLong = 11, + DxcTypeKind_UInt128 = 12, + DxcTypeKind_Char_S = 13, + DxcTypeKind_SChar = 14, + DxcTypeKind_WChar = 15, + DxcTypeKind_Short = 16, + DxcTypeKind_Int = 17, + DxcTypeKind_Long = 18, + DxcTypeKind_LongLong = 19, + DxcTypeKind_Int128 = 20, + DxcTypeKind_Float = 21, + DxcTypeKind_Double = 22, + DxcTypeKind_LongDouble = 23, + DxcTypeKind_NullPtr = 24, + DxcTypeKind_Overload = 25, + DxcTypeKind_Dependent = 26, + DxcTypeKind_ObjCId = 27, + DxcTypeKind_ObjCClass = 28, + DxcTypeKind_ObjCSel = 29, + DxcTypeKind_FirstBuiltin = DxcTypeKind_Void, + DxcTypeKind_LastBuiltin = DxcTypeKind_ObjCSel, + + DxcTypeKind_Complex = 100, + DxcTypeKind_Pointer = 101, + DxcTypeKind_BlockPointer = 102, + DxcTypeKind_LValueReference = 103, + DxcTypeKind_RValueReference = 104, + DxcTypeKind_Record = 105, + DxcTypeKind_Enum = 106, + DxcTypeKind_Typedef = 107, + DxcTypeKind_ObjCInterface = 108, + DxcTypeKind_ObjCObjectPointer = 109, + DxcTypeKind_FunctionNoProto = 110, + DxcTypeKind_FunctionProto = 111, + DxcTypeKind_ConstantArray = 112, + DxcTypeKind_Vector = 113, + DxcTypeKind_IncompleteArray = 114, + DxcTypeKind_VariableArray = 115, + DxcTypeKind_DependentSizedArray = 116, + DxcTypeKind_MemberPointer = 117 +} DxcTypeKind; + +// Describes the severity of a particular diagnostic. +typedef enum DxcDiagnosticSeverity { + // A diagnostic that has been suppressed, e.g., by a command-line option. + DxcDiagnostic_Ignored = 0, + + // This diagnostic is a note that should be attached to the previous + // (non-note) diagnostic. + DxcDiagnostic_Note = 1, + + // This diagnostic indicates suspicious code that may not be wrong. + DxcDiagnostic_Warning = 2, + + // This diagnostic indicates that the code is ill-formed. + DxcDiagnostic_Error = 3, + + // This diagnostic indicates that the code is ill-formed such that future + // parser rec unlikely to produce useful results. + DxcDiagnostic_Fatal = 4 + +} DxcDiagnosticSeverity; + +// Options to control the display of diagnostics. +typedef enum DxcDiagnosticDisplayOptions { + // Display the source-location information where the diagnostic was located. + DxcDiagnostic_DisplaySourceLocation = 0x01, + + // If displaying the source-location information of the diagnostic, + // also include the column number. + DxcDiagnostic_DisplayColumn = 0x02, + + // If displaying the source-location information of the diagnostic, + // also include information about source ranges in a machine-parsable format. + DxcDiagnostic_DisplaySourceRanges = 0x04, + + // Display the option name associated with this diagnostic, if any. + DxcDiagnostic_DisplayOption = 0x08, + + // Display the category number associated with this diagnostic, if any. + DxcDiagnostic_DisplayCategoryId = 0x10, + + // Display the category name associated with this diagnostic, if any. + DxcDiagnostic_DisplayCategoryName = 0x20, + + // Display the severity of the diagnostic message. + DxcDiagnostic_DisplaySeverity = 0x200 +} DxcDiagnosticDisplayOptions; + +typedef enum DxcTranslationUnitFlags { + // Used to indicate that no special translation-unit options are needed. + DxcTranslationUnitFlags_None = 0x0, + + // Used to indicate that the parser should construct a "detailed" + // preprocessing record, including all macro definitions and instantiations. + DxcTranslationUnitFlags_DetailedPreprocessingRecord = 0x01, + + // Used to indicate that the translation unit is incomplete. + DxcTranslationUnitFlags_Incomplete = 0x02, + + // Used to indicate that the translation unit should be built with an + // implicit precompiled header for the preamble. + DxcTranslationUnitFlags_PrecompiledPreamble = 0x04, + + // Used to indicate that the translation unit should cache some + // code-completion results with each reparse of the source file. + DxcTranslationUnitFlags_CacheCompletionResults = 0x08, + + // Used to indicate that the translation unit will be serialized with + // SaveTranslationUnit. + DxcTranslationUnitFlags_ForSerialization = 0x10, + + // DEPRECATED + DxcTranslationUnitFlags_CXXChainedPCH = 0x20, + + // Used to indicate that function/method bodies should be skipped while + // parsing. + DxcTranslationUnitFlags_SkipFunctionBodies = 0x40, + + // Used to indicate that brief documentation comments should be + // included into the set of code completions returned from this translation + // unit. + DxcTranslationUnitFlags_IncludeBriefCommentsInCodeCompletion = 0x80, + + // Used to indicate that compilation should occur on the caller's thread. + DxcTranslationUnitFlags_UseCallerThread = 0x800 +} DxcTranslationUnitFlags; + +typedef enum DxcCursorFormatting { + DxcCursorFormatting_Default = + 0x0, // Default rules, language-insensitive formatting. + DxcCursorFormatting_UseLanguageOptions = + 0x1, // Language-sensitive formatting. + DxcCursorFormatting_SuppressSpecifiers = 0x2, // Supresses type specifiers. + DxcCursorFormatting_SuppressTagKeyword = + 0x4, // Suppressed tag keyword (eg, 'class'). + DxcCursorFormatting_IncludeNamespaceKeyword = + 0x8, // Include namespace keyword. +} DxcCursorFormatting; + +enum DxcCursorKind { + /* Declarations */ + DxcCursor_UnexposedDecl = + 1, // A declaration whose specific kind is not exposed via this interface. + DxcCursor_StructDecl = 2, // A C or C++ struct. + DxcCursor_UnionDecl = 3, // A C or C++ union. + DxcCursor_ClassDecl = 4, // A C++ class. + DxcCursor_EnumDecl = 5, // An enumeration. + DxcCursor_FieldDecl = 6, // A field (in C) or non-static data member (in C++) + // in a struct, union, or C++ class. + DxcCursor_EnumConstantDecl = 7, // An enumerator constant. + DxcCursor_FunctionDecl = 8, // A function. + DxcCursor_VarDecl = 9, // A variable. + DxcCursor_ParmDecl = 10, // A function or method parameter. + DxcCursor_ObjCInterfaceDecl = 11, // An Objective-C interface. + DxcCursor_ObjCCategoryDecl = 12, // An Objective-C interface for a category. + DxcCursor_ObjCProtocolDecl = 13, // An Objective-C protocol declaration. + DxcCursor_ObjCPropertyDecl = 14, // An Objective-C property declaration. + DxcCursor_ObjCIvarDecl = 15, // An Objective-C instance variable. + DxcCursor_ObjCInstanceMethodDecl = 16, // An Objective-C instance method. + DxcCursor_ObjCClassMethodDecl = 17, // An Objective-C class method. + DxcCursor_ObjCImplementationDecl = 18, // An Objective-C \@implementation. + DxcCursor_ObjCCategoryImplDecl = + 19, // An Objective-C \@implementation for a category. + DxcCursor_TypedefDecl = 20, // A typedef + DxcCursor_CXXMethod = 21, // A C++ class method. + DxcCursor_Namespace = 22, // A C++ namespace. + DxcCursor_LinkageSpec = 23, // A linkage specification, e.g. 'extern "C"'. + DxcCursor_Constructor = 24, // A C++ constructor. + DxcCursor_Destructor = 25, // A C++ destructor. + DxcCursor_ConversionFunction = 26, // A C++ conversion function. + DxcCursor_TemplateTypeParameter = 27, // A C++ template type parameter. + DxcCursor_NonTypeTemplateParameter = 28, // A C++ non-type template parameter. + DxcCursor_TemplateTemplateParameter = + 29, // A C++ template template parameter. + DxcCursor_FunctionTemplate = 30, // A C++ function template. + DxcCursor_ClassTemplate = 31, // A C++ class template. + DxcCursor_ClassTemplatePartialSpecialization = + 32, // A C++ class template partial specialization. + DxcCursor_NamespaceAlias = 33, // A C++ namespace alias declaration. + DxcCursor_UsingDirective = 34, // A C++ using directive. + DxcCursor_UsingDeclaration = 35, // A C++ using declaration. + DxcCursor_TypeAliasDecl = 36, // A C++ alias declaration + DxcCursor_ObjCSynthesizeDecl = 37, // An Objective-C \@synthesize definition. + DxcCursor_ObjCDynamicDecl = 38, // An Objective-C \@dynamic definition. + DxcCursor_CXXAccessSpecifier = 39, // An access specifier. + + DxcCursor_FirstDecl = DxcCursor_UnexposedDecl, + DxcCursor_LastDecl = DxcCursor_CXXAccessSpecifier, + + /* References */ + DxcCursor_FirstRef = 40, /* Decl references */ + DxcCursor_ObjCSuperClassRef = 40, + DxcCursor_ObjCProtocolRef = 41, + DxcCursor_ObjCClassRef = 42, + /** + * \brief A reference to a type declaration. + * + * A type reference occurs anywhere where a type is named but not + * declared. For example, given: + * + * \code + * typedef unsigned size_type; + * size_type size; + * \endcode + * + * The typedef is a declaration of size_type (DxcCursor_TypedefDecl), + * while the type of the variable "size" is referenced. The cursor + * referenced by the type of size is the typedef for size_type. + */ + DxcCursor_TypeRef = 43, // A reference to a type declaration. + DxcCursor_CXXBaseSpecifier = 44, + DxcCursor_TemplateRef = + 45, // A reference to a class template, function template, template + // template parameter, or class template partial specialization. + DxcCursor_NamespaceRef = 46, // A reference to a namespace or namespace alias. + DxcCursor_MemberRef = + 47, // A reference to a member of a struct, union, or class that occurs in + // some non-expression context, e.g., a designated initializer. + /** + * \brief A reference to a labeled statement. + * + * This cursor kind is used to describe the jump to "start_over" in the + * goto statement in the following example: + * + * \code + * start_over: + * ++counter; + * + * goto start_over; + * \endcode + * + * A label reference cursor refers to a label statement. + */ + DxcCursor_LabelRef = 48, // A reference to a labeled statement. + + // A reference to a set of overloaded functions or function templates + // that has not yet been resolved to a specific function or function template. + // + // An overloaded declaration reference cursor occurs in C++ templates where + // a dependent name refers to a function. + DxcCursor_OverloadedDeclRef = 49, + DxcCursor_VariableRef = + 50, // A reference to a variable that occurs in some non-expression + // context, e.g., a C++ lambda capture list. + + DxcCursor_LastRef = DxcCursor_VariableRef, + + /* Error conditions */ + DxcCursor_FirstInvalid = 70, + DxcCursor_InvalidFile = 70, + DxcCursor_NoDeclFound = 71, + DxcCursor_NotImplemented = 72, + DxcCursor_InvalidCode = 73, + DxcCursor_LastInvalid = DxcCursor_InvalidCode, + + /* Expressions */ + DxcCursor_FirstExpr = 100, + + /** + * \brief An expression whose specific kind is not exposed via this + * interface. + * + * Unexposed expressions have the same operations as any other kind + * of expression; one can extract their location information, + * spelling, children, etc. However, the specific kind of the + * expression is not reported. + */ + DxcCursor_UnexposedExpr = 100, // An expression whose specific kind is not + // exposed via this interface. + DxcCursor_DeclRefExpr = + 101, // An expression that refers to some value declaration, such as a + // function, varible, or enumerator. + DxcCursor_MemberRefExpr = + 102, // An expression that refers to a member of a struct, union, class, + // Objective-C class, etc. + DxcCursor_CallExpr = 103, // An expression that calls a function. + DxcCursor_ObjCMessageExpr = 104, // An expression that sends a message to an + // Objective-C object or class. + DxcCursor_BlockExpr = 105, // An expression that represents a block literal. + DxcCursor_IntegerLiteral = 106, // An integer literal. + DxcCursor_FloatingLiteral = 107, // A floating point number literal. + DxcCursor_ImaginaryLiteral = 108, // An imaginary number literal. + DxcCursor_StringLiteral = 109, // A string literal. + DxcCursor_CharacterLiteral = 110, // A character literal. + DxcCursor_ParenExpr = + 111, // A parenthesized expression, e.g. "(1)". This AST node is only + // formed if full location information is requested. + DxcCursor_UnaryOperator = 112, // This represents the unary-expression's + // (except sizeof and alignof). + DxcCursor_ArraySubscriptExpr = 113, // [C99 6.5.2.1] Array Subscripting. + DxcCursor_BinaryOperator = + 114, // A builtin binary operation expression such as "x + y" or "x <= y". + DxcCursor_CompoundAssignOperator = 115, // Compound assignment such as "+=". + DxcCursor_ConditionalOperator = 116, // The ?: ternary operator. + DxcCursor_CStyleCastExpr = + 117, // An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ + // [expr.cast]), which uses the syntax (Type)expr, eg: (int)f. + DxcCursor_CompoundLiteralExpr = 118, // [C99 6.5.2.5] + DxcCursor_InitListExpr = 119, // Describes an C or C++ initializer list. + DxcCursor_AddrLabelExpr = + 120, // The GNU address of label extension, representing &&label. + DxcCursor_StmtExpr = + 121, // This is the GNU Statement Expression extension: ({int X=4; X;}) + DxcCursor_GenericSelectionExpr = 122, // Represents a C11 generic selection. + + /** \brief Implements the GNU __null extension, which is a name for a null + * pointer constant that has integral type (e.g., int or long) and is the same + * size and alignment as a pointer. + * + * The __null extension is typically only used by system headers, which define + * NULL as __null in C++ rather than using 0 (which is an integer that may not + * match the size of a pointer). + */ + DxcCursor_GNUNullExpr = 123, + DxcCursor_CXXStaticCastExpr = 124, // C++'s static_cast<> expression. + DxcCursor_CXXDynamicCastExpr = 125, // C++'s dynamic_cast<> expression. + DxcCursor_CXXReinterpretCastExpr = + 126, // C++'s reinterpret_cast<> expression. + DxcCursor_CXXConstCastExpr = 127, // C++'s const_cast<> expression. + + /** \brief Represents an explicit C++ type conversion that uses "functional" + * notion (C++ [expr.type.conv]). + * + * Example: + * \code + * x = int(0.5); + * \endcode + */ + DxcCursor_CXXFunctionalCastExpr = 128, + DxcCursor_CXXTypeidExpr = 129, // A C++ typeid expression (C++ [expr.typeid]). + DxcCursor_CXXBoolLiteralExpr = 130, // [C++ 2.13.5] C++ Boolean Literal. + DxcCursor_CXXNullPtrLiteralExpr = 131, // [C++0x 2.14.7] C++ Pointer Literal. + DxcCursor_CXXThisExpr = 132, // Represents the "this" expression in C++ + DxcCursor_CXXThrowExpr = 133, // [C++ 15] C++ Throw Expression, both 'throw' + // and 'throw' assignment-expression. + DxcCursor_CXXNewExpr = 134, // A new expression for memory allocation and + // constructor calls, e.g: "new CXXNewExpr(foo)". + DxcCursor_CXXDeleteExpr = + 135, // A delete expression for memory deallocation and destructor calls, + // e.g. "delete[] pArray". + DxcCursor_UnaryExpr = 136, // A unary expression. + DxcCursor_ObjCStringLiteral = + 137, // An Objective-C string literal i.e. @"foo". + DxcCursor_ObjCEncodeExpr = 138, // An Objective-C \@encode expression. + DxcCursor_ObjCSelectorExpr = 139, // An Objective-C \@selector expression. + DxcCursor_ObjCProtocolExpr = 140, // An Objective-C \@protocol expression. + + /** \brief An Objective-C "bridged" cast expression, which casts between + * Objective-C pointers and C pointers, transferring ownership in the process. + * + * \code + * NSString *str = (__bridge_transfer NSString *)CFCreateString(); + * \endcode + */ + DxcCursor_ObjCBridgedCastExpr = 141, + + /** \brief Represents a C++0x pack expansion that produces a sequence of + * expressions. + * + * A pack expansion expression contains a pattern (which itself is an + * expression) followed by an ellipsis. For example: + * + * \code + * template + * void forward(F f, Types &&...args) { + * f(static_cast(args)...); + * } + * \endcode + */ + DxcCursor_PackExpansionExpr = 142, + + /** \brief Represents an expression that computes the length of a parameter + * pack. + * + * \code + * template + * struct count { + * static const unsigned value = sizeof...(Types); + * }; + * \endcode + */ + DxcCursor_SizeOfPackExpr = 143, + + /* \brief Represents a C++ lambda expression that produces a local function + * object. + * + * \code + * void abssort(float *x, unsigned N) { + * std::sort(x, x + N, + * [](float a, float b) { + * return std::abs(a) < std::abs(b); + * }); + * } + * \endcode + */ + DxcCursor_LambdaExpr = 144, + DxcCursor_ObjCBoolLiteralExpr = 145, // Objective-c Boolean Literal. + DxcCursor_ObjCSelfExpr = + 146, // Represents the "self" expression in a ObjC method. + DxcCursor_LastExpr = DxcCursor_ObjCSelfExpr, + + /* Statements */ + DxcCursor_FirstStmt = 200, + /** + * \brief A statement whose specific kind is not exposed via this + * interface. + * + * Unexposed statements have the same operations as any other kind of + * statement; one can extract their location information, spelling, + * children, etc. However, the specific kind of the statement is not + * reported. + */ + DxcCursor_UnexposedStmt = 200, + + /** \brief A labelled statement in a function. + * + * This cursor kind is used to describe the "start_over:" label statement in + * the following example: + * + * \code + * start_over: + * ++counter; + * \endcode + * + */ + DxcCursor_LabelStmt = 201, + DxcCursor_CompoundStmt = + 202, // A group of statements like { stmt stmt }. This cursor kind is used + // to describe compound statements, e.g. function bodies. + DxcCursor_CaseStmt = 203, // A case statement. + DxcCursor_DefaultStmt = 204, // A default statement. + DxcCursor_IfStmt = 205, // An if statement + DxcCursor_SwitchStmt = 206, // A switch statement. + DxcCursor_WhileStmt = 207, // A while statement. + DxcCursor_DoStmt = 208, // A do statement. + DxcCursor_ForStmt = 209, // A for statement. + DxcCursor_GotoStmt = 210, // A goto statement. + DxcCursor_IndirectGotoStmt = 211, // An indirect goto statement. + DxcCursor_ContinueStmt = 212, // A continue statement. + DxcCursor_BreakStmt = 213, // A break statement. + DxcCursor_ReturnStmt = 214, // A return statement. + DxcCursor_GCCAsmStmt = 215, // A GCC inline assembly statement extension. + DxcCursor_AsmStmt = DxcCursor_GCCAsmStmt, + + DxcCursor_ObjCAtTryStmt = + 216, // Objective-C's overall \@try-\@catch-\@finally statement. + DxcCursor_ObjCAtCatchStmt = 217, // Objective-C's \@catch statement. + DxcCursor_ObjCAtFinallyStmt = 218, // Objective-C's \@finally statement. + DxcCursor_ObjCAtThrowStmt = 219, // Objective-C's \@throw statement. + DxcCursor_ObjCAtSynchronizedStmt = + 220, // Objective-C's \@synchronized statement. + DxcCursor_ObjCAutoreleasePoolStmt = + 221, // Objective-C's autorelease pool statement. + DxcCursor_ObjCForCollectionStmt = 222, // Objective-C's collection statement. + + DxcCursor_CXXCatchStmt = 223, // C++'s catch statement. + DxcCursor_CXXTryStmt = 224, // C++'s try statement. + DxcCursor_CXXForRangeStmt = 225, // C++'s for (* : *) statement. + + DxcCursor_SEHTryStmt = + 226, // Windows Structured Exception Handling's try statement. + DxcCursor_SEHExceptStmt = + 227, // Windows Structured Exception Handling's except statement. + DxcCursor_SEHFinallyStmt = + 228, // Windows Structured Exception Handling's finally statement. + + DxcCursor_MSAsmStmt = 229, // A MS inline assembly statement extension. + DxcCursor_NullStmt = 230, // The null satement ";": C99 6.8.3p3. + DxcCursor_DeclStmt = 231, // Adaptor class for mixing declarations with + // statements and expressions. + DxcCursor_OMPParallelDirective = 232, // OpenMP parallel directive. + DxcCursor_OMPSimdDirective = 233, // OpenMP SIMD directive. + DxcCursor_OMPForDirective = 234, // OpenMP for directive. + DxcCursor_OMPSectionsDirective = 235, // OpenMP sections directive. + DxcCursor_OMPSectionDirective = 236, // OpenMP section directive. + DxcCursor_OMPSingleDirective = 237, // OpenMP single directive. + DxcCursor_OMPParallelForDirective = 238, // OpenMP parallel for directive. + DxcCursor_OMPParallelSectionsDirective = + 239, // OpenMP parallel sections directive. + DxcCursor_OMPTaskDirective = 240, // OpenMP task directive. + DxcCursor_OMPMasterDirective = 241, // OpenMP master directive. + DxcCursor_OMPCriticalDirective = 242, // OpenMP critical directive. + DxcCursor_OMPTaskyieldDirective = 243, // OpenMP taskyield directive. + DxcCursor_OMPBarrierDirective = 244, // OpenMP barrier directive. + DxcCursor_OMPTaskwaitDirective = 245, // OpenMP taskwait directive. + DxcCursor_OMPFlushDirective = 246, // OpenMP flush directive. + DxcCursor_SEHLeaveStmt = + 247, // Windows Structured Exception Handling's leave statement. + DxcCursor_OMPOrderedDirective = 248, // OpenMP ordered directive. + DxcCursor_OMPAtomicDirective = 249, // OpenMP atomic directive. + DxcCursor_OMPForSimdDirective = 250, // OpenMP for SIMD directive. + DxcCursor_OMPParallelForSimdDirective = + 251, // OpenMP parallel for SIMD directive. + DxcCursor_OMPTargetDirective = 252, // OpenMP target directive. + DxcCursor_OMPTeamsDirective = 253, // OpenMP teams directive. + DxcCursor_OMPTaskgroupDirective = 254, // OpenMP taskgroup directive. + DxcCursor_OMPCancellationPointDirective = + 255, // OpenMP cancellation point directive. + DxcCursor_OMPCancelDirective = 256, // OpenMP cancel directive. + DxcCursor_LastStmt = DxcCursor_OMPCancelDirective, + + DxcCursor_TranslationUnit = + 300, // Cursor that represents the translation unit itself. + + /* Attributes */ + DxcCursor_FirstAttr = 400, + /** + * \brief An attribute whose specific kind is not exposed via this + * interface. + */ + DxcCursor_UnexposedAttr = 400, + + DxcCursor_IBActionAttr = 401, + DxcCursor_IBOutletAttr = 402, + DxcCursor_IBOutletCollectionAttr = 403, + DxcCursor_CXXFinalAttr = 404, + DxcCursor_CXXOverrideAttr = 405, + DxcCursor_AnnotateAttr = 406, + DxcCursor_AsmLabelAttr = 407, + DxcCursor_PackedAttr = 408, + DxcCursor_PureAttr = 409, + DxcCursor_ConstAttr = 410, + DxcCursor_NoDuplicateAttr = 411, + DxcCursor_CUDAConstantAttr = 412, + DxcCursor_CUDADeviceAttr = 413, + DxcCursor_CUDAGlobalAttr = 414, + DxcCursor_CUDAHostAttr = 415, + DxcCursor_CUDASharedAttr = 416, + DxcCursor_LastAttr = DxcCursor_CUDASharedAttr, + + /* Preprocessing */ + DxcCursor_PreprocessingDirective = 500, + DxcCursor_MacroDefinition = 501, + DxcCursor_MacroExpansion = 502, + DxcCursor_MacroInstantiation = DxcCursor_MacroExpansion, + DxcCursor_InclusionDirective = 503, + DxcCursor_FirstPreprocessing = DxcCursor_PreprocessingDirective, + DxcCursor_LastPreprocessing = DxcCursor_InclusionDirective, + + /* Extra Declarations */ + /** + * \brief A module import declaration. + */ + DxcCursor_ModuleImportDecl = 600, + DxcCursor_FirstExtraDecl = DxcCursor_ModuleImportDecl, + DxcCursor_LastExtraDecl = DxcCursor_ModuleImportDecl +}; + +enum DxcCursorKindFlags { + DxcCursorKind_None = 0, + DxcCursorKind_Declaration = 0x1, + DxcCursorKind_Reference = 0x2, + DxcCursorKind_Expression = 0x4, + DxcCursorKind_Statement = 0x8, + DxcCursorKind_Attribute = 0x10, + DxcCursorKind_Invalid = 0x20, + DxcCursorKind_TranslationUnit = 0x40, + DxcCursorKind_Preprocessing = 0x80, + DxcCursorKind_Unexposed = 0x100, +}; + +enum DxcCodeCompleteFlags { + DxcCodeCompleteFlags_None = 0, + DxcCodeCompleteFlags_IncludeMacros = 0x1, + DxcCodeCompleteFlags_IncludeCodePatterns = 0x2, + DxcCodeCompleteFlags_IncludeBriefComments = 0x4, +}; + +enum DxcCompletionChunkKind { + DxcCompletionChunk_Optional = 0, + DxcCompletionChunk_TypedText = 1, + DxcCompletionChunk_Text = 2, + DxcCompletionChunk_Placeholder = 3, + DxcCompletionChunk_Informative = 4, + DxcCompletionChunk_CurrentParameter = 5, + DxcCompletionChunk_LeftParen = 6, + DxcCompletionChunk_RightParen = 7, + DxcCompletionChunk_LeftBracket = 8, + DxcCompletionChunk_RightBracket = 9, + DxcCompletionChunk_LeftBrace = 10, + DxcCompletionChunk_RightBrace = 11, + DxcCompletionChunk_LeftAngle = 12, + DxcCompletionChunk_RightAngle = 13, + DxcCompletionChunk_Comma = 14, + DxcCompletionChunk_ResultType = 15, + DxcCompletionChunk_Colon = 16, + DxcCompletionChunk_SemiColon = 17, + DxcCompletionChunk_Equal = 18, + DxcCompletionChunk_HorizontalSpace = 19, + DxcCompletionChunk_VerticalSpace = 20, +}; + +struct IDxcCursor; +struct IDxcDiagnostic; +struct IDxcFile; +struct IDxcInclusion; +struct IDxcIntelliSense; +struct IDxcIndex; +struct IDxcSourceLocation; +struct IDxcSourceRange; +struct IDxcToken; +struct IDxcTranslationUnit; +struct IDxcType; +struct IDxcUnsavedFile; +struct IDxcCodeCompleteResults; +struct IDxcCompletionResult; +struct IDxcCompletionString; + +CROSS_PLATFORM_UUIDOF(IDxcCursor, "1467b985-288d-4d2a-80c1-ef89c42c40bc") +struct IDxcCursor : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + GetExtent(_Outptr_result_nullonfailure_ IDxcSourceRange **pRange) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetLocation(_Outptr_result_nullonfailure_ IDxcSourceLocation **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetKind(_Out_ DxcCursorKind *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetKindFlags(_Out_ DxcCursorKindFlags *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetSemanticParent(_Outptr_result_nullonfailure_ IDxcCursor **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetLexicalParent(_Outptr_result_nullonfailure_ IDxcCursor **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetCursorType(_Outptr_result_nullonfailure_ IDxcType **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetNumArguments(_Out_ int *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetArgumentAt( + int index, _Outptr_result_nullonfailure_ IDxcCursor **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetReferencedCursor(_Outptr_result_nullonfailure_ IDxcCursor **pResult) = 0; + /// For a cursor that is either a reference to or a declaration of + /// some entity, retrieve a cursor that describes the definition of that + /// entity. Some entities can be declared multiple times + /// within a translation unit, but only one of those declarations can also be + /// a definition. A cursor to the definition of this + /// entity; nullptr if there is no definition in this translation + /// unit. + virtual HRESULT STDMETHODCALLTYPE + GetDefinitionCursor(_Outptr_result_nullonfailure_ IDxcCursor **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + FindReferencesInFile(_In_ IDxcFile *file, unsigned skip, unsigned top, + _Out_ unsigned *pResultLength, + _Outptr_result_buffer_maybenull_(*pResultLength) + IDxcCursor ***pResult) = 0; + /// Gets the name for the entity references by the cursor, e.g. foo + /// for an 'int foo' variable. + virtual HRESULT STDMETHODCALLTYPE + GetSpelling(_Outptr_result_maybenull_ LPSTR *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE IsEqualTo(_In_ IDxcCursor *other, + _Out_ BOOL *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE IsNull(_Out_ BOOL *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE IsDefinition(_Out_ BOOL *pResult) = 0; + /// Gets the display name for the cursor, including e.g. parameter + /// types for a function. + virtual HRESULT STDMETHODCALLTYPE GetDisplayName(_Out_ BSTR *pResult) = 0; + /// Gets the qualified name for the symbol the cursor refers + /// to. + virtual HRESULT STDMETHODCALLTYPE GetQualifiedName( + BOOL includeTemplateArgs, _Outptr_result_maybenull_ BSTR *pResult) = 0; + /// Gets a name for the cursor, applying the specified formatting + /// flags. + virtual HRESULT STDMETHODCALLTYPE + GetFormattedName(DxcCursorFormatting formatting, + _Outptr_result_maybenull_ BSTR *pResult) = 0; + /// Gets children in pResult up to top elements. + virtual HRESULT STDMETHODCALLTYPE + GetChildren(unsigned skip, unsigned top, _Out_ unsigned *pResultLength, + _Outptr_result_buffer_maybenull_(*pResultLength) + IDxcCursor ***pResult) = 0; + /// Gets the cursor following a location within a compound + /// cursor. + virtual HRESULT STDMETHODCALLTYPE + GetSnappedChild(_In_ IDxcSourceLocation *location, + _Outptr_result_maybenull_ IDxcCursor **pResult) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcDiagnostic, "4f76b234-3659-4d33-99b0-3b0db994b564") +struct IDxcDiagnostic : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + FormatDiagnostic(DxcDiagnosticDisplayOptions options, + _Outptr_result_maybenull_ LPSTR *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetSeverity(_Out_ DxcDiagnosticSeverity *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetLocation(_Outptr_result_nullonfailure_ IDxcSourceLocation **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetSpelling(_Outptr_result_maybenull_ LPSTR *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetCategoryText(_Outptr_result_maybenull_ LPSTR *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetNumRanges(_Out_ unsigned *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetRangeAt(unsigned index, + _Outptr_result_nullonfailure_ IDxcSourceRange **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetNumFixIts(_Out_ unsigned *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetFixItAt(unsigned index, + _Outptr_result_nullonfailure_ IDxcSourceRange **pReplacementRange, + _Outptr_result_maybenull_ LPSTR *pText) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcFile, "bb2fca9e-1478-47ba-b08c-2c502ada4895") +struct IDxcFile : public IUnknown { + /// Gets the file name for this file. + virtual HRESULT STDMETHODCALLTYPE + GetName(_Outptr_result_maybenull_ LPSTR *pResult) = 0; + /// Checks whether this file is equal to the other specified + /// file. + virtual HRESULT STDMETHODCALLTYPE IsEqualTo(_In_ IDxcFile *other, + _Out_ BOOL *pResult) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcInclusion, "0c364d65-df44-4412-888e-4e552fc5e3d6") +struct IDxcInclusion : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + GetIncludedFile(_Outptr_result_nullonfailure_ IDxcFile **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetStackLength(_Out_ unsigned *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetStackItem(unsigned index, + _Outptr_result_nullonfailure_ IDxcSourceLocation **pResult) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcIntelliSense, "b1f99513-46d6-4112-8169-dd0d6053f17d") +struct IDxcIntelliSense : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + CreateIndex(_Outptr_result_nullonfailure_ IDxcIndex **index) = 0; + virtual HRESULT STDMETHODCALLTYPE GetNullLocation( + _Outptr_result_nullonfailure_ IDxcSourceLocation **location) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetNullRange(_Outptr_result_nullonfailure_ IDxcSourceRange **location) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetRange(_In_ IDxcSourceLocation *start, _In_ IDxcSourceLocation *end, + _Outptr_result_nullonfailure_ IDxcSourceRange **location) = 0; + virtual HRESULT STDMETHODCALLTYPE GetDefaultDiagnosticDisplayOptions( + _Out_ DxcDiagnosticDisplayOptions *pValue) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetDefaultEditingTUOptions(_Out_ DxcTranslationUnitFlags *pValue) = 0; + virtual HRESULT STDMETHODCALLTYPE CreateUnsavedFile( + _In_ LPCSTR fileName, _In_ LPCSTR contents, unsigned contentLength, + _Outptr_result_nullonfailure_ IDxcUnsavedFile **pResult) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcIndex, "937824a0-7f5a-4815-9ba7-7fc0424f4173") +struct IDxcIndex : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + SetGlobalOptions(DxcGlobalOptions options) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetGlobalOptions(_Out_ DxcGlobalOptions *options) = 0; + virtual HRESULT STDMETHODCALLTYPE ParseTranslationUnit( + _In_z_ const char *source_filename, + _In_count_(num_command_line_args) const char *const *command_line_args, + int num_command_line_args, + _In_count_(num_unsaved_files) IDxcUnsavedFile **unsaved_files, + unsigned num_unsaved_files, DxcTranslationUnitFlags options, + _Out_ IDxcTranslationUnit **pTranslationUnit) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcSourceLocation, + "8e7ddf1c-d7d3-4d69-b286-85fccba1e0cf") +struct IDxcSourceLocation : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE IsEqualTo(_In_ IDxcSourceLocation *other, + _Out_ BOOL *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetSpellingLocation( + _Outptr_opt_ IDxcFile **pFile, _Out_opt_ unsigned *pLine, + _Out_opt_ unsigned *pCol, _Out_opt_ unsigned *pOffset) = 0; + virtual HRESULT STDMETHODCALLTYPE IsNull(_Out_ BOOL *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetPresumedLocation(_Outptr_opt_ LPSTR *pFilename, _Out_opt_ unsigned *pLine, + _Out_opt_ unsigned *pCol) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcSourceRange, "f1359b36-a53f-4e81-b514-b6b84122a13f") +struct IDxcSourceRange : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE IsNull(_Out_ BOOL *pValue) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetStart(_Out_ IDxcSourceLocation **pValue) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetEnd(_Out_ IDxcSourceLocation **pValue) = 0; + virtual HRESULT STDMETHODCALLTYPE GetOffsets(_Out_ unsigned *startOffset, + _Out_ unsigned *endOffset) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcToken, "7f90b9ff-a275-4932-97d8-3cfd234482a2") +struct IDxcToken : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE GetKind(_Out_ DxcTokenKind *pValue) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetLocation(_Out_ IDxcSourceLocation **pValue) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetExtent(_Out_ IDxcSourceRange **pValue) = 0; + virtual HRESULT STDMETHODCALLTYPE GetSpelling(_Out_ LPSTR *pValue) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcTranslationUnit, + "9677dee0-c0e5-46a1-8b40-3db3168be63d") +struct IDxcTranslationUnit : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE GetCursor(_Out_ IDxcCursor **pCursor) = 0; + virtual HRESULT STDMETHODCALLTYPE + Tokenize(_In_ IDxcSourceRange *range, + _Outptr_result_buffer_maybenull_(*pTokenCount) IDxcToken ***pTokens, + _Out_ unsigned *pTokenCount) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetLocation(_In_ IDxcFile *file, unsigned line, unsigned column, + _Outptr_result_nullonfailure_ IDxcSourceLocation **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetNumDiagnostics(_Out_ unsigned *pValue) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetDiagnostic(unsigned index, + _Outptr_result_nullonfailure_ IDxcDiagnostic **pValue) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetFile(_In_ const char *name, + _Outptr_result_nullonfailure_ IDxcFile **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetFileName(_Outptr_result_maybenull_ LPSTR *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE Reparse(_In_count_(num_unsaved_files) + IDxcUnsavedFile **unsaved_files, + unsigned num_unsaved_files) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetCursorForLocation(_In_ IDxcSourceLocation *location, + _Outptr_result_nullonfailure_ IDxcCursor **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetLocationForOffset( + _In_ IDxcFile *file, unsigned offset, + _Outptr_result_nullonfailure_ IDxcSourceLocation **pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetSkippedRanges( + _In_ IDxcFile *file, _Out_ unsigned *pResultCount, + _Outptr_result_buffer_(*pResultCount) IDxcSourceRange ***pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetDiagnosticDetails(unsigned index, DxcDiagnosticDisplayOptions options, + _Out_ unsigned *errorCode, _Out_ unsigned *errorLine, + _Out_ unsigned *errorColumn, _Out_ BSTR *errorFile, + _Out_ unsigned *errorOffset, _Out_ unsigned *errorLength, + _Out_ BSTR *errorMessage) = 0; + virtual HRESULT STDMETHODCALLTYPE GetInclusionList( + _Out_ unsigned *pResultCount, + _Outptr_result_buffer_(*pResultCount) IDxcInclusion ***pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE CodeCompleteAt( + _In_ const char *fileName, unsigned line, unsigned column, + _In_ IDxcUnsavedFile **pUnsavedFiles, unsigned numUnsavedFiles, + _In_ DxcCodeCompleteFlags options, + _Outptr_result_nullonfailure_ IDxcCodeCompleteResults **pResult) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcType, "2ec912fd-b144-4a15-ad0d-1c5439c81e46") +struct IDxcType : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + GetSpelling(_Outptr_result_z_ LPSTR *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE IsEqualTo(_In_ IDxcType *other, + _Out_ BOOL *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetKind(_Out_ DxcTypeKind *pResult) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcUnsavedFile, "8ec00f98-07d0-4e60-9d7c-5a50b5b0017f") +struct IDxcUnsavedFile : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + GetFileName(_Outptr_result_z_ LPSTR *pFileName) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetContents(_Outptr_result_z_ LPSTR *pContents) = 0; + virtual HRESULT STDMETHODCALLTYPE GetLength(_Out_ unsigned *pLength) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcCodeCompleteResults, + "1E06466A-FD8B-45F3-A78F-8A3F76EBB552") +struct IDxcCodeCompleteResults : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE GetNumResults(_Out_ unsigned *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetResultAt(unsigned index, + _Outptr_result_nullonfailure_ IDxcCompletionResult **pResult) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcCompletionResult, + "943C0588-22D0-4784-86FC-701F802AC2B6") +struct IDxcCompletionResult : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + GetCursorKind(_Out_ DxcCursorKind *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetCompletionString( + _Outptr_result_nullonfailure_ IDxcCompletionString **pResult) = 0; +}; + +CROSS_PLATFORM_UUIDOF(IDxcCompletionString, + "06B51E0F-A605-4C69-A110-CD6E14B58EEC") +struct IDxcCompletionString : public IUnknown { + virtual HRESULT STDMETHODCALLTYPE + GetNumCompletionChunks(_Out_ unsigned *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE GetCompletionChunkKind( + unsigned chunkNumber, _Out_ DxcCompletionChunkKind *pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE + GetCompletionChunkText(unsigned chunkNumber, _Out_ LPSTR *pResult) = 0; +}; + +// Fun fact: 'extern' is required because const is by default static in C++, so +// CLSID_DxcIntelliSense is not visible externally (this is OK in C, since const +// is not by default static in C) + +#ifdef _MSC_VER +#define CLSID_SCOPE __declspec(selectany) extern +#else +#define CLSID_SCOPE +#endif + +CLSID_SCOPE const CLSID + CLSID_DxcIntelliSense = {/* 3047833c-d1c0-4b8e-9d40-102878605985 */ + 0x3047833c, + 0xd1c0, + 0x4b8e, + {0x9d, 0x40, 0x10, 0x28, 0x78, 0x60, 0x59, 0x85}}; + +#endif diff --git a/base/sources/libs/kong/sources/libs/dxc/lib/x64/dxcompiler.lib b/base/sources/libs/kong/sources/libs/dxc/lib/x64/dxcompiler.lib new file mode 100644 index 00000000..6bff5506 Binary files /dev/null and b/base/sources/libs/kong/sources/libs/dxc/lib/x64/dxcompiler.lib differ diff --git a/base/sources/libs/kong/sources/libs/stb_ds.c b/base/sources/libs/kong/sources/libs/stb_ds.c new file mode 100644 index 00000000..82ffae16 --- /dev/null +++ b/base/sources/libs/kong/sources/libs/stb_ds.c @@ -0,0 +1,3 @@ +#define STB_DS_IMPLEMENTATION + +#include "stb_ds.h" diff --git a/base/sources/libs/kong/sources/libs/stb_ds.h b/base/sources/libs/kong/sources/libs/stb_ds.h new file mode 100644 index 00000000..f0154d52 --- /dev/null +++ b/base/sources/libs/kong/sources/libs/stb_ds.h @@ -0,0 +1,1895 @@ +/* stb_ds.h - v0.67 - public domain data structures - Sean Barrett 2019 + + This is a single-header-file library that provides easy-to-use + dynamic arrays and hash tables for C (also works in C++). + + For a gentle introduction: + http://nothings.org/stb_ds + + To use this library, do this in *one* C or C++ file: + #define STB_DS_IMPLEMENTATION + #include "stb_ds.h" + +TABLE OF CONTENTS + + Table of Contents + Compile-time options + License + Documentation + Notes + Notes - Dynamic arrays + Notes - Hash maps + Credits + +COMPILE-TIME OPTIONS + + #define STBDS_NO_SHORT_NAMES + + This flag needs to be set globally. + + By default stb_ds exposes shorter function names that are not qualified + with the "stbds_" prefix. If these names conflict with the names in your + code, define this flag. + + #define STBDS_SIPHASH_2_4 + + This flag only needs to be set in the file containing #define STB_DS_IMPLEMENTATION. + + By default stb_ds.h hashes using a weaker variant of SipHash and a custom hash for + 4- and 8-byte keys. On 64-bit platforms, you can define the above flag to force + stb_ds.h to use specification-compliant SipHash-2-4 for all keys. Doing so makes + hash table insertion about 20% slower on 4- and 8-byte keys, 5% slower on + 64-byte keys, and 10% slower on 256-byte keys on my test computer. + + #define STBDS_REALLOC(context,ptr,size) better_realloc + #define STBDS_FREE(context,ptr) better_free + + These defines only need to be set in the file containing #define STB_DS_IMPLEMENTATION. + + By default stb_ds uses stdlib realloc() and free() for memory management. You can + substitute your own functions instead by defining these symbols. You must either + define both, or neither. Note that at the moment, 'context' will always be NULL. + @TODO add an array/hash initialization function that takes a memory context pointer. + + #define STBDS_UNIT_TESTS + + Defines a function stbds_unit_tests() that checks the functioning of the data structures. + + Note that on older versions of gcc (e.g. 5.x.x) you may need to build with '-std=c++0x' + (or equivalentally '-std=c++11') when using anonymous structures as seen on the web + page or in STBDS_UNIT_TESTS. + +LICENSE + + Placed in the public domain and also MIT licensed. + See end of file for detailed license information. + +DOCUMENTATION + + Dynamic Arrays + + Non-function interface: + + Declare an empty dynamic array of type T + T* foo = NULL; + + Access the i'th item of a dynamic array 'foo' of type T, T* foo: + foo[i] + + Functions (actually macros) + + arrfree: + void arrfree(T*); + Frees the array. + + arrlen: + ptrdiff_t arrlen(T*); + Returns the number of elements in the array. + + arrlenu: + size_t arrlenu(T*); + Returns the number of elements in the array as an unsigned type. + + arrpop: + T arrpop(T* a) + Removes the final element of the array and returns it. + + arrput: + T arrput(T* a, T b); + Appends the item b to the end of array a. Returns b. + + arrins: + T arrins(T* a, int p, T b); + Inserts the item b into the middle of array a, into a[p], + moving the rest of the array over. Returns b. + + arrinsn: + void arrinsn(T* a, int p, int n); + Inserts n uninitialized items into array a starting at a[p], + moving the rest of the array over. + + arraddnptr: + T* arraddnptr(T* a, int n) + Appends n uninitialized items onto array at the end. + Returns a pointer to the first uninitialized item added. + + arraddnindex: + size_t arraddnindex(T* a, int n) + Appends n uninitialized items onto array at the end. + Returns the index of the first uninitialized item added. + + arrdel: + void arrdel(T* a, int p); + Deletes the element at a[p], moving the rest of the array over. + + arrdeln: + void arrdeln(T* a, int p, int n); + Deletes n elements starting at a[p], moving the rest of the array over. + + arrdelswap: + void arrdelswap(T* a, int p); + Deletes the element at a[p], replacing it with the element from + the end of the array. O(1) performance. + + arrsetlen: + void arrsetlen(T* a, int n); + Changes the length of the array to n. Allocates uninitialized + slots at the end if necessary. + + arrsetcap: + size_t arrsetcap(T* a, int n); + Sets the length of allocated storage to at least n. It will not + change the length of the array. + + arrcap: + size_t arrcap(T* a); + Returns the number of total elements the array can contain without + needing to be reallocated. + + Hash maps & String hash maps + + Given T is a structure type: struct { TK key; TV value; }. Note that some + functions do not require TV value and can have other fields. For string + hash maps, TK must be 'char *'. + + Special interface: + + stbds_rand_seed: + void stbds_rand_seed(size_t seed); + For security against adversarially chosen data, you should seed the + library with a strong random number. Or at least seed it with time(). + + stbds_hash_string: + size_t stbds_hash_string(char *str, size_t seed); + Returns a hash value for a string. + + stbds_hash_bytes: + size_t stbds_hash_bytes(void *p, size_t len, size_t seed); + These functions hash an arbitrary number of bytes. The function + uses a custom hash for 4- and 8-byte data, and a weakened version + of SipHash for everything else. On 64-bit platforms you can get + specification-compliant SipHash-2-4 on all data by defining + STBDS_SIPHASH_2_4, at a significant cost in speed. + + Non-function interface: + + Declare an empty hash map of type T + T* foo = NULL; + + Access the i'th entry in a hash table T* foo: + foo[i] + + Function interface (actually macros): + + hmfree + shfree + void hmfree(T*); + void shfree(T*); + Frees the hashmap and sets the pointer to NULL. + + hmlen + shlen + ptrdiff_t hmlen(T*) + ptrdiff_t shlen(T*) + Returns the number of elements in the hashmap. + + hmlenu + shlenu + size_t hmlenu(T*) + size_t shlenu(T*) + Returns the number of elements in the hashmap. + + hmgeti + shgeti + hmgeti_ts + ptrdiff_t hmgeti(T*, TK key) + ptrdiff_t shgeti(T*, char* key) + ptrdiff_t hmgeti_ts(T*, TK key, ptrdiff_t tempvar) + Returns the index in the hashmap which has the key 'key', or -1 + if the key is not present. + + hmget + hmget_ts + shget + TV hmget(T*, TK key) + TV shget(T*, char* key) + TV hmget_ts(T*, TK key, ptrdiff_t tempvar) + Returns the value corresponding to 'key' in the hashmap. + The structure must have a 'value' field + + hmgets + shgets + T hmgets(T*, TK key) + T shgets(T*, char* key) + Returns the structure corresponding to 'key' in the hashmap. + + hmgetp + shgetp + hmgetp_ts + hmgetp_null + shgetp_null + T* hmgetp(T*, TK key) + T* shgetp(T*, char* key) + T* hmgetp_ts(T*, TK key, ptrdiff_t tempvar) + T* hmgetp_null(T*, TK key) + T* shgetp_null(T*, char *key) + Returns a pointer to the structure corresponding to 'key' in + the hashmap. Functions ending in "_null" return NULL if the key + is not present in the hashmap; the others return a pointer to a + structure holding the default value (but not the searched-for key). + + hmdefault + shdefault + TV hmdefault(T*, TV value) + TV shdefault(T*, TV value) + Sets the default value for the hashmap, the value which will be + returned by hmget/shget if the key is not present. + + hmdefaults + shdefaults + TV hmdefaults(T*, T item) + TV shdefaults(T*, T item) + Sets the default struct for the hashmap, the contents which will be + returned by hmgets/shgets if the key is not present. + + hmput + shput + TV hmput(T*, TK key, TV value) + TV shput(T*, char* key, TV value) + Inserts a pair into the hashmap. If the key is already + present in the hashmap, updates its value. + + hmputs + shputs + T hmputs(T*, T item) + T shputs(T*, T item) + Inserts a struct with T.key into the hashmap. If the struct is already + present in the hashmap, updates it. + + hmdel + shdel + int hmdel(T*, TK key) + int shdel(T*, char* key) + If 'key' is in the hashmap, deletes its entry and returns 1. + Otherwise returns 0. + + Function interface (actually macros) for strings only: + + sh_new_strdup + void sh_new_strdup(T*); + Overwrites the existing pointer with a newly allocated + string hashmap which will automatically allocate and free + each string key using realloc/free + + sh_new_arena + void sh_new_arena(T*); + Overwrites the existing pointer with a newly allocated + string hashmap which will automatically allocate each string + key to a string arena. Every string key ever used by this + hash table remains in the arena until the arena is freed. + Additionally, any key which is deleted and reinserted will + be allocated multiple times in the string arena. + +NOTES + + * These data structures are realloc'd when they grow, and the macro + "functions" write to the provided pointer. This means: (a) the pointer + must be an lvalue, and (b) the pointer to the data structure is not + stable, and you must maintain it the same as you would a realloc'd + pointer. For example, if you pass a pointer to a dynamic array to a + function which updates it, the function must return back the new + pointer to the caller. This is the price of trying to do this in C. + + * The following are the only functions that are thread-safe on a single data + structure, i.e. can be run in multiple threads simultaneously on the same + data structure + hmlen shlen + hmlenu shlenu + hmget_ts shget_ts + hmgeti_ts shgeti_ts + hmgets_ts shgets_ts + + * You iterate over the contents of a dynamic array and a hashmap in exactly + the same way, using arrlen/hmlen/shlen: + + for (i=0; i < arrlen(foo); ++i) + ... foo[i] ... + + * All operations except arrins/arrdel are O(1) amortized, but individual + operations can be slow, so these data structures may not be suitable + for real time use. Dynamic arrays double in capacity as needed, so + elements are copied an average of once. Hash tables double/halve + their size as needed, with appropriate hysteresis to maintain O(1) + performance. + +NOTES - DYNAMIC ARRAY + + * If you know how long a dynamic array is going to be in advance, you can avoid + extra memory allocations by using arrsetlen to allocate it to that length in + advance and use foo[n] while filling it out, or arrsetcap to allocate the memory + for that length and use arrput/arrpush as normal. + + * Unlike some other versions of the dynamic array, this version should + be safe to use with strict-aliasing optimizations. + +NOTES - HASH MAP + + * For compilers other than GCC and clang (e.g. Visual Studio), for hmput/hmget/hmdel + and variants, the key must be an lvalue (so the macro can take the address of it). + Extensions are used that eliminate this requirement if you're using C99 and later + in GCC or clang, or if you're using C++ in GCC. But note that this can make your + code less portable. + + * To test for presence of a key in a hashmap, just do 'hmgeti(foo,key) >= 0'. + + * The iteration order of your data in the hashmap is determined solely by the + order of insertions and deletions. In particular, if you never delete, new + keys are always added at the end of the array. This will be consistent + across all platforms and versions of the library. However, you should not + attempt to serialize the internal hash table, as the hash is not consistent + between different platforms, and may change with future versions of the library. + + * Use sh_new_arena() for string hashmaps that you never delete from. Initialize + with NULL if you're managing the memory for your strings, or your strings are + never freed (at least until the hashmap is freed). Otherwise, use sh_new_strdup(). + @TODO: make an arena variant that garbage collects the strings with a trivial + copy collector into a new arena whenever the table shrinks / rebuilds. Since + current arena recommendation is to only use arena if it never deletes, then + this can just replace current arena implementation. + + * If adversarial input is a serious concern and you're on a 64-bit platform, + enable STBDS_SIPHASH_2_4 (see the 'Compile-time options' section), and pass + a strong random number to stbds_rand_seed. + + * The default value for the hash table is stored in foo[-1], so if you + use code like 'hmget(T,k)->value = 5' you can accidentally overwrite + the value stored by hmdefault if 'k' is not present. + +CREDITS + + Sean Barrett -- library, idea for dynamic array API/implementation + Per Vognsen -- idea for hash table API/implementation + Rafael Sachetto -- arrpop() + github:HeroicKatora -- arraddn() reworking + + Bugfixes: + Andy Durdin + Shane Liesegang + Vinh Truong + Andreas Molzer + github:hashitaku + github:srdjanstipic + Macoy Madson + Andreas Vennstrom + Tobias Mansfield-Williams +*/ + +#ifdef STBDS_UNIT_TESTS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef INCLUDE_STB_DS_H +#define INCLUDE_STB_DS_H + +#include +#include + +#ifndef STBDS_NO_SHORT_NAMES +#define arrlen stbds_arrlen +#define arrlenu stbds_arrlenu +#define arrput stbds_arrput +#define arrpush stbds_arrput +#define arrpop stbds_arrpop +#define arrfree stbds_arrfree +#define arraddn stbds_arraddn // deprecated, use one of the following instead: +#define arraddnptr stbds_arraddnptr +#define arraddnindex stbds_arraddnindex +#define arrsetlen stbds_arrsetlen +#define arrlast stbds_arrlast +#define arrins stbds_arrins +#define arrinsn stbds_arrinsn +#define arrdel stbds_arrdel +#define arrdeln stbds_arrdeln +#define arrdelswap stbds_arrdelswap +#define arrcap stbds_arrcap +#define arrsetcap stbds_arrsetcap + +#define hmput stbds_hmput +#define hmputs stbds_hmputs +#define hmget stbds_hmget +#define hmget_ts stbds_hmget_ts +#define hmgets stbds_hmgets +#define hmgetp stbds_hmgetp +#define hmgetp_ts stbds_hmgetp_ts +#define hmgetp_null stbds_hmgetp_null +#define hmgeti stbds_hmgeti +#define hmgeti_ts stbds_hmgeti_ts +#define hmdel stbds_hmdel +#define hmlen stbds_hmlen +#define hmlenu stbds_hmlenu +#define hmfree stbds_hmfree +#define hmdefault stbds_hmdefault +#define hmdefaults stbds_hmdefaults + +#define shput stbds_shput +#define shputi stbds_shputi +#define shputs stbds_shputs +#define shget stbds_shget +#define shgeti stbds_shgeti +#define shgets stbds_shgets +#define shgetp stbds_shgetp +#define shgetp_null stbds_shgetp_null +#define shdel stbds_shdel +#define shlen stbds_shlen +#define shlenu stbds_shlenu +#define shfree stbds_shfree +#define shdefault stbds_shdefault +#define shdefaults stbds_shdefaults +#define sh_new_arena stbds_sh_new_arena +#define sh_new_strdup stbds_sh_new_strdup + +#define stralloc stbds_stralloc +#define strreset stbds_strreset +#endif + +#if defined(STBDS_REALLOC) && !defined(STBDS_FREE) || !defined(STBDS_REALLOC) && defined(STBDS_FREE) +#error "You must define both STBDS_REALLOC and STBDS_FREE, or neither." +#endif +#if !defined(STBDS_REALLOC) && !defined(STBDS_FREE) +#include +#define STBDS_REALLOC(c,p,s) realloc(p,s) +#define STBDS_FREE(c,p) free(p) +#endif + +#ifdef _MSC_VER +#define STBDS_NOTUSED(v) (void)(v) +#else +#define STBDS_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// for security against attackers, seed the library with a random number, at least time() but stronger is better +extern void stbds_rand_seed(size_t seed); + +// these are the hash functions used internally if you want to test them or use them for other purposes +extern size_t stbds_hash_bytes(void *p, size_t len, size_t seed); +extern size_t stbds_hash_string(char *str, size_t seed); + +// this is a simple string arena allocator, initialize with e.g. 'stbds_string_arena my_arena={0}'. +typedef struct stbds_string_arena stbds_string_arena; +extern char * stbds_stralloc(stbds_string_arena *a, char *str); +extern void stbds_strreset(stbds_string_arena *a); + +// have to #define STBDS_UNIT_TESTS to call this +extern void stbds_unit_tests(void); + +/////////////// +// +// Everything below here is implementation details +// + +extern void * stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap); +extern void stbds_arrfreef(void *a); +extern void stbds_hmfree_func(void *p, size_t elemsize); +extern void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); +extern void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode); +extern void * stbds_hmput_default(void *a, size_t elemsize); +extern void * stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); +extern void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode); +extern void * stbds_shmode_func(size_t elemsize, int mode); + +#ifdef __cplusplus +} +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define STBDS_HAS_TYPEOF +#ifdef __cplusplus +//#define STBDS_HAS_LITERAL_ARRAY // this is currently broken for clang +#endif +#endif + +#if !defined(__cplusplus) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define STBDS_HAS_LITERAL_ARRAY +#endif +#endif + +// this macro takes the address of the argument, but on gcc/clang can accept rvalues +#if defined(STBDS_HAS_LITERAL_ARRAY) && defined(STBDS_HAS_TYPEOF) + #if __clang__ + #define STBDS_ADDRESSOF(typevar, value) ((__typeof__(typevar)[1]){value}) // literal array decays to pointer to value + #else + #define STBDS_ADDRESSOF(typevar, value) ((typeof(typevar)[1]){value}) // literal array decays to pointer to value + #endif +#else +#define STBDS_ADDRESSOF(typevar, value) &(value) +#endif + +#define STBDS_OFFSETOF(var,field) ((char *) &(var)->field - (char *) (var)) + +#define stbds_header(t) ((stbds_array_header *) (t) - 1) +#define stbds_temp(t) stbds_header(t)->temp +#define stbds_temp_key(t) (*(char **) stbds_header(t)->hash_table) + +#define stbds_arrsetcap(a,n) (stbds_arrgrow(a,0,n)) +#define stbds_arrsetlen(a,n) ((stbds_arrcap(a) < (size_t) (n) ? stbds_arrsetcap((a),(size_t)(n)),0 : 0), (a) ? stbds_header(a)->length = (size_t) (n) : 0) +#define stbds_arrcap(a) ((a) ? stbds_header(a)->capacity : 0) +#define stbds_arrlen(a) ((a) ? (ptrdiff_t) stbds_header(a)->length : 0) +#define stbds_arrlenu(a) ((a) ? stbds_header(a)->length : 0) +#define stbds_arrput(a,v) (stbds_arrmaybegrow(a,1), (a)[stbds_header(a)->length++] = (v)) +#define stbds_arrpush stbds_arrput // synonym +#define stbds_arrpop(a) (stbds_header(a)->length--, (a)[stbds_header(a)->length]) +#define stbds_arraddn(a,n) ((void)(stbds_arraddnindex(a, n))) // deprecated, use one of the following instead: +#define stbds_arraddnptr(a,n) (stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), &(a)[stbds_header(a)->length-(n)]) : (a)) +#define stbds_arraddnindex(a,n)(stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), stbds_header(a)->length-(n)) : stbds_arrlen(a)) +#define stbds_arraddnoff stbds_arraddnindex +#define stbds_arrlast(a) ((a)[stbds_header(a)->length-1]) +#define stbds_arrfree(a) ((void) ((a) ? STBDS_FREE(NULL,stbds_header(a)) : (void)0), (a)=NULL) +#define stbds_arrdel(a,i) stbds_arrdeln(a,i,1) +#define stbds_arrdeln(a,i,n) (memmove(&(a)[i], &(a)[(i)+(n)], sizeof *(a) * (stbds_header(a)->length-(n)-(i))), stbds_header(a)->length -= (n)) +#define stbds_arrdelswap(a,i) ((a)[i] = stbds_arrlast(a), stbds_header(a)->length -= 1) +#define stbds_arrinsn(a,i,n) (stbds_arraddn((a),(n)), memmove(&(a)[(i)+(n)], &(a)[i], sizeof *(a) * (stbds_header(a)->length-(n)-(i)))) +#define stbds_arrins(a,i,v) (stbds_arrinsn((a),(i),1), (a)[i]=(v)) + +#define stbds_arrmaybegrow(a,n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \ + ? (stbds_arrgrow(a,n,0),0) : 0) + +#define stbds_arrgrow(a,b,c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c))) + +#define stbds_hmput(t, k, v) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, 0), \ + (t)[stbds_temp((t)-1)].key = (k), \ + (t)[stbds_temp((t)-1)].value = (v)) + +#define stbds_hmputs(t, s) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), &(s).key, sizeof (s).key, STBDS_HM_BINARY), \ + (t)[stbds_temp((t)-1)] = (s)) + +#define stbds_hmgeti(t,k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_HM_BINARY), \ + stbds_temp((t)-1)) + +#define stbds_hmgeti_ts(t,k,temp) \ + ((t) = stbds_hmget_key_ts_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, &(temp), STBDS_HM_BINARY), \ + (temp)) + +#define stbds_hmgetp(t, k) \ + ((void) stbds_hmgeti(t,k), &(t)[stbds_temp((t)-1)]) + +#define stbds_hmgetp_ts(t, k, temp) \ + ((void) stbds_hmgeti_ts(t,k,temp), &(t)[temp]) + +#define stbds_hmdel(t,k) \ + (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_BINARY)),(t)?stbds_temp((t)-1):0) + +#define stbds_hmdefault(t, v) \ + ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1].value = (v)) + +#define stbds_hmdefaults(t, s) \ + ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1] = (s)) + +#define stbds_hmfree(p) \ + ((void) ((p) != NULL ? stbds_hmfree_func((p)-1,sizeof*(p)),0 : 0),(p)=NULL) + +#define stbds_hmgets(t, k) (*stbds_hmgetp(t,k)) +#define stbds_hmget(t, k) (stbds_hmgetp(t,k)->value) +#define stbds_hmget_ts(t, k, temp) (stbds_hmgetp_ts(t,k,temp)->value) +#define stbds_hmlen(t) ((t) ? (ptrdiff_t) stbds_header((t)-1)->length-1 : 0) +#define stbds_hmlenu(t) ((t) ? stbds_header((t)-1)->length-1 : 0) +#define stbds_hmgetp_null(t,k) (stbds_hmgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) + +#define stbds_shput(t, k, v) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ + (t)[stbds_temp((t)-1)].value = (v)) + +#define stbds_shputi(t, k, v) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ + (t)[stbds_temp((t)-1)].value = (v), stbds_temp((t)-1)) + +#define stbds_shputs(t, s) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (s).key, sizeof (s).key, STBDS_HM_STRING), \ + (t)[stbds_temp((t)-1)] = (s), \ + (t)[stbds_temp((t)-1)].key = stbds_temp_key((t)-1)) // above line overwrites whole structure, so must rewrite key here if it was allocated internally + +#define stbds_pshput(t, p) \ + ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (p)->key, sizeof (p)->key, STBDS_HM_PTR_TO_STRING), \ + (t)[stbds_temp((t)-1)] = (p)) + +#define stbds_shgeti(t,k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ + stbds_temp((t)-1)) + +#define stbds_pshgeti(t,k) \ + ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_HM_PTR_TO_STRING), \ + stbds_temp((t)-1)) + +#define stbds_shgetp(t, k) \ + ((void) stbds_shgeti(t,k), &(t)[stbds_temp((t)-1)]) + +#define stbds_pshget(t, k) \ + ((void) stbds_pshgeti(t,k), (t)[stbds_temp((t)-1)]) + +#define stbds_shdel(t,k) \ + (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_STRING)),(t)?stbds_temp((t)-1):0) +#define stbds_pshdel(t,k) \ + (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_OFFSETOF(*(t),key), STBDS_HM_PTR_TO_STRING)),(t)?stbds_temp((t)-1):0) + +#define stbds_sh_new_arena(t) \ + ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_ARENA)) +#define stbds_sh_new_strdup(t) \ + ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_STRDUP)) + +#define stbds_shdefault(t, v) stbds_hmdefault(t,v) +#define stbds_shdefaults(t, s) stbds_hmdefaults(t,s) + +#define stbds_shfree stbds_hmfree +#define stbds_shlenu stbds_hmlenu + +#define stbds_shgets(t, k) (*stbds_shgetp(t,k)) +#define stbds_shget(t, k) (stbds_shgetp(t,k)->value) +#define stbds_shgetp_null(t,k) (stbds_shgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) +#define stbds_shlen stbds_hmlen + +typedef struct +{ + size_t length; + size_t capacity; + void * hash_table; + ptrdiff_t temp; +} stbds_array_header; + +typedef struct stbds_string_block +{ + struct stbds_string_block *next; + char storage[8]; +} stbds_string_block; + +struct stbds_string_arena +{ + stbds_string_block *storage; + size_t remaining; + unsigned char block; + unsigned char mode; // this isn't used by the string arena itself +}; + +#define STBDS_HM_BINARY 0 +#define STBDS_HM_STRING 1 + +enum +{ + STBDS_SH_NONE, + STBDS_SH_DEFAULT, + STBDS_SH_STRDUP, + STBDS_SH_ARENA +}; + +#ifdef __cplusplus +// in C we use implicit assignment from these void*-returning functions to T*. +// in C++ these templates make the same code work +template static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_t addlen, size_t min_cap) { + return (T*)stbds_arrgrowf((void *)a, elemsize, addlen, min_cap); +} +template static T * stbds_hmget_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { + return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode); +} +template static T * stbds_hmget_key_ts_wrapper(T *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) { + return (T*)stbds_hmget_key_ts((void*)a, elemsize, key, keysize, temp, mode); +} +template static T * stbds_hmput_default_wrapper(T *a, size_t elemsize) { + return (T*)stbds_hmput_default((void *)a, elemsize); +} +template static T * stbds_hmput_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { + return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode); +} +template static T * stbds_hmdel_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode){ + return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode); +} +template static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int mode) { + return (T*)stbds_shmode_func(elemsize, mode); +} +#else +#define stbds_arrgrowf_wrapper stbds_arrgrowf +#define stbds_hmget_key_wrapper stbds_hmget_key +#define stbds_hmget_key_ts_wrapper stbds_hmget_key_ts +#define stbds_hmput_default_wrapper stbds_hmput_default +#define stbds_hmput_key_wrapper stbds_hmput_key +#define stbds_hmdel_key_wrapper stbds_hmdel_key +#define stbds_shmode_func_wrapper(t,e,m) stbds_shmode_func(e,m) +#endif + +#endif // INCLUDE_STB_DS_H + + +////////////////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION +// + +#ifdef STB_DS_IMPLEMENTATION +#include +#include + +#ifndef STBDS_ASSERT +#define STBDS_ASSERT_WAS_UNDEFINED +#define STBDS_assert__(x) ((void) 0) +#endif + +#ifdef STBDS_STATISTICS +#define STBDS_STATS(x) x +size_t stbds_array_grow; +size_t stbds_hash_grow; +size_t stbds_hash_shrink; +size_t stbds_hash_rebuild; +size_t stbds_hash_probes; +size_t stbds_hash_alloc; +size_t stbds_rehash_probes; +size_t stbds_rehash_items; +#else +#define STBDS_STATS(x) +#endif + +// +// stbds_arr implementation +// + +//int *prev_allocs[65536]; +//int num_prev; + +void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap) +{ + stbds_array_header temp={0}; // force debugging + void *b; + size_t min_len = stbds_arrlen(a) + addlen; + (void) sizeof(temp); + + // compute the minimum capacity needed + if (min_len > min_cap) + min_cap = min_len; + + if (min_cap <= stbds_arrcap(a)) + return a; + + // increase needed capacity to guarantee O(1) amortized + if (min_cap < 2 * stbds_arrcap(a)) + min_cap = 2 * stbds_arrcap(a); + else if (min_cap < 4) + min_cap = 4; + + //if (num_prev < 65536) if (a) prev_allocs[num_prev++] = (int *) ((char *) a+1); + //if (num_prev == 2201) + // num_prev = num_prev; + b = STBDS_REALLOC(NULL, (a) ? stbds_header(a) : 0, elemsize * min_cap + sizeof(stbds_array_header)); + //if (num_prev < 65536) prev_allocs[num_prev++] = (int *) (char *) b; + b = (char *) b + sizeof(stbds_array_header); + if (a == NULL) { + stbds_header(b)->length = 0; + stbds_header(b)->hash_table = 0; + stbds_header(b)->temp = 0; + } else { + STBDS_STATS(++stbds_array_grow); + } + stbds_header(b)->capacity = min_cap; + + return b; +} + +void stbds_arrfreef(void *a) +{ + STBDS_FREE(NULL, stbds_header(a)); +} + +// +// stbds_hm hash table implementation +// + +#ifdef STBDS_INTERNAL_SMALL_BUCKET +#define STBDS_BUCKET_LENGTH 4 +#else +#define STBDS_BUCKET_LENGTH 8 +#endif + +#define STBDS_BUCKET_SHIFT (STBDS_BUCKET_LENGTH == 8 ? 3 : 2) +#define STBDS_BUCKET_MASK (STBDS_BUCKET_LENGTH-1) +#define STBDS_CACHE_LINE_SIZE 64 + +#define STBDS_ALIGN_FWD(n,a) (((n) + (a) - 1) & ~((a)-1)) + +typedef struct +{ + size_t hash [STBDS_BUCKET_LENGTH]; + ptrdiff_t index[STBDS_BUCKET_LENGTH]; +} stbds_hash_bucket; // in 32-bit, this is one 64-byte cache line; in 64-bit, each array is one 64-byte cache line + +typedef struct +{ + char * temp_key; // this MUST be the first field of the hash table + size_t slot_count; + size_t used_count; + size_t used_count_threshold; + size_t used_count_shrink_threshold; + size_t tombstone_count; + size_t tombstone_count_threshold; + size_t seed; + size_t slot_count_log2; + stbds_string_arena string; + stbds_hash_bucket *storage; // not a separate allocation, just 64-byte aligned storage after this struct +} stbds_hash_index; + +#define STBDS_INDEX_EMPTY -1 +#define STBDS_INDEX_DELETED -2 +#define STBDS_INDEX_IN_USE(x) ((x) >= 0) + +#define STBDS_HASH_EMPTY 0 +#define STBDS_HASH_DELETED 1 + +static size_t stbds_hash_seed=0x31415926; + +void stbds_rand_seed(size_t seed) +{ + stbds_hash_seed = seed; +} + +#define stbds_load_32_or_64(var, temp, v32, v64_hi, v64_lo) \ + temp = v64_lo ^ v32, temp <<= 16, temp <<= 16, temp >>= 16, temp >>= 16, /* discard if 32-bit */ \ + var = v64_hi, var <<= 16, var <<= 16, /* discard if 32-bit */ \ + var ^= temp ^ v32 + +#define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8) + +static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) +{ + size_t pos; + STBDS_NOTUSED(slot_log2); + pos = hash & (slot_count-1); + #ifdef STBDS_INTERNAL_BUCKET_START + pos &= ~STBDS_BUCKET_MASK; + #endif + return pos; +} + +static size_t stbds_log2(size_t slot_count) +{ + size_t n=0; + while (slot_count > 1) { + slot_count >>= 1; + ++n; + } + return n; +} + +static stbds_hash_index *stbds_make_hash_index(size_t slot_count, stbds_hash_index *ot) +{ + stbds_hash_index *t; + t = (stbds_hash_index *) STBDS_REALLOC(NULL,0,(slot_count >> STBDS_BUCKET_SHIFT) * sizeof(stbds_hash_bucket) + sizeof(stbds_hash_index) + STBDS_CACHE_LINE_SIZE-1); + t->storage = (stbds_hash_bucket *) STBDS_ALIGN_FWD((size_t) (t+1), STBDS_CACHE_LINE_SIZE); + t->slot_count = slot_count; + t->slot_count_log2 = stbds_log2(slot_count); + t->tombstone_count = 0; + t->used_count = 0; + + #if 0 // A1 + t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink + #elif 1 // A2 + //t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow + //t->tombstone_count_threshold = slot_count* 3/16; // if tombstones are 3/16th of table, rebuild + //t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink + + // compute without overflowing + t->used_count_threshold = slot_count - (slot_count>>2); + t->tombstone_count_threshold = (slot_count>>3) + (slot_count>>4); + t->used_count_shrink_threshold = slot_count >> 2; + + #elif 0 // B1 + t->used_count_threshold = slot_count*13/16; // if 13/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count* 5/16; // if table is only 5/16th full, shrink + #else // C1 + t->used_count_threshold = slot_count*14/16; // if 14/16th of table is occupied, grow + t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild + t->used_count_shrink_threshold = slot_count* 6/16; // if table is only 6/16th full, shrink + #endif + // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 + // Note that the larger tables have high variance as they were run fewer times + // A1 A2 B1 C1 + // 0.10ms : 0.10ms : 0.10ms : 0.11ms : 2,000 inserts creating 2K table + // 0.96ms : 0.95ms : 0.97ms : 1.04ms : 20,000 inserts creating 20K table + // 14.48ms : 14.46ms : 10.63ms : 11.00ms : 200,000 inserts creating 200K table + // 195.74ms : 196.35ms : 203.69ms : 214.92ms : 2,000,000 inserts creating 2M table + // 2193.88ms : 2209.22ms : 2285.54ms : 2437.17ms : 20,000,000 inserts creating 20M table + // 65.27ms : 53.77ms : 65.33ms : 65.47ms : 500,000 inserts & deletes in 2K table + // 72.78ms : 62.45ms : 71.95ms : 72.85ms : 500,000 inserts & deletes in 20K table + // 89.47ms : 77.72ms : 96.49ms : 96.75ms : 500,000 inserts & deletes in 200K table + // 97.58ms : 98.14ms : 97.18ms : 97.53ms : 500,000 inserts & deletes in 2M table + // 118.61ms : 119.62ms : 120.16ms : 118.86ms : 500,000 inserts & deletes in 20M table + // 192.11ms : 194.39ms : 196.38ms : 195.73ms : 500,000 inserts & deletes in 200M table + + if (slot_count <= STBDS_BUCKET_LENGTH) + t->used_count_shrink_threshold = 0; + // to avoid infinite loop, we need to guarantee that at least one slot is empty and will terminate probes + STBDS_assert__(t->used_count_threshold + t->tombstone_count_threshold < t->slot_count); + STBDS_STATS(++stbds_hash_alloc); + if (ot) { + t->string = ot->string; + // reuse old seed so we can reuse old hashes so below "copy out old data" doesn't do any hashing + t->seed = ot->seed; + } else { + size_t a,b,temp; + memset(&t->string, 0, sizeof(t->string)); + t->seed = stbds_hash_seed; + // LCG + // in 32-bit, a = 2147001325 b = 715136305 + // in 64-bit, a = 2862933555777941757 b = 3037000493 + stbds_load_32_or_64(a,temp, 2147001325, 0x27bb2ee6, 0x87b0b0fd); + stbds_load_32_or_64(b,temp, 715136305, 0, 0xb504f32d); + stbds_hash_seed = stbds_hash_seed * a + b; + } + + { + size_t i,j; + for (i=0; i < slot_count >> STBDS_BUCKET_SHIFT; ++i) { + stbds_hash_bucket *b = &t->storage[i]; + for (j=0; j < STBDS_BUCKET_LENGTH; ++j) + b->hash[j] = STBDS_HASH_EMPTY; + for (j=0; j < STBDS_BUCKET_LENGTH; ++j) + b->index[j] = STBDS_INDEX_EMPTY; + } + } + + // copy out the old data, if any + if (ot) { + size_t i,j; + t->used_count = ot->used_count; + for (i=0; i < ot->slot_count >> STBDS_BUCKET_SHIFT; ++i) { + stbds_hash_bucket *ob = &ot->storage[i]; + for (j=0; j < STBDS_BUCKET_LENGTH; ++j) { + if (STBDS_INDEX_IN_USE(ob->index[j])) { + size_t hash = ob->hash[j]; + size_t pos = stbds_probe_position(hash, t->slot_count, t->slot_count_log2); + size_t step = STBDS_BUCKET_LENGTH; + STBDS_STATS(++stbds_rehash_items); + for (;;) { + size_t limit,z; + stbds_hash_bucket *bucket; + bucket = &t->storage[pos >> STBDS_BUCKET_SHIFT]; + STBDS_STATS(++stbds_rehash_probes); + + for (z=pos & STBDS_BUCKET_MASK; z < STBDS_BUCKET_LENGTH; ++z) { + if (bucket->hash[z] == 0) { + bucket->hash[z] = hash; + bucket->index[z] = ob->index[j]; + goto done; + } + } + + limit = pos & STBDS_BUCKET_MASK; + for (z = 0; z < limit; ++z) { + if (bucket->hash[z] == 0) { + bucket->hash[z] = hash; + bucket->index[z] = ob->index[j]; + goto done; + } + } + + pos += step; // quadratic probing + step += STBDS_BUCKET_LENGTH; + pos &= (t->slot_count-1); + } + } + done: + ; + } + } + } + + return t; +} + +#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n)))) +#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n)))) + +size_t stbds_hash_string(char *str, size_t seed) +{ + size_t hash = seed; + while (*str) + hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char) *str++; + + // Thomas Wang 64-to-32 bit mix function, hopefully also works in 32 bits + hash ^= seed; + hash = (~hash) + (hash << 18); + hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,31); + hash = hash * 21; + hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,11); + hash += (hash << 6); + hash ^= STBDS_ROTATE_RIGHT(hash,22); + return hash+seed; +} + +#ifdef STBDS_SIPHASH_2_4 +#define STBDS_SIPHASH_C_ROUNDS 2 +#define STBDS_SIPHASH_D_ROUNDS 4 +typedef int STBDS_SIPHASH_2_4_can_only_be_used_in_64_bit_builds[sizeof(size_t) == 8 ? 1 : -1]; +#endif + +#ifndef STBDS_SIPHASH_C_ROUNDS +#define STBDS_SIPHASH_C_ROUNDS 1 +#endif +#ifndef STBDS_SIPHASH_D_ROUNDS +#define STBDS_SIPHASH_D_ROUNDS 1 +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()== +#endif + +static size_t stbds_siphash_bytes(void *p, size_t len, size_t seed) +{ + unsigned char *d = (unsigned char *) p; + size_t i,j; + size_t v0,v1,v2,v3, data; + + // hash that works on 32- or 64-bit registers without knowing which we have + // (computes different results on 32-bit and 64-bit platform) + // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit + v0 = ((((size_t) 0x736f6d65 << 16) << 16) + 0x70736575) ^ seed; + v1 = ((((size_t) 0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed; + v2 = ((((size_t) 0x6c796765 << 16) << 16) + 0x6e657261) ^ seed; + v3 = ((((size_t) 0x74656462 << 16) << 16) + 0x79746573) ^ ~seed; + + #ifdef STBDS_TEST_SIPHASH_2_4 + // hardcoded with key material in the siphash test vectors + v0 ^= 0x0706050403020100ull ^ seed; + v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; + v2 ^= 0x0706050403020100ull ^ seed; + v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; + #endif + + #define STBDS_SIPROUND() \ + do { \ + v0 += v1; v1 = STBDS_ROTATE_LEFT(v1, 13); v1 ^= v0; v0 = STBDS_ROTATE_LEFT(v0,STBDS_SIZE_T_BITS/2); \ + v2 += v3; v3 = STBDS_ROTATE_LEFT(v3, 16); v3 ^= v2; \ + v2 += v1; v1 = STBDS_ROTATE_LEFT(v1, 17); v1 ^= v2; v2 = STBDS_ROTATE_LEFT(v2,STBDS_SIZE_T_BITS/2); \ + v0 += v3; v3 = STBDS_ROTATE_LEFT(v3, 21); v3 ^= v0; \ + } while (0) + + for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) { + data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + data |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4 + + v3 ^= data; + for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) + STBDS_SIPROUND(); + v0 ^= data; + } + data = len << (STBDS_SIZE_T_BITS-8); + switch (len - i) { + case 7: data |= ((size_t) d[6] << 24) << 24; // fall through + case 6: data |= ((size_t) d[5] << 20) << 20; // fall through + case 5: data |= ((size_t) d[4] << 16) << 16; // fall through + case 4: data |= (d[3] << 24); // fall through + case 3: data |= (d[2] << 16); // fall through + case 2: data |= (d[1] << 8); // fall through + case 1: data |= d[0]; // fall through + case 0: break; + } + v3 ^= data; + for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) + STBDS_SIPROUND(); + v0 ^= data; + v2 ^= 0xff; + for (j=0; j < STBDS_SIPHASH_D_ROUNDS; ++j) + STBDS_SIPROUND(); + +#ifdef STBDS_SIPHASH_2_4 + return v0^v1^v2^v3; +#else + return v1^v2^v3; // slightly stronger since v0^v3 in above cancels out final round operation? I tweeted at the authors of SipHash about this but they didn't reply +#endif +} + +size_t stbds_hash_bytes(void *p, size_t len, size_t seed) +{ +#ifdef STBDS_SIPHASH_2_4 + return stbds_siphash_bytes(p,len,seed); +#else + unsigned char *d = (unsigned char *) p; + + if (len == 4) { + unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + #if 0 + // HASH32-A Bob Jenkin's hash function w/o large constants + hash ^= seed; + hash -= (hash<<6); + hash ^= (hash>>17); + hash -= (hash<<9); + hash ^= seed; + hash ^= (hash<<4); + hash -= (hash<<3); + hash ^= (hash<<10); + hash ^= (hash>>15); + #elif 1 + // HASH32-BB Bob Jenkin's presumably-accidental version of Thomas Wang hash with rotates turned into shifts. + // Note that converting these back to rotates makes it run a lot slower, presumably due to collisions, so I'm + // not really sure what's going on. + hash ^= seed; + hash = (hash ^ 61) ^ (hash >> 16); + hash = hash + (hash << 3); + hash = hash ^ (hash >> 4); + hash = hash * 0x27d4eb2d; + hash ^= seed; + hash = hash ^ (hash >> 15); + #else // HASH32-C - Murmur3 + hash ^= seed; + hash *= 0xcc9e2d51; + hash = (hash << 17) | (hash >> 15); + hash *= 0x1b873593; + hash ^= seed; + hash = (hash << 19) | (hash >> 13); + hash = hash*5 + 0xe6546b64; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= seed; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + #endif + // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 + // Note that the larger tables have high variance as they were run fewer times + // HASH32-A // HASH32-BB // HASH32-C + // 0.10ms // 0.10ms // 0.10ms : 2,000 inserts creating 2K table + // 0.96ms // 0.95ms // 0.99ms : 20,000 inserts creating 20K table + // 14.69ms // 14.43ms // 14.97ms : 200,000 inserts creating 200K table + // 199.99ms // 195.36ms // 202.05ms : 2,000,000 inserts creating 2M table + // 2234.84ms // 2187.74ms // 2240.38ms : 20,000,000 inserts creating 20M table + // 55.68ms // 53.72ms // 57.31ms : 500,000 inserts & deletes in 2K table + // 63.43ms // 61.99ms // 65.73ms : 500,000 inserts & deletes in 20K table + // 80.04ms // 77.96ms // 81.83ms : 500,000 inserts & deletes in 200K table + // 100.42ms // 97.40ms // 102.39ms : 500,000 inserts & deletes in 2M table + // 119.71ms // 120.59ms // 121.63ms : 500,000 inserts & deletes in 20M table + // 185.28ms // 195.15ms // 187.74ms : 500,000 inserts & deletes in 200M table + // 15.58ms // 14.79ms // 15.52ms : 200,000 inserts creating 200K table with varying key spacing + + return (((size_t) hash << 16 << 16) | hash) ^ seed; + } else if (len == 8 && sizeof(size_t) == 8) { + size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); + hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 + hash ^= seed; + hash = (~hash) + (hash << 21); + hash ^= STBDS_ROTATE_RIGHT(hash,24); + hash *= 265; + hash ^= STBDS_ROTATE_RIGHT(hash,14); + hash ^= seed; + hash *= 21; + hash ^= STBDS_ROTATE_RIGHT(hash,28); + hash += (hash << 31); + hash = (~hash) + (hash << 18); + return hash; + } else { + return stbds_siphash_bytes(p,len,seed); + } +#endif +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, size_t i) +{ + if (mode >= STBDS_HM_STRING) + return 0==strcmp((char *) key, * (char **) ((char *) a + elemsize*i + keyoffset)); + else + return 0==memcmp(key, (char *) a + elemsize*i + keyoffset, keysize); +} + +#define STBDS_HASH_TO_ARR(x,elemsize) ((char*) (x) - (elemsize)) +#define STBDS_ARR_TO_HASH(x,elemsize) ((char*) (x) + (elemsize)) + +#define stbds_hash_table(a) ((stbds_hash_index *) stbds_header(a)->hash_table) + +void stbds_hmfree_func(void *a, size_t elemsize) +{ + if (a == NULL) return; + if (stbds_hash_table(a) != NULL) { + if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) { + size_t i; + // skip 0th element, which is default + for (i=1; i < stbds_header(a)->length; ++i) + STBDS_FREE(NULL, *(char**) ((char *) a + elemsize*i)); + } + stbds_strreset(&stbds_hash_table(a)->string); + } + STBDS_FREE(NULL, stbds_header(a)->hash_table); + STBDS_FREE(NULL, stbds_header(a)); +} + +static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) +{ + void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); + stbds_hash_index *table = stbds_hash_table(raw_a); + size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); + size_t step = STBDS_BUCKET_LENGTH; + size_t limit,i; + size_t pos; + stbds_hash_bucket *bucket; + + if (hash < 2) hash += 2; // stored hash values are forbidden from being 0, so we can detect empty slots + + pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); + + for (;;) { + STBDS_STATS(++stbds_hash_probes); + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + + // start searching from pos to end of bucket, this should help performance on small hash tables that fit in cache + for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + return (pos & ~STBDS_BUCKET_MASK)+i; + } + } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { + return -1; + } + } + + // search from beginning of bucket to pos + limit = pos & STBDS_BUCKET_MASK; + for (i = 0; i < limit; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + return (pos & ~STBDS_BUCKET_MASK)+i; + } + } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { + return -1; + } + } + + // quadratic probing + pos += step; + step += STBDS_BUCKET_LENGTH; + pos &= (table->slot_count-1); + } + /* NOTREACHED */ +} + +void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) +{ + size_t keyoffset = 0; + if (a == NULL) { + // make it non-empty so we can return a temp + a = stbds_arrgrowf(0, elemsize, 0, 1); + stbds_header(a)->length += 1; + memset(a, 0, elemsize); + *temp = STBDS_INDEX_EMPTY; + // adjust a to point after the default element + return STBDS_ARR_TO_HASH(a,elemsize); + } else { + stbds_hash_index *table; + void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); + // adjust a to point to the default element + table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; + if (table == 0) { + *temp = -1; + } else { + ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); + if (slot < 0) { + *temp = STBDS_INDEX_EMPTY; + } else { + stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + *temp = b->index[slot & STBDS_BUCKET_MASK]; + } + } + return a; + } +} + +void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) +{ + ptrdiff_t temp; + void *p = stbds_hmget_key_ts(a, elemsize, key, keysize, &temp, mode); + stbds_temp(STBDS_HASH_TO_ARR(p,elemsize)) = temp; + return p; +} + +void * stbds_hmput_default(void *a, size_t elemsize) +{ + // three cases: + // a is NULL <- allocate + // a has a hash table but no entries, because of shmode <- grow + // a has entries <- do nothing + if (a == NULL || stbds_header(STBDS_HASH_TO_ARR(a,elemsize))->length == 0) { + a = stbds_arrgrowf(a ? STBDS_HASH_TO_ARR(a,elemsize) : NULL, elemsize, 0, 1); + stbds_header(a)->length += 1; + memset(a, 0, elemsize); + a=STBDS_ARR_TO_HASH(a,elemsize); + } + return a; +} + +static char *stbds_strdup(char *str); + +void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) +{ + size_t keyoffset=0; + void *raw_a; + stbds_hash_index *table; + + if (a == NULL) { + a = stbds_arrgrowf(0, elemsize, 0, 1); + memset(a, 0, elemsize); + stbds_header(a)->length += 1; + // adjust a to point AFTER the default element + a = STBDS_ARR_TO_HASH(a,elemsize); + } + + // adjust a to point to the default element + raw_a = a; + a = STBDS_HASH_TO_ARR(a,elemsize); + + table = (stbds_hash_index *) stbds_header(a)->hash_table; + + if (table == NULL || table->used_count >= table->used_count_threshold) { + stbds_hash_index *nt; + size_t slot_count; + + slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count*2; + nt = stbds_make_hash_index(slot_count, table); + if (table) + STBDS_FREE(NULL, table); + else + nt->string.mode = mode >= STBDS_HM_STRING ? STBDS_SH_DEFAULT : 0; + stbds_header(a)->hash_table = table = nt; + STBDS_STATS(++stbds_hash_grow); + } + + // we iterate hash table explicitly because we want to track if we saw a tombstone + { + size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); + size_t step = STBDS_BUCKET_LENGTH; + size_t pos; + ptrdiff_t tombstone = -1; + stbds_hash_bucket *bucket; + + // stored hash values are forbidden from being 0, so we can detect empty slots to early out quickly + if (hash < 2) hash += 2; + + pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); + + for (;;) { + size_t limit, i; + STBDS_STATS(++stbds_hash_probes); + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + + // start searching from pos to end of bucket + for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + stbds_temp(a) = bucket->index[i]; + if (mode >= STBDS_HM_STRING) + stbds_temp_key(a) = * (char **) ((char *) raw_a + elemsize*bucket->index[i] + keyoffset); + return STBDS_ARR_TO_HASH(a,elemsize); + } + } else if (bucket->hash[i] == 0) { + pos = (pos & ~STBDS_BUCKET_MASK) + i; + goto found_empty_slot; + } else if (tombstone < 0) { + if (bucket->index[i] == STBDS_INDEX_DELETED) + tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); + } + } + + // search from beginning of bucket to pos + limit = pos & STBDS_BUCKET_MASK; + for (i = 0; i < limit; ++i) { + if (bucket->hash[i] == hash) { + if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { + stbds_temp(a) = bucket->index[i]; + return STBDS_ARR_TO_HASH(a,elemsize); + } + } else if (bucket->hash[i] == 0) { + pos = (pos & ~STBDS_BUCKET_MASK) + i; + goto found_empty_slot; + } else if (tombstone < 0) { + if (bucket->index[i] == STBDS_INDEX_DELETED) + tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); + } + } + + // quadratic probing + pos += step; + step += STBDS_BUCKET_LENGTH; + pos &= (table->slot_count-1); + } + found_empty_slot: + if (tombstone >= 0) { + pos = tombstone; + --table->tombstone_count; + } + ++table->used_count; + + { + ptrdiff_t i = (ptrdiff_t) stbds_arrlen(a); + // we want to do stbds_arraddn(1), but we can't use the macros since we don't have something of the right type + if ((size_t) i+1 > stbds_arrcap(a)) + *(void **) &a = stbds_arrgrowf(a, elemsize, 1, 0); + raw_a = STBDS_ARR_TO_HASH(a,elemsize); + + STBDS_assert__((size_t) i+1 <= stbds_arrcap(a)); + stbds_header(a)->length = i+1; + bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; + bucket->hash[pos & STBDS_BUCKET_MASK] = hash; + bucket->index[pos & STBDS_BUCKET_MASK] = i-1; + stbds_temp(a) = i-1; + + switch (table->string.mode) { + case STBDS_SH_STRDUP: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_strdup((char*) key); break; + case STBDS_SH_ARENA: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key); break; + case STBDS_SH_DEFAULT: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = (char *) key; break; + default: memcpy((char *) a + elemsize*i, key, keysize); break; + } + } + return STBDS_ARR_TO_HASH(a,elemsize); + } +} + +void * stbds_shmode_func(size_t elemsize, int mode) +{ + void *a = stbds_arrgrowf(0, elemsize, 0, 1); + stbds_hash_index *h; + memset(a, 0, elemsize); + stbds_header(a)->length = 1; + stbds_header(a)->hash_table = h = (stbds_hash_index *) stbds_make_hash_index(STBDS_BUCKET_LENGTH, NULL); + h->string.mode = (unsigned char) mode; + return STBDS_ARR_TO_HASH(a,elemsize); +} + +void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) +{ + if (a == NULL) { + return 0; + } else { + stbds_hash_index *table; + void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); + table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; + stbds_temp(raw_a) = 0; + if (table == 0) { + return a; + } else { + ptrdiff_t slot; + slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); + if (slot < 0) + return a; + else { + stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + int i = slot & STBDS_BUCKET_MASK; + ptrdiff_t old_index = b->index[i]; + ptrdiff_t final_index = (ptrdiff_t) stbds_arrlen(raw_a)-1-1; // minus one for the raw_a vs a, and minus one for 'last' + STBDS_assert__(slot < (ptrdiff_t) table->slot_count); + --table->used_count; + ++table->tombstone_count; + stbds_temp(raw_a) = 1; + STBDS_assert__(table->used_count >= 0); + //STBDS_assert__(table->tombstone_count < table->slot_count/4); + b->hash[i] = STBDS_HASH_DELETED; + b->index[i] = STBDS_INDEX_DELETED; + + if (mode == STBDS_HM_STRING && table->string.mode == STBDS_SH_STRDUP) + STBDS_FREE(NULL, *(char**) ((char *) a+elemsize*old_index)); + + // if indices are the same, memcpy is a no-op, but back-pointer-fixup will fail, so skip + if (old_index != final_index) { + // swap delete + memmove((char*) a + elemsize*old_index, (char*) a + elemsize*final_index, elemsize); + + // now find the slot for the last element + if (mode == STBDS_HM_STRING) + slot = stbds_hm_find_slot(a, elemsize, *(char**) ((char *) a+elemsize*old_index + keyoffset), keysize, keyoffset, mode); + else + slot = stbds_hm_find_slot(a, elemsize, (char* ) a+elemsize*old_index + keyoffset, keysize, keyoffset, mode); + STBDS_assert__(slot >= 0); + b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; + i = slot & STBDS_BUCKET_MASK; + STBDS_assert__(b->index[i] == final_index); + b->index[i] = old_index; + } + stbds_header(raw_a)->length -= 1; + + if (table->used_count < table->used_count_shrink_threshold && table->slot_count > STBDS_BUCKET_LENGTH) { + stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count>>1, table); + STBDS_FREE(NULL, table); + STBDS_STATS(++stbds_hash_shrink); + } else if (table->tombstone_count > table->tombstone_count_threshold) { + stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count , table); + STBDS_FREE(NULL, table); + STBDS_STATS(++stbds_hash_rebuild); + } + + return a; + } + } + } + /* NOTREACHED */ +} + +static char *stbds_strdup(char *str) +{ + // to keep replaceable allocator simple, we don't want to use strdup. + // rolling our own also avoids problem of strdup vs _strdup + size_t len = strlen(str)+1; + char *p = (char*) STBDS_REALLOC(NULL, 0, len); + memmove(p, str, len); + return p; +} + +#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MIN +#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512u +#endif +#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MAX +#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u<<20) +#endif + +char *stbds_stralloc(stbds_string_arena *a, char *str) +{ + char *p; + size_t len = strlen(str)+1; + if (len > a->remaining) { + // compute the next blocksize + size_t blocksize = a->block; + + // size is 512, 512, 1024, 1024, 2048, 2048, 4096, 4096, etc., so that + // there are log(SIZE) allocations to free when we destroy the table + blocksize = (size_t) (STBDS_STRING_ARENA_BLOCKSIZE_MIN) << (blocksize>>1); + + // if size is under 1M, advance to next blocktype + if (blocksize < (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MAX)) + ++a->block; + + if (len > blocksize) { + // if string is larger than blocksize, then just allocate the full size. + // note that we still advance string_block so block size will continue + // increasing, so e.g. if somebody only calls this with 1000-long strings, + // eventually the arena will start doubling and handling those as well + stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + len); + memmove(sb->storage, str, len); + if (a->storage) { + // insert it after the first element, so that we don't waste the space there + sb->next = a->storage->next; + a->storage->next = sb; + } else { + sb->next = 0; + a->storage = sb; + a->remaining = 0; // this is redundant, but good for clarity + } + return sb->storage; + } else { + stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + blocksize); + sb->next = a->storage; + a->storage = sb; + a->remaining = blocksize; + } + } + + STBDS_assert__(len <= a->remaining); + p = a->storage->storage + a->remaining - len; + a->remaining -= len; + memmove(p, str, len); + return p; +} + +void stbds_strreset(stbds_string_arena *a) +{ + stbds_string_block *x,*y; + x = a->storage; + while (x) { + y = x->next; + STBDS_FREE(NULL, x); + x = y; + } + memset(a, 0, sizeof(*a)); +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// UNIT TESTS +// + +#ifdef STBDS_UNIT_TESTS +#include +#ifdef STBDS_ASSERT_WAS_UNDEFINED +#undef STBDS_ASSERT +#endif +#ifndef STBDS_ASSERT +#define STBDS_ASSERT assert +#include +#endif + +typedef struct { int key,b,c,d; } stbds_struct; +typedef struct { int key[2],b,c,d; } stbds_struct2; + +static char buffer[256]; +char *strkey(int n) +{ +#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) + sprintf_s(buffer, sizeof(buffer), "test_%d", n); +#else + sprintf(buffer, "test_%d", n); +#endif + return buffer; +} + +void stbds_unit_tests(void) +{ +#if defined(_MSC_VER) && _MSC_VER <= 1200 && defined(__cplusplus) + // VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing! + STBDS_assert__(0); +#else + const int testsize = 100000; + const int testsize2 = testsize/20; + int *arr=NULL; + struct { int key; int value; } *intmap = NULL; + struct { char *key; int value; } *strmap = NULL, s; + struct { stbds_struct key; int value; } *map = NULL; + stbds_struct *map2 = NULL; + stbds_struct2 *map3 = NULL; + stbds_string_arena sa = { 0 }; + int key3[2] = { 1,2 }; + ptrdiff_t temp; + + int i,j; + + STBDS_assert__(arrlen(arr)==0); + for (i=0; i < 20000; i += 50) { + for (j=0; j < i; ++j) + arrpush(arr,j); + arrfree(arr); + } + + for (i=0; i < 4; ++i) { + arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); + arrdel(arr,i); + arrfree(arr); + arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); + arrdelswap(arr,i); + arrfree(arr); + } + + for (i=0; i < 5; ++i) { + arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); + stbds_arrins(arr,i,5); + STBDS_assert__(arr[i] == 5); + if (i < 4) + STBDS_assert__(arr[4] == 4); + arrfree(arr); + } + + i = 1; + STBDS_assert__(hmgeti(intmap,i) == -1); + hmdefault(intmap, -2); + STBDS_assert__(hmgeti(intmap, i) == -1); + STBDS_assert__(hmget (intmap, i) == -2); + for (i=0; i < testsize; i+=2) + hmput(intmap, i, i*5); + for (i=0; i < testsize; i+=1) { + if (i & 1) STBDS_assert__(hmget(intmap, i) == -2 ); + else STBDS_assert__(hmget(intmap, i) == i*5); + if (i & 1) STBDS_assert__(hmget_ts(intmap, i, temp) == -2 ); + else STBDS_assert__(hmget_ts(intmap, i, temp) == i*5); + } + for (i=0; i < testsize; i+=2) + hmput(intmap, i, i*3); + for (i=0; i < testsize; i+=1) + if (i & 1) STBDS_assert__(hmget(intmap, i) == -2 ); + else STBDS_assert__(hmget(intmap, i) == i*3); + for (i=2; i < testsize; i+=4) + hmdel(intmap, i); // delete half the entries + for (i=0; i < testsize; i+=1) + if (i & 3) STBDS_assert__(hmget(intmap, i) == -2 ); + else STBDS_assert__(hmget(intmap, i) == i*3); + for (i=0; i < testsize; i+=1) + hmdel(intmap, i); // delete the rest of the entries + for (i=0; i < testsize; i+=1) + STBDS_assert__(hmget(intmap, i) == -2 ); + hmfree(intmap); + for (i=0; i < testsize; i+=2) + hmput(intmap, i, i*3); + hmfree(intmap); + + #if defined(__clang__) || defined(__GNUC__) + #ifndef __cplusplus + intmap = NULL; + hmput(intmap, 15, 7); + hmput(intmap, 11, 3); + hmput(intmap, 9, 5); + STBDS_assert__(hmget(intmap, 9) == 5); + STBDS_assert__(hmget(intmap, 11) == 3); + STBDS_assert__(hmget(intmap, 15) == 7); + #endif + #endif + + for (i=0; i < testsize; ++i) + stralloc(&sa, strkey(i)); + strreset(&sa); + + { + s.key = "a", s.value = 1; + shputs(strmap, s); + STBDS_assert__(*strmap[0].key == 'a'); + STBDS_assert__(strmap[0].key == s.key); + STBDS_assert__(strmap[0].value == s.value); + shfree(strmap); + } + + { + s.key = "a", s.value = 1; + sh_new_strdup(strmap); + shputs(strmap, s); + STBDS_assert__(*strmap[0].key == 'a'); + STBDS_assert__(strmap[0].key != s.key); + STBDS_assert__(strmap[0].value == s.value); + shfree(strmap); + } + + { + s.key = "a", s.value = 1; + sh_new_arena(strmap); + shputs(strmap, s); + STBDS_assert__(*strmap[0].key == 'a'); + STBDS_assert__(strmap[0].key != s.key); + STBDS_assert__(strmap[0].value == s.value); + shfree(strmap); + } + + for (j=0; j < 2; ++j) { + STBDS_assert__(shgeti(strmap,"foo") == -1); + if (j == 0) + sh_new_strdup(strmap); + else + sh_new_arena(strmap); + STBDS_assert__(shgeti(strmap,"foo") == -1); + shdefault(strmap, -2); + STBDS_assert__(shgeti(strmap,"foo") == -1); + for (i=0; i < testsize; i+=2) + shput(strmap, strkey(i), i*3); + for (i=0; i < testsize; i+=1) + if (i & 1) STBDS_assert__(shget(strmap, strkey(i)) == -2 ); + else STBDS_assert__(shget(strmap, strkey(i)) == i*3); + for (i=2; i < testsize; i+=4) + shdel(strmap, strkey(i)); // delete half the entries + for (i=0; i < testsize; i+=1) + if (i & 3) STBDS_assert__(shget(strmap, strkey(i)) == -2 ); + else STBDS_assert__(shget(strmap, strkey(i)) == i*3); + for (i=0; i < testsize; i+=1) + shdel(strmap, strkey(i)); // delete the rest of the entries + for (i=0; i < testsize; i+=1) + STBDS_assert__(shget(strmap, strkey(i)) == -2 ); + shfree(strmap); + } + + { + struct { char *key; char value; } *hash = NULL; + char name[4] = "jen"; + shput(hash, "bob" , 'h'); + shput(hash, "sally" , 'e'); + shput(hash, "fred" , 'l'); + shput(hash, "jen" , 'x'); + shput(hash, "doug" , 'o'); + + shput(hash, name , 'l'); + shfree(hash); + } + + for (i=0; i < testsize; i += 2) { + stbds_struct s = { i,i*2,i*3,i*4 }; + hmput(map, s, i*5); + } + + for (i=0; i < testsize; i += 1) { + stbds_struct s = { i,i*2,i*3 ,i*4 }; + stbds_struct t = { i,i*2,i*3+1,i*4 }; + if (i & 1) STBDS_assert__(hmget(map, s) == 0); + else STBDS_assert__(hmget(map, s) == i*5); + if (i & 1) STBDS_assert__(hmget_ts(map, s, temp) == 0); + else STBDS_assert__(hmget_ts(map, s, temp) == i*5); + //STBDS_assert__(hmget(map, t.key) == 0); + } + + for (i=0; i < testsize; i += 2) { + stbds_struct s = { i,i*2,i*3,i*4 }; + hmputs(map2, s); + } + hmfree(map); + + for (i=0; i < testsize; i += 1) { + stbds_struct s = { i,i*2,i*3,i*4 }; + stbds_struct t = { i,i*2,i*3+1,i*4 }; + if (i & 1) STBDS_assert__(hmgets(map2, s.key).d == 0); + else STBDS_assert__(hmgets(map2, s.key).d == i*4); + //STBDS_assert__(hmgetp(map2, t.key) == 0); + } + hmfree(map2); + + for (i=0; i < testsize; i += 2) { + stbds_struct2 s = { { i,i*2 }, i*3,i*4, i*5 }; + hmputs(map3, s); + } + for (i=0; i < testsize; i += 1) { + stbds_struct2 s = { { i,i*2}, i*3, i*4, i*5 }; + stbds_struct2 t = { { i,i*2}, i*3+1, i*4, i*5 }; + if (i & 1) STBDS_assert__(hmgets(map3, s.key).d == 0); + else STBDS_assert__(hmgets(map3, s.key).d == i*5); + //STBDS_assert__(hmgetp(map3, t.key) == 0); + } +#endif +} +#endif + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2019 Sean Barrett +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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 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. +------------------------------------------------------------------------------ +*/ diff --git a/base/sources/libs/kong/sources/log.c b/base/sources/libs/kong/sources/log.c new file mode 100644 index 00000000..9e552215 --- /dev/null +++ b/base/sources/libs/kong/sources/log.c @@ -0,0 +1,51 @@ +#include "log.h" + +#include +#include + +#ifdef WIN32 +#include +#endif + +#ifdef __android__ +#include +#endif + +void kong_log(log_level_t level, const char *format, ...) { + va_list args; + va_start(args, format); + kong_log_args(level, format, args); + va_end(args); +} + +void kong_log_args(log_level_t level, const char *format, va_list args) { +#ifdef WIN32 + { + char buffer[4096]; + vsnprintf(buffer, 4090, format, args); + strcat(buffer, "\r\n"); + OutputDebugStringA(buffer); + } +#endif + + { + char buffer[4096]; + vsnprintf(buffer, 4090, format, args); + strcat(buffer, "\n"); + fprintf(level == LOG_LEVEL_INFO ? stdout : stderr, "%s", buffer); + } + +#ifdef __android__ + switch (level) { + case KINC_LOG_LEVEL_INFO: + __android_log_vprint(ANDROID_LOG_INFO, "krom", format, args); + break; + case KINC_LOG_LEVEL_WARNING: + __android_log_vprint(ANDROID_LOG_WARN, "krom", format, args); + break; + case KINC_LOG_LEVEL_ERROR: + __android_log_vprint(ANDROID_LOG_ERROR, "krom", format, args); + break; + } +#endif +} diff --git a/base/sources/libs/kong/sources/log.h b/base/sources/libs/kong/sources/log.h new file mode 100644 index 00000000..0753e4d9 --- /dev/null +++ b/base/sources/libs/kong/sources/log.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { LOG_LEVEL_INFO, LOG_LEVEL_WARNING, LOG_LEVEL_ERROR } log_level_t; + +void kong_log(log_level_t log_level, const char *format, ...); + +void kong_log_args(log_level_t log_level, const char *format, va_list args); + +#ifdef __cplusplus +} +#endif diff --git a/base/sources/libs/kong/sources/names.c b/base/sources/libs/kong/sources/names.c new file mode 100644 index 00000000..7a55659a --- /dev/null +++ b/base/sources/libs/kong/sources/names.c @@ -0,0 +1,65 @@ +#include "names.h" + +#include "libs/stb_ds.h" + +#include "errors.h" + +#include + +static char *names = NULL; +static size_t names_size = 1024 * 1024; +static name_id names_index = 1; + +static struct { + char *key; + name_id value; +} *hash = NULL; + +void names_init(void) { + char *new_names = realloc(names, names_size); + debug_context context = {0}; + check(new_names != NULL, context, "Could not allocate names"); + names = new_names; + names[0] = 0; // make NO_NAME a proper string + + sh_new_arena(hash); // TODO: Get rid of this by using indices internally in the hash-map so it can survive grow_if_needed +} + +static void grow_if_needed(size_t size) { + while (size >= names_size) { + names_size *= 2; + char *new_names = realloc(names, names_size); + debug_context context = {0}; + check(new_names != NULL, context, "Could not allocate names"); + names = new_names; + } +} + +name_id add_name(char *name) { + ptrdiff_t old_id_index = shgeti(hash, name); + + if (old_id_index >= 0) { + return hash[old_id_index].value; + } + + size_t length = strlen(name); + + grow_if_needed(names_index + length + 1); + + name_id id = names_index; + + memcpy(&names[id], name, length); + names[id + length] = 0; + + names_index += length + 1; + + shput(hash, &names[id], id); + + return id; +} + +char *get_name(name_id id) { + debug_context context = {0}; + check(id < names_index, context, "Encountered a weird name id"); + return &names[id]; +} diff --git a/base/sources/libs/kong/sources/names.h b/base/sources/libs/kong/sources/names.h new file mode 100644 index 00000000..bd442f45 --- /dev/null +++ b/base/sources/libs/kong/sources/names.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +#define NO_NAME 0 + +typedef size_t name_id; + +void names_init(void); + +name_id add_name(char *name); + +char *get_name(name_id index); diff --git a/base/sources/libs/kong/sources/parser.c b/base/sources/libs/kong/sources/parser.c new file mode 100644 index 00000000..8b317777 --- /dev/null +++ b/base/sources/libs/kong/sources/parser.c @@ -0,0 +1,1319 @@ +#include "parser.h" +#include "errors.h" +#include "functions.h" +#include "sets.h" +#include "tokenizer.h" +#include "types.h" + +#include +#include +#include + +static statement *statement_allocate(void) { + statement *s = (statement *)malloc(sizeof(statement)); + debug_context context = {0}; + check(s != NULL, context, "Could not allocate statement"); + return s; +} + +// static void statement_free(statement *statement) { +// free(statement); +// } + +static void statements_init(statements *statements) { + statements->size = 0; +} + +static void statements_add(statements *statements, statement *statement) { + statements->s[statements->size] = statement; + statements->size += 1; +} + +static expression *expression_allocate(void) { + expression *e = (expression *)malloc(sizeof(expression)); + debug_context context = {0}; + check(e != NULL, context, "Could not allocate expression"); + init_type_ref(&e->type, NO_NAME); + return e; +} + +// static void expression_free(expression *expression) { +// free(expression); +// } + +typedef struct state { + tokens *tokens; + size_t index; + debug_context context; +} state_t; + +static token current(state_t *state) { + token token = tokens_get(state->tokens, state->index); + return token; +} + +static void update_debug_context(state_t *state) { + state->context.column = current(state).column; + state->context.line = current(state).line; +} + +static void advance_state(state_t *state) { + state->index += 1; + update_debug_context(state); +} + +static void match_token(state_t *state, int token, const char *error_message) { + int current_token = current(state).kind; + if (current_token != token) { + error(state->context, error_message); + } +} + +static void match_token_identifier(state_t *state) { + if (current(state).kind != TOKEN_IDENTIFIER) { + error(state->context, "Expected an identifier"); + } +} + +static definition parse_definition(state_t *state); +static statement *parse_statement(state_t *state, block *parent_block); +static expression *parse_expression(state_t *state); + +void kong_parse(const char *filename, tokens *tokens) { + state_t state = {0}; + state.context.filename = filename; + state.tokens = tokens; + state.index = 0; + + for (;;) { + token token = current(&state); + if (token.kind == TOKEN_NONE) { + return; + } + else { + parse_definition(&state); + } + } +} + +static statement *parse_block(state_t *state, block *parent_block) { + match_token(state, TOKEN_LEFT_CURLY, "Expected an opening curly bracket"); + advance_state(state); + + statements statements; + statements_init(&statements); + + statement *new_block = statement_allocate(); + new_block->kind = STATEMENT_BLOCK; + new_block->block.parent = parent_block; + new_block->block.vars.size = 0; + + for (;;) { + switch (current(state).kind) { + case TOKEN_RIGHT_CURLY: { + advance_state(state); + new_block->block.statements = statements; + return new_block; + } + case TOKEN_NONE: { + update_debug_context(state); + error(state->context, "File ended before a block ended"); + return NULL; + } + default: + statements_add(&statements, parse_statement(state, &new_block->block)); + break; + } + } +} + +typedef enum modifier { + MODIFIER_IN, + // Out, +} modifier_t; + +typedef struct modifiers { + modifier_t m[16]; + size_t size; +} modifiers_t; + +// static void modifiers_init(modifiers_t *modifiers) { +// modifiers->size = 0; +// } + +// static void modifiers_add(modifiers_t *modifiers, modifier_t modifier) { +// modifiers->m[modifiers->size] = modifier; +// modifiers->size += 1; +// } + +static definition parse_struct(state_t *state); +static definition parse_function(state_t *state); +static definition parse_const(state_t *state, attribute_list attributes); + +static double attribute_parameter_to_number(name_id attribute_name, name_id parameter_name) { + if (attribute_name == add_name("topology") && parameter_name == add_name("triangle")) { + return 0; + } + + type_id type = find_type_by_name(parameter_name); + if (type != NO_TYPE) { + return (double)type; + } + + debug_context context = {0}; + error(context, "Unknown attribute parameter %s", get_name(parameter_name)); + return 0; +} + +static definition parse_definition(state_t *state) { + attribute_list attributes = {0}; + descriptor_set *current_sets[64]; + size_t current_sets_count = 0; + + if (current(state).kind == TOKEN_HASH) { + advance_state(state); + match_token(state, TOKEN_LEFT_SQUARE, "Expected left square"); + advance_state(state); + + while (current(state).kind != TOKEN_RIGHT_SQUARE) { + attribute current_attribute = {0}; + + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + current_attribute.name = current(state).identifier; + + if (current_attribute.name == add_name("root_constants")) { + current_sets[current_sets_count] = create_set(current_attribute.name); + current_attribute.parameters[current_attribute.paramters_count] = current_sets[current_sets_count]->index; + current_sets_count += 1; + } + + advance_state(state); + + if (current(state).kind == TOKEN_LEFT_PAREN) { + advance_state(state); + + while (current(state).kind != TOKEN_RIGHT_PAREN) { + if (current(state).kind == TOKEN_IDENTIFIER) { + if (current_attribute.name == add_name("set")) { + if (current(state).identifier == add_name("root_constants")) { + debug_context context = {0}; + error(context, "Descriptor set can not be called root_constants"); + } + current_sets[current_sets_count] = create_set(current(state).identifier); + current_attribute.parameters[current_attribute.paramters_count] = current_sets[current_sets_count]->index; + current_sets_count += 1; + } + else { + current_attribute.parameters[current_attribute.paramters_count] = + attribute_parameter_to_number(current_attribute.name, current(state).identifier); + } + current_attribute.paramters_count += 1; + advance_state(state); + } + else if (current(state).kind == TOKEN_FLOAT || current(state).kind == TOKEN_INT) { + current_attribute.parameters[current_attribute.paramters_count] = current(state).number; + current_attribute.paramters_count += 1; + advance_state(state); + } + else { + debug_context context = {0}; + error(context, "Expected an identifier or a number"); + } + + if (current(state).kind != TOKEN_RIGHT_PAREN) { + match_token(state, TOKEN_COMMA, "Expected a comma"); + advance_state(state); + } + } + advance_state(state); + } + + attributes.attributes[attributes.attributes_count] = current_attribute; + attributes.attributes_count += 1; + + if (current(state).kind != TOKEN_RIGHT_SQUARE) { + match_token(state, TOKEN_COMMA, "Expected a comma"); + advance_state(state); + } + } + advance_state(state); + } + + switch (current(state).kind) { + case TOKEN_STRUCT: { + if (current_sets_count != 0) { + debug_context context = {0}; + error(context, "A struct can not be assigned to a set"); + } + + definition structy = parse_struct(state); + get_type(structy.type)->attributes = attributes; + return structy; + } + case TOKEN_FUNCTION: { + if (current_sets_count != 0) { + debug_context context = {0}; + error(context, "A function can not be assigned to a set"); + } + + definition d = parse_function(state); + function *f = get_function(d.function); + f->attributes = attributes; + return d; + } + case TOKEN_CONST: { + definition d = parse_const(state, attributes); + + for (size_t set_index = 0; set_index < current_sets_count; ++set_index) { + add_definition_to_set(current_sets[set_index], d); + } + + return d; + } + default: { + update_debug_context(state); + error(state->context, "Expected a struct, a function or a const"); + + definition d = {0}; + return d; + } + } +} + +static type_ref parse_type_ref(state_t *state) { + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + token type_name = current(state); + advance_state(state); + + uint32_t array_size = 0; + if (current(state).kind == TOKEN_LEFT_SQUARE) { + advance_state(state); + if (current(state).kind == TOKEN_INT) { + array_size = (uint32_t)current(state).number; + if (array_size == 0) { + error(state->context, "Array size of 0 is not allowed"); + } + advance_state(state); + } + else { + array_size = UINT32_MAX; + } + match_token(state, TOKEN_RIGHT_SQUARE, "Expected a closing square bracket"); + advance_state(state); + } + + type_ref t; + init_type_ref(&t, type_name.identifier); + t.unresolved.array_size = array_size; + return t; +} + +static statement *parse_statement(state_t *state, block *parent_block) { + switch (current(state).kind) { + case TOKEN_IF: { + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *test = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + statement *if_block = parse_statement(state, parent_block); + statement *s = statement_allocate(); + s->kind = STATEMENT_IF; + s->iffy.test = test; + s->iffy.if_block = if_block; + + s->iffy.else_size = 0; + + while (current(state).kind == TOKEN_ELSE) { + advance_state(state); + + if (current(state).kind == TOKEN_IF) { + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *test = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + statement *if_block = parse_statement(state, parent_block); + + s->iffy.else_tests[s->iffy.else_size] = test; + s->iffy.else_blocks[s->iffy.else_size] = if_block; + } + else { + statement *else_block = parse_statement(state, parent_block); + s->iffy.else_tests[s->iffy.else_size] = NULL; + s->iffy.else_blocks[s->iffy.else_size] = else_block; + } + + s->iffy.else_size += 1; + assert(s->iffy.else_size < 64); + } + + return s; + } + case TOKEN_WHILE: { + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *test = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + statement *while_block = parse_statement(state, parent_block); + + statement *s = statement_allocate(); + s->kind = STATEMENT_WHILE; + s->whiley.test = test; + s->whiley.while_block = while_block; + + return s; + } + case TOKEN_DO: { + advance_state(state); + + statement *do_block = parse_statement(state, parent_block); + + statement *s = statement_allocate(); + s->kind = STATEMENT_DO_WHILE; + s->whiley.while_block = do_block; + + match_token(state, TOKEN_WHILE, "Expected \"while\""); + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *test = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + s->whiley.test = test; + + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + return s; + } + case TOKEN_FOR: { + statements outer_block_statements; + statements_init(&outer_block_statements); + + statement *outer_block = statement_allocate(); + outer_block->kind = STATEMENT_BLOCK; + outer_block->block.parent = parent_block; + outer_block->block.vars.size = 0; + outer_block->block.statements = outer_block_statements; + + advance_state(state); + + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + statement *pre = parse_statement(state, &outer_block->block); + statements_add(&outer_block->block.statements, pre); + + expression *test = parse_expression(state); + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + expression *post_expression = parse_expression(state); + + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + + statement *inner_block = parse_statement(state, &outer_block->block); + + statement *post_statement = statement_allocate(); + post_statement->kind = STATEMENT_EXPRESSION; + post_statement->expression = post_expression; + + statements_add(&inner_block->block.statements, post_statement); + + statement *s = statement_allocate(); + s->kind = STATEMENT_WHILE; + s->whiley.test = test; + s->whiley.while_block = inner_block; + + statements_add(&outer_block->block.statements, s); + + return outer_block; + } + case TOKEN_LEFT_CURLY: { + return parse_block(state, parent_block); + } + case TOKEN_VAR: { + advance_state(state); + + match_token_identifier(state); + token name = current(state); + advance_state(state); + + match_token(state, TOKEN_COLON, "Expected a colon"); + advance_state(state); + + type_ref type = parse_type_ref(state); + + expression *init = NULL; + + if (current(state).kind == TOKEN_OPERATOR) { + check(current(state).op == OPERATOR_ASSIGN, state->context, "Expected an assign"); + advance_state(state); + init = parse_expression(state); + } + + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + statement *statement = statement_allocate(); + statement->kind = STATEMENT_LOCAL_VARIABLE; + statement->local_variable.var.name = name.identifier; + statement->local_variable.var.type = type; + statement->local_variable.var.variable_id = 0; + statement->local_variable.init = init; + return statement; + } + case TOKEN_RETURN: { + advance_state(state); + + expression *expr = parse_expression(state); + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + statement *statement = statement_allocate(); + statement->kind = STATEMENT_RETURN_EXPRESSION; + statement->expression = expr; + return statement; + } + default: { + expression *expr = parse_expression(state); + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + statement *statement = statement_allocate(); + statement->kind = STATEMENT_EXPRESSION; + statement->expression = expr; + return statement; + } + } +} + +static expression *parse_assign(state_t *state); + +static expression *parse_expression(state_t *state) { + return parse_assign(state); +} + +static expression *parse_logical(state_t *state); + +static expression *parse_assign(state_t *state) { + expression *expr = parse_logical(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_ASSIGN || op == OPERATOR_MINUS_ASSIGN || op == OPERATOR_PLUS_ASSIGN || op == OPERATOR_DIVIDE_ASSIGN || + op == OPERATOR_MULTIPLY_ASSIGN) { + advance_state(state); + expression *right = parse_logical(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_equality(state_t *state); + +static expression *parse_logical(state_t *state) { + expression *expr = parse_equality(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_OR || op == OPERATOR_AND || op == OPERATOR_XOR) { + advance_state(state); + expression *right = parse_equality(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_comparison(state_t *state); + +static expression *parse_equality(state_t *state) { + expression *expr = parse_comparison(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_EQUALS || op == OPERATOR_NOT_EQUALS) { + advance_state(state); + expression *right = parse_comparison(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_addition(state_t *state); + +static expression *parse_comparison(state_t *state) { + expression *expr = parse_addition(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_GREATER || op == OPERATOR_GREATER_EQUAL || op == OPERATOR_LESS || op == OPERATOR_LESS_EQUAL) { + advance_state(state); + expression *right = parse_addition(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_multiplication(state_t *state); + +static expression *parse_addition(state_t *state) { + expression *expr = parse_multiplication(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_MINUS || op == OPERATOR_PLUS) { + advance_state(state); + expression *right = parse_multiplication(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_unary(state_t *state); + +static expression *parse_multiplication(state_t *state) { + expression *expr = parse_unary(state); + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_DIVIDE || op == OPERATOR_MULTIPLY || op == OPERATOR_MOD) { + advance_state(state); + expression *right = parse_unary(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_BINARY; + expression->binary.left = expr; + expression->binary.op = op; + expression->binary.right = right; + expr = expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return expr; +} + +static expression *parse_primary(state_t *state); + +static expression *parse_unary(state_t *state) { + bool done = false; + while (!done) { + if (current(state).kind == TOKEN_OPERATOR) { + operatorr op = current(state).op; + if (op == OPERATOR_NOT || op == OPERATOR_MINUS) { + advance_state(state); + expression *right = parse_unary(state); + expression *expression = expression_allocate(); + expression->kind = EXPRESSION_UNARY; + expression->unary.op = op; + expression->unary.right = right; + return expression; + } + else { + done = true; + } + } + else { + done = true; + } + } + return parse_primary(state); +} + +static expression *parse_call(state_t *state, name_id func_name); + +static expression *parse_member(state_t *state, bool square) { + if (current(state).kind == TOKEN_IDENTIFIER && !square) { + token token = current(state); + advance_state(state); + + if (current(state).kind == TOKEN_LEFT_PAREN) { + return parse_call(state, token.identifier); + } + else if (current(state).kind == TOKEN_DOT || current(state).kind == TOKEN_LEFT_SQUARE) { + bool square = current(state).kind == TOKEN_LEFT_SQUARE; + + advance_state(state); + + bool dynamic = square && current(state).kind != TOKEN_INT; + + expression *var = expression_allocate(); + var->kind = EXPRESSION_VARIABLE; + var->variable = token.identifier; + + expression *member = expression_allocate(); + member->kind = dynamic ? EXPRESSION_DYNAMIC_MEMBER : EXPRESSION_STATIC_MEMBER; + member->member.left = var; + member->member.right = parse_member(state, square); + + return member; + } + else { + expression *var = expression_allocate(); + var->kind = EXPRESSION_VARIABLE; + var->variable = token.identifier; + return var; + } + } + else if (current(state).kind == TOKEN_INT && square) { + uint32_t index = (uint32_t)current(state).number; + advance_state(state); + match_token(state, TOKEN_RIGHT_SQUARE, "Expected a closing square bracket"); + advance_state(state); + + if (current(state).kind == TOKEN_DOT || current(state).kind == TOKEN_LEFT_SQUARE) { + bool square = current(state).kind == TOKEN_LEFT_SQUARE; + + advance_state(state); + + bool dynamic = square && current(state).kind != TOKEN_INT; + + expression *var = expression_allocate(); + var->kind = EXPRESSION_INDEX; + var->index = index; + + expression *member = expression_allocate(); + member->kind = dynamic ? EXPRESSION_DYNAMIC_MEMBER : EXPRESSION_STATIC_MEMBER; + member->member.left = var; + member->member.right = parse_member(state, square); + + return member; + } + else { + expression *var = expression_allocate(); + var->kind = EXPRESSION_INDEX; + var->index = index; + return var; + } + } + else if (square) { + expression *index = parse_expression(state); + match_token(state, TOKEN_RIGHT_SQUARE, "Expected a closing square bracket"); + advance_state(state); + + if (current(state).kind == TOKEN_DOT || current(state).kind == TOKEN_LEFT_SQUARE) { + bool square = current(state).kind == TOKEN_LEFT_SQUARE; + + advance_state(state); + + bool dynamic = square && current(state).kind != TOKEN_INT; + + expression *member = expression_allocate(); + member->kind = dynamic ? EXPRESSION_DYNAMIC_MEMBER : EXPRESSION_STATIC_MEMBER; + member->member.left = index; + member->member.right = parse_member(state, square); + + return member; + } + else { + return index; + } + } + else { + error(state->context, "Unexpected token"); + return NULL; + } +} + +static expression *parse_primary(state_t *state) { + expression *left = NULL; + + switch (current(state).kind) { + case TOKEN_BOOLEAN: { + bool value = current(state).boolean; + advance_state(state); + left = expression_allocate(); + left->kind = EXPRESSION_BOOLEAN; + left->boolean = value; + break; + } + case TOKEN_FLOAT: { + double value = current(state).number; + advance_state(state); + left = expression_allocate(); + left->kind = EXPRESSION_FLOAT; + left->number = value; + break; + } + case TOKEN_INT: { + double value = current(state).number; + advance_state(state); + left = expression_allocate(); + left->kind = EXPRESSION_INT; + left->number = value; + break; + } + /*case TOKEN_STRING: { + token token = current(state); + advance_state(state); + left = expression_allocate(); + left->kind = EXPRESSION_STRING; + left->string = add_name(token.string); + break; + }*/ + case TOKEN_IDENTIFIER: { + token token = current(state); + advance_state(state); + if (current(state).kind == TOKEN_LEFT_PAREN) { + left = parse_call(state, token.identifier); + } + else { + expression *var = expression_allocate(); + var->kind = EXPRESSION_VARIABLE; + var->variable = token.identifier; + left = var; + } + break; + } + case TOKEN_LEFT_PAREN: { + advance_state(state); + expression *expr = parse_expression(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + left = expression_allocate(); + left->kind = EXPRESSION_GROUPING; + left->grouping = expr; + break; + } + default: + error(state->context, "Unexpected token"); + return NULL; + } + + if (current(state).kind == TOKEN_DOT || current(state).kind == TOKEN_LEFT_SQUARE) { + bool square = current(state).kind == TOKEN_LEFT_SQUARE; + + advance_state(state); + + bool dynamic = square && current(state).kind != TOKEN_INT; + + expression *right = parse_member(state, square); + + expression *member = expression_allocate(); + member->kind = dynamic ? EXPRESSION_DYNAMIC_MEMBER : EXPRESSION_STATIC_MEMBER; + member->member.left = left; + member->member.right = right; + + if (current(state).kind == TOKEN_LEFT_PAREN) { + // return parse_call(state, member); + error(state->context, "Function members not currently supported"); + return NULL; + } + else { + return member; + } + } + + return left; +} + +static expressions parse_parameters(state_t *state) { + expressions e; + e.size = 0; + + if (current(state).kind == TOKEN_RIGHT_PAREN) { + advance_state(state); + return e; + } + + for (;;) { + e.e[e.size] = parse_expression(state); + e.size += 1; + + if (current(state).kind == TOKEN_COMMA) { + advance_state(state); + } + else { + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + return e; + } + } +} + +static expression *parse_call(state_t *state, name_id func_name) { + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + expression *call = NULL; + + call = expression_allocate(); + call->kind = EXPRESSION_CALL; + call->call.func_name = func_name; + call->call.parameters = parse_parameters(state); + + if (current(state).kind == TOKEN_DOT || current(state).kind == TOKEN_LEFT_SQUARE) { + bool square = current(state).kind == TOKEN_LEFT_SQUARE; + + advance_state(state); + + bool dynamic = square && current(state).kind != TOKEN_INT; + + expression *right = parse_member(state, square); + + expression *member = expression_allocate(); + member->kind = dynamic ? EXPRESSION_DYNAMIC_MEMBER : EXPRESSION_STATIC_MEMBER; + member->member.left = call; + member->member.right = right; + + if (current(state).kind == TOKEN_LEFT_PAREN) { + // return parse_call(state, member); + error(state->context, "Function members not currently supported"); + return NULL; + } + else { + return member; + } + } + + return call; +} + +static definition parse_struct_inner(state_t *state, name_id name) { + match_token(state, TOKEN_LEFT_CURLY, "Expected an opening curly bracket"); + advance_state(state); + + token member_names[MAX_MEMBERS]; + type_ref type_refs[MAX_MEMBERS]; + token member_values[MAX_MEMBERS]; + size_t count = 0; + + while (current(state).kind != TOKEN_RIGHT_CURLY) { + debug_context context = {0}; + check(count < MAX_MEMBERS, context, "Out of members"); + + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + member_names[count] = current(state); + + advance_state(state); + + if (current(state).kind == TOKEN_COLON) { + advance_state(state); + type_refs[count] = parse_type_ref(state); + } + else { + type_ref t; + t.type = NO_TYPE; + t.unresolved.name = NO_NAME; + t.unresolved.array_size = 0; + type_refs[count] = t; + } + + if (current(state).kind == TOKEN_OPERATOR && current(state).op == OPERATOR_ASSIGN) { + advance_state(state); + if (current(state).kind == TOKEN_BOOLEAN || current(state).kind == TOKEN_FLOAT || current(state).kind == TOKEN_INT || + current(state).kind == TOKEN_IDENTIFIER) { + member_values[count] = current(state); + advance_state(state); + + if (current(state).kind == TOKEN_LEFT_PAREN) { + advance_state(state); + match_token(state, TOKEN_RIGHT_PAREN, "Expected a right paren"); + advance_state(state); + } + } + else { + debug_context context = {0}; + error(context, "Unsupported assign in struct"); + } + } + else { + member_values[count].kind = TOKEN_NONE; + member_values[count].identifier = NO_NAME; + } + + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + + advance_state(state); + + ++count; + } + + advance_state(state); + + definition definition; + definition.kind = DEFINITION_STRUCT; + + definition.type = add_type(name); + + type *s = get_type(definition.type); + + for (size_t i = 0; i < count; ++i) { + member member; + member.name = member_names[i].identifier; + member.value = member_values[i]; + if (member.value.kind != TOKEN_NONE) { + if (member.value.kind == TOKEN_BOOLEAN) { + init_type_ref(&member.type, add_name("bool")); + } + else if (member.value.kind == TOKEN_FLOAT) { + init_type_ref(&member.type, add_name("float")); + } + else if (member.value.kind == TOKEN_INT) { + init_type_ref(&member.type, add_name("int")); + } + else if (member.value.kind == TOKEN_IDENTIFIER) { + global *g = find_global(member.value.identifier); + if (g != NULL && g->name != NO_NAME) { + init_type_ref(&member.type, get_type(g->type)->name); + } + else { + init_type_ref(&member.type, add_name("fun")); + } + } + else { + debug_context context = {0}; + error(context, "Unsupported value in struct"); + } + } + else { + member.type = type_refs[i]; + } + + s->members.m[i] = member; + } + s->members.size = count; + + return definition; +} + +static definition parse_struct(state_t *state) { + advance_state(state); + + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + token name = current(state); + advance_state(state); + + return parse_struct_inner(state, name.identifier); +} + +static definition parse_function(state_t *state) { + advance_state(state); + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + + token name = current(state); + advance_state(state); + match_token(state, TOKEN_LEFT_PAREN, "Expected an opening bracket"); + advance_state(state); + + uint8_t parameters_size = 0; + name_id param_names[256] = {0}; + type_ref param_types[256] = {0}; + name_id param_attributes[256] = {0}; + + while (current(state).kind != TOKEN_RIGHT_PAREN) { + if (current(state).kind == TOKEN_HASH) { + advance_state(state); + match_token(state, TOKEN_LEFT_SQUARE, "Expected an opening square bracket"); + advance_state(state); + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + token attribute_name = current(state); + param_attributes[parameters_size] = attribute_name.identifier; + advance_state(state); + match_token(state, TOKEN_RIGHT_SQUARE, "Expected a closing square bracket"); + advance_state(state); + } + + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + param_names[parameters_size] = current(state).identifier; + advance_state(state); + match_token(state, TOKEN_COLON, "Expected a colon"); + advance_state(state); + param_types[parameters_size] = parse_type_ref(state); + if (current(state).kind == TOKEN_COMMA) { + advance_state(state); + } + parameters_size += 1; + } + + match_token(state, TOKEN_RIGHT_PAREN, "Expected a closing bracket"); + advance_state(state); + match_token(state, TOKEN_COLON, "Expected a colon"); + advance_state(state); + + type_ref return_type = parse_type_ref(state); + + statement *block = parse_block(state, NULL); + + definition d; + d.kind = DEFINITION_FUNCTION; + d.function = add_function(name.identifier); + function *f = get_function(d.function); + f->return_type = return_type; + f->parameters_size = parameters_size; + for (uint8_t parameter_index = 0; parameter_index < parameters_size; ++parameter_index) { + f->parameter_names[parameter_index] = param_names[parameter_index]; + f->parameter_types[parameter_index] = param_types[parameter_index]; + f->parameter_attributes[parameter_index] = param_attributes[parameter_index]; + } + f->block = block; + + return d; +} + +static definition parse_const(state_t *state, attribute_list attributes) { + advance_state(state); + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + + token name = current(state); + advance_state(state); + match_token(state, TOKEN_COLON, "Expected a colon"); + advance_state(state); + + name_id type_name = NO_NAME; + type_id type = NO_TYPE; + + if (current(state).kind == TOKEN_LEFT_CURLY) { + type = parse_struct_inner(state, NO_NAME).type; + } + else { + match_token(state, TOKEN_IDENTIFIER, "Expected an identifier"); + type_name = current(state).identifier; + advance_state(state); + } + + bool array = false; + uint32_t array_size = UINT32_MAX; + + if (current(state).kind == TOKEN_LEFT_SQUARE) { + array = true; + advance_state(state); + + if (current(state).kind == TOKEN_INT) { + array_size = (uint32_t)current(state).number; + advance_state(state); + } + + match_token(state, TOKEN_RIGHT_SQUARE, "Expected a right square bracket"); + advance_state(state); + } + + expression *value = NULL; + if (current(state).kind == TOKEN_OPERATOR && current(state).op == OPERATOR_ASSIGN) { + advance_state(state); + value = parse_expression(state); + } + + match_token(state, TOKEN_SEMICOLON, "Expected a semicolon"); + advance_state(state); + + definition d = {0}; + + if (type_name == NO_NAME) { + debug_context context = {0}; + check(type != NO_TYPE, context, "Const has no type"); + d.kind = DEFINITION_CONST_CUSTOM; + d.global = add_global(type, attributes, name.identifier); + } + else if (type_name == add_name("tex2d")) { + d.kind = DEFINITION_TEX2D; + + type_id t_id = tex2d_type_id; + if (array) { + type_id array_type_id = add_type(get_type(t_id)->name); + get_type(array_type_id)->base = t_id; + get_type(array_type_id)->array_size = array_size; + t_id = array_type_id; + } + + d.global = add_global(t_id, attributes, name.identifier); + } + else if (type_name == add_name("tex2darray")) { + d.kind = DEFINITION_TEX2DARRAY; + d.global = add_global(tex2darray_type_id, attributes, name.identifier); + } + else if (type_name == add_name("texcube")) { + d.kind = DEFINITION_TEXCUBE; + d.global = add_global(texcube_type_id, attributes, name.identifier); + } + else if (type_name == add_name("sampler")) { + d.kind = DEFINITION_SAMPLER; + d.global = add_global(sampler_type_id, attributes, name.identifier); + } + else if (type_name == add_name("bvh")) { + d.kind = DEFINITION_BVH; + d.global = add_global(bvh_type_id, attributes, name.identifier); + } + else if (type_name == add_name("float")) { + debug_context context = {0}; + check(value != NULL, context, "const float requires an initialization value"); + check(value->kind == EXPRESSION_FLOAT || value->kind == EXPRESSION_INT, context, "const float requires a number"); + + global_value float_value; + float_value.kind = GLOBAL_VALUE_FLOAT; + + float_value.value.floats[0] = (float)value->number; + + d.kind = DEFINITION_CONST_BASIC; + d.global = add_global_with_value(float_id, attributes, name.identifier, float_value); + } + else if (type_name == add_name("float2")) { + debug_context context = {0}; + check(value != NULL, context, "const float2 requires an initialization value"); + check(value->kind == EXPRESSION_CALL, context, "const float2 requires a constructor call"); + check(value->call.func_name == add_name("float2"), context, "const float2 requires a float2 call"); + check(value->call.parameters.size == 3, context, "const float2 construtor call requires two parameters"); + + global_value float2_value; + float2_value.kind = GLOBAL_VALUE_FLOAT2; + + for (int i = 0; i < 2; ++i) { + check(value->call.parameters.e[i]->kind == EXPRESSION_FLOAT || value->call.parameters.e[i]->kind == EXPRESSION_INT, context, + "const float2 construtor parameters have to be numbers"); + float2_value.value.floats[i] = (float)value->call.parameters.e[i]->number; + } + + d.kind = DEFINITION_CONST_BASIC; + d.global = add_global_with_value(float2_id, attributes, name.identifier, float2_value); + } + else if (type_name == add_name("float3")) { + debug_context context = {0}; + check(value != NULL, context, "const float3 requires an initialization value"); + check(value->kind == EXPRESSION_CALL, context, "const float3 requires a constructor call"); + check(value->call.func_name == add_name("float3"), context, "const float3 requires a float3 call"); + check(value->call.parameters.size == 3, context, "const float3 construtor call requires three parameters"); + + global_value float3_value; + float3_value.kind = GLOBAL_VALUE_FLOAT3; + + for (int i = 0; i < 3; ++i) { + check(value->call.parameters.e[i]->kind == EXPRESSION_FLOAT || value->call.parameters.e[i]->kind == EXPRESSION_INT, context, + "const float3 construtor parameters have to be numbers"); + float3_value.value.floats[i] = (float)value->call.parameters.e[i]->number; + } + + d.kind = DEFINITION_CONST_BASIC; + d.global = add_global_with_value(float3_id, attributes, name.identifier, float3_value); + } + else if (type_name == add_name("float4")) { + debug_context context = {0}; + if (!array) { + check(value != NULL, context, "const float4 requires an initialization value"); + check(value->kind == EXPRESSION_CALL, context, "const float4 requires a constructor call"); + check(value->call.func_name == add_name("float4"), context, "const float4 requires a float4 call"); + check(value->call.parameters.size == 4, context, "const float4 construtor call requires four parameters"); + } + else { + check(value == NULL, context, "const float4[] does not allow an initialization value"); + } + + global_value float4_value; + float4_value.kind = GLOBAL_VALUE_FLOAT4; + + if (!array) { + for (int i = 0; i < 4; ++i) { + check(value->call.parameters.e[i]->kind == EXPRESSION_FLOAT || value->call.parameters.e[i]->kind == EXPRESSION_INT, context, + "const float4 construtor parameters have to be numbers"); + float4_value.value.floats[i] = (float)value->call.parameters.e[i]->number; + } + } + + d.kind = DEFINITION_CONST_BASIC; + if (array) { + type_id array_type_id = add_type(get_type(float4_id)->name); + get_type(array_type_id)->base = float4_id; + get_type(array_type_id)->array_size = array_size; + + d.global = add_global(array_type_id, attributes, name.identifier); + } + else { + d.global = add_global_with_value(float4_id, attributes, name.identifier, float4_value); + } + } + else { + debug_context context = {0}; + error(context, "Unsupported global"); + } + + return d; +} diff --git a/base/sources/libs/kong/sources/parser.h b/base/sources/libs/kong/sources/parser.h new file mode 100644 index 00000000..10e16c79 --- /dev/null +++ b/base/sources/libs/kong/sources/parser.h @@ -0,0 +1,144 @@ +#pragma once + +#include "functions.h" +#include "globals.h" +#include "names.h" +#include "tokenizer.h" +#include "types.h" + +#include +#include + +struct expression; + +typedef struct expressions { + struct expression *e[256]; + size_t size; +} expressions; + +typedef struct expression { + enum { + EXPRESSION_BINARY, + EXPRESSION_UNARY, + EXPRESSION_BOOLEAN, + EXPRESSION_FLOAT, + EXPRESSION_INT, + // EXPRESSION_STRING, + EXPRESSION_VARIABLE, + EXPRESSION_GROUPING, + EXPRESSION_CALL, + EXPRESSION_STATIC_MEMBER, + EXPRESSION_DYNAMIC_MEMBER, + EXPRESSION_INDEX, + EXPRESSION_CONSTRUCTOR + } kind; + + type_ref type; + + union { + struct { + struct expression *left; + operatorr op; + struct expression *right; + } binary; + struct { + operatorr op; + struct expression *right; + } unary; + bool boolean; + double number; + // char string[MAX_IDENTIFIER_SIZE]; + name_id variable; + uint32_t index; + struct expression *grouping; + struct { + name_id func_name; + expressions parameters; + } call; + struct { + struct expression *left; + struct expression *right; + } member; + struct { + expressions parameters; + } constructor; + }; +} expression; + +struct statement; + +typedef struct statements { + struct statement *s[256]; + size_t size; +} statements; + +typedef struct local_variable { + name_id name; + type_ref type; + uint64_t variable_id; +} local_variable; + +typedef struct local_variables { + local_variable v[256]; + size_t size; +} local_variables; + +typedef struct block { + struct block *parent; + local_variables vars; + statements statements; +} block; + +typedef struct statement { + enum { + STATEMENT_EXPRESSION, + STATEMENT_RETURN_EXPRESSION, + STATEMENT_IF, + STATEMENT_WHILE, + STATEMENT_DO_WHILE, + STATEMENT_BLOCK, + STATEMENT_LOCAL_VARIABLE + } kind; + + union { + expression *expression; + struct { + expression *test; + struct statement *if_block; + expression *else_tests[64]; + struct statement *else_blocks[64]; + uint16_t else_size; + } iffy; + struct { + expression *test; + struct statement *while_block; + } whiley; + block block; + struct { + local_variable var; + expression *init; + } local_variable; + }; +} statement; + +typedef struct definition { + enum { + DEFINITION_FUNCTION, + DEFINITION_STRUCT, + DEFINITION_TEX2D, + DEFINITION_TEX2DARRAY, + DEFINITION_TEXCUBE, + DEFINITION_SAMPLER, + DEFINITION_CONST_CUSTOM, + DEFINITION_CONST_BASIC, + DEFINITION_BVH + } kind; + + union { + function_id function; + global_id global; + type_id type; + }; +} definition; + +void kong_parse(const char *filename, tokens *tokens); diff --git a/base/sources/libs/kong/sources/sets.c b/base/sources/libs/kong/sources/sets.c new file mode 100644 index 00000000..a561a87d --- /dev/null +++ b/base/sources/libs/kong/sources/sets.c @@ -0,0 +1,44 @@ +#include "sets.h" + +#include "errors.h" + +static descriptor_set sets[MAX_SETS]; +static size_t sets_count = 0; + +descriptor_set *create_set(name_id name) { + for (size_t set_index = 0; set_index < sets_count; ++set_index) { + if (sets[set_index].name == name) { + return &sets[set_index]; + } + } + + if (sets_count >= MAX_SETS) { + debug_context context = {0}; + error(context, "Max set count of %i reached", MAX_SETS); + return NULL; + } + + descriptor_set *new_set = &sets[sets_count]; + new_set->name = name; + new_set->index = (uint32_t)sets_count; + new_set->definitions_count = 0; + + sets_count += 1; + + return new_set; +} + +void add_definition_to_set(descriptor_set *set, definition def) { + assert(def.kind != DEFINITION_FUNCTION && def.kind != DEFINITION_STRUCT); + + for (size_t definition_index = 0; definition_index < set->definitions_count; ++definition_index) { + if (set->definitions[definition_index].global == def.global) { + return; + } + } + + get_global(def.global)->sets[get_global(def.global)->sets_count] = set; + get_global(def.global)->sets_count += 1; + set->definitions[set->definitions_count] = def; + set->definitions_count += 1; +} diff --git a/base/sources/libs/kong/sources/sets.h b/base/sources/libs/kong/sources/sets.h new file mode 100644 index 00000000..bbbcf39a --- /dev/null +++ b/base/sources/libs/kong/sources/sets.h @@ -0,0 +1,22 @@ +#ifndef KONG_SETS_HEADER +#define KONG_SETS_HEADER + +#include "names.h" +#include "parser.h" + +#define MAX_SET_DEFINITIONS 32 + +typedef struct descriptor_set { + uint32_t index; + name_id name; + definition definitions[MAX_SET_DEFINITIONS]; + size_t definitions_count; +} descriptor_set; + +#define MAX_SETS 256 + +descriptor_set *create_set(name_id name); + +void add_definition_to_set(descriptor_set *set, definition def); + +#endif diff --git a/base/sources/libs/kong/sources/shader_stage.h b/base/sources/libs/kong/sources/shader_stage.h new file mode 100644 index 00000000..76195b49 --- /dev/null +++ b/base/sources/libs/kong/sources/shader_stage.h @@ -0,0 +1,14 @@ +#pragma once + +typedef enum shader_stage { + SHADER_STAGE_VERTEX, + SHADER_STAGE_AMPLIFICATION, + SHADER_STAGE_MESH, + SHADER_STAGE_FRAGMENT, + SHADER_STAGE_COMPUTE, + SHADER_STAGE_RAY_GENERATION, + SHADER_STAGE_RAY_MISS, + SHADER_STAGE_RAY_CLOSEST_HIT, + SHADER_STAGE_RAY_INTERSECTION, + SHADER_STAGE_RAY_ANY_HIT +} shader_stage; diff --git a/base/sources/libs/kong/sources/tokenizer.c b/base/sources/libs/kong/sources/tokenizer.c new file mode 100644 index 00000000..f4d3a723 --- /dev/null +++ b/base/sources/libs/kong/sources/tokenizer.c @@ -0,0 +1,517 @@ +#include "tokenizer.h" +#include "errors.h" + +#include +#include +#include +#include + +token tokens_get(tokens *tokens, size_t index) { + debug_context context = {0}; + check(tokens->current_size > index, context, "Token index out of bounds"); + return tokens->t[index]; +} + +static bool is_num(char ch, char chch) { + return (ch >= '0' && ch <= '9') || (ch == '-' && chch >= '0' && chch <= '9'); +} + +static bool is_op(char ch) { + return ch == '&' || ch == '|' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '=' || ch == '!' || ch == '<' || ch == '>' || ch == '%' || + ch == '^'; +} + +static bool is_whitespace(char ch) { + return ch == ' ' || (ch >= 9 && ch <= 13); +} + +typedef enum mode { + MODE_SELECT, + MODE_NUMBER, + // MODE_STRING, + MODE_OPERATOR, + MODE_IDENTIFIER, + MODE_LINE_COMMENT, + MODE_COMMENT +} mode; + +typedef struct tokenizer_state { + const char *iterator; + char next; + char next_next; + int line, column; + bool line_end; +} tokenizer_state; + +static void tokenizer_state_init(debug_context *context, tokenizer_state *state, const char *source) { + state->line = state->column = 0; + state->iterator = source; + state->next = *state->iterator; + if (*state->iterator != 0) { + state->iterator += 1; + } + state->next_next = *state->iterator; + state->line_end = false; + + context->column = 0; + context->line = 0; +} + +static void tokenizer_state_advance(debug_context *context, tokenizer_state *state) { + state->next = state->next_next; + if (*state->iterator != 0) { + state->iterator += 1; + } + state->next_next = *state->iterator; + + if (state->line_end) { + state->line_end = false; + state->line += 1; + state->column = 0; + } + else { + state->column += 1; + } + + if (state->next == '\n') { + state->line_end = true; + } + + context->column = state->column; + context->line = state->line; +} + +typedef struct tokenizer_buffer { + char *buf; + size_t current_size; + size_t max_size; + int column, line; +} tokenizer_buffer; + +static void tokenizer_buffer_init(tokenizer_buffer *buffer) { + buffer->max_size = 1024 * 1024; + buffer->buf = (char *)malloc(buffer->max_size); + buffer->current_size = 0; + buffer->column = buffer->line = 0; +} + +static void tokenizer_buffer_reset(tokenizer_buffer *buffer, tokenizer_state *state) { + buffer->current_size = 0; + buffer->column = state->column; + buffer->line = state->line; +} + +static void tokenizer_buffer_add(tokenizer_buffer *buffer, char ch) { + debug_context context = {0}; + check(buffer->current_size < buffer->max_size, context, "Token buffer is too small"); + buffer->buf[buffer->current_size] = ch; + buffer->current_size += 1; +} + +static bool tokenizer_buffer_equals(tokenizer_buffer *buffer, const char *str) { + buffer->buf[buffer->current_size] = 0; + return strcmp(buffer->buf, str) == 0; +} + +static name_id tokenizer_buffer_to_name(tokenizer_buffer *buffer) { + debug_context context = {0}; + check(buffer->current_size < buffer->max_size, context, "Token buffer is too small"); + buffer->buf[buffer->current_size] = 0; + buffer->current_size += 1; + return add_name(buffer->buf); +} + +static double tokenizer_buffer_parse_number(tokenizer_buffer *buffer) { + buffer->buf[buffer->current_size] = 0; + return strtod(buffer->buf, NULL); +} + +token token_create(int kind, tokenizer_state *state) { + token token; + token.kind = kind; + token.column = state->column; + token.line = state->line; + return token; +} + +static void tokens_init(tokens *tokens) { + tokens->max_size = 1024 * 1024; + tokens->t = malloc(tokens->max_size * sizeof(token)); + tokens->current_size = 0; +} + +static void tokens_add(tokens *tokens, token token) { + tokens->t[tokens->current_size] = token; + tokens->current_size += 1; + debug_context context = {0}; + check(tokens->current_size <= tokens->max_size, context, "Out of tokens"); +} + +static void tokens_add_identifier(tokenizer_state *state, tokens *tokens, tokenizer_buffer *buffer) { + token token; + + if (tokenizer_buffer_equals(buffer, "true")) { + token = token_create(TOKEN_BOOLEAN, state); + token.boolean = true; + } + else if (tokenizer_buffer_equals(buffer, "false")) { + token = token_create(TOKEN_BOOLEAN, state); + token.boolean = false; + } + else if (tokenizer_buffer_equals(buffer, "if")) { + token = token_create(TOKEN_IF, state); + } + else if (tokenizer_buffer_equals(buffer, "else")) { + token = token_create(TOKEN_ELSE, state); + } + else if (tokenizer_buffer_equals(buffer, "while")) { + token = token_create(TOKEN_WHILE, state); + } + else if (tokenizer_buffer_equals(buffer, "do")) { + token = token_create(TOKEN_DO, state); + } + else if (tokenizer_buffer_equals(buffer, "for")) { + token = token_create(TOKEN_FOR, state); + } + else if (tokenizer_buffer_equals(buffer, "in")) { + token = token_create(TOKEN_IN, state); + } + else if (tokenizer_buffer_equals(buffer, "struct")) { + token = token_create(TOKEN_STRUCT, state); + } + else if (tokenizer_buffer_equals(buffer, "fun")) { + token = token_create(TOKEN_FUNCTION, state); + } + else if (tokenizer_buffer_equals(buffer, "var")) { + token = token_create(TOKEN_VAR, state); + } + else if (tokenizer_buffer_equals(buffer, "const")) { + token = token_create(TOKEN_CONST, state); + } + else if (tokenizer_buffer_equals(buffer, "return")) { + token = token_create(TOKEN_RETURN, state); + } + else { + token = token_create(TOKEN_IDENTIFIER, state); + token.identifier = tokenizer_buffer_to_name(buffer); + } + + token.column = buffer->column; + token.line = buffer->line; + tokens_add(tokens, token); +} + +tokens tokenize(const char *filename, const char *source) { + mode mode = MODE_SELECT; + bool number_has_dot = false; + + tokens tokens; + tokens_init(&tokens); + + debug_context context = {0}; + context.filename = filename; + + tokenizer_state state; + tokenizer_state_init(&context, &state, source); + + tokenizer_buffer buffer; + tokenizer_buffer_init(&buffer); + + for (;;) { + if (state.next == 0) { + switch (mode) { + case MODE_IDENTIFIER: + tokens_add_identifier(&state, &tokens, &buffer); + break; + case MODE_NUMBER: { + token token = token_create(number_has_dot ? TOKEN_FLOAT : TOKEN_INT, &state); + token.number = tokenizer_buffer_parse_number(&buffer); + tokens_add(&tokens, token); + break; + } + case MODE_SELECT: + case MODE_LINE_COMMENT: + break; + // case MODE_STRING: + // error("Unclosed string", state.column, state.line); + case MODE_OPERATOR: + error(context, "File ends with an operator"); + case MODE_COMMENT: + error(context, "Unclosed comment"); + } + + tokens_add(&tokens, token_create(TOKEN_NONE, &state)); + return tokens; + } + else { + char ch = (char)state.next; + switch (mode) { + case MODE_SELECT: { + if (ch == '/') { + if (state.next_next >= 0) { + char chch = state.next_next; + switch (chch) { + case '/': + mode = MODE_LINE_COMMENT; + break; + case '*': + mode = MODE_COMMENT; + break; + default: + tokenizer_buffer_reset(&buffer, &state); + tokenizer_buffer_add(&buffer, ch); + mode = MODE_OPERATOR; + } + } + } + else if (is_num(ch, state.next_next)) { + mode = MODE_NUMBER; + number_has_dot = false; + tokenizer_buffer_reset(&buffer, &state); + tokenizer_buffer_add(&buffer, ch); + } + else if (is_op(ch)) { + mode = MODE_OPERATOR; + tokenizer_buffer_reset(&buffer, &state); + tokenizer_buffer_add(&buffer, ch); + } + else if (is_whitespace(ch)) { + } + else if (ch == '(') { + tokens_add(&tokens, token_create(TOKEN_LEFT_PAREN, &state)); + } + else if (ch == ')') { + tokens_add(&tokens, token_create(TOKEN_RIGHT_PAREN, &state)); + } + else if (ch == '{') { + tokens_add(&tokens, token_create(TOKEN_LEFT_CURLY, &state)); + } + else if (ch == '}') { + tokens_add(&tokens, token_create(TOKEN_RIGHT_CURLY, &state)); + } + else if (ch == '#') { + tokens_add(&tokens, token_create(TOKEN_HASH, &state)); + } + else if (ch == '[') { + tokens_add(&tokens, token_create(TOKEN_LEFT_SQUARE, &state)); + } + else if (ch == ']') { + tokens_add(&tokens, token_create(TOKEN_RIGHT_SQUARE, &state)); + } + else if (ch == ';') { + tokens_add(&tokens, token_create(TOKEN_SEMICOLON, &state)); + } + else if (ch == '.') { + tokens_add(&tokens, token_create(TOKEN_DOT, &state)); + } + else if (ch == ':') { + tokens_add(&tokens, token_create(TOKEN_COLON, &state)); + } + else if (ch == ',') { + tokens_add(&tokens, token_create(TOKEN_COMMA, &state)); + } + else if (ch == '"' || ch == '\'') { + // mode = MODE_STRING; + // tokenizer_buffer_reset(&buffer, &state); + error(context, "Strings are not supported"); + } + else { + mode = MODE_IDENTIFIER; + tokenizer_buffer_reset(&buffer, &state); + tokenizer_buffer_add(&buffer, ch); + } + tokenizer_state_advance(&context, &state); + break; + } + case MODE_LINE_COMMENT: { + if (ch == '\n') { + mode = MODE_SELECT; + } + tokenizer_state_advance(&context, &state); + break; + } + case MODE_COMMENT: { + if (ch == '*') { + if (state.next_next >= 0) { + char chch = (char)state.next_next; + if (chch == '/') { + mode = MODE_SELECT; + tokenizer_state_advance(&context, &state); + } + } + } + tokenizer_state_advance(&context, &state); + break; + } + case MODE_NUMBER: { + if (is_num(ch, 0) || ch == '.') { + if (ch == '.') { + number_has_dot = true; + } + tokenizer_buffer_add(&buffer, ch); + tokenizer_state_advance(&context, &state); + } + else { + token token = token_create(number_has_dot ? TOKEN_FLOAT : TOKEN_INT, &state); + token.number = tokenizer_buffer_parse_number(&buffer); + tokens_add(&tokens, token); + mode = MODE_SELECT; + } + break; + } + case MODE_OPERATOR: { + char long_op[3]; + long_op[0] = 0; + if (buffer.current_size == 1) { + long_op[0] = buffer.buf[0]; + long_op[1] = ch; + long_op[2] = 0; + } + + if (strcmp(long_op, "==") == 0 || strcmp(long_op, "!=") == 0 || strcmp(long_op, "<=") == 0 || strcmp(long_op, ">=") == 0 || + strcmp(long_op, "||") == 0 || strcmp(long_op, "&&") == 0 || strcmp(long_op, "->") == 0 || strcmp(long_op, "-=") == 0 || + strcmp(long_op, "+=") == 0 || strcmp(long_op, "/=") == 0 || strcmp(long_op, "*=") == 0) { + tokenizer_buffer_add(&buffer, ch); + tokenizer_state_advance(&context, &state); + } + + if (tokenizer_buffer_equals(&buffer, "==")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_EQUALS; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "!=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_NOT_EQUALS; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, ">")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_GREATER; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, ">=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_GREATER_EQUAL; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "<")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_LESS; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "<=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_LESS_EQUAL; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "-=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_MINUS_ASSIGN; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "+=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_PLUS_ASSIGN; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "/=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_DIVIDE_ASSIGN; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "*=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_MULTIPLY_ASSIGN; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "-")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_MINUS; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "+")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_PLUS; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "/")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_DIVIDE; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "*")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_MULTIPLY; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "!")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_NOT; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "||")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_OR; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "^")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_XOR; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "&&")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_AND; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "%")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_MOD; + tokens_add(&tokens, token); + } + else if (tokenizer_buffer_equals(&buffer, "=")) { + token token = token_create(TOKEN_OPERATOR, &state); + token.op = OPERATOR_ASSIGN; + tokens_add(&tokens, token); + } + else { + error(context, "Weird operator"); + } + + mode = MODE_SELECT; + break; + } + /*case MODE_STRING: { + if (ch == '"' || ch == '\'') { + token token = token_create(TOKEN_STRING, &state); + tokenizer_buffer_copy_to_string(&buffer, token.string); + token.column = buffer.column; + token.line = buffer.line; + tokens_add(&tokens, token); + + tokenizer_state_advance(&state); + mode = MODE_SELECT; + } + else { + tokenizer_buffer_add(&buffer, ch); + tokenizer_state_advance(&state); + } + break; + }*/ + case MODE_IDENTIFIER: { + if (is_whitespace(ch) || is_op(ch) || ch == '(' || ch == ')' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == '"' || ch == '\'' || + ch == ';' || ch == '.' || ch == ',' || ch == ':') { + tokens_add_identifier(&state, &tokens, &buffer); + mode = MODE_SELECT; + } + else { + tokenizer_buffer_add(&buffer, ch); + tokenizer_state_advance(&context, &state); + } + break; + } + } + } + } +} diff --git a/base/sources/libs/kong/sources/tokenizer.h b/base/sources/libs/kong/sources/tokenizer.h new file mode 100644 index 00000000..db97d19c --- /dev/null +++ b/base/sources/libs/kong/sources/tokenizer.h @@ -0,0 +1,83 @@ +#pragma once + +#include "names.h" + +#include +#include + +typedef enum operatorr { + OPERATOR_EQUALS, + OPERATOR_NOT_EQUALS, + OPERATOR_GREATER, + OPERATOR_GREATER_EQUAL, + OPERATOR_LESS, + OPERATOR_LESS_EQUAL, + OPERATOR_MINUS, + OPERATOR_PLUS, + OPERATOR_DIVIDE, + OPERATOR_MULTIPLY, + OPERATOR_NOT, + OPERATOR_OR, + OPERATOR_XOR, + OPERATOR_AND, + OPERATOR_MOD, + OPERATOR_ASSIGN, + OPERATOR_MINUS_ASSIGN, + OPERATOR_PLUS_ASSIGN, + OPERATOR_DIVIDE_ASSIGN, + OPERATOR_MULTIPLY_ASSIGN +} operatorr; + +typedef struct token { + int line, column; + + enum { + TOKEN_NONE, + TOKEN_BOOLEAN, + TOKEN_FLOAT, + TOKEN_INT, + // TOKEN_STRING, + TOKEN_IDENTIFIER, + TOKEN_LEFT_PAREN, + TOKEN_RIGHT_PAREN, + TOKEN_LEFT_CURLY, + TOKEN_RIGHT_CURLY, + TOKEN_LEFT_SQUARE, + TOKEN_RIGHT_SQUARE, + TOKEN_HASH, + TOKEN_IF, + TOKEN_ELSE, + TOKEN_WHILE, + TOKEN_DO, + TOKEN_FOR, + TOKEN_SEMICOLON, + TOKEN_COLON, + TOKEN_DOT, + TOKEN_COMMA, + TOKEN_OPERATOR, + TOKEN_IN, + TOKEN_STRUCT, + TOKEN_FUNCTION, + TOKEN_VAR, + TOKEN_CONST, + TOKEN_RETURN + } kind; + + union { + bool boolean; + double number; + // char string[MAX_IDENTIFIER_SIZE]; + name_id identifier; + operatorr op; + }; +} token; + +typedef struct tokens { + token *t; + size_t current_size; + size_t max_size; +} tokens; + +token tokens_get(tokens *arr, size_t index); + +tokens tokenize(const char *filename, const char *source); diff --git a/base/sources/libs/kong/sources/typer.c b/base/sources/libs/kong/sources/typer.c new file mode 100644 index 00000000..785468b3 --- /dev/null +++ b/base/sources/libs/kong/sources/typer.c @@ -0,0 +1,604 @@ +#include "compiler.h" +#include "disasm.h" +#include "errors.h" +#include "functions.h" +#include "globals.h" +#include "log.h" +#include "names.h" +#include "parser.h" +#include "tokenizer.h" +#include "types.h" + +#include +#include +#include +#include +#include + +type_ref find_local_var_type(block *b, name_id name) { + if (b == NULL) { + type_ref t; + init_type_ref(&t, NO_NAME); + return t; + } + + for (size_t i = 0; i < b->vars.size; ++i) { + if (b->vars.v[i].name == name) { + debug_context context = {0}; + check(b->vars.v[i].type.type != NO_TYPE, context, "Local var has no type"); + return b->vars.v[i].type; + } + } + + return find_local_var_type(b->parent, name); +} + +void resolve_types_in_expression(statement *parent, expression *e); + +type_ref resolve_member_var_type(statement *parent_block, type_ref parent_type, expression *left) { + if (left->kind == EXPRESSION_VARIABLE) { + if (parent_type.type != NO_TYPE) { + name_id name = left->variable; + + type *parent_struct = get_type(parent_type.type); + for (size_t i = 0; i < parent_struct->members.size; ++i) { + if (parent_struct->members.m[i].name == name) { + left->type = parent_struct->members.m[i].type; + return left->type; + } + } + + debug_context context = {0}; + error(context, "Member %s not found", get_name(name)); + type_ref t; + init_type_ref(&t, NO_NAME); + return t; + } + + if (parent_block != NULL) { + resolve_types_in_expression(parent_block, left); + return left->type; + } + } + else if (left->kind == EXPRESSION_CALL) { + if (parent_block != NULL) { + resolve_types_in_expression(parent_block, left); + return left->type; + } + } + else if (left->kind == EXPRESSION_INDEX) { + if (parent_type.type != NO_TYPE) { + init_type_ref(&left->type, NO_NAME); + left->type.type = get_type(parent_type.type)->base; + return left->type; + } + } + + { + debug_context context = {0}; + error(context, "Member not found"); + type_ref t; + init_type_ref(&t, NO_NAME); + return t; + } +} + +void resolve_member_type(statement *parent_block, type_ref parent_type, expression *e) { + debug_context context = {0}; + check(e->kind == EXPRESSION_STATIC_MEMBER || e->kind == EXPRESSION_DYNAMIC_MEMBER, context, "Malformed member"); + + type_ref t = resolve_member_var_type(parent_block, parent_type, e->member.left); + + if (e->kind == EXPRESSION_STATIC_MEMBER && e->member.right->kind == EXPRESSION_VARIABLE) { + resolve_member_var_type(parent_block, t, e->member.right); + e->type = e->member.right->type; + } + else if (e->kind == EXPRESSION_DYNAMIC_MEMBER) { + resolve_types_in_expression(parent_block, e->member.right); + if (e->member.left->type.type == tex2d_type_id) { + init_type_ref(&e->type, NO_NAME); + e->type.type = float4_id; + } + else if (get_type(e->member.left->type.type)->array_size > 0) { + init_type_ref(&e->type, NO_NAME); + e->type.type = get_type(e->member.left->type.type)->base; + } + else { + e->type = e->member.left->type; + } + } + else { + resolve_member_type(parent_block, t, e->member.right); + e->type = e->member.right->type; + } +} + +static bool types_compatible(type_id left, type_id right) { + if (left == right) { + return true; + } + + if ((left == int_id && right == float_id) || (left == float_id && right == int_id)) { + return true; + } + if ((left == int2_id && right == float2_id) || (left == float2_id && right == int2_id)) { + return true; + } + if ((left == int3_id && right == float3_id) || (left == float3_id && right == int3_id)) { + return true; + } + if ((left == int4_id && right == float4_id) || (left == float4_id && right == int4_id)) { + return true; + } + + if ((left == uint_id && right == float_id) || (left == float_id && right == uint_id)) { + return true; + } + if ((left == uint2_id && right == float2_id) || (left == float2_id && right == uint2_id)) { + return true; + } + if ((left == uint3_id && right == float3_id) || (left == float3_id && right == uint3_id)) { + return true; + } + if ((left == uint4_id && right == float4_id) || (left == float4_id && right == uint4_id)) { + return true; + } + + if ((left == uint_id && right == int_id) || (left == int_id && right == uint_id)) { + return true; + } + if ((left == uint2_id && right == int2_id) || (left == int2_id && right == uint2_id)) { + return true; + } + if ((left == uint3_id && right == int3_id) || (left == int3_id && right == uint3_id)) { + return true; + } + if ((left == uint4_id && right == int4_id) || (left == int4_id && right == uint4_id)) { + return true; + } + + if ((left == float_id && right == float2_id) || (left == float_id && right == float3_id) || (left == float_id && right == float4_id) || + (left == float2_id && right == float_id) || (left == float3_id && right == float_id) || (left == float4_id && right == float_id)) { + return true; + } + + if ((left == int_id && right == int2_id) || (left == int_id && right == int3_id) || (left == int_id && right == int4_id) || + (left == int2_id && right == int_id) || (left == int3_id && right == int_id) || (left == int4_id && right == int_id)) { + return true; + } + + if ((left == uint_id && right == uint2_id) || (left == uint_id && right == uint3_id) || (left == uint_id && right == uint4_id) || + (left == uint2_id && right == uint_id) || (left == uint3_id && right == uint_id) || (left == uint4_id && right == uint_id)) { + return true; + } + + if ((left == uint_id && right == int2_id) || (left == uint_id && right == int3_id) || (left == uint_id && right == int4_id) || + (left == int2_id && right == uint_id) || (left == int3_id && right == uint_id) || (left == int4_id && right == uint_id)) { + return true; + } + + if ((left == int_id && right == uint2_id) || (left == int_id && right == uint3_id) || (left == int_id && right == uint4_id) || + (left == uint2_id && right == int_id) || (left == uint3_id && right == int_id) || (left == uint4_id && right == int_id)) { + return true; + } + + return false; +} + +static type_ref upgrade_type(type_ref left_type, type_ref right_type) { + type_id left = left_type.type; + type_id right = right_type.type; + + if (left == right) { + return left_type; + } + + if (left == int_id && right == float_id) { + return right_type; + } + if (left == float_id && right == int_id) { + return left_type; + } + if (left == int2_id && right == float2_id) { + return right_type; + } + if (left == float2_id && right == int2_id) { + return left_type; + } + if (left == int3_id && right == float3_id) { + return right_type; + } + if (left == float3_id && right == int3_id) { + return left_type; + } + if (left == int4_id && right == float4_id) { + return right_type; + } + if (left == float4_id && right == int4_id) { + return left_type; + } + + if (left == uint_id && right == float_id) { + return right_type; + } + if (left == float_id && right == uint_id) { + return left_type; + } + if (left == uint2_id && right == float2_id) { + return right_type; + } + if (left == float2_id && right == uint2_id) { + return left_type; + } + if (left == uint3_id && right == float3_id) { + return right_type; + } + if (left == float3_id && right == uint3_id) { + return left_type; + } + if (left == uint4_id && right == float4_id) { + return right_type; + } + if (left == float4_id && right == uint4_id) { + return left_type; + } + + if (left == uint_id && right == int_id) { + return right_type; + } + if (left == int_id && right == uint_id) { + return left_type; + } + if (left == uint2_id && right == int2_id) { + return right_type; + } + if (left == int2_id && right == uint2_id) { + return left_type; + } + if (left == uint3_id && right == int3_id) { + return right_type; + } + if (left == int3_id && right == uint3_id) { + return left_type; + } + if (left == uint4_id && right == int4_id) { + return right_type; + } + if (left == int4_id && right == uint4_id) { + return left_type; + } + + if ((left == float2_id && right == float_id) || (left == float3_id && right == float_id) || (left == float4_id && right == float_id)) { + return left_type; + } + + if ((left == float_id && right == float2_id) || (left == float_id && right == float3_id) || (left == float_id && right == float4_id)) { + return right_type; + } + + if ((left == int2_id && right == int_id) || (left == int3_id && right == int_id) || (left == int4_id && right == int_id)) { + return left_type; + } + + if ((left == int_id && right == int2_id) || (left == int_id && right == int3_id) || (left == int_id && right == int4_id)) { + return right_type; + } + + if ((left == uint2_id && right == uint_id) || (left == uint3_id && right == uint_id) || (left == uint4_id && right == uint_id)) { + return left_type; + } + + if ((left == uint_id && right == uint2_id) || (left == uint_id && right == uint3_id) || (left == uint_id && right == uint4_id)) { + return right_type; + } + + if ((left == uint2_id && right == int_id) || (left == uint3_id && right == int_id) || (left == uint4_id && right == int_id)) { + return left_type; + } + + if ((left == int_id && right == uint2_id) || (left == int_id && right == uint3_id) || (left == int_id && right == uint4_id)) { + return right_type; + } + + if ((left == int2_id && right == uint_id) || (left == int3_id && right == uint_id) || (left == int4_id && right == uint_id)) { + return left_type; + } + + if ((left == uint_id && right == int2_id) || (left == uint_id && right == int3_id) || (left == uint_id && right == int4_id)) { + return right_type; + } + + kong_log(LOG_LEVEL_WARNING, "Suspicious type upgrade"); + return left_type; +} + +void resolve_types_in_expression(statement *parent, expression *e) { + switch (e->kind) { + case EXPRESSION_BINARY: { + resolve_types_in_expression(parent, e->binary.left); + resolve_types_in_expression(parent, e->binary.right); + switch (e->binary.op) { + case OPERATOR_EQUALS: + case OPERATOR_NOT_EQUALS: + case OPERATOR_GREATER: + case OPERATOR_GREATER_EQUAL: + case OPERATOR_LESS: + case OPERATOR_LESS_EQUAL: + case OPERATOR_OR: + case OPERATOR_AND: + case OPERATOR_XOR: { + e->type.type = bool_id; + break; + } + case OPERATOR_MULTIPLY: + case OPERATOR_MULTIPLY_ASSIGN: { + type_id left_type = e->binary.left->type.type; + type_id right_type = e->binary.right->type.type; + if ((left_type == float4x4_id && right_type == float4_id) || (left_type == float3x3_id && right_type == float3_id)) { + e->type = e->binary.right->type; + } + else if (right_type == float_id && (left_type == float2_id || left_type == float3_id || left_type == float4_id)) { + e->type = e->binary.left->type; + } + else if (types_compatible(left_type, right_type)) { + e->type = upgrade_type(e->binary.left->type, e->binary.right->type); + } + else { + debug_context context = {0}; + error(context, "Type mismatch %s vs %s", get_name(get_type(left_type)->name), get_name(get_type(right_type)->name)); + } + break; + } + case OPERATOR_MINUS: + case OPERATOR_PLUS: + case OPERATOR_DIVIDE: + case OPERATOR_MOD: { + type_id left_type = e->binary.left->type.type; + type_id right_type = e->binary.right->type.type; + if (!types_compatible(left_type, right_type)) { + debug_context context = {0}; + error(context, "Type mismatch %s vs %s", get_name(get_type(left_type)->name), get_name(get_type(right_type)->name)); + } + e->type = upgrade_type(e->binary.left->type, e->binary.right->type); + break; + } + case OPERATOR_ASSIGN: + case OPERATOR_DIVIDE_ASSIGN: + case OPERATOR_MINUS_ASSIGN: + case OPERATOR_PLUS_ASSIGN: { + type_id left_type = e->binary.left->type.type; + type_id right_type = e->binary.right->type.type; + if (!types_compatible(left_type, right_type)) { + debug_context context = {0}; + error(context, "Type mismatch %s vs %s", get_name(get_type(left_type)->name), get_name(get_type(right_type)->name)); + } + e->type = e->binary.left->type; + break; + } + case OPERATOR_NOT: { + debug_context context = {0}; + error(context, "Weird binary operator"); + break; + } + } + break; + } + case EXPRESSION_UNARY: { + resolve_types_in_expression(parent, e->unary.right); + switch (e->unary.op) { + case OPERATOR_MINUS: + case OPERATOR_PLUS: { + e->type = e->unary.right->type; + break; + } + case OPERATOR_NOT: { + e->type.type = bool_id; + break; + } + case OPERATOR_EQUALS: + case OPERATOR_NOT_EQUALS: + case OPERATOR_GREATER: + case OPERATOR_GREATER_EQUAL: + case OPERATOR_LESS: + case OPERATOR_LESS_EQUAL: + case OPERATOR_DIVIDE: + case OPERATOR_MULTIPLY: + case OPERATOR_OR: + case OPERATOR_XOR: + case OPERATOR_AND: + case OPERATOR_MOD: + case OPERATOR_ASSIGN: + default: { + debug_context context = {0}; + error(context, "Weird unary operator"); + break; + } + } + break; + } + case EXPRESSION_BOOLEAN: { + e->type.type = bool_id; + break; + } + case EXPRESSION_FLOAT: { + e->type.type = float_id; + break; + } + case EXPRESSION_INT: { + e->type.type = int_id; + break; + } + case EXPRESSION_VARIABLE: { + global *g = find_global(e->variable); + if (g != NULL && g->type != NO_TYPE) { + e->type.type = g->type; + } + else { + type_ref type = find_local_var_type(&parent->block, e->variable); + if (type.type == NO_TYPE) { + type = find_local_var_type(&parent->block, e->variable); + debug_context context = {0}; + error(context, "Variable %s not found", get_name(e->variable)); + } + e->type = type; + } + break; + } + case EXPRESSION_GROUPING: { + resolve_types_in_expression(parent, e->grouping); + e->type = e->grouping->type; + break; + } + case EXPRESSION_CALL: { + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + if (f->name == e->call.func_name) { + e->type = f->return_type; + break; + } + } + for (size_t i = 0; i < e->call.parameters.size; ++i) { + resolve_types_in_expression(parent, e->call.parameters.e[i]); + } + break; + } + case EXPRESSION_STATIC_MEMBER: + case EXPRESSION_DYNAMIC_MEMBER: { + type_ref t; + init_type_ref(&t, NO_NAME); + resolve_member_type(parent, t, e); + break; + } + case EXPRESSION_INDEX: + case EXPRESSION_CONSTRUCTOR: { + debug_context context = {0}; + error(context, "not implemented"); + break; + } + } + + if (e->type.type == NO_TYPE) { + debug_context context = {0}; + // const char *n = get_name(e->call.func_name); + error(context, "Could not resolve type"); + } +} + +void resolve_types_in_block(statement *parent, statement *block) { + debug_context context = {0}; + check(block->kind == STATEMENT_BLOCK, context, "Malformed block"); + + for (size_t i = 0; i < block->block.statements.size; ++i) { + statement *s = block->block.statements.s[i]; + switch (s->kind) { + case STATEMENT_EXPRESSION: { + resolve_types_in_expression(block, s->expression); + break; + } + case STATEMENT_RETURN_EXPRESSION: { + resolve_types_in_expression(block, s->expression); + break; + } + case STATEMENT_IF: { + resolve_types_in_expression(block, s->iffy.test); + resolve_types_in_block(block, s->iffy.if_block); + for (uint16_t i = 0; i < s->iffy.else_size; ++i) { + if (s->iffy.else_tests[i] != NULL) { + resolve_types_in_expression(block, s->iffy.else_tests[i]); + } + resolve_types_in_block(block, s->iffy.else_blocks[i]); + } + break; + } + case STATEMENT_WHILE: + case STATEMENT_DO_WHILE: { + resolve_types_in_expression(block, s->whiley.test); + resolve_types_in_block(block, s->whiley.while_block); + break; + } + case STATEMENT_BLOCK: { + resolve_types_in_block(block, s); + break; + } + case STATEMENT_LOCAL_VARIABLE: { + name_id var_name = s->local_variable.var.name; + name_id var_type_name = s->local_variable.var.type.unresolved.name; + + if (s->local_variable.var.type.type == NO_TYPE && var_type_name != NO_NAME) { + s->local_variable.var.type.type = find_type_by_ref(&s->local_variable.var.type); + } + + if (s->local_variable.var.type.type == NO_TYPE) { + debug_context context = {0}; + error(context, "Could not find type %s for %s", get_name(var_type_name), get_name(var_name)); + } + + if (s->local_variable.init != NULL) { + resolve_types_in_expression(block, s->local_variable.init); + } + + block->block.vars.v[block->block.vars.size].name = var_name; + block->block.vars.v[block->block.vars.size].type = s->local_variable.var.type; + ++block->block.vars.size; + break; + } + } + } +} + +void resolve_types(void) { + for (type_id i = 0; get_type(i) != NULL; ++i) { + type *s = get_type(i); + for (size_t j = 0; j < s->members.size; ++j) { + if (s->members.m[j].type.type == NO_TYPE) { + name_id name = s->members.m[j].type.unresolved.name; + s->members.m[j].type.type = find_type_by_name(name); + if (s->members.m[j].type.type == NO_TYPE) { + debug_context context = {0}; + error(context, "Could not find type %s in %s", get_name(name), get_name(s->name)); + } + } + } + } + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + if (f->parameter_types[parameter_index].type == NO_TYPE) { + name_id parameter_type_name = f->parameter_types[parameter_index].unresolved.name; + f->parameter_types[parameter_index].type = find_type_by_name(parameter_type_name); + if (f->parameter_types[parameter_index].type == NO_TYPE) { + debug_context context = {0}; + error(context, "Could not find type %s for %s", get_name(parameter_type_name), get_name(f->name)); + } + } + } + + if (f->return_type.type == NO_TYPE) { + f->return_type.type = find_type_by_ref(&f->return_type); + + if (f->return_type.type == NO_TYPE) { + error_no_context("Could not find type %s for %s", get_name(f->return_type.unresolved.name), get_name(f->name)); + } + } + } + + for (function_id i = 0; get_function(i) != NULL; ++i) { + function *f = get_function(i); + + if (f->block == NULL) { + // built in + continue; + } + + for (uint8_t parameter_index = 0; parameter_index < f->parameters_size; ++parameter_index) { + f->block->block.vars.v[f->block->block.vars.size].name = f->parameter_names[parameter_index]; + f->block->block.vars.v[f->block->block.vars.size].type = f->parameter_types[parameter_index]; + f->block->block.vars.v[f->block->block.vars.size].variable_id = 0; + ++f->block->block.vars.size; + } + + resolve_types_in_block(NULL, f->block); + } +} diff --git a/base/sources/libs/kong/sources/typer.h b/base/sources/libs/kong/sources/typer.h new file mode 100644 index 00000000..92a444fc --- /dev/null +++ b/base/sources/libs/kong/sources/typer.h @@ -0,0 +1,6 @@ +#ifndef KONG_TYPER_HEADER +#define KONG_TYPER_HEADER + +void resolve_types(void); + +#endif diff --git a/base/sources/libs/kong/sources/types.c b/base/sources/libs/kong/sources/types.c new file mode 100644 index 00000000..376d5b69 --- /dev/null +++ b/base/sources/libs/kong/sources/types.c @@ -0,0 +1,761 @@ +#include "types.h" + +#include "errors.h" + +#include +#include +#include + +static type *types = NULL; +static type_id types_size = 1024; +static type_id next_type_index = 0; + +type_id void_id; +type_id float_id; +type_id float2_id; +type_id float3_id; +type_id float4_id; +type_id float2x2_id; +type_id float3x2_id; +type_id float2x3_id; +type_id float4x2_id; +type_id float2x4_id; +type_id float3x3_id; +type_id float4x3_id; +type_id float3x4_id; +type_id float4x4_id; +type_id int_id; +type_id int2_id; +type_id int3_id; +type_id int4_id; +type_id uint_id; +type_id uint2_id; +type_id uint3_id; +type_id uint4_id; +type_id bool_id; +type_id bool2_id; +type_id bool3_id; +type_id bool4_id; +type_id function_type_id; +type_id tex2d_type_id; +type_id tex2darray_type_id; +type_id texcube_type_id; +type_id sampler_type_id; +type_id ray_type_id; +type_id bvh_type_id; + +typedef struct prefix { + char str[5]; + size_t size; +} prefix; + +static void permute_for_real(const char *set, prefix p, int n, int k, void (*found)(char *)) { + if (k == 0) { + found(p.str); + return; + } + + for (int i = 0; i < n; ++i) { + prefix newPrefix = p; + newPrefix.str[newPrefix.size] = set[i]; + ++newPrefix.size; + permute_for_real(set, newPrefix, n, k - 1, found); + } +} + +static void permute(const char *set, int n, int k, void (*found)(char *)) { + prefix prefix; + memset(prefix.str, 0, sizeof(prefix.str)); + prefix.size = 0; + permute_for_real(set, prefix, n, k, found); +} + +static void vec2_found_f32(char *permutation) { + type *t = get_type(float2_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = float_id; + ++t->members.size; +} + +static void vec2_found_vec2(char *permutation) { + type *t = get_type(float2_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = float2_id; + ++t->members.size; +} + +static void vec3_found_f32(char *permutation) { + type *t = get_type(float3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = float_id; + ++t->members.size; +} + +static void vec3_found_vec2(char *permutation) { + type *t = get_type(float3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = float2_id; + ++t->members.size; +} + +static void vec3_found_vec3(char *permutation) { + type *t = get_type(float3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = float3_id; + ++t->members.size; +} + +static void vec4_found_f32(char *permutation) { + type *t = get_type(float4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = float_id; + ++t->members.size; +} + +static void vec4_found_vec2(char *permutation) { + type *t = get_type(float4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = float2_id; + ++t->members.size; +} + +static void vec4_found_vec3(char *permutation) { + type *t = get_type(float4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = float3_id; + ++t->members.size; +} + +static void vec4_found_vec4(char *permutation) { + type *t = get_type(float4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = float4_id; + ++t->members.size; +} + +static void int2_found_int(char *permutation) { + type *t = get_type(int2_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = int_id; + ++t->members.size; +} + +static void int2_found_int2(char *permutation) { + type *t = get_type(int2_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = int2_id; + ++t->members.size; +} + +static void int3_found_int(char *permutation) { + type *t = get_type(int3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = int_id; + ++t->members.size; +} + +static void int3_found_int2(char *permutation) { + type *t = get_type(int3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = int2_id; + ++t->members.size; +} + +static void int3_found_int3(char *permutation) { + type *t = get_type(int3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = int3_id; + ++t->members.size; +} + +static void int4_found_int(char *permutation) { + type *t = get_type(int4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = int_id; + ++t->members.size; +} + +static void int4_found_int2(char *permutation) { + type *t = get_type(int4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = int2_id; + ++t->members.size; +} + +static void int4_found_int3(char *permutation) { + type *t = get_type(int4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = int3_id; + ++t->members.size; +} + +static void int4_found_int4(char *permutation) { + type *t = get_type(int4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = int4_id; + ++t->members.size; +} + +static void uint2_found_uint(char *permutation) { + type *t = get_type(uint2_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = uint_id; + ++t->members.size; +} + +static void uint2_found_uint2(char *permutation) { + type *t = get_type(uint2_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = uint2_id; + ++t->members.size; +} + +static void uint3_found_uint(char *permutation) { + type *t = get_type(uint3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = uint_id; + ++t->members.size; +} + +static void uint3_found_uint2(char *permutation) { + type *t = get_type(uint3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = uint2_id; + ++t->members.size; +} + +static void uint3_found_uint3(char *permutation) { + type *t = get_type(uint3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = uint3_id; + ++t->members.size; +} + +static void uint4_found_uint(char *permutation) { + type *t = get_type(uint4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = uint_id; + ++t->members.size; +} + +static void uint4_found_uint2(char *permutation) { + type *t = get_type(uint4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = uint2_id; + ++t->members.size; +} + +static void uint4_found_uint3(char *permutation) { + type *t = get_type(uint4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = uint3_id; + ++t->members.size; +} + +static void uint4_found_uint4(char *permutation) { + type *t = get_type(uint4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = uint4_id; + ++t->members.size; +} + +static void bool2_found_bool(char *permutation) { + type *t = get_type(bool2_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = bool_id; + ++t->members.size; +} + +static void bool2_found_bool2(char *permutation) { + type *t = get_type(bool2_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = bool2_id; + ++t->members.size; +} + +static void bool3_found_bool(char *permutation) { + type *t = get_type(bool3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = bool_id; + ++t->members.size; +} + +static void bool3_found_bool2(char *permutation) { + type *t = get_type(bool3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = bool2_id; + ++t->members.size; +} + +static void bool3_found_bool3(char *permutation) { + type *t = get_type(bool3_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = bool3_id; + ++t->members.size; +} + +static void bool4_found_bool(char *permutation) { + type *t = get_type(bool4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = bool_id; + ++t->members.size; +} + +static void bool4_found_bool2(char *permutation) { + type *t = get_type(bool4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = bool2_id; + ++t->members.size; +} + +static void bool4_found_bool3(char *permutation) { + type *t = get_type(bool4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = bool3_id; + ++t->members.size; +} + +static void bool4_found_bool4(char *permutation) { + type *t = get_type(bool4_id); + debug_context context = {0}; + check(t->members.size < MAX_MEMBERS, context, "Out of members"); + t->members.m[t->members.size].name = add_name(permutation); + t->members.m[t->members.size].type.type = bool4_id; + ++t->members.size; +} + +void init_type_ref(type_ref *t, name_id name) { + t->type = NO_TYPE; + t->unresolved.name = name; + t->unresolved.array_size = 0; +} + +void types_init(void) { + type *new_types = realloc(types, types_size * sizeof(type)); + debug_context context = {0}; + check(new_types != NULL, context, "Could not allocate types"); + types = new_types; + next_type_index = 0; + + void_id = add_type(add_name("void")); + get_type(void_id)->built_in = true; + + sampler_type_id = add_type(add_name("sampler")); + get_type(sampler_type_id)->built_in = true; + tex2d_type_id = add_type(add_name("tex2d")); + get_type(tex2d_type_id)->built_in = true; + tex2darray_type_id = add_type(add_name("tex2darray")); + get_type(tex2darray_type_id)->built_in = true; + texcube_type_id = add_type(add_name("texcube")); + get_type(texcube_type_id)->built_in = true; + + bool_id = add_type(add_name("bool")); + get_type(bool_id)->built_in = true; + float_id = add_type(add_name("float")); + get_type(float_id)->built_in = true; + int_id = add_type(add_name("int")); + get_type(int_id)->built_in = true; + uint_id = add_type(add_name("uint")); + get_type(uint_id)->built_in = true; + + { + float2_id = add_type(add_name("float2")); + get_type(float2_id)->built_in = true; + const char *letters = "xy"; + permute(letters, (int)strlen(letters), 1, vec2_found_f32); + permute(letters, (int)strlen(letters), 2, vec2_found_vec2); + letters = "rg"; + permute(letters, (int)strlen(letters), 1, vec2_found_f32); + permute(letters, (int)strlen(letters), 2, vec2_found_vec2); + } + + { + float3_id = add_type(add_name("float3")); + get_type(float3_id)->built_in = true; + const char *letters = "xyz"; + permute(letters, (int)strlen(letters), 1, vec3_found_f32); + permute(letters, (int)strlen(letters), 2, vec3_found_vec2); + permute(letters, (int)strlen(letters), 3, vec3_found_vec3); + letters = "rgb"; + permute(letters, (int)strlen(letters), 1, vec3_found_f32); + permute(letters, (int)strlen(letters), 2, vec3_found_vec2); + permute(letters, (int)strlen(letters), 3, vec3_found_vec3); + } + + { + float4_id = add_type(add_name("float4")); + get_type(float4_id)->built_in = true; + const char *letters = "xyzw"; + permute(letters, (int)strlen(letters), 1, vec4_found_f32); + permute(letters, (int)strlen(letters), 2, vec4_found_vec2); + permute(letters, (int)strlen(letters), 3, vec4_found_vec3); + permute(letters, (int)strlen(letters), 4, vec4_found_vec4); + letters = "rgba"; + permute(letters, (int)strlen(letters), 1, vec4_found_f32); + permute(letters, (int)strlen(letters), 2, vec4_found_vec2); + permute(letters, (int)strlen(letters), 3, vec4_found_vec3); + permute(letters, (int)strlen(letters), 4, vec4_found_vec4); + } + + { + int2_id = add_type(add_name("int2")); + get_type(int2_id)->built_in = true; + const char *letters = "xy"; + permute(letters, (int)strlen(letters), 1, int2_found_int); + permute(letters, (int)strlen(letters), 2, int2_found_int2); + letters = "rg"; + permute(letters, (int)strlen(letters), 1, int2_found_int); + permute(letters, (int)strlen(letters), 2, int2_found_int2); + } + + { + int3_id = add_type(add_name("int3")); + get_type(int3_id)->built_in = true; + const char *letters = "xyz"; + permute(letters, (int)strlen(letters), 1, int3_found_int); + permute(letters, (int)strlen(letters), 2, int3_found_int2); + permute(letters, (int)strlen(letters), 3, int3_found_int3); + letters = "rgb"; + permute(letters, (int)strlen(letters), 1, int3_found_int); + permute(letters, (int)strlen(letters), 2, int3_found_int2); + permute(letters, (int)strlen(letters), 3, int3_found_int3); + } + + { + int4_id = add_type(add_name("int4")); + get_type(int4_id)->built_in = true; + const char *letters = "xyzw"; + permute(letters, (int)strlen(letters), 1, int4_found_int); + permute(letters, (int)strlen(letters), 2, int4_found_int2); + permute(letters, (int)strlen(letters), 3, int4_found_int3); + permute(letters, (int)strlen(letters), 4, int4_found_int4); + letters = "rgba"; + permute(letters, (int)strlen(letters), 1, int4_found_int); + permute(letters, (int)strlen(letters), 2, int4_found_int2); + permute(letters, (int)strlen(letters), 3, int4_found_int3); + permute(letters, (int)strlen(letters), 4, int4_found_int4); + } + + { + uint2_id = add_type(add_name("uint2")); + get_type(uint2_id)->built_in = true; + const char *letters = "xy"; + permute(letters, (int)strlen(letters), 1, uint2_found_uint); + permute(letters, (int)strlen(letters), 2, uint2_found_uint2); + letters = "rg"; + permute(letters, (int)strlen(letters), 1, uint2_found_uint); + permute(letters, (int)strlen(letters), 2, uint2_found_uint2); + } + + { + uint3_id = add_type(add_name("uint3")); + get_type(uint3_id)->built_in = true; + const char *letters = "xyz"; + permute(letters, (int)strlen(letters), 1, uint3_found_uint); + permute(letters, (int)strlen(letters), 2, uint3_found_uint2); + permute(letters, (int)strlen(letters), 3, uint3_found_uint3); + letters = "rgb"; + permute(letters, (int)strlen(letters), 1, uint3_found_uint); + permute(letters, (int)strlen(letters), 2, uint3_found_uint2); + permute(letters, (int)strlen(letters), 3, uint3_found_uint3); + } + + { + uint4_id = add_type(add_name("uint4")); + get_type(uint4_id)->built_in = true; + const char *letters = "xyzw"; + permute(letters, (int)strlen(letters), 1, uint4_found_uint); + permute(letters, (int)strlen(letters), 2, uint4_found_uint2); + permute(letters, (int)strlen(letters), 3, uint4_found_uint3); + permute(letters, (int)strlen(letters), 4, uint4_found_uint4); + letters = "rgba"; + permute(letters, (int)strlen(letters), 1, uint4_found_uint); + permute(letters, (int)strlen(letters), 2, uint4_found_uint2); + permute(letters, (int)strlen(letters), 3, uint4_found_uint3); + permute(letters, (int)strlen(letters), 4, uint4_found_uint4); + } + + { + bool2_id = add_type(add_name("bool2")); + get_type(bool2_id)->built_in = true; + const char *letters = "xy"; + permute(letters, (int)strlen(letters), 1, bool2_found_bool); + permute(letters, (int)strlen(letters), 2, bool2_found_bool2); + letters = "rg"; + permute(letters, (int)strlen(letters), 1, bool2_found_bool); + permute(letters, (int)strlen(letters), 2, bool2_found_bool2); + } + + { + bool3_id = add_type(add_name("bool3")); + get_type(bool3_id)->built_in = true; + const char *letters = "xyz"; + permute(letters, (int)strlen(letters), 1, bool3_found_bool); + permute(letters, (int)strlen(letters), 2, bool3_found_bool2); + permute(letters, (int)strlen(letters), 3, bool3_found_bool3); + letters = "rgb"; + permute(letters, (int)strlen(letters), 1, bool3_found_bool); + permute(letters, (int)strlen(letters), 2, bool3_found_bool2); + permute(letters, (int)strlen(letters), 3, bool3_found_bool3); + } + + { + bool4_id = add_type(add_name("bool4")); + get_type(bool4_id)->built_in = true; + const char *letters = "xyzw"; + permute(letters, (int)strlen(letters), 1, bool4_found_bool); + permute(letters, (int)strlen(letters), 2, bool4_found_bool2); + permute(letters, (int)strlen(letters), 3, bool4_found_bool3); + permute(letters, (int)strlen(letters), 4, bool4_found_bool4); + letters = "rgba"; + permute(letters, (int)strlen(letters), 1, bool4_found_bool); + permute(letters, (int)strlen(letters), 2, bool4_found_bool2); + permute(letters, (int)strlen(letters), 3, bool4_found_bool3); + permute(letters, (int)strlen(letters), 4, bool4_found_bool4); + } + + { + float2x2_id = add_type(add_name("float2x2")); + get_type(float2x2_id)->built_in = true; + } + + { + float3x2_id = add_type(add_name("float3x2")); + get_type(float3x2_id)->built_in = true; + } + + { + float2x3_id = add_type(add_name("float2x3")); + get_type(float2x3_id)->built_in = true; + } + + { + float4x2_id = add_type(add_name("float4x2")); + get_type(float4x2_id)->built_in = true; + } + + { + float2x4_id = add_type(add_name("float2x4")); + get_type(float2x4_id)->built_in = true; + } + + { + float3x3_id = add_type(add_name("float3x3")); + get_type(float3x3_id)->built_in = true; + } + + { + float4x3_id = add_type(add_name("float4x3")); + get_type(float4x3_id)->built_in = true; + } + + { + float3x4_id = add_type(add_name("float3x4")); + get_type(float3x4_id)->built_in = true; + } + + { + float4x4_id = add_type(add_name("float4x4")); + get_type(float4x4_id)->built_in = true; + } + + { + ray_type_id = add_type(add_name("ray")); + get_type(ray_type_id)->built_in = true; + + type *t = get_type(ray_type_id); + + t->members.m[t->members.size].name = add_name("origin"); + t->members.m[t->members.size].type.type = float3_id; + ++t->members.size; + + t->members.m[t->members.size].name = add_name("direction"); + t->members.m[t->members.size].type.type = float3_id; + ++t->members.size; + + t->members.m[t->members.size].name = add_name("min"); + t->members.m[t->members.size].type.type = float_id; + ++t->members.size; + + t->members.m[t->members.size].name = add_name("max"); + t->members.m[t->members.size].type.type = float_id; + ++t->members.size; + } + + { + bvh_type_id = add_type(add_name("bvh")); + get_type(bvh_type_id)->built_in = true; + } + + { + function_type_id = add_type(add_name("fun")); + get_type(function_type_id)->built_in = true; + } +} + +static void grow_if_needed(uint64_t size) { + while (size >= types_size) { + types_size *= 2; + type *new_types = realloc(types, types_size * sizeof(type)); + debug_context context = {0}; + check(new_types != NULL, context, "Could not allocate types"); + types = new_types; + } +} + +type_id add_type(name_id name) { + grow_if_needed(next_type_index + 1); + + type_id s = next_type_index; + ++next_type_index; + + types[s].name = name; + types[s].attributes.attributes_count = 0; + types[s].members.size = 0; + types[s].built_in = false; + types[s].array_size = 0; + types[s].base = NO_TYPE; + + return s; +} + +type_id find_type_by_name(name_id name) { + debug_context context = {0}; + check(name != NO_NAME, context, "Attempted to find a no-name"); + for (type_id i = 0; i < next_type_index; ++i) { + if (types[i].name == name) { + return i; + } + } + + return NO_TYPE; +} + +type_id find_type_by_ref(type_ref *t) { + if (t->type != NO_TYPE) { + return t->type; + } + + debug_context context = {0}; + check(t->unresolved.name != NO_NAME, context, "Attempted to find a no-name"); + + bool found_name = false; + + for (type_id i = 0; i < next_type_index; ++i) { + if (types[i].name == t->unresolved.name) { + found_name = true; + if (types[i].array_size == t->unresolved.array_size) { + return i; + } + } + } + + if (found_name) { + type_id new_type = add_type(t->unresolved.name); + get_type(new_type)->array_size = t->unresolved.array_size; + + type_ref no_array_type; + no_array_type = *t; + no_array_type.unresolved.array_size = 0; + get_type(new_type)->base = find_type_by_ref(&no_array_type); + + return new_type; + } + + return NO_TYPE; +} + +type *get_type(type_id s) { + if (s >= next_type_index) { + return NULL; + } + return &types[s]; +} + +bool has_attribute(attribute_list *attributes, name_id name) { + for (uint8_t index = 0; index < attributes->attributes_count; ++index) { + if (attributes->attributes[index].name == name) { + return true; + } + } + return false; +} + +attribute *find_attribute(attribute_list *attributes, name_id name) { + for (uint8_t index = 0; index < attributes->attributes_count; ++index) { + if (attributes->attributes[index].name == name) { + return &attributes->attributes[index]; + } + } + return NULL; +} diff --git a/base/sources/libs/kong/sources/types.h b/base/sources/libs/kong/sources/types.h new file mode 100644 index 00000000..763d9802 --- /dev/null +++ b/base/sources/libs/kong/sources/types.h @@ -0,0 +1,95 @@ +#pragma once + +#include "names.h" +#include "tokenizer.h" + +#include +#include + +#define NO_TYPE 0xFFFFFFFF + +typedef uint32_t type_id; + +typedef struct unresolved_type_ref { + name_id name; + uint32_t array_size; +} unresolved_type_ref; + +typedef struct type_ref { + type_id type; + unresolved_type_ref unresolved; +} type_ref; + +void init_type_ref(type_ref *t, name_id name); + +typedef struct member { + name_id name; + type_ref type; + token value; +} member; + +#define MAX_MEMBERS 1024 + +typedef struct members { + member m[MAX_MEMBERS]; + size_t size; +} members; + +typedef struct attribute { + name_id name; + double parameters[16]; + uint8_t paramters_count; +} attribute; + +typedef struct attributes { + attribute attributes[64]; + uint8_t attributes_count; +} attribute_list; + +bool has_attribute(attribute_list *attributes, name_id name); + +attribute *find_attribute(attribute_list *attributes, name_id name); + +typedef struct type { + attribute_list attributes; + name_id name; + bool built_in; + + members members; + + type_id base; + uint32_t array_size; +} type; + +void types_init(void); + +type_id add_type(name_id name); + +type_id find_type_by_name(name_id name); + +type_id find_type_by_ref(type_ref *t); + +type *get_type(type_id t); + +extern type_id void_id; +extern type_id float_id; +extern type_id float2_id; +extern type_id float3_id; +extern type_id float4_id; +extern type_id float3x3_id; +extern type_id float4x4_id; +extern type_id int_id; +extern type_id int2_id; +extern type_id int3_id; +extern type_id int4_id; +extern type_id uint_id; +extern type_id uint2_id; +extern type_id uint3_id; +extern type_id uint4_id; +extern type_id bool_id; +extern type_id tex2d_type_id; +extern type_id tex2darray_type_id; +extern type_id texcube_type_id; +extern type_id sampler_type_id; +extern type_id ray_type_id; +extern type_id bvh_type_id; diff --git a/base/tools/amake/ashader.c b/base/tools/amake/ashader.c index 057551e0..71b99c0a 100644 --- a/base/tools/amake/ashader.c +++ b/base/tools/amake/ashader.c @@ -10,6 +10,58 @@ int krafix_compile(const char *source, char *output, int *length, const char *targetlang, const char *system, const char *shadertype, int version); #endif +#include "../../sources/libs/kong/sources/analyzer.h" +#include "../../sources/libs/kong/sources/compiler.h" +#include "../../sources/libs/kong/sources/disasm.h" +#include "../../sources/libs/kong/sources/errors.h" +#include "../../sources/libs/kong/sources/functions.h" +#include "../../sources/libs/kong/sources/globals.h" +#include "../../sources/libs/kong/sources/log.h" +#include "../../sources/libs/kong/sources/names.h" +#include "../../sources/libs/kong/sources/parser.h" +#include "../../sources/libs/kong/sources/tokenizer.h" +#include "../../sources/libs/kong/sources/typer.h" +#include "../../sources/libs/kong/sources/types.h" +#include "../../sources/libs/kong/sources/backends/hlsl.h" +#include "../../sources/libs/kong/sources/backends/metal.h" +#include "../../sources/libs/kong/sources/backends/spirv.h" +#include "../../sources/libs/kong/sources/backends/wgsl.h" + +void kong_compile(const char *from, const char *to) { + FILE *fp = fopen(from, "rb"); + fseek(fp , 0, SEEK_END); + int size = ftell(fp); + rewind(fp); + char *data = malloc(size + 1); + data[size] = 0; + fread(data, size, 1, fp); + fclose(fp); + + names_init(); + types_init(); + functions_init(); + globals_init(); + + tokens tokens = tokenize(from, data); + kong_parse(from, &tokens); + + resolve_types(); + allocate_globals(); + for (function_id i = 0; get_function(i) != NULL; ++i) { + compile_function_block(&get_function(i)->code, get_function(i)->block); + } + // analyze(); + + char output[512]; + strcpy(output, to); + int i = string_last_index_of(to, "/"); + output[i] = '\0'; + + // hlsl_export(output, api); + // metal_export(output); + spirv_export(output); +} + #ifdef _WIN32 #include #include @@ -1007,6 +1059,11 @@ int ashader(char *shader_lang, char *from, char *to) { // shader_lang == glsl || essl || hlsl || msl || spirv shader_type = string_index_of(from, ".vert") != -1 ? "vert" : "frag"; + if (ends_with(from, ".kong")) { + kong_compile(from, to); + return 0; + } + #ifdef _WIN32 char from_[512]; strcpy(from_, from); diff --git a/base/tools/amake/project.js b/base/tools/amake/project.js index a808cae7..dda766a3 100644 --- a/base/tools/amake/project.js +++ b/base/tools/amake/project.js @@ -30,6 +30,7 @@ project.add_cfiles("aimage.c"); if (platform === "linux") { project.add_project("../../sources/libs/to_spirv"); } + project.add_project("../../sources/libs/kong"); project.flatten(); }