From 4d575dc229af53bb9fa9930d81c538a68b560a92 Mon Sep 17 00:00:00 2001 From: Kevin Trogant Date: Thu, 4 Apr 2024 20:01:23 +0200 Subject: [PATCH] pipelines --- assets/shader/static_object.effect | 34 +++++ meson_options.txt | 3 +- src/asset_compiler/shader_compiler.c | 2 +- src/renderer/dx11/device_objects.hpp | 31 +++- src/renderer/dx11/init.cpp | 9 -- src/renderer/dx11/pipelines.cpp | 217 +++++++++++++++++++++++++++ 6 files changed, 279 insertions(+), 17 deletions(-) create mode 100644 src/renderer/dx11/pipelines.cpp diff --git a/assets/shader/static_object.effect b/assets/shader/static_object.effect index 9895f2e..fc4ec34 100644 --- a/assets/shader/static_object.effect +++ b/assets/shader/static_object.effect @@ -14,6 +14,25 @@ struct VSOutput float4 Pos : SV_POSITION; }; +VSOutput VsMain(VSInput input, uint vertexIndex : SV_VertexID) { + VSOutput output = (VSOutput)0; + return output; +} + END + + + dx11 BEGIN +#include "common.hlsl" + +struct VSInput +{ +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; +}; + VSOutput VsMain(VSInput input, uint vertexIndex : SV_VertexID) { VSOutput output = (VSOutput)0; return output; @@ -27,6 +46,21 @@ struct PSOutput { 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; +} + END + + dx11 BEGIN +struct PSOutput { +float4 Color : SV_TARGET0; +}; + PSOutput PsMain(void) { PSOutput output = (PSOutput)0; output.Color[0] = 0; diff --git a/meson_options.txt b/meson_options.txt index a3b7d6e..b7fd66d 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,5 +2,6 @@ option('static_renderer', type : 'string', value : 'vk', description : 'Name of option('use_xlib', type : 'boolean', value : false, description : 'Use Xlib for window creation under linux') option('error_report_debugbreak', type : 'boolean', value : true, description : 'Debugbreak in ReportError') option('enable_dxc_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dxc-based shader compiler.') +option('enable_dx11_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dx11-bases shader compiler.') option('game_as_subdir', type : 'boolean', value : false, description : 'If true, adds the directory "src/game" to the build.') -option('build_dx11', type : 'boolean', value : true, description : 'Enables/disables the build of the dx11 renderer.') +option('build_dx11', type : 'boolean', value : true, description : 'Enables/disables the build of the dx11 renderer.') \ No newline at end of file diff --git a/src/asset_compiler/shader_compiler.c b/src/asset_compiler/shader_compiler.c index f2e3862..629f54a 100644 --- a/src/asset_compiler/shader_compiler.c +++ b/src/asset_compiler/shader_compiler.c @@ -65,4 +65,4 @@ rt_shader_bytecode CompileShader(rt_shader_type type, return (rt_shader_bytecode){.bytes = NULL, .len = 0}; } return _compiler_funcs[type](stage, optimization, code, file_path, arena); -} \ No newline at end of file +} diff --git a/src/renderer/dx11/device_objects.hpp b/src/renderer/dx11/device_objects.hpp index dd8bed3..b5c2ec0 100644 --- a/src/renderer/dx11/device_objects.hpp +++ b/src/renderer/dx11/device_objects.hpp @@ -17,24 +17,24 @@ struct rt_render_target { rt_pixel_format format; - bool HasStencilComponent() const { + uint32_t version; + rt_render_target *next_free; + + RT_INLINE bool HasStencilComponent() const { return format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8; } - bool IsColorRenderTarget() const { + RT_INLINE bool IsColorRenderTarget() const { RT_ASSERT(!(rtv != nullptr && dsv != nullptr), "A render target should not contain a render target and a depth stencil view"); return rtv != nullptr; } - bool IsDepthStencilTarget() const { + RT_INLINE bool IsDepthStencilTarget() const { RT_ASSERT(!(rtv != nullptr && dsv != nullptr), "A render target should not contain a render target and a depth stencil view"); return dsv != nullptr; } - - uint32_t version; - rt_render_target *next_free; }; struct rt_command_buffer { @@ -55,8 +55,27 @@ struct rt_buffer { rt_buffer *next_free; }; +struct rt_pipeline { + ID3D11InputLayout *input_layout; + ID3D11VertexShader *vertex_shader; + ID3D11PixelShader *pixel_shader; + + ID3D11ComputeShader *compute_shader; + + + rt_pipeline *next_free; + uint32_t version; + + RT_INLINE bool IsComputePipeline() const { + RT_ASSERT(!(compute_shader && (vertex_shader || pixel_shader)), + "A pipeline should contain either a compute shader or graphics shaders."); + return compute_shader != nullptr; + } +}; + rt_render_target *rtGetRenderTarget(rt_render_target_handle handle); rt_command_buffer *rtGetCommandBuffer(rt_command_buffer_handle handle); rt_buffer *rtGetBuffer(rt_buffer_handle handle); +rt_pipeline *rtGetPipeline(rt_pipeline_handle handle); #endif \ No newline at end of file diff --git a/src/renderer/dx11/init.cpp b/src/renderer/dx11/init.cpp index b10d76e..a07c878 100644 --- a/src/renderer/dx11/init.cpp +++ b/src/renderer/dx11/init.cpp @@ -253,15 +253,6 @@ extern "C" { #define RETURN_HANDLE_ARRAY_STUB(out, count) RETURN_HANDLE_ARRAY_STUB2(out, count, 1) -rt_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_info *info) { - RT_UNUSED(info); - RETURN_HANDLE_STUB(rt_pipeline_handle); -} - -void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle handle) { - RT_UNUSED(handle); -} - rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count, const rt_gpu_semaphore_info *info, rt_gpu_semaphore_handle *p_semaphores) { diff --git a/src/renderer/dx11/pipelines.cpp b/src/renderer/dx11/pipelines.cpp new file mode 100644 index 0000000..2b84e0a --- /dev/null +++ b/src/renderer/dx11/pipelines.cpp @@ -0,0 +1,217 @@ +#include +#include + +#include "gfx/effect.h" +#include "gfx/renderer_api.h" +#include "runtime/config.h" +#include "runtime/handles.h" +#include "runtime/mem_arena.h" +#include "runtime/threading_helpers.hpp" + +#include "device_objects.hpp" +#include "gpu.hpp" + +RT_CVAR_I(rt_Dx11MaxPipelines, + "Maximum number of simultaneously existing pipelines. Default: 128", + 128); + +static rt_pipeline *_pipelines; +static rt_pipeline *_first_free; +static rt_mutex *_lock; + +rt_result InitPipelineManagement() { + _pipelines = + reinterpret_cast(calloc((size_t)rt_Dx11MaxPipelines.i, sizeof(rt_pipeline))); + if (!_pipelines) + return RT_OUT_OF_MEMORY; + + _first_free = _pipelines + 1; + for (int i = 0; i < rt_Dx11MaxPipelines.i - 1; ++i) + _pipelines[i].next_free = &_pipelines[i + 1]; + + _lock = rtCreateMutex(); + if (!_lock) { + free(_pipelines); + return RT_UNKNOWN_ERROR; + } + + return RT_SUCCESS; +} + +void ShutdownPipelineManagement() { + for (int i = 0; i < rt_Dx11MaxPipelines.i; ++i) { + if (_pipelines[i].compute_shader) + _pipelines[i].compute_shader->Release(); + if (_pipelines[i].vertex_shader) + _pipelines[i].vertex_shader->Release(); + if (_pipelines[i].pixel_shader) + _pipelines[i].pixel_shader->Release(); + if (_pipelines[i].input_layout) + _pipelines[i].input_layout->Release(); + } + free(_pipelines); + rtDestroyMutex(_lock); +} + +rt_result GetShader(rt_resource_id id, rt_shader_info **p_shader, rt_arena *arena) { + size_t shader_size = rtGetResourceSize(id); + if (shader_size == 0) + return RT_INVALID_VALUE; + void *buffer = rtArenaPush(arena, shader_size); + if (!buffer) + return RT_OUT_OF_MEMORY; + rt_result res = rtGetResource(id, buffer); + if (res != RT_SUCCESS) { + rtArenaPop(arena, shader_size); + return res; + } + + rt_resource *resource = reinterpret_cast(buffer); + RT_ASSERT(resource->type == RT_RESOURCE_SHADER, "Expected a shader"); + *p_shader = reinterpret_cast(resource->data); + return RT_SUCCESS; +} + +extern "C" rt_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_info *info) { + rt_pipeline *slot = nullptr; + { + auto lg = rtAutoLock(_lock); + + slot = _first_free; + if (slot) + _first_free = slot->next_free; + } + if (!slot) { + rtLog("dx11", "Could not create pipeline, because no slots are available."); + return RT_INVALID_HANDLE; + } + + rt_temp_arena temp = rtGetTemporaryArena(NULL, 0); + + if (info->vertex_shader != RT_INVALID_RESOURCE_ID) { + rt_shader_info *vs; + if (GetShader(info->vertex_shader, &vs, temp.arena) != RT_SUCCESS) { + rtReportError("dx11", "Could not retrieve vertex shader data."); + auto lg = rtAutoLock(_lock); + slot->next_free = _first_free; + _first_free = slot; + return RT_INVALID_HANDLE; + } + + void *bytecode = rtResolveRelptr(&vs->bytecode); + if (FAILED(g_gpu.device->CreateVertexShader(bytecode, + vs->bytecode_length, + NULL, + &slot->vertex_shader))) { + rtReportError("dx11", "Vertex shader creation failed"); + auto lg = rtAutoLock(_lock); + slot->next_free = _first_free; + _first_free = slot; + return RT_INVALID_HANDLE; + } + + // TODO: effects should specify the expected vertex layout + // For now, we use a default + /* clang-format off */ + D3D11_INPUT_ELEMENT_DESC default_layout[] = { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + /* clang-format on */ + + if (FAILED(g_gpu.device->CreateInputLayout(default_layout, + RT_ARRAY_COUNT(default_layout), + bytecode, + vs->bytecode_length, + &slot->input_layout))) { + rtReportError("dx11", "Failed to create the vertex layout."); + auto lg = rtAutoLock(_lock); + slot->next_free = _first_free; + _first_free = slot; + return RT_INVALID_HANDLE; + } + } + + if (info->fragment_shader != RT_INVALID_RESOURCE_ID) { + rt_shader_info *vs; + if (GetShader(info->fragment_shader, &vs, temp.arena) != RT_SUCCESS) { + rtReportError("dx11", "Could not retrieve fragment shader data."); + auto lg = rtAutoLock(_lock); + slot->next_free = _first_free; + _first_free = slot; + return RT_INVALID_HANDLE; + } + + void *bytecode = rtResolveRelptr(&vs->bytecode); + if (FAILED(g_gpu.device->CreatePixelShader(bytecode, + vs->bytecode_length, + NULL, + &slot->pixel_shader))) { + rtReportError("dx11", "Fragment shader creation failed"); + auto lg = rtAutoLock(_lock); + slot->next_free = _first_free; + _first_free = slot; + return RT_INVALID_HANDLE; + } + } + + if (info->compute_shader != RT_INVALID_RESOURCE_ID) { + rt_shader_info *vs; + if (GetShader(info->compute_shader, &vs, temp.arena) != RT_SUCCESS) { + rtReportError("dx11", "Could not retrieve compute shader data."); + auto lg = rtAutoLock(_lock); + slot->next_free = _first_free; + _first_free = slot; + return RT_INVALID_HANDLE; + } + + void *bytecode = rtResolveRelptr(&vs->bytecode); + if (FAILED(g_gpu.device->CreateComputeShader(bytecode, + vs->bytecode_length, + NULL, + &slot->compute_shader))) { + rtReportError("dx11", "Compute shader creation failed"); + auto lg = rtAutoLock(_lock); + slot->next_free = _first_free; + _first_free = slot; + return RT_INVALID_HANDLE; + } + } + + slot->version = (slot->version + 1) % RT_RENDER_BACKEND_HANDLE_MAX_VERSION; + uint32_t index = static_cast(slot - _pipelines); + return {slot->version, index}; +} + +extern "C" void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle handle) { + if (!RT_IS_HANDLE_VALID(handle) || (int)handle.index >= rt_Dx11MaxPipelines.i) + return; + auto lg = rtAutoLock(_lock); + if (handle.version != _pipelines[handle.index].version) + return; + + if (_pipelines[handle.index].compute_shader) + _pipelines[handle.index].compute_shader->Release(); + if (_pipelines[handle.index].vertex_shader) + _pipelines[handle.index].vertex_shader->Release(); + if (_pipelines[handle.index].pixel_shader) + _pipelines[handle.index].pixel_shader->Release(); + if (_pipelines[handle.index].input_layout) + _pipelines[handle.index].input_layout->Release(); + + _pipelines[handle.index].next_free = _first_free; + _pipelines[handle.index].version = + (_pipelines[handle.index].version + 1) % RT_RENDER_BACKEND_HANDLE_MAX_VERSION; + _first_free = &_pipelines[handle.index]; +} + +rt_pipeline *rtGetPipeline(rt_pipeline_handle handle) { + if (!RT_IS_HANDLE_VALID(handle) || (int)handle.index >= rt_Dx11MaxPipelines.i) + return nullptr; + auto lg = rtAutoLock(_lock); + if (handle.version != _pipelines[handle.index].version) + return nullptr; + return &_pipelines[handle.index]; +}