DX12: added dx12 support to r_renderAPI/r_twinMode cvars.

This commit is contained in:
Artem Kharytoniuk 2017-12-24 00:11:35 +01:00
parent 2610ef131e
commit c326ac6e3b
4 changed files with 135 additions and 39 deletions

View File

@ -409,10 +409,24 @@ static HWND create_main_window(int width, int height, qboolean fullscreen)
} }
} }
char window_name[1024];
if (r_twinMode->integer == 0) {
strcpy(window_name, MAIN_WINDOW_CLASS_NAME);
} else {
const char* api_name = "invalid-render-api";
if (r_renderAPI->integer == 0)
api_name = "OpenGL";
else if (r_renderAPI->integer == 1)
api_name = "Vulkan";
else if (r_renderAPI->integer == 2)
api_name = "DX12";
sprintf(window_name, "%s [%s]", MAIN_WINDOW_CLASS_NAME, api_name);
}
HWND hwnd = CreateWindowEx( HWND hwnd = CreateWindowEx(
0, 0,
MAIN_WINDOW_CLASS_NAME, MAIN_WINDOW_CLASS_NAME,
"Quake 3: Arena", window_name,
stylebits, stylebits,
x, y, w, h, x, y, w, h,
NULL, NULL,
@ -431,7 +445,7 @@ static HWND create_main_window(int width, int height, qboolean fullscreen)
return hwnd; return hwnd;
} }
static HWND create_twin_window(int width, int height, bool dx_window) static HWND create_twin_window(int width, int height, int render_api)
{ {
// //
// register the window class if necessary // register the window class if necessary
@ -478,8 +492,27 @@ static HWND create_twin_window(int width, int height, bool dx_window)
cvar_t* vid_xpos = ri.Cvar_Get ("vid_xpos", "", 0); cvar_t* vid_xpos = ri.Cvar_Get ("vid_xpos", "", 0);
cvar_t* vid_ypos = ri.Cvar_Get ("vid_ypos", "", 0); cvar_t* vid_ypos = ri.Cvar_Get ("vid_ypos", "", 0);
int x = vid_xpos->integer + width + 5; // offset to the right of the main window int x, y;
int y = vid_ypos->integer;
bool show_three_windows = (r_twinMode->integer | (1 << r_renderAPI->integer)) == 7;
if (!show_three_windows) { // two windows
x = vid_xpos->integer + width + 5; // offset to the right of the main window
y = vid_ypos->integer;
} else { // three windows
bool first_twin_window =
(r_renderAPI->integer > 0 && render_api == 0) ||
(r_renderAPI->integer == 0 && render_api == 1);
if (first_twin_window) {
x = vid_xpos->integer + width + 5;
y = vid_ypos->integer;
} else {
x = vid_xpos->integer + 2*width + 10;
y = vid_ypos->integer;
}
}
// adjust window coordinates if necessary // adjust window coordinates if necessary
// so that the window is completely on screen // so that the window is completely on screen
@ -499,10 +532,17 @@ static HWND create_twin_window(int width, int height, bool dx_window)
y = ( desktop_height - h ); y = ( desktop_height - h );
} }
// If r_renderAPI = 0 (OpenGL) then twin window uses Vulkan API.
// If r_renderAPI = 1 (Vulkan) then twin window uses OpenGL API.
char window_name[1024]; char window_name[1024];
sprintf(window_name, "%s [%s]", MAIN_WINDOW_CLASS_NAME, dx_window ? "DX12" : (r_renderAPI->integer == 0 ? "Vulkan" : "OpenGL"));
const char* api_name = "invalid-render-api";
if (render_api == 0)
api_name = "OpenGL";
else if (render_api == 1)
api_name = "Vulkan";
else if (render_api == 2)
api_name = "DX12";
sprintf(window_name, "%s [%s]", MAIN_WINDOW_CLASS_NAME, api_name);
HWND hwnd = CreateWindowEx( HWND hwnd = CreateWindowEx(
0, 0,
@ -726,7 +766,7 @@ void GLimp_Init( void )
SetFocus(g_wv.hWnd); SetFocus(g_wv.hWnd);
WG_CheckHardwareGamma(); WG_CheckHardwareGamma();
} else { } else {
g_wv.hWnd_opengl = create_twin_window(glConfig.vidWidth, glConfig.vidHeight, false); g_wv.hWnd_opengl = create_twin_window(glConfig.vidWidth, glConfig.vidHeight, 0);
} }
if (!GLW_InitDriver(g_wv.hWnd_opengl)) { if (!GLW_InitDriver(g_wv.hWnd_opengl)) {
@ -831,16 +871,14 @@ void vk_imp_init() {
// Create window. // Create window.
SetMode(r_mode->integer, (qboolean)r_fullscreen->integer); SetMode(r_mode->integer, (qboolean)r_fullscreen->integer);
if (r_renderAPI->integer != 0) { if (r_renderAPI->integer == 1) {
g_wv.hWnd_vulkan = create_main_window(glConfig.vidWidth, glConfig.vidHeight, (qboolean)r_fullscreen->integer); g_wv.hWnd_vulkan = create_main_window(glConfig.vidWidth, glConfig.vidHeight, (qboolean)r_fullscreen->integer);
g_wv.hWnd = g_wv.hWnd_vulkan; g_wv.hWnd = g_wv.hWnd_vulkan;
SetForegroundWindow(g_wv.hWnd); SetForegroundWindow(g_wv.hWnd);
SetFocus(g_wv.hWnd); SetFocus(g_wv.hWnd);
WG_CheckHardwareGamma(); WG_CheckHardwareGamma();
g_wv.hWnd_dx = create_twin_window(glConfig.vidWidth, glConfig.vidHeight, true);
} else { } else {
g_wv.hWnd_vulkan = create_twin_window(glConfig.vidWidth, glConfig.vidHeight, false); g_wv.hWnd_vulkan = create_twin_window(glConfig.vidWidth, glConfig.vidHeight, 1);
} }
} }
@ -864,16 +902,6 @@ void vk_imp_shutdown() {
} }
vkGetInstanceProcAddr = nullptr; vkGetInstanceProcAddr = nullptr;
if (g_wv.hWnd_dx) {
ri.Printf(PRINT_ALL, "...destroying DX12 window\n");
DestroyWindow(g_wv.hWnd_dx);
if (g_wv.hWnd == g_wv.hWnd_dx) {
g_wv.hWnd_dx = NULL;
}
g_wv.hWnd_dx = NULL;
}
// For vulkan mode we still have qgl pointers initialized with placeholder values. // For vulkan mode we still have qgl pointers initialized with placeholder values.
// Reset them the same way as we do in opengl mode. // Reset them the same way as we do in opengl mode.
QGL_Shutdown(); QGL_Shutdown();
@ -899,6 +927,58 @@ void vk_imp_create_surface() {
VK_CHECK(vkCreateWin32SurfaceKHR(vk.instance, &desc, nullptr, &vk.surface)); VK_CHECK(vkCreateWin32SurfaceKHR(vk.instance, &desc, nullptr, &vk.surface));
} }
void dx_imp_init() {
ri.Printf(PRINT_ALL, "Initializing DX12 subsystem\n");
// This will set qgl pointers to no-op placeholders.
if (!gl_active) {
QGL_Init(nullptr);
qglActiveTextureARB = [] (GLenum) {};
qglClientActiveTextureARB = [](GLenum) {};
}
// Create window.
SetMode(r_mode->integer, (qboolean)r_fullscreen->integer);
if (r_renderAPI->integer == 2) {
g_wv.hWnd_dx = create_main_window(glConfig.vidWidth, glConfig.vidHeight, (qboolean)r_fullscreen->integer);
g_wv.hWnd = g_wv.hWnd_dx;
SetForegroundWindow(g_wv.hWnd);
SetFocus(g_wv.hWnd);
WG_CheckHardwareGamma();
} else {
g_wv.hWnd_dx = create_twin_window(glConfig.vidWidth, glConfig.vidHeight, 2);
}
}
void dx_imp_shutdown() {
ri.Printf(PRINT_ALL, "Shutting down DX12 subsystem\n");
if (g_wv.hWnd_dx) {
ri.Printf(PRINT_ALL, "...destroying DX12 window\n");
DestroyWindow(g_wv.hWnd_dx);
if (g_wv.hWnd == g_wv.hWnd_dx) {
g_wv.hWnd = NULL;
}
g_wv.hWnd_dx = NULL;
}
// For DX12 mode we still have qgl pointers initialized with placeholder values.
// Reset them the same way as we do in opengl mode.
QGL_Shutdown();
WG_RestoreGamma();
memset(&glConfig, 0, sizeof(glConfig));
memset(&glState, 0, sizeof(glState));
if (log_fp) {
fclose(log_fp);
log_fp = 0;
}
}
/* /*
=========================================================== ===========================================================

View File

@ -75,7 +75,7 @@ typedef struct
HINSTANCE reflib_library; // Handle to refresh DLL HINSTANCE reflib_library; // Handle to refresh DLL
qboolean reflib_active; qboolean reflib_active;
HWND hWnd; // main window, refers either to hWnd_opengl or to hWnd_vulkan HWND hWnd; // main window, refers to one of the hWnd_XXX listed below
HWND hWnd_opengl; HWND hWnd_opengl;
HWND hWnd_vulkan; HWND hWnd_vulkan;

View File

@ -191,7 +191,7 @@ static void InitRenderAPI( void )
if ( glConfig.vidWidth == 0 ) if ( glConfig.vidWidth == 0 )
{ {
// OpenGL // OpenGL
if (r_renderAPI->integer == 0 || r_twinMode->integer) { if (r_renderAPI->integer == 0 || (r_twinMode->integer&1)) {
GLimp_Init(); GLimp_Init();
GLint temp; GLint temp;
@ -202,10 +202,14 @@ static void InitRenderAPI( void )
} }
// VULKAN // VULKAN
// DX12 if (r_renderAPI->integer == 1 || (r_twinMode->integer&2)) {
if (r_renderAPI->integer != 0 || r_twinMode->integer) {
vk_imp_init(); vk_imp_init();
vk_initialize(); vk_initialize();
}
// DX12
if (r_renderAPI->integer == 2 || (r_twinMode->integer&4)) {
dx_imp_init();
dx_initialize(); dx_initialize();
} }
} }
@ -373,9 +377,9 @@ void RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) {
if (r_renderAPI->integer == 0) { if (r_renderAPI->integer == 0) {
qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 );
} else { } else if (r_renderAPI->integer == 1) { // VULKAN
// VULKAN
byte* buffer2 = (byte*) ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4); byte* buffer2 = (byte*) ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4);
vk_read_pixels(buffer2); vk_read_pixels(buffer2);
byte* buffer_ptr = buffer + 18; byte* buffer_ptr = buffer + 18;
@ -418,8 +422,7 @@ void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName
if (r_renderAPI->integer == 0) { if (r_renderAPI->integer == 0) {
qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
} else { } else if (r_renderAPI->integer == 1) { // VULKAN
// VULKAN
vk_read_pixels(buffer); vk_read_pixels(buffer);
} }
@ -557,8 +560,7 @@ void R_LevelShot( void ) {
if (r_renderAPI->integer == 0) { if (r_renderAPI->integer == 0) {
qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source );
} else { } else if (r_renderAPI->integer == 1) { // VULKAN
// VULKAN
byte* buffer2 = (byte*) ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4); byte* buffer2 = (byte*) ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4);
vk_read_pixels(buffer2); vk_read_pixels(buffer2);
@ -1121,16 +1123,22 @@ void RE_Shutdown( qboolean destroyWindow ) {
// VULKAN // VULKAN
if (vk.active) { if (vk.active) {
dx_release_resources();
vk_release_resources(); vk_release_resources();
if (destroyWindow) { if (destroyWindow) {
dx_shutdown();
vk_shutdown(); vk_shutdown();
vk_imp_shutdown(); vk_imp_shutdown();
} }
} }
// DX12
if (dx.active) {
dx_release_resources();
if (destroyWindow) {
dx_shutdown();
dx_imp_shutdown();
}
}
tr.registered = qfalse; tr.registered = qfalse;
} }

View File

@ -949,11 +949,16 @@ extern Dx_World dx_world; // this data is cleared during ref re-init
// //
// cvars // cvars
// //
extern cvar_t *r_renderAPI; // 3D API to use: 0 - OpenGL, 1 - Vulkan. extern cvar_t *r_renderAPI; // 3D API to use: 0 - OpenGL, 1 - Vulkan, 2 - DX12
extern cvar_t *r_twinMode; // If enabled, renderer creates two separate windows. extern cvar_t *r_twinMode; // Allows to render the same frame in different windows using different graphics APIs.
// The first window uses rendering API specified by r_renderAPI, // This cvar specifies a bitmask that determines which APIs.
// the second window uses rendering API corresponding to (1 - r_renderAPI). // 0 - regular rendering with single window using the graphics API specified by r_renderAPI.
// bit 0 - enables OpenGL backend
// bit 1 - enables Vulkan backend
// bit 2 - enables DX12 backend
// Combinations of the above values are allowed, for example, r_twinMode=7 creates three diffent
// windows using all the supported APIs.
extern cvar_t *r_railWidth; extern cvar_t *r_railWidth;
extern cvar_t *r_railCoreWidth; extern cvar_t *r_railCoreWidth;
@ -1204,6 +1209,9 @@ void vk_imp_init();
void vk_imp_shutdown(); void vk_imp_shutdown();
void vk_imp_create_surface(); void vk_imp_create_surface();
void dx_imp_init();
void dx_imp_shutdown();
// NOTE TTimo linux works with float gamma value, not the gamma table // NOTE TTimo linux works with float gamma value, not the gamma table
// the params won't be used, getting the r_gamma cvar directly // the params won't be used, getting the r_gamma cvar directly
void GLimp_SetGamma( unsigned char red[256], void GLimp_SetGamma( unsigned char red[256],