diff --git a/meson.build b/meson.build index ccbc968..e7cfb81 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project('rtengine', ['c', 'cpp'], default_options: ['buildtype=debug', 'b_sanitize=address', 'c_std=c17', - 'cpp_std=c++14', + 'cpp_std=c++20', 'warning_level=3', 'werror=true', 'b_vscrt=static_from_buildtype', @@ -85,6 +85,8 @@ if get_option('default_library') == 'static' engine_link_libs = [runtime_lib, gfx_lib, app_lib, vk_renderer_lib] elif get_option('static_renderer') == 'null' engine_link_libs = [runtime_lib, gfx_lib, app_lib, null_renderer_lib] + elif get_option('static_renderer') == 'dx11' + engine_link_libs = [runtime_lib, gfx_lib, app_lib, dx11_renderer_lib] else error('Invalid static_renderer option ', get_option('static_renderer')) endif diff --git a/meson_options.txt b/meson_options.txt index 400f79b..a3b7d6e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,4 +3,4 @@ option('use_xlib', type : 'boolean', value : false, description : 'Use Xlib for 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('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.') diff --git a/src/game/main.c b/src/game/main.c index 030fb12..94d3a9d 100644 --- a/src/game/main.c +++ b/src/game/main.c @@ -13,87 +13,18 @@ void RegisterCVars(void) { static rt_framegraph *_framegraph; -static void PassPrepare(rt_render_pass_id pass, - const rt_render_target_write *writes, - uint32_t write_count, - const rt_render_target_read *reads, - uint32_t read_count) { - // rtLog("GAME", "Prepare pass %x", pass); -} - -static void PassExecute(rt_render_pass_id pass, - const rt_render_target_write *writes, - uint32_t write_count, - const rt_render_target_read *reads, - uint32_t read_count) { - // rtLog("GAME", "Execute pass %x", pass); -} - -static void PassFinalize(rt_render_pass_id pass, - const rt_render_target_write *writes, - uint32_t write_count, - const rt_render_target_read *reads, - uint32_t read_count) { - // rtLog("GAME", "Finalize pass %x", pass); -} - /* Called after the runtime has finished its initialization and before entering the main-loop*/ void Init(void) { rtLog("GAME", "Init"); rtInitAssetCompiler(); rtWaitForAssetProcessing(); - - rt_temp_arena temp = rtGetTemporaryArena(NULL, 0); - -#if 0 - rt_resource_id resid = rtGetResourceID("assets/forward.framegraph"); - size_t size = rtGetResourceSize(resid); - rt_resource *res = rtArenaPush(temp.arena, size); - rtGetResource(resid, res); - - _framegraph = rtCreateFramegraph(res->data); - - rt_render_pass_bind_fns bind = {.Execute = PassExecute, - .Prepare = PassPrepare, - .Finalize = PassFinalize}; - rtBindRenderPass(_framegraph, rtCalculateRenderPassID("forward", sizeof("forward") - 1), &bind); -#else - rt_resource_id resid = rtGetResourceID("assets/test.framegraph"); - size_t size = rtGetResourceSize(resid); - rt_resource *res = rtArenaPush(temp.arena, size); - rtGetResource(resid, res); - - _framegraph = rtCreateFramegraph(res->data); - - rt_render_pass_bind_fns bind = {.Execute = PassExecute, - .Prepare = PassPrepare, - .Finalize = PassFinalize}; - rtBindRenderPass(_framegraph, rtCalculateRenderPassID("pass0", sizeof("pass0") - 1), &bind); - rtBindRenderPass(_framegraph, rtCalculateRenderPassID("pass1", sizeof("pass1") - 1), &bind); - - rt_v2 vertices[] = { - { 0, 0.5}, - { 0.5, -0.5}, - {-0.5, -0.5} - }; - rt_buffer_info info = { - .type = RT_BUFFER_TYPE_VERTEX, - .usage = RT_BUFFER_USAGE_STATIC, - .size = sizeof(vertices), - .data = vertices, - }; - rt_buffer_handle buf; - g_renderer.CreateBuffers(1, &info, &buf); - -#endif } /* Called after exiting the main-loop and before the runtime starts its shutdown */ void Shutdown(void) { rtLog("GAME", "Shutdown"); rtShutdownAssetCompiler(); - rtDestroyFramegraph(_framegraph); } void Update(unsigned int frame_id) { @@ -101,5 +32,4 @@ void Update(unsigned int frame_id) { } void Render(unsigned int frame_id) { - rtExecuteFramegraph(_framegraph, frame_id); } \ No newline at end of file diff --git a/src/meson.build b/src/meson.build index 32aed4b..b7e1d29 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,3 +6,4 @@ subdir('app_framework') # Renderer libs subdir('renderer/vk') subdir('renderer/null') +subdir('renderer/dx11') diff --git a/src/renderer/dx11/gpu.h b/src/renderer/dx11/gpu.h new file mode 100644 index 0000000..5b40f3c --- /dev/null +++ b/src/renderer/dx11/gpu.h @@ -0,0 +1,32 @@ +#ifndef RT_DX11_GPU_H +#define RT_DX11_GPU_H + +#include +#include +#include +#include + +// Smart pointer for COM-Objects +template +using ComPtr = Microsoft::WRL::ComPtr; + +struct rt_swap_chain { + ComPtr swap_chain; + ComPtr rtv; +}; + +struct rt_gpu { + ComPtr device; + ComPtr device_context; + ComPtr dxgi_factory; + + rt_swap_chain swap_chain; + + D3D_FEATURE_LEVEL feature_level; +}; + +#ifndef DONT_DEFINE_GPU_GLOBAL +extern rt_gpu g_gpu; +#endif + +#endif \ No newline at end of file diff --git a/src/renderer/dx11/init.cpp b/src/renderer/dx11/init.cpp new file mode 100644 index 0000000..c46d19f --- /dev/null +++ b/src/renderer/dx11/init.cpp @@ -0,0 +1,330 @@ +#ifndef _WIN32 +#pragma warning Building DX11 on non - windows is probably a mistake +#endif + +#pragma comment(lib, "d3d11.lib") +#pragma comment(lib, "dxgi.lib") +#pragma comment(lib, "d3dcompiler.lib") +#pragma comment(lib, "winmm.lib") +#pragma comment(lib, "dxguid.lib") + +#include +#include +#include + +#include "gfx/renderer_api.h" +#include "runtime/config.h" + +#define DONT_DEFINE_RENDERER_GLOBAL +#include "gpu.h" + +RT_CVAR_S( + rt_Dx11AdapterName, + "Name of the adapter that should be used for device creation. Default: \"\" (Use default)", + ""); +RT_CVAR_I(rt_Dx11VSync, "Enable vsync. Default: 1", 1); + +rt_gpu g_gpu; + +extern "C" void RT_RENDERER_API_FN(RegisterCVars)(void) { + rtRegisterCVAR(&rt_Dx11AdapterName); + rtRegisterCVAR(&rt_Dx11VSync); +} + +static rt_swap_chain CreateSwapChain(HWND hwnd) { + rt_swap_chain swc; + + DXGI_SWAP_CHAIN_DESC1 desc; + desc.Width = 0; // use window width + desc.Height = 0; // use window height + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // can't specify _SRGB here when using + // DXGI_SWAP_EFFECT_FLIP_* ...; + desc.Stereo = FALSE; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = 2; + desc.Scaling = DXGI_SCALING_STRETCH; + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; + desc.Flags = 0; + + if (FAILED(g_gpu.dxgi_factory->CreateSwapChainForHwnd(g_gpu.device.Get(), + hwnd, + &desc, + nullptr, + nullptr, + &swc.swap_chain))) { + rtReportError("dx11", "Failed to create the swap chain."); + return swc; + } + + ID3D11Texture2D *frame_buffer; + if (FAILED(swc.swap_chain->GetBuffer(0, IID_PPV_ARGS(&frame_buffer)))) { + rtReportError("dx11", "Failed to retrieve the backbuffer."); + swc.swap_chain.Reset(); + return swc; + } + + D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {}; + rtv_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + + if (FAILED(g_gpu.device->CreateRenderTargetView(frame_buffer, &rtv_desc, &swc.rtv))) { + rtReportError("dx11", "Failed to create the render target view for the backbuffer."); + swc.swap_chain.Reset(); + return swc; + } + + return swc; +} + +static IDXGIAdapter *RetrieveSelectedAdapter(void) { + ComPtr factory; + if (FAILED(CreateDXGIFactory2(0, IID_PPV_ARGS(&factory)))) { + return NULL; + } + + UINT i = 0; + IDXGIAdapter *adapter; + while (factory->EnumAdapters(i, &adapter) == S_OK) { + ++i; + + DXGI_ADAPTER_DESC desc; + adapter->GetDesc(&desc); + + char utf8_desc[256]; + rtWStrToUTF8(desc.Description, utf8_desc, 256); + + if (strncmp(utf8_desc, rt_Dx11AdapterName.s, 256) == 0) + return adapter; + } + return NULL; +} + +extern "C" rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *info) { + constexpr D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0}; + UINT device_flags = 0; +#ifdef RT_DEBUG + device_flags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + + IDXGIAdapter *selected_adapter = RetrieveSelectedAdapter(); + + ID3D11Device *base_device; + ID3D11DeviceContext *base_context; + if (FAILED(D3D11CreateDevice(selected_adapter, + D3D_DRIVER_TYPE_HARDWARE, + nullptr, + device_flags, + feature_levels, + RT_ARRAY_COUNT(feature_levels), + D3D11_SDK_VERSION, + &base_device, + &g_gpu.feature_level, + &base_context))) { + rtLog("dx11", "Feature level 11.1 creation failed, retrying with feature level 11.0"); + if (FAILED(D3D11CreateDevice(selected_adapter, + D3D_DRIVER_TYPE_HARDWARE, + nullptr, + device_flags, + &feature_levels[1], + RT_ARRAY_COUNT(feature_levels) - 1, + D3D11_SDK_VERSION, + &base_device, + &g_gpu.feature_level, + &base_context))) { + rtReportError("dx11", "Failed to create the d3d11 device."); + return RT_UNKNOWN_ERROR; + } + } + + if (FAILED(base_device->QueryInterface(IID_PPV_ARGS(&g_gpu.device)))) { + rtReportError("dx11", "Failed to query the D3D11Device1 interface."); + return RT_UNKNOWN_ERROR; + } + if (FAILED(base_context->QueryInterface(IID_PPV_ARGS(&g_gpu.device_context)))) { + rtReportError("dx11", "Failed to query the D3D11DeviceContext1 interface."); + return RT_UNKNOWN_ERROR; + } + + IDXGIDevice1 *dxgi_device; + if (FAILED(g_gpu.device->QueryInterface(&dxgi_device))) { + rtReportError("dx11", "Failed to query the DXGIDevice1 interface."); + return RT_UNKNOWN_ERROR; + } + IDXGIAdapter *adapter; + if (FAILED(dxgi_device->GetAdapter(&adapter))) { + rtReportError("dx11", "Failed to retrieve the dxgi adapter."); + return RT_UNKNOWN_ERROR; + } + if (FAILED(adapter->GetParent(IID_PPV_ARGS(&g_gpu.dxgi_factory)))) { + rtReportError("dx11", "Failed to retrieve the dxgi factory."); + return RT_UNKNOWN_ERROR; + } + + g_gpu.swap_chain = CreateSwapChain(info->hWnd); + + return RT_SUCCESS; +} + +extern "C" void RT_RENDERER_API_FN(Shutdown)(void) { +} + +extern "C" void RT_RENDERER_API_FN(BeginFrame)(unsigned int frame_id) { + RT_UNUSED(frame_id); + FLOAT clear_color[4] = { + 0, + 0, + 0, + 0, + }; + g_gpu.device_context->ClearRenderTargetView(g_gpu.swap_chain.rtv.Get(), clear_color); +} + +extern "C" void RT_RENDERER_API_FN(EndFrame)(unsigned int frame_id) { + RT_UNUSED(frame_id); + UINT sync_interval = rt_Dx11VSync.i ? 1 : 0; + g_gpu.swap_chain.swap_chain->Present(sync_interval, 0); +} + +// Copied from null. Delete once no longer needed + +extern "C" { + +#define RETURN_HANDLE_STUB2(type, initial) \ + static unsigned int s_next = (initial); \ + s_next = (s_next + 1) % RT_RENDERER_BACKEND_HANDLE_MAX_INDEX; \ + type h = { \ + 1, \ + s_next, \ + }; \ + return h; + +#define RETURN_HANDLE_STUB(type) RETURN_HANDLE_STUB2(type, 1) + +#define RETURN_HANDLE_ARRAY_STUB2(out, count, initial) \ + static unsigned int s_next = (initial); \ + for (uint32_t i = 0; i < (count); ++i) { \ + (out)[i].index = (s_next++) % RT_RENDERER_BACKEND_HANDLE_MAX_INDEX; \ + (out)[i].version = 1; \ + } + +#define RETURN_HANDLE_ARRAY_STUB(out, count) RETURN_HANDLE_ARRAY_STUB2(out, count, 1) + +unsigned int RT_RENDERER_API_FN(GetMaxFramesInFlight)(void) { + return 2; +} +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_render_target_handle RT_RENDERER_API_FN(CreateRenderTarget)(const rt_render_target_info *info) { + RT_UNUSED(info); + RETURN_HANDLE_STUB2(rt_render_target_handle, 2); +} + +rt_render_target_handle RT_RENDERER_API_FN(GetSwapchainRenderTarget)(void) { + return {1, 1}; +} + +void RT_RENDERER_API_FN(DestroyRenderTarget)(rt_render_target_handle handle) { + RT_UNUSED(handle); +} + +rt_result RT_RENDERER_API_FN(AllocCommandBuffers)(uint32_t count, + const rt_alloc_command_buffer_info *info, + rt_command_buffer_handle *p_command_buffers) { + RT_UNUSED(info); + RETURN_HANDLE_ARRAY_STUB(p_command_buffers, count) + return RT_SUCCESS; +} + +rt_result RT_RENDERER_API_FN(SubmitCommandBuffers)(rt_gpu_queue queue, + const rt_submit_command_buffers_info *info) { + RT_UNUSED(queue); + RT_UNUSED(info); + return RT_SUCCESS; +} + +rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count, + const rt_gpu_semaphore_info *info, + rt_gpu_semaphore_handle *p_semaphores) { + RT_UNUSED(info); + RETURN_HANDLE_ARRAY_STUB2(p_semaphores, count, 3) + return RT_SUCCESS; +} + +void RT_RENDERER_API_FN(DestroySemaphores)(uint32_t count, rt_gpu_semaphore_handle *semaphores) { + RT_UNUSED(count); + RT_UNUSED(semaphores); +} + +/* NOTE(Kevin): It might become necessary to actually track the value, to correctly simulate gpu + * behaviour */ +uint64_t RT_RENDERER_API_FN(GetSemaphoreValue)(rt_gpu_semaphore_handle sem) { + RT_UNUSED(sem); + return 0; +} + +rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetSwapchainAvailableSemaphore)(void) { + return {1, 1}; +} + +rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetRenderFinishedSemaphore)(void) { + return {1, 2}; +} + +rt_result RT_RENDERER_API_FN(CreateBuffers)(uint32_t count, + const rt_buffer_info *info, + rt_buffer_handle *p_buffers) { + RT_UNUSED(info); + RETURN_HANDLE_ARRAY_STUB(p_buffers, count); + return RT_SUCCESS; +} + +void RT_RENDERER_API_FN(DestroyBuffers)(uint32_t count, rt_buffer_handle *buffers) { + RT_UNUSED(count); + RT_UNUSED(buffers); +} + +void RT_RENDERER_API_FN(CmdBeginPass)(rt_command_buffer_handle cmd, + const rt_cmd_begin_pass_info *info) { + RT_UNUSED(cmd); + RT_UNUSED(info); +} + +void RT_RENDERER_API_FN(CmdEndPass)(rt_command_buffer_handle cmd) { + RT_UNUSED(cmd); +} + +void RT_RENDERER_API_FN(CmdTransitionRenderTarget)(rt_command_buffer_handle cmd, + rt_render_target_handle target, + rt_render_target_state state) { + RT_UNUSED(cmd); + RT_UNUSED(target); + RT_UNUSED(state); +} + +void RT_RENDERER_API_FN(CmdFlushRenderTargetWrite)(rt_command_buffer_handle cmdbuf_handle, + rt_render_target_handle render_target) { + RT_UNUSED(cmdbuf_handle); + RT_UNUSED(render_target); +} + +rt_render_graph_builder RT_RENDERER_API_FN(CreateRenderGraphBuilder)(void) { + rt_render_graph_builder b = { + .obj = NULL, + }; + return b; +} + +void RT_RENDERER_API_FN(DestroyRenderGraphBuilder)(rt_render_graph_builder *builder) { + RT_UNUSED(builder); +} +} \ No newline at end of file diff --git a/src/renderer/dx11/meson.build b/src/renderer/dx11/meson.build new file mode 100644 index 0000000..507df5d --- /dev/null +++ b/src/renderer/dx11/meson.build @@ -0,0 +1,17 @@ +if get_option('build_dx11') + dx11_renderer_lib = library('rtdx11', + # Project Sources + 'gpu.h', + + 'init.cpp', + + dependencies : [m_dep, windowing_dep], + include_directories : [engine_incdir, contrib_incdir], + link_with : [runtime_lib], + cpp_pch : 'pch/dx11_pch.h', + override_options : ['b_sanitize=none'], + install : true) + + engine_libs += dx11_renderer_lib + engine_lib_paths += dx11_renderer_lib.full_path() +endif \ No newline at end of file diff --git a/src/renderer/dx11/pch/dx11_pch.h b/src/renderer/dx11/pch/dx11_pch.h new file mode 100644 index 0000000..8288418 --- /dev/null +++ b/src/renderer/dx11/pch/dx11_pch.h @@ -0,0 +1,5 @@ +// DX11 headers +#include +#include +#include +#include \ No newline at end of file