(D3D12) add menu display driver.

This commit is contained in:
aliaspider 2018-02-08 00:17:09 +01:00
parent 92afd7387d
commit 0d88799e6d
8 changed files with 389 additions and 27 deletions

View File

@ -1269,7 +1269,7 @@ endif
ifeq ($(HAVE_D3D12), 1)
OBJ += gfx/drivers/d3d12.o gfx/common/d3d12_common.o \
gfx/drivers_font/d3d12_font.o
gfx/drivers_font/d3d12_font.o menu/drivers_display/menu_display_d3d12.o
DEFINES += -DHAVE_D3D12
endif

View File

@ -55,6 +55,7 @@ HAVE_LANGEXTRA := 1
HAVE_CHEEVOS := 1
HAVE_KEYMAPPER := 1
HAVE_SHADERPIPELINE := 1
HAVE_IMAGEVIEWER := 1
include Makefile.common
INCLUDE_DIRS := $(patsubst -isystem%,-I%,$(INCLUDE_DIRS))

View File

@ -1311,7 +1311,27 @@ typedef struct
bool dirty;
} d3d12_texture_t;
#define TEXTURE_DESC_SLOTS_COUNT 128
#ifndef ALIGN
#ifdef _MSC_VER
#define ALIGN(x) __declspec(align(x))
#else
#define ALIGN(x) __attribute__((aligned(x)))
#endif
#endif
typedef struct ALIGN(16)
{
math_matrix_4x4 mvp;
struct
{
float width;
float height;
} OutputSize;
float time;
} d3d12_uniform_t;
static_assert(
(!(sizeof(d3d12_uniform_t) & 0xF)), "sizeof(d3d12_uniform_t) must be a multiple of 16");
typedef struct
{
@ -1386,6 +1406,7 @@ typedef struct
} sprites;
D3D12PipelineState pipes[GFX_MAX_SHADERS];
d3d12_uniform_t ubo_values;
D3D12Resource ubo;
D3D12_CONSTANT_BUFFER_VIEW_DESC ubo_view;
DXGI_FORMAT format;
@ -1395,6 +1416,8 @@ typedef struct
bool resize_chain;
bool keep_aspect;
bool resize_viewport;
D3D12Resource menu_pipeline_vbo;
D3D12_VERTEX_BUFFER_VIEW menu_pipeline_vbo_view;
#ifdef DEBUG
D3D12Debug debugController;

View File

