From ac3a5394cab6b75be87773e562cb2e3736cd865f Mon Sep 17 00:00:00 2001 From: binary1248 Date: Wed, 8 Apr 2015 09:04:46 +0200 Subject: [PATCH] Made Windows and Unix pixel format selection more consistent with each other, fixed pixel format evaluation scoring formats with better settings equal to formats with worse settings. --- src/SFML/Window/GlContext.cpp | 25 +++- src/SFML/Window/GlContext.hpp | 3 +- src/SFML/Window/Unix/GlxContext.cpp | 47 ++++++- src/SFML/Window/Win32/WglContext.cpp | 200 ++++++++++++++++++--------- src/SFML/Window/Win32/WglContext.hpp | 12 ++ 5 files changed, 206 insertions(+), 81 deletions(-) diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp index b63fc41e..e01be10e 100644 --- a/src/SFML/Window/GlContext.cpp +++ b/src/SFML/Window/GlContext.cpp @@ -340,12 +340,27 @@ GlContext::GlContext() //////////////////////////////////////////////////////////// -int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing) +int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated) { - return std::abs(static_cast(bitsPerPixel - colorBits)) + - std::abs(static_cast(settings.depthBits - depthBits)) + - std::abs(static_cast(settings.stencilBits - stencilBits)) + - std::abs(static_cast(settings.antialiasingLevel - antialiasing)); + int colorDiff = static_cast(bitsPerPixel) - colorBits; + int depthDiff = static_cast(settings.depthBits) - depthBits; + int stencilDiff = static_cast(settings.stencilBits) - stencilBits; + int antialiasingDiff = static_cast(settings.antialiasingLevel) - antialiasing; + + // Weight sub-scores so that better settings don't score equally as bad as worse settings + colorDiff *= ((colorDiff > 0) ? 100000 : 1); + depthDiff *= ((depthDiff > 0) ? 100000 : 1); + stencilDiff *= ((stencilDiff > 0) ? 100000 : 1); + antialiasingDiff *= ((antialiasingDiff > 0) ? 100000 : 1); + + // Aggregate the scores + int score = std::abs(colorDiff) + std::abs(depthDiff) + std::abs(stencilDiff) + std::abs(antialiasingDiff); + + // Make sure we prefer hardware acceleration over features + if (!accelerated) + score += 100000000; + + return score; } diff --git a/src/SFML/Window/GlContext.hpp b/src/SFML/Window/GlContext.hpp index 9b838351..f9225cd8 100644 --- a/src/SFML/Window/GlContext.hpp +++ b/src/SFML/Window/GlContext.hpp @@ -216,11 +216,12 @@ protected: /// \param depthBits Depth bits of the configuration to evaluate /// \param stencilBits Stencil bits of the configuration to evaluate /// \param antialiasing Antialiasing level of the configuration to evaluate + /// \param accelerated Whether the pixel format is hardware accelerated /// /// \return Score of the configuration /// //////////////////////////////////////////////////////////// - static int evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing); + static int evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated); //////////////////////////////////////////////////////////// // Member data diff --git a/src/SFML/Window/Unix/GlxContext.cpp b/src/SFML/Window/Unix/GlxContext.cpp index 5688291e..f342df0d 100644 --- a/src/SFML/Window/Unix/GlxContext.cpp +++ b/src/SFML/Window/Unix/GlxContext.cpp @@ -308,17 +308,34 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe XVisualInfo* visuals = XGetVisualInfo(display, 0, NULL, &count); if (visuals) { + // There are no GLX versions prior to 1.0 + int major = 0; + int minor = 0; + + if (!glXQueryVersion(display, &major, &minor)) + err() << "Failed to query GLX version" << std::endl; + // Evaluate all the returned visuals, and pick the best one - int bestScore = 0xFFFF; + int bestScore = 0x7FFFFFFF; XVisualInfo bestVisual; for (int i = 0; i < count; ++i) { // Check mandatory attributes - int doubleBuffer; + int useGL, doubleBuffer, rgba; + glXGetConfig(display, &visuals[i], GLX_USE_GL, &useGL); glXGetConfig(display, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer); - if (!doubleBuffer) + glXGetConfig(display, &visuals[i], GLX_RGBA, &rgba); + if (!useGL || !doubleBuffer || !rgba) continue; + if (major > 1 || minor >= 3) + { + int drawableType; + glXGetConfig(display, &visuals[i], GLX_DRAWABLE_TYPE, &drawableType); + if (!(drawableType & GLX_WINDOW_BIT)) + continue; + } + // Extract the components of the current visual int red, green, blue, alpha, depth, stencil, multiSampling, samples; glXGetConfig(display, &visuals[i], GLX_RED_SIZE, &red); @@ -327,12 +344,30 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe glXGetConfig(display, &visuals[i], GLX_ALPHA_SIZE, &alpha); glXGetConfig(display, &visuals[i], GLX_DEPTH_SIZE, &depth); glXGetConfig(display, &visuals[i], GLX_STENCIL_SIZE, &stencil); - glXGetConfig(display, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling); - glXGetConfig(display, &visuals[i], GLX_SAMPLES_ARB, &samples); + + if (sfglx_ext_ARB_multisample == sfglx_LOAD_SUCCEEDED) + { + glXGetConfig(display, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling); + glXGetConfig(display, &visuals[i], GLX_SAMPLES_ARB, &samples); + } + else + { + multiSampling = 0; + samples = 0; + } + + bool accelerated = true; + if (major > 1 || minor >= 3) + { + int caveat; + glXGetConfig(display, &visuals[i], GLX_CONFIG_CAVEAT, &caveat); + if (caveat == GLX_SLOW_CONFIG) + accelerated = false; + } // Evaluate the visual int color = red + green + blue + alpha; - int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0); + int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0, accelerated); // If it's better than the current best, make it the new best if (score < bestScore) diff --git a/src/SFML/Window/Win32/WglContext.cpp b/src/SFML/Window/Win32/WglContext.cpp index 97ae3896..c36cb8c9 100644 --- a/src/SFML/Window/Win32/WglContext.cpp +++ b/src/SFML/Window/Win32/WglContext.cpp @@ -214,81 +214,83 @@ void WglContext::setVerticalSyncEnabled(bool enabled) //////////////////////////////////////////////////////////// -void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings) +int WglContext::selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPixel, const ContextSettings& settings) { - // Save the creation settings - m_settings = settings; - - // Make sure that extensions are initialized if this is not the shared context - // The shared context is the context used to initialize the extensions - if (shared) - ensureExtensionsInit(m_deviceContext); - - // Let's find a suitable pixel format -- first try with antialiasing + // Let's find a suitable pixel format -- first try with wglChoosePixelFormatARB int bestFormat = 0; - if (m_settings.antialiasingLevel > 0) + if (sfwgl_ext_ARB_pixel_format == sfwgl_LOAD_SUCCEEDED) { - if ((sfwgl_ext_ARB_pixel_format == sfwgl_LOAD_SUCCEEDED) && (sfwgl_ext_ARB_multisample == sfwgl_LOAD_SUCCEEDED)) + // Define the basic attributes we want for our window + int intAttributes[] = { - // Define the basic attributes we want for our window - int intAttributes[] = - { - WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, - WGL_SUPPORT_OPENGL_ARB, GL_TRUE, - WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, - WGL_DOUBLE_BUFFER_ARB, GL_TRUE, - WGL_SAMPLE_BUFFERS_ARB, (m_settings.antialiasingLevel ? 1 : 0), - WGL_SAMPLES_ARB, static_cast(m_settings.antialiasingLevel), - 0, 0 - }; + WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, + WGL_SUPPORT_OPENGL_ARB, GL_TRUE, + WGL_DOUBLE_BUFFER_ARB, GL_TRUE, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + 0, 0 + }; - // Let's check how many formats are supporting our requirements - int formats[128]; - UINT nbFormats; - float floatAttributes[] = {0, 0}; - bool isValid = wglChoosePixelFormatARB(m_deviceContext, intAttributes, floatAttributes, sizeof(formats) / sizeof(*formats), formats, &nbFormats) != 0; - while ((!isValid || (nbFormats == 0)) && m_settings.antialiasingLevel > 0) - { - // Decrease the antialiasing level until we find a valid one - m_settings.antialiasingLevel--; - intAttributes[11] = m_settings.antialiasingLevel; - isValid = wglChoosePixelFormatARB(m_deviceContext, intAttributes, floatAttributes, sizeof(formats) / sizeof(*formats), formats, &nbFormats) != 0; - } + // Let's check how many formats are supporting our requirements + int formats[256]; + UINT nbFormats; + bool isValid = wglChoosePixelFormatARB(deviceContext, intAttributes, NULL, 256, formats, &nbFormats) != 0; - // Get the best format among the returned ones - if (isValid && (nbFormats > 0)) + // Get the best format among the returned ones + if (isValid && (nbFormats > 0)) + { + int bestScore = 0x7FFFFFFF; + for (UINT i = 0; i < nbFormats; ++i) { - int bestScore = 0xFFFF; - for (UINT i = 0; i < nbFormats; ++i) + // Extract the components of the current format + int values[7]; + const int attributes[] = { - // Get the current format's attributes - PIXELFORMATDESCRIPTOR attributes; - attributes.nSize = sizeof(attributes); - attributes.nVersion = 1; - DescribePixelFormat(m_deviceContext, formats[i], sizeof(attributes), &attributes); + WGL_RED_BITS_ARB, + WGL_GREEN_BITS_ARB, + WGL_BLUE_BITS_ARB, + WGL_ALPHA_BITS_ARB, + WGL_DEPTH_BITS_ARB, + WGL_STENCIL_BITS_ARB, + WGL_ACCELERATION_ARB + }; - // Evaluate the current configuration - int color = attributes.cRedBits + attributes.cGreenBits + attributes.cBlueBits + attributes.cAlphaBits; - int score = evaluateFormat(bitsPerPixel, m_settings, color, attributes.cDepthBits, attributes.cStencilBits, m_settings.antialiasingLevel); + if (!wglGetPixelFormatAttribivARB(deviceContext, formats[i], PFD_MAIN_PLANE, 7, attributes, values)) + { + err() << "Failed to retrieve pixel format information: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + break; + } - // Keep it if it's better than the current best - if (score < bestScore) + int sampleValues[2] = {0, 0}; + if (sfwgl_ext_ARB_multisample == sfwgl_LOAD_SUCCEEDED) + { + const int sampleAttributes[] = { - bestScore = score; - bestFormat = formats[i]; + WGL_SAMPLE_BUFFERS_ARB, + WGL_SAMPLES_ARB + }; + + if (!wglGetPixelFormatAttribivARB(deviceContext, formats[i], PFD_MAIN_PLANE, 2, sampleAttributes, sampleValues)) + { + err() << "Failed to retrieve pixel format multisampling information: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + break; } } + + // Evaluate the current configuration + int color = values[0] + values[1] + values[2] + values[3]; + int score = evaluateFormat(bitsPerPixel, settings, color, values[4], values[5], sampleValues[0] ? sampleValues[1] : 0, values[6] == WGL_FULL_ACCELERATION_ARB); + + // Keep it if it's better than the current best + if (score < bestScore) + { + bestScore = score; + bestFormat = formats[i]; + } } } - else - { - // wglChoosePixelFormatARB not supported ; disabling antialiasing - err() << "Antialiasing is not supported ; it will be disabled" << std::endl; - m_settings.antialiasingLevel = 0; - } } - // Find a pixel format with no antialiasing, if not needed or not supported + // Find a pixel format with ChoosePixelFormat, if wglChoosePixelFormatARB is not supported if (bestFormat == 0) { // Setup a pixel format descriptor from the rendering settings @@ -300,18 +302,36 @@ void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, co descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; descriptor.iPixelType = PFD_TYPE_RGBA; descriptor.cColorBits = static_cast(bitsPerPixel); - descriptor.cDepthBits = static_cast(m_settings.depthBits); - descriptor.cStencilBits = static_cast(m_settings.stencilBits); + descriptor.cDepthBits = static_cast(settings.depthBits); + descriptor.cStencilBits = static_cast(settings.stencilBits); descriptor.cAlphaBits = bitsPerPixel == 32 ? 8 : 0; // Get the pixel format that best matches our requirements - bestFormat = ChoosePixelFormat(m_deviceContext, &descriptor); - if (bestFormat == 0) - { - err() << "Failed to find a suitable pixel format for device context: " << getErrorString(GetLastError()).toAnsiString() << std::endl - << "Cannot create OpenGL context" << std::endl; - return; - } + bestFormat = ChoosePixelFormat(deviceContext, &descriptor); + } + + return bestFormat; +} + + +//////////////////////////////////////////////////////////// +void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings) +{ + // Save the creation settings + m_settings = settings; + + // Make sure that extensions are initialized if this is not the shared context + // The shared context is the context used to initialize the extensions + if (shared) + ensureExtensionsInit(m_deviceContext); + + int bestFormat = selectBestPixelFormat(m_deviceContext, bitsPerPixel, settings); + + if (bestFormat == 0) + { + err() << "Failed to find a suitable pixel format for device context: " << getErrorString(GetLastError()).toAnsiString() << std::endl + << "Cannot create OpenGL context" << std::endl; + return; } // Extract the depth and stencil bits from the chosen format @@ -319,8 +339,50 @@ void WglContext::createContext(WglContext* shared, unsigned int bitsPerPixel, co actualFormat.nSize = sizeof(actualFormat); actualFormat.nVersion = 1; DescribePixelFormat(m_deviceContext, bestFormat, sizeof(actualFormat), &actualFormat); - m_settings.depthBits = actualFormat.cDepthBits; - m_settings.stencilBits = actualFormat.cStencilBits; + + if (sfwgl_ext_ARB_pixel_format == sfwgl_LOAD_SUCCEEDED) + { + const int attributes[] = {WGL_DEPTH_BITS_ARB, WGL_STENCIL_BITS_ARB}; + int values[2]; + + if (wglGetPixelFormatAttribivARB(m_deviceContext, bestFormat, PFD_MAIN_PLANE, 2, attributes, values)) + { + m_settings.depthBits = values[0]; + m_settings.stencilBits = values[1]; + } + else + { + err() << "Failed to retrieve pixel format information: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + m_settings.depthBits = actualFormat.cDepthBits; + m_settings.stencilBits = actualFormat.cStencilBits; + } + + if (sfwgl_ext_ARB_multisample == sfwgl_LOAD_SUCCEEDED) + { + const int sampleAttributes[] = {WGL_SAMPLE_BUFFERS_ARB, WGL_SAMPLES_ARB}; + int sampleValues[2]; + + if (wglGetPixelFormatAttribivARB(m_deviceContext, bestFormat, PFD_MAIN_PLANE, 2, sampleAttributes, sampleValues)) + { + m_settings.antialiasingLevel = sampleValues[0] ? sampleValues[1] : 0; + } + else + { + err() << "Failed to retrieve pixel format multisampling information: " << getErrorString(GetLastError()).toAnsiString() << std::endl; + m_settings.antialiasingLevel = 0; + } + } + else + { + m_settings.antialiasingLevel = 0; + } + } + else + { + m_settings.depthBits = actualFormat.cDepthBits; + m_settings.stencilBits = actualFormat.cStencilBits; + m_settings.antialiasingLevel = 0; + } // Set the chosen pixel format if (!SetPixelFormat(m_deviceContext, bestFormat, &actualFormat)) diff --git a/src/SFML/Window/Win32/WglContext.hpp b/src/SFML/Window/Win32/WglContext.hpp index 6aed1b5b..45070f62 100644 --- a/src/SFML/Window/Win32/WglContext.hpp +++ b/src/SFML/Window/Win32/WglContext.hpp @@ -118,6 +118,18 @@ public: //////////////////////////////////////////////////////////// virtual void setVerticalSyncEnabled(bool enabled); + //////////////////////////////////////////////////////////// + /// \brief Select the best pixel format for a given set of settings + /// + /// \param deviceContext Device context + /// \param bitsPerPixel Pixel depth, in bits per pixel + /// \param settings Requested context settings + /// + /// \return The best pixel format + /// + //////////////////////////////////////////////////////////// + static int selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPixel, const ContextSettings& settings); + private: ////////////////////////////////////////////////////////////