1
0
Fork 0
mirror of https://github.com/gwm17/glfw.git synced 2024-11-23 10:48:51 -05:00

Reintroduced manual framebuffer config selection.

The default behavior of WGL, EGL and GLX is to choose a config that has
/at least/ the specified number of bits, whereas the GLFW 2 behavior was
to choose the closest match with very few hard constraints.  Moving the
responsibility of finding the supported minimum values to the client was
problematic, as there's no way to enumerate supported configurations,
forcing the client to perform multiple (and slow) window/context
creation attempts.  Not even the currently set defaults (24-bit color
and depth, 8-bit stencil) is universally supported, as bug reports show.
This commit is contained in:
Camilla Berglund 2013-05-13 15:49:59 +02:00
parent 538556bfd5
commit d82f068f7e
9 changed files with 589 additions and 256 deletions

View File

@ -204,6 +204,163 @@ GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig)
return GL_TRUE; return GL_TRUE;
} }
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
const _GLFWfbconfig* alternatives,
unsigned int count)
{
unsigned int i;
unsigned int missing, leastMissing = UINT_MAX;
unsigned int colorDiff, leastColorDiff = UINT_MAX;
unsigned int extraDiff, leastExtraDiff = UINT_MAX;
const _GLFWfbconfig* current;
const _GLFWfbconfig* closest = NULL;
for (i = 0; i < count; i++)
{
current = alternatives + i;
if (desired->stereo > 0 && current->stereo == 0)
{
// Stereo is a hard constraint
continue;
}
// Count number of missing buffers
{
missing = 0;
if (desired->alphaBits > 0 && current->alphaBits == 0)
missing++;
if (desired->depthBits > 0 && current->depthBits == 0)
missing++;
if (desired->stencilBits > 0 && current->stencilBits == 0)
missing++;
if (desired->auxBuffers > 0 && current->auxBuffers < desired->auxBuffers)
missing += desired->auxBuffers - current->auxBuffers;
if (desired->samples > 0 && current->samples == 0)
{
// Technically, several multisampling buffers could be
// involved, but that's a lower level implementation detail and
// not important to us here, so we count them as one
missing++;
}
}
// These polynomials make many small channel size differences matter
// less than one large channel size difference
// Calculate color channel size difference value
{
colorDiff = 0;
if (desired->redBits > 0)
{
colorDiff += (desired->redBits - current->redBits) *
(desired->redBits - current->redBits);
}
if (desired->greenBits > 0)
{
colorDiff += (desired->greenBits - current->greenBits) *
(desired->greenBits - current->greenBits);
}
if (desired->blueBits > 0)
{
colorDiff += (desired->blueBits - current->blueBits) *
(desired->blueBits - current->blueBits);
}
}
// Calculate non-color channel size difference value
{
extraDiff = 0;
if (desired->alphaBits > 0)
{
extraDiff += (desired->alphaBits - current->alphaBits) *
(desired->alphaBits - current->alphaBits);
}
if (desired->depthBits > 0)
{
extraDiff += (desired->depthBits - current->depthBits) *
(desired->depthBits - current->depthBits);
}
if (desired->stencilBits > 0)
{
extraDiff += (desired->stencilBits - current->stencilBits) *
(desired->stencilBits - current->stencilBits);
}
if (desired->accumRedBits > 0)
{
extraDiff += (desired->accumRedBits - current->accumRedBits) *
(desired->accumRedBits - current->accumRedBits);
}
if (desired->accumGreenBits > 0)
{
extraDiff += (desired->accumGreenBits - current->accumGreenBits) *
(desired->accumGreenBits - current->accumGreenBits);
}
if (desired->accumBlueBits > 0)
{
extraDiff += (desired->accumBlueBits - current->accumBlueBits) *
(desired->accumBlueBits - current->accumBlueBits);
}
if (desired->accumAlphaBits > 0)
{
extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) *
(desired->accumAlphaBits - current->accumAlphaBits);
}
if (desired->samples > 0)
{
extraDiff += (desired->samples - current->samples) *
(desired->samples - current->samples);
}
if (desired->sRGB)
{
if (!current->sRGB)
extraDiff++;
}
}
// Figure out if the current one is better than the best one found so far
// Least number of missing buffers is the most important heuristic,
// then color buffer size match and lastly size match for other buffers
if (missing < leastMissing)
closest = current;
else if (missing == leastMissing)
{
if ((colorDiff < leastColorDiff) ||
(colorDiff == leastColorDiff && extraDiff < leastExtraDiff))
{
closest = current;
}
}
if (current == closest)
{
leastMissing = missing;
leastColorDiff = colorDiff;
leastExtraDiff = extraDiff;
}
}
return closest;
}
GLboolean _glfwRefreshContextParams(void) GLboolean _glfwRefreshContextParams(void)
{ {
_GLFWwindow* window = _glfwPlatformGetCurrentContext(); _GLFWwindow* window = _glfwPlatformGetCurrentContext();

View File

@ -100,6 +100,107 @@ static const char* getErrorString(EGLint error)
return "UNKNOWN EGL ERROR"; return "UNKNOWN EGL ERROR";
} }
// Returns the specified attribute of the specified EGLConfig
//
static int getConfigAttrib(EGLConfig config, int attrib)
{
int value;
eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
return value;
}
// Return a list of available and usable framebuffer configs
//
static GLboolean chooseFBConfigs(const _GLFWwndconfig* wndconfig,
const _GLFWfbconfig* desired,
EGLConfig* result)
{
EGLConfig* nativeConfigs;
_GLFWfbconfig* usableConfigs;
const _GLFWfbconfig* closest;
int i, nativeCount, usableCount;
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
if (!nativeCount)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
return GL_FALSE;
}
nativeConfigs = (EGLConfig*) calloc(nativeCount, sizeof(EGLConfig));
eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount);
usableConfigs = (_GLFWfbconfig*) calloc(nativeCount, sizeof(_GLFWfbconfig));
usableCount = 0;
for (i = 0; i < nativeCount; i++)
{
const EGLConfig n = nativeConfigs[i];
_GLFWfbconfig* u = usableConfigs + usableCount;
#if defined(_GLFW_X11)
if (!getConfigAttrib(n, EGL_NATIVE_VISUAL_ID))
{
// Only consider EGLConfigs with associated visuals
continue;
}
#endif // _GLFW_X11
if (!(getConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) & EGL_RGB_BUFFER))
{
// Only consider RGB(A) EGLConfigs
continue;
}
if (!(getConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
{
// Only consider window EGLConfigs
continue;
}
if (wndconfig->clientAPI == GLFW_OPENGL_ES_API)
{
if (wndconfig->glMajor == 1)
{
if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
continue;
}
else
{
if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
continue;
}
}
else if (wndconfig->clientAPI == GLFW_OPENGL_API)
{
if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
continue;
}
u->redBits = getConfigAttrib(n, EGL_RED_SIZE);
u->greenBits = getConfigAttrib(n, EGL_GREEN_SIZE);
u->blueBits = getConfigAttrib(n, EGL_BLUE_SIZE);
u->alphaBits = getConfigAttrib(n, EGL_ALPHA_SIZE);
u->depthBits = getConfigAttrib(n, EGL_DEPTH_SIZE);
u->stencilBits = getConfigAttrib(n, EGL_STENCIL_SIZE);
u->samples = getConfigAttrib(n, EGL_SAMPLES);
u->egl = n;
usableCount++;
}
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
if (closest)
*result = closest->egl;
free(nativeConfigs);
free(usableConfigs);
return closest ? GL_TRUE : GL_FALSE;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW internal API ////// ////// GLFW internal API //////
@ -162,58 +263,12 @@ int _glfwCreateContext(_GLFWwindow* window,
if (wndconfig->share) if (wndconfig->share)
share = wndconfig->share->egl.context; share = wndconfig->share->egl.context;
// Find a suitable EGLConfig if (!chooseFBConfigs(wndconfig, fbconfig, &config))
{
int index = 0;
if (wndconfig->clientAPI == GLFW_OPENGL_API)
setEGLattrib(EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT);
if (wndconfig->clientAPI == GLFW_OPENGL_ES_API)
{
if (wndconfig->glMajor == 1)
setEGLattrib(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT);
if (wndconfig->glMajor == 2)
setEGLattrib(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT);
if (wndconfig->glMajor == 3)
setEGLattrib(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR);
}
setEGLattrib(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
if (fbconfig->redBits)
setEGLattrib(EGL_RED_SIZE, fbconfig->redBits);
if (fbconfig->greenBits)
setEGLattrib(EGL_GREEN_SIZE, fbconfig->greenBits);
if (fbconfig->blueBits)
setEGLattrib(EGL_BLUE_SIZE, fbconfig->blueBits);
if (fbconfig->alphaBits)
setEGLattrib(EGL_ALPHA_SIZE, fbconfig->alphaBits);
if (fbconfig->depthBits)
setEGLattrib(EGL_DEPTH_SIZE, fbconfig->depthBits);
if (fbconfig->stencilBits)
setEGLattrib(EGL_STENCIL_SIZE, fbconfig->stencilBits);
if (fbconfig->samples)
{
setEGLattrib(EGL_SAMPLE_BUFFERS, 1);
setEGLattrib(EGL_SAMPLES, fbconfig->samples);
}
setEGLattrib(EGL_NONE, EGL_NONE);
eglChooseConfig(_glfw.egl.display, attribs, &config, 1, &count);
if (!count)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to find a suitable EGLConfig: %s", "EGL: Failed to find a suitable EGLConfig");
getErrorString(eglGetError()));
return GL_FALSE; return GL_FALSE;
} }
}
#if defined(_GLFW_X11) #if defined(_GLFW_X11)
// Retrieve the visual corresponding to the chosen EGL config // Retrieve the visual corresponding to the chosen EGL config

