render targets

This commit is contained in:
Kevin Trogant 2024-04-03 20:56:10 +02:00
parent 2035f73f3e
commit 565c330f71
14 changed files with 531 additions and 63 deletions

View File

@ -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;

View File

@ -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) \

View File

@ -0,0 +1,133 @@
#include <d3d11.h>
#include <d3d11_1.h>
#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<rt_command_buffer *>(
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];
}

View File

@ -0,0 +1,45 @@
#ifndef RT_DX11_DEVICE_OBJECTS_HPP
#define RT_DX11_DEVICE_OBJECTS_HPP
// Types containing various api objects
#include <stdint.h>
#include <d3d11.h>
#include <d3d11_1.h>
#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

View File

@ -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 <wrl.h>
#include <d3d11.h>
#include <d3d11_1.h>
#include <dxgi1_3.h>
#include "runtime/threading.h"
#include "gfx/renderer_api.h"
// Smart pointer for COM-Objects
template<typename T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
@ -15,6 +18,7 @@ struct rt_swap_chain {
ComPtr<ID3D11RenderTargetView> rtv;
};
struct rt_gpu {
ComPtr<ID3D11Device1> device;
ComPtr<ID3D11DeviceContext1> 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

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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],

View File

@ -0,0 +1,166 @@
#include <d3d11.h>
#include <d3d11_1.h>
#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<rt_render_target *>(
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<uint32_t>(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<uint32_t>(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];
}

View File

@ -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; \
}

View File

@ -19,6 +19,7 @@ runtime_lib = library('rt',
'resources.h',
'runtime.h',
'threading.h',
'threading_helpers.hpp',
'aio.c',
'assert.c',

View File

@ -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

View File

@ -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 {

View File

@ -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 <typename _LockType, void (*_AcquireFunc)(_LockType *), void (*_ReleaseFunc)(_LockType *)>
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<rt_mutex,
__rt_auto_lock_mutex_wrappers::Lock,
__rt_auto_lock_mutex_wrappers::Unlock>;
using rt_read_auto_lock = rt_generic_auto_lock<rt_rwlock, rtLockRead, rtUnlockRead>;
using rt_write_auto_lock = rt_generic_auto_lock<rt_rwlock, rtLockWrite, rtUnlockWrite>;
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