diff --git a/assets/shader/static_object.pipeline b/assets/shader/static_object.pipeline index 4f4d6df..159b4c3 100644 --- a/assets/shader/static_object.pipeline +++ b/assets/shader/static_object.pipeline @@ -1,7 +1,9 @@ optimization speed; -vertex { - vk BEGIN +passes { + pass0 { + vertex { + vk BEGIN #include "common.hlsl" struct VSInput @@ -10,29 +12,31 @@ struct VSInput struct VSOutput { - float4 Pos : SV_POSITION; + float4 Pos : SV_POSITION; }; VSOutput VsMain(VSInput input, uint vertexIndex : SV_VertexID) { - VSOutput output = (VSOutput)0; - return output; -} - END + VSOutput output = (VSOutput)0; + return output; } + END + } -fragment { - vk BEGIN + fragment { + vk BEGIN struct PSOutput { - float4 Color : SV_TARGET0; +float4 Color : SV_TARGET0; }; PSOutput PsMain(void) { - PSOutput output = (PSOutput)0; - output.Color[0] = 0; - output.Color[1] = 0; - output.Color[2] = 0; - output.Color[3] = 0; - return output; + PSOutput output = (PSOutput)0; + output.Color[0] = 0; + output.Color[1] = 0; + output.Color[2] = 0; + output.Color[3] = 0; + return output; } - END + END + } + } } diff --git a/assets/test.effect b/assets/test.effect new file mode 100644 index 0000000..6e7b091 --- /dev/null +++ b/assets/test.effect @@ -0,0 +1,5 @@ +passes { + pass0 { + pipeline test/shader/static_object.pipeline; + } +} diff --git a/src/asset_compiler/pipeline_processor.c b/src/asset_compiler/effect_processor.c similarity index 57% rename from src/asset_compiler/pipeline_processor.c rename to src/asset_compiler/effect_processor.c index d1f134c..52df467 100644 --- a/src/asset_compiler/pipeline_processor.c +++ b/src/asset_compiler/effect_processor.c @@ -15,10 +15,6 @@ #include typedef struct { - rt_attribute_binding *uniform_bindings; - rt_attribute_binding *storage_bindings; - rt_attribute_binding *texture_bindings; - rt_resource shaders[3]; char *shader_names[3]; unsigned int shader_count; @@ -36,96 +32,17 @@ typedef struct { uint16_t texture_binding_count; } rt_parsed_pipeline_data; +typedef struct { + unsigned int pass_count; + rt_parsed_pipeline_data pipelines[RT_MAX_SUBRESOURCES]; +} rt_parsed_effect_data; + enum { RT_SHADER_NOT_PRESENT = RT_ASSET_PROCESSING_FAILED + 1 }; extern RT_DLLIMPORT rt_cvar rt_Renderer; -static bool ParseBindingIndex(rt_text_span span, unsigned int *index) { - if (span.length == 0) - return false; - int at = (int)span.length - 1; - unsigned int exp = 1; - unsigned int n = 0; - while (at >= 0) { - if (span.start[at] >= '0' && span.start[at] <= '9') { - unsigned int digit = (unsigned int)(span.start[at] - '0'); - n += digit * exp; - } else { - rtReportError("GFX", "Unexpected non-digit character in binding index"); - return false; - } - --at; - exp *= 10; - } - *index = n; - return true; -} - -static rt_attribute_value ParseBindingValue(rt_text_span span) { - if (rtCompareSpanToString(span, "MATERIAL_ALBEDO") == 0) { - return RT_ATTRIBUTE_VALUE_MATERIAL_ALBEDO; - } else if (rtCompareSpanToString(span, "MATERIAL_NORMAL") == 0) { - return RT_ATTRIBUTE_VALUE_MATERIAL_NORMAL; - } - rtReportError("GFX", "Unsupported binding value %*.s", span.length, span.start); - return RT_ATTRIBUTE_VALUE_UNDEFINED; -} - -static bool ParseBindings(rt_parse_state *state, - unsigned int root_list, - const char *name, - const char *file_path, - rt_attribute_binding **p_bindings, - uint16_t *p_binding_count) { - const rt_parsed_stmt *bindings = rtFindStatement(state, root_list, name); - if (bindings) { - if (bindings->form != RT_STMT_FORM_LIST) { - rtReportError("GFX", - "Expected list of bindings as the value of " - "\"%s\" in %s", - name, - file_path); - return false; - } - const rt_parsed_stmt_list *binding_list = &state->statement_lists[bindings->list_index]; - rt_attribute_binding *shader_bindings = - rtAllocBuffer(sizeof(rt_attribute_binding) * binding_list->count); - if (!bindings) { - rtReportError("GFX", "Out of memory"); - return false; - } - unsigned int binding_count = binding_list->count; - - unsigned int stmt_index = binding_list->first; - for (unsigned int i = 0; i < binding_list->count; ++i) { - const rt_parsed_stmt *stmt = &state->statements[stmt_index]; - if (!ParseBindingIndex(stmt->attribute, &shader_bindings[i].index)) { - rtReleaseBuffer(shader_bindings, - sizeof(rt_attribute_binding) * binding_list->count); - return false; - } - - shader_bindings[i].value = ParseBindingValue(stmt->value); - if (shader_bindings[i].value == RT_ATTRIBUTE_VALUE_UNDEFINED) { - rtReleaseBuffer(shader_bindings, - sizeof(rt_attribute_binding) * binding_list->count); - return false; - } - stmt_index = stmt->next; - } - - *p_bindings = shader_bindings; - *p_binding_count = (uint16_t)binding_count; - return true; - } else { - *p_bindings = NULL; - *p_binding_count = 0; - return true; - } -} - static char *GenerateShaderName(rt_shader_type type, rt_shader_stage stage, rt_shader_optimization_level optimization, @@ -300,27 +217,13 @@ ParseOptimizationLevel(rt_parse_state *state, unsigned int root_list, const char return optimization_level; } -static rt_result ParsePipelineFile(rt_file_id fid, - const char *text, - size_t length, - rt_parsed_pipeline_data *pipeline, - rt_arena *arena) { - /* This is the grammar for pipeline files: - * ::= * - * ::= ( ( ';' ) | ( '{' '}' ) ) - * ::= [:alnum:]* - * :: = [:alnum:]* */ - const char *file_path = rtGetFilePath(fid); - rt_parse_state state; - unsigned int root_list; - rt_result result = rtParseDescription(text, length, file_path, &root_list, &state, arena); - if (result != RT_SUCCESS) { - goto out; - } - - /* We allow the pipeline file to overwrite the optimization level */ - rt_shader_optimization_level optimization = - ParseOptimizationLevel(&state, root_list, file_path); +static rt_result ParsePipeline(rt_parse_state *state, + unsigned int root_list, + const char *file_path, + rt_shader_optimization_level optimization, + rt_parsed_pipeline_data *pipeline, + rt_arena *arena) { + rt_result result = RT_SUCCESS; rt_shader_type type = RT_SHADER_TYPE_INVALID; if (strcmp(rt_Renderer.s, "vk") == 0) @@ -333,7 +236,7 @@ static rt_result ParsePipelineFile(rt_file_id fid, } /* Process shader stages */ - result = ParseShader(&state, + result = ParseShader(state, root_list, "vertex", file_path, @@ -353,7 +256,7 @@ static rt_result ParsePipelineFile(rt_file_id fid, } result = RT_SUCCESS; - result = ParseShader(&state, + result = ParseShader(state, root_list, "fragment", file_path, @@ -373,7 +276,7 @@ static rt_result ParsePipelineFile(rt_file_id fid, } result = RT_SUCCESS; - result = ParseShader(&state, + result = ParseShader(state, root_list, "compute", file_path, @@ -393,115 +296,123 @@ static rt_result ParsePipelineFile(rt_file_id fid, } result = RT_SUCCESS; - /* Process bindings */ - pipeline->texture_bindings = NULL; - pipeline->texture_binding_count = 0; - pipeline->uniform_bindings = NULL; - pipeline->uniform_binding_count = 0; - pipeline->storage_bindings = NULL; - pipeline->storage_binding_count = 0; - - if (!ParseBindings(&state, - root_list, - "texture_bindings", - file_path, - &pipeline->texture_bindings, - &pipeline->texture_binding_count)) { - result = RT_ASSET_PROCESSING_FAILED; - goto out; - } - - if (!ParseBindings(&state, - root_list, - "uniform_bindings", - file_path, - &pipeline->uniform_bindings, - &pipeline->uniform_binding_count)) { - result = RT_ASSET_PROCESSING_FAILED; - goto out; - } - - if (!ParseBindings(&state, - root_list, - "storage_bindings", - file_path, - &pipeline->storage_bindings, - &pipeline->storage_binding_count)) { - result = RT_ASSET_PROCESSING_FAILED; - goto out; - } - out: return result; } +static rt_result ParseEffect(rt_file_id fid, + const char *text, + size_t length, + rt_parsed_effect_data *effect, + rt_arena *arena) { + /* This is the grammar for pipeline files: + * ::= * + * ::= ( ( ';' ) | ( '{' '}' ) ) + * ::= [:alnum:]* + * :: = [:alnum:]* */ + const char *file_path = rtGetFilePath(fid); + rt_parse_state state; + unsigned int root_list; + rt_result result = rtParseDescription(text, length, file_path, &root_list, &state, arena); + if (result != RT_SUCCESS) { + return result; + } + + memset(effect, 0, sizeof(*effect)); + + rt_shader_optimization_level optimization = + ParseOptimizationLevel(&state, root_list, file_path); + + const rt_parsed_stmt *passes_stmt = rtFindStatement(&state, root_list, "passes"); + if (!passes_stmt) { + rtLog("AC", "Did not find passes list in %s.", file_path); + return RT_INVALID_VALUE; + } + const rt_parsed_stmt_list *passes_list = &state.statement_lists[passes_stmt->list_index]; + if (passes_list->count > RT_MAX_SUBRESOURCES) { + rtLog("AC", + "Too many passes in 'passes'. Maximum supported number is %u. In %s.", + RT_MAX_SUBRESOURCES, + file_path); + return RT_INVALID_VALUE; + } + const rt_parsed_stmt *pass_stmt = &state.statements[passes_list->first]; + for (unsigned int i = 0; i < passes_list->count; + ++i, pass_stmt = &state.statements[pass_stmt->next]) { + if (pass_stmt->form != RT_STMT_FORM_LIST) { + rtLog("AC", + "Expected a list as the value of passes.%*s in %s", + pass_stmt->attribute.length, + pass_stmt->attribute.start, + file_path); + return RT_INVALID_VALUE; + } + result = ParsePipeline(&state, + pass_stmt->list_index, + file_path, + optimization, + &effect->pipelines[i], + arena); + if (result != RT_SUCCESS) + return result; + } + + return result; +} + RT_ASSET_PROCESSOR_FN(PipelineProcessor) { rt_loaded_asset asset = LoadAsset(file); if (!asset.buffer) return RT_UNKNOWN_ERROR; - rt_parsed_pipeline_data pipeline; - memset(&pipeline, 0, sizeof(pipeline)); - rt_result result = ParsePipelineFile(file, asset.buffer, asset.size, &pipeline, arena); + rt_parsed_effect_data effect; + memset(&effect, 0, sizeof(effect)); + rt_result result = ParseEffect(file, asset.buffer, asset.size, &effect, arena); if (result != RT_SUCCESS) goto out; - rt_resource_id shader_resources[3] = {0}; - result = rtCreateResources(pipeline.shader_count, - pipeline.shader_names, - pipeline.shaders, - shader_resources); - if (result != RT_SUCCESS) - goto out; + for (unsigned int i = 0; i < effect.pass_count; ++i) { + rt_parsed_pipeline_data pipeline; + memcpy(&pipeline, &effect.pipelines[i], sizeof(pipeline)); + rt_resource_id shader_resources[3] = {0}; + result = rtCreateResources(pipeline.shader_count, + pipeline.shader_names, + pipeline.shaders, + shader_resources); + if (result != RT_SUCCESS) + goto out; - rt_resource pipeline_resource = {0}; - pipeline_resource.type = RT_RESOURCE_PIPELINE; - pipeline_resource.dependency_count = pipeline.shader_count; - memcpy(pipeline_resource.dependencies, shader_resources, sizeof(shader_resources)); - pipeline_resource.subresource_count = 0; + rt_resource pipeline_resource = {0}; + pipeline_resource.type = RT_RESOURCE_PIPELINE; + pipeline_resource.dependency_count = pipeline.shader_count; + memcpy(pipeline_resource.dependencies, shader_resources, sizeof(shader_resources)); + pipeline_resource.subresource_count = 0; - size_t data_size = - sizeof(rt_pipeline_info) + sizeof(rt_attribute_binding) * (pipeline.texture_binding_count + - pipeline.uniform_binding_count + - pipeline.storage_binding_count); - pipeline_resource.data = rtArenaPush(arena, data_size); - if (!pipeline_resource.data) { - result = RT_OUT_OF_MEMORY; - goto out; - } - rt_pipeline_info *info = pipeline_resource.data; - memset(info, 0, sizeof(*info)); - info->vertex_shader = (pipeline.vertex_shader != UINT_MAX) - ? shader_resources[pipeline.vertex_shader] - : RT_INVALID_RESOURCE_ID; - info->fragment_shader = (pipeline.fragment_shader != UINT_MAX) - ? shader_resources[pipeline.fragment_shader] - : RT_INVALID_RESOURCE_ID; - info->compute_shader = (pipeline.compute_shader != UINT_MAX) - ? shader_resources[pipeline.compute_shader] - : RT_INVALID_RESOURCE_ID; - rt_attribute_binding *uniform_bindings = (rt_attribute_binding *)(info + 1); - if (pipeline.uniform_binding_count > 0) { - memcpy(uniform_bindings, pipeline.uniform_bindings, pipeline.uniform_binding_count); - rtSetRelptr(&info->uniform_bindings, uniform_bindings); - } - rt_attribute_binding *texture_bindings = (uniform_bindings + pipeline.uniform_binding_count); - if (pipeline.texture_binding_count > 0) { - memcpy(texture_bindings, pipeline.texture_bindings, pipeline.texture_binding_count); - rtSetRelptr(&info->texture_bindings, texture_bindings); - } - rt_attribute_binding *storage_bindings = (texture_bindings + pipeline.texture_binding_count); - if (pipeline.texture_binding_count > 0) { - memcpy(storage_bindings, pipeline.storage_bindings, pipeline.storage_binding_count); - rtSetRelptr(&info->storage_bindings, storage_bindings); - } - rt_resource_id pipeline_id; - const char *name = rtGetFilePath(file); - result = rtCreateResources(1, &name, &pipeline_resource, &pipeline_id); - if (result == RT_SUCCESS) { - new_resources[0] = pipeline_id; - memcpy(&new_resources[1], shader_resources, sizeof(shader_resources)); - *new_resource_count = 1 + pipeline.shader_count; + size_t data_size = sizeof(rt_pipeline_info); + pipeline_resource.data = rtArenaPush(arena, data_size); + if (!pipeline_resource.data) { + result = RT_OUT_OF_MEMORY; + goto out; + } + rt_pipeline_info *info = pipeline_resource.data; + memset(info, 0, sizeof(*info)); + info->vertex_shader = (pipeline.vertex_shader != UINT_MAX) + ? shader_resources[pipeline.vertex_shader] + : RT_INVALID_RESOURCE_ID; + info->fragment_shader = (pipeline.fragment_shader != UINT_MAX) + ? shader_resources[pipeline.fragment_shader] + : RT_INVALID_RESOURCE_ID; + info->compute_shader = (pipeline.compute_shader != UINT_MAX) + ? shader_resources[pipeline.compute_shader] + : RT_INVALID_RESOURCE_ID; + rt_resource_id pipeline_id; + const char *name = rtGetFilePath(file); + result = rtCreateResources(1, &name, &pipeline_resource, &pipeline_id); + if (result == RT_SUCCESS) { + new_resources[0] = pipeline_id; + memcpy(&new_resources[1], shader_resources, sizeof(shader_resources)); + *new_resource_count = 1 + pipeline.shader_count; + } } out: rtLog("AC", "Released %p", asset.buffer); diff --git a/src/asset_compiler/meson.build b/src/asset_compiler/meson.build index e98b44c..9b1335f 100644 --- a/src/asset_compiler/meson.build +++ b/src/asset_compiler/meson.build @@ -33,8 +33,8 @@ asset_compiler = static_library('asset_compiler', 'asset_compiler.c', 'description_parser.c', + 'effect_processor.c', 'framegraph_processor.c', - 'pipeline_processor.c', 'shader_compiler.c', sources : ac_sources, include_directories : engine_incdir, diff --git a/src/gfx/effect.h b/src/gfx/effect.h new file mode 100644 index 0000000..cfa2abe --- /dev/null +++ b/src/gfx/effect.h @@ -0,0 +1,25 @@ +#ifndef RT_GFX_EFFECT_H +#define RT_GFX_EFFECT_H + +/* A effect lists the passes during which an object needs to be rendered + * and a pipeline for each pass. + * The effect also defines the required vertex layout per pass. + */ + +#include "gfx.h" +#include "runtime/resources.h" + +typedef struct { + /* Id of the render pass during which this effect pass is run. */ + rt_render_pass_id pass_id; + + rt_resource_id vertex_shader; + rt_resource_id fragment_shader; + rt_resource_id compute_shader; +} rt_effect_pass_info; + +typedef struct { + +} rt_effect_info; + +#endif diff --git a/src/gfx/meson.build b/src/gfx/meson.build index 444e935..b4bd641 100644 --- a/src/gfx/meson.build +++ b/src/gfx/meson.build @@ -1,6 +1,7 @@ gfx_deps = [thread_dep, m_dep] gfx_lib = library('rtgfx', # Project Sources + 'effect.h', 'gfx.h', 'renderer_api.h', 'render_list.h', diff --git a/src/gfx/renderer_api.h b/src/gfx/renderer_api.h index 3754b40..e92abc9 100644 --- a/src/gfx/renderer_api.h +++ b/src/gfx/renderer_api.h @@ -59,20 +59,14 @@ typedef enum { RT_TRANSFER_QUEUE, } rt_gpu_queue; + typedef struct { rt_resource_id vertex_shader; rt_resource_id fragment_shader; rt_resource_id compute_shader; - - rt_relptr texture_bindings; - rt_relptr uniform_bindings; - rt_relptr storage_bindings; - - uint16_t texture_binding_count; - uint16_t uniform_binding_count; - uint16_t storage_binding_count; } rt_pipeline_info; +#if 0 /* Attributes are used to bind buffers (or textures) to symbolic values. * For example, an attribute might be bound to "CELL_GRID", which would be * replaced with the (at the time of the invoke) grid buffer of the current @@ -93,6 +87,8 @@ typedef struct { rt_attribute_value value; } rt_attribute_binding; +#endif + typedef enum { RT_SHADER_TYPE_INVALID, RT_SHADER_TYPE_VULKAN, diff --git a/src/runtime/resource_manager.c b/src/runtime/resource_manager.c index 7cd9f0a..946446c 100644 --- a/src/runtime/resource_manager.c +++ b/src/runtime/resource_manager.c @@ -957,47 +957,11 @@ RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resour } switch (resource->type) { case RT_RESOURCE_PIPELINE: { - static const char *binding_str[RT_ATTRIBUTE_VALUE_count] = {"", - "MaterialAlbedo", - "MaterialNormal"}; const rt_pipeline_info *pipeline = resource->data; rtLog("RESMGR", " pipeline data:"); rtLog("RESMGR", " vertex shader: %llx", pipeline->vertex_shader); rtLog("RESMGR", " fragment shader: %llx", pipeline->fragment_shader); rtLog("RESMGR", " compute shader: %llx", pipeline->compute_shader); - rtLog("RESMGR", " uniform bindings:"); - const rt_attribute_binding *uniform_bindings = - rtResolveConstRelptr(&pipeline->uniform_bindings); - for (uint32_t i = 0; i < pipeline->uniform_binding_count; ++i) { - rtLog("RESMGR", - " - %u : %s", - uniform_bindings[i].index, - (uniform_bindings[i].value < RT_ATTRIBUTE_VALUE_count) - ? binding_str[uniform_bindings[i].value] - : ""); - } - rtLog("RESMGR", " texture bindings:"); - const rt_attribute_binding *texture_bindings = - rtResolveConstRelptr(&pipeline->texture_bindings); - for (uint32_t i = 0; i < pipeline->texture_binding_count; ++i) { - rtLog("RESMGR", - " - %u : %s", - texture_bindings[i].index, - (texture_bindings[i].value < RT_ATTRIBUTE_VALUE_count) - ? binding_str[texture_bindings[i].value] - : ""); - } - rtLog("RESMGR", " storage bindings:"); - const rt_attribute_binding *storage_bindings = - rtResolveConstRelptr(&pipeline->storage_bindings); - for (uint32_t i = 0; i < pipeline->storage_binding_count; ++i) { - rtLog("RESMGR", - " - %u : %s", - storage_bindings[i].index, - (storage_bindings[i].value < RT_ATTRIBUTE_VALUE_count) - ? binding_str[storage_bindings[i].value] - : ""); - } } break; case RT_RESOURCE_SHADER: { static const char *stype_str[RT_SHADER_TYPE_count] = {"", "Vulkan"}; diff --git a/src/runtime/resources.h b/src/runtime/resources.h index 1332c64..27f1ab7 100644 --- a/src/runtime/resources.h +++ b/src/runtime/resources.h @@ -37,6 +37,8 @@ typedef enum { RT_RESOURCE_FRAMEGRAPH, + RT_RESOURCE_EFFECT, + RT_RESOURCE_TYPE_count, } rt_resource_type;