This commit is contained in:
Doug Binks 2025-02-11 16:17:59 +00:00 committed by GitHub
commit 481f83d218
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 1124 additions and 93 deletions

View File

@ -121,6 +121,9 @@ information on what to include when reporting a bug.
## Changelog since 3.4 ## Changelog since 3.4
- Added OpenGL and OpenGL ES user contexts for multiple window contexts via
`GLFWusercontext`, `glfwCreateUserContext`, `glfwDestroyUserContext`,
`glfwMakeUserContextCurrent`, `glfwGetCurrentUserContext` (#1687,#1870)
- Added `GLFW_UNLIMITED_MOUSE_BUTTONS` input mode that allows mouse buttons beyond - Added `GLFW_UNLIMITED_MOUSE_BUTTONS` input mode that allows mouse buttons beyond
the limit of the mouse button tokens to be reported (#2423) the limit of the mouse button tokens to be reported (#2423)
- Updated minimum CMake version to 3.16 (#2541) - Updated minimum CMake version to 3.16 (#2541)
@ -135,7 +138,6 @@ information on what to include when reporting a bug.
- [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to - [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to
`GLFW_NATIVE_CONTEXT_API` (#2518) `GLFW_NATIVE_CONTEXT_API` (#2518)
## Contact ## Contact
On [glfw.org](https://www.glfw.org/) you can find the latest version of GLFW, as On [glfw.org](https://www.glfw.org/) you can find the latest version of GLFW, as

View File

@ -91,6 +91,28 @@ You can disable context creation by setting the
Windows without contexts should not be passed to @ref glfwMakeContextCurrent or Windows without contexts should not be passed to @ref glfwMakeContextCurrent or
@ref glfwSwapBuffers. Doing this generates a @ref GLFW_NO_WINDOW_CONTEXT error. @ref glfwSwapBuffers. Doing this generates a @ref GLFW_NO_WINDOW_CONTEXT error.
@subsection context_user User contexts for multi context windows
GLFW supports multiple OpenGL or OpenGL ES contexts per window. Providing
a window with an existing OpenGL or OpenGL ES context has been created further
user contexts can be created using @ref glfwCreateUserContext with the same
API sharing the window context objects.
@code
GLFWusercontext* usercontext = glfwCreateUserContext(window);
/* make the user context current */
glfwMakeUserContextCurrent(usercontext);
/* make the window context current */
glfwMakeContextCurrent(window);
/* destroy the user context */
glfwDestroyUserContext(usercontext);
@endcode
User contexts See also the test program `usercontext`.
## Current context {#context_current} ## Current context {#context_current}
@ -121,6 +143,26 @@ error.
- @ref glfwExtensionSupported - @ref glfwExtensionSupported
- @ref glfwGetProcAddress - @ref glfwGetProcAddress
@subsection context_current_user Current user context
When using [user contexts](@ref context_user) the user context can be
made current using @ref glfwMakeUserContextCurrent.
@code
glfwMakeUserContextCurrent(usercontext);
@endcode
This makes the any window context non-current on the calling thread, such that
a call to @ref glfwGetCurrentContext will return `NULL`.
The current user context is returned by @ref glfwGetCurrentUserContext.
@code
GLFWusercontext* usercontext = glfwGetCurrentUserContext();
@endcode
This will return the current user context or `NULL` if either the main window context
or no context is current.
## Buffer swapping {#context_swap} ## Buffer swapping {#context_swap}

View File

@ -5,6 +5,15 @@
## New features {#features} ## New features {#features}
### Multiple window contexts {#multiple_window_contexts}
GLFW now provides the ability to create multiple OpenGL and OpenGL ES
contexts for a given window. Called user contexts, a [GLFWusercontext](@ref context_user)
can be created using @ref glfwCreateUserContext,
destroyed using @ref glfwDestroyUserContext, and managed with
@ref glfwMakeUserContextCurrent and @ref glfwGetCurrentUserContext.
For more information see the [user context](@ref context_user) documentation.
### Unlimited mouse buttons {#unlimited_mouse_buttons} ### Unlimited mouse buttons {#unlimited_mouse_buttons}
GLFW now has an input mode which allows an unlimited number of mouse buttons to GLFW now has an input mode which allows an unlimited number of mouse buttons to

View File

@ -1403,6 +1403,18 @@ typedef struct GLFWmonitor GLFWmonitor;
*/ */
typedef struct GLFWwindow GLFWwindow; typedef struct GLFWwindow GLFWwindow;
/*! @brief Opaque user OpenGL & OpenGL ES context object.
*
* Opaque user OpenGL OpenGL ES context object.
*
* @see @ref context_user
*
* @since Added in version 3.4.
*
* @ingroup window
*/
typedef struct GLFWusercontext GLFWusercontext;
/*! @brief Opaque cursor object. /*! @brief Opaque cursor object.
* *
* Opaque cursor object. * Opaque cursor object.
@ -6088,6 +6100,9 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void);
* thread can have only a single current context at a time. Making a context * thread can have only a single current context at a time. Making a context
* current detaches any previously current context on the calling thread. * current detaches any previously current context on the calling thread.
* *
* Making a context of a window current on a given thread will detach
* any user context which is current on that thread and visa versa.
*
* When moving a context between threads, you must detach it (make it * When moving a context between threads, you must detach it (make it
* non-current) on the old thread before making it current on the new one. * non-current) on the old thread before making it current on the new one.
* *
@ -6115,6 +6130,9 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void);
* *
* @sa @ref context_current * @sa @ref context_current
* @sa @ref glfwGetCurrentContext * @sa @ref glfwGetCurrentContext
* @sa @ref context_current_user
* @sa @ref glfwMakeUserContextCurrent
* @sa @ref glfwGetCurrentUserContext
* *
* @since Added in version 3.0. * @since Added in version 3.0.
* *
@ -6303,6 +6321,147 @@ GLFWAPI int glfwExtensionSupported(const char* extension);
*/ */
GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname);
/*! @brief Create a new OpenGL or OpenGL ES user context for a window
*
* This function creates a new OpenGL or OpenGL ES user context for a
* window, which can be used to call OpenGL or OpenGL ES functions on
* another thread. For a valid user context the window must be created
* with a [GLFW_CLIENT_API](@ref GLFW_CLIENT_API_hint) other than
* `GLFW_NO_API`.
*
* User context creation uses the window context and framebuffer related
* hints to ensure a valid context is created for that window, these hints
* should be the same at the time of user context creation as when the
* window was created.
*
* Contexts share resources with the window context and with any other
* user context created for that window.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED,
* @ref GLFW_INVALID_VALUE the window parameter is `NULL`,
* @ref GLFW_NO_WINDOW_CONTEXT if the window has no OpenGL or
* OpenGL US context, and @ref GLFW_PLATFORM_ERROR.
*
* @param[in] window The Window for which the user context is to be
* created.
* @return The handle of the user context created, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref context_user
* @sa @ref usercontext_creation
* @sa @ref glfwDestroyUserContext
* @sa @ref window_creation
* @sa @ref glfwCreateWindow
* @sa @ref glfwDestroyWindow
*
* @since Added in version 3.4.
*
* @ingroup context
*/
GLFWAPI GLFWusercontext* glfwCreateUserContext(GLFWwindow* window);
/*! @brief Destroys the specified user context
*
* This function destroys the specified user context.
* User contexts should be destroyed before destroying the
* window they were made with.
*
* If the user context is current on the main thread, it is
* detached before being destroyed.
*
* @param[in] context The user context to destroy.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @note The user context must not be current on any other
* thread when this function is called.
*
* @reentrancy This function must not be called from a callback.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref context_user
* @sa @ref usercontext_creation
* @sa @ref glfwCreateUserContext
* @sa @ref window_creation
* @sa @ref glfwCreateWindow
* @sa @ref glfwDestroyWindow
*
* @since Added in version 3.4.
*
* @ingroup context
*/
GLFWAPI void glfwDestroyUserContext(GLFWusercontext* context);
/*! @brief Makes the user context current for the calling thread.
*
* This function makes the OpenGL or OpenGL ES context of the specified user
* context current on the calling thread. A context must only be made current on
* a single thread at a time and each thread can have only a single current
* context at a time.
*
* Making a user context current on a given thread will detach the context of
* any window which is current on that thread and visa versa.
*
* When moving a context between threads, you must make it non-current on the
* old thread before making it current on the new one.
*
* By default, making a context non-current implicitly forces a pipeline flush.
* On machines that support `GL_KHR_context_flush_control`, you can control
* whether a context performs this flush by setting the
* [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint)
* hint.
*
* @param[in] context The user context to make current, or `NULL` to
* detach the current context.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED,
* and @ref GLFW_PLATFORM_ERROR.
*
* @thread_safety This function may be called from any thread.
*
* @sa @ref context_user
* @sa @ref context_current_user
* @sa @ref glfwGetCurrentUserContext
* @sa @ref context_current
* @sa @ref glfwMakeContextCurrent
* @sa @ref glfwGetCurrentContext
*
* @since Added in version 3.4.
*
* @ingroup context
*/
GLFWAPI void glfwMakeUserContextCurrent(GLFWusercontext* context);
/*! @brief Returns the current OpenGL or OpenGL ES user context
*
* This function returns the user context which is current
* on the calling thread.
*
* @return The user context current, or `NULL` if no user context
* is current.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function may be called from any thread.
*
* @sa @ref context_user
* @sa @ref context_current_user
* @sa @ref glfwMakeUserContextCurrent
* @sa @ref context_current
* @sa @ref glfwMakeContextCurrent
* @sa @ref glfwGetCurrentContext
*
* @since Added in version 3.4.
*
* @ingroup context
*/
GLFWAPI GLFWusercontext* glfwGetCurrentUserContext(void);
/*! @brief Returns whether the Vulkan loader and an ICD have been found. /*! @brief Returns whether the Vulkan loader and an ICD have been found.
* *
* This function returns whether the Vulkan loader and any minimally functional * This function returns whether the Vulkan loader and any minimally functional

View File

@ -559,6 +559,7 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform)
.waitEvents = _glfwWaitEventsCocoa, .waitEvents = _glfwWaitEventsCocoa,
.waitEventsTimeout = _glfwWaitEventsTimeoutCocoa, .waitEventsTimeout = _glfwWaitEventsTimeoutCocoa,
.postEmptyEvent = _glfwPostEmptyEventCocoa, .postEmptyEvent = _glfwPostEmptyEventCocoa,
.createUserContext = _glfwCreateUserContextCocoa,
.getEGLPlatform = _glfwGetEGLPlatformCocoa, .getEGLPlatform = _glfwGetEGLPlatformCocoa,
.getEGLNativeDisplay = _glfwGetEGLNativeDisplayCocoa, .getEGLNativeDisplay = _glfwGetEGLNativeDisplayCocoa,
.getEGLNativeWindow = _glfwGetEGLNativeWindowCocoa, .getEGLNativeWindow = _glfwGetEGLNativeWindowCocoa,

View File

@ -107,6 +107,7 @@ typedef VkResult (APIENTRY *PFN_vkCreateMetalSurfaceEXT)(VkInstance,const VkMeta
#define GLFW_NSGL_CONTEXT_STATE _GLFWcontextNSGL nsgl; #define GLFW_NSGL_CONTEXT_STATE _GLFWcontextNSGL nsgl;
#define GLFW_NSGL_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl; #define GLFW_NSGL_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl;
#define GLFW_NSGL_USER_CONTEXT_STATE _GLFWusercontextNSGL nsgl;
// HIToolbox.framework pointer typedefs // HIToolbox.framework pointer typedefs
#define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData #define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData
@ -134,6 +135,14 @@ typedef struct _GLFWlibraryNSGL
CFBundleRef framework; CFBundleRef framework;
} _GLFWlibraryNSGL; } _GLFWlibraryNSGL;
// NSGL-specific per usercontext data
//
typedef struct _GLFWusercontextNSGL
{
id object;
} _GLFWusercontextNSGL;
// Cocoa-specific per-window data // Cocoa-specific per-window data
// //
typedef struct _GLFWwindowNS typedef struct _GLFWwindowNS
@ -300,3 +309,5 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
const _GLFWfbconfig* fbconfig); const _GLFWfbconfig* fbconfig);
void _glfwDestroyContextNSGL(_GLFWwindow* window); void _glfwDestroyContextNSGL(_GLFWwindow* window);
_GLFWusercontext* _glfwCreateUserContextCocoa(_GLFWwindow* window);
_GLFWusercontext* _glfwCreateUserContextNSGL(_GLFWwindow* window);

View File

@ -2021,6 +2021,25 @@ VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance,
} }
_GLFWusercontext* _glfwCreateUserContextCocoa(_GLFWwindow* window)
{
if (window->context.nsgl.object)
{
return _glfwCreateUserContextNSGL(window);
}
else if (window->context.egl.handle)
{
return _glfwCreateUserContextEGL(window);
}
else if (window->context.osmesa.handle)
{
return _glfwCreateUserContextOSMesa(window);
}
return NULL;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -619,7 +619,9 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
_GLFWwindow* window = (_GLFWwindow*) handle; _GLFWwindow* window = (_GLFWwindow*) handle;
_GLFWwindow* previous; _GLFWwindow* previous;
_GLFWusercontext* previousUserContext;
previousUserContext = _glfwPlatformGetTls(&_glfw.usercontextSlot);
previous = _glfwPlatformGetTls(&_glfw.contextSlot); previous = _glfwPlatformGetTls(&_glfw.contextSlot);
if (window && window->context.client == GLFW_NO_API) if (window && window->context.client == GLFW_NO_API)
@ -629,6 +631,12 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
return; return;
} }
if (previousUserContext)
{
assert(previous==NULL);
previousUserContext->makeCurrent(NULL);
}
if (previous) if (previous)
{ {
if (!window || window->context.source != previous->context.source) if (!window || window->context.source != previous->context.source)
@ -763,3 +771,65 @@ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
return window->context.getProcAddress(procname); return window->context.getProcAddress(procname);
} }
GLFWAPI GLFWusercontext* glfwCreateUserContext(GLFWwindow* handle)
{
_GLFWusercontext* context;
_GLFWwindow* window = (_GLFWwindow*)handle;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!window)
{
_glfwInputError(GLFW_INVALID_VALUE,
"Cannot create a user context without a valid window handle");
return NULL;
}
if (window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT,
"Cannot create a user context for a window that has no OpenGL or OpenGL ES context");
return NULL;
}
context = _glfw.platform.createUserContext(window);
return (GLFWusercontext*)context;
}
GLFWAPI void glfwDestroyUserContext(GLFWusercontext* handle)
{
_GLFWusercontext* context = (_GLFWusercontext*)handle;
_GLFWusercontext* current = _glfwPlatformGetTls(&_glfw.usercontextSlot);
_GLFW_REQUIRE_INIT();
if (context)
{
if(current==context)
glfwMakeContextCurrent(NULL);
context->destroy(context);
}
}
GLFWAPI void glfwMakeUserContextCurrent(GLFWusercontext* handle)
{
_GLFWusercontext* context = (_GLFWusercontext*)handle;
_GLFW_REQUIRE_INIT();
// Call glfwMakeContextCurrent(NULL) to both clear context TLS and set
// context to NULL if required by platform & context, and this
// handles case of calling glfwMakeUserContextCurrent(NULL)
glfwMakeContextCurrent(NULL);
if (context)
context->makeCurrent(context);
}
GLFWAPI GLFWusercontext* glfwGetCurrentUserContext(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return _glfwPlatformGetTls(&_glfw.usercontextSlot);
}

View File

@ -436,6 +436,10 @@ GLFWbool _glfwInitEGL(void)
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglQueryString"); _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglQueryString");
_glfw.egl.GetProcAddress = (PFN_eglGetProcAddress) _glfw.egl.GetProcAddress = (PFN_eglGetProcAddress)
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetProcAddress"); _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetProcAddress");
_glfw.egl.CreatePbufferSurface = (PFN_eglCreatePbufferSurface)
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreatePbufferSurface");
_glfw.egl.ChooseConfig = (PFN_eglChooseConfig)
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglChooseConfig");
if (!_glfw.egl.GetConfigAttrib || if (!_glfw.egl.GetConfigAttrib ||
!_glfw.egl.GetConfigs || !_glfw.egl.GetConfigs ||
@ -453,7 +457,9 @@ GLFWbool _glfwInitEGL(void)
!_glfw.egl.SwapBuffers || !_glfw.egl.SwapBuffers ||
!_glfw.egl.SwapInterval || !_glfw.egl.SwapInterval ||
!_glfw.egl.QueryString || !_glfw.egl.QueryString ||
!_glfw.egl.GetProcAddress) !_glfw.egl.GetProcAddress ||
!_glfw.egl.CreatePbufferSurface||
!_glfw.egl.ChooseConfig)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to load required entry points"); "EGL: Failed to load required entry points");
@ -569,17 +575,15 @@ void _glfwTerminateEGL(void)
attribs[index++] = v; \ attribs[index++] = v; \
} }
// Create the OpenGL or OpenGL ES context // Create the OpenGL or OpenGL ES context for the window eglConfig
// //
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, GLFWbool _glfwCreateContextForConfigEGL(EGLConfig eglConfig,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig) EGLContext* context)
{ {
EGLint attribs[40]; EGLint attribs[40];
EGLConfig config;
EGLContext share = NULL;
EGLNativeWindowType native;
int index = 0; int index = 0;
EGLContext share = NULL;
if (!_glfw.egl.display) if (!_glfw.egl.display)
{ {
@ -590,9 +594,6 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
if (ctxconfig->share) if (ctxconfig->share)
share = ctxconfig->share->context.egl.handle; share = ctxconfig->share->context.egl.handle;
if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
return GLFW_FALSE;
if (ctxconfig->client == GLFW_OPENGL_ES_API) if (ctxconfig->client == GLFW_OPENGL_ES_API)
{ {
if (!eglBindAPI(EGL_OPENGL_ES_API)) if (!eglBindAPI(EGL_OPENGL_ES_API))
@ -688,10 +689,9 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
SET_ATTRIB(EGL_NONE, EGL_NONE); SET_ATTRIB(EGL_NONE, EGL_NONE);
window->context.egl.handle = eglCreateContext(_glfw.egl.display, *context = eglCreateContext(_glfw.egl.display, eglConfig, share, attribs);
config, share, attribs);
if (window->context.egl.handle == EGL_NO_CONTEXT) if (*context == EGL_NO_CONTEXT)
{ {
_glfwInputError(GLFW_VERSION_UNAVAILABLE, _glfwInputError(GLFW_VERSION_UNAVAILABLE,
"EGL: Failed to create context: %s", "EGL: Failed to create context: %s",
@ -699,9 +699,32 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
return GLFW_FALSE; return GLFW_FALSE;
} }
// Set up attributes for surface creation return GLFW_TRUE;
index = 0; }
// Create the OpenGL or OpenGL ES context
//
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
EGLNativeWindowType native;
EGLint attribs[40];
int index = 0;
if (!chooseEGLConfig(ctxconfig, fbconfig, &window->context.egl.config))
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"EGL: Failed to find a suitable EGLConfig");
return GLFW_FALSE;
}
if (!_glfwCreateContextForConfigEGL(window->context.egl.config,ctxconfig,&window->context.egl.handle))
{
return GLFW_FALSE;
}
// Set up attributes for surface creation
if (fbconfig->sRGB) if (fbconfig->sRGB)
{ {
if (_glfw.egl.KHR_gl_colorspace) if (_glfw.egl.KHR_gl_colorspace)
@ -735,18 +758,18 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
// implement eglCreatePlatformWindowSurfaceEXT despite reporting // implement eglCreatePlatformWindowSurfaceEXT despite reporting
// support for EGL_EXT_platform_base // support for EGL_EXT_platform_base
window->context.egl.surface = window->context.egl.surface =
eglCreateWindowSurface(_glfw.egl.display, config, native, attribs); eglCreateWindowSurface(_glfw.egl.display, window->context.egl.config, native, attribs);
} }
else if (_glfw.egl.platform == EGL_PLATFORM_SURFACELESS_MESA) else if (_glfw.egl.platform == EGL_PLATFORM_SURFACELESS_MESA)
{ {
// HACK: Use a pbuffer surface as the default framebuffer // HACK: Use a pbuffer surface as the default framebuffer
window->context.egl.surface = window->context.egl.surface =
eglCreatePbufferSurface(_glfw.egl.display, config, attribs); eglCreatePbufferSurface(_glfw.egl.display, window->context.egl.config, attribs);
} }
else else
{ {
window->context.egl.surface = window->context.egl.surface =
eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, config, native, attribs); eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, window->context.egl.config, native, attribs);
} }
if (window->context.egl.surface == EGL_NO_SURFACE) if (window->context.egl.surface == EGL_NO_SURFACE)
@ -757,7 +780,6 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
return GLFW_FALSE; return GLFW_FALSE;
} }
window->context.egl.config = config;
// Load the appropriate client library // Load the appropriate client library
if (!_glfw.egl.KHR_get_all_proc_addresses) if (!_glfw.egl.KHR_get_all_proc_addresses)
@ -895,6 +917,109 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
} }
#endif // _GLFW_X11 #endif // _GLFW_X11
static void _glfwMakeUserContextCurrentEGL(_GLFWusercontext* context)
{
if (context)
{
if (!eglMakeCurrent(_glfw.egl.display,
context->egl.surface,
context->egl.surface,
context->egl.handle))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to make user context current: %s",
getEGLErrorString(eglGetError()));
_glfwPlatformSetTls(&_glfw.usercontextSlot, NULL);
return;
}
}
else
{
if (!eglMakeCurrent(_glfw.egl.display,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to clear current user context: %s",
getEGLErrorString(eglGetError()));
return;
}
}
_glfwPlatformSetTls(&_glfw.usercontextSlot, context);
}
static void _glfwDestroyUserContextEGL(_GLFWusercontext* context)
{
if (context->egl.surface!=EGL_NO_SURFACE)
eglDestroySurface(_glfw.egl.display,context->egl.surface);
eglDestroyContext(_glfw.egl.display, context->egl.handle);
free(context);
}
_GLFWusercontext* _glfwCreateUserContextEGL(_GLFWwindow* window)
{
_GLFWusercontext* context;
_GLFWctxconfig ctxconfig;
EGLint dummyConfigAttribs[] =
{
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1,
EGL_NONE
};
EGLint dummySurfaceAttribs[] =
{
EGL_WIDTH, 1, EGL_HEIGHT, 1,
EGL_NONE
};
EGLint dummySurfaceNumConfigs;
EGLConfig dummySurfaceConfig;
context = calloc(1, sizeof(_GLFWusercontext));
context->window = window;
ctxconfig = _glfw.hints.context;
ctxconfig.share = window;
if (!_glfwCreateContextForConfigEGL(window->context.egl.config,&ctxconfig,&context->egl.handle))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to create user OpenGL context");
free(context);
return NULL;
}
if (glfwExtensionSupported("EGL_KHR_surfaceless_context"))
context->egl.surface = EGL_NO_SURFACE;
else
{
eglChooseConfig(_glfw.egl.display, dummyConfigAttribs, &dummySurfaceConfig, 1, &dummySurfaceNumConfigs);
if (!dummySurfaceNumConfigs)
{
eglDestroyContext(_glfw.egl.display, context->egl.handle);
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to find surface config for user context: %s", getEGLErrorString(eglGetError()));
free(context);
return NULL;
}
context->egl.surface = eglCreatePbufferSurface(_glfw.egl.display, dummySurfaceConfig, dummySurfaceAttribs);
if (context->egl.surface == EGL_NO_SURFACE)
{
eglDestroyContext(_glfw.egl.display, context->egl.handle);
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to create surface for user context: %s for %s", getEGLErrorString(eglGetError()), eglQueryString(_glfw.egl.display,0x3054));
free(context);
return NULL;
}
}
context->makeCurrent = _glfwMakeUserContextCurrentEGL;
context->destroy = _glfwDestroyUserContextEGL;
return context;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////

View File

@ -447,26 +447,19 @@ void _glfwTerminateGLX(void)
attribs[index++] = v; \ attribs[index++] = v; \
} }
// Create the OpenGL or OpenGL ES context
// Create the OpenGL or OpenGL ES context for the window fbConfig
// //
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, GLFWbool _glfwCreateContextForFBGLX(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig) GLXContext* context)
{ {
int attribs[40]; int attribs[40];
GLXFBConfig native = NULL;
GLXContext share = NULL; GLXContext share = NULL;
if (ctxconfig->share) if (ctxconfig->share)
share = ctxconfig->share->context.glx.handle; share = ctxconfig->share->context.glx.handle;
if (!chooseGLXFBConfig(fbconfig, &native))
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"GLX: Failed to find a suitable GLXFBConfig");
return GLFW_FALSE;
}
if (ctxconfig->client == GLFW_OPENGL_ES_API) if (ctxconfig->client == GLFW_OPENGL_ES_API)
{ {
if (!_glfw.glx.ARB_create_context || if (!_glfw.glx.ARB_create_context ||
@ -581,9 +574,9 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
SET_ATTRIB(None, None); SET_ATTRIB(None, None);
window->context.glx.handle = *context =
_glfw.glx.CreateContextAttribsARB(_glfw.x11.display, _glfw.glx.CreateContextAttribsARB(_glfw.x11.display,
native, window->context.glx.fbconfig,
share, share,
True, True,
attribs); attribs);
@ -592,34 +585,56 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
// implementation of GLX_ARB_create_context_profile that fail // implementation of GLX_ARB_create_context_profile that fail
// default 1.0 context creation with a GLXBadProfileARB error in // default 1.0 context creation with a GLXBadProfileARB error in
// violation of the extension spec // violation of the extension spec
if (!window->context.glx.handle) if (!(*context))
{ {
if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB &&
ctxconfig->client == GLFW_OPENGL_API && ctxconfig->client == GLFW_OPENGL_API &&
ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE &&
ctxconfig->forward == GLFW_FALSE) ctxconfig->forward == GLFW_FALSE)
{ {
window->context.glx.handle = *context =
createLegacyContextGLX(window, native, share); createLegacyContextGLX(window, window->context.glx.fbconfig, share);
} }
} }
} }
else else
{ {
window->context.glx.handle = *context =
createLegacyContextGLX(window, native, share); createLegacyContextGLX(window, window->context.glx.fbconfig, share);
} }
_glfwReleaseErrorHandlerX11(); _glfwReleaseErrorHandlerX11();
if (!window->context.glx.handle) if (!(*context))
{ {
_glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context"); _glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context");
return GLFW_FALSE; return GLFW_FALSE;
} }
return GLFW_TRUE;
}
// Create the OpenGL or OpenGL ES context
//
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (!chooseGLXFBConfig(fbconfig, &window->context.glx.fbconfig))
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"GLX: Failed to find a suitable GLXFBConfig");
return GLFW_FALSE;
}
if(!_glfwCreateContextForFBGLX(window,ctxconfig,&window->context.glx.handle))
{
return GLFW_FALSE;
}
window->context.glx.window = window->context.glx.window =
glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL); glXCreateWindow(_glfw.x11.display, window->context.glx.fbconfig, window->x11.handle, NULL);
if (!window->context.glx.window) if (!window->context.glx.window)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window"); _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window");
@ -670,6 +685,60 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
return GLFW_TRUE; return GLFW_TRUE;
} }
static void _glfwMakeUserContextCurrentGLX(_GLFWusercontext* context)
{
if (context)
{
if(!glXMakeCurrent(_glfw.x11.display, context->window->context.glx.window,context->glx.handle))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"GLX: Failed to make user context current");
_glfwPlatformSetTls(&_glfw.usercontextSlot, NULL);
return;
}
}
else
{
if (!glXMakeCurrent(_glfw.x11.display, None, NULL))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"GLX: Failed to clear current user context");
return;
}
}
_glfwPlatformSetTls(&_glfw.usercontextSlot, context);
}
static void _glfwDestroyUserContextGLX(_GLFWusercontext* context)
{
glXDestroyContext(_glfw.x11.display, context->glx.handle);
free(context);
}
_GLFWusercontext* _glfwCreateUserContextGLX(_GLFWwindow* window)
{
_GLFWusercontext* context;
_GLFWctxconfig ctxconfig;
context = calloc(1, sizeof(_GLFWusercontext));
context->window = window;
ctxconfig = _glfw.hints.context;
ctxconfig.share = window;
if(!_glfwCreateContextForFBGLX(window,&ctxconfig,&context->glx.handle))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"GLX: Failed to create user OpenGL context");
free(context);
return NULL;
}
context->makeCurrent = _glfwMakeUserContextCurrentGLX;
context->destroy = _glfwDestroyUserContextGLX;
return context;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////

View File

@ -132,6 +132,7 @@ static void terminate(void)
_glfw_free(error); _glfw_free(error);
} }
_glfwPlatformDestroyTls(&_glfw.usercontextSlot);
_glfwPlatformDestroyTls(&_glfw.contextSlot); _glfwPlatformDestroyTls(&_glfw.contextSlot);
_glfwPlatformDestroyTls(&_glfw.errorSlot); _glfwPlatformDestroyTls(&_glfw.errorSlot);
_glfwPlatformDestroyMutex(&_glfw.errorLock); _glfwPlatformDestroyMutex(&_glfw.errorLock);
@ -410,7 +411,8 @@ GLFWAPI int glfwInit(void)
if (!_glfwPlatformCreateMutex(&_glfw.errorLock) || if (!_glfwPlatformCreateMutex(&_glfw.errorLock) ||
!_glfwPlatformCreateTls(&_glfw.errorSlot) || !_glfwPlatformCreateTls(&_glfw.errorSlot) ||
!_glfwPlatformCreateTls(&_glfw.contextSlot)) !_glfwPlatformCreateTls(&_glfw.contextSlot) ||
!_glfwPlatformCreateTls(&_glfw.usercontextSlot))
{ {
terminate(); terminate();
return GLFW_FALSE; return GLFW_FALSE;

View File

@ -79,6 +79,7 @@ typedef struct _GLFWmapping _GLFWmapping;
typedef struct _GLFWjoystick _GLFWjoystick; typedef struct _GLFWjoystick _GLFWjoystick;
typedef struct _GLFWtls _GLFWtls; typedef struct _GLFWtls _GLFWtls;
typedef struct _GLFWmutex _GLFWmutex; typedef struct _GLFWmutex _GLFWmutex;
typedef struct _GLFWusercontext _GLFWusercontext;
#define GL_VERSION 0x1f02 #define GL_VERSION 0x1f02
#define GL_NONE 0 #define GL_NONE 0
@ -217,6 +218,7 @@ typedef EGLBoolean (APIENTRY * PFN_eglSwapBuffers)(EGLDisplay,EGLSurface);
typedef EGLBoolean (APIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint); typedef EGLBoolean (APIENTRY * PFN_eglSwapInterval)(EGLDisplay,EGLint);
typedef const char* (APIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint); typedef const char* (APIENTRY * PFN_eglQueryString)(EGLDisplay,EGLint);
typedef GLFWglproc (APIENTRY * PFN_eglGetProcAddress)(const char*); typedef GLFWglproc (APIENTRY * PFN_eglGetProcAddress)(const char*);
typedef EGLBoolean (APIENTRY * PFN_eglChooseConfig)(EGLDisplay,EGLint const*,EGLConfig*,EGLint,EGLint*);
#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib #define eglGetConfigAttrib _glfw.egl.GetConfigAttrib
#define eglGetConfigs _glfw.egl.GetConfigs #define eglGetConfigs _glfw.egl.GetConfigs
#define eglGetDisplay _glfw.egl.GetDisplay #define eglGetDisplay _glfw.egl.GetDisplay
@ -234,6 +236,8 @@ typedef GLFWglproc (APIENTRY * PFN_eglGetProcAddress)(const char*);
#define eglSwapInterval _glfw.egl.SwapInterval #define eglSwapInterval _glfw.egl.SwapInterval
#define eglQueryString _glfw.egl.QueryString #define eglQueryString _glfw.egl.QueryString
#define eglGetProcAddress _glfw.egl.GetProcAddress #define eglGetProcAddress _glfw.egl.GetProcAddress
#define eglCreatePbufferSurface _glfw.egl.CreatePbufferSurface
#define eglChooseConfig _glfw.egl.ChooseConfig
typedef EGLDisplay (APIENTRY * PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum,void*,const EGLint*); typedef EGLDisplay (APIENTRY * PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum,void*,const EGLint*);
typedef EGLSurface (APIENTRY * PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)(EGLDisplay,EGLConfig,void*,const EGLint*); typedef EGLSurface (APIENTRY * PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)(EGLDisplay,EGLConfig,void*,const EGLint*);
@ -525,6 +529,29 @@ struct _GLFWcontext
GLFW_PLATFORM_CONTEXT_STATE GLFW_PLATFORM_CONTEXT_STATE
}; };
// User Context structure
//
struct _GLFWusercontext
{
_GLFWwindow* window;
void (*makeCurrent)(_GLFWusercontext* context);
void (*destroy)(_GLFWusercontext* context);
struct {
EGLContext handle;
EGLSurface surface;
} egl;
struct {
OSMesaContext handle;
} osmesa;
// This is defined in platform.h
GLFW_PLATFORM_USER_CONTEXT_STATE
};
// Window and context structure // Window and context structure
// //
struct _GLFWwindow struct _GLFWwindow
@ -751,6 +778,7 @@ struct _GLFWplatform
void (*waitEvents)(void); void (*waitEvents)(void);
void (*waitEventsTimeout)(double); void (*waitEventsTimeout)(double);
void (*postEmptyEvent)(void); void (*postEmptyEvent)(void);
_GLFWusercontext* (*createUserContext)(_GLFWwindow*);
// EGL // EGL
EGLenum (*getEGLPlatform)(EGLint**); EGLenum (*getEGLPlatform)(EGLint**);
EGLNativeDisplayType (*getEGLNativeDisplay)(void); EGLNativeDisplayType (*getEGLNativeDisplay)(void);
@ -792,6 +820,7 @@ struct _GLFWlibrary
_GLFWtls errorSlot; _GLFWtls errorSlot;
_GLFWtls contextSlot; _GLFWtls contextSlot;
_GLFWtls usercontextSlot;
_GLFWmutex errorLock; _GLFWmutex errorLock;
struct { struct {
@ -842,6 +871,7 @@ struct _GLFWlibrary
PFN_eglSwapInterval SwapInterval; PFN_eglSwapInterval SwapInterval;
PFN_eglQueryString QueryString; PFN_eglQueryString QueryString;
PFN_eglGetProcAddress GetProcAddress; PFN_eglGetProcAddress GetProcAddress;
PFN_eglChooseConfig ChooseConfig;
PFNEGLGETPLATFORMDISPLAYEXTPROC GetPlatformDisplayEXT; PFNEGLGETPLATFORMDISPLAYEXTPROC GetPlatformDisplayEXT;
PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC CreatePlatformWindowSurfaceEXT; PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC CreatePlatformWindowSurfaceEXT;
@ -992,6 +1022,7 @@ void _glfwTerminateEGL(void);
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig); const _GLFWfbconfig* fbconfig);
_GLFWusercontext* _glfwCreateUserContextEGL(_GLFWwindow* window);
#if defined(_GLFW_X11) #if defined(_GLFW_X11)
GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
@ -1004,6 +1035,7 @@ void _glfwTerminateOSMesa(void);
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig); const _GLFWfbconfig* fbconfig);
_GLFWusercontext* _glfwCreateUserContextOSMesa(_GLFWwindow* window);
GLFWbool _glfwInitVulkan(int mode); GLFWbool _glfwInitVulkan(int mode);
void _glfwTerminateVulkan(void); void _glfwTerminateVulkan(void);

View File

@ -353,6 +353,54 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
} }
static void _glfwMakeUserContextCurrentNSGL(_GLFWusercontext* context)
{
@autoreleasepool {
if (context)
[context->nsgl.object makeCurrentContext];
else
[NSOpenGLContext clearCurrentContext];
_glfwPlatformSetTls(&_glfw.usercontextSlot, context);
} // autoreleasepool
}
static void _glfwDestroyUserContextNSGL(_GLFWusercontext* context)
{
@autoreleasepool {
[context->nsgl.object release];
} // autoreleasepool
free(context);
}
_GLFWusercontext* _glfwCreateUserContextNSGL(_GLFWwindow* window)
{
_GLFWusercontext* context;
context = calloc(1, sizeof(_GLFWusercontext));
context->window = window;
context->nsgl.object =
[[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat
shareContext:window->context.nsgl.object];
if (window->context.nsgl.object == nil)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"NSGL: Failed to create OpenGL user context");
free(context);
return NULL;
}
context->makeCurrent = _glfwMakeUserContextCurrentNSGL;
context->destroy = _glfwDestroyUserContextNSGL;
return context;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -105,6 +105,7 @@ GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform)
.waitEvents = _glfwWaitEventsNull, .waitEvents = _glfwWaitEventsNull,
.waitEventsTimeout = _glfwWaitEventsTimeoutNull, .waitEventsTimeout = _glfwWaitEventsTimeoutNull,
.postEmptyEvent = _glfwPostEmptyEventNull, .postEmptyEvent = _glfwPostEmptyEventNull,
.createUserContext = _glfwCreateUserContextNull,
.getEGLPlatform = _glfwGetEGLPlatformNull, .getEGLPlatform = _glfwGetEGLPlatformNull,
.getEGLNativeDisplay = _glfwGetEGLNativeDisplayNull, .getEGLNativeDisplay = _glfwGetEGLNativeDisplayNull,
.getEGLNativeWindow = _glfwGetEGLNativeWindowNull, .getEGLNativeWindow = _glfwGetEGLNativeWindowNull,

View File

@ -32,6 +32,7 @@
#define GLFW_NULL_CONTEXT_STATE #define GLFW_NULL_CONTEXT_STATE
#define GLFW_NULL_CURSOR_STATE #define GLFW_NULL_CURSOR_STATE
#define GLFW_NULL_LIBRARY_CONTEXT_STATE #define GLFW_NULL_LIBRARY_CONTEXT_STATE
#define GLFW_NULL_USER_CONTEXT_STATE
#define GLFW_NULL_SC_FIRST GLFW_NULL_SC_SPACE #define GLFW_NULL_SC_FIRST GLFW_NULL_SC_SPACE
#define GLFW_NULL_SC_SPACE 1 #define GLFW_NULL_SC_SPACE 1
@ -280,3 +281,5 @@ VkResult _glfwCreateWindowSurfaceNull(VkInstance instance, _GLFWwindow* window,
void _glfwPollMonitorsNull(void); void _glfwPollMonitorsNull(void);
_GLFWusercontext* _glfwCreateUserContextNull(_GLFWwindow* window);

View File

@ -747,3 +747,12 @@ VkResult _glfwCreateWindowSurfaceNull(VkInstance instance,
return err; return err;
} }
_GLFWusercontext* _glfwCreateUserContextNull(_GLFWwindow* window)
{
if (window->context.osmesa.handle)
{
return _glfwCreateUserContextOSMesa(window);
}
return NULL;
}

View File

@ -194,9 +194,9 @@ void _glfwTerminateOSMesa(void)
attribs[index++] = v; \ attribs[index++] = v; \
} }
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, GLFWbool _glfwCreateContextForConfigOSMesa(const _GLFWctxconfig* ctxconfig,
const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig,
const _GLFWfbconfig* fbconfig) OSMesaContext* context )
{ {
OSMesaContext share = NULL; OSMesaContext share = NULL;
const int accumBits = fbconfig->accumRedBits + const int accumBits = fbconfig->accumRedBits +
@ -247,7 +247,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
SET_ATTRIB(0, 0); SET_ATTRIB(0, 0);
window->context.osmesa.handle = *context =
OSMesaCreateContextAttribs(attribs, share); OSMesaCreateContextAttribs(attribs, share);
} }
else else
@ -259,7 +259,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
return GLFW_FALSE; return GLFW_FALSE;
} }
window->context.osmesa.handle = *context =
OSMesaCreateContextExt(OSMESA_RGBA, OSMesaCreateContextExt(OSMESA_RGBA,
fbconfig->depthBits, fbconfig->depthBits,
fbconfig->stencilBits, fbconfig->stencilBits,
@ -267,13 +267,27 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
share); share);
} }
if (window->context.osmesa.handle == NULL) if (*context == NULL)
{ {
_glfwInputError(GLFW_VERSION_UNAVAILABLE, _glfwInputError(GLFW_VERSION_UNAVAILABLE,
"OSMesa: Failed to create context"); "OSMesa: Failed to create context");
return GLFW_FALSE; return GLFW_FALSE;
} }
return GLFW_TRUE;
}
#undef setAttrib
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if(!_glfwCreateContextForConfigOSMesa(ctxconfig,fbconfig,&window->context.osmesa.handle))
{
return GLFW_FALSE;
}
window->context.makeCurrent = makeContextCurrentOSMesa; window->context.makeCurrent = makeContextCurrentOSMesa;
window->context.swapBuffers = swapBuffersOSMesa; window->context.swapBuffers = swapBuffersOSMesa;
window->context.swapInterval = swapIntervalOSMesa; window->context.swapInterval = swapIntervalOSMesa;
@ -284,8 +298,62 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
return GLFW_TRUE; return GLFW_TRUE;
} }
#undef SET_ATTRIB static void _glfwMakeUserContextCurrentOSMesa(_GLFWusercontext* context)
{
if (context)
{
if (!OSMesaMakeCurrent(context->osmesa.handle,
context->window->context.osmesa.buffer,
GL_UNSIGNED_BYTE,
context->window->context.osmesa.width, context->window->context.osmesa.height))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OSMesa: Failed to make user context current");
_glfwPlatformSetTls(&_glfw.usercontextSlot, NULL);
return;
}
}
_glfwPlatformSetTls(&_glfw.usercontextSlot, context);
}
static void _glfwDestroyUserContextOSMesa(_GLFWusercontext* context)
{
if (context->osmesa.handle)
{
OSMesaDestroyContext(context->osmesa.handle);
}
free(context);
}
_GLFWusercontext* _glfwCreateUserContextOSMesa(_GLFWwindow* window)
{
_GLFWusercontext* context;
_GLFWctxconfig ctxconfig;
_GLFWfbconfig fbconfig;
context = calloc(1, sizeof(_GLFWusercontext));
context->window = window;
ctxconfig = _glfw.hints.context;
ctxconfig.share = window;
fbconfig = _glfw.hints.framebuffer;
if(!_glfwCreateContextForConfigOSMesa(&ctxconfig,&fbconfig,&context->osmesa.handle))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OSMesa: Failed to create user OpenGL context");
free(context);
return NULL;
}
context->makeCurrent = _glfwMakeUserContextCurrentOSMesa;
context->destroy = _glfwDestroyUserContextOSMesa;
return context;
}
#undef SET_ATTRIB
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////

View File

@ -52,6 +52,7 @@
#define GLFW_WIN32_LIBRARY_WINDOW_STATE #define GLFW_WIN32_LIBRARY_WINDOW_STATE
#define GLFW_WGL_CONTEXT_STATE #define GLFW_WGL_CONTEXT_STATE
#define GLFW_WGL_LIBRARY_CONTEXT_STATE #define GLFW_WGL_LIBRARY_CONTEXT_STATE
#define GLFW_WGL_USER_CONTEXT_STATE
#endif #endif
#if defined(_GLFW_COCOA) #if defined(_GLFW_COCOA)
@ -65,6 +66,7 @@
#define GLFW_COCOA_LIBRARY_WINDOW_STATE #define GLFW_COCOA_LIBRARY_WINDOW_STATE
#define GLFW_NSGL_CONTEXT_STATE #define GLFW_NSGL_CONTEXT_STATE
#define GLFW_NSGL_LIBRARY_CONTEXT_STATE #define GLFW_NSGL_LIBRARY_CONTEXT_STATE
#define GLFW_NSGL_USER_CONTEXT_STATE
#endif #endif
#if defined(_GLFW_WAYLAND) #if defined(_GLFW_WAYLAND)
@ -88,6 +90,7 @@
#define GLFW_X11_LIBRARY_WINDOW_STATE #define GLFW_X11_LIBRARY_WINDOW_STATE
#define GLFW_GLX_CONTEXT_STATE #define GLFW_GLX_CONTEXT_STATE
#define GLFW_GLX_LIBRARY_CONTEXT_STATE #define GLFW_GLX_LIBRARY_CONTEXT_STATE
#define GLFW_GLX_USER_CONTEXT_STATE
#endif #endif
#include "null_joystick.h" #include "null_joystick.h"
@ -165,6 +168,11 @@
GLFW_NSGL_LIBRARY_CONTEXT_STATE \ GLFW_NSGL_LIBRARY_CONTEXT_STATE \
GLFW_GLX_LIBRARY_CONTEXT_STATE GLFW_GLX_LIBRARY_CONTEXT_STATE
#define GLFW_PLATFORM_USER_CONTEXT_STATE \
GLFW_WGL_USER_CONTEXT_STATE \
GLFW_NSGL_USER_CONTEXT_STATE \
GLFW_GLX_USER_CONTEXT_STATE
#if defined(_WIN32) #if defined(_WIN32)
#define GLFW_BUILD_WIN32_THREAD #define GLFW_BUILD_WIN32_THREAD
#else #else

View File

@ -536,47 +536,17 @@ void _glfwTerminateWGL(void)
attribs[index++] = v; \ attribs[index++] = v; \
} }
// Create the OpenGL or OpenGL ES context // Create the OpenGL or OpenGL ES context for the given HDC
// //
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, GLFWbool _glfwCreateContextForDCWGL(HDC dc, const _GLFWctxconfig* ctxconfig, HGLRC* context)
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{ {
int attribs[40]; int attribs[40];
int pixelFormat;
PIXELFORMATDESCRIPTOR pfd;
HGLRC share = NULL; HGLRC share = NULL;
*context = NULL;
if (ctxconfig->share) if (ctxconfig->share)
share = ctxconfig->share->context.wgl.handle; share = ctxconfig->share->context.wgl.handle;
window->context.wgl.dc = GetDC(window->win32.handle);
if (!window->context.wgl.dc)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to retrieve DC for window");
return GLFW_FALSE;
}
pixelFormat = choosePixelFormatWGL(window, ctxconfig, fbconfig);
if (!pixelFormat)
return GLFW_FALSE;
if (!DescribePixelFormat(window->context.wgl.dc,
pixelFormat, sizeof(pfd), &pfd))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to retrieve PFD for selected pixel format");
return GLFW_FALSE;
}
if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to set selected pixel format");
return GLFW_FALSE;
}
if (ctxconfig->client == GLFW_OPENGL_API) if (ctxconfig->client == GLFW_OPENGL_API)
{ {
if (ctxconfig->forward) if (ctxconfig->forward)
@ -690,9 +660,9 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
SET_ATTRIB(0, 0); SET_ATTRIB(0, 0);
window->context.wgl.handle = *context =
wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs); wglCreateContextAttribsARB(dc, share, attribs);
if (!window->context.wgl.handle) if (!(*context))
{ {
const DWORD error = GetLastError(); const DWORD error = GetLastError();
@ -742,8 +712,8 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
} }
else else
{ {
window->context.wgl.handle = wglCreateContext(window->context.wgl.dc); *context = wglCreateContext(dc);
if (!window->context.wgl.handle) if (!(*context) )
{ {
_glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE, _glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE,
"WGL: Failed to create OpenGL context"); "WGL: Failed to create OpenGL context");
@ -752,7 +722,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
if (share) if (share)
{ {
if (!wglShareLists(share, window->context.wgl.handle)) if (!wglShareLists(share, *context))
{ {
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR, _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to enable sharing with specified OpenGL context"); "WGL: Failed to enable sharing with specified OpenGL context");
@ -761,6 +731,50 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
} }
} }
return GLFW_TRUE;
}
// Create the OpenGL or OpenGL ES context
//
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
int pixelFormat;
PIXELFORMATDESCRIPTOR pfd;
window->context.wgl.dc = GetDC(window->win32.handle);
if (!window->context.wgl.dc)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to retrieve DC for window");
return GLFW_FALSE;
}
pixelFormat = choosePixelFormatWGL(window, ctxconfig, fbconfig);
if (!pixelFormat)
return GLFW_FALSE;
if (!DescribePixelFormat(window->context.wgl.dc,
pixelFormat, sizeof(pfd), &pfd))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to retrieve PFD for selected pixel format");
return GLFW_FALSE;
}
if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to set selected pixel format");
return GLFW_FALSE;
}
if(!_glfwCreateContextForDCWGL( window->context.wgl.dc, ctxconfig, &window->context.wgl.handle ))
{
return GLFW_FALSE;
}
window->context.makeCurrent = makeContextCurrentWGL; window->context.makeCurrent = makeContextCurrentWGL;
window->context.swapBuffers = swapBuffersWGL; window->context.swapBuffers = swapBuffersWGL;
window->context.swapInterval = swapIntervalWGL; window->context.swapInterval = swapIntervalWGL;
@ -771,6 +785,65 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
return GLFW_TRUE; return GLFW_TRUE;
} }
static void _glfwMakeUserContextCurrentWGL(_GLFWusercontext* context)
{
if (context)
{
if (!wglMakeCurrent(context->window->context.wgl.dc,context->wgl.handle))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to make user context current");
_glfwPlatformSetTls(&_glfw.usercontextSlot, NULL);
return;
}
}
else
{
if (!wglMakeCurrent(NULL, NULL))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to clear current user context");
}
}
_glfwPlatformSetTls(&_glfw.usercontextSlot, context);
}
static void _glfwDestroyUserContextWGL(_GLFWusercontext* context)
{
wglDeleteContext(context->wgl.handle);
free(context);
}
_GLFWusercontext* _glfwCreateUserContextWGL(_GLFWwindow* window)
{
_GLFWusercontext* context;
_GLFWctxconfig ctxconfig;
context = calloc(1, sizeof(_GLFWusercontext));
context->window = window;
ctxconfig = _glfw.hints.context;
ctxconfig.share = window;
if (!_glfwCreateContextForDCWGL(window->context.wgl.dc, &ctxconfig, &context->wgl.handle))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to create user OpenGL context");
free(context);
return NULL;
}
context->makeCurrent = _glfwMakeUserContextCurrentWGL;
context->destroy = _glfwDestroyUserContextWGL;
return context;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
#undef SET_ATTRIB #undef SET_ATTRIB
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)

View File

@ -668,6 +668,7 @@ GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform)
.waitEvents = _glfwWaitEventsWin32, .waitEvents = _glfwWaitEventsWin32,
.waitEventsTimeout = _glfwWaitEventsTimeoutWin32, .waitEventsTimeout = _glfwWaitEventsTimeoutWin32,
.postEmptyEvent = _glfwPostEmptyEventWin32, .postEmptyEvent = _glfwPostEmptyEventWin32,
.createUserContext = _glfwCreateUserContextWin32,
.getEGLPlatform = _glfwGetEGLPlatformWin32, .getEGLPlatform = _glfwGetEGLPlatformWin32,
.getEGLNativeDisplay = _glfwGetEGLNativeDisplayWin32, .getEGLNativeDisplay = _glfwGetEGLNativeDisplayWin32,
.getEGLNativeWindow = _glfwGetEGLNativeWindowWin32, .getEGLNativeWindow = _glfwGetEGLNativeWindowWin32,

View File

@ -363,8 +363,9 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(
#define GLFW_WIN32_MONITOR_STATE _GLFWmonitorWin32 win32; #define GLFW_WIN32_MONITOR_STATE _GLFWmonitorWin32 win32;
#define GLFW_WIN32_CURSOR_STATE _GLFWcursorWin32 win32; #define GLFW_WIN32_CURSOR_STATE _GLFWcursorWin32 win32;
#define GLFW_WGL_CONTEXT_STATE _GLFWcontextWGL wgl; #define GLFW_WGL_CONTEXT_STATE _GLFWcontextWGL wgl;
#define GLFW_WGL_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl; #define GLFW_WGL_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl;
#define GLFW_WGL_USER_CONTEXT_STATE _GLFWusercontextWGL wgl;
// WGL-specific per-context data // WGL-specific per-context data
@ -408,6 +409,14 @@ typedef struct _GLFWlibraryWGL
GLFWbool ARB_context_flush_control; GLFWbool ARB_context_flush_control;
} _GLFWlibraryWGL; } _GLFWlibraryWGL;
// WGL-specific per-usercontext data
//
typedef struct _GLFWusercontextWGL
{
HDC dc;
HGLRC handle;
} _GLFWusercontextWGL;
// Win32-specific per-window data // Win32-specific per-window data
// //
typedef struct _GLFWwindowWin32 typedef struct _GLFWwindowWin32
@ -625,3 +634,5 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig); const _GLFWfbconfig* fbconfig);
_GLFWusercontext* _glfwCreateUserContextWin32(_GLFWwindow* window);
_GLFWusercontext* _glfwCreateUserContextWGL(_GLFWwindow* window);

View File

@ -2575,6 +2575,28 @@ VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance,
return err; return err;
} }
_GLFWusercontext* _glfwCreateUserContextWin32(_GLFWwindow* window)
{
if (window->context.wgl.handle)
{
return _glfwCreateUserContextWGL(window);
}
else if (window->context.egl.handle)
{
return _glfwCreateUserContextEGL(window);
}
else if (window->context.osmesa.handle)
{
return _glfwCreateUserContextOSMesa(window);
}
return GLFW_FALSE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle) GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
{ {
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);

View File

@ -510,6 +510,7 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
.waitEvents = _glfwWaitEventsWayland, .waitEvents = _glfwWaitEventsWayland,
.waitEventsTimeout = _glfwWaitEventsTimeoutWayland, .waitEventsTimeout = _glfwWaitEventsTimeoutWayland,
.postEmptyEvent = _glfwPostEmptyEventWayland, .postEmptyEvent = _glfwPostEmptyEventWayland,
.createUserContext = _glfwCreateUserContextWayland,
.getEGLPlatform = _glfwGetEGLPlatformWayland, .getEGLPlatform = _glfwGetEGLPlatformWayland,
.getEGLNativeDisplay = _glfwGetEGLNativeDisplayWayland, .getEGLNativeDisplay = _glfwGetEGLNativeDisplayWayland,
.getEGLNativeWindow = _glfwGetEGLNativeWindowWayland, .getEGLNativeWindow = _glfwGetEGLNativeWindowWayland,

View File

@ -689,6 +689,8 @@ void _glfwSetGammaRampWayland(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
void _glfwAddOutputWayland(uint32_t name, uint32_t version); void _glfwAddOutputWayland(uint32_t name, uint32_t version);
void _glfwUpdateBufferScaleFromOutputsWayland(_GLFWwindow* window); void _glfwUpdateBufferScaleFromOutputsWayland(_GLFWwindow* window);
_GLFWusercontext* _glfwCreateUserContextWayland(_GLFWwindow* window);
void _glfwAddSeatListenerWayland(struct wl_seat* seat); void _glfwAddSeatListenerWayland(struct wl_seat* seat);
void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device); void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device);

View File

@ -3278,6 +3278,19 @@ VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance,
return err; return err;
} }
_GLFWusercontext* _glfwCreateUserContextWayland(_GLFWwindow* window)
{
if (window->context.egl.handle)
{
return _glfwCreateUserContextEGL(window);
}
else if (window->context.osmesa.handle)
{
return _glfwCreateUserContextOSMesa(window);
}
return NULL;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////

View File

@ -1241,6 +1241,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
.waitEvents = _glfwWaitEventsX11, .waitEvents = _glfwWaitEventsX11,
.waitEventsTimeout = _glfwWaitEventsTimeoutX11, .waitEventsTimeout = _glfwWaitEventsTimeoutX11,
.postEmptyEvent = _glfwPostEmptyEventX11, .postEmptyEvent = _glfwPostEmptyEventX11,
.createUserContext = _glfwCreateUserContextX11,
.getEGLPlatform = _glfwGetEGLPlatformX11, .getEGLPlatform = _glfwGetEGLPlatformX11,
.getEGLNativeDisplay = _glfwGetEGLNativeDisplayX11, .getEGLNativeDisplay = _glfwGetEGLNativeDisplayX11,
.getEGLNativeWindow = _glfwGetEGLNativeWindowX11, .getEGLNativeWindow = _glfwGetEGLNativeWindowX11,

View File

@ -462,7 +462,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(Vk
#define GLFW_GLX_CONTEXT_STATE _GLFWcontextGLX glx; #define GLFW_GLX_CONTEXT_STATE _GLFWcontextGLX glx;
#define GLFW_GLX_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx; #define GLFW_GLX_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx;
#define GLFW_GLX_USER_CONTEXT_STATE _GLFWusercontextGLX glx;
// GLX-specific per-context data // GLX-specific per-context data
// //
@ -470,6 +470,7 @@ typedef struct _GLFWcontextGLX
{ {
GLXContext handle; GLXContext handle;
GLXWindow window; GLXWindow window;
GLXFBConfig fbconfig;
} _GLFWcontextGLX; } _GLFWcontextGLX;
// GLX-specific global data // GLX-specific global data
@ -518,6 +519,13 @@ typedef struct _GLFWlibraryGLX
GLFWbool ARB_context_flush_control; GLFWbool ARB_context_flush_control;
} _GLFWlibraryGLX; } _GLFWlibraryGLX;
// GLX-specific per usercontext data
//
typedef struct _GLFWusercontextGLX
{
GLXContext handle;
} _GLFWusercontextGLX;
// X11-specific per-window data // X11-specific per-window data
// //
typedef struct _GLFWwindowX11 typedef struct _GLFWwindowX11
@ -1002,3 +1010,5 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
const _GLFWfbconfig* fbconfig, const _GLFWfbconfig* fbconfig,
Visual** visual, int* depth); Visual** visual, int* depth);
_GLFWusercontext* _glfwCreateUserContextX11(_GLFWwindow* window);
_GLFWusercontext* _glfwCreateUserContextGLX(_GLFWwindow* window);

View File

@ -3282,6 +3282,24 @@ VkResult _glfwCreateWindowSurfaceX11(VkInstance instance,
} }
} }
_GLFWusercontext* _glfwCreateUserContextX11(_GLFWwindow* window)
{
if (window->context.glx.handle)
{
return _glfwCreateUserContextGLX(window);
}
else if (window->context.egl.handle)
{
return _glfwCreateUserContextEGL(window);
}
else if (window->context.osmesa.handle)
{
return _glfwCreateUserContextOSMesa(window);
}
return NULL;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////

View File

@ -28,6 +28,7 @@ add_executable(iconify iconify.c ${GETOPT} ${GLAD_GL})
add_executable(monitors monitors.c ${GETOPT} ${GLAD_GL}) add_executable(monitors monitors.c ${GETOPT} ${GLAD_GL})
add_executable(reopen reopen.c ${GLAD_GL}) add_executable(reopen reopen.c ${GLAD_GL})
add_executable(cursor cursor.c ${GLAD_GL}) add_executable(cursor cursor.c ${GLAD_GL})
add_executable(usercontext usercontext.c ${TINYCTHREAD} ${GLAD_GL})
add_executable(empty WIN32 MACOSX_BUNDLE empty.c ${TINYCTHREAD} ${GLAD_GL}) add_executable(empty WIN32 MACOSX_BUNDLE empty.c ${TINYCTHREAD} ${GLAD_GL})
add_executable(gamma WIN32 MACOSX_BUNDLE gamma.c ${GLAD_GL}) add_executable(gamma WIN32 MACOSX_BUNDLE gamma.c ${GLAD_GL})
@ -51,7 +52,7 @@ endif()
set(GUI_ONLY_BINARIES empty gamma icon inputlag joysticks tearing threads set(GUI_ONLY_BINARIES empty gamma icon inputlag joysticks tearing threads
timeout title triangle-vulkan window) timeout title triangle-vulkan window)
set(CONSOLE_BINARIES allocator clipboard events msaa glfwinfo iconify monitors set(CONSOLE_BINARIES allocator clipboard events msaa glfwinfo iconify monitors
reopen cursor) reopen cursor usercontext)
set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES
C_STANDARD 99 C_STANDARD 99

200
tests/usercontext.c Normal file
View File

@ -0,0 +1,200 @@
//========================================================================
// User context test
// Copyright (c) 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.
//
//========================================================================
//
// This test is intended to verify whether the OpenGL user context part of
// the GLFW API is able to be used from multiple threads
//
//========================================================================
#include "tinycthread.h"
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <stdio.h>
static void error_callback(int error, const char* description)
{
fprintf(stderr, "Error: %s\n", description);
}
static int thread_main(void* data)
{
GLFWusercontext* usercontext = (GLFWusercontext*)data;
/* set the user context current */
glfwMakeUserContextCurrent(usercontext);
if (glfwGetCurrentContext() != NULL)
{
fprintf(stderr, "Current glfw window context not NULL after glfwMakeUserContextCurrent\n");
glfwTerminate();
return -1;
}
if (glfwGetCurrentUserContext() != usercontext)
{
fprintf(stderr, "Current user context not correct after glfwMakeUserContextCurrent\n");
glfwTerminate();
return -1;
}
/* set the user context to NULL */
glfwMakeUserContextCurrent(NULL);
if (glfwGetCurrentUserContext() != NULL)
{
fprintf(stderr, "Current user context not NULL after glfwMakeContextCurrent\n");
glfwTerminate();
return -1;
}
return 0;
}
int main(void)
{
GLFWwindow* window;
GLFWusercontext* usercontext;
thrd_t thread_id;
int result, count;
glfwSetErrorCallback(error_callback);
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "User Context", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
gladLoadGL(glfwGetProcAddress);
/* make a new context */
usercontext = glfwCreateUserContext(window);
if (!usercontext)
{
fprintf(stderr, "Failed to create user context\n");
glfwTerminate();
return -1;
}
/* set the user context current */
glfwMakeUserContextCurrent(usercontext);
if (glfwGetCurrentContext() != NULL)
{
fprintf(stderr, "Current glfw window context not NULL after glfwMakeUserContextCurrent\n");
glfwTerminate();
return -1;
}
if (glfwGetCurrentUserContext() != usercontext)
{
fprintf(stderr, "Current user context not correct after glfwMakeUserContextCurrent\n");
glfwTerminate();
return -1;
}
/* set the window context current */
glfwMakeContextCurrent(window);
if (glfwGetCurrentUserContext() != NULL)
{
fprintf(stderr, "Current user context not NULL after glfwMakeContextCurrent\n");
glfwTerminate();
return -1;
}
if (glfwGetCurrentContext() != window)
{
fprintf(stderr, "Current glfw window context not correct after glfwMakeContextCurrent\n");
glfwTerminate();
return -1;
}
glClearColor( 0.4f, 0.3f, 0.4f, 1.0f );
// Launch a thread which should create and use the usercontext
if (thrd_create(&thread_id, thread_main, usercontext ) !=
thrd_success)
{
fprintf(stderr, "Failed to create secondary thread\n");
glfwTerminate();
exit(EXIT_FAILURE);
}
/* Loop 60 times or until the user closes the window */
count = 0;
while (!glfwWindowShouldClose(window) && count++ < 60)
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
thrd_join(thread_id, &result);
/* One more test now the thread has joined */
/* set the user context current */
glfwMakeUserContextCurrent(usercontext);
if (glfwGetCurrentContext() != NULL)
{
fprintf(stderr, "Current glfw window context not NULL after glfwMakeUserContextCurrent\n");
glfwTerminate();
return -1;
}
if (glfwGetCurrentUserContext() != usercontext)
{
fprintf(stderr, "Current user context not correct after glfwMakeUserContextCurrent\n");
glfwTerminate();
return -1;
}
/* set the user context to NULL */
glfwMakeUserContextCurrent(NULL);
if (glfwGetCurrentUserContext() != NULL)
{
fprintf(stderr, "Current user context not NULL after glfwMakeContextCurrent\n");
glfwTerminate();
return -1;
}
glfwDestroyUserContext(usercontext);
glfwTerminate();
return 0;
}