Fixed ContextSettings ignored on Linux when creating a window (#35)

This commit is contained in:
Laurent Gomila 2013-07-03 22:57:33 +02:00
parent 6b50691551
commit 68748d2de1
11 changed files with 112 additions and 87 deletions

View File

@ -158,12 +158,69 @@ void GlxContext::setVerticalSyncEnabled(bool enabled)
////////////////////////////////////////////////////////////
void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings)
XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPerPixel, const ContextSettings& settings)
{
// Retrieve all the visuals
int count;
XVisualInfo* visuals = XGetVisualInfo(display, 0, NULL, &count);
if (visuals)
{
// Evaluate all the returned visuals, and pick the best one1
int bestScore = 0xFFFF;
XVisualInfo bestVisual;
for (int i = 0; i < count; ++i)
{
// Check mandatory attributes
int doubleBuffer;
glXGetConfig(display, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer);
if (!doubleBuffer)
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);
glXGetConfig(display, &visuals[i], GLX_GREEN_SIZE, &green);
glXGetConfig(display, &visuals[i], GLX_BLUE_SIZE, &blue);
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);
// Evaluate the visual
int color = red + green + blue + alpha;
int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0);
// If it's better than the current best, make it the new best
if (score < bestScore)
{
bestScore = score;
bestVisual = visuals[i];
}
}
// Free the array of visuals
XFree(visuals);
return bestVisual;
}
else
{
// Should never happen...
err() << "No GLX visual found. You should check your graphics driver" << std::endl;
return XVisualInfo();
}
}
////////////////////////////////////////////////////////////
void GlxContext::createContext(GlxContext* shared, unsigned int /*bitsPerPixel*/, const ContextSettings& settings)
{
// Save the creation settings
m_settings = settings;
// Get the attributes of the target window
// Retrieve the attributes of the target window
XWindowAttributes windowAttributes;
if (XGetWindowAttributes(m_display, m_window, &windowAttributes) == 0)
{
@ -171,63 +228,12 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
return;
}
// Setup the visual infos to match
// Get its visual
XVisualInfo tpl;
tpl.depth = windowAttributes.depth;
tpl.visualid = XVisualIDFromVisual(windowAttributes.visual);
tpl.screen = DefaultScreen(m_display);
// Get all the visuals matching the template
tpl.visualid = XVisualIDFromVisual(windowAttributes.visual);
int nbVisuals = 0;
XVisualInfo* visuals = XGetVisualInfo(m_display, VisualDepthMask | VisualIDMask | VisualScreenMask, &tpl, &nbVisuals);
if (!visuals || (nbVisuals == 0))
{
if (visuals)
XFree(visuals);
err() << "There is no valid visual for the selected screen" << std::endl;
return;
}
// Find the best visual
int bestScore = 0xFFFF;
XVisualInfo* bestVisual = NULL;
for (int i = 0; i < nbVisuals; ++i)
{
// Get the current visual attributes
int RGBA, doubleBuffer, red, green, blue, alpha, depth, stencil, multiSampling, samples;
glXGetConfig(m_display, &visuals[i], GLX_RGBA, &RGBA);
glXGetConfig(m_display, &visuals[i], GLX_DOUBLEBUFFER, &doubleBuffer);
glXGetConfig(m_display, &visuals[i], GLX_RED_SIZE, &red);
glXGetConfig(m_display, &visuals[i], GLX_GREEN_SIZE, &green);
glXGetConfig(m_display, &visuals[i], GLX_BLUE_SIZE, &blue);
glXGetConfig(m_display, &visuals[i], GLX_ALPHA_SIZE, &alpha);
glXGetConfig(m_display, &visuals[i], GLX_DEPTH_SIZE, &depth);
glXGetConfig(m_display, &visuals[i], GLX_STENCIL_SIZE, &stencil);
glXGetConfig(m_display, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
glXGetConfig(m_display, &visuals[i], GLX_SAMPLES_ARB, &samples);
// First check the mandatory parameters
if ((RGBA == 0) || (doubleBuffer == 0))
continue;
// Evaluate the current configuration
int color = red + green + blue + alpha;
int score = evaluateFormat(bitsPerPixel, m_settings, color, depth, stencil, multiSampling ? samples : 0);
// Keep it if it's better than the current best
if (score < bestScore)
{
bestScore = score;
bestVisual = &visuals[i];
}
}
// Make sure that we have found a visual
if (!bestVisual)
{
err() << "Failed to find a suitable pixel format for the window -- cannot create OpenGL context" << std::endl;
return;
}
XVisualInfo* visualInfo = XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals);
// Get the context to share display lists with
GLXContext toShare = shared ? shared->m_context : NULL;
@ -283,7 +289,7 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
m_settings.majorVersion = 2;
m_settings.minorVersion = 0;
m_context = glXCreateContext(m_display, bestVisual, toShare, true);
m_context = glXCreateContext(m_display, visualInfo, toShare, true);
if (!m_context)
{
err() << "Failed to create an OpenGL context for this window" << std::endl;
@ -293,21 +299,16 @@ void GlxContext::createContext(GlxContext* shared, unsigned int bitsPerPixel, co
// Update the creation settings from the chosen format
int depth, stencil, multiSampling, samples;
glXGetConfig(m_display, bestVisual, GLX_DEPTH_SIZE, &depth);
glXGetConfig(m_display, bestVisual, GLX_STENCIL_SIZE, &stencil);
glXGetConfig(m_display, bestVisual, GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
glXGetConfig(m_display, bestVisual, GLX_SAMPLES_ARB, &samples);
glXGetConfig(m_display, visualInfo, GLX_DEPTH_SIZE, &depth);
glXGetConfig(m_display, visualInfo, GLX_STENCIL_SIZE, &stencil);
glXGetConfig(m_display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &multiSampling);
glXGetConfig(m_display, visualInfo, GLX_SAMPLES_ARB, &samples);
m_settings.depthBits = static_cast<unsigned int>(depth);
m_settings.stencilBits = static_cast<unsigned int>(stencil);
m_settings.antialiasingLevel = multiSampling ? samples : 0;
// Change the target window's colormap so that it matches the context's one
::Window root = RootWindow(m_display, DefaultScreen(m_display));
Colormap colorMap = XCreateColormap(m_display, root, bestVisual->visual, AllocNone);
XSetWindowColormap(m_display, m_window, colorMap);
// Free the temporary visuals array
XFree(visuals);
// Free the visual info
XFree(visualInfo);
}
} // namespace priv

View File

@ -108,6 +108,18 @@ public :
////////////////////////////////////////////////////////////
virtual void setVerticalSyncEnabled(bool enabled);
////////////////////////////////////////////////////////////
/// \brief Select the best GLX visual for a given set of settings
///
/// \param display X display
/// \param bitsPerPixel Pixel depth, in bits per pixel
/// \param settings Requested context settings
///
/// \return The best visual
///
////////////////////////////////////////////////////////////
static XVisualInfo selectBestVisual(::Display* display, unsigned int bitsPerPixel, const ContextSettings& settings);
private :
////////////////////////////////////////////////////////////

View File

@ -27,6 +27,7 @@
////////////////////////////////////////////////////////////
#include <SFML/Window/WindowStyle.hpp> // important to be included first (conflict with None)
#include <SFML/Window/Linux/WindowImplX11.hpp>
#include <SFML/Window/Linux/GlxContext.hpp>
#include <SFML/Window/Linux/Display.hpp>
#include <SFML/System/Utf.hpp>
#include <SFML/System/Err.hpp>
@ -96,7 +97,7 @@ m_previousSize(-1, -1)
{
// Open a connection with the X server
m_display = OpenDisplay();
m_screen = DefaultScreen(m_display);
m_screen = DefaultScreen(m_display);
// Save the window handle
m_window = handle;
@ -113,7 +114,7 @@ m_previousSize(-1, -1)
////////////////////////////////////////////////////////////
WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style) :
WindowImplX11::WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings) :
m_window (0),
m_inputMethod (NULL),
m_inputContext(NULL),
@ -126,7 +127,8 @@ m_previousSize(-1, -1)
{
// Open a connection with the X server
m_display = OpenDisplay();
m_screen = DefaultScreen(m_display);
m_screen = DefaultScreen(m_display);
::Window root = RootWindow(m_display, m_screen);
// Compute position and size
int left, top;
@ -148,21 +150,25 @@ m_previousSize(-1, -1)
if (fullscreen)
switchToFullscreen(mode);
// Choose the visual according to the context settings
XVisualInfo visualInfo = GlxContext::selectBestVisual(m_display, mode.bitsPerPixel, settings);
// Define the window attributes
XSetWindowAttributes attributes;
attributes.event_mask = eventMask;
attributes.override_redirect = fullscreen;
attributes.event_mask = eventMask;
attributes.colormap = XCreateColormap(m_display, root, visualInfo.visual, AllocNone);
// Create the window
m_window = XCreateWindow(m_display,
RootWindow(m_display, m_screen),
root,
left, top,
width, height,
0,
DefaultDepth(m_display, m_screen),
visualInfo.depth,
InputOutput,
DefaultVisual(m_display, m_screen),
CWEventMask | CWOverrideRedirect, &attributes);
visualInfo.visual,
CWEventMask | CWOverrideRedirect | CWColormap, &attributes);
if (!m_window)
{
err() << "Failed to create window" << std::endl;

View File

@ -61,9 +61,10 @@ public :
/// \param mode Video mode to use
/// \param title Title of the window
/// \param style Window style (resizable, fixed, or fullscren)
/// \param settings Additional settings for the underlying OpenGL context
///
////////////////////////////////////////////////////////////
WindowImplX11(VideoMode mode, const String& title, unsigned long style);
WindowImplX11(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings);
////////////////////////////////////////////////////////////
/// \brief Destructor

View File

@ -78,9 +78,10 @@ public :
/// \param mode Video mode to use
/// \param title Title of the window
/// \param style Window style (resizable, fixed, or fullscren)
/// \param settings Additional settings for the underlying OpenGL context
///
////////////////////////////////////////////////////////////
WindowImplCocoa(VideoMode mode, const String& title, unsigned long style);
WindowImplCocoa(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings);
////////////////////////////////////////////////////////////
/// \brief Destructor

View File

@ -81,9 +81,10 @@ WindowImplCocoa::WindowImplCocoa(WindowHandle handle)
////////////////////////////////////////////////////////////
WindowImplCocoa::WindowImplCocoa(VideoMode mode,
const String& title,
unsigned long style)
WindowImplCocoa::WindowImplCocoa(VideoMode mode,
const String& title,
unsigned long style,
const ContextSettings& /*settings*/)
: m_showCursor(true)
{
// Transform the app process.

View File

@ -86,7 +86,7 @@ m_surrogate (0)
////////////////////////////////////////////////////////////
WindowImplWin32::WindowImplWin32(VideoMode mode, const String& title, Uint32 style) :
WindowImplWin32::WindowImplWin32(VideoMode mode, const String& title, Uint32 style, const ContextSettings& /*settings*/) :
m_handle (NULL),
m_callback (0),
m_cursor (NULL),

View File

@ -60,9 +60,10 @@ public :
/// \param mode Video mode to use
/// \param title Title of the window
/// \param style Window style
/// \param settings Additional settings for the underlying OpenGL context
///
////////////////////////////////////////////////////////////
WindowImplWin32(VideoMode mode, const String& title, Uint32 style);
WindowImplWin32(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings);
////////////////////////////////////////////////////////////
/// \brief Destructor

View File

@ -114,7 +114,7 @@ void Window::create(VideoMode mode, const String& title, Uint32 style, const Con
style |= Style::Titlebar;
// Recreate the window implementation
m_impl = priv::WindowImpl::create(mode, title, style);
m_impl = priv::WindowImpl::create(mode, title, style, settings);
// Recreate the context
m_context = priv::GlContext::create(settings, m_impl, mode.bitsPerPixel);

View File

@ -55,9 +55,9 @@ namespace sf
namespace priv
{
////////////////////////////////////////////////////////////
WindowImpl* WindowImpl::create(VideoMode mode, const String& title, Uint32 style)
WindowImpl* WindowImpl::create(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings)
{
return new WindowImplType(mode, title, style);
return new WindowImplType(mode, title, style, settings);
}

View File

@ -36,6 +36,7 @@
#include <SFML/Window/JoystickImpl.hpp>
#include <SFML/Window/VideoMode.hpp>
#include <SFML/Window/WindowHandle.hpp>
#include <SFML/Window/ContextSettings.hpp>
#include <queue>
#include <set>
@ -59,11 +60,12 @@ public :
/// \param mode Video mode to use
/// \param title Title of the window
/// \param style Window style
/// \param settings Additional settings for the underlying OpenGL context
///
/// \return Pointer to the created window (don't forget to delete it)
///
////////////////////////////////////////////////////////////
static WindowImpl* create(VideoMode mode, const String& title, Uint32 style);
static WindowImpl* create(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings);
////////////////////////////////////////////////////////////
/// \brief Create a new window depending on to the current OS