Fallback flow for graphics APIs

This commit is contained in:
Jack Andersen 2016-07-20 07:14:18 -10:00
parent 1c8236d100
commit 66c64cde08
7 changed files with 150 additions and 120 deletions

View File

@ -45,7 +45,7 @@ public:
virtual EGraphicsAPI getAPI() const=0; virtual EGraphicsAPI getAPI() const=0;
virtual EPixelFormat getPixelFormat() const=0; virtual EPixelFormat getPixelFormat() const=0;
virtual void setPixelFormat(EPixelFormat pf)=0; virtual void setPixelFormat(EPixelFormat pf)=0;
virtual void initializeContext(void* handle)=0; virtual bool initializeContext(void* handle)=0;
virtual void makeCurrent()=0; virtual void makeCurrent()=0;
virtual void postInit()=0; virtual void postInit()=0;
virtual void present()=0; virtual void present()=0;

View File

@ -74,7 +74,7 @@ struct VulkanContext
std::unordered_map<const boo::IWindow*, std::unique_ptr<Window>> m_windows; std::unordered_map<const boo::IWindow*, std::unique_ptr<Window>> m_windows;
void initVulkan(const char* appName); void initVulkan(const char* appName);
void enumerateDevices(); bool enumerateDevices();
void initDevice(); void initDevice();
void initSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace); void initSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace);
void resizeSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace); void resizeSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace);

View File

@ -342,26 +342,32 @@ void VulkanContext::initVulkan(const char* appName)
#endif #endif
} }
void VulkanContext::enumerateDevices() bool VulkanContext::enumerateDevices()
{ {
uint32_t gpuCount = 1; uint32_t gpuCount = 1;
ThrowIfFailed(vk::EnumeratePhysicalDevices(m_instance, &gpuCount, nullptr)); ThrowIfFailed(vk::EnumeratePhysicalDevices(m_instance, &gpuCount, nullptr));
assert(gpuCount); if (!gpuCount)
return false;
m_gpus.resize(gpuCount); m_gpus.resize(gpuCount);
ThrowIfFailed(vk::EnumeratePhysicalDevices(m_instance, &gpuCount, m_gpus.data())); ThrowIfFailed(vk::EnumeratePhysicalDevices(m_instance, &gpuCount, m_gpus.data()));
assert(gpuCount >= 1); if (!gpuCount)
return false;
vk::GetPhysicalDeviceQueueFamilyProperties(m_gpus[0], &m_queueCount, nullptr); vk::GetPhysicalDeviceQueueFamilyProperties(m_gpus[0], &m_queueCount, nullptr);
assert(m_queueCount >= 1); if (!m_queueCount)
return false;
m_queueProps.resize(m_queueCount); m_queueProps.resize(m_queueCount);
vk::GetPhysicalDeviceQueueFamilyProperties(m_gpus[0], &m_queueCount, m_queueProps.data()); vk::GetPhysicalDeviceQueueFamilyProperties(m_gpus[0], &m_queueCount, m_queueProps.data());
assert(m_queueCount >= 1); if (!m_queueCount)
return false;
/* This is as good a place as any to do this */ /* This is as good a place as any to do this */
vk::GetPhysicalDeviceMemoryProperties(m_gpus[0], &m_memoryProperties); vk::GetPhysicalDeviceMemoryProperties(m_gpus[0], &m_memoryProperties);
vk::GetPhysicalDeviceProperties(m_gpus[0], &m_gpuProps); vk::GetPhysicalDeviceProperties(m_gpus[0], &m_gpuProps);
return true;
} }
void VulkanContext::initDevice() void VulkanContext::initDevice()

View File

