render targets
This commit is contained in:
parent
2035f73f3e
commit
565c330f71
@ -20,6 +20,9 @@ extern "C" {
|
|||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4201) /* anonymous struct */
|
||||||
#endif
|
#endif
|
||||||
typedef union {
|
typedef union {
|
||||||
float v[4];
|
float v[4];
|
||||||
@ -32,6 +35,8 @@ typedef union {
|
|||||||
} rt_color;
|
} rt_color;
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* NOTE(kevin): When you add a value here, you need to handle them in
|
/* 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_count,
|
||||||
} rt_pixel_format;
|
} 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 */
|
/* In renderer_api.h -> Not necessary for almost all gfx usage */
|
||||||
typedef struct rt_renderer_init_info_s rt_renderer_init_info;
|
typedef struct rt_renderer_init_info_s rt_renderer_init_info;
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ extern "C" {
|
|||||||
|
|
||||||
/* Handles for backend objects */
|
/* 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_MAX_VERSION 255
|
||||||
|
|
||||||
#define RT_RENDER_BACKEND_HANDLE(name) \
|
#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
|
#ifndef RT_DX11_GPU_HPP
|
||||||
#define RT_DX11_GPU_H
|
#define RT_DX11_GPU_HPP
|
||||||
|
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
#include <d3d11.h>
|
#include <d3d11.h>
|
||||||
#include <d3d11_1.h>
|
#include <d3d11_1.h>
|
||||||
#include <dxgi1_3.h>
|
#include <dxgi1_3.h>
|
||||||
|
|
||||||
|
#include "runtime/threading.h"
|
||||||
|
#include "gfx/renderer_api.h"
|
||||||
|
|
||||||
// Smart pointer for COM-Objects
|
// Smart pointer for COM-Objects
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using ComPtr = Microsoft::WRL::ComPtr<T>;
|
using ComPtr = Microsoft::WRL::ComPtr<T>;
|
||||||
@ -15,6 +18,7 @@ struct rt_swap_chain {
|
|||||||
ComPtr<ID3D11RenderTargetView> rtv;
|
ComPtr<ID3D11RenderTargetView> rtv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct rt_gpu {
|
struct rt_gpu {
|
||||||
ComPtr<ID3D11Device1> device;
|
ComPtr<ID3D11Device1> device;
|
||||||
ComPtr<ID3D11DeviceContext1> device_context;
|
ComPtr<ID3D11DeviceContext1> device_context;
|
||||||
@ -22,11 +26,16 @@ struct rt_gpu {
|
|||||||
|
|
||||||
rt_swap_chain swap_chain;
|
rt_swap_chain swap_chain;
|
||||||
|
|
||||||
|
rt_mutex *context_lock;
|
||||||
|
|
||||||
D3D_FEATURE_LEVEL feature_level;
|
D3D_FEATURE_LEVEL feature_level;
|
||||||
|
D3D11_FEATURE_DATA_THREADING threading_support;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef DONT_DEFINE_GPU_GLOBAL
|
#ifndef DONT_DEFINE_GPU_GLOBAL
|
||||||
extern rt_gpu g_gpu;
|
extern rt_gpu g_gpu;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
DXGI_FORMAT rtConvertPixelFormat(rt_pixel_format format);
|
||||||
|
|
||||||
#endif
|
#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,19 +16,25 @@
|
|||||||
#include "runtime/config.h"
|
#include "runtime/config.h"
|
||||||
|
|
||||||
#define DONT_DEFINE_RENDERER_GLOBAL
|
#define DONT_DEFINE_RENDERER_GLOBAL
|
||||||
#include "gpu.h"
|
#include "gpu.hpp"
|
||||||
|
|
||||||
RT_CVAR_S(
|
RT_CVAR_S(
|
||||||
rt_Dx11AdapterName,
|
rt_Dx11AdapterName,
|
||||||
"Name of the adapter that should be used for device creation. Default: \"\" (Use default)",
|
"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_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;
|
rt_gpu g_gpu;
|
||||||
|
|
||||||
extern "C" void RT_RENDERER_API_FN(RegisterCVars)(void) {
|
extern "C" void RT_RENDERER_API_FN(RegisterCVars)(void) {
|
||||||
rtRegisterCVAR(&rt_Dx11AdapterName);
|
rtRegisterCVAR(&rt_Dx11AdapterName);
|
||||||
rtRegisterCVAR(&rt_Dx11VSync);
|
rtRegisterCVAR(&rt_Dx11VSync);
|
||||||
|
rtRegisterCVAR(&rt_Dx11MaxCommandBuffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static rt_swap_chain CreateSwapChain(HWND hwnd) {
|
static rt_swap_chain CreateSwapChain(HWND hwnd) {
|
||||||
@ -102,6 +108,11 @@ static IDXGIAdapter *RetrieveSelectedAdapter(void) {
|
|||||||
return NULL;
|
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) {
|
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};
|
constexpr D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0};
|
||||||
UINT device_flags = 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;
|
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.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;
|
return RT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void RT_RENDERER_API_FN(Shutdown)(void) {
|
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) {
|
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,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
rtLockMutex(g_gpu.context_lock);
|
||||||
g_gpu.device_context->ClearRenderTargetView(g_gpu.swap_chain.rtv.Get(), clear_color);
|
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) {
|
extern "C" void RT_RENDERER_API_FN(EndFrame)(unsigned int frame_id) {
|
||||||
RT_UNUSED(frame_id);
|
RT_UNUSED(frame_id);
|
||||||
|
|
||||||
|
rtLockMutex(g_gpu.context_lock);
|
||||||
UINT sync_interval = rt_Dx11VSync.i ? 1 : 0;
|
UINT sync_interval = rt_Dx11VSync.i ? 1 : 0;
|
||||||
g_gpu.swap_chain.swap_chain->Present(sync_interval, 0);
|
g_gpu.swap_chain.swap_chain->Present(sync_interval, 0);
|
||||||
|
rtUnlockMutex(g_gpu.context_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copied from null. Delete once no longer needed
|
// Copied from null. Delete once no longer needed
|
||||||
@ -194,7 +235,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define RETURN_HANDLE_STUB2(type, initial) \
|
#define RETURN_HANDLE_STUB2(type, initial) \
|
||||||
static unsigned int s_next = (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 = { \
|
type h = { \
|
||||||
1, \
|
1, \
|
||||||
s_next, \
|
s_next, \
|
||||||
@ -206,15 +247,12 @@ extern "C" {
|
|||||||
#define RETURN_HANDLE_ARRAY_STUB2(out, count, initial) \
|
#define RETURN_HANDLE_ARRAY_STUB2(out, count, initial) \
|
||||||
static unsigned int s_next = (initial); \
|
static unsigned int s_next = (initial); \
|
||||||
for (uint32_t i = 0; i < (count); ++i) { \
|
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; \
|
(out)[i].version = 1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RETURN_HANDLE_ARRAY_STUB(out, count) RETURN_HANDLE_ARRAY_STUB2(out, count, 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_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_info *info) {
|
||||||
RT_UNUSED(info);
|
RT_UNUSED(info);
|
||||||
RETURN_HANDLE_STUB(rt_pipeline_handle);
|
RETURN_HANDLE_STUB(rt_pipeline_handle);
|
||||||
@ -224,33 +262,6 @@ void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle handle) {
|
|||||||
RT_UNUSED(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,
|
rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count,
|
||||||
const rt_gpu_semaphore_info *info,
|
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(cmdbuf_handle);
|
||||||
RT_UNUSED(render_target);
|
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')
|
if get_option('build_dx11')
|
||||||
dx11_renderer_lib = library('rtdx11',
|
dx11_renderer_lib = library('rtdx11',
|
||||||
# Project Sources
|
# Project Sources
|
||||||
'gpu.h',
|
'device_objects.hpp',
|
||||||
|
'gpu.hpp',
|
||||||
|
|
||||||
|
'command_buffers.cpp',
|
||||||
|
'helpers.cpp',
|
||||||
'init.cpp',
|
'init.cpp',
|
||||||
|
'render_targets.cpp',
|
||||||
|
|
||||||
dependencies : [m_dep, windowing_dep],
|
dependencies : [m_dep, windowing_dep],
|
||||||
include_directories : [engine_incdir, contrib_incdir],
|
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) \
|
#define RETURN_HANDLE_STUB2(type, initial) \
|
||||||
static unsigned int s_next = (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_STUB(type) RETURN_HANDLE_STUB2(type, 1)
|
||||||
|
|
||||||
#define RETURN_HANDLE_ARRAY_STUB2(out, count, initial) \
|
#define RETURN_HANDLE_ARRAY_STUB2(out, count, initial) \
|
||||||
static unsigned int s_next = (initial); \
|
static unsigned int s_next = (initial); \
|
||||||
for (uint32_t i = 0; i < (count); ++i) { \
|
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; \
|
(out)[i].version = 1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ runtime_lib = library('rt',
|
|||||||
'resources.h',
|
'resources.h',
|
||||||
'runtime.h',
|
'runtime.h',
|
||||||
'threading.h',
|
'threading.h',
|
||||||
|
'threading_helpers.hpp',
|
||||||
|
|
||||||
'aio.c',
|
'aio.c',
|
||||||
'assert.c',
|
'assert.c',
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4201) /* anonymous struct */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct vec2 {
|
struct vec2 {
|
||||||
@ -44,6 +47,8 @@ typedef struct {
|
|||||||
|
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -121,8 +121,11 @@ RT_DLLEXPORT int rtAssertHandler(const char *expr, const char *msg, const char *
|
|||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define RT_ASSERT_ALWAYS_EVAL(x, msg) RT_ASSERT(x, msg)
|
||||||
#else
|
#else
|
||||||
#define RT_ASSERT(x, msg) RT_UNUSED(x)
|
#define RT_ASSERT(x, msg) RT_UNUSED(x)
|
||||||
|
#define RT_ASSERT_ALWAYS_EVAL(x, msg) (x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum {
|
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