@ -26,11 +26,13 @@
#include "../common/d3d12_common.h"
#include "../common/d3dcompiler_common.h"
//#include "../../menu/menu_driver.h"
#include "../../menu/menu_driver.h"
#include "../../driver.h"
#include "../../verbosity.h"
#include "../../configuration.h"
#include "wiiu/wiiu_dbg.h"
static void d3d12_set_filtering(void* data, unsigned index, bool smooth)
{
int i;
@ -71,10 +73,10 @@ static void d3d12_update_viewport(void* data, bool force_full)
video_driver_update_viewport(&d3d12->vp, force_full, d3d12->keep_aspect);
d3d12->frame.viewport.TopLeftX = (float)d3d12->vp.x;
d3d12->frame.viewport.TopLeftY = (float)d3d12->vp.y;
d3d12->frame.viewport.Width = (float)d3d12->vp.width;
d3d12->frame.viewport.Height = (float)d3d12->vp.height;
d3d12->frame.viewport.TopLeftX = d3d12->vp.x;
d3d12->frame.viewport.TopLeftY = d3d12->vp.y;
d3d12->frame.viewport.Width = d3d12->vp.width;
d3d12->frame.viewport.Height = d3d12->vp.height;
d3d12->frame.viewport.MaxDepth = 0.0f;
d3d12->frame.viewport.MaxDepth = 1.0f;
@ -160,6 +162,7 @@ static bool d3d12_gfx_init_pipelines(d3d12_video_t* d3d12)
if (!d3d_compile(shader, sizeof(shader), NULL, "GSMain", "gs_5_0", &gs_code))
goto error;
// desc.BlendState.RenderTarget[0].BlendEnable = false;
desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
desc.InputLayout.pInputElementDescs = inputElementDesc;
desc.InputLayout.NumElements = countof(inputElementDesc);
@ -301,9 +304,9 @@ static bool d3d12_gfx_init_pipelines(d3d12_video_t* d3d12)
vs_code = NULL;
ps_code = NULL;
if (!d3d_compile(ribbon_simple, sizeof(ribbon), NULL, "VSMain", "vs_5_0", &vs_code))
if (!d3d_compile(ribbon_simple, sizeof(ribbon_simple), NULL, "VSMain", "vs_5_0", &vs_code))
goto error;
if (!d3d_compile(ribbon_simple, sizeof(ribbon), NULL, "PSMain", "ps_5_0", &ps_code))
if (!d3d_compile(ribbon_simple, sizeof(ribbon_simple), NULL, "PSMain", "ps_5_0", &ps_code))
goto error;
if (!d3d12_init_pipeline(
@ -383,6 +386,8 @@ static void*
d3d12_gfx_init(const video_info_t* video, const input_driver_t** input, void** input_data)
{
WNDCLASSEX wndclass = { 0 };
MONITORINFOEX current_mon;
HMONITOR hm_to_use;
settings_t* settings = config_get_ptr();
d3d12_video_t* d3d12 = (d3d12_video_t*)calloc(1, sizeof(*d3d12));
@ -394,7 +399,17 @@ d3d12_gfx_init(const video_info_t* video, const input_driver_t** input, void** i
wndclass.lpfnWndProc = WndProcD3D;
win32_window_init(&wndclass, true, NULL);
if (!win32_set_video_mode(d3d12, video->width, video->height, video->fullscreen))
win32_monitor_info(&current_mon, &hm_to_use, &d3d12->cur_mon_id);
d3d12->vp.full_width = video->width;
d3d12->vp.full_height = video->height;
if (!d3d12->vp.full_width)
d3d12->vp.full_width = current_mon.rcMonitor.right - current_mon.rcMonitor.left;
if (!d3d12->vp.full_height)
d3d12->vp.full_height = current_mon.rcMonitor.bottom - current_mon.rcMonitor.top;
if (!win32_set_video_mode(d3d12, d3d12->vp.full_width, d3d12->vp.full_height, video->fullscreen))
{
RARCH_ERR("[D3D12]: win32_set_video_mode failed.\n");
goto error;
@ -414,7 +429,7 @@ d3d12_gfx_init(const video_info_t* video, const input_driver_t** input, void** i
if (!d3d12_init_queue(d3d12))
goto error;
if (!d3d12_init_swapchain(d3d12, video->width, video->height, main_window.hwnd))
if (!d3d12_init_swapchain(d3d12, d3d12->vp.full_width, d3d12->vp.full_height, main_window.hwnd))
goto error;
d3d12_init_samplers(d3d12);
@ -429,21 +444,20 @@ d3d12_gfx_init(const video_info_t* video, const input_driver_t** input, void** i
d3d12->sprites.vbo_view.BufferLocation = d3d12_create_buffer(
d3d12->device, d3d12->sprites.vbo_view.SizeInBytes, &d3d12->sprites.vbo);
d3d12->keep_aspect = video->force_aspect;
d3d12->chain.vsync = video->vsync;
d3d12->format = video->rgb32 ? DXGI_FORMAT_B8G8R8X8_UNORM : DXGI_FORMAT_B5G6R5_UNORM;
d3d12->frame.texture.desc.Format = d3d12->format;
d3d12->ubo_view.SizeInBytes = sizeof(math_matrix_4x4);
d3d12->ubo_view.SizeInBytes = sizeof(d3d12_uniform_t);
d3d12->ubo_view.BufferLocation =
d3d12_create_buffer(d3d12->device, d3d12->ubo_view.SizeInBytes, &d3d12->ubo);
d3d12->frame.ubo_view.SizeInBytes = sizeof(math_matrix_4x4);
d3d12->frame.ubo_view.SizeInBytes = sizeof(d3d12_uniform_t);
d3d12->frame.ubo_view.BufferLocation =
d3d12_create_buffer(d3d12->device, d3d12->frame.ubo_view.SizeInBytes, &d3d12->frame.ubo);
matrix_4x4_ortho(d3d12->mvp_no_rot, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
d3d12->ubo_values.mvp = d3d12->mvp_no_rot;
d3d12->ubo_values.OutputSize.width = d3d12->chain.viewport.Width;
d3d12->ubo_values.OutputSize.height = d3d12->chain.viewport.Height;
{
math_matrix_4x4* mvp;
D3D12_RANGE read_range = { 0, 0 };
@ -453,9 +467,14 @@ d3d12_gfx_init(const video_info_t* video, const input_driver_t** input, void** i
}
d3d12_gfx_set_rotation(d3d12, 0);
d3d12->vp.full_width = video->width;
d3d12->vp.full_height = video->height;
d3d12->resize_viewport = true;
video_driver_set_size(&d3d12->vp.full_width, &d3d12->vp.full_height);
d3d12->chain.viewport.Width = d3d12->vp.full_width;
d3d12->chain.viewport.Height = d3d12->vp.full_height;
d3d12->resize_viewport = true;
d3d12->keep_aspect = video->force_aspect;
d3d12->chain.vsync = video->vsync;
d3d12->format = video->rgb32 ? DXGI_FORMAT_B8G8R8X8_UNORM : DXGI_FORMAT_B5G6R5_UNORM;
d3d12->frame.texture.desc.Format = d3d12->format;
font_driver_init_osd(d3d12, false, video->is_threaded, FONT_DRIVER_RENDER_D3D12_API);
@ -496,8 +515,18 @@ static bool d3d12_gfx_frame(
}
d3d12->chain.frame_index = DXGIGetCurrentBackBufferIndex(d3d12->chain.handle);
d3d12->resize_chain = false;
d3d12->resize_viewport = true;
d3d12->chain.viewport.Width = video_info->width;
d3d12->chain.viewport.Height = video_info->height;
d3d12->chain.scissorRect.right = video_info->width;
d3d12->chain.scissorRect.bottom = video_info->height;
d3d12->resize_chain = false;
d3d12->resize_viewport = true;
d3d12->ubo_values.OutputSize.width = d3d12->chain.viewport.Width;
d3d12->ubo_values.OutputSize.height = d3d12->chain.viewport.Height;
video_driver_set_size(&video_info->width, &video_info->height);
}
PERF_START();
@ -578,7 +607,7 @@ static bool d3d12_gfx_frame(
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->sprites.vbo_view);
d3d12->sprites.enabled = true;
#if 0
#if 1
if (d3d12->menu.enabled)
menu_driver_frame(video_info);
#endif
@ -589,7 +618,6 @@ static bool d3d12_gfx_frame(
}
d3d12->sprites.enabled = false;
d3d12_resource_transition(
d3d12->queue.cmd, d3d12->chain.renderTargets[d3d12->chain.frame_index],
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
@ -759,11 +787,64 @@ static void d3d12_gfx_set_osd_msg(
}
}
static uintptr_t d3d12_gfx_load_texture(
void* video_data, void* data, bool threaded, enum texture_filter_type filter_type)
{
d3d12_texture_t* texture = NULL;
d3d12_video_t* d3d12 = (d3d12_video_t*)video_data;
struct texture_image* image = (struct texture_image*)data;
if (!d3d12)
return 0;
texture = (d3d12_texture_t*)calloc(1, sizeof(*texture));
if (!texture)
return 0;
/* todo : mipmapping */
switch (filter_type)
{
case TEXTURE_FILTER_MIPMAP_LINEAR:
/* fallthrough */
case TEXTURE_FILTER_LINEAR:
texture->sampler = d3d12->samplers[RARCH_FILTER_LINEAR][RARCH_WRAP_DEFAULT];
break;
case TEXTURE_FILTER_MIPMAP_NEAREST:
/* fallthrough */
case TEXTURE_FILTER_NEAREST:
texture->sampler = d3d12->samplers[RARCH_FILTER_NEAREST][RARCH_WRAP_DEFAULT];
break;
}
texture->desc.Width = image->width;
texture->desc.Height = image->height;
texture->desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
texture->srv_heap = &d3d12->desc.srv_heap;
d3d12_init_texture(d3d12->device, texture);
d3d12_update_texture(
image->width, image->height, 0, DXGI_FORMAT_B8G8R8A8_UNORM, image->pixels, texture);
return (uintptr_t)texture;
}
static void d3d12_gfx_unload_texture(void* data, uintptr_t handle)
{
d3d12_texture_t* texture = (d3d12_texture_t*)handle;
if (!texture)
return;
d3d12_release_texture(texture);
free(texture);
}
static const video_poke_interface_t d3d12_poke_interface = {
NULL, /* set_coords */
NULL, /* set_mvp */
NULL, /* load_texture */
NULL, /* unload_texture */
d3d12_gfx_load_texture,
d3d12_gfx_unload_texture,
NULL, /* set_video_mode */
d3d12_set_filtering,
NULL, /* get_video_output_size */

View File

@ -1172,6 +1172,10 @@ MENU
#include "../menu/drivers_display/menu_display_d3d11.c"
#endif
#if defined(HAVE_D3D12)
#include "../menu/drivers_display/menu_display_d3d12.c"
#endif
#ifdef HAVE_OPENGL
#include "../menu/drivers_display/menu_display_gl.c"
#endif

View File

@ -0,0 +1,244 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2014-2018 - Ali Bouhlel
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#define CINTERFACE
#include <retro_miscellaneous.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../menu_driver.h"
#include "../../retroarch.h"
#include "../../gfx/font_driver.h"
#include "../../gfx/video_driver.h"
#include "../../gfx/common/d3d12_common.h"
static const float* menu_display_d3d12_get_default_vertices(void) { return NULL; }
static const float* menu_display_d3d12_get_default_tex_coords(void) { return NULL; }
static void* menu_display_d3d12_get_default_mvp(void) { return NULL; }
static void menu_display_d3d12_blend_begin(void)
{
d3d12_video_t* d3d12 = (d3d12_video_t*)video_driver_get_ptr(false);
/*todo: d3d12->sprites.pipe_blend */
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe);
}
static void menu_display_d3d12_blend_end(void)
{
d3d12_video_t* d3d12 = (d3d12_video_t*)video_driver_get_ptr(false);
/*todo: d3d12->sprites.pipe_noblend */
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe);
}
static void menu_display_d3d12_viewport(void* data) {}
static void menu_display_d3d12_draw(void* data)
{
d3d12_video_t* d3d12 = (d3d12_video_t*)video_driver_get_ptr(false);
menu_display_ctx_draw_t* draw = (menu_display_ctx_draw_t*)data;
if (!d3d12 || !draw || !draw->texture)
return;
switch (draw->pipeline.id)
{
case VIDEO_SHADER_MENU:
case VIDEO_SHADER_MENU_2:
case VIDEO_SHADER_MENU_3:
case VIDEO_SHADER_MENU_4:
case VIDEO_SHADER_MENU_5:
case VIDEO_SHADER_MENU_6:
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->pipes[draw->pipeline.id]);
D3D12DrawInstanced(d3d12->queue.cmd, draw->coords->vertices, 1, 0, 0);
D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe);
D3D12IASetPrimitiveTopology(d3d12->queue.cmd, D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->sprites.vbo_view);
return;
}
if (!d3d12->sprites.enabled)
return;
if (d3d12->sprites.offset + 1 > d3d12->sprites.capacity)
d3d12->sprites.offset = 0;
{
d3d12_sprite_t* v;
D3D12_RANGE range = { 0, 0 };
D3D12Map(d3d12->sprites.vbo, 0, &range, (void**)&v);
v += d3d12->sprites.offset;
v->pos.x = draw->x / (float)d3d12->chain.viewport.Width;
v->pos.y = (d3d12->chain.viewport.Height - draw->y - draw->height) /
(float)d3d12->chain.viewport.Height;
v->pos.w = draw->width / (float)d3d12->chain.viewport.Width;
v->pos.h = draw->height / (float)d3d12->chain.viewport.Height;
v->coords.u = 0.0f;
v->coords.v = 0.0f;
v->coords.w = 1.0f;
v->coords.h = 1.0f;
if (draw->scale_factor)
v->params.scaling = draw->scale_factor;
else
v->params.scaling = 1.0f;
v->params.rotation = draw->rotation;
v->colors[3] = DXGI_COLOR_RGBA(
0xFF * draw->coords->color[0], 0xFF * draw->coords->color[1],
0xFF * draw->coords->color[2], 0xFF * draw->coords->color[3]);
v->colors[2] = DXGI_COLOR_RGBA(
0xFF * draw->coords->color[4], 0xFF * draw->coords->color[5],
0xFF * draw->coords->color[6], 0xFF * draw->coords->color[7]);
v->colors[1] = DXGI_COLOR_RGBA(
0xFF * draw->coords->color[8], 0xFF * draw->coords->color[9],
0xFF * draw->coords->color[10], 0xFF * draw->coords->color[12]);
v->colors[0] = DXGI_COLOR_RGBA(
0xFF * draw->coords->color[12], 0xFF * draw->coords->color[13],
0xFF * draw->coords->color[14], 0xFF * draw->coords->color[15]);
range.Begin = d3d12->sprites.offset * sizeof(*v);
range.End = (d3d12->sprites.offset + 1) * sizeof(*v);
D3D12Unmap(d3d12->sprites.vbo, 0, &range);
}
{
d3d12_texture_t* texture = (d3d12_texture_t*)draw->texture;
if (texture->dirty)
d3d12_upload_texture(d3d12->queue.cmd, texture);
d3d12_set_texture_and_sampler(d3d12->queue.cmd, texture);
}
D3D12DrawInstanced(d3d12->queue.cmd, 1, 1, d3d12->sprites.offset, 0);
d3d12->sprites.offset++;
return;
}
static void menu_display_d3d12_draw_pipeline(void* data)
{
menu_display_ctx_draw_t* draw = (menu_display_ctx_draw_t*)data;
d3d12_video_t* d3d12 = (d3d12_video_t*)video_driver_get_ptr(false);
if (!d3d12 || !draw)
return;
switch (draw->pipeline.id)
{
case VIDEO_SHADER_MENU:
case VIDEO_SHADER_MENU_2:
{
video_coord_array_t* ca = menu_display_get_coords_array();
if (!d3d12->menu_pipeline_vbo)
{
void* vertex_data_begin;
D3D12_RANGE read_range = { 0, 0 };
d3d12->menu_pipeline_vbo_view.StrideInBytes = 2 * sizeof(float);
d3d12->menu_pipeline_vbo_view.SizeInBytes =
ca->coords.vertices * d3d12->menu_pipeline_vbo_view.StrideInBytes;
d3d12->menu_pipeline_vbo_view.BufferLocation = d3d12_create_buffer(
d3d12->device, d3d12->menu_pipeline_vbo_view.SizeInBytes,
&d3d12->menu_pipeline_vbo);
D3D12Map(d3d12->menu_pipeline_vbo, 0, &read_range, &vertex_data_begin);
memcpy(vertex_data_begin, ca->coords.vertex, d3d12->menu_pipeline_vbo_view.SizeInBytes);
D3D12Unmap(d3d12->menu_pipeline_vbo, 0, NULL);
}
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->menu_pipeline_vbo_view);
draw->coords->vertices = ca->coords.vertices;
break;
}
case VIDEO_SHADER_MENU_3:
case VIDEO_SHADER_MENU_4:
case VIDEO_SHADER_MENU_5:
case VIDEO_SHADER_MENU_6:
D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->frame.vbo_view);
draw->coords->vertices = 4;
break;
default:
return;
}
D3D12IASetPrimitiveTopology(d3d12->queue.cmd, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
d3d12->ubo_values.time += 0.01f;
{
D3D12_RANGE read_range = { 0, 0 };
d3d12_uniform_t* mapped_ubo;
D3D12Map(d3d12->ubo, 0, &read_range, (void**)&mapped_ubo);
*mapped_ubo = d3d12->ubo_values;
D3D12Unmap(d3d12->ubo, 0, NULL);
}
D3D12SetGraphicsRootConstantBufferView(
d3d12->queue.cmd, ROOT_ID_UBO, d3d12->ubo_view.BufferLocation);
}
static void menu_display_d3d12_restore_clear_color(void) {}
static void menu_display_d3d12_clear_color(menu_display_ctx_clearcolor_t* clearcolor)
{
d3d12_video_t* d3d12 = (d3d12_video_t*)video_driver_get_ptr(false);
if (!d3d12 || !clearcolor)
return;
D3D12ClearRenderTargetView(
d3d12->queue.cmd, d3d12->chain.desc_handles[d3d12->chain.frame_index], (float*)clearcolor,
0, NULL);
}
static bool menu_display_d3d12_font_init_first(
void** font_handle,
void* video_data,
const char* font_path,
float font_size,
bool is_threaded)
{
font_data_t** handle = (font_data_t**)font_handle;
font_data_t* new_handle = font_driver_init_first(
video_data, font_path, font_size, true, is_threaded, FONT_DRIVER_RENDER_D3D12_API);
if (!new_handle)
return false;
*handle = new_handle;
return true;
}
menu_display_ctx_driver_t menu_display_ctx_d3d12 = {
menu_display_d3d12_draw,
menu_display_d3d12_draw_pipeline,
menu_display_d3d12_viewport,
menu_display_d3d12_blend_begin,
menu_display_d3d12_blend_end,
menu_display_d3d12_restore_clear_color,
menu_display_d3d12_clear_color,
menu_display_d3d12_get_default_mvp,
menu_display_d3d12_get_default_vertices,
menu_display_d3d12_get_default_tex_coords,
menu_display_d3d12_font_init_first,
MENU_VIDEO_DRIVER_DIRECT3D12,
"menu_display_d3d12",
};

View File

@ -93,6 +93,9 @@ static menu_display_ctx_driver_t *menu_display_ctx_drivers[] = {
#ifdef HAVE_D3D11
&menu_display_ctx_d3d11,
#endif
#ifdef HAVE_D3D12
&menu_display_ctx_d3d12,
#endif
#ifdef HAVE_OPENGL
&menu_display_ctx_gl,
#endif
@ -229,6 +232,10 @@ static bool menu_display_check_compatibility(
if (string_is_equal(video_driver, "d3d11"))
return true;
break;
case MENU_VIDEO_DRIVER_DIRECT3D12:
if (string_is_equal(video_driver, "d3d12"))
return true;
break;
case MENU_VIDEO_DRIVER_VITA2D:
if (string_is_equal(video_driver, "vita2d"))
return true;

View File

@ -280,6 +280,7 @@ enum menu_display_driver_type
MENU_VIDEO_DRIVER_VULKAN,
MENU_VIDEO_DRIVER_DIRECT3D,
MENU_VIDEO_DRIVER_DIRECT3D11,
MENU_VIDEO_DRIVER_DIRECT3D12,
MENU_VIDEO_DRIVER_VITA2D,
MENU_VIDEO_DRIVER_CTR,
MENU_VIDEO_DRIVER_WIIU,
@ -735,6 +736,7 @@ extern menu_display_ctx_driver_t menu_display_ctx_gl;
extern menu_display_ctx_driver_t menu_display_ctx_vulkan;
extern menu_display_ctx_driver_t menu_display_ctx_d3d;
extern menu_display_ctx_driver_t menu_display_ctx_d3d11;
extern menu_display_ctx_driver_t menu_display_ctx_d3d12;
extern menu_display_ctx_driver_t menu_display_ctx_vita2d;
extern menu_display_ctx_driver_t menu_display_ctx_ctr;
extern menu_display_ctx_driver_t menu_display_ctx_wiiu;