View File

@ -43,6 +43,7 @@
#include <dlfcn.h> #include <dlfcn.h>
#endif #endif
#define _GLFW_PLATFORM_FBCONFIG EGLConfig egl
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextEGL egl #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextEGL egl
#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryEGL egl #define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryEGL egl

View File

@ -53,6 +53,130 @@ static int errorHandler(Display *display, XErrorEvent* event)
return 0; return 0;
} }
// Returns the specified attribute of the specified GLXFBConfig
// NOTE: Do not call this unless we have found GLX 1.3+ or GLX_SGIX_fbconfig
//
static int getFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
{
int value;
if (_glfw.glx.SGIX_fbconfig)
{
_glfw.glx.GetFBConfigAttribSGIX(_glfw.x11.display,
fbconfig, attrib, &value);
}
else
glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value);
return value;
}
// Return a list of available and usable framebuffer configs
//
static GLboolean chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result)
{
GLXFBConfig* nativeConfigs;
_GLFWfbconfig* usableConfigs;
const _GLFWfbconfig* closest;
int i, nativeCount, usableCount;
const char* vendor;
GLboolean trustWindowBit = GL_TRUE;
vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
if (strcmp(vendor, "Chromium") == 0)
{
// HACK: This is a (hopefully temporary) workaround for Chromium
// (VirtualBox GL) not setting the window bit on any GLXFBConfigs
trustWindowBit = GL_FALSE;
}
if (_glfw.glx.SGIX_fbconfig)
{
nativeConfigs = _glfw.glx.ChooseFBConfigSGIX(_glfw.x11.display,
_glfw.x11.screen,
NULL,
&nativeCount);
}
else
{
nativeConfigs = glXGetFBConfigs(_glfw.x11.display,
_glfw.x11.screen,
&nativeCount);
}
if (!nativeCount)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"GLX: No GLXFBConfigs returned");
return GL_FALSE;
}
usableConfigs = (_GLFWfbconfig*) calloc(nativeCount, sizeof(_GLFWfbconfig));
usableCount = 0;
for (i = 0; i < nativeCount; i++)
{
const GLXFBConfig n = nativeConfigs[i];
_GLFWfbconfig* u = usableConfigs + usableCount;
if (!getFBConfigAttrib(n, GLX_DOUBLEBUFFER) ||
!getFBConfigAttrib(n, GLX_VISUAL_ID))
{
// Only consider double-buffered GLXFBConfigs with associated visuals
continue;
}
if (!(getFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT))
{
// Only consider RGBA GLXFBConfigs
continue;
}
if (!(getFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT))
{
if (trustWindowBit)
{
// Only consider window GLXFBConfigs
continue;
}
}
u->redBits = getFBConfigAttrib(n, GLX_RED_SIZE);
u->greenBits = getFBConfigAttrib(n, GLX_GREEN_SIZE);
u->blueBits = getFBConfigAttrib(n, GLX_BLUE_SIZE);
u->alphaBits = getFBConfigAttrib(n, GLX_ALPHA_SIZE);
u->depthBits = getFBConfigAttrib(n, GLX_DEPTH_SIZE);
u->stencilBits = getFBConfigAttrib(n, GLX_STENCIL_SIZE);
u->accumRedBits = getFBConfigAttrib(n, GLX_ACCUM_RED_SIZE);
u->accumGreenBits = getFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE);
u->accumBlueBits = getFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE);
u->accumAlphaBits = getFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
u->auxBuffers = getFBConfigAttrib(n, GLX_AUX_BUFFERS);
u->stereo = getFBConfigAttrib(n, GLX_STEREO);
if (_glfw.glx.ARB_multisample)
u->samples = getFBConfigAttrib(n, GLX_SAMPLES);
if (_glfw.glx.ARB_framebuffer_sRGB)
u->sRGB = getFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
u->glx = n;
usableCount++;
}
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
if (closest)
*result = closest->glx;
XFree(nativeConfigs);
free(usableConfigs);
return closest ? GL_TRUE : GL_FALSE;
}
// Create the OpenGL context using legacy API // Create the OpenGL context using legacy API
// //
static GLXContext createLegacyContext(_GLFWwindow* window, static GLXContext createLegacyContext(_GLFWwindow* window,
@ -240,104 +364,30 @@ int _glfwCreateContext(_GLFWwindow* window,
const _GLFWfbconfig* fbconfig) const _GLFWfbconfig* fbconfig)
{ {
int attribs[40]; int attribs[40];
GLXFBConfig* native; GLXFBConfig native;
GLXContext share = NULL; GLXContext share = NULL;
if (wndconfig->share) if (wndconfig->share)
share = wndconfig->share->glx.context; share = wndconfig->share->glx.context;
// Find a suitable GLXFBConfig if (!chooseFBConfig(fbconfig, &native))
{
int count, index = 0;
setGLXattrib(GLX_DOUBLEBUFFER, True);
setGLXattrib(GLX_X_RENDERABLE, True);
if (fbconfig->redBits)
setGLXattrib(GLX_RED_SIZE, fbconfig->redBits);
if (fbconfig->greenBits)
setGLXattrib(GLX_GREEN_SIZE, fbconfig->greenBits);
if (fbconfig->blueBits)
setGLXattrib(GLX_BLUE_SIZE, fbconfig->blueBits);
if (fbconfig->alphaBits)
setGLXattrib(GLX_ALPHA_SIZE, fbconfig->alphaBits);
if (fbconfig->depthBits)
setGLXattrib(GLX_DEPTH_SIZE, fbconfig->depthBits);
if (fbconfig->stencilBits)
setGLXattrib(GLX_STENCIL_SIZE, fbconfig->stencilBits);
if (fbconfig->auxBuffers)
setGLXattrib(GLX_AUX_BUFFERS, fbconfig->auxBuffers);
if (fbconfig->accumRedBits)
setGLXattrib(GLX_ACCUM_RED_SIZE, fbconfig->accumRedBits);
if (fbconfig->accumGreenBits)
setGLXattrib(GLX_ACCUM_GREEN_SIZE, fbconfig->accumGreenBits);
if (fbconfig->accumBlueBits)
setGLXattrib(GLX_ACCUM_BLUE_SIZE, fbconfig->accumBlueBits);
if (fbconfig->accumAlphaBits)
setGLXattrib(GLX_ACCUM_BLUE_SIZE, fbconfig->accumAlphaBits);
if (fbconfig->stereo)
setGLXattrib(GLX_STEREO, True);
if (_glfw.glx.ARB_multisample)
{
if (fbconfig->samples)
{
setGLXattrib(GLX_SAMPLE_BUFFERS_ARB, 1);
setGLXattrib(GLX_SAMPLES_ARB, fbconfig->samples);
}
}
if (_glfw.glx.ARB_framebuffer_sRGB)
{
if (fbconfig->sRGB)
setGLXattrib(GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True);
}
setGLXattrib(None, None);
if (_glfw.glx.SGIX_fbconfig)
{
native = _glfw.glx.ChooseFBConfigSGIX(_glfw.x11.display,
_glfw.x11.screen,
attribs,
&count);
}
else
{
native = glXChooseFBConfig(_glfw.x11.display,
_glfw.x11.screen,
attribs,
&count);
}
if (native == NULL)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"GLX: Failed to find a suitable GLXFBConfig"); "GLX: Failed to find a suitable GLXFBConfig");
return GL_FALSE; return GL_FALSE;
} }
}
// Retrieve the corresponding visual // Retrieve the corresponding visual
if (_glfw.glx.SGIX_fbconfig) if (_glfw.glx.SGIX_fbconfig)
{ {
window->glx.visual = window->glx.visual =
_glfw.glx.GetVisualFromFBConfigSGIX(_glfw.x11.display, *native); _glfw.glx.GetVisualFromFBConfigSGIX(_glfw.x11.display, native);
} }
else else
{ window->glx.visual = glXGetVisualFromFBConfig(_glfw.x11.display, native);
window->glx.visual = glXGetVisualFromFBConfig(_glfw.x11.display,
*native);
}
if (window->glx.visual == NULL) if (window->glx.visual == NULL)
{ {
XFree(native);
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"GLX: Failed to retrieve visual for GLXFBConfig"); "GLX: Failed to retrieve visual for GLXFBConfig");
return GL_FALSE; return GL_FALSE;
@ -349,8 +399,6 @@ int _glfwCreateContext(_GLFWwindow* window,
!_glfw.glx.ARB_create_context_profile || !_glfw.glx.ARB_create_context_profile ||
!_glfw.glx.EXT_create_context_es2_profile) !_glfw.glx.EXT_create_context_es2_profile)
{ {
XFree(native);
_glfwInputError(GLFW_VERSION_UNAVAILABLE, _glfwInputError(GLFW_VERSION_UNAVAILABLE,
"GLX: OpenGL ES requested but " "GLX: OpenGL ES requested but "
"GLX_EXT_create_context_es2_profile is unavailable"); "GLX_EXT_create_context_es2_profile is unavailable");
@ -362,8 +410,6 @@ int _glfwCreateContext(_GLFWwindow* window,
{ {
if (!_glfw.glx.ARB_create_context) if (!_glfw.glx.ARB_create_context)
{ {
XFree(native);
_glfwInputError(GLFW_VERSION_UNAVAILABLE, _glfwInputError(GLFW_VERSION_UNAVAILABLE,
"GLX: Forward compatibility requested but " "GLX: Forward compatibility requested but "
"GLX_ARB_create_context_profile is unavailable"); "GLX_ARB_create_context_profile is unavailable");
@ -376,8 +422,6 @@ int _glfwCreateContext(_GLFWwindow* window,
if (!_glfw.glx.ARB_create_context || if (!_glfw.glx.ARB_create_context ||
!_glfw.glx.ARB_create_context_profile) !_glfw.glx.ARB_create_context_profile)
{ {
XFree(native);
_glfwInputError(GLFW_VERSION_UNAVAILABLE, _glfwInputError(GLFW_VERSION_UNAVAILABLE,
"GLX: An OpenGL profile requested but " "GLX: An OpenGL profile requested but "
"GLX_ARB_create_context_profile is unavailable"); "GLX_ARB_create_context_profile is unavailable");
@ -447,7 +491,7 @@ int _glfwCreateContext(_GLFWwindow* window,
window->glx.context = window->glx.context =
_glfw.glx.CreateContextAttribsARB(_glfw.x11.display, _glfw.glx.CreateContextAttribsARB(_glfw.x11.display,
*native, native,
share, share,
True, True,
attribs); attribs);
@ -462,17 +506,15 @@ int _glfwCreateContext(_GLFWwindow* window,
wndconfig->glProfile == GLFW_OPENGL_NO_PROFILE && wndconfig->glProfile == GLFW_OPENGL_NO_PROFILE &&
wndconfig->glForward == GL_FALSE) wndconfig->glForward == GL_FALSE)
{ {
window->glx.context = createLegacyContext(window, *native, share); window->glx.context = createLegacyContext(window, native, share);
} }
} }
} }
else else
window->glx.context = createLegacyContext(window, *native, share); window->glx.context = createLegacyContext(window, native, share);
XSetErrorHandler(NULL); XSetErrorHandler(NULL);
XFree(native);
if (window->glx.context == NULL) if (window->glx.context == NULL)
{ {
char buffer[8192]; char buffer[8192];

View File

@ -60,6 +60,7 @@
#error "No OpenGL entry point retrieval mechanism was enabled" #error "No OpenGL entry point retrieval mechanism was enabled"
#endif #endif
#define _GLFW_PLATFORM_FBCONFIG GLXFBConfig glx
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx
#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryGLX glx #define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryGLX glx

View File

@ -153,8 +153,11 @@ struct _GLFWwndconfig
/*! @brief Framebuffer configuration. /*! @brief Framebuffer configuration.
* *
* This describes buffers and their sizes. It is used to pass framebuffer * This describes buffers and their sizes. It also contains
* parameters from shared code to the platform API. * a platform-specific ID used to map back to the backend API's object.
*
* It is used to pass framebuffer parameters from shared code to the platform
* API and also to enumerate and select available framebuffer configs.
*/ */
struct _GLFWfbconfig struct _GLFWfbconfig
{ {
@ -172,6 +175,9 @@ struct _GLFWfbconfig
GLboolean stereo; GLboolean stereo;
int samples; int samples;
GLboolean sRGB; GLboolean sRGB;
// This is defined in the context API's platform.h
_GLFW_PLATFORM_FBCONFIG;
}; };
@ -670,6 +676,18 @@ void _glfwSplitBPP(int bpp, int* red, int* green, int* blue);
*/ */
int _glfwStringInExtensionString(const char* string, const GLubyte* extensions); int _glfwStringInExtensionString(const char* string, const GLubyte* extensions);
/*! @brief Chooses the framebuffer config that best matches the desired one.
* @param[in] desired The desired framebuffer config.
* @param[in] alternatives The framebuffer configs supported by the system.
* @param[in] count The number of entries in the alternatives array.
* @return The framebuffer config most closely matching the desired one, or @c
* NULL if none fulfilled the hard constraints of the desired values.
* @ingroup utility
*/
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
const _GLFWfbconfig* alternatives,
unsigned int count);
/*! @brief Checks and reads back properties from the current context. /*! @brief Checks and reads back properties from the current context.
* @return `GL_TRUE` if successful, or `GL_FALSE` if the context is unusable. * @return `GL_TRUE` if successful, or `GL_FALSE` if the context is unusable.
* @ingroup utility * @ingroup utility

View File

@ -31,6 +31,7 @@
#define _nsgl_platform_h_ #define _nsgl_platform_h_
#define _GLFW_PLATFORM_FBCONFIG
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl
#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryNSGL nsgl #define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryNSGL nsgl

View File

@ -45,7 +45,7 @@ static void initWGLExtensions(_GLFWwindow* window)
{ {
// This needs to include every function pointer loaded below // This needs to include every function pointer loaded below
window->wgl.SwapIntervalEXT = NULL; window->wgl.SwapIntervalEXT = NULL;
window->wgl.ChoosePixelFormatARB = NULL; window->wgl.GetPixelFormatAttribivARB = NULL;
window->wgl.GetExtensionsStringARB = NULL; window->wgl.GetExtensionsStringARB = NULL;
window->wgl.GetExtensionsStringEXT = NULL; window->wgl.GetExtensionsStringEXT = NULL;
window->wgl.CreateContextAttribsARB = NULL; window->wgl.CreateContextAttribsARB = NULL;
@ -116,14 +116,174 @@ static void initWGLExtensions(_GLFWwindow* window)
if (_glfwPlatformExtensionSupported("WGL_ARB_pixel_format")) if (_glfwPlatformExtensionSupported("WGL_ARB_pixel_format"))
{ {
window->wgl.ChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) window->wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
wglGetProcAddress("wglChoosePixelFormatARB"); wglGetProcAddress("wglGetPixelFormatAttribivARB");
if (window->wgl.ChoosePixelFormatARB) if (window->wgl.GetPixelFormatAttribivARB)
window->wgl.ARB_pixel_format = GL_TRUE; window->wgl.ARB_pixel_format = GL_TRUE;
} }
} }
// Returns the specified attribute of the specified pixel format
// NOTE: Do not call this unless we have found WGL_ARB_pixel_format
//
static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib)
{
int value = 0;
if (!window->wgl.GetPixelFormatAttribivARB(window->wgl.dc,
pixelFormat,
0, 1, &attrib, &value))
{
// NOTE: We should probably handle this error somehow
return 0;
}
return value;
}
// Return a list of available and usable framebuffer configs
//
static GLboolean choosePixelFormat(_GLFWwindow* window,
const _GLFWfbconfig* desired,
int* result)
{
_GLFWfbconfig* usableConfigs;
const _GLFWfbconfig* closest;
int i, nativeCount, usableCount;
if (window->wgl.ARB_pixel_format)
{
nativeCount = getPixelFormatAttrib(window,
1,
WGL_NUMBER_PIXEL_FORMATS_ARB);
}
else
{
nativeCount = DescribePixelFormat(window->wgl.dc,
1,
sizeof(PIXELFORMATDESCRIPTOR),
NULL);
}
if (!nativeCount)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "WGL: No pixel formats found");
return GL_FALSE;
}
usableConfigs = (_GLFWfbconfig*) calloc(nativeCount, sizeof(_GLFWfbconfig));
usableCount = 0;
for (i = 0; i < nativeCount; i++)
{
const int n = i + 1;
_GLFWfbconfig* u = usableConfigs + usableCount;
if (window->wgl.ARB_pixel_format)
{
// Get pixel format attributes through WGL_ARB_pixel_format
if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) ||
!getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB) ||
!getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB))
{
continue;
}
if (getPixelFormatAttrib(window, n, WGL_PIXEL_TYPE_ARB) !=
WGL_TYPE_RGBA_ARB)
{
continue;
}
if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) ==
WGL_NO_ACCELERATION_ARB)
{
continue;
}
u->redBits = getPixelFormatAttrib(window, n, WGL_RED_BITS_ARB);
u->greenBits = getPixelFormatAttrib(window, n, WGL_GREEN_BITS_ARB);
u->blueBits = getPixelFormatAttrib(window, n, WGL_BLUE_BITS_ARB);
u->alphaBits = getPixelFormatAttrib(window, n, WGL_ALPHA_BITS_ARB);
u->depthBits = getPixelFormatAttrib(window, n, WGL_DEPTH_BITS_ARB);
u->stencilBits = getPixelFormatAttrib(window, n, WGL_STENCIL_BITS_ARB);
u->accumRedBits = getPixelFormatAttrib(window, n, WGL_ACCUM_RED_BITS_ARB);
u->accumGreenBits = getPixelFormatAttrib(window, n, WGL_ACCUM_GREEN_BITS_ARB);
u->accumBlueBits = getPixelFormatAttrib(window, n, WGL_ACCUM_BLUE_BITS_ARB);
u->accumAlphaBits = getPixelFormatAttrib(window, n, WGL_ACCUM_ALPHA_BITS_ARB);
u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_ARB);
u->stereo = getPixelFormatAttrib(window, n, WGL_STEREO_ARB);
if (window->wgl.ARB_multisample)
u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB);
if (window->wgl.ARB_framebuffer_sRGB)
u->sRGB = getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
}
else
{
PIXELFORMATDESCRIPTOR pfd;
// Get pixel format attributes through old-fashioned PFDs
if (!DescribePixelFormat(window->wgl.dc,
n,
sizeof(PIXELFORMATDESCRIPTOR),
&pfd))
{
continue;
}
if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
!(pfd.dwFlags & PFD_SUPPORT_OPENGL) ||
!(pfd.dwFlags & PFD_DOUBLEBUFFER))
{
continue;
}
if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) &&
(pfd.dwFlags & PFD_GENERIC_FORMAT))
{
continue;
}
if (pfd.iPixelType != PFD_TYPE_RGBA)
continue;
u->redBits = pfd.cRedBits;
u->greenBits = pfd.cGreenBits;
u->blueBits = pfd.cBlueBits;
u->alphaBits = pfd.cAlphaBits;
u->depthBits = pfd.cDepthBits;
u->stencilBits = pfd.cStencilBits;
u->accumRedBits = pfd.cAccumRedBits;
u->accumGreenBits = pfd.cAccumGreenBits;
u->accumBlueBits = pfd.cAccumBlueBits;
u->accumAlphaBits = pfd.cAccumAlphaBits;
u->auxBuffers = pfd.cAuxBuffers;
u->stereo = (pfd.dwFlags & PFD_STEREO) ? GL_TRUE : GL_FALSE;
}
u->wgl = n;
usableCount++;
}
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
if (closest)
*result = closest->wgl;
free(usableConfigs);
return GL_TRUE;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW internal API ////// ////// GLFW internal API //////
@ -183,107 +343,12 @@ int _glfwCreateContext(_GLFWwindow* window,
return GL_FALSE; return GL_FALSE;
} }
if (window->wgl.ARB_pixel_format) if (!choosePixelFormat(window, fbconfig, &pixelFormat))
{
int index = 0;
UINT count;
setWGLattrib(WGL_SUPPORT_OPENGL_ARB, TRUE);
setWGLattrib(WGL_DRAW_TO_WINDOW_ARB, TRUE);
setWGLattrib(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
setWGLattrib(WGL_DOUBLE_BUFFER_ARB, TRUE);
if (fbconfig->redBits)
setWGLattrib(WGL_RED_BITS_ARB, fbconfig->redBits);
if (fbconfig->greenBits)
setWGLattrib(WGL_GREEN_BITS_ARB, fbconfig->greenBits);
if (fbconfig->blueBits)
setWGLattrib(WGL_BLUE_BITS_ARB, fbconfig->blueBits);
if (fbconfig->alphaBits)
setWGLattrib(WGL_ALPHA_BITS_ARB, fbconfig->alphaBits);
if (fbconfig->depthBits)
setWGLattrib(WGL_DEPTH_BITS_ARB, fbconfig->depthBits);
if (fbconfig->stencilBits)
setWGLattrib(WGL_STENCIL_BITS_ARB, fbconfig->stencilBits);
if (fbconfig->auxBuffers)
setWGLattrib(WGL_AUX_BUFFERS_ARB, fbconfig->auxBuffers);
if (fbconfig->accumRedBits)
setWGLattrib(WGL_ACCUM_RED_BITS_ARB, fbconfig->accumRedBits);
if (fbconfig->accumGreenBits)
setWGLattrib(WGL_ACCUM_GREEN_BITS_ARB, fbconfig->accumGreenBits);
if (fbconfig->accumBlueBits)
setWGLattrib(WGL_ACCUM_BLUE_BITS_ARB, fbconfig->accumBlueBits);
if (fbconfig->accumAlphaBits)
setWGLattrib(WGL_ACCUM_BLUE_BITS_ARB, fbconfig->accumAlphaBits);
if (fbconfig->stereo)
setWGLattrib(WGL_STEREO_ARB, TRUE);
if (window->wgl.ARB_multisample)
{
if (fbconfig->samples)
{
setWGLattrib(WGL_SAMPLE_BUFFERS_ARB, 1);
setWGLattrib(WGL_SAMPLES_ARB, fbconfig->samples);
}
}
if (window->wgl.ARB_framebuffer_sRGB)
{
if (fbconfig->sRGB)
setWGLattrib(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE);
}
setWGLattrib(0, 0);
if (!window->wgl.ChoosePixelFormatARB(window->wgl.dc,
attribs,
NULL,
1,
&pixelFormat,
&count))
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to find a suitable pixel format"); "WGL: Failed to find a suitable pixel format");
return GL_FALSE; return GL_FALSE;
} }
}
else
{
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags |= PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
if (fbconfig->stereo)
pfd.dwFlags |= PFD_STEREO;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = fbconfig->redBits +
fbconfig->greenBits +
fbconfig->blueBits;
pfd.cAlphaBits = fbconfig->alphaBits;
pfd.cAccumBits = fbconfig->accumRedBits +
fbconfig->accumGreenBits +
fbconfig->accumBlueBits;
pfd.cDepthBits = fbconfig->depthBits;
pfd.cStencilBits = fbconfig->stencilBits;
pfd.cAuxBuffers = fbconfig->auxBuffers;
pixelFormat = ChoosePixelFormat(window->wgl.dc, &pfd);
if (!pixelFormat)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to find a suitable pixel format");
return GL_FALSE;
}
}
if (!DescribePixelFormat(window->wgl.dc, pixelFormat, sizeof(pfd), &pfd)) if (!DescribePixelFormat(window->wgl.dc, pixelFormat, sizeof(pfd), &pfd))
{ {
@ -293,14 +358,6 @@ int _glfwCreateContext(_GLFWwindow* window,
return GL_FALSE; return GL_FALSE;
} }
if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) &&
(pfd.dwFlags & PFD_GENERIC_FORMAT))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to find an accelerated pixel format");
return GL_FALSE;
}
if (!SetPixelFormat(window->wgl.dc, pixelFormat, &pfd)) if (!SetPixelFormat(window->wgl.dc, pixelFormat, &pfd))
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,

View File

@ -37,6 +37,7 @@
#include "../deps/GL/wglext.h" #include "../deps/GL/wglext.h"
#define _GLFW_PLATFORM_FBCONFIG int wgl
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl
#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryWGL wgl #define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryWGL wgl
@ -56,7 +57,7 @@ typedef struct _GLFWcontextWGL
// Platform specific extensions (context specific) // Platform specific extensions (context specific)
PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT;
PFNWGLCHOOSEPIXELFORMATARBPROC ChoosePixelFormatARB; PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB;
PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT;
PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;