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.

This commit is contained in:
binary1248 2015-04-08 09:04:46 +02:00 committed by Lukas Dürrenberger
parent bbe2c656e6
commit ac3a5394ca
5 changed files with 206 additions and 81 deletions

View File

@ -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<int>(bitsPerPixel - colorBits)) +
std::abs(static_cast<int>(settings.depthBits - depthBits)) +
std::abs(static_cast<int>(settings.stencilBits - stencilBits)) +
std::abs(static_cast<int>(settings.antialiasingLevel - antialiasing));
int colorDiff = static_cast<int>(bitsPerPixel) - colorBits;
int depthDiff = static_cast<int>(settings.depthBits) - depthBits;
int stencilDiff = static_cast<int>(settings.stencilBits) - stencilBits;
int antialiasingDiff = static_cast<int>(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;
}

View File

@ -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

View File

@ -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)

View File

@ -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<int>(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<BYTE>(bitsPerPixel);
descriptor.cDepthBits = static_cast<BYTE>(m_settings.depthBits);
descriptor.cStencilBits = static_cast<BYTE>(m_settings.stencilBits);
descriptor.cDepthBits = static_cast<BYTE>(settings.depthBits);
descriptor.cStencilBits = static_cast<BYTE>(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))

View File

@ -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:
////////////////////////////////////////////////////////////