dolphin-emulator/Externals/wxWidgets3/src/unix/glx11.cpp

777 lines
21 KiB
C++
Raw Normal View History

///////////////////////////////////////////////////////////////////////////////
// Name: src/unix/glx11.cpp
// Purpose: code common to all X11-based wxGLCanvas implementations
// Author: Vadim Zeitlin
// Created: 2007-04-15
// Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if wxUSE_GLCANVAS
#ifndef WX_PRECOMP
#include "wx/log.h"
#endif //WX_PRECOMP
#include "wx/glcanvas.h"
// IRIX headers call this differently
#ifdef __SGI__
#ifndef GLX_SAMPLE_BUFFERS_ARB
#define GLX_SAMPLE_BUFFERS_ARB GLX_SAMPLE_BUFFERS_SGIS
#endif
#ifndef GLX_SAMPLES_ARB
#define GLX_SAMPLES_ARB GLX_SAMPLES_SGIS
#endif
#endif // __SGI__
// ----------------------------------------------------------------------------
// define possibly missing XGL constants and types
// ----------------------------------------------------------------------------
#ifndef GLX_NONE_EXT
#define GLX_NONE_EXT 0x8000
#endif
#ifndef GLX_ARB_multisample
#define GLX_ARB_multisample
#define GLX_SAMPLE_BUFFERS_ARB 100000
#define GLX_SAMPLES_ARB 100001
#endif
#ifndef GLX_EXT_visual_rating
#define GLX_EXT_visual_rating
#define GLX_VISUAL_CAVEAT_EXT 0x20
#define GLX_NONE_EXT 0x8000
#define GLX_SLOW_VISUAL_EXT 0x8001
#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
#endif
#ifndef GLX_EXT_visual_info
#define GLX_EXT_visual_info
#define GLX_X_VISUAL_TYPE_EXT 0x22
#define GLX_DIRECT_COLOR_EXT 0x8003
#endif
#ifndef GLX_ARB_framebuffer_sRGB
#define GLX_ARB_framebuffer_sRGB
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
#endif
/* Typedef for the GL 3.0 context creation function */
typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC)
(Display * dpy, GLXFBConfig config, GLXContext share_context,
Bool direct, const int *attrib_list);
#ifndef GLX_ARB_create_context
#define GLX_ARB_create_context
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GLX_CONTEXT_FLAGS_ARB 0x2094
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
#endif
#ifndef GLX_ARB_create_context_profile
#define GLX_ARB_create_context_profile
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#endif
#ifndef GLX_ARB_create_context_robustness
#define GLX_ARB_create_context_robustness
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
#endif
#ifndef GLX_ARB_robustness_application_isolation
#define GLX_ARB_robustness_application_isolation
#define GLX_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008
#endif
#ifndef GLX_ARB_robustness_share_group_isolation
#define GLX_ARB_robustness_share_group_isolation
#endif
#ifndef GLX_ARB_context_flush_control
#define GLX_ARB_context_flush_control
#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
#endif
#ifndef GLX_EXT_create_context_es2_profile
#define GLX_EXT_create_context_es2_profile
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
#endif
#ifndef GLX_EXT_create_context_es_profile
#define GLX_EXT_create_context_es_profile
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
#endif
// ----------------------------------------------------------------------------
// wxGLContextAttrs: OpenGL rendering context attributes
// ----------------------------------------------------------------------------
// GLX specific values
wxGLContextAttrs& wxGLContextAttrs::CoreProfile()
{
AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB,
GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
SetNeedsARB();
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::MajorVersion(int val)
{
if ( val > 0 )
{
AddAttribute(GLX_CONTEXT_MAJOR_VERSION_ARB);
AddAttribute(val);
if ( val >= 3 )
SetNeedsARB();
}
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::MinorVersion(int val)
{
if ( val >= 0 )
{
AddAttribute(GLX_CONTEXT_MINOR_VERSION_ARB);
AddAttribute(val);
}
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile()
{
AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB,
GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
SetNeedsARB();
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::ForwardCompatible()
{
AddAttribBits(GLX_CONTEXT_FLAGS_ARB,
GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);
SetNeedsARB();
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::ES2()
{
AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB,
GLX_CONTEXT_ES2_PROFILE_BIT_EXT);
SetNeedsARB();
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::DebugCtx()
{
AddAttribBits(GLX_CONTEXT_FLAGS_ARB,
GLX_CONTEXT_DEBUG_BIT_ARB);
SetNeedsARB();
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::Robust()
{
AddAttribBits(GLX_CONTEXT_FLAGS_ARB,
GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB);
SetNeedsARB();
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::NoResetNotify()
{
AddAttribute(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
AddAttribute(GLX_NO_RESET_NOTIFICATION_ARB);
SetNeedsARB();
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::LoseOnReset()
{
AddAttribute(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
AddAttribute(GLX_LOSE_CONTEXT_ON_RESET_ARB);
SetNeedsARB();
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::ResetIsolation()
{
AddAttribBits(GLX_CONTEXT_FLAGS_ARB,
GLX_CONTEXT_RESET_ISOLATION_BIT_ARB);
SetNeedsARB();
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::ReleaseFlush(int val)
{
AddAttribute(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB);
if ( val == 1 )
AddAttribute(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
else
AddAttribute(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
SetNeedsARB();
return *this;
}
wxGLContextAttrs& wxGLContextAttrs::PlatformDefaults()
{
renderTypeRGBA = true;
x11Direct = true;
return *this;
}
void wxGLContextAttrs::EndList()
{
AddAttribute(None);
}
// ----------------------------------------------------------------------------
// wxGLAttributes: Visual/FBconfig attributes
// ----------------------------------------------------------------------------
// GLX specific values
// Different versions of GLX API use rather different attributes lists, see
// the following URLs:
//
// - <= 1.2: http://www.opengl.org/sdk/docs/man/xhtml/glXChooseVisual.xml
// - >= 1.3: http://www.opengl.org/sdk/docs/man/xhtml/glXChooseFBConfig.xml
//
// Notice in particular that
// - GLX_RGBA is boolean attribute in the old version of the API but a
// value of GLX_RENDER_TYPE in the new one
// - Boolean attributes such as GLX_DOUBLEBUFFER don't take values in the
// old version but must be followed by True or False in the new one.
wxGLAttributes& wxGLAttributes::RGBA()
{
if ( wxGLCanvasX11::GetGLXVersion() >= 13 )
AddAttribBits(GLX_RENDER_TYPE, GLX_RGBA_BIT);
else
AddAttribute(GLX_RGBA);
return *this;
}
wxGLAttributes& wxGLAttributes::BufferSize(int val)
{
if ( val >= 0 )
{
AddAttribute(GLX_BUFFER_SIZE);
AddAttribute(val);
}
return *this;
}
wxGLAttributes& wxGLAttributes::Level(int val)
{
AddAttribute(GLX_LEVEL);
AddAttribute(val);
return *this;
}
wxGLAttributes& wxGLAttributes::DoubleBuffer()
{
AddAttribute(GLX_DOUBLEBUFFER);
if ( wxGLCanvasX11::GetGLXVersion() >= 13 )
AddAttribute(True);
return *this;
}
wxGLAttributes& wxGLAttributes::Stereo()
{
AddAttribute(GLX_STEREO);
if ( wxGLCanvasX11::GetGLXVersion() >= 13 )
AddAttribute(True);
return *this;
}
wxGLAttributes& wxGLAttributes::AuxBuffers(int val)
{
if ( val >= 0 )
{
AddAttribute(GLX_AUX_BUFFERS);
AddAttribute(val);
}
return *this;
}
wxGLAttributes& wxGLAttributes::MinRGBA(int mRed, int mGreen, int mBlue, int mAlpha)
{
if ( mRed >= 0)
{
AddAttribute(GLX_RED_SIZE);
AddAttribute(mRed);
}
if ( mGreen >= 0)
{
AddAttribute(GLX_GREEN_SIZE);
AddAttribute(mGreen);
}
if ( mBlue >= 0)
{
AddAttribute(GLX_BLUE_SIZE);
AddAttribute(mBlue);
}
if ( mAlpha >= 0)
{
AddAttribute(GLX_ALPHA_SIZE);
AddAttribute(mAlpha);
}
return *this;
}
wxGLAttributes& wxGLAttributes::Depth(int val)
{
if ( val >= 0 )
{
AddAttribute(GLX_DEPTH_SIZE);
AddAttribute(val);
}
return *this;
}
wxGLAttributes& wxGLAttributes::Stencil(int val)
{
if ( val >= 0 )
{
AddAttribute(GLX_STENCIL_SIZE);
AddAttribute(val);
}
return *this;
}
wxGLAttributes& wxGLAttributes::MinAcumRGBA(int mRed, int mGreen, int mBlue, int mAlpha)
{
if ( mRed >= 0)
{
AddAttribute(GLX_ACCUM_RED_SIZE);
AddAttribute(mRed);
}
if ( mGreen >= 0)
{
AddAttribute(GLX_ACCUM_GREEN_SIZE);
AddAttribute(mGreen);
}
if ( mBlue >= 0)
{
AddAttribute(GLX_ACCUM_BLUE_SIZE);
AddAttribute(mBlue);
}
if ( mAlpha >= 0)
{
AddAttribute(GLX_ACCUM_ALPHA_SIZE);
AddAttribute(mAlpha);
}
return *this;
}
wxGLAttributes& wxGLAttributes::SampleBuffers(int val)
{
#ifdef GLX_SAMPLE_BUFFERS_ARB
if ( val >= 0 && wxGLCanvasX11::IsGLXMultiSampleAvailable() )
{
AddAttribute(GLX_SAMPLE_BUFFERS_ARB);
AddAttribute(val);
}
#endif
return *this;
}
wxGLAttributes& wxGLAttributes::Samplers(int val)
{
#ifdef GLX_SAMPLES_ARB
if ( val >= 0 && wxGLCanvasX11::IsGLXMultiSampleAvailable() )
{
AddAttribute(GLX_SAMPLES_ARB);
AddAttribute(val);
}
#endif
return *this;
}
wxGLAttributes& wxGLAttributes::FrameBuffersRGB()
{
AddAttribute(GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
AddAttribute(True);
return *this;
}
void wxGLAttributes::EndList()
{
AddAttribute(None);
}
wxGLAttributes& wxGLAttributes::PlatformDefaults()
{
// No GLX specific values
return *this;
}
wxGLAttributes& wxGLAttributes::Defaults()
{
RGBA().DoubleBuffer();
if ( wxGLCanvasX11::GetGLXVersion() < 13 )
Depth(1).MinRGBA(1, 1, 1, 0);
else
Depth(16).SampleBuffers(1).Samplers(4);
return *this;
}
// ============================================================================
// wxGLContext implementation
// ============================================================================
// Need this X error handler for the case context creation fails
static bool g_ctxErrorOccurred = false;
static int CTXErrorHandler( Display* WXUNUSED(dpy), XErrorEvent* WXUNUSED(ev) )
{
g_ctxErrorOccurred = true;
return 0;
}
wxIMPLEMENT_CLASS(wxGLContext, wxObject);
wxGLContext::wxGLContext(wxGLCanvas *win,
const wxGLContext *other,
const wxGLContextAttrs *ctxAttrs)
: m_glContext(NULL)
{
const int* contextAttribs = NULL;
Bool x11Direct = True;
int renderType = GLX_RGBA_TYPE;
bool needsARB = false;
if ( ctxAttrs )
{
contextAttribs = ctxAttrs->GetGLAttrs();
x11Direct = ctxAttrs->x11Direct;
renderType = ctxAttrs->renderTypeRGBA ? GLX_RGBA_TYPE : GLX_COLOR_INDEX_TYPE;
needsARB = ctxAttrs->NeedsARB();
}
else if ( win->GetGLCTXAttrs().GetGLAttrs() )
{
// If OpenGL context parameters were set at wxGLCanvas ctor, get them now
contextAttribs = win->GetGLCTXAttrs().GetGLAttrs();
x11Direct = win->GetGLCTXAttrs().x11Direct;
renderType = win->GetGLCTXAttrs().renderTypeRGBA ? GLX_RGBA_TYPE : GLX_COLOR_INDEX_TYPE;
needsARB = win->GetGLCTXAttrs().NeedsARB();
}
// else use GPU driver defaults and x11Direct renderType ones
m_isOk = false;
Display* dpy = wxGetX11Display();
XVisualInfo *vi = win->GetXVisualInfo();
wxCHECK_RET( vi, "invalid visual for OpenGL" );
// We need to create a temporary context to get the
// glXCreateContextAttribsARB function
GLXContext tempContext = glXCreateContext(dpy, vi, NULL,
win->GetGLCTXAttrs().x11Direct );
wxCHECK_RET(tempContext, "glXCreateContext failed" );
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB
= (PFNGLXCREATECONTEXTATTRIBSARBPROC)
glXGetProcAddress((GLubyte *)"glXCreateContextAttribsARB");
glXDestroyContext( dpy, tempContext );
// The preferred way is using glXCreateContextAttribsARB, even for old context
if ( !glXCreateContextAttribsARB && needsARB ) // OpenGL 3 context creation
{
wxLogMessage(_("OpenGL 3.0 or later is not supported by the OpenGL driver."));
return;
}
// Install a X error handler, so as to the app doesn't exit (without
// even a warning) if GL >= 3.0 context creation fails
g_ctxErrorOccurred = false;
int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&CTXErrorHandler);
if ( glXCreateContextAttribsARB )
{
GLXFBConfig *fbc = win->GetGLXFBConfig();
wxCHECK_RET( fbc, "Invalid GLXFBConfig for OpenGL" );
m_glContext = glXCreateContextAttribsARB( dpy, fbc[0],
other ? other->m_glContext : None,
x11Direct, contextAttribs );
}
else if ( wxGLCanvas::GetGLXVersion() >= 13 )
{
GLXFBConfig *fbc = win->GetGLXFBConfig();
wxCHECK_RET( fbc, "Invalid GLXFBConfig for OpenGL" );
m_glContext = glXCreateNewContext( dpy, fbc[0], renderType,
other ? other->m_glContext : None,
x11Direct );
}
else // GLX <= 1.2
{
m_glContext = glXCreateContext( dpy, vi,
other ? other->m_glContext : None,
x11Direct );
}
// Sync to ensure any errors generated are processed.
XSync( dpy, False );
if ( g_ctxErrorOccurred || !m_glContext )
wxLogMessage(_("Couldn't create OpenGL context"));
else
m_isOk = true;
// Restore old error handler
XSetErrorHandler( oldHandler );
}
wxGLContext::~wxGLContext()
{
if ( !m_glContext )
return;
if ( m_glContext == glXGetCurrentContext() )
MakeCurrent(None, NULL);
glXDestroyContext( wxGetX11Display(), m_glContext );
}
bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
{
if ( !m_glContext )
return false;
const Window xid = win.GetXWindow();
wxCHECK2_MSG( xid, return false, wxT("window must be shown") );
return MakeCurrent(xid, m_glContext);
}
// wrapper around glXMakeContextCurrent/glXMakeCurrent depending on GLX
// version
/* static */
bool wxGLContext::MakeCurrent(GLXDrawable drawable, GLXContext context)
{
if (wxGLCanvas::GetGLXVersion() >= 13)
return glXMakeContextCurrent( wxGetX11Display(), drawable, drawable, context);
else // GLX <= 1.2 doesn't have glXMakeContextCurrent()
return glXMakeCurrent( wxGetX11Display(), drawable, context);
}
// ============================================================================
// wxGLCanvasX11 implementation
// ============================================================================
// ----------------------------------------------------------------------------
// initialization methods and dtor
// ----------------------------------------------------------------------------
wxGLCanvasX11::wxGLCanvasX11()
{
m_fbc = NULL;
m_vi = NULL;
}
bool wxGLCanvasX11::InitVisual(const wxGLAttributes& dispAttrs)
{
bool ret = InitXVisualInfo(dispAttrs, &m_fbc, &m_vi);
if ( !ret )
{
wxFAIL_MSG("Failed to get a XVisualInfo for the requested attributes.");
}
return ret;
}
wxGLCanvasX11::~wxGLCanvasX11()
{
if ( m_fbc && m_fbc != ms_glFBCInfo )
XFree(m_fbc);
if ( m_vi && m_vi != ms_glVisualInfo )
XFree(m_vi);
}
// ----------------------------------------------------------------------------
// working with GL attributes
// ----------------------------------------------------------------------------
/* static */
bool wxGLCanvasBase::IsExtensionSupported(const char *extension)
{
Display * const dpy = wxGetX11Display();
return IsExtensionInList(glXQueryExtensionsString(dpy, DefaultScreen(dpy)),
extension);
}
/* static */
bool wxGLCanvasX11::IsGLXMultiSampleAvailable()
{
static int s_isMultiSampleAvailable = -1;
if ( s_isMultiSampleAvailable == -1 )
s_isMultiSampleAvailable = IsExtensionSupported("GLX_ARB_multisample");
return s_isMultiSampleAvailable != 0;
}
/* static */
bool wxGLCanvasX11::InitXVisualInfo(const wxGLAttributes& dispAttrs,
GLXFBConfig** pFBC,
XVisualInfo** pXVisual)
{
// GLX_XX attributes
const int* attrsListGLX = dispAttrs.GetGLAttrs();
if ( !attrsListGLX )
{
wxFAIL_MSG("wxGLAttributes object is empty.");
return false;
}
Display* dpy = wxGetX11Display();
if ( GetGLXVersion() >= 13 )
{
int returned;
*pFBC = glXChooseFBConfig(dpy, DefaultScreen(dpy), attrsListGLX, &returned);
if ( *pFBC )
{
// Use the first good match
*pXVisual = glXGetVisualFromFBConfig(wxGetX11Display(), **pFBC);
if ( !*pXVisual )
{
XFree(*pFBC);
*pFBC = NULL;
}
}
}
else // GLX <= 1.2
{
*pFBC = NULL;
*pXVisual = glXChooseVisual(dpy, DefaultScreen(dpy),
wx_const_cast(int*, attrsListGLX) );
}
return *pXVisual != NULL;
}
/* static */
bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs)
{
GLXFBConfig *fbc = NULL;
XVisualInfo *vi = NULL;
bool isSupported = wxGLCanvasX11::InitXVisualInfo(dispAttrs, &fbc, &vi);
if ( fbc )
XFree(fbc);
if ( vi )
XFree(vi);
return isSupported;
}
/* static */
bool wxGLCanvasBase::IsDisplaySupported(const int *attribList)
{
wxGLAttributes dispAttrs;
ParseAttribList(attribList, dispAttrs);
return IsDisplaySupported(dispAttrs);
}
// ----------------------------------------------------------------------------
// default visual management
// ----------------------------------------------------------------------------
XVisualInfo *wxGLCanvasX11::ms_glVisualInfo = NULL;
GLXFBConfig *wxGLCanvasX11::ms_glFBCInfo = NULL;
/* static */
bool wxGLCanvasX11::InitDefaultVisualInfo(const int *attribList)
{
FreeDefaultVisualInfo();
wxGLAttributes dispAttrs;
ParseAttribList(attribList, dispAttrs);
return InitXVisualInfo(dispAttrs, &ms_glFBCInfo, &ms_glVisualInfo);
}
/* static */
void wxGLCanvasX11::FreeDefaultVisualInfo()
{
if ( ms_glFBCInfo )
{
XFree(ms_glFBCInfo);
ms_glFBCInfo = NULL;
}
if ( ms_glVisualInfo )
{
XFree(ms_glVisualInfo);
ms_glVisualInfo = NULL;
}
}
// ----------------------------------------------------------------------------
// other GL methods
// ----------------------------------------------------------------------------
/* static */
int wxGLCanvasX11::GetGLXVersion()
{
static int s_glxVersion = 0;
if ( s_glxVersion == 0 )
{
// check the GLX version
int glxMajorVer, glxMinorVer;
bool ok = glXQueryVersion(wxGetX11Display(), &glxMajorVer, &glxMinorVer);
wxASSERT_MSG( ok, wxT("GLX version not found") );
if (!ok)
s_glxVersion = 10; // 1.0 by default
else
s_glxVersion = glxMajorVer*10 + glxMinorVer;
}
return s_glxVersion;
}
bool wxGLCanvasX11::SwapBuffers()
{
const Window xid = GetXWindow();
wxCHECK2_MSG( xid, return false, wxT("window must be shown") );
glXSwapBuffers(wxGetX11Display(), xid);
return true;
}
bool wxGLCanvasX11::IsShownOnScreen() const
{
return GetXWindow() && wxGLCanvasBase::IsShownOnScreen();
}
#endif // wxUSE_GLCANVAS