@ -219,7 +219,7 @@ public:
m_pf = pf; m_pf = pf;
} }
void initializeContext(void*) bool initializeContext(void*)
{ {
m_nsContext = [[GraphicsContextCocoaGLInternal alloc] initWithBooContext:this]; m_nsContext = [[GraphicsContextCocoaGLInternal alloc] initWithBooContext:this];
if (!m_nsContext) if (!m_nsContext)
@ -229,6 +229,7 @@ public:
CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this); CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this);
CVDisplayLinkStart(m_dispLink); CVDisplayLinkStart(m_dispLink);
m_commandQueue = _NewGLCommandQueue(this); m_commandQueue = _NewGLCommandQueue(this);
return true;
} }
void makeCurrent() void makeCurrent()
@ -375,7 +376,7 @@ public:
m_pf = pf; m_pf = pf;
} }
void initializeContext(void*) bool initializeContext(void*)
{ {
MetalContext::Window& w = m_metalCtx->m_windows[m_parentWindow]; MetalContext::Window& w = m_metalCtx->m_windows[m_parentWindow];
m_nsContext = [[GraphicsContextCocoaMetalInternal alloc] initWithBooContext:this]; m_nsContext = [[GraphicsContextCocoaMetalInternal alloc] initWithBooContext:this];
@ -387,6 +388,7 @@ public:
CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this); CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this);
CVDisplayLinkStart(m_dispLink); CVDisplayLinkStart(m_dispLink);
m_commandQueue = _NewMetalCommandQueue(m_metalCtx, m_parentWindow, this); m_commandQueue = _NewMetalCommandQueue(m_metalCtx, m_parentWindow, this);
return true;
} }
void makeCurrent() void makeCurrent()

View File

@ -164,7 +164,7 @@ public:
m_pf = pf; m_pf = pf;
} }
void initializeContext(void*) {} bool initializeContext(void*) {return true;}
void makeCurrent() {} void makeCurrent() {}
@ -305,7 +305,7 @@ public:
m_pf = pf; m_pf = pf;
} }
void initializeContext(void*) {} bool initializeContext(void*) {return true;}
void makeCurrent() void makeCurrent()
{ {
@ -487,7 +487,7 @@ public:
m_pf = pf; m_pf = pf;
} }
void initializeContext(void* getVkProc) bool initializeContext(void* getVkProc)
{ {
vk::init_dispatch_table_top(PFN_vkGetInstanceProcAddr(getVkProc)); vk::init_dispatch_table_top(PFN_vkGetInstanceProcAddr(getVkProc));
if (m_ctx->m_instance == VK_NULL_HANDLE) if (m_ctx->m_instance == VK_NULL_HANDLE)
@ -500,7 +500,8 @@ public:
} }
vk::init_dispatch_table_middle(m_ctx->m_instance, false); vk::init_dispatch_table_middle(m_ctx->m_instance, false);
m_ctx->enumerateDevices(); if (!m_ctx->enumerateDevices())
return false;
m_windowCtx = m_windowCtx =
m_ctx->m_windows.emplace(std::make_pair(m_parentWindow, m_ctx->m_windows.emplace(std::make_pair(m_parentWindow,
@ -554,7 +555,7 @@ public:
if (!vk::GetPhysicalDeviceWin32PresentationSupportKHR(m_ctx->m_gpus[0], m_ctx->m_graphicsQueueFamilyIndex)) if (!vk::GetPhysicalDeviceWin32PresentationSupportKHR(m_ctx->m_gpus[0], m_ctx->m_graphicsQueueFamilyIndex))
{ {
Log.report(logvisor::Fatal, "Win32 doesn't support vulkan present"); Log.report(logvisor::Fatal, "Win32 doesn't support vulkan present");
return; return false;
} }
/* Get the list of VkFormats that are supported */ /* Get the list of VkFormats that are supported */
@ -582,6 +583,7 @@ public:
m_dataFactory = new class VulkanDataFactory(this, m_ctx, m_sampleCount); m_dataFactory = new class VulkanDataFactory(this, m_ctx, m_sampleCount);
m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this); m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this);
return true;
} }
void makeCurrent() {} void makeCurrent() {}
@ -974,8 +976,8 @@ public:
{ {
m_gfxCtx.reset(new GraphicsContextWin32Vulkan(this, wndInstance, m_hwnd, &g_VulkanContext, m_gfxCtx.reset(new GraphicsContextWin32Vulkan(this, wndInstance, m_hwnd, &g_VulkanContext,
b3dCtx, sampleCount)); b3dCtx, sampleCount));
m_gfxCtx->initializeContext(vulkanHandle); if (m_gfxCtx->initializeContext(vulkanHandle))
return; return;
} }
m_gfxCtx.reset(new GraphicsContextWin32D3D(api, this, m_hwnd, b3dCtx, sampleCount)); m_gfxCtx.reset(new GraphicsContextWin32D3D(api, this, m_hwnd, b3dCtx, sampleCount));
} }

