mirror of
https://github.com/glfw/glfw.git
synced 2025-04-22 08:32:51 +00:00
Merge e2f9340a8c
into e7ea71be03
This commit is contained in:
commit
481f83d218
@ -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
|
||||||
|
@ -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}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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 //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -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);
|
||||||
|
}
|
@ -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 //////
|
||||||
|
@ -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 //////
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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 //////
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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 //////
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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 //////
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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 //////
|
||||||
|
@ -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
200
tests/usercontext.c
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user