From 565c330f712ffd09afbb86b9385d1f13c3f76961 Mon Sep 17 00:00:00 2001 From: Kevin Trogant Date: Wed, 3 Apr 2024 20:56:10 +0200 Subject: [PATCH] render targets --- src/gfx/gfx.h | 9 ++ src/gfx/renderer_api.h | 2 +- src/renderer/dx11/command_buffers.cpp | 133 +++++++++++++++++++++ src/renderer/dx11/device_objects.hpp | 45 +++++++ src/renderer/dx11/{gpu.h => gpu.hpp} | 13 +- src/renderer/dx11/helpers.cpp | 32 +++++ src/renderer/dx11/init.cpp | 114 +++++++++--------- src/renderer/dx11/meson.build | 6 +- src/renderer/dx11/render_targets.cpp | 166 ++++++++++++++++++++++++++ src/renderer/null/null.c | 4 +- src/runtime/meson.build | 1 + src/runtime/rt_math.h | 5 + src/runtime/runtime.h | 3 + src/runtime/threading_helpers.hpp | 61 ++++++++++ 14 files changed, 531 insertions(+), 63 deletions(-) create mode 100644 src/renderer/dx11/command_buffers.cpp create mode 100644 src/renderer/dx11/device_objects.hpp rename src/renderer/dx11/{gpu.h => gpu.hpp} (69%) create mode 100644 src/renderer/dx11/helpers.cpp create mode 100644 src/renderer/dx11/render_targets.cpp create mode 100644 src/runtime/threading_helpers.hpp diff --git a/src/gfx/gfx.h b/src/gfx/gfx.h index 612c956..a170d5e 100644 --- a/src/gfx/gfx.h +++ b/src/gfx/gfx.h @@ -20,6 +20,9 @@ extern "C" { #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4201) /* anonymous struct */ #endif typedef union { float v[4]; @@ -32,6 +35,8 @@ typedef union { } rt_color; #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop +#elif defined(_MSC_VER) +#pragma warning(pop) #endif /* NOTE(kevin): When you add a value here, you need to handle them in @@ -59,6 +64,10 @@ typedef enum { RT_PIXEL_FORMAT_count, } rt_pixel_format; +RT_INLINE int rtIsDepthFormat(rt_pixel_format format) { + return format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8 || format == RT_PIXEL_FORMAT_DEPTH32; +} + /* In renderer_api.h -> Not necessary for almost all gfx usage */ typedef struct rt_renderer_init_info_s rt_renderer_init_info; diff --git a/src/gfx/renderer_api.h b/src/gfx/renderer_api.h index 89a4389..fd14d43 100644 --- a/src/gfx/renderer_api.h +++ b/src/gfx/renderer_api.h @@ -17,7 +17,7 @@ extern "C" { /* Handles for backend objects */ -#define RT_RENDERER_BACKEND_HANDLE_MAX_INDEX ((1u<<24)-1) +#define RT_RENDER_BACKEND_HANDLE_MAX_INDEX ((1u<<24)-1) #define RT_RENDER_BACKEND_HANDLE_MAX_VERSION 255 #define RT_RENDER_BACKEND_HANDLE(name) \ diff --git a/src/renderer/dx11/command_buffers.cpp b/src/renderer/dx11/command_buffers.cpp new file mode 100644 index 0000000..319d1cb --- /dev/null +++ b/src/renderer/dx11/command_buffers.cpp @@ -0,0 +1,133 @@ +#include +#include + +#include "gfx/renderer_api.h" +#include "runtime/config.h" +#include "runtime/threading.h" +#include "runtime/threading_helpers.hpp" +#include "runtime/handles.h" + +#include "gpu.hpp" +#include "device_objects.hpp" + +RT_CVAR_I(rt_Dx11MaxCommandBuffers, + "Maximum number of simultaneously created command buffers. Default: 1024", + 1024); + +static rt_command_buffer *_buffers; +static rt_command_buffer *_first_free; +static rt_mutex *_lock; + +rt_result InitCommandBufferManagement() { + _buffers = reinterpret_cast( + calloc((size_t)rt_Dx11MaxCommandBuffers.i, sizeof(rt_command_buffer))); + if (!_buffers) + return RT_OUT_OF_MEMORY; + _first_free = &_buffers[1]; + + _lock = rtCreateMutex(); + if (!_lock) { + free(_buffers); + return RT_UNKNOWN_ERROR; + } + + for (int i = 0; i < rt_Dx11MaxCommandBuffers.i - 1; ++i) { + _buffers[i].next_free = &_buffers[i + 1]; + } + return RT_SUCCESS; +} + +void ShutdownCommandBufferManagement() { + for (int i = 0; i < rt_Dx11MaxCommandBuffers.i; ++i) { + if (_buffers[i].context) + _buffers[i].context->Release(); + } + free(_buffers); + _buffers = nullptr; +} + +extern "C" rt_result +RT_RENDERER_API_FN(AllocCommandBuffers)(uint32_t count, + const rt_alloc_command_buffer_info *, + rt_command_buffer_handle *p_command_buffers) { + for (uint32_t i = 0; i < count; ++i) { + rtLockMutex(_lock); + rt_command_buffer *slot = _first_free; + if (slot) + _first_free = slot->next_free; + rtUnlockMutex(_lock); + + if (!slot) { + rtLog("dx11", "Failed to allocate a command buffer slot."); + rtLockMutex(_lock); + for (uint32_t j = 0; j < i; ++j) { + rt_command_buffer *s = &_buffers[p_command_buffers[j].index]; + s->next_free = _first_free; + _first_free = s; + } + rtUnlockMutex(_lock); + return RT_OUT_OF_MEMORY; + } + + if (!slot->context) { + if (FAILED(g_gpu.device->CreateDeferredContext1(0, &slot->context))) { + rtLog("dx11", "Failed to create a deferred context."); + auto lock_guard = rtAutoLock(_lock); + for (uint32_t j = 0; j < i; ++j) { + rt_command_buffer *s = &_buffers[p_command_buffers[j].index]; + s->next_free = _first_free; + _first_free = s; + } + return RT_UNKNOWN_ERROR; + } + } else { + slot->context->ClearState(); + } + + slot->version = (slot->version + 1) % RT_RENDER_BACKEND_HANDLE_MAX_VERSION; + const uint32_t index = (uint32_t)(slot - _buffers); + p_command_buffers[i].version = slot->version; + p_command_buffers[i].index = index; + } + + return RT_SUCCESS; +} + +extern "C" rt_result +RT_RENDERER_API_FN(SubmitCommandBuffers)(rt_gpu_queue, const rt_submit_command_buffers_info *info) { + // TODO: Handle semaphores + + // Submit the command lists to the gpu + for (uint32_t i = 0; i < info->command_buffer_count; ++i) { + rt_command_buffer *cmdbuf = &_buffers[info->command_buffers[i].index]; + if (cmdbuf->version != info->command_buffers[i].version) { + rtLog("dx11", "Tried to submit an invalid command buffer (version mismatch)"); + return RT_INVALID_VALUE; + } + + ID3D11CommandList *cmdlist; + if (FAILED(cmdbuf->context->FinishCommandList(FALSE, &cmdlist))) { + rtLog("dx11", "FinishCommandList failed"); + return RT_UNKNOWN_ERROR; + } + + rtLockMutex(g_gpu.context_lock); + g_gpu.device_context->ExecuteCommandList(cmdlist, FALSE); + rtUnlockMutex(g_gpu.context_lock); + + rtLockMutex(_lock); + cmdbuf->next_free = _first_free; + _first_free = cmdbuf; + rtUnlockMutex(_lock); + } + return RT_SUCCESS; +} + +rt_command_buffer *rtGetCommandBuffer(rt_command_buffer_handle handle) { + if (!RT_IS_HANDLE_VALID(handle) || (int)handle.index >= rt_Dx11MaxCommandBuffers.i) + return nullptr; + auto lg = rtAutoLock(_lock); + if (handle.version != _buffers[handle.index].version) + return nullptr; + return &_buffers[handle.index]; +} \ No newline at end of file diff --git a/src/renderer/dx11/device_objects.hpp b/src/renderer/dx11/device_objects.hpp new file mode 100644 index 0000000..d5ffec3 --- /dev/null +++ b/src/renderer/dx11/device_objects.hpp @@ -0,0 +1,45 @@ +#ifndef RT_DX11_DEVICE_OBJECTS_HPP +#define RT_DX11_DEVICE_OBJECTS_HPP + +// Types containing various api objects +#include +#include +#include + +#include "runtime/runtime.h" + +struct rt_render_target { + // Only one of these should be valid + ID3D11RenderTargetView *rtv; + ID3D11DepthStencilView *dsv; + + ID3D11Texture2D *texture; + + 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_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 { + // Only created once and then re-used. + ID3D11DeviceContext1 *context; + + uint32_t version; + rt_command_buffer *next_free; +}; + +rt_render_target *rtGetRenderTarget(rt_render_target_handle handle); +rt_command_buffer *rtGetCommandBuffer(rt_command_buffer_handle handle); + +#endif \ No newline at end of file diff --git a/src/renderer/dx11/gpu.h b/src/renderer/dx11/gpu.hpp similarity index 69% rename from src/renderer/dx11/gpu.h rename to src/renderer/dx11/gpu.hpp index 5b40f3c..43595bc 100644 --- a/src/renderer/dx11/gpu.h +++ b/src/renderer/dx11/gpu.hpp @@ -1,11 +1,14 @@ -#ifndef RT_DX11_GPU_H -#define RT_DX11_GPU_H +#ifndef RT_DX11_GPU_HPP +#define RT_DX11_GPU_HPP #include #include #include #include +#include "runtime/threading.h" +#include "gfx/renderer_api.h" + // Smart pointer for COM-Objects template using ComPtr = Microsoft::WRL::ComPtr; @@ -15,6 +18,7 @@ struct rt_swap_chain { ComPtr rtv; }; + struct rt_gpu { ComPtr device; ComPtr device_context; @@ -22,11 +26,16 @@ struct rt_gpu { rt_swap_chain swap_chain; + rt_mutex *context_lock; + D3D_FEATURE_LEVEL feature_level; + D3D11_FEATURE_DATA_THREADING threading_support; }; #ifndef DONT_DEFINE_GPU_GLOBAL extern rt_gpu g_gpu; #endif +DXGI_FORMAT rtConvertPixelFormat(rt_pixel_format format); + #endif \ No newline at end of file diff --git a/src/renderer/dx11/helpers.cpp b/src/renderer/dx11/helpers.cpp new file mode 100644 index 0000000..f27b6ae --- /dev/null +++ b/src/renderer/dx11/helpers.cpp @@ -0,0 +1,32 @@ +#include "gpu.hpp" + +DXGI_FORMAT rtConvertPixelFormat(rt_pixel_format format) { + switch (format) { + case RT_PIXEL_FORMAT_INVALID: + return DXGI_FORMAT_UNKNOWN; + case RT_PIXEL_FORMAT_R8G8B8A8_UNORM: + return DXGI_FORMAT_R8G8B8A8_UNORM; + case RT_PIXEL_FORMAT_B8G8R8A8_UNORM: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case RT_PIXEL_FORMAT_R8G8B8A8_SRGB: + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + case RT_PIXEL_FORMAT_B8G8R8A8_SRGB: + return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + case RT_PIXEL_FORMAT_R8G8B8_UNORM: + return DXGI_FORMAT_R8G8B8A8_UNORM; + case RT_PIXEL_FORMAT_B8G8R8_UNORM: + return DXGI_FORMAT_B8G8R8X8_UNORM; + case RT_PIXEL_FORMAT_R8G8B8_SRGB: + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + case RT_PIXEL_FORMAT_B8G8R8_SRGB: + return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; + + case RT_PIXEL_FORMAT_DEPTH24_STENCIL8: + return DXGI_FORMAT_D24_UNORM_S8_UINT; + case RT_PIXEL_FORMAT_DEPTH32: + return DXGI_FORMAT_D32_FLOAT; + + default: + return DXGI_FORMAT_UNKNOWN; + } +} diff --git a/src/renderer/dx11/init.cpp b/src/renderer/dx11/init.cpp index c46d19f..ca9a87b 100644 --- a/src/renderer/dx11/init.cpp +++ b/src/renderer/dx11/init.cpp @@ -16,38 +16,44 @@ #include "runtime/config.h" #define DONT_DEFINE_RENDERER_GLOBAL -#include "gpu.h" +#include "gpu.hpp" 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_CVAR_I(rt_Dx11MaxSubmittedCommandBuffers, + "Maximum number of submitted command buffers per frame. Default: 1024", + 1024); + +extern rt_cvar rt_Dx11MaxCommandBuffers; rt_gpu g_gpu; extern "C" void RT_RENDERER_API_FN(RegisterCVars)(void) { rtRegisterCVAR(&rt_Dx11AdapterName); rtRegisterCVAR(&rt_Dx11VSync); + rtRegisterCVAR(&rt_Dx11MaxCommandBuffers); } static rt_swap_chain CreateSwapChain(HWND hwnd) { rt_swap_chain swc; DXGI_SWAP_CHAIN_DESC1 desc; - desc.Width = 0; // use window width + 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; + 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, @@ -84,7 +90,7 @@ static IDXGIAdapter *RetrieveSelectedAdapter(void) { if (FAILED(CreateDXGIFactory2(0, IID_PPV_ARGS(&factory)))) { return NULL; } - + UINT i = 0; IDXGIAdapter *adapter; while (factory->EnumAdapters(i, &adapter) == S_OK) { @@ -102,6 +108,11 @@ static IDXGIAdapter *RetrieveSelectedAdapter(void) { return NULL; } +extern rt_result InitCommandBufferManagement(); +extern void ShutdownCommandBufferManagement(); +extern rt_result InitRenderTargetManagement(); +extern void ShutdownRenderTargetManagement(); + 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; @@ -163,12 +174,37 @@ extern "C" rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *info) return RT_UNKNOWN_ERROR; } + g_gpu.device->CheckFeatureSupport(D3D11_FEATURE_THREADING, + &g_gpu.threading_support, + sizeof(g_gpu.threading_support)); + g_gpu.swap_chain = CreateSwapChain(info->hWnd); + g_gpu.context_lock = rtCreateMutex(); + + rt_result res = InitCommandBufferManagement(); + if (res != RT_SUCCESS) + return res; + res = InitRenderTargetManagement(); + if (res != RT_SUCCESS) + return res; + return RT_SUCCESS; } extern "C" void RT_RENDERER_API_FN(Shutdown)(void) { + ShutdownRenderTargetManagement(); + ShutdownCommandBufferManagement(); + rtDestroyMutex(g_gpu.context_lock); + g_gpu.swap_chain.rtv.Reset(); + g_gpu.swap_chain.swap_chain.Reset(); + g_gpu.dxgi_factory.Reset(); + g_gpu.device.Reset(); +} + +extern "C" unsigned int RT_RENDERER_API_FN(GetMaxFramesInFlight)(void) { + // TODO: Verify this. + return 1; } extern "C" void RT_RENDERER_API_FN(BeginFrame)(unsigned int frame_id) { @@ -179,13 +215,18 @@ extern "C" void RT_RENDERER_API_FN(BeginFrame)(unsigned int frame_id) { 0, 0, }; + rtLockMutex(g_gpu.context_lock); g_gpu.device_context->ClearRenderTargetView(g_gpu.swap_chain.rtv.Get(), clear_color); + rtUnlockMutex(g_gpu.context_lock); } extern "C" void RT_RENDERER_API_FN(EndFrame)(unsigned int frame_id) { RT_UNUSED(frame_id); + + rtLockMutex(g_gpu.context_lock); UINT sync_interval = rt_Dx11VSync.i ? 1 : 0; g_gpu.swap_chain.swap_chain->Present(sync_interval, 0); + rtUnlockMutex(g_gpu.context_lock); } // Copied from null. Delete once no longer needed @@ -194,7 +235,7 @@ 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; \ + s_next = (s_next + 1) % RT_RENDER_BACKEND_HANDLE_MAX_INDEX; \ type h = { \ 1, \ s_next, \ @@ -206,15 +247,12 @@ extern "C" { #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].index = (s_next++) % RT_RENDER_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); @@ -224,33 +262,6 @@ 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, @@ -316,15 +327,4 @@ void RT_RENDERER_API_FN(CmdFlushRenderTargetWrite)(rt_command_buffer_handle cmdb 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 index 507df5d..4522cfa 100644 --- a/src/renderer/dx11/meson.build +++ b/src/renderer/dx11/meson.build @@ -1,9 +1,13 @@ if get_option('build_dx11') dx11_renderer_lib = library('rtdx11', # Project Sources - 'gpu.h', + 'device_objects.hpp', + 'gpu.hpp', + 'command_buffers.cpp', + 'helpers.cpp', 'init.cpp', + 'render_targets.cpp', dependencies : [m_dep, windowing_dep], include_directories : [engine_incdir, contrib_incdir], diff --git a/src/renderer/dx11/render_targets.cpp b/src/renderer/dx11/render_targets.cpp new file mode 100644 index 0000000..d253231 --- /dev/null +++ b/src/renderer/dx11/render_targets.cpp @@ -0,0 +1,166 @@ +#include +#include + +#include "gfx/renderer_api.h" +#include "runtime/config.h" +#include "runtime/handles.h" +#include "runtime/threading_helpers.hpp" + +#include "device_objects.hpp" +#include "gpu.hpp" + +RT_CVAR_I(rt_Dx11MaxRenderTargets, + "Maximum number of simultaneously existing render targets. Default: 128", + 128); + +static rt_render_target *_render_targets; +static rt_render_target *_first_free; +static rt_mutex *_lock; + +rt_result InitRenderTargetManagement() { + _render_targets = reinterpret_cast( + calloc((size_t)rt_Dx11MaxRenderTargets.i, sizeof(rt_render_target))); + if (!_render_targets) { + return RT_OUT_OF_MEMORY; + } + + _lock = rtCreateMutex(); + if (!_lock) { + free(_render_targets); + return RT_UNKNOWN_ERROR; + } + + _first_free = _render_targets + 2; + for (int i = 0; i < rt_Dx11MaxRenderTargets.i; ++i) { + _render_targets[i].next_free = &_render_targets[i + 1]; + } + return RT_SUCCESS; +} + +void ShutdownRenderTargetManagement() { + for (int i = 0; i < rt_Dx11MaxRenderTargets.i; ++i) { + if (_render_targets[i].rtv) + _render_targets[i].rtv->Release(); + if (_render_targets[i].dsv) + _render_targets[i].dsv->Release(); + if (_render_targets[i].texture) + _render_targets[i].texture->Release(); + } + free(_render_targets); + rtDestroyMutex(_lock); +} + +extern "C" rt_render_target_handle +RT_RENDERER_API_FN(CreateRenderTarget)(const rt_render_target_info *info) { + rt_render_target *slot = nullptr; + { + auto lock_guard = rtAutoLock(_lock); + slot = _first_free; + _first_free = slot->next_free; + } + + if (!slot) { + rtLog("dx11", + "Could not create a new render target, because all available slots are currently in " + "use."); + return RT_INVALID_HANDLE; + } + + if (!rtIsDepthFormat(info->format)) { + D3D11_TEXTURE2D_DESC tex_desc = {}; + tex_desc.Width = info->width; + tex_desc.Height = info->height; + tex_desc.MipLevels = 1; + tex_desc.ArraySize = 1; + tex_desc.Format = rtConvertPixelFormat(info->format); + tex_desc.SampleDesc.Count = 1; + tex_desc.SampleDesc.Quality = 0; + tex_desc.Usage = D3D11_USAGE_DEFAULT; // read and write + tex_desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + tex_desc.CPUAccessFlags = 0; // none + tex_desc.MiscFlags = 0; + if (FAILED(g_gpu.device->CreateTexture2D(&tex_desc, nullptr, &slot->texture))) { + rtLog("dx11", "Failed to create backing texture for render target %s", info->name); + auto lg = rtAutoLock(_lock); + slot->next_free = _first_free; + _first_free = slot; + return RT_INVALID_HANDLE; + } + + D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {}; + rtv_desc.Format = rtConvertPixelFormat(info->format); + rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtv_desc.Texture2D.MipSlice = 0; + if (FAILED(g_gpu.device->CreateRenderTargetView(slot->texture, &rtv_desc, &slot->rtv))) { + slot->texture->Release(); + rtLog("dx11", + "Failed to create the render target view for render target %s", + info->name); + 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 - _render_targets); + return {.version = slot->version, .index = index}; + } else { + D3D11_TEXTURE2D_DESC tex_desc = {}; + tex_desc.Width = info->width; + tex_desc.Height = info->height; + tex_desc.MipLevels = 1; + tex_desc.ArraySize = 1; + tex_desc.Format = rtConvertPixelFormat(info->format); + tex_desc.SampleDesc.Count = 1; + tex_desc.SampleDesc.Quality = 0; + tex_desc.Usage = D3D11_USAGE_DEFAULT; // read and write + tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; + tex_desc.CPUAccessFlags = 0; // none + tex_desc.MiscFlags = 0; + if (FAILED(g_gpu.device->CreateTexture2D(&tex_desc, nullptr, &slot->texture))) { + rtLog("dx11", "Failed to create backing texture for render target %s", info->name); + auto lg = rtAutoLock(_lock); + slot->next_free = _first_free; + _first_free = slot; + return RT_INVALID_HANDLE; + } + + D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = {}; + dsv_desc.Format = rtConvertPixelFormat(info->format); + dsv_desc.Flags = 0; + dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + dsv_desc.Texture2D.MipSlice = 0; + if (FAILED(g_gpu.device->CreateDepthStencilView(slot->texture, &dsv_desc, &slot->dsv))) { + slot->texture->Release(); + rtLog("dx11", + "Failed to create the depth stencil view for render target %s", + info->name); + 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 - _render_targets); + return {.version = slot->version, .index = index}; + } +} + +extern "C" rt_render_target_handle RT_RENDERER_API_FN(GetSwapchainRenderTarget)(void) { + return {1, 1}; +} + +extern "C" void RT_RENDERER_API_FN(DestroyRenderTarget)(rt_render_target_handle handle) { + RT_UNUSED(handle); +} + +rt_render_target *rtGetRenderTarget(rt_render_target_handle handle) { + if (!RT_IS_HANDLE_VALID(handle) || (int)handle.index >= rt_Dx11MaxRenderTargets.i) + return nullptr; + auto lg = rtAutoLock(_lock); + if (_render_targets[handle.index].version != handle.version) + return nullptr; + return &_render_targets[handle.index]; +} diff --git a/src/renderer/null/null.c b/src/renderer/null/null.c index c179d9f..507ac47 100644 --- a/src/renderer/null/null.c +++ b/src/renderer/null/null.c @@ -6,14 +6,14 @@ #define RETURN_HANDLE_STUB2(type, initial) \ static unsigned int s_next = (initial); \ - return (type) { .index = (s_next++) % RT_RENDERER_BACKEND_HANDLE_MAX_INDEX, .version = 1 } + return (type) { .index = (s_next++) % RT_RENDER_BACKEND_HANDLE_MAX_INDEX, .version = 1 } #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].index = (s_next++) % RT_RENDER_BACKEND_HANDLE_MAX_INDEX; \ (out)[i].version = 1; \ } diff --git a/src/runtime/meson.build b/src/runtime/meson.build index 4555b13..0668b33 100644 --- a/src/runtime/meson.build +++ b/src/runtime/meson.build @@ -19,6 +19,7 @@ runtime_lib = library('rt', 'resources.h', 'runtime.h', 'threading.h', + 'threading_helpers.hpp', 'aio.c', 'assert.c', diff --git a/src/runtime/rt_math.h b/src/runtime/rt_math.h index b2668f1..821eb5f 100644 --- a/src/runtime/rt_math.h +++ b/src/runtime/rt_math.h @@ -5,6 +5,9 @@ #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4201) /* anonymous struct */ #endif struct vec2 { @@ -44,6 +47,8 @@ typedef struct { #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop +#elif defined(_MSC_VER) +#pragma warning(pop) #endif #endif diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index bd6ea5d..08843b8 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -121,8 +121,11 @@ RT_DLLEXPORT int rtAssertHandler(const char *expr, const char *msg, const char * } \ } \ } while (0) + +#define RT_ASSERT_ALWAYS_EVAL(x, msg) RT_ASSERT(x, msg) #else #define RT_ASSERT(x, msg) RT_UNUSED(x) +#define RT_ASSERT_ALWAYS_EVAL(x, msg) (x) #endif enum { diff --git a/src/runtime/threading_helpers.hpp b/src/runtime/threading_helpers.hpp new file mode 100644 index 0000000..72272e2 --- /dev/null +++ b/src/runtime/threading_helpers.hpp @@ -0,0 +1,61 @@ +#ifndef RT_THREADING_HELPERS_HPP +#define RT_THREADING_HELPERS_HPP + +// C++ wrappers around threading functions/types + +#ifndef __cplusplus +#error This file must only be used from C++ code +#endif + +#include "threading.h" + +template +class rt_generic_auto_lock { + public: + explicit rt_generic_auto_lock(_LockType *lock) : m_lock(lock) { + _AcquireFunc(lock); + } + + ~rt_generic_auto_lock() { + _ReleaseFunc(m_lock); + } + + rt_generic_auto_lock(const rt_generic_auto_lock &) = delete; + const rt_generic_auto_lock &operator=(const rt_generic_auto_lock &) = delete; + + private: + _LockType *m_lock; +}; + +namespace __rt_auto_lock_mutex_wrappers { + +RT_INLINE void Lock(rt_mutex *mtx) { + RT_ASSERT_ALWAYS_EVAL(rtLockMutex(mtx), "Lock mutex failed!"); +} + +RT_INLINE void Unlock(rt_mutex *mtx) { + RT_ASSERT_ALWAYS_EVAL(rtUnlockMutex(mtx), "Unlock mutex failed!"); +} + +} // namespace __rt_auto_lock_mutex_wrappers + +using rt_mutex_auto_lock = rt_generic_auto_lock; + +using rt_read_auto_lock = rt_generic_auto_lock; +using rt_write_auto_lock = rt_generic_auto_lock; + +RT_INLINE rt_mutex_auto_lock rtAutoLock(rt_mutex *mutex) { + return rt_mutex_auto_lock(mutex); +} + +RT_INLINE rt_read_auto_lock rtAutoLock(rt_rwlock *rw) { + return rt_read_auto_lock(rw); +} + +RT_INLINE rt_write_auto_lock rtAutoWriteLock(rt_rwlock *rw) { + return rt_write_auto_lock(rw); +} + +#endif