Merge branch 'main' into f/framegraph-v2
This commit is contained in:
commit
df50759303
@ -14,6 +14,25 @@ struct VSOutput
|
||||
float4 Pos : SV_POSITION;
|
||||
};
|
||||
|
||||
VSOutput VsMain(VSInput input, uint vertexIndex : SV_VertexID) {
|
||||
VSOutput output = (VSOutput)0;
|
||||
return output;
|
||||
}
|
||||
END
|
||||
|
||||
|
||||
dx11 BEGIN
|
||||
#include "common.hlsl"
|
||||
|
||||
struct VSInput
|
||||
{
|
||||
};
|
||||
|
||||
struct VSOutput
|
||||
{
|
||||
float4 Pos : SV_POSITION;
|
||||
};
|
||||
|
||||
VSOutput VsMain(VSInput input, uint vertexIndex : SV_VertexID) {
|
||||
VSOutput output = (VSOutput)0;
|
||||
return output;
|
||||
@ -27,6 +46,21 @@ struct PSOutput {
|
||||
float4 Color : SV_TARGET0;
|
||||
};
|
||||
|
||||
PSOutput PsMain(void) {
|
||||
PSOutput output = (PSOutput)0;
|
||||
output.Color[0] = 0;
|
||||
output.Color[1] = 0;
|
||||
output.Color[2] = 0;
|
||||
output.Color[3] = 0;
|
||||
return output;
|
||||
}
|
||||
END
|
||||
|
||||
dx11 BEGIN
|
||||
struct PSOutput {
|
||||
float4 Color : SV_TARGET0;
|
||||
};
|
||||
|
||||
PSOutput PsMain(void) {
|
||||
PSOutput output = (PSOutput)0;
|
||||
output.Color[0] = 0;
|
||||
|
@ -2,7 +2,7 @@ project('rtengine', ['c', 'cpp'],
|
||||
default_options: ['buildtype=debug',
|
||||
'b_sanitize=address',
|
||||
'c_std=c17',
|
||||
'cpp_std=c++14',
|
||||
'cpp_std=c++20',
|
||||
'warning_level=3',
|
||||
'werror=true',
|
||||
'b_vscrt=static_from_buildtype',
|
||||
@ -85,6 +85,8 @@ if get_option('default_library') == 'static'
|
||||
engine_link_libs = [runtime_lib, gfx_lib, app_lib, vk_renderer_lib]
|
||||
elif get_option('static_renderer') == 'null'
|
||||
engine_link_libs = [runtime_lib, gfx_lib, app_lib, null_renderer_lib]
|
||||
elif get_option('static_renderer') == 'dx11'
|
||||
engine_link_libs = [runtime_lib, gfx_lib, app_lib, dx11_renderer_lib]
|
||||
else
|
||||
error('Invalid static_renderer option ', get_option('static_renderer'))
|
||||
endif
|
||||
|
@ -2,5 +2,6 @@ option('static_renderer', type : 'string', value : 'vk', description : 'Name of
|
||||
option('use_xlib', type : 'boolean', value : false, description : 'Use Xlib for window creation under linux')
|
||||
option('error_report_debugbreak', type : 'boolean', value : true, description : 'Debugbreak in ReportError')
|
||||
option('enable_dxc_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dxc-based shader compiler.')
|
||||
option('enable_dx11_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dx11-bases shader compiler.')
|
||||
option('game_as_subdir', type : 'boolean', value : false, description : 'If true, adds the directory "src/game" to the build.')
|
||||
|
||||
option('build_dx11', type : 'boolean', value : true, description : 'Enables/disables the build of the dx11 renderer.')
|
89
src/asset_compiler/dx11_shader_compiler.cpp
Normal file
89
src/asset_compiler/dx11_shader_compiler.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
#include "shader_compiler.h"
|
||||
|
||||
extern "C" rt_shader_bytecode CompileDX11Shader(rt_shader_stage stage,
|
||||
rt_shader_optimization_level optimization,
|
||||
rt_text_span code,
|
||||
const char *file_path,
|
||||
rt_arena *arena) {
|
||||
rt_shader_bytecode bytecode = {};
|
||||
|
||||
D3D_SHADER_MACRO defines[] = {
|
||||
{"RT_DX11", "1"},
|
||||
{ NULL, NULL},
|
||||
};
|
||||
|
||||
LPCSTR target = NULL;
|
||||
LPCSTR entrypoint = NULL;
|
||||
switch (stage) {
|
||||
case RT_SHADER_STAGE_VERTEX:
|
||||
target = "vs_5_0";
|
||||
entrypoint = "VsMain";
|
||||
break;
|
||||
case RT_SHADER_STAGE_FRAGMENT:
|
||||
target = "ps_5_0";
|
||||
entrypoint = "PsMain";
|
||||
break;
|
||||
case RT_SHADER_STAGE_COMPUTE:
|
||||
target = "cs_5_0";
|
||||
entrypoint = "CsMain";
|
||||
break;
|
||||
default:
|
||||
rtLog("AC", "Tried to compile an invalid shader stage %u for %s", stage, file_path);
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
UINT flags = D3DCOMPILE_PARTIAL_PRECISION | D3DCOMPILE_WARNINGS_ARE_ERRORS;
|
||||
switch (optimization) {
|
||||
case RT_SHADER_OPTIMIZATION_NONE:
|
||||
flags |= D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_OPTIMIZATION_LEVEL0;
|
||||
break;
|
||||
case RT_SHADER_OPTIMIZATION_SIZE:
|
||||
flags |= D3DCOMPILE_OPTIMIZATION_LEVEL2;
|
||||
break;
|
||||
case RT_SHADER_OPTIMIZATION_SPEED:
|
||||
flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
||||
break;
|
||||
}
|
||||
#ifdef RT_DEBUG
|
||||
flags |= D3DCOMPILE_DEBUG;
|
||||
#endif
|
||||
ID3DBlob *bytes = nullptr, *error = nullptr;
|
||||
if (FAILED(D3DCompile2(code.start,
|
||||
code.length,
|
||||
file_path,
|
||||
defines,
|
||||
D3D_COMPILE_STANDARD_FILE_INCLUDE,
|
||||
entrypoint,
|
||||
target,
|
||||
flags,
|
||||
0,
|
||||
0,
|
||||
nullptr,
|
||||
0,
|
||||
&bytes,
|
||||
&error))) {
|
||||
if (error) {
|
||||
rtLog("AC",
|
||||
"Shader compilation failed (%s): %s",file_path,
|
||||
(const char *)error->GetBufferPointer());
|
||||
error->Release();
|
||||
return bytecode;
|
||||
} else {
|
||||
rtLog("AC", "Shader compilation failed (%s): NO ERROR INFORMATION", file_path);
|
||||
return bytecode;
|
||||
}
|
||||
}
|
||||
|
||||
bytecode.bytes = rtArenaPush(arena, bytes->GetBufferSize());
|
||||
if (bytecode.bytes) {
|
||||
bytecode.len = bytes->GetBufferSize();
|
||||
memcpy(bytecode.bytes, bytes->GetBufferPointer(), bytecode.len);
|
||||
} else {
|
||||
rtLog("AC", "Out of memory while compiling %s", file_path);
|
||||
}
|
||||
bytes->Release();
|
||||
|
||||
return bytecode;
|
||||
}
|
@ -62,6 +62,9 @@ static char *GenerateShaderName(rt_shader_type type,
|
||||
case RT_SHADER_TYPE_VULKAN:
|
||||
type_str = ":vk";
|
||||
break;
|
||||
case RT_SHADER_TYPE_DX11:
|
||||
type_str = ":dx11";
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -135,6 +138,8 @@ static rt_result ParseShader(rt_parse_state *state,
|
||||
rt_shader_type in_file_type = RT_SHADER_TYPE_INVALID;
|
||||
if (rtCompareSpanToString(shader->attribute, "vk") == 0) {
|
||||
in_file_type = RT_SHADER_TYPE_VULKAN;
|
||||
} else if (rtCompareSpanToString(shader->attribute, "dx11") == 0) {
|
||||
in_file_type = RT_SHADER_TYPE_DX11;
|
||||
} else {
|
||||
rtReportError("GFX",
|
||||
"Invalid renderer backend"
|
||||
@ -230,6 +235,8 @@ static rt_result ParsePipeline(rt_parse_state *state,
|
||||
rt_shader_type type = RT_SHADER_TYPE_INVALID;
|
||||
if (strcmp(rt_Renderer.s, "vk") == 0)
|
||||
type = RT_SHADER_TYPE_VULKAN;
|
||||
else if (strcmp(rt_Renderer.s, "dx11") == 0)
|
||||
type = RT_SHADER_TYPE_DX11;
|
||||
|
||||
if (type == RT_SHADER_TYPE_INVALID) {
|
||||
result = RT_ASSET_PROCESSING_FAILED;
|
||||
|
@ -39,6 +39,13 @@ if get_option('enable_dxc_shader_compiler')
|
||||
ac_cargs += '-DRT_BUILD_DXC_SHADER_COMPILER'
|
||||
endif
|
||||
|
||||
if get_option('enable_dx11_shader_compiler')
|
||||
ac_cargs += '-DRT_BUILD_DX11_SHADER_COMPILER'
|
||||
ac_sources += ['dx11_shader_compiler.cpp']
|
||||
d3dcompiler_dep = declare_dependency(link_args : ['-lD3DCompiler'])
|
||||
ac_deps += d3dcompiler_dep
|
||||
endif
|
||||
|
||||
asset_compiler = static_library('asset_compiler',
|
||||
'asset_compiler.h',
|
||||
'description_parser.h',
|
||||
|
@ -8,10 +8,18 @@ extern rt_shader_bytecode CompileVulkanShader(rt_shader_stage stage,
|
||||
rt_arena *arena);
|
||||
#endif
|
||||
|
||||
#ifdef RT_BUILD_DX11_SHADER_COMPILER
|
||||
extern rt_shader_bytecode CompileDX11Shader(rt_shader_stage stage,
|
||||
rt_shader_optimization_level optimization,
|
||||
rt_text_span code,
|
||||
const char *file_path,
|
||||
rt_arena *arena);
|
||||
#endif
|
||||
|
||||
static rt_shader_bytecode CompileNullShader(rt_shader_stage stage,
|
||||
rt_shader_optimization_level optimization,
|
||||
rt_text_span code,
|
||||
const char *file_path,
|
||||
const char *file_path,
|
||||
rt_arena *arena) {
|
||||
RT_UNUSED(stage);
|
||||
RT_UNUSED(optimization);
|
||||
@ -24,8 +32,11 @@ static rt_shader_bytecode CompileNullShader(rt_shader_stage stage,
|
||||
};
|
||||
}
|
||||
|
||||
typedef rt_shader_bytecode
|
||||
shader_compiler_fn(rt_shader_stage, rt_shader_optimization_level, rt_text_span, const char *, rt_arena *);
|
||||
typedef rt_shader_bytecode shader_compiler_fn(rt_shader_stage,
|
||||
rt_shader_optimization_level,
|
||||
rt_text_span,
|
||||
const char *,
|
||||
rt_arena *);
|
||||
|
||||
static shader_compiler_fn *_compiler_funcs[RT_SHADER_TYPE_count] = {
|
||||
CompileNullShader,
|
||||
@ -36,6 +47,11 @@ static shader_compiler_fn *_compiler_funcs[RT_SHADER_TYPE_count] = {
|
||||
CompileNullShader,
|
||||
#endif
|
||||
|
||||
#ifdef RT_BUILD_DX11_SHADER_COMPILER
|
||||
CompileDX11Shader,
|
||||
#else
|
||||
CompileNullShader,
|
||||
#endif
|
||||
};
|
||||
|
||||
rt_shader_bytecode CompileShader(rt_shader_type type,
|
||||
@ -49,4 +65,4 @@ rt_shader_bytecode CompileShader(rt_shader_type type,
|
||||
return (rt_shader_bytecode){.bytes = NULL, .len = 0};
|
||||
}
|
||||
return _compiler_funcs[type](stage, optimization, code, file_path, arena);
|
||||
}
|
||||
}
|
||||
|
@ -13,29 +13,7 @@ void RegisterCVars(void) {
|
||||
|
||||
static rt_framegraph *_framegraph;
|
||||
|
||||
static void PassPrepare(rt_render_pass_id pass,
|
||||
const rt_render_target_write *writes,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count) {
|
||||
// rtLog("GAME", "Prepare pass %x", pass);
|
||||
}
|
||||
|
||||
static void PassExecute(rt_render_pass_id pass,
|
||||
const rt_render_target_write *writes,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count) {
|
||||
// rtLog("GAME", "Execute pass %x", pass);
|
||||
}
|
||||
|
||||
static void PassFinalize(rt_render_pass_id pass,
|
||||
const rt_render_target_write *writes,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count) {
|
||||
// rtLog("GAME", "Finalize pass %x", pass);
|
||||
}
|
||||
static rt_render_target_handle _rt;
|
||||
|
||||
/* Called after the runtime has finished its initialization and before entering the main-loop*/
|
||||
void Init(void) {
|
||||
@ -44,56 +22,13 @@ void Init(void) {
|
||||
|
||||
rtWaitForAssetProcessing();
|
||||
|
||||
rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
|
||||
|
||||
#if 0
|
||||
rt_resource_id resid = rtGetResourceID("assets/forward.framegraph");
|
||||
size_t size = rtGetResourceSize(resid);
|
||||
rt_resource *res = rtArenaPush(temp.arena, size);
|
||||
rtGetResource(resid, res);
|
||||
|
||||
_framegraph = rtCreateFramegraph(res->data);
|
||||
|
||||
rt_render_pass_bind_fns bind = {.Execute = PassExecute,
|
||||
.Prepare = PassPrepare,
|
||||
.Finalize = PassFinalize};
|
||||
rtBindRenderPass(_framegraph, rtCalculateRenderPassID("forward", sizeof("forward") - 1), &bind);
|
||||
#else
|
||||
rt_resource_id resid = rtGetResourceID("assets/test.framegraph");
|
||||
size_t size = rtGetResourceSize(resid);
|
||||
rt_resource *res = rtArenaPush(temp.arena, size);
|
||||
rtGetResource(resid, res);
|
||||
|
||||
_framegraph = rtCreateFramegraph(res->data);
|
||||
|
||||
rt_render_pass_bind_fns bind = {.Execute = PassExecute,
|
||||
.Prepare = PassPrepare,
|
||||
.Finalize = PassFinalize};
|
||||
rtBindRenderPass(_framegraph, rtCalculateRenderPassID("pass0", sizeof("pass0") - 1), &bind);
|
||||
rtBindRenderPass(_framegraph, rtCalculateRenderPassID("pass1", sizeof("pass1") - 1), &bind);
|
||||
|
||||
rt_v2 vertices[] = {
|
||||
{ 0, 0.5},
|
||||
{ 0.5, -0.5},
|
||||
{-0.5, -0.5}
|
||||
};
|
||||
rt_buffer_info info = {
|
||||
.type = RT_BUFFER_TYPE_VERTEX,
|
||||
.usage = RT_BUFFER_USAGE_STATIC,
|
||||
.size = sizeof(vertices),
|
||||
.data = vertices,
|
||||
};
|
||||
rt_buffer_handle buf;
|
||||
g_renderer.CreateBuffers(1, &info, &buf);
|
||||
|
||||
#endif
|
||||
_rt = g_renderer.GetSwapchainRenderTarget();
|
||||
}
|
||||
|
||||
/* Called after exiting the main-loop and before the runtime starts its shutdown */
|
||||
void Shutdown(void) {
|
||||
rtLog("GAME", "Shutdown");
|
||||
rtShutdownAssetCompiler();
|
||||
rtDestroyFramegraph(_framegraph);
|
||||
}
|
||||
|
||||
void Update(unsigned int frame_id) {
|
||||
@ -101,5 +36,20 @@ void Update(unsigned int frame_id) {
|
||||
}
|
||||
|
||||
void Render(unsigned int frame_id) {
|
||||
rtExecuteFramegraph(_framegraph, frame_id);
|
||||
rt_alloc_command_buffer_info info = {RT_GRAPHICS_QUEUE};
|
||||
rt_command_buffer_handle cmd;
|
||||
g_renderer.AllocCommandBuffers(1, &info, &cmd);
|
||||
|
||||
rt_cmd_begin_pass_info pass_info = {
|
||||
.color_buffer_count = 1,
|
||||
.color_buffers = {_rt},
|
||||
.color_buffer_loads = {RT_PASS_LOAD_MODE_CLEAR},
|
||||
.color_buffer_clear_values = {{.color = {1.f, 0.f, 0.f, 1.f}}},
|
||||
.name = "testme",
|
||||
};
|
||||
g_renderer.CmdBeginPass(cmd, &pass_info);
|
||||
g_renderer.CmdEndPass(cmd);
|
||||
|
||||
rt_submit_command_buffers_info submit = {.command_buffer_count = 1, .command_buffers = &cmd};
|
||||
g_renderer.SubmitCommandBuffers(RT_GRAPHICS_QUEUE, &submit);
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -25,7 +25,7 @@ static bool _renderer_loaded = false;
|
||||
RT_DLLEXPORT
|
||||
RT_CVAR_S(rt_Renderer,
|
||||
"Select the render backend. Available options: [vk, null], Default: vk",
|
||||
"vk");
|
||||
"dx11");
|
||||
|
||||
#ifdef RT_STATIC_LIB
|
||||
extern void RT_RENDERER_API_FN(RegisterCVars)(void);
|
||||
|
@ -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) \
|
||||
@ -87,6 +87,7 @@ typedef struct {
|
||||
typedef enum {
|
||||
RT_SHADER_TYPE_INVALID,
|
||||
RT_SHADER_TYPE_VULKAN,
|
||||
RT_SHADER_TYPE_DX11,
|
||||
|
||||
RT_SHADER_TYPE_count,
|
||||
} rt_shader_type;
|
||||
|
@ -6,3 +6,4 @@ subdir('app_framework')
|
||||
# Renderer libs
|
||||
subdir('renderer/vk')
|
||||
subdir('renderer/null')
|
||||
subdir('renderer/dx11')
|
||||
|
146
src/renderer/dx11/buffers.cpp
Normal file
146
src/renderer/dx11/buffers.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
#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_Dx11MaxBuffers,
|
||||
"Maximum number of simultaneously existing buffers. Default: 4096",
|
||||
4096);
|
||||
|
||||
static rt_buffer *_buffers;
|
||||
static rt_buffer *_first_free;
|
||||
static rt_mutex *_lock;
|
||||
|
||||
rt_result InitBufferManagement() {
|
||||
_buffers =
|
||||
reinterpret_cast<rt_buffer *>(calloc((size_t)rt_Dx11MaxBuffers.i, sizeof(rt_buffer)));
|
||||
if (!_buffers) {
|
||||
return RT_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
_lock = rtCreateMutex();
|
||||
if (!_lock) {
|
||||
free(_buffers);
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
_first_free = _buffers + 2;
|
||||
for (int i = 0; i < rt_Dx11MaxBuffers.i; ++i) {
|
||||
_buffers[i].next_free = &_buffers[i + 1];
|
||||
}
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
void ShutdownBufferManagement() {
|
||||
for (int i = 0; i < rt_Dx11MaxBuffers.i; ++i) {
|
||||
if (_buffers[i].buffer)
|
||||
_buffers[i].buffer->Release();
|
||||
}
|
||||
free(_buffers);
|
||||
rtDestroyMutex(_lock);
|
||||
}
|
||||
|
||||
rt_buffer *rtGetBuffer(rt_buffer_handle handle) {
|
||||
if (!RT_IS_HANDLE_VALID(handle) || (int)handle.index >= rt_Dx11MaxBuffers.i)
|
||||
return nullptr;
|
||||
auto lg = rtAutoLock(_lock);
|
||||
if (handle.version != _buffers[handle.index].version)
|
||||
return nullptr;
|
||||
return &_buffers[handle.index];
|
||||
}
|
||||
|
||||
extern "C" rt_result RT_RENDERER_API_FN(CreateBuffers)(uint32_t count,
|
||||
const rt_buffer_info *info,
|
||||
rt_buffer_handle *p_buffers) {
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
rtLockMutex(_lock);
|
||||
rt_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_buffer *s = &_buffers[p_buffers[j].index];
|
||||
s->next_free = _first_free;
|
||||
_first_free = s;
|
||||
_first_free = s;
|
||||
}
|
||||
rtUnlockMutex(_lock);
|
||||
return RT_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
|
||||
if (info[i].usage == RT_BUFFER_USAGE_STATIC) {
|
||||
usage = D3D11_USAGE_IMMUTABLE;
|
||||
} else if (info[i].usage == RT_BUFFER_USAGE_DYNAMIC) {
|
||||
usage = D3D11_USAGE_DEFAULT;
|
||||
} else if (info[i].usage == RT_BUFFER_USAGE_TRANSIENT) {
|
||||
usage = D3D11_USAGE_DYNAMIC;
|
||||
}
|
||||
|
||||
UINT bind_flags = D3D11_BIND_UNORDERED_ACCESS;
|
||||
if (info[i].type == RT_BUFFER_TYPE_VERTEX)
|
||||
bind_flags = D3D11_BIND_VERTEX_BUFFER;
|
||||
else if (info[i].type == RT_BUFFER_TYPE_INDEX)
|
||||
bind_flags = D3D11_BIND_INDEX_BUFFER;
|
||||
else if (info[i].type == RT_BUFFER_TYPE_UNIFORM)
|
||||
bind_flags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
else if (info[i].type == RT_BUFFER_TYPE_STORAGE)
|
||||
bind_flags = D3D11_BIND_UNORDERED_ACCESS;
|
||||
|
||||
|
||||
D3D11_BUFFER_DESC desc = {};
|
||||
desc.ByteWidth = static_cast<UINT>(((info[i].size + 15) / 16) * 16);
|
||||
desc.Usage = usage;
|
||||
desc.BindFlags = bind_flags;
|
||||
desc.CPUAccessFlags = 0;
|
||||
desc.MiscFlags = 0;
|
||||
desc.StructureByteStride = 1;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA data;
|
||||
data.pSysMem = info->data;
|
||||
data.SysMemPitch = 0;
|
||||
data.SysMemSlicePitch = 0;
|
||||
|
||||
if (FAILED(
|
||||
g_gpu.device->CreateBuffer(&desc, info[i].data ? &data : nullptr, &slot->buffer))) {
|
||||
rtLog("dx11", "Failed to create a deferred context.");
|
||||
auto lock_guard = rtAutoLock(_lock);
|
||||
for (uint32_t j = 0; j < i; ++j) {
|
||||
rt_buffer *s = &_buffers[p_buffers[j].index];
|
||||
s->next_free = _first_free;
|
||||
_first_free = s;
|
||||
}
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
slot->version = (slot->version + 1) % RT_RENDER_BACKEND_HANDLE_MAX_VERSION;
|
||||
const uint32_t index = (uint32_t)(slot - _buffers);
|
||||
p_buffers[i].version = slot->version;
|
||||
p_buffers[i].index = index;
|
||||
}
|
||||
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C" void RT_RENDERER_API_FN(DestroyBuffers)(uint32_t count, rt_buffer_handle *buffers) {
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (!RT_IS_HANDLE_VALID(buffers[i]) || (int)buffers[i].index >= rt_Dx11MaxBuffers.i)
|
||||
continue;
|
||||
auto lg = rtAutoLock(_lock);
|
||||
if (buffers[i].version != _buffers[buffers[i].index].version)
|
||||
continue;
|
||||
_buffers[buffers[i].index].buffer->Release();
|
||||
_buffers[buffers[i].index].next_free = _first_free;
|
||||
_first_free = &_buffers[buffers[i].index];
|
||||
}
|
||||
}
|
140
src/renderer/dx11/command_buffers.cpp
Normal file
140
src/renderer/dx11/command_buffers.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#include <d3d11.h>
|
||||
#include <d3d11_1.h>
|
||||
|
||||
#include "gfx/renderer_api.h"
|
||||
#include "runtime/config.h"
|
||||
#include "runtime/handles.h"
|
||||
#include "runtime/threading.h"
|
||||
#include "runtime/threading_helpers.hpp"
|
||||
|
||||
#include "device_objects.hpp"
|
||||
#include "gpu.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;
|
||||
}
|
||||
|
||||
#ifdef RT_DEBUG
|
||||
if (FAILED(slot->context->QueryInterface(IID_PPV_ARGS(&slot->annotation)))) {
|
||||
rtLog("dx11", "Failed to retrieve the annotation interface.");
|
||||
slot->annotation = nullptr;
|
||||
}
|
||||
#endif
|
||||
} 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];
|
||||
}
|
87
src/renderer/dx11/commands.cpp
Normal file
87
src/renderer/dx11/commands.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include <d3d11.h>
|
||||
#include <d3d11_1.h>
|
||||
|
||||
#include "gfx/renderer_api.h"
|
||||
|
||||
#include "device_objects.hpp"
|
||||
#include "gpu.hpp"
|
||||
|
||||
extern "C" void RT_RENDERER_API_FN(CmdBeginPass)(rt_command_buffer_handle cmdhandle,
|
||||
const rt_cmd_begin_pass_info *info) {
|
||||
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
|
||||
if (!RT_VERIFY(cmd))
|
||||
return;
|
||||
|
||||
if (cmd->annotation) {
|
||||
WCHAR wname[128];
|
||||
if (rtUTF8ToWStr(info->name, wname, sizeof(wname)) == RT_SUCCESS)
|
||||
cmd->annotation->BeginEvent(wname);
|
||||
}
|
||||
|
||||
// Setup rtvs
|
||||
ID3D11RenderTargetView *rtvs[4];
|
||||
ID3D11DepthStencilView *dsv = nullptr;
|
||||
|
||||
for (uint32_t i = 0; i < info->color_buffer_count; ++i) {
|
||||
rt_render_target *rt = rtGetRenderTarget(info->color_buffers[i]);
|
||||
if (!RT_VERIFY(rt))
|
||||
return;
|
||||
RT_ASSERT(rt->IsColorRenderTarget(), "Needs to provide a valid color render target");
|
||||
rtvs[i] = rt->rtv;
|
||||
|
||||
if (info->color_buffer_loads[i] == RT_PASS_LOAD_MODE_CLEAR) {
|
||||
FLOAT color[4] = {
|
||||
info->color_buffer_clear_values[i].color.r,
|
||||
info->color_buffer_clear_values[i].color.g,
|
||||
info->color_buffer_clear_values[i].color.b,
|
||||
info->color_buffer_clear_values[i].color.a,
|
||||
};
|
||||
cmd->context->ClearRenderTargetView(rt->rtv, color);
|
||||
}
|
||||
}
|
||||
|
||||
rt_render_target *dsvrt = rtGetRenderTarget(info->depth_stencil_buffer);
|
||||
if (dsvrt) {
|
||||
RT_ASSERT(dsvrt->IsDepthStencilTarget(),
|
||||
"Need to provide a valid depth stencil render target");
|
||||
dsv = dsvrt->dsv;
|
||||
|
||||
if (info->depth_stencil_buffer_load == RT_PASS_LOAD_MODE_CLEAR)
|
||||
cmd->context->ClearDepthStencilView(
|
||||
dsv,
|
||||
(dsvrt->HasStencilComponent()) ? D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL
|
||||
: D3D11_CLEAR_DEPTH,
|
||||
info->depth_stencil_buffer_clear_value.depth_stencil.depth,
|
||||
static_cast<UINT8>(info->depth_stencil_buffer_clear_value.depth_stencil.stencil));
|
||||
}
|
||||
|
||||
cmd->context->OMSetRenderTargets(static_cast<UINT>(info->color_buffer_count), rtvs, dsv);
|
||||
}
|
||||
|
||||
extern "C" void RT_RENDERER_API_FN(CmdEndPass)(rt_command_buffer_handle cmdhandle) {
|
||||
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
|
||||
if (!RT_VERIFY(cmd))
|
||||
return;
|
||||
if (cmd->annotation) {
|
||||
cmd->annotation->EndEvent();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void RT_RENDERER_API_FN(CmdTransitionRenderTarget)(rt_command_buffer_handle cmdhandle,
|
||||
rt_render_target_handle target,
|
||||
rt_render_target_state state) {
|
||||
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
|
||||
if (!RT_VERIFY(cmd))
|
||||
return;
|
||||
RT_UNUSED(target);
|
||||
RT_UNUSED(state);
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
RT_RENDERER_API_FN(CmdFlushRenderTargetWrite)(rt_command_buffer_handle cmdhandle,
|
||||
rt_render_target_handle render_target) {
|
||||
rt_command_buffer *cmd = rtGetCommandBuffer(cmdhandle);
|
||||
if (!RT_VERIFY(cmd))
|
||||
return;
|
||||
RT_UNUSED(render_target);
|
||||
}
|
81
src/renderer/dx11/device_objects.hpp
Normal file
81
src/renderer/dx11/device_objects.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
#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;
|
||||
|
||||
rt_pixel_format format;
|
||||
|
||||
uint32_t version;
|
||||
rt_render_target *next_free;
|
||||
|
||||
RT_INLINE bool HasStencilComponent() const {
|
||||
return format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8;
|
||||
}
|
||||
|
||||
RT_INLINE 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;
|
||||
}
|
||||
|
||||
RT_INLINE 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;
|
||||
}
|
||||
};
|
||||
|
||||
struct rt_command_buffer {
|
||||
// Only created once and then re-used.
|
||||
ID3D11DeviceContext1 *context;
|
||||
ID3DUserDefinedAnnotation *annotation;
|
||||
|
||||
uint32_t version;
|
||||
rt_command_buffer *next_free;
|
||||
};
|
||||
|
||||
struct rt_buffer {
|
||||
ID3D11Buffer *buffer;
|
||||
rt_buffer_type type;
|
||||
rt_buffer_usage usage;
|
||||
|
||||
uint32_t version;
|
||||
rt_buffer *next_free;
|
||||
};
|
||||
|
||||
struct rt_pipeline {
|
||||
ID3D11InputLayout *input_layout;
|
||||
ID3D11VertexShader *vertex_shader;
|
||||
ID3D11PixelShader *pixel_shader;
|
||||
|
||||
ID3D11ComputeShader *compute_shader;
|
||||
|
||||
|
||||
rt_pipeline *next_free;
|
||||
uint32_t version;
|
||||
|
||||
RT_INLINE bool IsComputePipeline() const {
|
||||
RT_ASSERT(!(compute_shader && (vertex_shader || pixel_shader)),
|
||||
"A pipeline should contain either a compute shader or graphics shaders.");
|
||||
return compute_shader != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
rt_render_target *rtGetRenderTarget(rt_render_target_handle handle);
|
||||
rt_command_buffer *rtGetCommandBuffer(rt_command_buffer_handle handle);
|
||||
rt_buffer *rtGetBuffer(rt_buffer_handle handle);
|
||||
rt_pipeline *rtGetPipeline(rt_pipeline_handle handle);
|
||||
|
||||
#endif
|
41
src/renderer/dx11/gpu.hpp
Normal file
41
src/renderer/dx11/gpu.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
#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>;
|
||||
|
||||
struct rt_swap_chain {
|
||||
ComPtr<IDXGISwapChain1> swap_chain;
|
||||
ComPtr<ID3D11RenderTargetView> rtv;
|
||||
};
|
||||
|
||||
|
||||
struct rt_gpu {
|
||||
ComPtr<ID3D11Device1> device;
|
||||
ComPtr<ID3D11DeviceContext1> device_context;
|
||||
ComPtr<IDXGIFactory2> dxgi_factory;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
283
src/renderer/dx11/init.cpp
Normal file
283
src/renderer/dx11/init.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
#ifndef _WIN32
|
||||
#pragma warning Building DX11 on non - windows is probably a mistake
|
||||
#endif
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_3.h>
|
||||
#include <wrl.h>
|
||||
|
||||
#include "gfx/renderer_api.h"
|
||||
#include "runtime/config.h"
|
||||
|
||||
#define DONT_DEFINE_RENDERER_GLOBAL
|
||||
#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.Height = 0; // use window height
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // can't specify _SRGB here when using
|
||||
// DXGI_SWAP_EFFECT_FLIP_* ...;
|
||||
desc.Stereo = FALSE;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
desc.BufferCount = 2;
|
||||
desc.Scaling = DXGI_SCALING_STRETCH;
|
||||
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
||||
desc.Flags = 0;
|
||||
|
||||
if (FAILED(g_gpu.dxgi_factory->CreateSwapChainForHwnd(g_gpu.device.Get(),
|
||||
hwnd,
|
||||
&desc,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&swc.swap_chain))) {
|
||||
rtReportError("dx11", "Failed to create the swap chain.");
|
||||
return swc;
|
||||
}
|
||||
|
||||
ID3D11Texture2D *frame_buffer;
|
||||
if (FAILED(swc.swap_chain->GetBuffer(0, IID_PPV_ARGS(&frame_buffer)))) {
|
||||
rtReportError("dx11", "Failed to retrieve the backbuffer.");
|
||||
swc.swap_chain.Reset();
|
||||
return swc;
|
||||
}
|
||||
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {};
|
||||
rtv_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
|
||||
rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
|
||||
if (FAILED(g_gpu.device->CreateRenderTargetView(frame_buffer, &rtv_desc, &swc.rtv))) {
|
||||
rtReportError("dx11", "Failed to create the render target view for the backbuffer.");
|
||||
swc.swap_chain.Reset();
|
||||
return swc;
|
||||
}
|
||||
|
||||
return swc;
|
||||
}
|
||||
|
||||
static IDXGIAdapter *RetrieveSelectedAdapter(void) {
|
||||
ComPtr<IDXGIFactory2> factory;
|
||||
if (FAILED(CreateDXGIFactory2(0, IID_PPV_ARGS(&factory)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UINT i = 0;
|
||||
IDXGIAdapter *adapter;
|
||||
while (factory->EnumAdapters(i, &adapter) == S_OK) {
|
||||
++i;
|
||||
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
adapter->GetDesc(&desc);
|
||||
|
||||
char utf8_desc[256];
|
||||
rtWStrToUTF8(desc.Description, utf8_desc, 256);
|
||||
|
||||
if (strncmp(utf8_desc, rt_Dx11AdapterName.s, 256) == 0)
|
||||
return adapter;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern rt_result InitCommandBufferManagement();
|
||||
extern void ShutdownCommandBufferManagement();
|
||||
extern rt_result InitRenderTargetManagement();
|
||||
extern void ShutdownRenderTargetManagement();
|
||||
extern rt_result InitBufferManagement();
|
||||
extern void ShutdownBufferManagement();
|
||||
|
||||
extern "C" rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *info) {
|
||||
constexpr D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0};
|
||||
UINT device_flags = 0;
|
||||
#ifdef RT_DEBUG
|
||||
device_flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
#endif
|
||||
|
||||
IDXGIAdapter *selected_adapter = RetrieveSelectedAdapter();
|
||||
|
||||
ID3D11Device *base_device;
|
||||
ID3D11DeviceContext *base_context;
|
||||
if (FAILED(D3D11CreateDevice(selected_adapter,
|
||||
D3D_DRIVER_TYPE_HARDWARE,
|
||||
nullptr,
|
||||
device_flags,
|
||||
feature_levels,
|
||||
RT_ARRAY_COUNT(feature_levels),
|
||||
D3D11_SDK_VERSION,
|
||||
&base_device,
|
||||
&g_gpu.feature_level,
|
||||
&base_context))) {
|
||||
rtLog("dx11", "Feature level 11.1 creation failed, retrying with feature level 11.0");
|
||||
if (FAILED(D3D11CreateDevice(selected_adapter,
|
||||
D3D_DRIVER_TYPE_HARDWARE,
|
||||
nullptr,
|
||||
device_flags,
|
||||
&feature_levels[1],
|
||||
RT_ARRAY_COUNT(feature_levels) - 1,
|
||||
D3D11_SDK_VERSION,
|
||||
&base_device,
|
||||
&g_gpu.feature_level,
|
||||
&base_context))) {
|
||||
rtReportError("dx11", "Failed to create the d3d11 device.");
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(base_device->QueryInterface(IID_PPV_ARGS(&g_gpu.device)))) {
|
||||
rtReportError("dx11", "Failed to query the D3D11Device1 interface.");
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
if (FAILED(base_context->QueryInterface(IID_PPV_ARGS(&g_gpu.device_context)))) {
|
||||
rtReportError("dx11", "Failed to query the D3D11DeviceContext1 interface.");
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
IDXGIDevice1 *dxgi_device;
|
||||
if (FAILED(g_gpu.device->QueryInterface(&dxgi_device))) {
|
||||
rtReportError("dx11", "Failed to query the DXGIDevice1 interface.");
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
IDXGIAdapter *adapter;
|
||||
if (FAILED(dxgi_device->GetAdapter(&adapter))) {
|
||||
rtReportError("dx11", "Failed to retrieve the dxgi adapter.");
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
if (FAILED(adapter->GetParent(IID_PPV_ARGS(&g_gpu.dxgi_factory)))) {
|
||||
rtReportError("dx11", "Failed to retrieve the dxgi factory.");
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
g_gpu.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;
|
||||
res = InitBufferManagement();
|
||||
if (res != RT_SUCCESS)
|
||||
return res;
|
||||
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C" void RT_RENDERER_API_FN(Shutdown)(void) {
|
||||
ShutdownBufferManagement();
|
||||
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) {
|
||||
RT_UNUSED(frame_id);
|
||||
FLOAT clear_color[4] = {
|
||||
0,
|
||||
0,
|
||||
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
|
||||
|
||||
extern "C" {
|
||||
|
||||
#define RETURN_HANDLE_STUB2(type, initial) \
|
||||
static unsigned int s_next = (initial); \
|
||||
s_next = (s_next + 1) % RT_RENDER_BACKEND_HANDLE_MAX_INDEX; \
|
||||
type h = { \
|
||||
1, \
|
||||
s_next, \
|
||||
}; \
|
||||
return h;
|
||||
|
||||
#define RETURN_HANDLE_STUB(type) RETURN_HANDLE_STUB2(type, 1)
|
||||
|
||||
#define RETURN_HANDLE_ARRAY_STUB2(out, count, initial) \
|
||||
static unsigned int s_next = (initial); \
|
||||
for (uint32_t i = 0; i < (count); ++i) { \
|
||||
(out)[i].index = (s_next++) % RT_RENDER_BACKEND_HANDLE_MAX_INDEX; \
|
||||
(out)[i].version = 1; \
|
||||
}
|
||||
|
||||
#define RETURN_HANDLE_ARRAY_STUB(out, count) RETURN_HANDLE_ARRAY_STUB2(out, count, 1)
|
||||
|
||||
rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count,
|
||||
const rt_gpu_semaphore_info *info,
|
||||
rt_gpu_semaphore_handle *p_semaphores) {
|
||||
RT_UNUSED(info);
|
||||
RETURN_HANDLE_ARRAY_STUB2(p_semaphores, count, 3)
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(DestroySemaphores)(uint32_t count, rt_gpu_semaphore_handle *semaphores) {
|
||||
RT_UNUSED(count);
|
||||
RT_UNUSED(semaphores);
|
||||
}
|
||||
|
||||
/* NOTE(Kevin): It might become necessary to actually track the value, to correctly simulate gpu
|
||||
* behaviour */
|
||||
uint64_t RT_RENDERER_API_FN(GetSemaphoreValue)(rt_gpu_semaphore_handle sem) {
|
||||
RT_UNUSED(sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetSwapchainAvailableSemaphore)(void) {
|
||||
return {1, 1};
|
||||
}
|
||||
|
||||
rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetRenderFinishedSemaphore)(void) {
|
||||
return {1, 2};
|
||||
}
|
||||
}
|
25
src/renderer/dx11/meson.build
Normal file
25
src/renderer/dx11/meson.build
Normal file
@ -0,0 +1,25 @@
|
||||
if get_option('build_dx11')
|
||||
dx11_dep = declare_dependency(link_args: ['-ld3d11', '-ldxgi', '-lwinmm', '-ldxguid'])
|
||||
|
||||
dx11_renderer_lib = library('rtdx11',
|
||||
# Project Sources
|
||||
'device_objects.hpp',
|
||||
'gpu.hpp',
|
||||
|
||||
'buffers.cpp',
|
||||
'commands.cpp',
|
||||
'command_buffers.cpp',
|
||||
'helpers.cpp',
|
||||
'init.cpp',
|
||||
'render_targets.cpp',
|
||||
|
||||
dependencies : [m_dep, windowing_dep, dx11_dep],
|
||||
include_directories : [engine_incdir, contrib_incdir],
|
||||
link_with : [runtime_lib],
|
||||
cpp_pch : 'pch/dx11_pch.h',
|
||||
override_options : ['b_sanitize=none'],
|
||||
install : true)
|
||||
|
||||
engine_libs += dx11_renderer_lib
|
||||
engine_lib_paths += dx11_renderer_lib.full_path()
|
||||
endif
|
5
src/renderer/dx11/pch/dx11_pch.h
Normal file
5
src/renderer/dx11/pch/dx11_pch.h
Normal file
@ -0,0 +1,5 @@
|
||||
// DX11 headers
|
||||
#include <wrl.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3d11_1.h>
|
||||
#include <dxgi1_3.h>
|
217
src/renderer/dx11/pipelines.cpp
Normal file
217
src/renderer/dx11/pipelines.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
#include <d3d11.h>
|
||||
#include <d3d11_1.h>
|
||||
|
||||
#include "gfx/effect.h"
|
||||
#include "gfx/renderer_api.h"
|
||||
#include "runtime/config.h"
|
||||
#include "runtime/handles.h"
|
||||
#include "runtime/mem_arena.h"
|
||||
#include "runtime/threading_helpers.hpp"
|
||||
|
||||
#include "device_objects.hpp"
|
||||
#include "gpu.hpp"
|
||||
|
||||
RT_CVAR_I(rt_Dx11MaxPipelines,
|
||||
"Maximum number of simultaneously existing pipelines. Default: 128",
|
||||
128);
|
||||
|
||||
static rt_pipeline *_pipelines;
|
||||
static rt_pipeline *_first_free;
|
||||
static rt_mutex *_lock;
|
||||
|
||||
rt_result InitPipelineManagement() {
|
||||
_pipelines =
|
||||
reinterpret_cast<rt_pipeline *>(calloc((size_t)rt_Dx11MaxPipelines.i, sizeof(rt_pipeline)));
|
||||
if (!_pipelines)
|
||||
return RT_OUT_OF_MEMORY;
|
||||
|
||||
_first_free = _pipelines + 1;
|
||||
for (int i = 0; i < rt_Dx11MaxPipelines.i - 1; ++i)
|
||||
_pipelines[i].next_free = &_pipelines[i + 1];
|
||||
|
||||
_lock = rtCreateMutex();
|
||||
if (!_lock) {
|
||||
free(_pipelines);
|
||||
return RT_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
void ShutdownPipelineManagement() {
|
||||
for (int i = 0; i < rt_Dx11MaxPipelines.i; ++i) {
|
||||
if (_pipelines[i].compute_shader)
|
||||
_pipelines[i].compute_shader->Release();
|
||||
if (_pipelines[i].vertex_shader)
|
||||
_pipelines[i].vertex_shader->Release();
|
||||
if (_pipelines[i].pixel_shader)
|
||||
_pipelines[i].pixel_shader->Release();
|
||||
if (_pipelines[i].input_layout)
|
||||
_pipelines[i].input_layout->Release();
|
||||
}
|
||||
free(_pipelines);
|
||||
rtDestroyMutex(_lock);
|
||||
}
|
||||
|
||||
rt_result GetShader(rt_resource_id id, rt_shader_info **p_shader, rt_arena *arena) {
|
||||
size_t shader_size = rtGetResourceSize(id);
|
||||
if (shader_size == 0)
|
||||
return RT_INVALID_VALUE;
|
||||
void *buffer = rtArenaPush(arena, shader_size);
|
||||
if (!buffer)
|
||||
return RT_OUT_OF_MEMORY;
|
||||
rt_result res = rtGetResource(id, buffer);
|
||||
if (res != RT_SUCCESS) {
|
||||
rtArenaPop(arena, shader_size);
|
||||
return res;
|
||||
}
|
||||
|
||||
rt_resource *resource = reinterpret_cast<rt_resource *>(buffer);
|
||||
RT_ASSERT(resource->type == RT_RESOURCE_SHADER, "Expected a shader");
|
||||
*p_shader = reinterpret_cast<rt_shader_info *>(resource->data);
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C" rt_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_info *info) {
|
||||
rt_pipeline *slot = nullptr;
|
||||
{
|
||||
auto lg = rtAutoLock(_lock);
|
||||
|
||||
slot = _first_free;
|
||||
if (slot)
|
||||
_first_free = slot->next_free;
|
||||
}
|
||||
if (!slot) {
|
||||
rtLog("dx11", "Could not create pipeline, because no slots are available.");
|
||||
return RT_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
|
||||
|
||||
if (info->vertex_shader != RT_INVALID_RESOURCE_ID) {
|
||||
rt_shader_info *vs;
|
||||
if (GetShader(info->vertex_shader, &vs, temp.arena) != RT_SUCCESS) {
|
||||
rtReportError("dx11", "Could not retrieve vertex shader data.");
|
||||
auto lg = rtAutoLock(_lock);
|
||||
slot->next_free = _first_free;
|
||||
_first_free = slot;
|
||||
return RT_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
void *bytecode = rtResolveRelptr(&vs->bytecode);
|
||||
if (FAILED(g_gpu.device->CreateVertexShader(bytecode,
|
||||
vs->bytecode_length,
|
||||
NULL,
|
||||
&slot->vertex_shader))) {
|
||||
rtReportError("dx11", "Vertex shader creation failed");
|
||||
auto lg = rtAutoLock(_lock);
|
||||
slot->next_free = _first_free;
|
||||
_first_free = slot;
|
||||
return RT_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
// TODO: effects should specify the expected vertex layout
|
||||
// For now, we use a default
|
||||
/* clang-format off */
|
||||
D3D11_INPUT_ELEMENT_DESC default_layout[] = {
|
||||
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{"TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
if (FAILED(g_gpu.device->CreateInputLayout(default_layout,
|
||||
RT_ARRAY_COUNT(default_layout),
|
||||
bytecode,
|
||||
vs->bytecode_length,
|
||||
&slot->input_layout))) {
|
||||
rtReportError("dx11", "Failed to create the vertex layout.");
|
||||
auto lg = rtAutoLock(_lock);
|
||||
slot->next_free = _first_free;
|
||||
_first_free = slot;
|
||||
return RT_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->fragment_shader != RT_INVALID_RESOURCE_ID) {
|
||||
rt_shader_info *vs;
|
||||
if (GetShader(info->fragment_shader, &vs, temp.arena) != RT_SUCCESS) {
|
||||
rtReportError("dx11", "Could not retrieve fragment shader data.");
|
||||
auto lg = rtAutoLock(_lock);
|
||||
slot->next_free = _first_free;
|
||||
_first_free = slot;
|
||||
return RT_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
void *bytecode = rtResolveRelptr(&vs->bytecode);
|
||||
if (FAILED(g_gpu.device->CreatePixelShader(bytecode,
|
||||
vs->bytecode_length,
|
||||
NULL,
|
||||
&slot->pixel_shader))) {
|
||||
rtReportError("dx11", "Fragment shader creation failed");
|
||||
auto lg = rtAutoLock(_lock);
|
||||
slot->next_free = _first_free;
|
||||
_first_free = slot;
|
||||
return RT_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->compute_shader != RT_INVALID_RESOURCE_ID) {
|
||||
rt_shader_info *vs;
|
||||
if (GetShader(info->compute_shader, &vs, temp.arena) != RT_SUCCESS) {
|
||||
rtReportError("dx11", "Could not retrieve compute shader data.");
|
||||
auto lg = rtAutoLock(_lock);
|
||||
slot->next_free = _first_free;
|
||||
_first_free = slot;
|
||||
return RT_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
void *bytecode = rtResolveRelptr(&vs->bytecode);
|
||||
if (FAILED(g_gpu.device->CreateComputeShader(bytecode,
|
||||
vs->bytecode_length,
|
||||
NULL,
|
||||
&slot->compute_shader))) {
|
||||
rtReportError("dx11", "Compute shader creation failed");
|
||||
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 - _pipelines);
|
||||
return {slot->version, index};
|
||||
}
|
||||
|
||||
extern "C" void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle handle) {
|
||||
if (!RT_IS_HANDLE_VALID(handle) || (int)handle.index >= rt_Dx11MaxPipelines.i)
|
||||
return;
|
||||
auto lg = rtAutoLock(_lock);
|
||||
if (handle.version != _pipelines[handle.index].version)
|
||||
return;
|
||||
|
||||
if (_pipelines[handle.index].compute_shader)
|
||||
_pipelines[handle.index].compute_shader->Release();
|
||||
if (_pipelines[handle.index].vertex_shader)
|
||||
_pipelines[handle.index].vertex_shader->Release();
|
||||
if (_pipelines[handle.index].pixel_shader)
|
||||
_pipelines[handle.index].pixel_shader->Release();
|
||||
if (_pipelines[handle.index].input_layout)
|
||||
_pipelines[handle.index].input_layout->Release();
|
||||
|
||||
_pipelines[handle.index].next_free = _first_free;
|
||||
_pipelines[handle.index].version =
|
||||
(_pipelines[handle.index].version + 1) % RT_RENDER_BACKEND_HANDLE_MAX_VERSION;
|
||||
_first_free = &_pipelines[handle.index];
|
||||
}
|
||||
|
||||
rt_pipeline *rtGetPipeline(rt_pipeline_handle handle) {
|
||||
if (!RT_IS_HANDLE_VALID(handle) || (int)handle.index >= rt_Dx11MaxPipelines.i)
|
||||
return nullptr;
|
||||
auto lg = rtAutoLock(_lock);
|
||||
if (handle.version != _pipelines[handle.index].version)
|
||||
return nullptr;
|
||||
return &_pipelines[handle.index];
|
||||
}
|
173
src/renderer/dx11/render_targets.cpp
Normal file
173
src/renderer/dx11/render_targets.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
_render_targets[1].rtv = g_gpu.swap_chain.rtv.Get();
|
||||
_render_targets[1].format = RT_PIXEL_FORMAT_B8G8R8A8_SRGB;
|
||||
_render_targets[1].version = 1;
|
||||
|
||||
_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() {
|
||||
// Swapchain rtv in slot 1 will be released elsewhere
|
||||
for (int i = 2; 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;
|
||||
}
|
||||
|
||||
slot->format = info->format;
|
||||
|
||||
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,18 @@ 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)
|
||||
|
||||
// Asserts if p is "false", evaluates to p
|
||||
// NOTE that this will evaluate p multiple times!
|
||||
#define RT_VERIFY(p) \
|
||||
((!p) ? (RT_DEBUGBREAK, rtAssertHandler(#p, "Verify failed", __FILE__, __LINE__), p) : p)
|
||||
|
||||
#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)
|
||||
#define RT_VERIFY(p) (p)
|
||||
#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