View File

@ -50,9 +50,9 @@ public:
m_pf = pf; m_pf = pf;
} }
void initializeContext(void*) bool initializeContext(void*)
{ {
return false;
} }
void makeCurrent() void makeCurrent()

View File

@ -439,7 +439,7 @@ public:
m_pf = pf; m_pf = pf;
} }
void initializeContext(void*) bool initializeContext(void*)
{ {
if (!glXCreateContextAttribsARB) if (!glXCreateContextAttribsARB)
{ {
@ -522,6 +522,8 @@ public:
XUnlockDisplay(m_xDisp); XUnlockDisplay(m_xDisp);
m_commandQueue = _NewGLCommandQueue(this); m_commandQueue = _NewGLCommandQueue(this);
XLockDisplay(m_xDisp); XLockDisplay(m_xDisp);
return true;
} }
void makeCurrent() void makeCurrent()
@ -675,7 +677,7 @@ public:
m_pf = pf; m_pf = pf;
} }
void initializeContext(void* getVkProc) bool initializeContext(void* getVkProc)
{ {
if (!glXWaitVideoSyncSGI) if (!glXWaitVideoSyncSGI)
{ {
@ -690,7 +692,8 @@ public:
m_ctx->initVulkan(APP->getUniqueName().c_str()); m_ctx->initVulkan(APP->getUniqueName().c_str());
vk::init_dispatch_table_middle(m_ctx->m_instance, false); vk::init_dispatch_table_middle(m_ctx->m_instance, false);
m_ctx->enumerateDevices(); if (!m_ctx->enumerateDevices())
return false;
m_windowCtx = m_windowCtx =
m_ctx->m_windows.emplace(std::make_pair(m_parentWindow, m_ctx->m_windows.emplace(std::make_pair(m_parentWindow,
@ -744,7 +747,7 @@ public:
if (!vk::GetPhysicalDeviceXcbPresentationSupportKHR(m_ctx->m_gpus[0], m_ctx->m_graphicsQueueFamilyIndex, m_xcbConn, m_visualid)) if (!vk::GetPhysicalDeviceXcbPresentationSupportKHR(m_ctx->m_gpus[0], m_ctx->m_graphicsQueueFamilyIndex, m_xcbConn, m_visualid))
{ {
Log.report(logvisor::Fatal, "XCB visual doesn't support vulkan present"); Log.report(logvisor::Fatal, "XCB visual doesn't support vulkan present");
return; return false;
} }
/* Get the list of VkFormats that are supported */ /* Get the list of VkFormats that are supported */
@ -817,6 +820,8 @@ public:
m_dataFactory = new class VulkanDataFactory(this, m_ctx, m_drawSamples); m_dataFactory = new class VulkanDataFactory(this, m_ctx, m_drawSamples);
m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this); m_commandQueue = _NewVulkanCommandQueue(m_ctx, m_ctx->m_windows[m_parentWindow].get(), this);
return true;
} }
void makeCurrent() {} void makeCurrent() {}
@ -916,108 +921,123 @@ public:
if (!S_ATOMS) if (!S_ATOMS)
S_ATOMS = new XlibAtoms(display); S_ATOMS = new XlibAtoms(display);
for (int i = 1; i >= 0 ; --i)
{
#if BOO_HAS_VULKAN #if BOO_HAS_VULKAN
if (vulkanHandle) if (vulkanHandle && i == 1)
m_gfxCtx.reset(new GraphicsContextXlibVulkan(this, display, (xcb_connection_t*)xcbConn, defaultScreen,
&g_VulkanContext, m_visualId, drawSamples));
else
#endif
m_gfxCtx.reset(new GraphicsContextXlibGLX(IGraphicsContext::EGraphicsAPI::OpenGL3_3,
this, display, defaultScreen, lastCtx, m_visualId, drawSamples));
/* Default screen */
Screen* screen = ScreenOfDisplay(display, defaultScreen);
m_pixelFactor = screen->width / (float)screen->mwidth / REF_DPMM;
XVisualInfo visTemplate;
visTemplate.screen = defaultScreen;
int numVisuals;
XVisualInfo* visualList = XGetVisualInfo(display, VisualScreenMask, &visTemplate, &numVisuals);
Visual* selectedVisual = nullptr;
for (int i=0 ; i<numVisuals ; ++i)
{
if (visualList[i].visualid == m_visualId)
{ {
selectedVisual = visualList[i].visual; m_gfxCtx.reset(new GraphicsContextXlibVulkan(this, display, (xcb_connection_t*)xcbConn, defaultScreen,
break; &g_VulkanContext, m_visualId, drawSamples));
} }
else
#endif
{
i = 0;
m_gfxCtx.reset(new GraphicsContextXlibGLX(IGraphicsContext::EGraphicsAPI::OpenGL3_3,
this, display, defaultScreen, lastCtx, m_visualId, drawSamples));
}
/* Default screen */
Screen* screen = ScreenOfDisplay(display, defaultScreen);
m_pixelFactor = screen->width / (float)screen->mwidth / REF_DPMM;
XVisualInfo visTemplate;
visTemplate.screen = defaultScreen;
int numVisuals;
XVisualInfo* visualList = XGetVisualInfo(display, VisualScreenMask, &visTemplate, &numVisuals);
Visual* selectedVisual = nullptr;
for (int i=0 ; i<numVisuals ; ++i)
{
if (visualList[i].visualid == m_visualId)
{
selectedVisual = visualList[i].visual;
break;
}
}
XFree(visualList);
/* Create colormap */
m_colormapId = XCreateColormap(m_xDisp, screen->root, selectedVisual, AllocNone);
/* Create window */
int x, y, w, h;
genFrameDefault(screen, x, y, w, h);
XSetWindowAttributes swa;
swa.colormap = m_colormapId;
swa.border_pixmap = 0;
swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask | LeaveWindowMask | EnterWindowMask;
m_windowId = XCreateWindow(display, screen->root, x, y, w, h, 10,
CopyFromParent, CopyFromParent, selectedVisual,
CWBorderPixel | CWEventMask | CWColormap, &swa);
/*
* Now go create an IC using the style we chose.
* Also set the window and fontset attributes now.
*/
if (xIM)
{
XPoint pt = {0,0};
XVaNestedList nlist;
m_xIC = XCreateIC(xIM, XNInputStyle, bestInputStyle,
XNClientWindow, m_windowId,
XNFocusWindow, m_windowId,
XNPreeditAttributes, nlist = XVaCreateNestedList(0,
XNSpotLocation, &pt,
XNFontSet, fontset,
nullptr),
nullptr);
XFree(nlist);
long im_event_mask;
XGetICValues(m_xIC, XNFilterEvents, &im_event_mask, nullptr);
XSelectInput(display, m_windowId, swa.event_mask | im_event_mask);
XSetICFocus(m_xIC);
}
/* The XInput 2.1 extension enables per-pixel smooth scrolling trackpads */
XIEventMask mask = {XIAllMasterDevices, XIMaskLen(XI_LASTEVENT)};
mask.mask = (unsigned char*)malloc(mask.mask_len);
memset(mask.mask, 0, mask.mask_len);
/* XISetMask(mask.mask, XI_Motion); Can't do this without losing mouse move events :( */
XISetMask(mask.mask, XI_TouchBegin);
XISetMask(mask.mask, XI_TouchUpdate);
XISetMask(mask.mask, XI_TouchEnd);
XISelectEvents(m_xDisp, m_windowId, &mask, 1);
free(mask.mask);
/* Register netwm extension atom for window closing */
XSetWMProtocols(m_xDisp, m_windowId, &S_ATOMS->m_wmDeleteWindow, 1);
/* Set the title of the window */
const unsigned char* c_title = (unsigned char*)title.c_str();
XChangeProperty(m_xDisp, m_windowId, XA_WM_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length());
/* Set the title of the window icon */
XChangeProperty(m_xDisp, m_windowId, XA_WM_ICON_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length());
/* Add window icon */
if (MAINICON_NETWM_SZ && S_ATOMS->m_netwmIcon)
{
XChangeProperty(display, m_windowId, S_ATOMS->m_netwmIcon, XA_CARDINAL,
32, PropModeReplace, MAINICON_NETWM, MAINICON_NETWM_SZ / sizeof(unsigned long));
}
/* Initialize context */
XMapWindow(m_xDisp, m_windowId);
setStyle(EWindowStyle::Default);
setCursor(EMouseCursor::Pointer);
XFlush(m_xDisp);
if (!m_gfxCtx->initializeContext(vulkanHandle))
{
XUnmapWindow(m_xDisp, m_windowId);
XDestroyWindow(m_xDisp, m_windowId);
XFreeColormap(m_xDisp, m_colormapId);
continue;
}
break;
} }
XFree(visualList);
/* Create colormap */
m_colormapId = XCreateColormap(m_xDisp, screen->root, selectedVisual, AllocNone);
/* Create window */
int x, y, w, h;
genFrameDefault(screen, x, y, w, h);
XSetWindowAttributes swa;
swa.colormap = m_colormapId;
swa.border_pixmap = 0;
swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask | LeaveWindowMask | EnterWindowMask;
m_windowId = XCreateWindow(display, screen->root, x, y, w, h, 10,
CopyFromParent, CopyFromParent, selectedVisual,
CWBorderPixel | CWEventMask | CWColormap, &swa);
/*
* Now go create an IC using the style we chose.
* Also set the window and fontset attributes now.
*/
if (xIM)
{
XPoint pt = {0,0};
XVaNestedList nlist;
m_xIC = XCreateIC(xIM, XNInputStyle, bestInputStyle,
XNClientWindow, m_windowId,
XNFocusWindow, m_windowId,
XNPreeditAttributes, nlist = XVaCreateNestedList(0,
XNSpotLocation, &pt,
XNFontSet, fontset,
nullptr),
nullptr);
XFree(nlist);
long im_event_mask;
XGetICValues(m_xIC, XNFilterEvents, &im_event_mask, nullptr);
XSelectInput(display, m_windowId, swa.event_mask | im_event_mask);
XSetICFocus(m_xIC);
}
/* The XInput 2.1 extension enables per-pixel smooth scrolling trackpads */
XIEventMask mask = {XIAllMasterDevices, XIMaskLen(XI_LASTEVENT)};
mask.mask = (unsigned char*)malloc(mask.mask_len);
memset(mask.mask, 0, mask.mask_len);
/* XISetMask(mask.mask, XI_Motion); Can't do this without losing mouse move events :( */
XISetMask(mask.mask, XI_TouchBegin);
XISetMask(mask.mask, XI_TouchUpdate);
XISetMask(mask.mask, XI_TouchEnd);
XISelectEvents(m_xDisp, m_windowId, &mask, 1);
free(mask.mask);
/* Register netwm extension atom for window closing */
XSetWMProtocols(m_xDisp, m_windowId, &S_ATOMS->m_wmDeleteWindow, 1);
/* Set the title of the window */
const unsigned char* c_title = (unsigned char*)title.c_str();
XChangeProperty(m_xDisp, m_windowId, XA_WM_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length());
/* Set the title of the window icon */
XChangeProperty(m_xDisp, m_windowId, XA_WM_ICON_NAME, XA_STRING, 8, PropModeReplace, c_title, title.length());
/* Add window icon */
if (MAINICON_NETWM_SZ && S_ATOMS->m_netwmIcon)
{
XChangeProperty(display, m_windowId, S_ATOMS->m_netwmIcon, XA_CARDINAL,
32, PropModeReplace, MAINICON_NETWM, MAINICON_NETWM_SZ / sizeof(unsigned long));
}
/* Initialize context */
XMapWindow(m_xDisp, m_windowId);
setStyle(EWindowStyle::Default);
setCursor(EMouseCursor::Pointer);
XFlush(m_xDisp);
m_gfxCtx->initializeContext(vulkanHandle);
} }
~WindowXlib() ~WindowXlib()