From 5a5b0b4d2b9e3438b4406f332cb188eef5bf21cd Mon Sep 17 00:00:00 2001 From: Artem Kharytoniuk Date: Fri, 5 May 2017 13:55:55 +0300 Subject: [PATCH] Vulkan platform specific code reorganization. --- src/cgame/cg_local.h | 4 - src/engine/client/snd_local.h | 3 - src/engine/platform/glw_win.h | 10 - src/engine/platform/win_gamma.c | 12 +- src/engine/platform/win_glimp.c | 322 +++++++++++++++---------------- src/engine/platform/win_qgl.c | 42 ++-- src/engine/renderer/tr_backend.c | 6 +- src/engine/renderer/tr_image.c | 4 +- src/engine/renderer/tr_init.c | 44 ++--- src/engine/renderer/tr_local.h | 9 +- src/engine/renderer/tr_shade.c | 6 +- src/engine/renderer/tr_shader.c | 2 +- src/engine/renderer/tr_sky.c | 2 +- src/engine/renderer/vk.cpp | 73 ++++--- src/engine/renderer/vk.h | 18 +- 15 files changed, 276 insertions(+), 281 deletions(-) diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index db01726..63d3f50 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -1539,10 +1539,6 @@ void trap_CIN_SetExtents (int handle, int x, int y, int w, int h); void trap_SnapVector( float *v ); -qboolean trap_loadCamera(const char *name); -void trap_startCamera(int time); -qboolean trap_getCameraInfo(int time, vec3_t *origin, vec3_t *angles); - qboolean trap_GetEntityToken( char *buffer, int bufferSize ); void CG_ClearParticles (void); diff --git a/src/engine/client/snd_local.h b/src/engine/client/snd_local.h index c5e2452..7c48a1b 100644 --- a/src/engine/client/snd_local.h +++ b/src/engine/client/snd_local.h @@ -175,9 +175,6 @@ void S_PaintChannels(int endtime); void S_memoryLoad(sfx_t *sfx); portable_samplepair_t *S_GetRawSamplePointer(); -// spatializes a channel -void S_Spatialize(channel_t *ch); - // adpcm functions int S_AdpcmMemoryNeeded( const wavinfo_t *info ); void S_AdpcmEncodeSound( sfx_t *sfx, short *samples ); diff --git a/src/engine/platform/glw_win.h b/src/engine/platform/glw_win.h index 93b2f2e..dc31239 100644 --- a/src/engine/platform/glw_win.h +++ b/src/engine/platform/glw_win.h @@ -28,16 +28,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA typedef struct { - WNDPROC wndproc; - - HDC hDC; // handle to device context - HGLRC hGLRC; // handle to GL rendering context - - HINSTANCE hinstOpenGL; // HINSTANCE for the OpenGL library - - int desktopBitsPixel; - int desktopWidth, desktopHeight; - FILE *log_fp; } glwstate_t; diff --git a/src/engine/platform/win_gamma.c b/src/engine/platform/win_gamma.c index c047eb5..2dafb83 100644 --- a/src/engine/platform/win_gamma.c +++ b/src/engine/platform/win_gamma.c @@ -123,18 +123,12 @@ void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned } } - HDC gamma_hdc = glw_state.hDC; - if (gamma_hdc == NULL) - gamma_hdc = GetDC(NULL); - - ret = SetDeviceGammaRamp( gamma_hdc, table ); + HDC hdc = GetDC(NULL); + ret = SetDeviceGammaRamp( hdc, table ); if ( !ret ) { Com_Printf( "SetDeviceGammaRamp failed.\n" ); } - - if (glw_state.hDC == NULL) - ReleaseDC(NULL, gamma_hdc); - + ReleaseDC(NULL, hdc); } /* diff --git a/src/engine/platform/win_glimp.c b/src/engine/platform/win_glimp.c index 496069f..775821d 100644 --- a/src/engine/platform/win_glimp.c +++ b/src/engine/platform/win_glimp.c @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ** WIN_GLIMP.C ** ** This file contains ALL Win32 specific stuff having to do with the -** OpenGL refresh. When a port is being made the following functions +** OpenGL/Vulkan refresh. When a port is being made the following functions ** must be implemented by the port: ** ** GLimp_EndFrame @@ -31,8 +31,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ** GLimp_LogComment ** GLimp_Shutdown ** -** Note that the GLW_xxx functions are Windows specific GL-subsystem -** related functions that are relevant ONLY to win_glimp.c +** vk_imp_init +** vk_imp_shutdown */ #include #include "../renderer/tr_local.h" @@ -60,8 +60,21 @@ void QGL_Shutdown( void ); // // variable declarations // +static HDC gl_hdc; // handle to device context +static HGLRC gl_hglrc; // handle to GL rendering context + glwstate_t glw_state; +static int GetDesktopCaps(int index) { + HDC hdc = GetDC(GetDesktopWindow()); + int value = GetDeviceCaps(hdc, index); + ReleaseDC(GetDesktopWindow(), hdc); + return value; +} +static int GetDesktopColorDepth() { return GetDesktopCaps(BITSPIXEL); } +static int GetDesktopWidth() { return GetDesktopCaps(HORZRES); } +static int GetDesktopHeight() { return GetDesktopCaps(VERTRES); } + /* ** ChoosePFD ** @@ -251,15 +264,12 @@ static bool GLW_SetPixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR *pPFD, int colorbi static qboolean GLW_InitDriver(HWND hwnd) { ri.Printf( PRINT_ALL, "Initializing OpenGL driver\n" ); - glw_state.hDC = NULL; - glw_state.hGLRC = NULL; - // // get a DC for our window // ri.Printf(PRINT_ALL, "...getting DC: "); - HDC hdc = GetDC(hwnd); - if (hdc == NULL) { + gl_hdc = GetDC(hwnd); + if (gl_hdc == NULL) { ri.Printf(PRINT_ALL, "failed\n"); return qfalse; } @@ -268,13 +278,14 @@ static qboolean GLW_InitDriver(HWND hwnd) { // // set pixel format // - int colorbits = glw_state.desktopBitsPixel; + int colorbits = GetDesktopColorDepth(); int depthbits = (r_depthbits->integer == 0) ? 24 : r_depthbits->integer; int stencilbits = r_stencilbits->integer; PIXELFORMATDESCRIPTOR pfd; - if (!GLW_SetPixelFormat(hdc, &pfd, colorbits, depthbits, stencilbits, (qboolean)r_stereo->integer)) { - ReleaseDC(hwnd, hdc); + if (!GLW_SetPixelFormat(gl_hdc, &pfd, colorbits, depthbits, stencilbits, (qboolean)r_stereo->integer)) { + ReleaseDC(hwnd, gl_hdc); + gl_hdc = NULL; ri.Printf(PRINT_ALL, "...failed to find an appropriate PIXELFORMAT\n"); return qfalse; } @@ -288,34 +299,30 @@ static qboolean GLW_InitDriver(HWND hwnd) { // startup the OpenGL subsystem by creating a context and making it current // ri.Printf(PRINT_ALL, "...creating GL context: "); - HGLRC hglrc = qwglCreateContext(hdc); - if (hglrc == NULL) { - ReleaseDC(hwnd, hdc); + gl_hglrc = qwglCreateContext(gl_hdc); + if (gl_hglrc == NULL) { + ReleaseDC(hwnd, gl_hdc); + gl_hdc = NULL; ri.Printf(PRINT_ALL, "failed\n"); return qfalse; } ri.Printf(PRINT_ALL, "succeeded\n"); ri.Printf(PRINT_ALL, "...making context current: "); - if (!qwglMakeCurrent(hdc, hglrc)) { - qwglDeleteContext(hglrc); - ReleaseDC(hwnd, hdc); + if (!qwglMakeCurrent(gl_hdc, gl_hglrc)) { + qwglDeleteContext(gl_hglrc); + gl_hglrc = NULL; + ReleaseDC(hwnd, gl_hdc); + gl_hdc = NULL; ri.Printf(PRINT_ALL, "failed\n"); return qfalse; } ri.Printf(PRINT_ALL, "succeeded\n"); - // - // update global state and return - // - glw_state.hDC = hdc; - glw_state.hGLRC = hglrc; - glConfig.colorBits = ( int ) pfd.cColorBits; glConfig.depthBits = ( int ) pfd.cDepthBits; glConfig.stencilBits = ( int ) pfd.cStencilBits; glConfig.stereoEnabled = (pfd.dwFlags & PFD_STEREO) ? qtrue : qfalse; - return qtrue; } @@ -326,12 +333,16 @@ static HWND create_main_window(int width, int height, qboolean fullscreen) // if (!s_main_window_class_registered) { + cvar_t* cv = ri.Cvar_Get( "win_wndproc", "", 0 ); + WNDPROC wndproc; + sscanf(cv->string, "%p", (void **)&wndproc); + WNDCLASS wc; memset( &wc, 0, sizeof( wc ) ); wc.style = 0; - wc.lpfnWndProc = glw_state.wndproc; + wc.lpfnWndProc = wndproc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = g_wv.hInstance; @@ -393,13 +404,15 @@ static HWND create_main_window(int width, int height, qboolean fullscreen) if ( y < 0 ) y = 0; - if ( w < glw_state.desktopWidth && - h < glw_state.desktopHeight ) + int desktop_width = GetDesktopWidth(); + int desktop_height = GetDesktopHeight(); + + if (w < desktop_width && h < desktop_height) { - if ( x + w > glw_state.desktopWidth ) - x = ( glw_state.desktopWidth - w ); - if ( y + h > glw_state.desktopHeight ) - y = ( glw_state.desktopHeight - h ); + if ( x + w > desktop_width ) + x = ( desktop_width - w ); + if ( y + h > desktop_height ) + y = ( desktop_height - h ); } } @@ -482,13 +495,15 @@ static HWND create_api_compare_window(int width, int height) if ( y < 0 ) y = 0; - if ( w < glw_state.desktopWidth && - h < glw_state.desktopHeight ) + int desktop_width = GetDesktopWidth(); + int desktop_height = GetDesktopHeight(); + + if (w < desktop_width && h < desktop_height) { - if ( x + w > glw_state.desktopWidth ) - x = ( glw_state.desktopWidth - w ); - if ( y + h > glw_state.desktopHeight ) - y = ( glw_state.desktopHeight - h ); + if ( x + w > desktop_width ) + x = ( desktop_width - w ); + if ( y + h > desktop_height ) + y = ( desktop_height - h ); } // If r_renderAPI = 0 (OpenGL) then compare window uses Vulkan API. @@ -518,86 +533,21 @@ static HWND create_api_compare_window(int width, int height) return hwnd; } -/* -** GLW_SetMode -*/ -static bool GLW_SetMode(int mode, qboolean fullscreen) { - { - HDC hDC = GetDC(GetDesktopWindow()); - glw_state.desktopBitsPixel = GetDeviceCaps(hDC, BITSPIXEL); - glw_state.desktopWidth = GetDeviceCaps(hDC, HORZRES); - glw_state.desktopHeight = GetDeviceCaps(hDC, VERTRES); - ReleaseDC(GetDesktopWindow(), hDC); - } - +static void SetMode(int mode, qboolean fullscreen) { if (fullscreen) { ri.Printf( PRINT_ALL, "...setting fullscreen mode:"); - glConfig.vidWidth = glw_state.desktopWidth; - glConfig.vidHeight = glw_state.desktopHeight; + glConfig.vidWidth = GetDesktopWidth(); + glConfig.vidHeight = GetDesktopHeight(); glConfig.windowAspect = 1.0f; - } - else { + } else { ri.Printf( PRINT_ALL, "...setting mode %d:", mode ); if (!R_GetModeInfo(&glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode)) { ri.Printf( PRINT_ALL, " invalid mode\n" ); - return false; + ri.Error(ERR_FATAL, "SetMode - could not set the given mode (%d)\n", mode); } } - glConfig.isFullscreen = fullscreen; + glConfig.isFullscreen = fullscreen; ri.Printf( PRINT_ALL, " %d %d %s\n", glConfig.vidWidth, glConfig.vidHeight, fullscreen ? "FS" : "W"); - - g_wv.hWnd = NULL; - g_wv.hWnd_opengl = NULL; - g_wv.hWnd_vulkan = NULL; - - HWND hwnd = create_main_window(glConfig.vidWidth, glConfig.vidHeight, fullscreen); - - if (r_renderAPI->integer == 0) { // opengl - if (!GLW_InitDriver(hwnd)) { - ShowWindow(hwnd, SW_HIDE); - DestroyWindow(hwnd); - return false; - } - g_wv.hWnd = hwnd; - g_wv.hWnd_opengl = hwnd; - - if (r_renderAPICompareWindow->integer) { - HWND hwnd2 = create_api_compare_window(glConfig.vidWidth, glConfig.vidHeight); - vk_create_instance(hwnd2); - g_wv.hWnd_vulkan = hwnd2; - /*if (!vk_initialize(hwnd2)) { - ShowWindow(hwnd2, SW_HIDE); - DestroyWindow(hwnd2); - ri.Printf(PRINT_WARNING, "GLW_SetMode: could not create API compare window"); - } else { - g_wv.hWnd_vulkan = hwnd2; - }*/ - } - } else { // vulkan - if (r_renderAPICompareWindow->integer) { - HWND hwnd2 = create_api_compare_window(glConfig.vidWidth, glConfig.vidHeight); - if (!GLW_InitDriver(hwnd2)) { - DestroyWindow(hwnd2); - ri.Printf(PRINT_WARNING, "GLW_SetMode: could not create API compare window"); - } else { - g_wv.hWnd_opengl = hwnd2; - } - } - - vk_create_instance(hwnd); - /*if (!vk_initialize(hwnd)) { - ShowWindow(hwnd, SW_HIDE); - DestroyWindow(hwnd); - return false; - }*/ - - g_wv.hWnd = hwnd; - g_wv.hWnd_vulkan = hwnd; - } - - SetForegroundWindow(g_wv.hWnd); - SetFocus(g_wv.hWnd); - return true; } /* @@ -605,12 +555,6 @@ static bool GLW_SetMode(int mode, qboolean fullscreen) { */ static void GLW_InitExtensions( void ) { - if (!gl_active) { - qglActiveTextureARB = [] (GLenum) {}; - qglClientActiveTextureARB = [](GLenum) {}; - return; - } - ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" ); // GL_S3_s3tc @@ -731,7 +675,7 @@ void GLimp_EndFrame (void) // don't flip if drawing to front buffer if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 ) { - SwapBuffers( glw_state.hDC ); + SwapBuffers( gl_hdc ); } // check logging @@ -750,14 +694,8 @@ void GLimp_EndFrame (void) */ void GLimp_Init( void ) { - cvar_t *cv; - ri.Printf( PRINT_ALL, "Initializing OpenGL subsystem\n" ); - // save wndproc - cv = ri.Cvar_Get( "win_wndproc", "", 0 ); - sscanf( cv->string, "%p", (void **)&glw_state.wndproc ); - // load appropriate DLL and initialize subsystem // // load the driver and bind our function pointers to it @@ -767,11 +705,21 @@ void GLimp_Init( void ) ri.Error(ERR_FATAL, "QGL_Init - could not load OpenGL driver\n"); } - // create the window and set up the context - if (!GLW_SetMode(r_mode->integer, (qboolean)r_fullscreen->integer)) - { - ri.Error(ERR_FATAL, "GLW_SetMode - could not set the given mode (%d)\n", r_mode->integer); - } + SetMode(r_mode->integer, (qboolean)r_fullscreen->integer); + + if (r_renderAPI->integer == 0) { + g_wv.hWnd_opengl = create_main_window(glConfig.vidWidth, glConfig.vidHeight, (qboolean)r_fullscreen->integer); + g_wv.hWnd = g_wv.hWnd_opengl; + } else { + g_wv.hWnd_opengl = create_api_compare_window(glConfig.vidWidth, glConfig.vidHeight); + } + + if (!GLW_InitDriver(g_wv.hWnd_opengl)) { + ri.Error(ERR_FATAL, "GLW_InitDriver - could not initialize OpenGL subsystem\n"); + } + + SetForegroundWindow(g_wv.hWnd); + SetFocus(g_wv.hWnd); // get our config strings Q_strncpyz( glConfig.vendor_string, (const char*) qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) ); @@ -792,31 +740,24 @@ void GLimp_Init( void ) void GLimp_Shutdown( void ) { const char *success[] = { "failed", "success" }; - int retVal; ri.Printf(PRINT_ALL, "Shutting down OpenGL subsystem\n"); - // restore gamma. We do this first because 3Dfx's extension needs a valid OGL subsystem - WG_RestoreGamma(); - - // set current context to NULL if (qwglMakeCurrent) { - retVal = qwglMakeCurrent(NULL, NULL) != 0; + int retVal = qwglMakeCurrent(NULL, NULL) != 0; ri.Printf(PRINT_ALL, "...wglMakeCurrent( NULL, NULL ): %s\n", success[retVal]); } - // delete HGLRC - if (glw_state.hGLRC) { - retVal = qwglDeleteContext(glw_state.hGLRC) != 0; + if (gl_hglrc) { + int retVal = qwglDeleteContext(gl_hglrc) != 0; ri.Printf(PRINT_ALL, "...deleting GL context: %s\n", success[retVal]); - glw_state.hGLRC = NULL; + gl_hglrc = NULL; } - // release DC - if (glw_state.hDC) { - retVal = ReleaseDC(g_wv.hWnd_opengl, glw_state.hDC) != 0; + if (gl_hdc) { + int retVal = ReleaseDC(g_wv.hWnd_opengl, gl_hdc) != 0; ri.Printf(PRINT_ALL, "...releasing DC: %s\n", success[retVal]); - glw_state.hDC = NULL; + gl_hdc = NULL; } // destroy window @@ -824,32 +765,26 @@ void GLimp_Shutdown( void ) ri.Printf(PRINT_ALL, "...destroying opengl window\n"); ShowWindow(g_wv.hWnd_opengl, SW_HIDE); DestroyWindow(g_wv.hWnd_opengl); + + if (g_wv.hWnd == g_wv.hWnd_opengl) + g_wv.hWnd = NULL; + g_wv.hWnd_opengl = NULL; } - if (g_wv.hWnd_vulkan) { - ri.Printf(PRINT_ALL, "...destroying vulkan window\n"); - ShowWindow(g_wv.hWnd_vulkan, SW_HIDE); - DestroyWindow(g_wv.hWnd_vulkan); - g_wv.hWnd_vulkan = NULL; - } - g_wv.hWnd = NULL; - // close the r_logFile + QGL_Shutdown(); + + WG_RestoreGamma(); + + memset(&glConfig, 0, sizeof(glConfig)); + memset(&glState, 0, sizeof(glState)); + if (glw_state.log_fp) { fclose(glw_state.log_fp); glw_state.log_fp = 0; } - - // shutdown QGL subsystem - QGL_Shutdown(); - - memset(&glConfig, 0, sizeof(glConfig)); - memset(&glState, 0, sizeof(glState)); } -/* -** GLimp_LogComment -*/ void GLimp_LogComment( char *comment ) { if ( glw_state.log_fp ) { @@ -857,6 +792,69 @@ void GLimp_LogComment( char *comment ) } } +void vk_imp_init() { + ri.Printf(PRINT_ALL, "Initializing Vulkan subsystem\n"); + + if (!gl_enabled) { + QGL_Init(nullptr); // this will set qgl pointers to no-op placeholders + qglActiveTextureARB = [] (GLenum) {}; + qglClientActiveTextureARB = [](GLenum) {}; + } + + SetMode(r_mode->integer, (qboolean)r_fullscreen->integer); + + if (r_renderAPI->integer != 0) { + g_wv.hWnd_vulkan = create_main_window(glConfig.vidWidth, glConfig.vidHeight, (qboolean)r_fullscreen->integer); + g_wv.hWnd = g_wv.hWnd_vulkan; + } else { + g_wv.hWnd_vulkan = create_api_compare_window(glConfig.vidWidth, glConfig.vidHeight); + } + + // In order to create surface we need to create VkInstance first. + vk_create_instance(); + + // Create VkSurfaceKHR for Win32 platform. + VkWin32SurfaceCreateInfoKHR desc; + desc.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + desc.pNext = nullptr; + desc.flags = 0; + desc.hinstance = ::GetModuleHandle(nullptr); + desc.hwnd = g_wv.hWnd_vulkan; + VK_CHECK(vkCreateWin32SurfaceKHR(vk.instance, &desc, nullptr, &vk.surface)); + + SetForegroundWindow(g_wv.hWnd); + SetFocus(g_wv.hWnd); + + WG_CheckHardwareGamma(); +} + +void vk_imp_shutdown() { + ri.Printf(PRINT_ALL, "Shutting down Vulkan subsystem\n"); + + if (g_wv.hWnd_vulkan) { + ri.Printf(PRINT_ALL, "...destroying vulkan window\n"); + DestroyWindow(g_wv.hWnd_vulkan); + + if (g_wv.hWnd == g_wv.hWnd_vulkan) + g_wv.hWnd = NULL; + + g_wv.hWnd_vulkan = NULL; + } + + // For vulkan mode we still have qgl pointers initialized with placeholder values. + // Thus 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 (glw_state.log_fp) { + fclose(glw_state.log_fp); + glw_state.log_fp = 0; + } +} /* =========================================================== @@ -876,7 +874,7 @@ void GLimp_RenderThreadWrapper( void ) { glimpRenderThread(); // unbind the context before we die - qwglMakeCurrent( glw_state.hDC, NULL ); + qwglMakeCurrent( gl_hdc, NULL ); } /* @@ -915,7 +913,7 @@ static int wglErrors; void *GLimp_RendererSleep( void ) { void *data; - if ( !qwglMakeCurrent( glw_state.hDC, NULL ) ) { + if ( !qwglMakeCurrent( gl_hdc, NULL ) ) { wglErrors++; } @@ -926,7 +924,7 @@ void *GLimp_RendererSleep( void ) { WaitForSingleObject( renderCommandsEvent, INFINITE ); - if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) ) { + if ( !qwglMakeCurrent( gl_hdc, gl_hglrc ) ) { wglErrors++; } @@ -945,7 +943,7 @@ void *GLimp_RendererSleep( void ) { void GLimp_FrontEndSleep( void ) { WaitForSingleObject( renderCompletedEvent, INFINITE ); - if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) ) { + if ( !qwglMakeCurrent( gl_hdc, gl_hglrc ) ) { wglErrors++; } } @@ -954,7 +952,7 @@ void GLimp_FrontEndSleep( void ) { void GLimp_WakeRenderer( void *data ) { smpData = data; - if ( !qwglMakeCurrent( glw_state.hDC, NULL ) ) { + if ( !qwglMakeCurrent( gl_hdc, NULL ) ) { wglErrors++; } diff --git a/src/engine/platform/win_qgl.c b/src/engine/platform/win_qgl.c index 22e13af..42cfe35 100644 --- a/src/engine/platform/win_qgl.c +++ b/src/engine/platform/win_qgl.c @@ -32,6 +32,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../renderer/tr_local.h" #include "glw_win.h" +static HINSTANCE hinstOpenGL; // HINSTANCE for the OpenGL library + void QGL_EnableLogging( qboolean enable ); HGLRC ( WINAPI * qwglCreateContext)(HDC); @@ -664,15 +666,17 @@ static void APIENTRY logViewport(GLint x, GLint y, GLsizei width, GLsizei height */ void QGL_Shutdown( void ) { - ri.Printf( PRINT_ALL, "...shutting down QGL\n" ); + if (gl_enabled) { + ri.Printf( PRINT_ALL, "...shutting down QGL\n" ); - if ( glw_state.hinstOpenGL ) - { - ri.Printf( PRINT_ALL, "...unloading OpenGL DLL\n" ); - FreeLibrary( glw_state.hinstOpenGL ); + if ( hinstOpenGL ) + { + ri.Printf( PRINT_ALL, "...unloading OpenGL DLL\n" ); + FreeLibrary( hinstOpenGL ); + } } - glw_state.hinstOpenGL = NULL; + hinstOpenGL = NULL; qglAlphaFunc = NULL; qglBegin = NULL; @@ -734,7 +738,7 @@ void QGL_Shutdown( void ) } # pragma warning (disable : 4113 4133 4047 ) -# define GPA( a ) (gl_active ? (void*)GetProcAddress(glw_state.hinstOpenGL, #a) : (void*)(&no ## a)) +# define GPA( a ) (gl_enabled ? (void*)GetProcAddress(hinstOpenGL, #a) : (void*)(&no ## a)) /* ** QGL_Init @@ -747,17 +751,19 @@ void QGL_Shutdown( void ) */ qboolean QGL_Init( const char *dllname ) { - assert( glw_state.hinstOpenGL == 0 ); + if (gl_enabled) { + assert( hinstOpenGL == 0 ); - ri.Printf( PRINT_ALL, "...initializing QGL\n" ); - ri.Printf( PRINT_ALL, "...calling LoadLibrary('%s'): ", dllname ); + ri.Printf( PRINT_ALL, "...initializing QGL\n" ); + ri.Printf( PRINT_ALL, "...calling LoadLibrary('%s'): ", dllname ); - if ( ( glw_state.hinstOpenGL = LoadLibrary( dllname ) ) == 0 ) - { - ri.Printf( PRINT_ALL, "failed\n" ); - return qfalse; + if ( ( hinstOpenGL = LoadLibrary( dllname ) ) == 0 ) + { + ri.Printf( PRINT_ALL, "failed\n" ); + return qfalse; + } + ri.Printf( PRINT_ALL, "succeeded\n" ); } - ri.Printf( PRINT_ALL, "succeeded\n" ); qglAlphaFunc = dllAlphaFunc = (decltype(dllAlphaFunc))GPA(glAlphaFunc); qglBegin = dllBegin = (decltype(dllBegin))GPA(glBegin); @@ -823,8 +829,10 @@ qboolean QGL_Init( const char *dllname ) qglLockArraysEXT = 0; qglUnlockArraysEXT = 0; - // check logging - QGL_EnableLogging( (qboolean) r_logFile->integer ); + if (gl_enabled) { + // check logging + QGL_EnableLogging( (qboolean) r_logFile->integer ); + } return qtrue; } diff --git a/src/engine/renderer/tr_backend.c b/src/engine/renderer/tr_backend.c index b97a198..c76815a 100644 --- a/src/engine/renderer/tr_backend.c +++ b/src/engine/renderer/tr_backend.c @@ -64,7 +64,7 @@ void GL_Bind( image_t *image ) { qglBindTexture (GL_TEXTURE_2D, texnum); // VULKAN - if (vk_active) { + if (vk.active) { VkDescriptorSet set = vk_resources.images[final_image->index].descriptor_set; vk_resources.current_descriptor_sets[glState.currenttmu] = set; } @@ -711,7 +711,7 @@ void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); // VULKAN - if (vk_active) { + if (vk.active) { Vk_Image& image = vk_resources.images[tr.scratchImage[client]->index]; vkDestroyImage(vk.device, image.handle, nullptr); vkDestroyImageView(vk.device, image.view, nullptr); @@ -727,7 +727,7 @@ void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); // VULKAN - if (vk_active) { + if (vk.active) { const Vk_Image& image = vk_resources.images[tr.scratchImage[client]->index]; vk_upload_image_data(image.handle, cols, rows, false, data); } diff --git a/src/engine/renderer/tr_image.c b/src/engine/renderer/tr_image.c index c73a153..1cdb2f4 100644 --- a/src/engine/renderer/tr_image.c +++ b/src/engine/renderer/tr_image.c @@ -145,7 +145,7 @@ void GL_TextureMode( const char *string ) { } // VULKAN - if (vk_active) { + if (vk.active) { VK_CHECK(vkDeviceWaitIdle(vk.device)); for ( i = 0 ; i < tr.numImages ; i++ ) { image_t* glt = tr.images[i]; @@ -722,7 +722,7 @@ static void Upload32( unsigned *data, done: // VULKAN - if (vk_active) { + if (vk.active) { image = vk_create_image(*pUploadWidth, *pUploadHeight, miplevel + 1, repeat_texture); vk_upload_image_data(image.handle, *pUploadWidth, *pUploadHeight, mipmap == qtrue, mipmap_buffer); } diff --git a/src/engine/renderer/tr_init.c b/src/engine/renderer/tr_init.c index 6896523..7d0af53 100644 --- a/src/engine/renderer/tr_init.c +++ b/src/engine/renderer/tr_init.c @@ -29,8 +29,6 @@ glstate_t glState; // VULKAN Vk_Instance vk; Vk_Resources vk_resources; -bool gl_active; -bool vk_active; static void GfxInfo_f( void ); @@ -178,14 +176,9 @@ static void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, qboolean sh /* -** InitOpenGL -** -** This function is responsible for initializing a valid OpenGL subsystem. This -** is done by calling GLimp_Init (which gives us a working OGL subsystem) then -** setting variables, checking GL constants, and reporting the gfx system config -** to the user. +** This function is responsible for initializing a valid OpenGL/Vulkan subsystem. */ -static void InitOpenGL( void ) +static void InitRenderAPI( void ) { // // initialize OS specific portions of the renderer @@ -200,10 +193,17 @@ static void InitOpenGL( void ) // if ( glConfig.vidWidth == 0 ) { - GLimp_Init(); + if (gl_enabled) + GLimp_Init(); + + // VULKAN + if (vk_enabled) { + vk_imp_init(); + vk_initialize(); + } // OpenGL driver constants - GLint temp; + GLint temp; qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); glConfig.maxTextureSize = temp; } @@ -930,6 +930,7 @@ void R_Init( void ) { Com_Memset( &tr, 0, sizeof( tr ) ); Com_Memset( &backEnd, 0, sizeof( backEnd ) ); Com_Memset( &tess, 0, sizeof( tess ) ); + Com_Memset( &vk_resources, 0, sizeof( vk_resources ) ); if ( (intptr_t)tess.xyz & 15 ) { Com_Printf( "WARNING: tess.xyz not 16 byte aligned\n" ); @@ -991,10 +992,7 @@ void R_Init( void ) { } R_ToggleSmpFrame(); - gl_active = (r_renderAPI->integer == 0 || r_renderAPICompareWindow->integer > 0); - vk_active = (r_renderAPI->integer > 0 || r_renderAPICompareWindow->integer > 0); - - InitOpenGL(); + InitRenderAPI(); R_InitImages(); @@ -1032,13 +1030,6 @@ void RE_Shutdown( qboolean destroyWindow ) { ri.Cmd_RemoveCommand( "modelist" ); ri.Cmd_RemoveCommand( "shaderstate" ); - // VULKAN - if (vk_active) { - vk_destroy_resources(); - if (destroyWindow) - vk_destroy_instance(); - } - if ( tr.registered ) { R_SyncRenderThread(); R_ShutdownCommandBuffers(); @@ -1052,6 +1043,15 @@ void RE_Shutdown( qboolean destroyWindow ) { GLimp_Shutdown(); } + // VULKAN + if (vk.active) { + vk_release_resources(); + if (destroyWindow) { + vk_shutdown(); + vk_imp_shutdown(); + } + } + tr.registered = qfalse; } diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index ade6863..c4ef987 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -942,8 +942,6 @@ extern glstate_t glState; // outside of TR since it shouldn't be cleared during // VULKAN extern Vk_Instance vk; // shouldn't be cleared during ref re-init extern Vk_Resources vk_resources; // this data is cleared during ref re-init -extern bool gl_active; -extern bool vk_active; // @@ -1197,13 +1195,15 @@ IMPLEMENTATION SPECIFIC FUNCTIONS void GLimp_Init( void ); void GLimp_Shutdown( void ); void GLimp_EndFrame( void ); +void GLimp_LogComment( char *comment ); qboolean GLimp_SpawnRenderThread( void (*function)( void ) ); void *GLimp_RendererSleep( void ); void GLimp_FrontEndSleep( void ); void GLimp_WakeRenderer( void *data ); -void GLimp_LogComment( char *comment ); +void vk_imp_init(); +void vk_imp_shutdown(); // NOTE TTimo linux works with float gamma value, not the gamma table // the params won't be used, getting the r_gamma cvar directly @@ -1422,6 +1422,9 @@ void RB_CalcDiffuseColor( unsigned char *colors ); void myGlMultMatrix( const float *a, const float *b, float *out ); +#define gl_enabled (r_renderAPI->integer == 0 || r_renderAPICompareWindow->integer) +#define vk_enabled (r_renderAPI->integer != 0 || r_renderAPICompareWindow->integer) + /* ============================================================= diff --git a/src/engine/renderer/tr_shade.c b/src/engine/renderer/tr_shade.c index 49531ef..80f75b7 100644 --- a/src/engine/renderer/tr_shade.c +++ b/src/engine/renderer/tr_shade.c @@ -362,7 +362,7 @@ static void ProjectDlightTexture( void ) { backEnd.pc.c_dlightIndexes += numIndexes; // VULKAN - if (vk_active) { + if (vk.active) { VkPipeline pipeline = vk.dlight_pipelines[dl->additive > 0 ? 1 : 0][tess.shader->cullType][tess.shader->polygonOffset]; vk_bind_stage_specific_resources(pipeline, false, false); vkCmdDrawIndexed(vk.command_buffer, tess.numIndexes, 1, 0, 0, 0); @@ -408,7 +408,7 @@ static void RB_FogPass( void ) { R_DrawElements( tess.numIndexes, tess.indexes ); // VULKAN - if (vk_active) { + if (vk.active) { assert(tess.shader->fogPass > 0); VkPipeline pipeline = vk.fog_pipelines[tess.shader->fogPass - 1][tess.shader->cullType][tess.shader->polygonOffset]; vk_bind_stage_specific_resources(pipeline, false, false); @@ -767,7 +767,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) } // VULKAN - if (vk_active) { + if (vk.active) { VkPipeline pipeline = pStage->vk_pipeline; if (backEnd.viewParms.isMirror) pipeline = pStage->vk_mirror_pipeline; diff --git a/src/engine/renderer/tr_shader.c b/src/engine/renderer/tr_shader.c index f680a60..062df60 100644 --- a/src/engine/renderer/tr_shader.c +++ b/src/engine/renderer/tr_shader.c @@ -2161,7 +2161,7 @@ static shader_t *FinishShader( void ) { } // VULKAN: create pipelines for each shader stage - if (vk_active) { + if (vk.active) { Vk_Pipeline_Def def; def.face_culling = shader.cullType; def.polygon_offset = (shader.polygonOffset == qtrue); diff --git a/src/engine/renderer/tr_sky.c b/src/engine/renderer/tr_sky.c index 94da1d0..36eaf27 100644 --- a/src/engine/renderer/tr_sky.c +++ b/src/engine/renderer/tr_sky.c @@ -451,7 +451,7 @@ static void DrawSkyBox( shader_t *shader ) sky_maxs_subd ); // VULKAN: draw skybox side - if (vk_active) { + if (vk.active) { VkDescriptorSet set = vk_resources.images[shader->sky.outerbox[sky_texorder[i]]->index].descriptor_set; vk_resources.current_descriptor_sets[0] = set; diff --git a/src/engine/renderer/vk.cpp b/src/engine/renderer/vk.cpp index 92297b2..da172ab 100644 --- a/src/engine/renderer/vk.cpp +++ b/src/engine/renderer/vk.cpp @@ -95,33 +95,6 @@ static uint32_t select_queue_family(VkPhysicalDevice physical_device, VkSurfaceK return -1; } -static VkInstance create_instance() { - uint32_t count = 0; - VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr)); - - std::vector extension_properties(count); - VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &count, extension_properties.data())); - - for (auto name : instance_extensions) { - if (!is_extension_available(extension_properties, name)) - ri.Error(ERR_FATAL, "Vulkan error: required instance extension is not available: %s", name); - } - - VkInstanceCreateInfo desc; - desc.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - desc.pNext = nullptr; - desc.flags = 0; - desc.pApplicationInfo = nullptr; - desc.enabledLayerCount = 0; - desc.ppEnabledLayerNames = nullptr; - desc.enabledExtensionCount = static_cast(instance_extensions.size()); - desc.ppEnabledExtensionNames = instance_extensions.data(); - - VkInstance instance; - VK_CHECK(vkCreateInstance(&desc, nullptr, &instance)); - return instance; -} - static VkPhysicalDevice select_physical_device(VkInstance instance) { uint32_t count; VK_CHECK(vkEnumeratePhysicalDevices(instance, &count, nullptr)); @@ -517,18 +490,41 @@ static void ensure_staging_buffer_allocation(VkDeviceSize size) { VkPipeline create_pipeline(const Vk_Pipeline_Def&); -void vk_create_instance(HWND hwnd) { +void vk_create_instance() { + uint32_t count = 0; + VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr)); + + std::vector extension_properties(count); + VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &count, extension_properties.data())); + + for (auto name : instance_extensions) { + if (!is_extension_available(extension_properties, name)) + ri.Error(ERR_FATAL, "Vulkan error: required instance extension is not available: %s", name); + } + + VkInstanceCreateInfo desc; + desc.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + desc.pNext = nullptr; + desc.flags = 0; + desc.pApplicationInfo = nullptr; + desc.enabledLayerCount = 0; + desc.ppEnabledLayerNames = nullptr; + desc.enabledExtensionCount = static_cast(instance_extensions.size()); + desc.ppEnabledExtensionNames = instance_extensions.data(); + + VK_CHECK(vkCreateInstance(&desc, nullptr, &vk.instance)); +} + +void vk_initialize() { vk_log_file = fopen("vk_dev.log", "w"); - vk.instance = create_instance(); - vk.physical_device = select_physical_device(vk.instance); + vk.physical_device = select_physical_device(vk.instance); VkPhysicalDeviceFeatures features; vkGetPhysicalDeviceFeatures(vk.physical_device, &features); if (features.shaderClipDistance == VK_FALSE) ri.Error(ERR_FATAL, "vk_create_instance: shaderClipDistance feature is not supported"); - - vk.surface = create_surface(vk.instance, hwnd); + vk.surface_format = select_surface_format(vk.physical_device, vk.surface); vk.queue_family_index = select_queue_family(vk.physical_device, vk.surface); @@ -919,9 +915,10 @@ void vk_create_instance(HWND hwnd) { } } } + vk.active = true; } -void vk_destroy_instance() { +void vk_shutdown() { fclose(vk_log_file); vk_log_file = nullptr; @@ -975,7 +972,7 @@ void vk_destroy_instance() { static float pipeline_create_time; -void vk_destroy_resources() { +void vk_release_resources() { vkDeviceWaitIdle(vk.device); auto& res = vk_resources; @@ -1620,7 +1617,7 @@ VkPipeline vk_find_pipeline(const Vk_Pipeline_Def& def) { } void vk_clear_attachments(bool clear_stencil, bool fast_sky) { - if (!vk_active) + if (!vk.active) return; if (!vk_resources.dirty_attachments && !fast_sky) @@ -1755,7 +1752,7 @@ static void get_mvp_transform(float* mvp) { } void vk_bind_resources_shared_between_stages() { - if (!vk_active) return; + if (!vk.active) return; // xyz { @@ -1888,7 +1885,7 @@ void vk_bind_stage_specific_resources(VkPipeline pipeline, bool multitexture, bo } void vk_begin_frame() { - if (!vk_active) + if (!vk.active) return; if (r_logFile->integer) @@ -1931,7 +1928,7 @@ void vk_begin_frame() { } void vk_end_frame() { - if (!vk_active) + if (!vk.active) return; if (r_logFile->integer) diff --git a/src/engine/renderer/vk.h b/src/engine/renderer/vk.h index ee97e97..0557a74 100644 --- a/src/engine/renderer/vk.h +++ b/src/engine/renderer/vk.h @@ -54,9 +54,20 @@ struct Vk_Image { // // Initialization. // -void vk_create_instance(HWND hwnd); // initializes VK_Instance -void vk_destroy_instance(); // destroys Vk_Instance resources -void vk_destroy_resources(); // destroys Vk_Resources resources + +// Creates VkInstance and stores it as Vk_Instance::instance. +void vk_create_instance(); + +// Initializes VK_Instance structure. +// After calling this function we get fully functional vulkan subsystem. +void vk_initialize(); + +// Shutdown vulkan subsystem by releasing resources acquired by Vk_Instance. +void vk_shutdown(); + +// Releases vulkan resources allocated during program execution. +// This effectively puts vulkan subsystem into initial state (the state we have after vk_initialize call). +void vk_release_resources(); // // Resources allocation. @@ -79,6 +90,7 @@ void vk_end_frame(); // Vulkan specific structures used by the engine. struct Vk_Instance { + bool active = false; VkInstance instance = VK_NULL_HANDLE; VkPhysicalDevice physical_device = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE;