glfw/src/null_window.c
Camilla Löwy 738dd6ff1d Null: Add limited EGL context creation on Mesa
This provides very limited support for context creation via EGL on the
Null platform.  It supports Unix-like systems with a version of Mesa
that provides EGL_MESA_platform_surfaceless.

Even then, the actual framebuffer provided is not resized along with the
'window'.  That will hopefully change once context and framebuffer
creation are separated, but this commit should at least allow more
applications than before to run on the Null platform.
2024-03-28 16:53:04 +01:00

750 lines
19 KiB
C

//========================================================================
// GLFW 3.5 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <stdlib.h>
#include <string.h>
static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
{
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
{
const float ratio = (float) window->numer / (float) window->denom;
*height = (int) (*width / ratio);
}
if (window->minwidth != GLFW_DONT_CARE)
*width = _glfw_max(*width, window->minwidth);
else if (window->maxwidth != GLFW_DONT_CARE)
*width = _glfw_min(*width, window->maxwidth);
if (window->minheight != GLFW_DONT_CARE)
*height = _glfw_min(*height, window->minheight);
else if (window->maxheight != GLFW_DONT_CARE)
*height = _glfw_max(*height, window->maxheight);
}
static void fitToMonitor(_GLFWwindow* window)
{
GLFWvidmode mode;
_glfwGetVideoModeNull(window->monitor, &mode);
_glfwGetMonitorPosNull(window->monitor,
&window->null.xpos,
&window->null.ypos);
window->null.width = mode.width;
window->null.height = mode.height;
}
static void acquireMonitor(_GLFWwindow* window)
{
_glfwInputMonitorWindow(window->monitor, window);
}
static void releaseMonitor(_GLFWwindow* window)
{
if (window->monitor->window != window)
return;
_glfwInputMonitorWindow(window->monitor, NULL);
}
static int createNativeWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWfbconfig* fbconfig)
{
if (window->monitor)
fitToMonitor(window);
else
{
if (wndconfig->xpos == GLFW_ANY_POSITION && wndconfig->ypos == GLFW_ANY_POSITION)
{
window->null.xpos = 17;
window->null.ypos = 17;
}
else
{
window->null.xpos = wndconfig->xpos;
window->null.ypos = wndconfig->ypos;
}
window->null.width = wndconfig->width;
window->null.height = wndconfig->height;
}
window->null.visible = wndconfig->visible;
window->null.decorated = wndconfig->decorated;
window->null.maximized = wndconfig->maximized;
window->null.floating = wndconfig->floating;
window->null.transparent = fbconfig->transparent;
window->null.opacity = 1.f;
return GLFW_TRUE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwCreateWindowNull(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (!createNativeWindow(window, wndconfig, fbconfig))
return GLFW_FALSE;
if (ctxconfig->client != GLFW_NO_API)
{
if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API ||
ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
{
if (!_glfwInitOSMesa())
return GLFW_FALSE;
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
else if (ctxconfig->source == GLFW_EGL_CONTEXT_API)
{
if (!_glfwInitEGL())
return GLFW_FALSE;
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
}
if (wndconfig->mousePassthrough)
_glfwSetWindowMousePassthroughNull(window, GLFW_TRUE);
if (window->monitor)
{
_glfwShowWindowNull(window);
_glfwFocusWindowNull(window);
acquireMonitor(window);
if (wndconfig->centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig->visible)
{
_glfwShowWindowNull(window);
if (wndconfig->focused)
_glfwFocusWindowNull(window);
}
}
return GLFW_TRUE;
}
void _glfwDestroyWindowNull(_GLFWwindow* window)
{
if (window->monitor)
releaseMonitor(window);
if (_glfw.null.focusedWindow == window)
_glfw.null.focusedWindow = NULL;
if (window->context.destroy)
window->context.destroy(window);
}
void _glfwSetWindowTitleNull(_GLFWwindow* window, const char* title)
{
}
void _glfwSetWindowIconNull(_GLFWwindow* window, int count, const GLFWimage* images)
{
}
void _glfwSetWindowMonitorNull(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,
int width, int height,
int refreshRate)
{
if (window->monitor == monitor)
{
if (!monitor)
{
_glfwSetWindowPosNull(window, xpos, ypos);
_glfwSetWindowSizeNull(window, width, height);
}
return;
}
if (window->monitor)
releaseMonitor(window);
_glfwInputWindowMonitor(window, monitor);
if (window->monitor)
{
window->null.visible = GLFW_TRUE;
acquireMonitor(window);
fitToMonitor(window);
}
else
{
_glfwSetWindowPosNull(window, xpos, ypos);
_glfwSetWindowSizeNull(window, width, height);
}
}
void _glfwGetWindowPosNull(_GLFWwindow* window, int* xpos, int* ypos)
{
if (xpos)
*xpos = window->null.xpos;
if (ypos)
*ypos = window->null.ypos;
}
void _glfwSetWindowPosNull(_GLFWwindow* window, int xpos, int ypos)
{
if (window->monitor)
return;
if (window->null.xpos != xpos || window->null.ypos != ypos)
{
window->null.xpos = xpos;
window->null.ypos = ypos;
_glfwInputWindowPos(window, xpos, ypos);
}
}
void _glfwGetWindowSizeNull(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->null.width;
if (height)
*height = window->null.height;
}
void _glfwSetWindowSizeNull(_GLFWwindow* window, int width, int height)
{
if (window->monitor)
return;
if (window->null.width != width || window->null.height != height)
{
window->null.width = width;
window->null.height = height;
_glfwInputFramebufferSize(window, width, height);
_glfwInputWindowDamage(window);
_glfwInputWindowSize(window, width, height);
}
}
void _glfwSetWindowSizeLimitsNull(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight)
{
int width = window->null.width;
int height = window->null.height;
applySizeLimits(window, &width, &height);
_glfwSetWindowSizeNull(window, width, height);
}
void _glfwSetWindowAspectRatioNull(_GLFWwindow* window, int n, int d)
{
int width = window->null.width;
int height = window->null.height;
applySizeLimits(window, &width, &height);
_glfwSetWindowSizeNull(window, width, height);
}
void _glfwGetFramebufferSizeNull(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->null.width;
if (height)
*height = window->null.height;
}
void _glfwGetWindowFrameSizeNull(_GLFWwindow* window,
int* left, int* top,
int* right, int* bottom)
{
if (window->null.decorated && !window->monitor)
{
if (left)
*left = 1;
if (top)
*top = 10;
if (right)
*right = 1;
if (bottom)
*bottom = 1;
}
else
{
if (left)
*left = 0;
if (top)
*top = 0;
if (right)
*right = 0;
if (bottom)
*bottom = 0;
}
}
void _glfwGetWindowContentScaleNull(_GLFWwindow* window, float* xscale, float* yscale)
{
if (xscale)
*xscale = 1.f;
if (yscale)
*yscale = 1.f;
}
void _glfwIconifyWindowNull(_GLFWwindow* window)
{
if (_glfw.null.focusedWindow == window)
{
_glfw.null.focusedWindow = NULL;
_glfwInputWindowFocus(window, GLFW_FALSE);
}
if (!window->null.iconified)
{
window->null.iconified = GLFW_TRUE;
_glfwInputWindowIconify(window, GLFW_TRUE);
if (window->monitor)
releaseMonitor(window);
}
}
void _glfwRestoreWindowNull(_GLFWwindow* window)
{
if (window->null.iconified)
{
window->null.iconified = GLFW_FALSE;
_glfwInputWindowIconify(window, GLFW_FALSE);
if (window->monitor)
acquireMonitor(window);
}
else if (window->null.maximized)
{
window->null.maximized = GLFW_FALSE;
_glfwInputWindowMaximize(window, GLFW_FALSE);
}
}
void _glfwMaximizeWindowNull(_GLFWwindow* window)
{
if (!window->null.maximized)
{
window->null.maximized = GLFW_TRUE;
_glfwInputWindowMaximize(window, GLFW_TRUE);
}
}
GLFWbool _glfwWindowMaximizedNull(_GLFWwindow* window)
{
return window->null.maximized;
}
GLFWbool _glfwWindowHoveredNull(_GLFWwindow* window)
{
return _glfw.null.xcursor >= window->null.xpos &&
_glfw.null.ycursor >= window->null.ypos &&
_glfw.null.xcursor <= window->null.xpos + window->null.width - 1 &&
_glfw.null.ycursor <= window->null.ypos + window->null.height - 1;
}
GLFWbool _glfwFramebufferTransparentNull(_GLFWwindow* window)
{
return window->null.transparent;
}
void _glfwSetWindowResizableNull(_GLFWwindow* window, GLFWbool enabled)
{
window->null.resizable = enabled;
}
void _glfwSetWindowDecoratedNull(_GLFWwindow* window, GLFWbool enabled)
{
window->null.decorated = enabled;
}
void _glfwSetWindowFloatingNull(_GLFWwindow* window, GLFWbool enabled)
{
window->null.floating = enabled;
}
void _glfwSetWindowMousePassthroughNull(_GLFWwindow* window, GLFWbool enabled)
{
}
float _glfwGetWindowOpacityNull(_GLFWwindow* window)
{
return window->null.opacity;
}
void _glfwSetWindowOpacityNull(_GLFWwindow* window, float opacity)
{
window->null.opacity = opacity;
}
void _glfwSetRawMouseMotionNull(_GLFWwindow *window, GLFWbool enabled)
{
}
GLFWbool _glfwRawMouseMotionSupportedNull(void)
{
return GLFW_TRUE;
}
void _glfwShowWindowNull(_GLFWwindow* window)
{
window->null.visible = GLFW_TRUE;
}
void _glfwRequestWindowAttentionNull(_GLFWwindow* window)
{
}
void _glfwHideWindowNull(_GLFWwindow* window)
{
if (_glfw.null.focusedWindow == window)
{
_glfw.null.focusedWindow = NULL;
_glfwInputWindowFocus(window, GLFW_FALSE);
}
window->null.visible = GLFW_FALSE;
}
void _glfwFocusWindowNull(_GLFWwindow* window)
{
_GLFWwindow* previous;
if (_glfw.null.focusedWindow == window)
return;
if (!window->null.visible)
return;
previous = _glfw.null.focusedWindow;
_glfw.null.focusedWindow = window;
if (previous)
{
_glfwInputWindowFocus(previous, GLFW_FALSE);
if (previous->monitor && previous->autoIconify)
_glfwIconifyWindowNull(previous);
}
_glfwInputWindowFocus(window, GLFW_TRUE);
}
GLFWbool _glfwWindowFocusedNull(_GLFWwindow* window)
{
return _glfw.null.focusedWindow == window;
}
GLFWbool _glfwWindowIconifiedNull(_GLFWwindow* window)
{
return window->null.iconified;
}
GLFWbool _glfwWindowVisibleNull(_GLFWwindow* window)
{
return window->null.visible;
}
void _glfwPollEventsNull(void)
{
}
void _glfwWaitEventsNull(void)
{
}
void _glfwWaitEventsTimeoutNull(double timeout)
{
}
void _glfwPostEmptyEventNull(void)
{
}
void _glfwGetCursorPosNull(_GLFWwindow* window, double* xpos, double* ypos)
{
if (xpos)
*xpos = _glfw.null.xcursor - window->null.xpos;
if (ypos)
*ypos = _glfw.null.ycursor - window->null.ypos;
}
void _glfwSetCursorPosNull(_GLFWwindow* window, double x, double y)
{
_glfw.null.xcursor = window->null.xpos + (int) x;
_glfw.null.ycursor = window->null.ypos + (int) y;
}
void _glfwSetCursorModeNull(_GLFWwindow* window, int mode)
{
}
GLFWbool _glfwCreateCursorNull(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
{
return GLFW_TRUE;
}
GLFWbool _glfwCreateStandardCursorNull(_GLFWcursor* cursor, int shape)
{
return GLFW_TRUE;
}
void _glfwDestroyCursorNull(_GLFWcursor* cursor)
{
}
void _glfwSetCursorNull(_GLFWwindow* window, _GLFWcursor* cursor)
{
}
void _glfwSetClipboardStringNull(const char* string)
{
char* copy = _glfw_strdup(string);
_glfw_free(_glfw.null.clipboardString);
_glfw.null.clipboardString = copy;
}
const char* _glfwGetClipboardStringNull(void)
{
return _glfw.null.clipboardString;
}
EGLenum _glfwGetEGLPlatformNull(EGLint** attribs)
{
if (_glfw.egl.EXT_platform_base && _glfw.egl.MESA_platform_surfaceless)
return EGL_PLATFORM_SURFACELESS_MESA;
else
return 0;
}
EGLNativeDisplayType _glfwGetEGLNativeDisplayNull(void)
{
return EGL_DEFAULT_DISPLAY;
}
EGLNativeWindowType _glfwGetEGLNativeWindowNull(_GLFWwindow* window)
{
return 0;
}
const char* _glfwGetScancodeNameNull(int scancode)
{
if (scancode < GLFW_NULL_SC_FIRST || scancode > GLFW_NULL_SC_LAST)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode);
return NULL;
}
switch (scancode)
{
case GLFW_NULL_SC_APOSTROPHE:
return "'";
case GLFW_NULL_SC_COMMA:
return ",";
case GLFW_NULL_SC_MINUS:
case GLFW_NULL_SC_KP_SUBTRACT:
return "-";
case GLFW_NULL_SC_PERIOD:
case GLFW_NULL_SC_KP_DECIMAL:
return ".";
case GLFW_NULL_SC_SLASH:
case GLFW_NULL_SC_KP_DIVIDE:
return "/";
case GLFW_NULL_SC_SEMICOLON:
return ";";
case GLFW_NULL_SC_EQUAL:
case GLFW_NULL_SC_KP_EQUAL:
return "=";
case GLFW_NULL_SC_LEFT_BRACKET:
return "[";
case GLFW_NULL_SC_RIGHT_BRACKET:
return "]";
case GLFW_NULL_SC_KP_MULTIPLY:
return "*";
case GLFW_NULL_SC_KP_ADD:
return "+";
case GLFW_NULL_SC_BACKSLASH:
case GLFW_NULL_SC_WORLD_1:
case GLFW_NULL_SC_WORLD_2:
return "\\";
case GLFW_NULL_SC_0:
case GLFW_NULL_SC_KP_0:
return "0";
case GLFW_NULL_SC_1:
case GLFW_NULL_SC_KP_1:
return "1";
case GLFW_NULL_SC_2:
case GLFW_NULL_SC_KP_2:
return "2";
case GLFW_NULL_SC_3:
case GLFW_NULL_SC_KP_3:
return "3";
case GLFW_NULL_SC_4:
case GLFW_NULL_SC_KP_4:
return "4";
case GLFW_NULL_SC_5:
case GLFW_NULL_SC_KP_5:
return "5";
case GLFW_NULL_SC_6:
case GLFW_NULL_SC_KP_6:
return "6";
case GLFW_NULL_SC_7:
case GLFW_NULL_SC_KP_7:
return "7";
case GLFW_NULL_SC_8:
case GLFW_NULL_SC_KP_8:
return "8";
case GLFW_NULL_SC_9:
case GLFW_NULL_SC_KP_9:
return "9";
case GLFW_NULL_SC_A:
return "a";
case GLFW_NULL_SC_B:
return "b";
case GLFW_NULL_SC_C:
return "c";
case GLFW_NULL_SC_D:
return "d";
case GLFW_NULL_SC_E:
return "e";
case GLFW_NULL_SC_F:
return "f";
case GLFW_NULL_SC_G:
return "g";
case GLFW_NULL_SC_H:
return "h";
case GLFW_NULL_SC_I:
return "i";
case GLFW_NULL_SC_J:
return "j";
case GLFW_NULL_SC_K:
return "k";
case GLFW_NULL_SC_L:
return "l";
case GLFW_NULL_SC_M:
return "m";
case GLFW_NULL_SC_N:
return "n";
case GLFW_NULL_SC_O:
return "o";
case GLFW_NULL_SC_P:
return "p";
case GLFW_NULL_SC_Q:
return "q";
case GLFW_NULL_SC_R:
return "r";
case GLFW_NULL_SC_S:
return "s";
case GLFW_NULL_SC_T:
return "t";
case GLFW_NULL_SC_U:
return "u";
case GLFW_NULL_SC_V:
return "v";
case GLFW_NULL_SC_W:
return "w";
case GLFW_NULL_SC_X:
return "x";
case GLFW_NULL_SC_Y:
return "y";
case GLFW_NULL_SC_Z:
return "z";
}
return NULL;
}
int _glfwGetKeyScancodeNull(int key)
{
return _glfw.null.scancodes[key];
}
void _glfwGetRequiredInstanceExtensionsNull(char** extensions)
{
if (!_glfw.vk.KHR_surface || !_glfw.vk.EXT_headless_surface)
return;
extensions[0] = "VK_KHR_surface";
extensions[1] = "VK_EXT_headless_surface";
}
GLFWbool _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
return GLFW_TRUE;
}
VkResult _glfwCreateWindowSurfaceNull(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
PFN_vkCreateHeadlessSurfaceEXT vkCreateHeadlessSurfaceEXT =
(PFN_vkCreateHeadlessSurfaceEXT)
vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT");
if (!vkCreateHeadlessSurfaceEXT)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Null: Vulkan instance missing VK_EXT_headless_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
VkHeadlessSurfaceCreateInfoEXT sci;
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT;
const VkResult err = vkCreateHeadlessSurfaceEXT(instance, &sci, allocator, surface);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Null: Failed to create Vulkan surface: %s",
_glfwGetVulkanResultString(err));
}
return err;
}