- added initial support of Vulkan to SDL backend

Removed all platform-specific code from vulkan device
This commit is contained in:
alexey.lysiuk 2019-03-06 13:38:45 +02:00
parent 08d8ea5d31
commit 108ea066f3
6 changed files with 420 additions and 250 deletions

View file

@ -504,7 +504,8 @@ set( PLAT_WIN32_SOURCES
win32/gl_sysfb.cpp win32/gl_sysfb.cpp
win32/base_sysfb.cpp win32/base_sysfb.cpp
win32/win32basevideo.cpp win32/win32basevideo.cpp
win32/win32glvideo.cpp ) win32/win32glvideo.cpp
win32/win32vulkanvideo.cpp )
set( PLAT_POSIX_SOURCES set( PLAT_POSIX_SOURCES
posix/i_cd.cpp posix/i_cd.cpp
posix/i_steam.cpp ) posix/i_steam.cpp )

View file

@ -32,6 +32,7 @@
*/ */
#include "gl_load/gl_load.h" #include "gl_load/gl_load.h"
#include "volk/volk.h"
#include "i_common.h" #include "i_common.h"
@ -660,3 +661,19 @@ void I_SetWindowTitle(const char* title)
{ {
SystemBaseFrameBuffer::SetWindowTitle(title); SystemBaseFrameBuffer::SetWindowTitle(title);
} }
void I_GetVulkanDrawableSize(int *width, int *height)
{
assert(!"Not implemented");
}
bool I_GetVulkanPlatformExtensions(unsigned int *count, const char **names)
{
assert(!"Not implemented");
}
bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface)
{
assert(!"Not implemented");
}

View file

@ -12,43 +12,17 @@ class SystemBaseFrameBuffer : public DFrameBuffer
public: public:
// this must have the same parameters as the Windows version, even if they are not used! // this must have the same parameters as the Windows version, even if they are not used!
SystemBaseFrameBuffer (void *hMonitor, bool fullscreen); SystemBaseFrameBuffer (void *hMonitor, bool fullscreen);
~SystemBaseFrameBuffer ();
void ForceBuffering (bool force); bool IsFullscreen() override;
bool IsFullscreen ();
virtual void SetVSync( bool vsync );
void SwapBuffers();
friend class SDLGLVideo;
int GetClientWidth() override; int GetClientWidth() override;
int GetClientHeight() override; int GetClientHeight() override;
void ToggleFullscreen(bool yes) override; void ToggleFullscreen(bool yes) override;
void SetWindowSize(int client_w, int client_h); void SetWindowSize(int client_w, int client_h) override;
SDL_Window *GetSDLWindow() { return Screen; }
void GetWindowBordersSize(int &top, int &left);
bool m_fsswitch;
protected: protected:
void SetGammaTable(uint16_t *tbl);
void ResetGammaTable();
SystemBaseFrameBuffer () {} SystemBaseFrameBuffer () {}
uint8_t GammaTable[3][256];
bool UpdatePending;
SDL_Window *Screen;
SDL_GLContext GLContext;
void UpdateColors ();
static const int MIN_WIDTH = 320;
static const int MIN_HEIGHT = 200;
}; };
class SystemGLFrameBuffer : public SystemBaseFrameBuffer class SystemGLFrameBuffer : public SystemBaseFrameBuffer
@ -56,11 +30,18 @@ class SystemGLFrameBuffer : public SystemBaseFrameBuffer
typedef SystemBaseFrameBuffer Super; typedef SystemBaseFrameBuffer Super;
public: public:
SystemGLFrameBuffer(void *hMonitor, bool fullscreen) SystemGLFrameBuffer(void *hMonitor, bool fullscreen);
: SystemBaseFrameBuffer(hMonitor, fullscreen) ~SystemGLFrameBuffer();
{}
int GetClientWidth() override;
int GetClientHeight() override;
virtual void SetVSync(bool vsync) override;
void SwapBuffers();
protected: protected:
SDL_GLContext GLContext;
SystemGLFrameBuffer() {} SystemGLFrameBuffer() {}
}; };

