render targets
This commit is contained in:
		
							parent
							
								
									2035f73f3e
								
							
						
					
					
						commit
						565c330f71
					
				@ -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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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)                                                             \
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										133
									
								
								src/renderer/dx11/command_buffers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								src/renderer/dx11/command_buffers.cpp
									
									
									
									
									
										Normal 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];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/renderer/dx11/device_objects.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/renderer/dx11/device_objects.hpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
@ -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
 | 
			
		||||
							
								
								
									
										32
									
								
								src/renderer/dx11/helpers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/renderer/dx11/helpers.cpp
									
									
									
									
									
										Normal 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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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,
 | 
			
		||||
@ -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);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@ -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],
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										166
									
								
								src/renderer/dx11/render_targets.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								src/renderer/dx11/render_targets.cpp
									
									
									
									
									
										Normal 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];
 | 
			
		||||
}
 | 
			
		||||
@ -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;                                                                      \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ runtime_lib = library('rt',
 | 
			
		||||
  'resources.h',
 | 
			
		||||
  'runtime.h',
 | 
			
		||||
  'threading.h',
 | 
			
		||||
  'threading_helpers.hpp',
 | 
			
		||||
  
 | 
			
		||||
  'aio.c',
 | 
			
		||||
  'assert.c',
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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 {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										61
									
								
								src/runtime/threading_helpers.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/runtime/threading_helpers.hpp
									
									
									
									
									
										Normal 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
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user