View file

@ -53,6 +53,8 @@
#include "gl/system/gl_framebuffer.h" #include "gl/system/gl_framebuffer.h"
#include "gl/shaders/gl_shader.h" #include "gl/shaders/gl_shader.h"
#include "rendering/vulkan/system/vk_framebuffer.h"
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
// TYPES ------------------------------------------------------------------- // TYPES -------------------------------------------------------------------
@ -89,45 +91,60 @@ CVAR (Int, vid_adapter, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------
class SDLGLVideo : public IVideo namespace Priv
{ {
public: FModule library("SDL2");
SDLGLVideo (int parm);
~SDLGLVideo ();
DFrameBuffer *CreateFrameBuffer (); #define SDL2_OPTIONAL_FUNCTION(RESULT, NAME, ...) \
static TOptProc<library, RESULT(*)(__VA_ARGS__)> NAME("SDL_" #NAME)
void SetupPixelFormat(bool allowsoftware, int multisample, const int *glver); SDL2_OPTIONAL_FUNCTION(int, GetWindowBordersSize, SDL_Window *window, int *top, int *left, int *bottom, int *right);
}; SDL2_OPTIONAL_FUNCTION(void, Vulkan_GetDrawableSize, SDL_Window *window, int *width, int *height);
SDL2_OPTIONAL_FUNCTION(SDL_bool, Vulkan_GetInstanceExtensions, SDL_Window *window, unsigned int *count, const char **names);
SDL2_OPTIONAL_FUNCTION(SDL_bool, Vulkan_CreateSurface, SDL_Window *window, VkInstance instance, VkSurfaceKHR *surface);
// CODE -------------------------------------------------------------------- #undef SDL2_OPTIONAL_FUNCTION
SDLGLVideo::SDLGLVideo (int parm) static const uint32_t VulkanWindowFlag = 0x1000'0000;
static const int MIN_WIDTH = 320;
static const int MIN_HEIGHT = 200;
SDL_Window *window;
bool vulkanSupported;
bool fullscreenSwitch;
void CreateWindow(uint32_t extraFlags)
{ {
if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { assert(Priv::window == nullptr);
fprintf( stderr, "Video initialization failed: %s\n",
SDL_GetError( ) ); // Set default size
SDL_Rect bounds;
SDL_GetDisplayBounds(vid_adapter, &bounds);
if (win_w <= 0 || win_h <= 0)
{
win_w = bounds.w * 8 / 10;
win_h = bounds.h * 8 / 10;
}
FString caption;
caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
const uint32_t windowFlags = (win_maximized ? SDL_WINDOW_MAXIMIZED : 0) | SDL_WINDOW_RESIZABLE | extraFlags;
Priv::window = SDL_CreateWindow(caption,
(win_x <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_x,
(win_y <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_y,
win_w, win_h, windowFlags);
if (Priv::window != nullptr)
{
// Enforce minimum size limit
SDL_SetWindowMinimumSize(Priv::window, Priv::MIN_WIDTH, Priv::MIN_HEIGHT);
} }
} }
SDLGLVideo::~SDLGLVideo () void SetupPixelFormat(int multisample, const int *glver)
{
}
DFrameBuffer *SDLGLVideo::CreateFrameBuffer ()
{
SystemBaseFrameBuffer *fb = new OpenGLRenderer::OpenGLFrameBuffer(0, fullscreen);
return fb;
}
//==========================================================================
//
//
//
//==========================================================================
void SDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, const int *glver)
{ {
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
@ -162,47 +179,209 @@ void SDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, const int
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
} }
} }
}
class SDLVideo : public IVideo
{
public:
SDLVideo ();
~SDLVideo ();
DFrameBuffer *CreateFrameBuffer ();
private:
VulkanDevice *device = nullptr;
};
// CODE --------------------------------------------------------------------
void I_GetVulkanDrawableSize(int *width, int *height)
{
assert(Priv::vulkanSupported);
assert(Priv::window != nullptr);
assert(Priv::Vulkan_GetDrawableSize);
Priv::Vulkan_GetDrawableSize(Priv::window, width, height);
}
bool I_GetVulkanPlatformExtensions(unsigned int *count, const char **names)
{
assert(Priv::vulkanSupported);
assert(Priv::window != nullptr);
assert(Priv::Vulkan_GetInstanceExtensions);
return Priv::Vulkan_GetInstanceExtensions(Priv::window, count, names) == SDL_TRUE;
}
bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface)
{
assert(Priv::vulkanSupported);
assert(Priv::window != nullptr);
assert(Priv::Vulkan_CreateSurface);
return Priv::Vulkan_CreateSurface(Priv::window, instance, surface) == SDL_TRUE;
}
SDLVideo::SDLVideo ()
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
fprintf(stderr, "Video initialization failed: %s\n", SDL_GetError());
return;
}
// Load optional SDL functions
if (!Priv::library.IsLoaded())
{
Priv::library.Load({ "libSDL2.so", "libSDL2-2.0.so" });
}
Priv::vulkanSupported = Priv::Vulkan_GetDrawableSize && Priv::Vulkan_GetInstanceExtensions && Priv::Vulkan_CreateSurface;
if (Priv::vulkanSupported)
{
Priv::CreateWindow(Priv::VulkanWindowFlag | SDL_WINDOW_HIDDEN);
if (Priv::window == nullptr)
{
Priv::vulkanSupported = false;
}
}
}
SDLVideo::~SDLVideo ()
{
delete device;
}
DFrameBuffer *SDLVideo::CreateFrameBuffer ()
{
SystemBaseFrameBuffer *fb = nullptr;
// first try Vulkan, if that fails OpenGL
if (Priv::vulkanSupported)
{
try
{
assert(device == nullptr);
device = new VulkanDevice();
fb = new VulkanFrameBuffer(nullptr, fullscreen, device);
}
catch (CRecoverableError const&)
{
Priv::vulkanSupported = false;
}
}
if (fb == nullptr)
{
fb = new OpenGLRenderer::OpenGLFrameBuffer(0, fullscreen);
}
return fb;
}
IVideo *gl_CreateVideo() IVideo *gl_CreateVideo()
{ {
return new SDLGLVideo(0); return new SDLVideo();
} }
// FrameBuffer implementation ----------------------------------------------- // FrameBuffer Implementation -----------------------------------------------
FModule sdl_lib("SDL2");
typedef int (*SDL_GetWindowBordersSizePtr)(SDL_Window *, int *, int *, int *, int *);
static TOptProc<sdl_lib, SDL_GetWindowBordersSizePtr> SDL_GetWindowBordersSize_("SDL_GetWindowBordersSize");
SystemBaseFrameBuffer::SystemBaseFrameBuffer (void *, bool fullscreen) SystemBaseFrameBuffer::SystemBaseFrameBuffer (void *, bool fullscreen)
: DFrameBuffer (vid_defwidth, vid_defheight) : DFrameBuffer (vid_defwidth, vid_defheight)
{ {
m_fsswitch = false; if (Priv::window != nullptr)
// SDL_GetWindowBorderSize() is only available since 2.0.5, but because
// GZDoom supports platforms with older SDL2 versions, this function
// has to be dynamically loaded
if (!sdl_lib.IsLoaded())
{ {
sdl_lib.Load({ "libSDL2.so", "libSDL2-2.0.so" }); SDL_SetWindowFullscreen(Priv::window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
SDL_ShowWindow(Priv::window);
}
} }
int SystemBaseFrameBuffer::GetClientWidth()
{
int width = 0;
assert(Priv::vulkanSupported);
Priv::Vulkan_GetDrawableSize(Priv::window, &width, nullptr);
return width;
}
int SystemBaseFrameBuffer::GetClientHeight()
{
int height = 0;
assert(Priv::vulkanSupported);
Priv::Vulkan_GetDrawableSize(Priv::window, nullptr, &height);
return height;
}
bool SystemBaseFrameBuffer::IsFullscreen ()
{
return (SDL_GetWindowFlags(Priv::window) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
}
void SystemBaseFrameBuffer::ToggleFullscreen(bool yes)
{
SDL_SetWindowFullscreen(Priv::window, yes ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
if ( !yes )
{
if ( !Priv::fullscreenSwitch )
{
Priv::fullscreenSwitch = true;
fullscreen = false;
}
else
{
Priv::fullscreenSwitch = false;
SetWindowSize(win_w, win_h);
}
}
}
void SystemBaseFrameBuffer::SetWindowSize(int w, int h)
{
if (w < Priv::MIN_WIDTH || h < Priv::MIN_HEIGHT)
{
w = Priv::MIN_WIDTH;
h = Priv::MIN_HEIGHT;
}
win_w = w;
win_h = h;
if ( fullscreen )
{
fullscreen = false;
}
else
{
win_maximized = false;
SDL_SetWindowSize(Priv::window, w, h);
SDL_SetWindowPosition(Priv::window, SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter), SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter));
SetSize(GetClientWidth(), GetClientHeight());
int x, y;
SDL_GetWindowPosition(Priv::window, &x, &y);
win_x = x;
win_y = y;
}
}
SystemGLFrameBuffer::SystemGLFrameBuffer(void *hMonitor, bool fullscreen)
: SystemBaseFrameBuffer(hMonitor, fullscreen)
{
// NOTE: Core profiles were added with GL 3.2, so there's no sense trying // NOTE: Core profiles were added with GL 3.2, so there's no sense trying
// to set core 3.1 or 3.0. We could try a forward-compatible context // to set core 3.1 or 3.0. We could try a forward-compatible context
// instead, but that would be too restrictive (w.r.t. shaders). // instead, but that would be too restrictive (w.r.t. shaders).
static const int glvers[][2] = { static const int glvers[][2] = {
{ 4, 5 }, { 4, 4 }, { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 }, { 4, 6 }, { 4, 5 }, { 4, 4 }, { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 },
{ 3, 3 }, { 3, 2 }, { 2, 0 }, { 3, 3 }, { 3, 2 }, { 2, 0 },
{ 0, 0 }, { 0, 0 },
}; };
int glveridx = 0; int glveridx = 0;
int i; int i;
UpdatePending = false;
const char *version = Args->CheckValue("-glversion"); const char *version = Args->CheckValue("-glversion");
if (version != NULL) if (version != NULL)
{ {
@ -222,61 +401,58 @@ SystemBaseFrameBuffer::SystemBaseFrameBuffer (void *, bool fullscreen)
} }
} }
FString caption;
caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
for ( ; glvers[glveridx][0] > 0; ++glveridx) for ( ; glvers[glveridx][0] > 0; ++glveridx)
{ {
static_cast<SDLGLVideo*>(Video)->SetupPixelFormat(false, 0, glvers[glveridx]); Priv::SetupPixelFormat(0, glvers[glveridx]);
Priv::CreateWindow(SDL_WINDOW_OPENGL | (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0));
SDL_Rect bounds; if (Priv::window == nullptr)
SDL_GetDisplayBounds(vid_adapter,&bounds);
// set default size
if ( win_w <= 0 || win_h <= 0 )
{ {
win_w = bounds.w * 8 / 10; continue;
win_h = bounds.h * 8 / 10;
} }
Screen = SDL_CreateWindow(caption, GLContext = SDL_GL_CreateContext(Priv::window);
(win_x <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_x, if (GLContext == nullptr)
(win_y <= 0) ? SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter) : win_y,
win_w, win_h, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0) | (win_maximized ? SDL_WINDOW_MAXIMIZED : 0) | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (Screen != NULL)
{ {
// enforce minimum size limit SDL_DestroyWindow(Priv::window);
SDL_SetWindowMinimumSize(Screen, MIN_WIDTH, MIN_HEIGHT); Priv::window = nullptr;
GLContext = SDL_GL_CreateContext(Screen);
if (GLContext != NULL)
return;
SDL_DestroyWindow(Screen);
Screen = NULL;
} }
} else
}
SystemBaseFrameBuffer::~SystemBaseFrameBuffer ()
{ {
if (Screen) break;
}
}
}
SystemGLFrameBuffer::~SystemGLFrameBuffer ()
{
if (Priv::window)
{ {
if (GLContext) if (GLContext)
{ {
SDL_GL_DeleteContext(GLContext); SDL_GL_DeleteContext(GLContext);
} }
SDL_DestroyWindow(Screen); SDL_DestroyWindow(Priv::window);
Priv::window = nullptr;
} }
} }
int SystemGLFrameBuffer::GetClientWidth()
bool SystemBaseFrameBuffer::IsFullscreen ()
{ {
return (SDL_GetWindowFlags (Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; int width = 0;
SDL_GL_GetDrawableSize(Priv::window, &width, nullptr);
return width;
} }
void SystemBaseFrameBuffer::SetVSync( bool vsync ) int SystemGLFrameBuffer::GetClientHeight()
{
int height = 0;
SDL_GL_GetDrawableSize(Priv::window, nullptr, &height);
return height;
}
void SystemGLFrameBuffer::SetVSync( bool vsync )
{ {
#if defined (__APPLE__) #if defined (__APPLE__)
const GLint value = vsync ? 1 : 0; const GLint value = vsync ? 1 : 0;
@ -294,7 +470,7 @@ void SystemBaseFrameBuffer::SetVSync( bool vsync )
#endif #endif
} }
void SystemBaseFrameBuffer::SwapBuffers() void SystemGLFrameBuffer::SwapBuffers()
{ {
#if !defined(__APPLE__) && !defined(__OpenBSD__) #if !defined(__APPLE__) && !defined(__OpenBSD__)
if (vid_maxfps && !cl_capfps) if (vid_maxfps && !cl_capfps)
@ -303,74 +479,9 @@ void SystemBaseFrameBuffer::SwapBuffers()
} }
#endif #endif
SDL_GL_SwapWindow (Screen); SDL_GL_SwapWindow(Priv::window);
} }
void SystemBaseFrameBuffer::ToggleFullscreen(bool yes)
{
SDL_SetWindowFullscreen(Screen, yes ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
if ( !yes )
{
if ( !m_fsswitch )
{
m_fsswitch = true;
fullscreen = false;
}
else
{
m_fsswitch = false;
SetWindowSize(win_w, win_h);
}
}
}
int SystemBaseFrameBuffer::GetClientWidth()
{
int width = 0;
SDL_GL_GetDrawableSize(Screen, &width, nullptr);
return width;
}
int SystemBaseFrameBuffer::GetClientHeight()
{
int height = 0;
SDL_GL_GetDrawableSize(Screen, nullptr, &height);
return height;
}
void SystemBaseFrameBuffer::SetWindowSize(int w, int h)
{
if (w < MIN_WIDTH || h < MIN_HEIGHT)
{
w = MIN_WIDTH;
h = MIN_HEIGHT;
}
win_w = w;
win_h = h;
if ( fullscreen )
{
fullscreen = false;
}
else
{
win_maximized = false;
SDL_SetWindowSize(Screen, w, h);
SDL_SetWindowPosition(Screen, SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter), SDL_WINDOWPOS_CENTERED_DISPLAY(vid_adapter));
SetSize(GetClientWidth(), GetClientHeight());
int x, y;
SDL_GetWindowPosition(Screen, &x, &y);
win_x = x;
win_y = y;
}
}
void SystemBaseFrameBuffer::GetWindowBordersSize(int &top, int &left)
{
if (SDL_GetWindowBordersSize_)
{
SDL_GetWindowBordersSize_(Screen, &top, &left, nullptr, nullptr);
}
}
void ProcessSDLWindowEvent(const SDL_WindowEvent &event) void ProcessSDLWindowEvent(const SDL_WindowEvent &event)
{ {
@ -389,17 +500,17 @@ void ProcessSDLWindowEvent(const SDL_WindowEvent &event)
break; break;
case SDL_WINDOWEVENT_MOVED: case SDL_WINDOWEVENT_MOVED:
if (!fullscreen) if (!fullscreen && Priv::GetWindowBordersSize)
{ {
int top = 0, left = 0; int top = 0, left = 0;
static_cast<SystemBaseFrameBuffer *>(screen)->GetWindowBordersSize(top,left); Priv::GetWindowBordersSize(Priv::window, &top, &left, nullptr, nullptr);
win_x = event.data1-left; win_x = event.data1-left;
win_y = event.data2-top; win_y = event.data2-top;
} }
break; break;
case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_RESIZED:
if (!fullscreen && !(static_cast<SystemBaseFrameBuffer *>(screen)->m_fsswitch)) if (!fullscreen && !Priv::fullscreenSwitch)
{ {
win_w = event.data1; win_w = event.data1;
win_h = event.data2; win_h = event.data2;
@ -420,14 +531,15 @@ void ProcessSDLWindowEvent(const SDL_WindowEvent &event)
// each platform has its own specific version of this function. // each platform has its own specific version of this function.
void I_SetWindowTitle(const char* caption) void I_SetWindowTitle(const char* caption)
{ {
auto window = static_cast<SystemBaseFrameBuffer *>(screen)->GetSDLWindow();
if (caption) if (caption)
SDL_SetWindowTitle(window, caption); {
SDL_SetWindowTitle(Priv::window, caption);
}
else else
{ {
FString default_caption; FString default_caption;
default_caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime()); default_caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
SDL_SetWindowTitle(window, default_caption); SDL_SetWindowTitle(Priv::window, default_caption);
} }
} }

View file

@ -21,17 +21,11 @@
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// //
#ifdef _WIN32
#define VK_USE_PLATFORM_WIN32_KHR
#endif
#include "volk/volk.h" #include "volk/volk.h"
#ifdef _WIN32 #ifdef _WIN32
#undef max #undef max
#undef min #undef min
extern HWND Window;
#endif #endif
#include <vector> #include <vector>
@ -48,6 +42,10 @@ extern HWND Window;
#include "doomerrors.h" #include "doomerrors.h"
#include "gamedata/fonts/v_text.h" #include "gamedata/fonts/v_text.h"
void I_GetVulkanDrawableSize(int *width, int *height);
bool I_GetVulkanPlatformExtensions(unsigned int *count, const char **names);
bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface);
EXTERN_CVAR(Bool, vid_vsync); EXTERN_CVAR(Bool, vid_vsync);
CUSTOM_CVAR(Bool, vk_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) CUSTOM_CVAR(Bool, vk_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
@ -75,13 +73,9 @@ VulkanDevice::VulkanDevice()
createDevice(); createDevice();
createAllocator(); createAllocator();
#ifdef _WIN32 int width, height;
RECT clientRect = { 0 }; I_GetVulkanDrawableSize(&width, &height);
GetClientRect(Window, &clientRect); swapChain = std::make_unique<VulkanSwapChain>(this, width, height, vid_vsync);
swapChain = std::make_unique<VulkanSwapChain>(this, clientRect.right, clientRect.bottom, vid_vsync);
#else
assert(!"Implement platform-specific swapchain size getter");
#endif
createSemaphores(); createSemaphores();
} }
@ -99,15 +93,11 @@ VulkanDevice::~VulkanDevice()
void VulkanDevice::windowResized() void VulkanDevice::windowResized()
{ {
#ifdef _WIN32 int width, height;
RECT clientRect = { 0 }; I_GetVulkanDrawableSize(&width, &height);
GetClientRect(Window, &clientRect);
swapChain.reset(); swapChain.reset();
swapChain = std::make_unique<VulkanSwapChain>(this, clientRect.right, clientRect.bottom, vid_vsync); swapChain = std::make_unique<VulkanSwapChain>(this, width, height, vid_vsync);
#else
assert(!"Implement platform-specific swapchain resize");
#endif
} }
void VulkanDevice::waitPresent() void VulkanDevice::waitPresent()
@ -211,12 +201,19 @@ void VulkanDevice::createInstance()
appInfo.engineVersion = VK_MAKE_VERSION(ENG_MAJOR, ENG_MINOR, ENG_REVISION); appInfo.engineVersion = VK_MAKE_VERSION(ENG_MAJOR, ENG_MINOR, ENG_REVISION);
appInfo.apiVersion = VK_API_VERSION_1_0; appInfo.apiVersion = VK_API_VERSION_1_0;
std::vector<const char *> enabledExtensions = { VK_KHR_SURFACE_EXTENSION_NAME }; std::vector<const char *> enabledExtensions;
#ifdef _WIN32
enabledExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); if (!I_GetVulkanPlatformExtensions(&extensionCount, nullptr))
#else {
assert(!"Add platform-specific surface extension"); throw std::runtime_error("Cannot obtain number of Vulkan extensions");
#endif }
enabledExtensions.resize(extensionCount);
if (!I_GetVulkanPlatformExtensions(&extensionCount, &enabledExtensions[0]))
{
throw std::runtime_error("Cannot obtain list of Vulkan extensions");
}
std::vector<const char*> validationLayers; std::vector<const char*> validationLayers;
std::string debugLayer = "VK_LAYER_LUNARG_standard_validation"; std::string debugLayer = "VK_LAYER_LUNARG_standard_validation";
@ -269,22 +266,10 @@ void VulkanDevice::createInstance()
void VulkanDevice::createSurface() void VulkanDevice::createSurface()
{ {
#ifdef _WIN32 if (!I_CreateVulkanSurface(instance, &surface))
VkWin32SurfaceCreateInfoKHR windowCreateInfo; {
windowCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
windowCreateInfo.pNext = nullptr;
windowCreateInfo.flags = 0;
windowCreateInfo.hwnd = Window;
windowCreateInfo.hinstance = GetModuleHandle(nullptr);
VkResult result = vkCreateWin32SurfaceKHR(instance, &windowCreateInfo, nullptr, &surface);
if (result != VK_SUCCESS)
throw std::runtime_error("Could not create vulkan surface"); throw std::runtime_error("Could not create vulkan surface");
#elif defined __APPLE__ }
// todo
#else
// todo
#endif
} }
void VulkanDevice::selectPhysicalDevice() void VulkanDevice::selectPhysicalDevice()

View file

@ -0,0 +1,74 @@
#include <assert.h>
#ifdef _WIN32
#define VK_USE_PLATFORM_WIN32_KHR
#endif
#include "volk/volk.h"
extern HWND Window;
void I_GetVulkanDrawableSize(int *width, int *height)
{
assert(Window);
RECT clientRect = { 0 };
GetClientRect(Window, &clientRect);
if (width != nullptr)
{
*width = clientRect.right;
}
if (height != nullptr)
{
*height = clientRect.bottom;
}
}
bool I_GetVulkanPlatformExtensions(unsigned int *count, const char **names)
{
static const char* extensions[] =
{
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
};
static const unsigned int extensionCount = static_cast<unsigned int>(sizeof extensions / sizeof extensions[0]);
if (count == nullptr && names == nullptr)
{
return false;
}
else if (names == nullptr)
{
*count = extensionCount;
return true;
}
else
{
const bool result = *count >= extensionCount;
*count = min(*count, extensionCount);
for (unsigned int i = 0; i < *count; ++i)
{
names[i] = extensions[i];
}
return result;
}
}
bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface)
{
VkWin32SurfaceCreateInfoKHR windowCreateInfo;
windowCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
windowCreateInfo.pNext = nullptr;
windowCreateInfo.flags = 0;
windowCreateInfo.hwnd = Window;
windowCreateInfo.hinstance = GetModuleHandle(nullptr);
const VkResult result = vkCreateWin32SurfaceKHR(instance, &windowCreateInfo, nullptr, surface);
return result == VK_SUCCESS;
}