diff --git a/docs/changes.txt b/docs/changes.txt index 6a7d622b78..598ff85071 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -59,6 +59,8 @@ Changes in behaviour which may result in build errors - Added wxNativeWindow allowing to embed native widgets in wxWidgets programs. +- Improve wxGLCanvas to be more type safe and better support modern OpenGL. + All: - Add UTF-8 and ZIP 64 support to wxZip{Input,Output}Stream (Tobias Taschner). diff --git a/include/wx/glcanvas.h b/include/wx/glcanvas.h index 557b7d1774..545040d4bc 100644 --- a/include/wx/glcanvas.h +++ b/include/wx/glcanvas.h @@ -49,13 +49,120 @@ enum WX_GL_MIN_ACCUM_ALPHA, // use alpha buffer with most bits (> MIN_ACCUM_ALPHA bits) WX_GL_SAMPLE_BUFFERS, // 1 for multisampling support (antialiasing) WX_GL_SAMPLES, // 4 for 2x2 antialiasing supersampling on most graphics cards + WX_GL_FRAMEBUFFER_SRGB,// capability for sRGB framebuffer + // Context attributes WX_GL_CORE_PROFILE, // use an OpenGL core profile WX_GL_MAJOR_VERSION, // major OpenGL version of the core profile - WX_GL_MINOR_VERSION // minor OpenGL version of the core profile + WX_GL_MINOR_VERSION, // minor OpenGL version of the core profile + wx_GL_COMPAT_PROFILE, // use compatible profile (use all versions features) + WX_GL_FORWARD_COMPAT, // forward compatible context. OpenGL >= 3.0 + WX_GL_ES2, // ES or ES2 context. + WX_GL_DEBUG, // create a debug context + WX_GL_ROBUST_ACCESS, // robustness. + WX_GL_NO_RESET_NOTIFY, // never deliver notification of reset events + WX_GL_LOSE_ON_RESET, // if graphics reset, all context state is lost + WX_GL_RESET_ISOLATION, // protect other apps or share contexts from reset side-effects + WX_GL_RELEASE_FLUSH, // on context release, flush pending commands + WX_GL_RELEASE_NONE // on context release, pending commands are not flushed }; #define wxGLCanvasName wxT("GLCanvas") +// ---------------------------------------------------------------------------- +// wxGLAttribsBase: OpenGL rendering attributes +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_GL wxGLAttribsBase +{ +public: + wxGLAttribsBase() { Reset(); } + + // Setters + void AddAttribute(int attribute) { m_GLValues.push_back(attribute); } + // Search for searchVal and combine the next value with combineVal + void AddAttribBits(int searchVal, int combineVal); + // ARB functions necessity + void SetNeedsARB(bool needsARB = true) { m_needsARB = needsARB; } + + // Delete contents + void Reset() + { + m_GLValues.clear(); + m_needsARB = false; + } + + // Accessors + const int* GetGLAttrs() const + { + return (m_GLValues.empty() || !m_GLValues[0]) ? NULL : &*m_GLValues.begin(); + } + + int GetSize() const { return (int)(m_GLValues.size()); } + + // ARB function (e.g. wglCreateContextAttribsARB) is needed + bool NeedsARB() const { return m_needsARB; } + +private: + wxVector m_GLValues; + bool m_needsARB; +}; + +// ---------------------------------------------------------------------------- +// wxGLContextAttrs: OpenGL rendering context attributes +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_GL wxGLContextAttrs : public wxGLAttribsBase +{ +public: + // Setters, allowing chained calls + wxGLContextAttrs& CoreProfile(); + wxGLContextAttrs& MajorVersion(int val); + wxGLContextAttrs& MinorVersion(int val); + wxGLContextAttrs& OGLVersion(int vmayor, int vminor) + { return MajorVersion(vmayor).MinorVersion(vminor); } + wxGLContextAttrs& CompatibilityProfile(); + wxGLContextAttrs& ForwardCompatible(); + wxGLContextAttrs& ES2(); + wxGLContextAttrs& DebugCtx(); + wxGLContextAttrs& Robust(); + wxGLContextAttrs& NoResetNotify(); + wxGLContextAttrs& LoseOnReset(); + wxGLContextAttrs& ResetIsolation(); + wxGLContextAttrs& ReleaseFlush(int val = 1); //'int' allows future values + wxGLContextAttrs& PlatformDefaults(); + void EndList(); // No more values can be chained + + // Currently only used for X11 context creation + bool x11Direct; // X11 direct render + bool renderTypeRGBA; +}; + +// ---------------------------------------------------------------------------- +// wxGLAttributes: canvas configuration +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_GL wxGLAttributes : public wxGLAttribsBase +{ +public: + // Setters, allowing chained calls + wxGLAttributes& RGBA(); + wxGLAttributes& BufferSize(int val); + wxGLAttributes& Level(int val); + wxGLAttributes& DoubleBuffer(); + wxGLAttributes& Stereo(); + wxGLAttributes& AuxBuffers(int val); + wxGLAttributes& MinRGBA(int mRed, int mGreen, int mBlue, int mAlpha); + wxGLAttributes& Depth(int val); + wxGLAttributes& Stencil(int val); + wxGLAttributes& MinAcumRGBA(int mRed, int mGreen, int mBlue, int mAlpha); + wxGLAttributes& PlatformDefaults(); + wxGLAttributes& Defaults(); + wxGLAttributes& SampleBuffers(int val); + wxGLAttributes& Samplers(int val); + wxGLAttributes& FrameBuffersRGB(); + void EndList(); // No more values can be chained +}; + // ---------------------------------------------------------------------------- // wxGLContextBase: OpenGL rendering context // ---------------------------------------------------------------------------- @@ -63,14 +170,20 @@ enum class WXDLLIMPEXP_GL wxGLContextBase : public wxObject { public: - /* - The derived class should provide a ctor with this signature: - wxGLContext(wxGLCanvas *win, const wxGLContext *other = NULL); - */ +// The derived class should provide a ctor with this signature: +// +// wxGLContext(wxGLCanvas *win, +// const wxGLContext *other = NULL, +// const wxGLContextAttrs *ctxAttrs = NULL); // set this context as the current one virtual bool SetCurrent(const wxGLCanvas& win) const = 0; + + bool IsOK() { return m_isOk; } + +protected: + bool m_isOk; }; // ---------------------------------------------------------------------------- @@ -90,8 +203,8 @@ public: The derived class should provide a ctor with this signature: wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, wxWindowID id = wxID_ANY, - int* attribList = 0, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, @@ -113,6 +226,7 @@ public: // --------- // check if the given attributes are supported without creating a canvas + static bool IsDisplaySupported(const wxGLAttributes& dispAttrs); static bool IsDisplaySupported(const int *attribList); #if wxUSE_PALETTE @@ -134,6 +248,11 @@ public: // compilation static bool IsExtensionSupported(const char *extension); + // Get the wxGLContextAttrs object filled with the context-related values + // of the list of attributes passed at ctor when no wxGLAttributes is used + // as a parameter + wxGLContextAttrs& GetGLCTXAttrs() { return m_GLCTXAttrs; } + // deprecated methods using the implicit wxGLContext #if WXWIN_COMPATIBILITY_2_8 wxDEPRECATED( wxGLContext* GetContext() const ); @@ -158,6 +277,15 @@ protected: // by glXQueryExtensionsString() or glGetString(GL_EXTENSIONS) static bool IsExtensionInList(const char *list, const char *extension); + // For the case of "int* attribList" at ctor is != 0 + wxGLContextAttrs m_GLCTXAttrs; + + // Extract pixel format and context attributes. + // Return false if an unknown attribute is found. + static bool ParseAttribList(const int* attribList, + wxGLAttributes& dispAttrs, + wxGLContextAttrs* ctxAttrs = NULL); + #if wxUSE_PALETTE // create default palette if we're not using RGBA mode // (not supported in most ports) diff --git a/include/wx/gtk/glcanvas.h b/include/wx/gtk/glcanvas.h index 1a2d6734e7..f194e60f37 100644 --- a/include/wx/gtk/glcanvas.h +++ b/include/wx/gtk/glcanvas.h @@ -20,6 +20,16 @@ class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasX11 { public: + wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + + wxEXPLICIT // avoid implicitly converting a wxWindow* to wxGLCanvas wxGLCanvas(wxWindow *parent, wxWindowID id = wxID_ANY, const int *attribList = NULL, @@ -29,6 +39,15 @@ public: const wxString& name = wxGLCanvasName, const wxPalette& palette = wxNullPalette); + bool Create(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + bool Create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, diff --git a/include/wx/gtk1/glcanvas.h b/include/wx/gtk1/glcanvas.h index bb4cd67323..446344b860 100644 --- a/include/wx/gtk1/glcanvas.h +++ b/include/wx/gtk1/glcanvas.h @@ -20,6 +20,16 @@ class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasX11 { public: + wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + + wxEXPLICIT // avoid implicitly converting a wxWindow* to wxGLCanvas wxGLCanvas(wxWindow *parent, wxWindowID id = wxID_ANY, const int *attribList = NULL, @@ -29,6 +39,15 @@ public: const wxString& name = wxGLCanvasName, const wxPalette& palette = wxNullPalette); + bool Create(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + bool Create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, diff --git a/include/wx/msw/glcanvas.h b/include/wx/msw/glcanvas.h index b56ccd1f5d..fdcdd1faa5 100644 --- a/include/wx/msw/glcanvas.h +++ b/include/wx/msw/glcanvas.h @@ -24,7 +24,9 @@ class WXDLLIMPEXP_GL wxGLContext : public wxGLContextBase { public: - wxGLContext(wxGLCanvas *win, const wxGLContext* other = NULL); + wxGLContext(wxGLCanvas *win, + const wxGLContext *other = NULL, + const wxGLContextAttrs *ctxAttrs = NULL); virtual ~wxGLContext(); virtual bool SetCurrent(const wxGLCanvas& win) const; @@ -46,6 +48,16 @@ class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasBase { public: wxEXPLICIT // avoid implicitly converting a wxWindow* to wxGLCanvas + wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + + wxEXPLICIT wxGLCanvas(wxWindow *parent, wxWindowID id = wxID_ANY, const int *attribList = NULL, @@ -55,6 +67,15 @@ public: const wxString& name = wxGLCanvasName, const wxPalette& palette = wxNullPalette); + bool Create(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + bool Create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, @@ -76,9 +97,12 @@ public: // get the HDC used for OpenGL rendering HDC GetHDC() const { return m_hDC; } - // try to find pixel format matching the given attributes list for the - // specified HDC, return 0 on error, otherwise pfd is filled in with the - // information from attribList if non-NULL + // Try to find pixel format matching the given attributes list for the + // specified HDC, return 0 on error, otherwise ppfd is filled in with the + // information from dispAttrs + static int FindMatchingPixelFormat(const wxGLAttributes& dispAttrs, + PIXELFORMATDESCRIPTOR* ppfd = NULL); + // Same as FindMatchingPixelFormat static int ChooseMatchingPixelFormat(HDC hdc, const int *attribList, PIXELFORMATDESCRIPTOR *pfd = NULL); diff --git a/include/wx/osx/glcanvas.h b/include/wx/osx/glcanvas.h index 69f29fc499..268b5d43a5 100644 --- a/include/wx/osx/glcanvas.h +++ b/include/wx/osx/glcanvas.h @@ -29,13 +29,18 @@ WXDLLIMPEXP_GL void WXGLDestroyContext( WXGLContext context ); WXDLLIMPEXP_GL WXGLContext WXGLGetCurrentContext(); WXDLLIMPEXP_GL bool WXGLSetCurrentContext(WXGLContext context); -WXDLLIMPEXP_GL WXGLPixelFormat WXGLChoosePixelFormat(const int *attribList); +WXDLLIMPEXP_GL WXGLPixelFormat WXGLChoosePixelFormat(const int *GLAttrs = NULL, + int n1 = 0, + const int *ctxAttrs = NULL, + int n2 = 0); WXDLLIMPEXP_GL void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat ); class WXDLLIMPEXP_GL wxGLContext : public wxGLContextBase { public: - wxGLContext(wxGLCanvas *win, const wxGLContext *other = NULL); + wxGLContext(wxGLCanvas *win, + const wxGLContext *other = NULL, + const wxGLContextAttrs *ctxAttrs = NULL); virtual ~wxGLContext(); virtual bool SetCurrent(const wxGLCanvas& win) const; @@ -52,6 +57,15 @@ private: class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasBase { public: + wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + wxGLCanvas(wxWindow *parent, wxWindowID id = wxID_ANY, const int *attribList = NULL, @@ -61,6 +75,15 @@ public: const wxString& name = wxGLCanvasName, const wxPalette& palette = wxNullPalette); + bool Create(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + bool Create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, @@ -85,6 +108,9 @@ public: // return the pixel format used by this window WXGLPixelFormat GetWXGLPixelFormat() const { return m_glFormat; } + // Return the copy of attributes passed at ctor + wxGLAttributes& GetGLDispAttrs() { return m_GLAttrs; } + // update the view port of the current context to match this window void SetViewport(); @@ -133,6 +159,7 @@ public: protected: WXGLPixelFormat m_glFormat; + wxGLAttributes m_GLAttrs; #if wxOSX_USE_CARBON bool m_macCanvasIsShown, diff --git a/include/wx/unix/glx11.h b/include/wx/unix/glx11.h index 5a321a2860..9295687a4b 100644 --- a/include/wx/unix/glx11.h +++ b/include/wx/unix/glx11.h @@ -12,6 +12,9 @@ #include +class wxGLContextAttrs; +class wxGLAttributes; + // ---------------------------------------------------------------------------- // wxGLContext // ---------------------------------------------------------------------------- @@ -19,7 +22,9 @@ class WXDLLIMPEXP_GL wxGLContext : public wxGLContextBase { public: - wxGLContext(wxGLCanvas *win, const wxGLContext *other = NULL); + wxGLContext(wxGLCanvas *win, + const wxGLContext *other = NULL, + const wxGLContextAttrs *ctxAttrs = NULL); virtual ~wxGLContext(); virtual bool SetCurrent(const wxGLCanvas& win) const wxOVERRIDE; @@ -46,8 +51,8 @@ public: // default ctor doesn't do anything, InitVisual() must be called wxGLCanvasX11(); - // initializes the XVisualInfo corresponding to the given attributes - bool InitVisual(const int *attribList); + // initializes GLXFBConfig and XVisualInfo corresponding to the given attributes + bool InitVisual(const wxGLAttributes& dispAttrs); // frees XVisualInfo info virtual ~wxGLCanvasX11(); @@ -75,10 +80,6 @@ public: // GLX-specific methods // -------------------- - // return attribs for glXCreateContextAttribsARB - const int *GetGLXContextAttribs() const { return m_glxContextAttribs; } - - // override some wxWindow methods // ------------------------------ @@ -108,22 +109,10 @@ public: // // returns false if XVisualInfo couldn't be initialized, otherwise caller // is responsible for freeing the pointers - static bool InitXVisualInfo(const int *attribList, + static bool InitXVisualInfo(const wxGLAttributes& dispAttrs, GLXFBConfig **pFBC, XVisualInfo **pXVisual); private: - // initializes glxContextAttribs as defined by wxattrs which must be - // 0-terminated - static void InitGLXContextAttribs(const int *wxattrs, int *glxctxattribs); - - // fills in glattrs with attributes defined by wxattrs which must be - // 0-terminated if it is non-NULL - // will ignore any gl context attribs - // - // n is the max size of glattrs, false is returned if we overflow it, it - // should be at least 16 to accommodate the default attributes - static bool ConvertWXAttrsToGL(const int *wxattrs, int *glattrs, size_t n); - // this is only used if it's supported i.e. if GL >= 1.3 GLXFBConfig *m_fbc; @@ -134,10 +123,6 @@ private: // the global/default versions of the above static GLXFBConfig *ms_glFBCInfo; static XVisualInfo *ms_glVisualInfo; - - // max 8 attributes plus terminator - // if first is 0, create legacy context - int m_glxContextAttribs[9]; }; // ---------------------------------------------------------------------------- diff --git a/include/wx/x11/glcanvas.h b/include/wx/x11/glcanvas.h index 84a8b14980..a02e0ba4b9 100644 --- a/include/wx/x11/glcanvas.h +++ b/include/wx/x11/glcanvas.h @@ -17,6 +17,16 @@ class WXDLLIMPEXP_GL wxGLCanvas : public wxGLCanvasX11 { public: + wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + + wxEXPLICIT // avoid implicitly converting a wxWindow* to wxGLCanvas wxGLCanvas(wxWindow *parent, wxWindowID id = wxID_ANY, const int *attribList = NULL, @@ -26,6 +36,15 @@ public: const wxString& name = wxGLCanvasName, const wxPalette& palette = wxNullPalette); + bool Create(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + bool Create(wxWindow *parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, diff --git a/interface/wx/glcanvas.h b/interface/wx/glcanvas.h index 36e404a7bc..642da7dd80 100644 --- a/interface/wx/glcanvas.h +++ b/interface/wx/glcanvas.h @@ -5,6 +5,433 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// +/** + @class wxGLAttribsBase + + This is the base class for wxGLAttributes and wxGLContextAttrs. + It stores internally the list required by OS and OpenGL driver for setting + display and rendering context attributes. + + Normally this class is not used directly. But there's a case where it its + member functions are useful: setting attributes not handled by wxWidgets. + Suppose the OpenGL Board sets a new functionality of the context, by adding + a new attribute (let's call it NEW_CTX_F) and also a new type of context by + allowing a new bit value (let's call it NEW_BITS) for the CONTEXT_PROFILE_MASK_ARB + value. These new values can be added to the list using code like this: + + @code + wxGLContextAttrs cxtAttrs; + // Some values + cxtAttrs.CoreProfile().OGLVersion(5, 0); // OGL 5.0, whenever available + cxtAttrs.PlatformDefaults(); + // Values usually are platform-dependant named (even value assigned!) + #if defined(__WXMSW__) + cxtAttrs.AddAttribute(WGL_NEW_CTX_F); + cxtAttrs.AddAttribBits(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_NEW_BITS); + #elif defined(__WXX11__) + cxtAttrs.AddAttribute(GLX_NEW_CTX_F); + cxtAttrs.AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_NEW_BITS); + #else + // Other platforms + #endif + cxtAttrs.EndList(); // Don't forget this + cxtAttrs.SetNeedsARB(true); // Context attributes are set by an ARB-function + @endcode + + @since 3.1.0 + + @library{wxgl} + @category{gl} + + @see wxGLCanvas, wxGLContext, wxGLContextAttrs, wxGLAttributes +*/ +class WXDLLIMPEXP_GL wxGLAttribsBase +{ +public: + /// Constructor. + wxGLAttribsBase(); + + /** + Adds an integer value to the list of attributes. + + @param attribute + The value to add. + */ + void AddAttribute(int attribute); + + /** + Combine (bitwise OR) a given value with the existing one, if any. + This function first searches for an identifier and then combines the + given value with the value right after the identifier. + If the identifier is not found, two new values (i.e. the identifier and + the given value) are added to the list. + + @param searchVal + The identifier to search for. + @param combineVal + The value to combine with the existing one. + */ + void AddAttribBits(int searchVal, int combineVal); + + /** + Sets the necessity of using special ARB-functions + (e.g. wglCreateContextAttribsARB in MSW) for some of the attributes of + the list. + Multi-sampling and modern context require these ARB-functions. + + @param needsARB + @true if an ARB-function is needed for any of the attributes. + + @see NeedsARB + */ + void SetNeedsARB(bool needsARB = true); + + /// Delete contents and sets ARB-flag to false. + void Reset(); + + /** + Returns a pointer to the internal list of attributes. It's very unlikely + you need this function. + If the list is empty the returned value is @NULL. + */ + const int* GetGLAttrs() const; + + /** Returns the size of the internal list of attributes. + Remember that the last value in the list must be a '0' (zero). So, a + minimal list is of size = 2, the first value is meaningful and the last is '0'. + */ + int GetSize(); + + /** + Returns the current value of the ARB-flag. + + @see SetNeedsARB + */ + bool NeedsARB() const; +}; + +/** + @class wxGLAttributes + + This class is used for setting display attributes when drawing through + OpenGL ("Pixel format" in MSW and OSX parlance, "Configs" in X11). + While framebuffer depth and samplers are still common, attributes + like layers overlay or not using true colour are rarely used nowadays. + + Attributes can be chained. For example: + @code + wxGLAttributes dispAttrs; + dispAttrs.PlatformDefaults().MinRGBA(8, 8, 8, 8).DoubleBuffer().Depth(32).EndList(); + @endcode + + Notice that EndList() must be used as the last attribute. Not adding it will + likely result in nothing displayed at all. + + @note Not all of platform-dependant available attributes are implemented in + wxWidgets. You can set other attributes by using AddAttribute() and + AddAttribBits() functions inherited from the base wxGLAttribsBase class. + + @since 3.1.0 + + @library{wxgl} + @category{gl} + + @see wxGLCanvas, wxGLContext, wxGLAttribsBase, wxGLContextAttrs +*/ +class wxGLAttributes : public wxGLAttribsBase +{ +public: + /** + Use true color (8 bits for each color plus 8 bits for alpha channel). + */ + wxGLAttributes& RGBA(); + + /** + Specifies the number of bits for buffer when it isn't a RGBA buffer. + It makes no effect for OS X. + + @param val + The number of bits. + */ + wxGLAttributes& BufferSize(int val); + + /** + Specifies the framebuffer level. It makes no effect for OS X. + + @param val + 0 for main buffer, >0 for overlay, <0 for underlay. + */ + wxGLAttributes& Level(int val); + + /** + Requests using double buffering if present. + */ + wxGLAttributes& DoubleBuffer(); + + /** + Use stereoscopic display if present. + */ + wxGLAttributes& Stereo(); + + /** + Specifies the number of auxiliary buffers. + + @param val + The number of auxiliary buffers. + */ + wxGLAttributes& AuxBuffers(int val); + + /** + Specifies the minimal number of bits for colour buffers. + + @param mRed + The minimal number of bits for colour red. + @param mGreen + The minimal number of bits for colour green. + @param mBlue + The minimal number of bits for colour blue. + @param mAlpha + The minimal number of bits for alpha channel. + */ + wxGLAttributes& MinRGBA(int mRed, int mGreen, int mBlue, int mAlpha); + + /** + Specifies number of bits for Z-buffer. + + @param val + Number of bits for Z-buffer (typically 0, 16 or 32). + */ + wxGLAttributes& Depth(int val); + + /** + Specifies number of bits for stencil buffer. + + @param val + Number of bits. + */ + wxGLAttributes& Stencil(int val); + + /** + Specifies the minimal number of bits for the accumulation buffer. + + @param mRed + The minimal number of bits for red accumulator. + @param mGreen + The minimal number of bits for green accumulator. + @param mBlue + The minimal number of bits for blue accumulator. + @param mAlpha + The minimal number of bits for alpha accumulator. + */ + wxGLAttributes& MinAcumRGBA(int mRed, int mGreen, int mBlue, int mAlpha); + + /** + Use multi-sampling support (antialiasing). + + @param val + Number of sample buffers, usually 1. + */ + wxGLAttributes& SampleBuffers(int val); + + /** + Specifies the number of samplers per pixel. + + @param val + Number of samplers, e.g. 4 for 2x2 antialiasing. + */ + wxGLAttributes& Samplers(int val); + + /** + Used to request a frame buffer sRGB capable. It makes no effect for OS X. + */ + wxGLAttributes& FrameBuffersRGB(); + + /** + Set some typically needed attributes. E.g. full-acceleration on MSW. + + @see Defaults() + */ + wxGLAttributes& PlatformDefaults(); + + /** + wxWidgets defaults: + RGBA, Z-depth 16 bits, double buffering, 1 sample buffer, 4 samplers. + + @see PlatformDefaults() + */ + wxGLAttributes& Defaults(); + + /** + The set of attributes must end with this one; otherwise, the GPU may + display nothing at all. + */ + void EndList(); +}; + +/** + @class wxGLContextAttrs + + This class is used for setting context attributes. + Since OpenGL version 3.0 the ARB adds attributes time to time to the rendering + context functionality. wxWidgets implements attributes up to OGL 4.5, but + you can set new attributes by using AddAttribute() and AddAttribBits() + functions inherited from the base wxGLAttribsBase class. + + Attributes can be chained. For example: + @code + wxGLContextAttrs cxtAttrs; + cxtAttrs.CoreProfile().OGLVersion(4, 5).Robust().ResetIsolation().EndList(); + @endcode + + Notice that EndList() must be used as the last attribute. Not adding it will + likely result in nothing displayed at all. + + @since 3.1.0 + + @library{wxgl} + @category{gl} + + @see wxGLCanvas, wxGLContext, wxGLAttribsBase, wxGLAttributes +*/ +class wxGLContextAttrs : public wxGLAttribsBase +{ +public: + /** + Request an OpenGL core profile for the context. + + If the requested OpenGL version is less than 3.2, this attribute is + ignored and the functionality of the context is determined solely by + the requested version. + */ + wxGLContextAttrs& CoreProfile(); + + /** + Request specific OpenGL core major version number (>= 3). + + @param val + The major version number requested. + + It has no effect under OS X where specifying CoreProfile() will + result in using OpenGL version at least 3.2. + */ + wxGLContextAttrs& MajorVersion(int val); + + /** + Request specific OpenGL core minor version number. + + @param val + The minor version number requested, e.g. 2 if OpenGL 3.2 is requested. + + It has no effect under OS X where specifying CoreProfile() will + result in using OpenGL version at least 3.2. + */ + wxGLContextAttrs& MinorVersion(int val); + + /** + An easy way of requesting an OpenGL version. + + @param vmayor + The major version number requested, e.g. 4 if OpenGL 4.5 is requested. + + @param vminor + The minor version number requested, e.g. 5 if OpenGL 4.5 is requested. + + It has no effect under OS X where specifying CoreProfile() will + result in using OpenGL version at least 3.2. + */ + wxGLContextAttrs& OGLVersion(int vmayor, int vminor); + + /** + Request a type of context with all OpenGL features from version 1.0 to + the newest available by the GPU driver. In this mode the GPU may be some + slower than it would be without this compatibility attribute. + */ + wxGLContextAttrs& CompatibilityProfile(); + + /** + Request a forward-compatible context. + Forward-compatible contexts are defined only for OpenGL versions 3.0 and + later. They must not support functionality marked as deprecated or + removed by the requested version of the OpenGL API. + + It has no effect under OS X. + */ + wxGLContextAttrs& ForwardCompatible(); + + /** + Request an ES or ES2 ("Embedded Subsystem") context. These are special + subsets of OpenGL, lacking some features of the full specification. + Used mainly in embedded devices such as mobile phones. + + It has no effect under OS X. + */ + wxGLContextAttrs& ES2(); + + /** + Request debugging functionality. This tells OpenGL to prepare a set where + some logs are enabled and also allows OGL to send debug messages through + a callback function. + + It has no effect under OS X. + */ + wxGLContextAttrs& DebugCtx(); + + /** + Request robustness, or how OpenGL handles out-of-bounds buffer object + accesses and graphics reset notification behaviours. + + It has no effect under OS X. + */ + wxGLContextAttrs& Robust(); + + /** + With robustness enabled, never deliver notification of reset events. + + It has no effect under OS X. + */ + wxGLContextAttrs& NoResetNotify(); + + /** + With robustness enabled, if graphics reset happens, all context state is + lost. + + It has no effect under OS X. + */ + wxGLContextAttrs& LoseOnReset(); + + /** + Request OpenGL to protect other applications or shared contexts from reset + side-effects. + + It has no effect under OS X. + */ + wxGLContextAttrs& ResetIsolation(); + + /** + Request OpenGL to avoid or not flushing pending commands when the context + is made no longer current (released). If you don't specify this attribute, + the GPU driver default is 'flushing'. + + @param val + 0 for not flushing, 1 (wxWidgets default) for flushing pending commands. + + It has no effect under OS X. + */ + wxGLContextAttrs& ReleaseFlush(int val = 1); + + /** + Set platform specific defaults. Currently only Unix defaults are + implemented: use X11 direct rendering and use X11 RGBA type. + */ + wxGLContextAttrs& PlatformDefaults(); + + /** + The set of attributes must end with this one; otherwise, the GPU may + display nothing at all. + */ + void EndList(); +}; + /** @class wxGLContext @@ -12,33 +439,46 @@ machine and the connection between OpenGL and the system. The OpenGL state includes everything that can be set with the OpenGL API: - colors, rendering variables, display lists, texture objects, etc. Although - it is possible to have multiple rendering contexts share display lists in - order to save resources, this method is hardly used today any more, because - display lists are only a tiny fraction of the overall state. + colors, rendering variables, buffer data ids, texture objects, etc. It is + possible to have multiple rendering contexts share buffer data and textures. + This feature is specially useful when the application use multiple threads + for updating data into the memory of the graphics card. - Therefore, one rendering context is usually used with or bound to multiple - output windows in turn, so that the application has access to the complete - and identical state while rendering into each window. + Whether one only rendering context is used with or bound to multiple output + windows or if each window has its own bound context is a developer decision. + It is important to take into account that GPU makers may set different pointers + to the same OGL function for different contexts. The way these pointers are + retrieved from the OGL driver should be used again for each new context. Binding (making current) a rendering context with another instance of a - wxGLCanvas however works only if the other wxGLCanvas was created with the - same attributes as the wxGLCanvas from which the wxGLContext was - initialized. (This applies to sharing display lists among contexts - analogously.) + wxGLCanvas however works only if the both wxGLCanvas instances were created + with the same attributes. + + OpenGL version 3 introduced a new type of specification profile, the modern + core profile. The old compatibility profile maintains all legacy features. + Since wxWidgets 3.1.0 you can choose the type of context and even ask for a + specified OGL version number. However, its advised to use only core profile + as the compatibility profile may run a bit slower. + + OpenGL core profile specification defines several flags at context creation + that determine not only the type of context but also some features. Some of + these flags can be set in the list of attributes used at wxGLCanvas ctor. + But since wxWidgets 3.1.0 it is strongly encouraged to use the new mechanism: + setting the context attributes with a wxGLContextAttrs object and the canvas + attributes with a wxGLAttributes object. + + The best way of knowing if your OpenGL environment supports a specific type + of context is creating a wxGLContext instance and checking wxGLContext::IsOK(). + If it returns false, then simply delete that instance and create a new one + with other attributes. - Note that some wxGLContext features are extremely platform-specific - its - best to check your native platform's glcanvas header (on windows - include/wx/msw/glcanvas.h) to see what features your native platform - provides. - wxHAS_OPENGL_ES is defined on platforms that only have this implementation - available (eg the iPhone) und don't support the full specification. + available (e.g. the iPhone) and don't support the full specification. @library{wxgl} @category{gl} - @see wxGLCanvas + @see wxGLCanvas, wxGLContextAttrs, wxGLAttributes */ class wxGLContext : public wxObject { @@ -54,10 +494,31 @@ public: other wxGLCanvas that has been created with equivalent attributes as win. @param other - Context to share display lists with or @NULL (the default) for no + Context to share some data with or @NULL (the default) for no sharing. + @param ctxAttrs + A wxGLContextAttrs pointer to the attributes used for defining the + flags when OGL >= 3.2 is requested. This is the preferred method + since wxWidgets 3.1.0. The previous method (still available for + backwards compatibility) is to define the attributes at wxGLCanvas + ctor. If this parameter is @NULL (the default) then that previous + method is taken. + If no attributes are defined at all, then those provided by the GPU + driver defaults will be used. */ - wxGLContext(wxGLCanvas* win, const wxGLContext* other = NULL); + wxGLContext(wxGLCanvas* win, + const wxGLContext* other = NULL, + const wxGLContextAttrs* ctxAttrs = NULL); + + /** + Checks if the underlying OpenGL rendering context was correctly created + by the system with the requested attributes. If this function returns + @false then the wxGLContext object is useless and should be deleted and + recreated with different attributes. + + @since 3.1.0 + */ + bool IsOK(); /** Makes the OpenGL state that is represented by this rendering context @@ -75,85 +536,82 @@ public: /** @anchor wxGL_FLAGS - Constants for use with wxGLCanvas. + Constants for use with wxGLCanvas. Most of the constants must be followed + by a value. This is indicated by "(F)". + Instead of these flags, the use of wxGLAttributes and wxGLContextAttrs is + preferred since wxWidgets 3.1.0. @note Not all implementations support options such as stereo, auxiliary buffers, alpha channel, and accumulator buffer, use - wxGLCanvas::IsDisplaySupported() to check for individual attributes - support. - */ + wxGLCanvas::IsDisplaySupported() to check for individual visual + attributes support. +*/ enum { /// Use true color (the default if no attributes at all are specified); /// do not use a palette. WX_GL_RGBA = 1, - /// Specifies the number of bits for buffer if not WX_GL_RGBA. + /// (F) Specifies the number of bits for buffer if not WX_GL_RGBA. WX_GL_BUFFER_SIZE, - /// Must be followed by 0 for main buffer, >0 for overlay, <0 for underlay. + /// (F) 0 for main buffer, >0 for overlay, <0 for underlay. WX_GL_LEVEL, - /// Use double buffering if present (on if no attributes specified). + /// Use double buffering if present ("on" if no attributes specified). WX_GL_DOUBLEBUFFER, /// Use stereoscopic display. WX_GL_STEREO, - /// Specifies number of auxiliary buffers. + /// (F) The number of auxiliary buffers. WX_GL_AUX_BUFFERS, - /// Use red buffer with most bits (> MIN_RED bits) + /// (F) Use red buffer with most bits (> MIN_RED bits) WX_GL_MIN_RED, - /// Use green buffer with most bits (> MIN_GREEN bits) + /// (F) Use green buffer with most bits (> MIN_GREEN bits) WX_GL_MIN_GREEN, - /// Use blue buffer with most bits (> MIN_BLUE bits) + /// (F) Use blue buffer with most bits (> MIN_BLUE bits) WX_GL_MIN_BLUE, - /// Use alpha buffer with most bits (> MIN_ALPHA bits) + /// (F) Use alpha buffer with most bits (> MIN_ALPHA bits) WX_GL_MIN_ALPHA, - /// Specifies number of bits for Z-buffer (typically 0, 16 or 32). + /// (F) Specifies number of bits for Z-buffer (typically 0, 16 or 32). WX_GL_DEPTH_SIZE, - /// Specifies number of bits for stencil buffer. + /// (F) Specifies number of bits for stencil buffer. WX_GL_STENCIL_SIZE, - /// Specifies minimal number of red accumulator bits. + /// (F) Specifies minimal number of red accumulator bits. WX_GL_MIN_ACCUM_RED, - /// Specifies minimal number of green accumulator bits. + /// (F) Specifies minimal number of green accumulator bits. WX_GL_MIN_ACCUM_GREEN, - /// Specifies minimal number of blue accumulator bits. + /// (F) Specifies minimal number of blue accumulator bits. WX_GL_MIN_ACCUM_BLUE, - /// Specifies minimal number of alpha accumulator bits. + /// (F) Specifies minimal number of alpha accumulator bits. WX_GL_MIN_ACCUM_ALPHA, - /// 1 for multisampling support (antialiasing) + /// (F) 1 for multi-sampling support (antialiasing) WX_GL_SAMPLE_BUFFERS, - /// 4 for 2x2 antialiasing supersampling on most graphics cards + /// (F) 4 for 2x2 antialiasing supersampling on most graphics cards WX_GL_SAMPLES, /** - Request an OpenGL core profile. + Used to request a frame buffer sRGB capable - Notice that using this attribute will result in also requesting OpenGL - at least version 3.0. - - See ::WX_GL_MAJOR_VERSION and ::WX_GL_MINOR_VERSION for more precise - version selection. - - @since 3.0.3 - */ - WX_GL_CORE_PROFILE, + @since 3.1.0 + */ + WX_GL_FRAMEBUFFER_SRGB, /** - Request specific OpenGL core major version number (>= 3). + (F) Request specific OpenGL core major version number (>= 3). This attribute should be followed by the major version number requested. @@ -163,19 +621,111 @@ enum there for portability. @since 3.0.3 - */ + */ WX_GL_MAJOR_VERSION, /** - Request specific OpenGL core minor version number. + (F) Request specific OpenGL core minor version number. This attribute has the same semantics as ::WX_GL_MAJOR_VERSION but is for the minor OpenGL version, e.g. 2 if OpenGL 3.2 is requested. @since 3.0.3 - */ - WX_GL_MINOR_VERSION + */ + WX_GL_MINOR_VERSION, + /** + Request an OpenGL core profile for the context. + + If the requested OpenGL version is less than 3.2, this attribute is + ignored and the functionality of the context is determined solely by + the requested version. + + @since 3.0.3 + */ + WX_GL_CORE_PROFILE, + + /** + Request a type of context with all OpenGL features from version 1.0 to + the newest available by the GPU driver. In this mode the GPU may be some + slower than it would be without this compatibility attribute. + + @since 3.1.0 + */ + wx_GL_COMPAT_PROFILE, + + /** + Request a forward-compatible context. + Forward-compatible contexts are defined only for OpenGL versions 3.0 and + later. They must not support functionality marked as deprecated by that + version of the OpenGL API. + + @since 3.1.0 + */ + WX_GL_FORWARD_COMPAT, + + /** + Request an ES or ES2 ("Embedded Subsystem") context. These are special + subsets of OpenGL, lacking some features of the full specification. + Used mainly in embedded devices such as mobile phones. + + @since 3.1.0 + */ + WX_GL_ES2, + + /** + Request debugging functionality. This tells OpenGL to prepare a set where + some logs are enabled and also allows OGL to send debug messages through + a callback function. + + @since 3.1.0 + */ + WX_GL_DEBUG, + + /** + Request robustness, or how OpenGL handles out-of-bounds buffer object + accesses and graphics reset notification behaviours. + + @since 3.1.0 + */ + WX_GL_ROBUST_ACCESS, + + /** + With robustness enabled, never deliver notification of reset events. + + @since 3.1.0 + */ + WX_GL_NO_RESET_NOTIFY, + + /** + With robustness enabled, if graphics reset happens, all context state is + lost. + + @since 3.1.0 + */ + WX_GL_LOSE_ON_RESET, + + /** + Request OpenGL to protect other apps or shared contexts from reset + side-effects. + + @since 3.1.0 + */ + WX_GL_RESET_ISOLATION, + + /** + Request OpenGL to flush pending commands when the context is released. + + @since 3.1.0 + */ + WX_GL_RELEASE_FLUSH, + + /** + Request OpenGL to avoid flushing pending commands when the context is released. + + @since 3.1.0 + */ + WX_GL_RELEASE_NONE }; /** @@ -200,9 +750,10 @@ enum please update your code to create the rendering contexts explicitly. To set up the attributes for the canvas (number of bits for the depth - buffer, number of bits for the stencil buffer and so on) you should set up - the correct values of the @e attribList parameter. The values that should - be set up and their meanings will be described below. + buffer, number of bits for the stencil buffer and so on) you pass them + in the constructor using a wxGLAttributes instance. You can still use + the way before 3.1.0 (setting up the correct values of the @e attribList + parameter) but it's discouraged. @note On those platforms which use a configure script (e.g. Linux and Mac OS) @@ -211,12 +762,13 @@ enum To switch it on under the other platforms (e.g. Windows), you need to edit the @c setup.h file and set @c wxUSE_GLCANVAS to @c 1 and then also pass @c USE_OPENGL=1 to the make utility. You may also need to add @c opengl32.lib - and @c glu32.lib to the list of the libraries your program is linked with. + (and @c glu32.lib for old OpenGL versions) to the list of the libraries + your program is linked with. @library{wxgl} @category{gl} - @see wxGLContext + @see wxGLContext, wxGLAttributes, wxGLContextAttrs */ class wxGLCanvas : public wxWindow { @@ -225,10 +777,11 @@ public: Creates a window with the given parameters. Notice that you need to create and use a wxGLContext to output to this window. - If @a attribList is not specified, double buffered RGBA mode is used. - @param parent Pointer to a parent window. + @param dispAttrs + The wxGLAttributes used for setting display attributes (not for + rendering context attributes). @param id Window identifier. If -1, will automatically create an identifier. @param pos @@ -244,6 +797,27 @@ public: Window style. @param name Window name. + @param palette + Palette for indexed colour (i.e. non WX_GL_RGBA) mode. Ignored + under most platforms. + + @since 3.1.0 + */ + wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString& name = wxGLCanvasName, + const wxPalette& palette = wxNullPalette); + + /** + This constructor is still available only for compatibility reasons. + Please use the constructor with wxGLAttributes instead. + + If @a attribList is not specified, wxGLAttributes::Defaults() is used. + @param attribList Array of integers. With this parameter you can set the device context attributes associated to this window. This array is @@ -262,9 +836,6 @@ public: WX_GL_DOUBLEBUFFER are used. But notice that if you do specify some attributes you also need to explicitly include these two default attributes in the list if you need them. - @param palette - Palette for indexed colour (i.e. non WX_GL_RGBA) mode. Ignored - under most platforms. */ wxGLCanvas(wxWindow* parent, wxWindowID id = wxID_ANY, const int* attribList = NULL, @@ -276,6 +847,21 @@ public: /** Determines if a canvas having the specified attributes is available. + This only applies for visual attributes, not rendering context attributes. + + @param dispAttrs + The requested attributes. + + @return @true if attributes are supported. + + @since 3.1.0 + */ + static bool IsDisplaySupported(const wxGLAttributes& dispAttrs); + + /** + Determines if a canvas having the specified attributes is available. + This only applies for visual attributes, not rendering context attributes. + Please, use the new form of this method, using wxGLAttributes. @param attribList See @a attribList for wxGLCanvas(). diff --git a/src/common/glcmn.cpp b/src/common/glcmn.cpp index c83273e4a1..1db976b914 100644 --- a/src/common/glcmn.cpp +++ b/src/common/glcmn.cpp @@ -40,6 +40,34 @@ wxIMPLEMENT_CLASS(wxGLApp, wxApp); // implementation // ============================================================================ +void wxGLAttribsBase::AddAttribBits(int searchVal, int combineVal) +{ + // Search for searchVal + wxVector::iterator it = m_GLValues.begin(); + while ( it != m_GLValues.end() && *it != searchVal ) + it++; + // Have we searchVal? + if ( it != m_GLValues.end() ) + { + if ( ++it == m_GLValues.end() ) + { + m_GLValues.push_back(combineVal); + } + else + { + *it |= combineVal; + } + } + else + { + // Add the identifier and the bits + m_GLValues.push_back(searchVal); + m_GLValues.push_back(combineVal); + } +} + +// ============================================================================ + wxGLCanvasBase::wxGLCanvasBase() { #if WXWIN_COMPATIBILITY_2_8 @@ -147,6 +175,207 @@ bool wxGLCanvasBase::IsExtensionInList(const char *list, const char *extension) return false; } +/* static */ +bool wxGLCanvasBase::ParseAttribList(const int *attribList, + wxGLAttributes& dispAttrs, + wxGLContextAttrs* ctxAttrs) +{ + // Some attributes are usually needed + dispAttrs.PlatformDefaults(); + if ( ctxAttrs ) + ctxAttrs->PlatformDefaults(); + + if ( !attribList ) + { + // Set default attributes + dispAttrs.Defaults(); + dispAttrs.EndList(); + if ( ctxAttrs ) + ctxAttrs->EndList(); + return true; + } + + int src = 0; + int minColo[4] = {0, 0, 0, 0}; + int minAcum[4] = {0, 0, 0, 0}; + int num = 0; + while ( attribList[src] ) + { + // Check a non zero-terminated list. This may help a bit with malformed lists. + if ( ++num > 200 ) + { + wxFAIL_MSG("The attributes list is not zero-terminated"); + } + + switch ( attribList[src++] ) + { + // Pixel format attributes + + case WX_GL_RGBA: + dispAttrs.RGBA(); + break; + + case WX_GL_BUFFER_SIZE: + dispAttrs.BufferSize(attribList[src++]); + break; + + case WX_GL_LEVEL: + dispAttrs.Level(attribList[src++]); + break; + + case WX_GL_DOUBLEBUFFER: + dispAttrs.DoubleBuffer(); + break; + + case WX_GL_STEREO: + dispAttrs.Stereo(); + break; + + case WX_GL_AUX_BUFFERS: + dispAttrs.AuxBuffers(attribList[src++]); + break; + + case WX_GL_MIN_RED: + minColo[0] = attribList[src++]; + break; + + case WX_GL_MIN_GREEN: + minColo[1] = attribList[src++]; + break; + + case WX_GL_MIN_BLUE: + minColo[2] = attribList[src++]; + break; + + case WX_GL_MIN_ALPHA: + minColo[3] = attribList[src++]; + break; + + case WX_GL_DEPTH_SIZE: + dispAttrs.Depth(attribList[src++]); + break; + + case WX_GL_STENCIL_SIZE: + dispAttrs.Stencil(attribList[src++]); + break; + + case WX_GL_MIN_ACCUM_RED: + minAcum[0] = attribList[src++]; + break; + + case WX_GL_MIN_ACCUM_GREEN: + minAcum[1] = attribList[src++]; + break; + + case WX_GL_MIN_ACCUM_BLUE: + minAcum[2] = attribList[src++]; + break; + + case WX_GL_MIN_ACCUM_ALPHA: + minAcum[3] = attribList[src++]; + break; + + case WX_GL_SAMPLE_BUFFERS: + dispAttrs.SampleBuffers(attribList[src++]); + break; + + case WX_GL_SAMPLES: + dispAttrs.Samplers(attribList[src++]); + break; + + case WX_GL_FRAMEBUFFER_SRGB: + dispAttrs.FrameBuffersRGB(); + break; + + // Context attributes + + case WX_GL_CORE_PROFILE: + if ( ctxAttrs ) + ctxAttrs->CoreProfile(); + break; + + case WX_GL_MAJOR_VERSION: + if ( ctxAttrs ) + ctxAttrs->MajorVersion(attribList[src]); + src++; + break; + + case WX_GL_MINOR_VERSION: + if ( ctxAttrs ) + ctxAttrs->MinorVersion(attribList[src]); + src++; + break; + + case wx_GL_COMPAT_PROFILE: + if ( ctxAttrs ) + ctxAttrs->CompatibilityProfile(); + break; + + case WX_GL_FORWARD_COMPAT: + if ( ctxAttrs ) + ctxAttrs->ForwardCompatible(); + break; + + case WX_GL_ES2: + if ( ctxAttrs ) + ctxAttrs->ES2(); + break; + + case WX_GL_DEBUG: + if ( ctxAttrs ) + ctxAttrs->DebugCtx(); + break; + + case WX_GL_ROBUST_ACCESS: + if ( ctxAttrs ) + ctxAttrs->Robust(); + break; + + case WX_GL_NO_RESET_NOTIFY: + if ( ctxAttrs ) + ctxAttrs->NoResetNotify(); + break; + + case WX_GL_LOSE_ON_RESET: + if ( ctxAttrs ) + ctxAttrs->LoseOnReset(); + break; + + case WX_GL_RESET_ISOLATION: + if ( ctxAttrs ) + ctxAttrs->ResetIsolation(); + break; + + case WX_GL_RELEASE_FLUSH: + if ( ctxAttrs ) + ctxAttrs->ReleaseFlush(1); + break; + + case WX_GL_RELEASE_NONE: + if ( ctxAttrs ) + ctxAttrs->ReleaseFlush(0); + break; + + default: + wxFAIL_MSG("Unexpected value in attributes list"); + return false; + } + } + + // Set color and accumulation + if ( minColo[0] || minColo[1] || minColo[2] || minColo[3] ) + dispAttrs.MinRGBA(minColo[0], minColo[1], minColo[2], minColo[3]); + if ( minAcum[0] || minAcum[1] || minAcum[2] || minAcum[3] ) + dispAttrs.MinAcumRGBA(minAcum[0], minAcum[1], minAcum[2], minAcum[3]); + + // The attributes lists must be zero-terminated + dispAttrs.EndList(); + if ( ctxAttrs ) + ctxAttrs->EndList(); + + return true; +} + // ============================================================================ // compatibility layer for OpenGL 3 and OpenGL ES // ============================================================================ diff --git a/src/gtk/glcanvas.cpp b/src/gtk/glcanvas.cpp index aba6655462..1e68741ca0 100644 --- a/src/gtk/glcanvas.cpp +++ b/src/gtk/glcanvas.cpp @@ -142,6 +142,21 @@ parent_set_hook(GSignalInvocationHint*, guint, const GValue* param_values, void* wxIMPLEMENT_CLASS(wxGLCanvas, wxWindow); +wxGLCanvas::wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const wxPalette& palette) +#if WXWIN_COMPATIBILITY_2_8 + : m_createImplicitContext(false) +#endif +{ + Create(parent, dispAttrs, id, pos, size, style, name, palette); +} + wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, const int *attribList, @@ -216,6 +231,24 @@ bool wxGLCanvas::Create(wxWindow *parent, const wxString& name, const int *attribList, const wxPalette& palette) +{ + // Separate 'GLXFBConfig/XVisual' attributes. + // Also store context attributes for wxGLContext ctor + wxGLAttributes dispAttrs; + if ( ! ParseAttribList(attribList, dispAttrs, &m_GLCTXAttrs) ) + return false; + + return Create(parent, dispAttrs, id, pos, size, style, name, palette); +} + +bool wxGLCanvas::Create(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const wxPalette& palette) { #if wxUSE_PALETTE wxASSERT_MSG( !palette.IsOk(), wxT("palettes not supported") ); @@ -230,7 +263,7 @@ bool wxGLCanvas::Create(wxWindow *parent, m_backgroundStyle = wxBG_STYLE_PAINT; #endif - if ( !InitVisual(attribList) ) + if ( !InitVisual(dispAttrs) ) return false; // watch for the "parent-set" signal on m_wxwindow so we can set colormap diff --git a/src/gtk1/glcanvas.cpp b/src/gtk1/glcanvas.cpp index 971f582f6d..f19df8e0cf 100644 --- a/src/gtk1/glcanvas.cpp +++ b/src/gtk1/glcanvas.cpp @@ -135,6 +135,21 @@ gtk_glcanvas_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, w wxIMPLEMENT_CLASS(wxGLCanvas, wxWindow); +wxGLCanvas::wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const wxPalette& palette) +#if WXWIN_COMPATIBILITY_2_8 + : m_createImplicitContext(false) +#endif +{ + Create(parent, dispAttrs, id, pos, size, style, name, palette); +} + wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, const int *attribList, @@ -206,10 +221,29 @@ bool wxGLCanvas::Create(wxWindow *parent, const int *attribList, const wxPalette& palette) { + // Separate 'GLXFBConfig/XVisual' attributes. + // Also store context attributes for wxGLContext ctor + wxGLAttributes dispAttrs; + if ( ! ParseAttribList(attribList, dispAttrs, &m_GLCTXAttrs) ) + return false; + + return Create(parent, dispAttrs, id, pos, size, style, name, palette); +} + +bool wxGLCanvas::Create(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const wxPalette& palette) +{ + m_noExpose = true; m_nativeSizeEvent = true; - if ( !InitVisual(attribList) ) + if ( !InitVisual(dispAttrs) ) return false; GdkVisual *visual = gdkx_visual_get( GetXVisualInfo()->visualid ); diff --git a/src/msw/glcanvas.cpp b/src/msw/glcanvas.cpp index 017d49f9ed..5863b71270 100644 --- a/src/msw/glcanvas.cpp +++ b/src/msw/glcanvas.cpp @@ -49,18 +49,27 @@ wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); // ---------------------------------------------------------------------------- #ifndef WGL_ARB_pixel_format +#define WGL_ARB_pixel_format #define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_DRAW_TO_BITMAP_ARB 0x2002 #define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NEED_PALETTE_ARB 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SWAP_METHOD_ARB 0x2007 #define WGL_NUMBER_OVERLAYS_ARB 0x2008 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define WGL_SUPPORT_GDI_ARB 0x200F #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DOUBLE_BUFFER_ARB 0x2011 #define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 #define WGL_COLOR_BITS_ARB 0x2014 #define WGL_RED_BITS_ARB 0x2015 #define WGL_GREEN_BITS_ARB 0x2017 #define WGL_BLUE_BITS_ARB 0x2019 #define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ACCUM_BITS_ARB 0x201D #define WGL_ACCUM_RED_BITS_ARB 0x201E #define WGL_ACCUM_GREEN_BITS_ARB 0x201F #define WGL_ACCUM_BLUE_BITS_ARB 0x2020 @@ -68,14 +77,26 @@ wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #define WGL_DEPTH_BITS_ARB 0x2022 #define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 #define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_SWAP_COPY_ARB 0x2029 +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C #endif #ifndef WGL_ARB_multisample +#define WGL_ARB_multisample #define WGL_SAMPLE_BUFFERS_ARB 0x2041 #define WGL_SAMPLES_ARB 0x2042 #endif +#ifndef WGL_ARB_framebuffer_sRGB +#define WGL_ARB_framebuffer_sRGB +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 +#endif + #ifndef WGL_ARB_create_context #define WGL_ARB_create_context #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 @@ -84,6 +105,7 @@ wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#endif #ifndef WGL_ARB_create_context_profile #define WGL_ARB_create_context_profile @@ -99,6 +121,20 @@ wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 #define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 #endif + +#ifndef WGL_ARB_robustness_application_isolation +#define WGL_ARB_robustness_application_isolation +#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 +#endif +#ifndef WGL_ARB_robustness_share_group_isolation +#define WGL_ARB_robustness_share_group_isolation +#endif + +#ifndef WGL_ARB_context_flush_control +#define WGL_ARB_context_flush_control +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 #endif #ifndef WGL_EXT_create_context_es2_profile @@ -111,11 +147,6 @@ wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); #define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 #endif -#ifndef WGL_ARB_framebuffer_sRGB -#define WGL_ARB_framebuffer_sRGB -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 -#endif - typedef HGLRC(WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); @@ -145,58 +176,439 @@ typedef HGLRC(WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) # pragma comment( lib, "glu32" ) #endif +//----------------------------------------------------------------------------- +// Documentation on internals +//----------------------------------------------------------------------------- + +// OpenGL has evolved not only adding new features, but also there are new +// ways of doing things. Among these new ways, we pay special attention to +// pixel format choosing and context creation. +// +// The old way of choosing a pixel format is to use a PIXELFORMATDESCRIPTOR +// struct for setting the wanted attributes and to call ChoosePixelFormat() +// with that struct. +// When new attributes came into scene, the MSW struct became inadequate, and +// a new method was implemented: wglChoosePixelFormatARB(). +// +// For rendering context creation wglCreateContext() was the function to call. +// Starting with OpenGL 3.0 (2009) there are several attributes for context, +// specially for wanted version and "core" or "compatibility" profiles. +// In order to use these new features, wglCreateContextAttribsARB() must be +// called instead of wglCreateContext(). +// +// wxWidgets handles this OpenGL evolution trying to use the new ways, and +// falling back to the old ways if neither the latter are available nor the +// user requires them. +// +// wxGLAttributes is used for pixel format attributes. +// wxGLContextAttrs is used for OpenGL rendering context attributes. +// wxWidgets does not handle all of OpenGL attributes. This is because some of +// them are platform-dependent, or perhaps too new for wx. To cope with these +// cases, these two objects allow the user to set his own attributes. +// +// To keep wxWidgets backwards compatibility, a list of mixed attributes is +// still allowed at wxGLCanvas constructor. + + +// ---------------------------------------------------------------------------- +// wxGLContextAttrs: OpenGL rendering context attributes +// ---------------------------------------------------------------------------- +// MSW specific values + +wxGLContextAttrs& wxGLContextAttrs::CoreProfile() +{ + AddAttribBits(WGL_CONTEXT_PROFILE_MASK_ARB, + WGL_CONTEXT_CORE_PROFILE_BIT_ARB); + SetNeedsARB(); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::MajorVersion(int val) +{ + if ( val > 0 ) + { + AddAttribute(WGL_CONTEXT_MAJOR_VERSION_ARB); + AddAttribute(val); + if ( val >= 3 ) + SetNeedsARB(); + } + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::MinorVersion(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WGL_CONTEXT_MINOR_VERSION_ARB); + AddAttribute(val); + } + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile() +{ + AddAttribBits(WGL_CONTEXT_PROFILE_MASK_ARB, + WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); + SetNeedsARB(); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ForwardCompatible() +{ + AddAttribBits(WGL_CONTEXT_FLAGS_ARB, + WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB); + SetNeedsARB(); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ES2() +{ + AddAttribBits(WGL_CONTEXT_PROFILE_MASK_ARB, + WGL_CONTEXT_ES2_PROFILE_BIT_EXT); + SetNeedsARB(); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::DebugCtx() +{ + AddAttribBits(WGL_CONTEXT_FLAGS_ARB, + WGL_CONTEXT_DEBUG_BIT_ARB); + SetNeedsARB(); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::Robust() +{ + AddAttribBits(WGL_CONTEXT_FLAGS_ARB, + WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB); + SetNeedsARB(); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::NoResetNotify() +{ + AddAttribute(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); + AddAttribute(WGL_NO_RESET_NOTIFICATION_ARB); + SetNeedsARB(); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::LoseOnReset() +{ + AddAttribute(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); + AddAttribute(WGL_LOSE_CONTEXT_ON_RESET_ARB); + SetNeedsARB(); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ResetIsolation() +{ + AddAttribBits(WGL_CONTEXT_FLAGS_ARB, + WGL_CONTEXT_RESET_ISOLATION_BIT_ARB); + SetNeedsARB(); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ReleaseFlush(int val) +{ + AddAttribute(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB); + if ( val == 1 ) + AddAttribute(WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + else + AddAttribute(WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + SetNeedsARB(); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::PlatformDefaults() +{ + // No MSW specific defaults + return *this; +} + +void wxGLContextAttrs::EndList() +{ + AddAttribute(0); +} + +// ---------------------------------------------------------------------------- +// wxGLAttributes: pixel format attributes +// ---------------------------------------------------------------------------- +// MSW specific values + +wxGLAttributes& wxGLAttributes::RGBA() +{ + AddAttribute(WGL_PIXEL_TYPE_ARB); + AddAttribute(WGL_TYPE_RGBA_ARB); + AddAttribute(WGL_COLOR_BITS_ARB); + AddAttribute(24); + AddAttribute(WGL_ALPHA_BITS_ARB); + AddAttribute(8); + return *this; +} + +wxGLAttributes& wxGLAttributes::BufferSize(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WGL_COLOR_BITS_ARB); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Level(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WGL_NUMBER_OVERLAYS_ARB); + AddAttribute(val); + } + else if ( val < 0 ) + { + AddAttribute(WGL_NUMBER_UNDERLAYS_ARB); + AddAttribute(-val); + } + if ( val < -1 || val > 1 ) + { + SetNeedsARB(); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::DoubleBuffer() +{ + AddAttribute(WGL_DOUBLE_BUFFER_ARB); + AddAttribute(GL_TRUE); + return *this; +} + +wxGLAttributes& wxGLAttributes::Stereo() +{ + AddAttribute(WGL_STEREO_ARB); + AddAttribute(GL_TRUE); + return *this; +} + +wxGLAttributes& wxGLAttributes::AuxBuffers(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WGL_AUX_BUFFERS_ARB); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::MinRGBA(int mRed, int mGreen, int mBlue, int mAlpha) +{ + int colorBits = 0; + if ( mRed >= 0) + { + AddAttribute(WGL_RED_BITS_ARB); + AddAttribute(mRed); + colorBits += mRed; + } + if ( mGreen >= 0) + { + AddAttribute(WGL_GREEN_BITS_ARB); + AddAttribute(mGreen); + colorBits += mGreen; + } + if ( mBlue >= 0) + { + AddAttribute(WGL_BLUE_BITS_ARB); + AddAttribute(mBlue); + colorBits += mBlue; + } + if ( mAlpha >= 0) + { + AddAttribute(WGL_ALPHA_BITS_ARB); + AddAttribute(mAlpha); + // doesn't count in colorBits + } + if ( colorBits ) + { + AddAttribute(WGL_COLOR_BITS_ARB); + AddAttribute(colorBits); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Depth(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WGL_DEPTH_BITS_ARB); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Stencil(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WGL_STENCIL_BITS_ARB); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::MinAcumRGBA(int mRed, int mGreen, int mBlue, int mAlpha) +{ + int acumBits = 0; + if ( mRed >= 0) + { + AddAttribute(WGL_ACCUM_RED_BITS_ARB); + AddAttribute(mRed); + acumBits += mRed; + } + if ( mGreen >= 0) + { + AddAttribute(WGL_ACCUM_GREEN_BITS_ARB); + AddAttribute(mGreen); + acumBits += mGreen; + } + if ( mBlue >= 0) + { + AddAttribute(WGL_ACCUM_BLUE_BITS_ARB); + AddAttribute(mBlue); + acumBits += mBlue; + } + if ( mAlpha >= 0) + { + AddAttribute(WGL_ACCUM_ALPHA_BITS_ARB); + AddAttribute(mAlpha); + acumBits += mAlpha; + } + if ( acumBits ) + { + AddAttribute(WGL_ACCUM_BITS_ARB); + AddAttribute(acumBits); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::SampleBuffers(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WGL_SAMPLE_BUFFERS_ARB); + AddAttribute(val); + SetNeedsARB(); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Samplers(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WGL_SAMPLES_ARB); + AddAttribute(val); + SetNeedsARB(); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::FrameBuffersRGB() +{ + AddAttribute(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); + AddAttribute(GL_TRUE); + SetNeedsARB(); + return *this; +} + +void wxGLAttributes::EndList() +{ + AddAttribute(0); +} + +wxGLAttributes& wxGLAttributes::PlatformDefaults() +{ + AddAttribute(WGL_DRAW_TO_WINDOW_ARB); + AddAttribute(GL_TRUE); + AddAttribute(WGL_SUPPORT_OPENGL_ARB); + AddAttribute(GL_TRUE); + AddAttribute(WGL_ACCELERATION_ARB); + AddAttribute(WGL_FULL_ACCELERATION_ARB); + return *this; +} + +wxGLAttributes& wxGLAttributes::Defaults() +{ + RGBA().Depth(16).DoubleBuffer().SampleBuffers(1).Samplers(4); + SetNeedsARB(); + return *this; +} + // ---------------------------------------------------------------------------- // wxGLContext // ---------------------------------------------------------------------------- wxIMPLEMENT_CLASS(wxGLContext, wxObject); -// The window will always be created first so the array will be initialized -// and then the window will be assigned to the context. -// max 8 attributes plus terminator -// if first is 0, create legacy context -static int s_wglContextAttribs[9] = {0}; - -wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext* other) +wxGLContext::wxGLContext(wxGLCanvas *win, + const wxGLContext *other, + const wxGLContextAttrs *ctxAttrs) { - if ( s_wglContextAttribs[0] == 0 ) // create legacy context - { - m_glContext = wglCreateContext(win->GetHDC()); - wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGL context") ); - } - else // create a context using attributes - { - // We need to create a temporary context to get the - // wglCreateContextAttribsARB function - HGLRC tempContext = wglCreateContext(win->GetHDC()); - wxCHECK_RET( tempContext, wxT("Couldn't create OpenGL context") ); + const int* contextAttribs = NULL; + bool needsARB = false; - wglMakeCurrent(win->GetHDC(), tempContext); - PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB + if ( ctxAttrs ) + { + contextAttribs = ctxAttrs->GetGLAttrs(); + needsARB = ctxAttrs->NeedsARB(); + } + else if ( win->GetGLCTXAttrs().GetGLAttrs() ) + { + // If OpenGL context parameters were set at wxGLCanvas ctor, get them now + contextAttribs = win->GetGLCTXAttrs().GetGLAttrs(); + needsARB = win->GetGLCTXAttrs().NeedsARB(); + } + // else use GPU driver defaults + + m_isOk = false; + + // We need to create a temporary context to get the pointer to + // wglCreateContextAttribsARB function + HGLRC tempContext = wglCreateContext(win->GetHDC()); + wxCHECK_RET( tempContext, "wglCreateContext failed!" ); + + wglMakeCurrent(win->GetHDC(), tempContext); + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress("wglCreateContextAttribsARB"); - wglMakeCurrent(win->GetHDC(), NULL); - wglDeleteContext(tempContext); + wglMakeCurrent(win->GetHDC(), NULL); + wglDeleteContext(tempContext); - if ( !wglCreateContextAttribsARB ) - { - wxLogError(_("Core OpenGL profile is not supported by the OpenGL driver.")); - return; - } - - m_glContext = wglCreateContextAttribsARB( - win->GetHDC(), 0, s_wglContextAttribs); - wxCHECK_RET( m_glContext, - wxT("Couldn't create core profile OpenGL context") ); - } - - if ( other ) + // The preferred way is using wglCreateContextAttribsARB, even for old context + if ( !wglCreateContextAttribsARB && needsARB ) // OpenGL 3 context creation { - if ( !wglShareLists(other->m_glContext, m_glContext) ) - { - wxLogLastError(wxT("wglShareLists")); - } + wxLogMessage(_("OpenGL 3.0 or later is not supported by the OpenGL driver.")); + return; } + + if ( wglCreateContextAttribsARB ) + { + m_glContext = wglCreateContextAttribsARB(win->GetHDC(), + other ? other->m_glContext : 0, + contextAttribs); + } + else + { + // Create legacy context + m_glContext = wglCreateContext(win->GetHDC()); + // Set shared context + if ( other && !wglShareLists(other->m_glContext, m_glContext) ) + wxLogLastError("wglShareLists"); + } + + if ( !m_glContext ) + wxLogMessage(_("Couldn't create OpenGL context")); + else + m_isOk = true; } wxGLContext::~wxGLContext() @@ -232,8 +644,6 @@ wxEND_EVENT_TABLE() // wxGLCanvas construction // ---------------------------------------------------------------------------- -static int ChoosePixelFormatARB(HDC hdc, const int *attribList); - void wxGLCanvas::Init() { #if WXWIN_COMPATIBILITY_2_8 @@ -242,6 +652,20 @@ void wxGLCanvas::Init() m_hDC = NULL; } +wxGLCanvas::wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const wxPalette& palette) +{ + Init(); + + (void)Create(parent, dispAttrs, id, pos, size, style, name, palette); +} + wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, const int *attribList, @@ -306,111 +730,50 @@ bool wxGLCanvas::Create(wxWindow *parent, const wxString& name, const int *attribList, const wxPalette& palette) +{ + // Separate 'pixel format' attributes. + // Also store context attributes for wxGLContext ctor + wxGLAttributes dispAttrs; + if ( ! ParseAttribList(attribList, dispAttrs, &m_GLCTXAttrs) ) + return false; + + return Create(parent, dispAttrs, id, pos, size, style, name, palette); +} + +bool wxGLCanvas::Create(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const wxPalette& palette) { // Create the window first: we will either use it as is or use it to query // for multisampling support and recreate it later with another pixel format if ( !CreateWindow(parent, id, pos, size, style, name) ) return false; - // these will be used for the context creation attributes - // if a core profile is requested - bool useGLCoreProfile = false; - - // the minimum gl core version is 3.0 - int glVersionMajor = 3, - glVersionMinor = 0; - - // Check for a core profile request - if ( attribList ) - { - for ( int i = 0; attribList[i]; ) - { - switch ( attribList[i++] ) - { - case WX_GL_CORE_PROFILE: - useGLCoreProfile = true; - break; - - case WX_GL_MAJOR_VERSION: - glVersionMajor = attribList[i++]; - break; - - case WX_GL_MINOR_VERSION: - glVersionMinor = attribList[i++]; - break; - - default: - // ignore all other flags for now - break; - } - } - } - - if ( useGLCoreProfile ) - { - s_wglContextAttribs[0] = WGL_CONTEXT_MAJOR_VERSION_ARB; - s_wglContextAttribs[1] = glVersionMajor; - s_wglContextAttribs[2] = WGL_CONTEXT_MINOR_VERSION_ARB; - s_wglContextAttribs[3] = glVersionMinor; - s_wglContextAttribs[4] = WGL_CONTEXT_FLAGS_ARB; - s_wglContextAttribs[5] = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; - s_wglContextAttribs[6] = WGL_CONTEXT_PROFILE_MASK_ARB; - s_wglContextAttribs[7] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; - s_wglContextAttribs[8] = 0; // terminate - } - else // create legacy/compatibility context - { - s_wglContextAttribs[0] = 0; - } - - + // Choose a matching pixel format. + // Need a PIXELFORMATDESCRIPTOR for SetPixelFormat() PIXELFORMATDESCRIPTOR pfd; - const int setupVal = DoSetup(pfd, attribList); - if ( setupVal == 0 ) // PixelFormat error - return false; - - if ( setupVal == -1 ) // FSAA requested + int pixelFormat = FindMatchingPixelFormat(dispAttrs, &pfd); + if ( !pixelFormat ) { - // now that we have a valid OpenGL window, query it for FSAA support - int pixelFormat; - { - wxGLContext ctx(this); - ctx.SetCurrent(*this); - pixelFormat = ::ChoosePixelFormatARB(m_hDC, attribList); - } + wxFAIL_MSG("Can't find a pixel format for the requested attributes"); + return false; + } - if ( pixelFormat > 0 ) - { - // from http://msdn.microsoft.com/en-us/library/ms537559(VS.85).aspx: - // - // Setting the pixel format of a window more than once can - // lead to significant complications for the Window Manager - // and for multithread applications, so it is not allowed. An - // application can only set the pixel format of a window one - // time. Once a window's pixel format is set, it cannot be - // changed. - // - // so we need to delete the old window and create the new one - - // destroy Window - ::ReleaseDC(GetHwnd(), m_hDC); - m_hDC = 0; - - parent->RemoveChild(this); - const HWND hwnd = GetHwnd(); - DissociateHandle(); // will do SetHWND(0); - ::DestroyWindow(hwnd); - - // now recreate with FSAA pixelFormat - if ( !CreateWindow(parent, id, pos, size, style, name) ) - return false; - - if ( !::SetPixelFormat(m_hDC, pixelFormat, &pfd) ) - { - wxLogLastError(wxT("SetPixelFormat")); - return false; - } - } + // From SetPixelFormat() docs, relating pfd parameter: + // https://msdn.microsoft.com/en-us/library/dd369049%28v=vs.85%29.aspx + // "The system's metafile component uses this structure to record the + // logical pixel format specification." + // If anybody understands this sentence, please explain. + // Pass pfd just in case it's somehow needed. Passing NULL also works here. + if ( !::SetPixelFormat(m_hDC, pixelFormat, &pfd) ) + { + wxLogLastError("SetPixelFormat"); + return false; } #if wxUSE_PALETTE @@ -439,10 +802,6 @@ bool wxGLCanvas::SwapBuffers() } -// ---------------------------------------------------------------------------- -// multi sample support -// ---------------------------------------------------------------------------- - // this macro defines a variable of type "name_t" called "name" and initializes // it with the pointer to WGL function "name" (which may be NULL) #define wxDEFINE_WGL_FUNC(name) \ @@ -480,12 +839,228 @@ bool wxGLCanvasBase::IsExtensionSupported(const char *extension) return s_extensionsList && IsExtensionInList(s_extensionsList, extension); } -// this is a wrapper around wglChoosePixelFormatARB(): returns the pixel format -// index matching the given attributes on success or 0 on failure -static int ChoosePixelFormatARB(HDC hdc, const int *attribList) +// ---------------------------------------------------------------------------- +// pixel format stuff +// ---------------------------------------------------------------------------- + +// A dummy window, needed at FindMatchingPixelFormat() +class WXDLLIMPEXP_GL wxGLdummyWin : public wxWindow { - if ( !wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample") ) +public: + wxGLdummyWin() + { + hdc = 0; + CreateBase(NULL, wxID_ANY); + DWORD msflags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + if( MSWCreate(wxApp::GetRegisteredClassName(wxT("wxGLCanvas"), -1, CS_OWNDC), + NULL, wxDefaultPosition, wxDefaultSize, msflags, 0) ) + { + hdc = ::GetDC(GetHwnd()); + } + } + ~wxGLdummyWin() + { + if ( hdc ) + ::ReleaseDC(GetHwnd(), hdc); + } + HDC hdc; +}; + +// Fills PIXELFORMATDESCRIPTOR struct +static void SetPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, const int* attrsListWGL) +{ + // Some defaults + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.iLayerType = PFD_MAIN_PLANE; // For very early MSW OpenGL + + // We can meet some WGL_XX values not managed by wx. But the user + // may require them. Allow here those that are also used for pfd. + // Color shift and transparency are not handled. + for ( int arg = 0; attrsListWGL[arg]; ) + { + switch ( attrsListWGL[arg++] ) + { + case WGL_DRAW_TO_WINDOW_ARB: + if ( attrsListWGL[arg++] ) + pfd.dwFlags |= PFD_DRAW_TO_WINDOW; + break; + + case WGL_DRAW_TO_BITMAP_ARB: + if ( attrsListWGL[arg++] ) + pfd.dwFlags |= PFD_DRAW_TO_BITMAP; + break; + + case WGL_ACCELERATION_ARB: + if ( attrsListWGL[arg++] == WGL_GENERIC_ACCELERATION_ARB ) + pfd.dwFlags |= PFD_GENERIC_ACCELERATED; + break; + + case WGL_NEED_PALETTE_ARB: + if ( attrsListWGL[arg++] ) + pfd.dwFlags |= PFD_NEED_PALETTE; + break; + + case WGL_NEED_SYSTEM_PALETTE_ARB: + if ( attrsListWGL[arg++] ) + pfd.dwFlags |= PFD_NEED_SYSTEM_PALETTE; + break; + + case WGL_SWAP_LAYER_BUFFERS_ARB: + if ( attrsListWGL[arg++] ) + pfd.dwFlags |= PFD_SWAP_LAYER_BUFFERS; + break; + + case WGL_SWAP_METHOD_ARB: + if ( attrsListWGL[arg++] == WGL_SWAP_EXCHANGE_ARB ) + pfd.dwFlags |= PFD_SWAP_EXCHANGE; + else if ( attrsListWGL[arg] == WGL_SWAP_COPY_ARB ) + pfd.dwFlags |= PFD_SWAP_COPY; + break; + + case WGL_NUMBER_OVERLAYS_ARB: + pfd.bReserved &= 240; + pfd.bReserved |= attrsListWGL[arg++] & 15; + break; + + case WGL_NUMBER_UNDERLAYS_ARB: + pfd.bReserved &= 15; + pfd.bReserved |= attrsListWGL[arg++] & 240; + break; + + case WGL_SUPPORT_GDI_ARB: + if ( attrsListWGL[arg++] ) + pfd.dwFlags |= PFD_SUPPORT_GDI; + break; + + case WGL_SUPPORT_OPENGL_ARB: + if ( attrsListWGL[arg++] ) + pfd.dwFlags |= PFD_SUPPORT_OPENGL; + break; + + case WGL_DOUBLE_BUFFER_ARB: + if ( attrsListWGL[arg++] ) + pfd.dwFlags |= PFD_DOUBLEBUFFER; + break; + + case WGL_STEREO_ARB: + if ( attrsListWGL[arg++] ) + pfd.dwFlags |= PFD_STEREO; + break; + + case WGL_PIXEL_TYPE_ARB: + if ( attrsListWGL[arg++] == WGL_TYPE_RGBA_ARB ) + pfd.iPixelType = PFD_TYPE_RGBA; + else + pfd.iPixelType = PFD_TYPE_COLORINDEX; + break; + + case WGL_COLOR_BITS_ARB: + pfd.cColorBits = attrsListWGL[arg++]; + break; + + case WGL_RED_BITS_ARB: + pfd.cRedBits = attrsListWGL[arg++]; + break; + + case WGL_GREEN_BITS_ARB: + pfd.cGreenBits = attrsListWGL[arg++]; + break; + + case WGL_BLUE_BITS_ARB: + pfd.cBlueBits = attrsListWGL[arg++]; + break; + + case WGL_ALPHA_BITS_ARB: + pfd.cAlphaBits = attrsListWGL[arg++]; + break; + + case WGL_ACCUM_BITS_ARB: + pfd.cAccumBits = attrsListWGL[arg++]; + break; + + case WGL_ACCUM_RED_BITS_ARB: + pfd.cAccumRedBits = attrsListWGL[arg++]; + break; + + case WGL_ACCUM_GREEN_BITS_ARB: + pfd.cAccumGreenBits = attrsListWGL[arg++]; + break; + + case WGL_ACCUM_BLUE_BITS_ARB: + pfd.cAccumBlueBits = attrsListWGL[arg++]; + break; + + case WGL_ACCUM_ALPHA_BITS_ARB: + pfd.cAccumAlphaBits = attrsListWGL[arg++]; + break; + + case WGL_DEPTH_BITS_ARB: + pfd.cDepthBits = attrsListWGL[arg++]; + break; + + case WGL_STENCIL_BITS_ARB: + pfd.cStencilBits = attrsListWGL[arg++]; + break; + + case WGL_AUX_BUFFERS_ARB: + pfd.cAuxBuffers = attrsListWGL[arg++]; + break; + + default: + // ignore + break; + } + } +} + +/* static */ +int wxGLCanvas::FindMatchingPixelFormat(const wxGLAttributes& dispAttrs, + PIXELFORMATDESCRIPTOR* ppfd) +{ + // WGL_XX attributes + const int* attrsListWGL = dispAttrs.GetGLAttrs(); + if ( !attrsListWGL ) + { + wxFAIL_MSG("wxGLAttributes object is empty."); return 0; + } + + // The preferred way is using wglChoosePixelFormatARB. This is not a MSW + // function, we must ask the GPU driver for a pointer to it. We need a + // rendering context for this operation. Create a dummy one. + // Notice that we don't create a wxGLContext on purpose. + // We meet another issue: + // Before creating any context, we must set a pixel format for its hdc: + // https://msdn.microsoft.com/en-us/library/dd374379%28v=vs.85%29.aspx + // but we can't set a pixel format more than once: + // https://msdn.microsoft.com/en-us/library/dd369049%28v=vs.85%29.aspx + // To cope with this we need a dummy hidden window. + // + // Having this dummy window allows also calling IsDisplaySupported() + // without creating a wxGLCanvas. + wxGLdummyWin* dummyWin = new wxGLdummyWin(); + HDC dummyHDC = dummyWin->hdc; + if ( !dummyHDC ) + { + dummyWin->Destroy(); + wxFAIL_MSG("Can't create dummy window"); + return 0; + } + // Dummy context + PIXELFORMATDESCRIPTOR dpfd; //any one is valid + ::SetPixelFormat(dummyHDC, 1, &dpfd); // pixelformat=1, any one is valid + HGLRC dumctx = ::wglCreateContext(dummyHDC); + if ( !dumctx ) + { + dummyWin->Destroy(); + // A fatal error! + wxFAIL_MSG("wglCreateContext failed!"); + return 0; + } + + ::wglMakeCurrent(dummyHDC, dumctx); typedef BOOL (WINAPI * wglChoosePixelFormatARB_t) (HDC hdc, @@ -496,256 +1071,74 @@ static int ChoosePixelFormatARB(HDC hdc, const int *attribList) UINT *nNumFormats ); - wxDEFINE_WGL_FUNC(wglChoosePixelFormatARB); - if ( !wglChoosePixelFormatARB ) - return 0; // should not occur if extension is supported + wxDEFINE_WGL_FUNC(wglChoosePixelFormatARB); // get a pointer to it - int iAttributes[128]; - int dst = 0; // index in iAttributes array - - #define ADD_ATTR(attr, value) \ - iAttributes[dst++] = attr; iAttributes[dst++] = value - - ADD_ATTR( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE ); - ADD_ATTR( WGL_SUPPORT_OPENGL_ARB, GL_TRUE ); - ADD_ATTR( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB ); - - if ( !attribList ) + // If wglChoosePixelFormatARB is not supported but the attributes require + // it, then fail. + if ( !wglChoosePixelFormatARB && dispAttrs.NeedsARB() ) { - ADD_ATTR( WGL_COLOR_BITS_ARB, 24 ); - ADD_ATTR( WGL_ALPHA_BITS_ARB, 8 ); - ADD_ATTR( WGL_DEPTH_BITS_ARB, 16 ); - ADD_ATTR( WGL_STENCIL_BITS_ARB, 0 ); - ADD_ATTR( WGL_DOUBLE_BUFFER_ARB, GL_TRUE ); - ADD_ATTR( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE ); - ADD_ATTR( WGL_SAMPLES_ARB, 4 ); - } - else // have custom attributes - { - #define ADD_ATTR_VALUE(attr) ADD_ATTR(attr, attribList[src++]) - - int src = 0; - while ( attribList[src] ) - { - switch ( attribList[src++] ) - { - case WX_GL_RGBA: - ADD_ATTR( WGL_COLOR_BITS_ARB, 24 ); - ADD_ATTR( WGL_ALPHA_BITS_ARB, 8 ); - break; - - case WX_GL_BUFFER_SIZE: - ADD_ATTR_VALUE( WGL_COLOR_BITS_ARB); - break; - - case WX_GL_LEVEL: - if ( attribList[src] > 0 ) - { - ADD_ATTR( WGL_NUMBER_OVERLAYS_ARB, 1 ); - } - else if ( attribList[src] <0 ) - { - ADD_ATTR( WGL_NUMBER_UNDERLAYS_ARB, 1 ); - } - //else: ignore it - - src++; // skip the value in any case - break; - - case WX_GL_DOUBLEBUFFER: - ADD_ATTR( WGL_DOUBLE_BUFFER_ARB, GL_TRUE ); - break; - - case WX_GL_STEREO: - ADD_ATTR( WGL_STEREO_ARB, GL_TRUE ); - break; - - case WX_GL_AUX_BUFFERS: - ADD_ATTR_VALUE( WGL_AUX_BUFFERS_ARB ); - break; - - case WX_GL_MIN_RED: - ADD_ATTR_VALUE( WGL_RED_BITS_ARB ); - break; - - case WX_GL_MIN_GREEN: - ADD_ATTR_VALUE( WGL_GREEN_BITS_ARB ); - break; - - case WX_GL_MIN_BLUE: - ADD_ATTR_VALUE( WGL_BLUE_BITS_ARB ); - break; - - case WX_GL_MIN_ALPHA: - ADD_ATTR_VALUE( WGL_ALPHA_BITS_ARB ); - break; - - case WX_GL_DEPTH_SIZE: - ADD_ATTR_VALUE( WGL_DEPTH_BITS_ARB ); - break; - - case WX_GL_STENCIL_SIZE: - ADD_ATTR_VALUE( WGL_STENCIL_BITS_ARB ); - break; - - case WX_GL_MIN_ACCUM_RED: - ADD_ATTR_VALUE( WGL_ACCUM_RED_BITS_ARB ); - break; - - case WX_GL_MIN_ACCUM_GREEN: - ADD_ATTR_VALUE( WGL_ACCUM_GREEN_BITS_ARB ); - break; - - case WX_GL_MIN_ACCUM_BLUE: - ADD_ATTR_VALUE( WGL_ACCUM_BLUE_BITS_ARB ); - break; - - case WX_GL_MIN_ACCUM_ALPHA: - ADD_ATTR_VALUE( WGL_ACCUM_ALPHA_BITS_ARB ); - break; - - case WX_GL_SAMPLE_BUFFERS: - ADD_ATTR_VALUE( WGL_SAMPLE_BUFFERS_ARB ); - break; - - case WX_GL_SAMPLES: - ADD_ATTR_VALUE( WGL_SAMPLES_ARB ); - break; - } - } - - #undef ADD_ATTR_VALUE - } - - #undef ADD_ATTR - - iAttributes[dst++] = 0; - - int pf; - UINT numFormats = 0; - - if ( !wglChoosePixelFormatARB(hdc, iAttributes, NULL, 1, &pf, &numFormats) ) - { - wxLogLastError(wxT("wglChoosePixelFormatARB")); + wxLogLastError("wglChoosePixelFormatARB unavailable"); + // Delete the dummy objects + ::wglMakeCurrent(NULL, NULL); + ::wglDeleteContext(dumctx); + dummyWin->Destroy(); return 0; } - // Although TRUE is returned if no matching formats are found (see - // http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt), pf is - // not initialized in this case so we need to check for numFormats being - // not 0 explicitly (however this is not an error so don't call - // wxLogLastError() here). - if ( !numFormats ) - pf = 0; + int pixelFormat = 0; - return pf; -} - -// ---------------------------------------------------------------------------- -// pixel format stuff -// ---------------------------------------------------------------------------- - -// returns true if pfd was adjusted accordingly to attributes provided, false -// if there is an error with attributes or -1 if the attributes indicate -// features not supported by ChoosePixelFormat() at all (currently only multi -// sampling) -static int -AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, const int *attribList) -{ - if ( !attribList ) - return 1; - - // remove default attributes - pfd.dwFlags &= ~PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_COLORINDEX; - - bool requestFSAA = false; - for ( int arg = 0; attribList[arg]; ) + if ( !wglChoosePixelFormatARB && !dispAttrs.NeedsARB() ) { - switch ( attribList[arg++] ) + // Old way + if ( !ppfd ) { - case WX_GL_RGBA: - pfd.iPixelType = PFD_TYPE_RGBA; - break; - - case WX_GL_BUFFER_SIZE: - pfd.cColorBits = attribList[arg++]; - break; - - case WX_GL_LEVEL: - // this member looks like it may be obsolete - if ( attribList[arg] > 0 ) - pfd.iLayerType = PFD_OVERLAY_PLANE; - else if ( attribList[arg] < 0 ) - pfd.iLayerType = (BYTE)PFD_UNDERLAY_PLANE; - else - pfd.iLayerType = PFD_MAIN_PLANE; - arg++; - break; - - case WX_GL_DOUBLEBUFFER: - pfd.dwFlags |= PFD_DOUBLEBUFFER; - break; - - case WX_GL_STEREO: - pfd.dwFlags |= PFD_STEREO; - break; - - case WX_GL_AUX_BUFFERS: - pfd.cAuxBuffers = attribList[arg++]; - break; - - case WX_GL_MIN_RED: - pfd.cColorBits += (pfd.cRedBits = attribList[arg++]); - break; - - case WX_GL_MIN_GREEN: - pfd.cColorBits += (pfd.cGreenBits = attribList[arg++]); - break; - - case WX_GL_MIN_BLUE: - pfd.cColorBits += (pfd.cBlueBits = attribList[arg++]); - break; - - case WX_GL_MIN_ALPHA: - // doesn't count in cColorBits - pfd.cAlphaBits = attribList[arg++]; - break; - - case WX_GL_DEPTH_SIZE: - pfd.cDepthBits = attribList[arg++]; - break; - - case WX_GL_STENCIL_SIZE: - pfd.cStencilBits = attribList[arg++]; - break; - - case WX_GL_MIN_ACCUM_RED: - pfd.cAccumBits += (pfd.cAccumRedBits = attribList[arg++]); - break; - - case WX_GL_MIN_ACCUM_GREEN: - pfd.cAccumBits += (pfd.cAccumGreenBits = attribList[arg++]); - break; - - case WX_GL_MIN_ACCUM_BLUE: - pfd.cAccumBits += (pfd.cAccumBlueBits = attribList[arg++]); - break; - - case WX_GL_MIN_ACCUM_ALPHA: - pfd.cAccumBits += (pfd.cAccumAlphaBits = attribList[arg++]); - break; - - case WX_GL_SAMPLE_BUFFERS: - case WX_GL_SAMPLES: - // There is no support for multisample when using PIXELFORMATDESCRIPTOR - requestFSAA = true; // Remember that multi sample is requested. - arg++; // will call ChoosePixelFormatARB() later - break; + // We have been called from IsDisplaySupported() + PIXELFORMATDESCRIPTOR pfd; + SetPFDForAttributes(pfd, attrsListWGL); + pixelFormat = ::ChoosePixelFormat(dummyHDC, &pfd); } + else + { + SetPFDForAttributes(*ppfd, attrsListWGL); + pixelFormat = ::ChoosePixelFormat(dummyHDC, ppfd); + } + // We should ensure that we have got what we have asked for. This can + // be done using DescribePixelFormat() and comparing attributes. + // Nevertheless wglChoosePixelFormatARB exists since 2001, so it's + // very unlikely that ChoosePixelFormat() is used. So, do nothing. + } + else + { + // New way, using wglChoosePixelFormatARB + // 'ppfd' is used at wxGLCanvas::Create(). See explanations there. + if ( ppfd ) + SetPFDForAttributes(*ppfd, attrsListWGL); + + UINT numFormats = 0; + + // Get the first good match + if ( !wglChoosePixelFormatARB(dummyHDC, attrsListWGL, NULL, + 1, &pixelFormat, &numFormats) ) + { + wxLogLastError("wglChoosePixelFormatARB. Is the list zero-terminated?"); + numFormats = 0; + } + + // Although TRUE is returned if no matching formats are found (see + // https://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt), + // pixelFormat is not initialized in this case so we need to check + // for numFormats being not 0 explicitly (however this is not an error + // so don't call wxLogLastError() here). + if ( !numFormats ) + pixelFormat = 0; } - return requestFSAA ? -1 : 1; + // Delete the dummy objects + ::wglMakeCurrent(NULL, NULL); + ::wglDeleteContext(dumctx); + dummyWin->Destroy(); + + return pixelFormat; } /* static */ @@ -754,54 +1147,16 @@ wxGLCanvas::ChooseMatchingPixelFormat(HDC hdc, const int *attribList, PIXELFORMATDESCRIPTOR *ppfd) { - // default neutral pixel format - PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), // size - 1, // version - PFD_SUPPORT_OPENGL | - PFD_DRAW_TO_WINDOW | - PFD_DOUBLEBUFFER, // use double-buffering by default - PFD_TYPE_RGBA, // default pixel type - 0, // preferred color depth (don't care) - 0, 0, 0, 0, 0, 0, // color bits and shift bits (ignored) - 0, 0, // alpha bits and shift (ignored) - 0, // accumulation total bits - 0, 0, 0, 0, // accumulator RGBA bits (not used) - 16, // depth buffer - 0, // no stencil buffer - 0, // no auxiliary buffers - PFD_MAIN_PLANE, // main layer - 0, // reserved - 0, 0, 0, // no layer, visible, damage masks - }; + wxGLAttributes dispAttrs; + ParseAttribList(attribList, dispAttrs); + wxUnusedVar(hdc); + return FindMatchingPixelFormat(dispAttrs, ppfd); +} - if ( !ppfd ) - ppfd = &pfd; - else - *ppfd = pfd; - - // adjust the PFD using the provided attributes and also check if we can - // use PIXELFORMATDESCRIPTOR at all: if multisampling is requested, we - // can't as it's not supported by ChoosePixelFormat() - switch ( AdjustPFDForAttributes(*ppfd, attribList) ) - { - case 1: - return ::ChoosePixelFormat(hdc, ppfd); - - default: - wxFAIL_MSG( "unexpected AdjustPFDForAttributes() return value" ); - // fall through - - case 0: - // error in attributes - return 0; - - case -1: - // requestFSAA == true, will continue as normal - // in order to query later for a FSAA pixelformat - return -1; - } +/* static */ +bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs) +{ + return wxGLCanvas::FindMatchingPixelFormat(dispAttrs) > 0; } /* static */ @@ -809,30 +1164,16 @@ bool wxGLCanvasBase::IsDisplaySupported(const int *attribList) { // We need a device context to test the pixel format, so get one // for the root window. + // Not true anymore. Keep it just in case some body uses this undocumented function return wxGLCanvas::ChooseMatchingPixelFormat(ScreenHDC(), attribList) > 0; } int wxGLCanvas::DoSetup(PIXELFORMATDESCRIPTOR &pfd, const int *attribList) { - int pixelFormat = ChooseMatchingPixelFormat(m_hDC, attribList, &pfd); - - const bool requestFSAA = pixelFormat == -1; - if ( requestFSAA ) - pixelFormat = ::ChoosePixelFormat(m_hDC, &pfd); - - if ( !pixelFormat ) - { - wxLogLastError(wxT("ChoosePixelFormat")); - return 0; - } - - if ( !::SetPixelFormat(m_hDC, pixelFormat, &pfd) ) - { - wxLogLastError(wxT("SetPixelFormat")); - return 0; - } - - return requestFSAA ? -1 : 1; + // Keep this member is case somebody is overriding it + wxUnusedVar(pfd); + wxUnusedVar(attribList); + return -1; } // ---------------------------------------------------------------------------- diff --git a/src/osx/cocoa/glcanvas.mm b/src/osx/cocoa/glcanvas.mm index 8783ef4f1c..1490dbaff8 100644 --- a/src/osx/cocoa/glcanvas.mm +++ b/src/osx/cocoa/glcanvas.mm @@ -37,10 +37,6 @@ WXGLContext WXGLCreateContext( WXGLPixelFormat pixelFormat, WXGLContext shareContext ) { WXGLContext context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext: shareContext]; - if ( !context ) - { - wxFAIL_MSG("NSOpenGLContext creation failed"); - } return context ; } @@ -77,178 +73,39 @@ void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat ) } } - -WXGLPixelFormat WXGLChoosePixelFormat(const int *attribList) +// Form a list of attributes by joining canvas attributes and context attributes. +// OS X uses just one list to find a suitable pixel format. +WXGLPixelFormat WXGLChoosePixelFormat(const int *GLAttrs, + int n1, + const int *ctxAttrs, + int n2) { - NSOpenGLPixelFormatAttribute data[512]; - - unsigned p = 0; - data[p++] = NSOpenGLPFAMinimumPolicy; // make _SIZE tags behave more like GLX - - // Test if we support hardware acceleration, we always want to use it if it - // is available and, apparently, in spite of the Apple docs explicitly - // saying the contrary: - // - // If present, this attribute indicates that only hardware-accelerated - // renderers are considered. If not present, accelerated renderers are - // still preferred. - // - // hardware acceleration is not always used without it, so we do need to - // specify it. But we shouldn't do it if acceleration is really not - // available. - const NSOpenGLPixelFormatAttribute - attrsAccel[] = { NSOpenGLPFAAccelerated, 0 }; - if ( WXGLPixelFormat testFormat = [[NSOpenGLPixelFormat alloc] - initWithAttributes: attrsAccel] ) - { - // Hardware acceleration is available, use it. - data[p++] = NSOpenGLPFAAccelerated; - [testFormat release]; - } - + NSOpenGLPixelFormatAttribute data[128]; const NSOpenGLPixelFormatAttribute *attribs; - if ( !attribList ) + unsigned p = 0; + + // The list should have at least one value and the '0' at end. So the + // minimum size is 2. + if ( GLAttrs && n1 > 1 ) { - // Default attributes - data[p++] = NSOpenGLPFADoubleBuffer; - data[p++] = NSOpenGLPFAColorSize; - data[p++] = (NSOpenGLPixelFormatAttribute)8; - data[p++] = NSOpenGLPFAAlphaSize; - data[p++] = (NSOpenGLPixelFormatAttribute)0; - data[p++] = NSOpenGLPFADepthSize; - data[p++] = (NSOpenGLPixelFormatAttribute)8; - data[p] = 0; - attribs = data; + n1--; // skip the ending '0' + while ( p < n1 ) + data[p++] = (NSOpenGLPixelFormatAttribute) GLAttrs[p]; } - else + + if ( ctxAttrs && n2 > 1 ) { - for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); ) - { - switch ( attribList[arg++] ) - { - case WX_GL_RGBA: - //data[p++] = AGL_RGBA; - break; - - case WX_GL_BUFFER_SIZE: - //data[p++] = AGL_BUFFER_SIZE; - //data[p++] = attribList[arg++]; - break; - - case WX_GL_LEVEL: - //data[p++]=AGL_LEVEL; - //data[p++]=attribList[arg++]; - break; - - case WX_GL_DOUBLEBUFFER: - data[p++] = NSOpenGLPFADoubleBuffer; - break; - - case WX_GL_STEREO: - data[p++] = NSOpenGLPFAStereo; - break; - - case WX_GL_AUX_BUFFERS: - data[p++] = NSOpenGLPFAAuxBuffers; - data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]; - break; - - case WX_GL_MIN_RED: - data[p++] = NSOpenGLPFAColorSize; - data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]; - break; - - case WX_GL_MIN_GREEN: - //data[p++] = AGL_GREEN_SIZE; - //data[p++] = attribList[arg++]; - break; - - case WX_GL_MIN_BLUE: - //data[p++] = AGL_BLUE_SIZE; - //data[p++] = attribList[arg++]; - break; - - case WX_GL_MIN_ALPHA: - data[p++] = NSOpenGLPFAAlphaSize; - data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]; - break; - - case WX_GL_DEPTH_SIZE: - data[p++] = NSOpenGLPFADepthSize; - data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]; - break; - - case WX_GL_STENCIL_SIZE: - data[p++] = NSOpenGLPFAStencilSize; - data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]; - break; - - case WX_GL_MIN_ACCUM_RED: - data[p++] = NSOpenGLPFAAccumSize; - data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]; - break; - - case WX_GL_MIN_ACCUM_GREEN: - //data[p++] = AGL_ACCUM_GREEN_SIZE; - //data[p++] = attribList[arg++]; - break; - - case WX_GL_MIN_ACCUM_BLUE: - //data[p++] = AGL_ACCUM_BLUE_SIZE; - //data[p++] = attribList[arg++]; - break; - - case WX_GL_MIN_ACCUM_ALPHA: - //data[p++] = AGL_ACCUM_ALPHA_SIZE; - //data[p++] = attribList[arg++]; - break; - - case WX_GL_SAMPLE_BUFFERS: - if ( !wxGLCanvas::IsAGLMultiSampleAvailable() ) - { - if ( !attribList[arg++] ) - break; - - return nil; - } - - data[p++] = NSOpenGLPFASampleBuffers; - if ( (data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]) == true ) - { - // don't use software fallback - data[p++] = NSOpenGLPFANoRecovery; - } - break; - - case WX_GL_SAMPLES: - if ( !wxGLCanvas::IsAGLMultiSampleAvailable() ) - { - if ( !attribList[arg++] ) - break; - - return nil; - } - - data[p++] = NSOpenGLPFASamples; - data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]; - break; - - case WX_GL_CORE_PROFILE: - data[p++] = NSOpenGLPFAOpenGLProfile; - // request an OpenGL core profile - // will use the highest available OpenGL version - // which will be at least 3.2 - data[p++] = NSOpenGLProfileVersion3_2Core; - - break; - } - } - - data[p] = 0; - - attribs = data; + n2--; // skip the ending '0' + unsigned p2 = 0; + while ( p2 < n2 ) + data[p++] = (NSOpenGLPixelFormatAttribute) ctxAttrs[p2++]; } + // End the list + data[p] = (NSOpenGLPixelFormatAttribute) 0; + + attribs = data; + return [[NSOpenGLPixelFormat alloc] initWithAttributes:(NSOpenGLPixelFormatAttribute*) attribs]; } @@ -278,34 +135,6 @@ WXGLPixelFormat WXGLChoosePixelFormat(const int *attribList) @end -bool wxGLCanvas::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name, - const int *attribList, - const wxPalette& WXUNUSED(palette)) -{ - m_glFormat = WXGLChoosePixelFormat(attribList); - if ( !m_glFormat ) - return false; - - // DontCreatePeer(); - - if ( !wxWindow::Create(parent, id, pos, size, style, name) ) - return false; - -/* - NSRect r = wxOSXGetFrameForControl( this, pos , size ) ; - wxNSCustomOpenGLView* v = [[wxNSCustomOpenGLView alloc] initWithFrame:r]; - m_peer = new wxWidgetCocoaImpl( this, v ); - - MacPostControlCreate(pos, size) ; -*/ - return true; -} - wxGLCanvas::~wxGLCanvas() { if ( m_glFormat ) @@ -325,13 +154,13 @@ bool wxGLCanvas::SwapBuffers() bool wxGLContext::SetCurrent(const wxGLCanvas& win) const { if ( !m_glContext ) - return false; + return false; [m_glContext setView: win.GetHandle() ]; [m_glContext update]; - + [m_glContext makeCurrentContext]; - + return true; } diff --git a/src/osx/glcanvas_osx.cpp b/src/osx/glcanvas_osx.cpp index 08bf445036..a91f748533 100644 --- a/src/osx/glcanvas_osx.cpp +++ b/src/osx/glcanvas_osx.cpp @@ -34,14 +34,367 @@ #include "wx/osx/private.h" +// These 'WX' values are the same as 'NS' ones +// Source: https://developer.apple.com/library/mac/documentation/ +// Cocoa/Reference/ApplicationKit/Classes/NSOpenGLPixelFormat_Class/index.html +#define WXOpenGLPFAAllRenderers 1 +#define WXOpenGLPFATripleBuffer 3 +#define WXOpenGLPFADoubleBuffer 5 +#define WXOpenGLPFAStereo 6 +#define WXOpenGLPFAAuxBuffers 7 +#define WXOpenGLPFAColorSize 8 +#define WXOpenGLPFAAlphaSize 11 +#define WXOpenGLPFADepthSize 12 +#define WXOpenGLPFAStencilSize 13 +#define WXOpenGLPFAAccumSize 14 +#define WXOpenGLPFAMinimumPolicy 51 +#define WXOpenGLPFAMaximumPolicy 52 +#define WXOpenGLPFAOffScreen 53 +#define WXOpenGLPFAFullScreen 54 +#define WXOpenGLPFASampleBuffers 55 +#define WXOpenGLPFASamples 56 +#define WXOpenGLPFAAuxDepthStencil 57 +#define WXOpenGLPFAColorFloat 58 +#define WXOpenGLPFAMultisample 59 +#define WXOpenGLPFASupersample 60 +#define WXOpenGLPFASampleAlpha 61 +#define WXOpenGLPFARendererID 70 +#define WXOpenGLPFASingleRenderer 71 +#define WXOpenGLPFANoRecovery 72 +#define WXOpenGLPFAAccelerated 73 +#define WXOpenGLPFAClosestPolicy 74 +#define WXOpenGLPFARobust 75 +#define WXOpenGLPFABackingStore 76 +#define WXOpenGLPFAMPSafe 78 +#define WXOpenGLPFAWindow 80 +#define WXOpenGLPFAMultiScreen 81 +#define WXOpenGLPFACompliant 83 +#define WXOpenGLPFAScreenMask 84 +#define WXOpenGLPFAPixelBuffer 90 +#define WXOpenGLPFARemotePixelBuffer 91 +#define WXOpenGLPFAAllowOfflineRenderers 96 +#define WXOpenGLPFAAcceleratedCompute 97 +#define WXOpenGLPFAOpenGLProfile 99 +#define WXOpenGLPFAVirtualScreenCount 128 + +#define WXOpenGLProfileVersionLegacy 0x1000 +#define WXOpenGLProfileVersion3_2Core 0x3200 + // ---------------------------------------------------------------------------- -// wxGLCanvas +// wxGLContextAttrs: OpenGL rendering context attributes +// ---------------------------------------------------------------------------- +// OSX specific values + +wxGLContextAttrs& wxGLContextAttrs::CoreProfile() +{ + AddAttribute(WXOpenGLPFAOpenGLProfile); + AddAttribute(WXOpenGLProfileVersion3_2Core); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::MajorVersion(int val) +{ + // No effect + wxUnusedVar(val); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::MinorVersion(int val) +{ + // No effect + wxUnusedVar(val); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile() +{ + AddAttribute(WXOpenGLPFAOpenGLProfile); + AddAttribute(WXOpenGLProfileVersionLegacy); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ForwardCompatible() +{ + // No effect + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ES2() +{ + // No effect + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::DebugCtx() +{ + // No effect + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::Robust() +{ + // No effect. Somehow similar flag (NSOpenGLPFARobust) is deprecated in OS X v10.5 + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::NoResetNotify() +{ + // No effect + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::LoseOnReset() +{ + // No effect + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ResetIsolation() +{ + // No effect + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::ReleaseFlush(int val) +{ + // No effect + wxUnusedVar(val); + return *this; +} + +wxGLContextAttrs& wxGLContextAttrs::PlatformDefaults() +{ + // No OSX specific defaults + return *this; +} + +void wxGLContextAttrs::EndList() +{ + AddAttribute(0); +} + +// ---------------------------------------------------------------------------- +// wxGLAttributes: pixel format attributes +// ---------------------------------------------------------------------------- +// OSX specific values + +wxGLAttributes& wxGLAttributes::RGBA() +{ + AddAttribute(WXOpenGLPFAColorSize); + AddAttribute(24); + AddAttribute(WXOpenGLPFAAlphaSize); + AddAttribute(8); + return *this; +} + +wxGLAttributes& wxGLAttributes::BufferSize(int val) +{ + // No effect + wxUnusedVar(val); + return *this; +} + +wxGLAttributes& wxGLAttributes::Level(int val) +{ + // No effect + wxUnusedVar(val); + return *this; +} + +wxGLAttributes& wxGLAttributes::DoubleBuffer() +{ + AddAttribute(WXOpenGLPFADoubleBuffer); + return *this; +} + +wxGLAttributes& wxGLAttributes::Stereo() +{ + AddAttribute(WXOpenGLPFAStereo); + return *this; +} + +wxGLAttributes& wxGLAttributes::AuxBuffers(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WXOpenGLPFAAuxBuffers); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::MinRGBA(int mRed, int mGreen, int mBlue, int mAlpha) +{ + int minColorBits = 0; + if ( mRed > minColorBits ) + minColorBits = mRed; + if ( mGreen > minColorBits ) + minColorBits = mGreen; + if ( mBlue > minColorBits ) + minColorBits = mBlue; + if ( minColorBits > 0 ) + { + AddAttribute(WXOpenGLPFAColorSize); + AddAttribute(minColorBits); + } + + if ( mAlpha >= 0 ) + { + AddAttribute(WXOpenGLPFAAlphaSize); + AddAttribute(mAlpha); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Depth(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WXOpenGLPFADepthSize); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Stencil(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WXOpenGLPFAStencilSize); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::MinAcumRGBA(int mRed, int mGreen, int mBlue, int mAlpha) +{ + int minAcumBits = 0; + if ( mRed > minAcumBits ) + minAcumBits = mRed; + if ( mGreen > minAcumBits ) + minAcumBits = mGreen; + if ( mBlue > minAcumBits ) + minAcumBits = mBlue; + if ( minAcumBits > 0 ) + { + AddAttribute(WXOpenGLPFAAccumSize); + AddAttribute(minAcumBits); + } + + // No effect for Alpha in accumulation buffer + wxUnusedVar(mAlpha); + + return *this; +} + +wxGLAttributes& wxGLAttributes::SampleBuffers(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WXOpenGLPFASampleBuffers); + AddAttribute(val); + // Don't use software fallback + AddAttribute(WXOpenGLPFANoRecovery); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Samplers(int val) +{ + if ( val >= 0 ) + { + AddAttribute(WXOpenGLPFASamples); + AddAttribute(val); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::FrameBuffersRGB() +{ + // No effect + return *this; +} + +void wxGLAttributes::EndList() +{ + AddAttribute(0); +} + +wxGLAttributes& wxGLAttributes::PlatformDefaults() +{ + AddAttribute(WXOpenGLPFAMinimumPolicy); // use _SIZE tags as minimum sizes + + // Test if we support hardware acceleration, we always want to use it if it + // is available and, apparently, in spite of the Apple docs explicitly + // saying the contrary: + // + // If present, this attribute indicates that only hardware-accelerated + // renderers are considered. If not present, accelerated renderers are + // still preferred. + // + // hardware acceleration is not always used without it, so we do need to + // specify it. But we shouldn't do it if acceleration is really not + // available. + const int attrsAccel[] = { WXOpenGLPFAAccelerated, 0 }; + WXGLPixelFormat testFormat = WXGLChoosePixelFormat(attrsAccel, 2); + if ( testFormat ) + { + // Hardware acceleration is available, use it. + AddAttribute(WXOpenGLPFAAccelerated); + WXGLDestroyPixelFormat(testFormat); + } + return *this; +} + +wxGLAttributes& wxGLAttributes::Defaults() +{ + RGBA().Depth(16).DoubleBuffer().SampleBuffers(1).Samplers(4); + return *this; +} + +// ---------------------------------------------------------------------------- +// wxGLContext // ---------------------------------------------------------------------------- -wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext *other) +wxGLContext::wxGLContext(wxGLCanvas *win, + const wxGLContext *other, + const wxGLContextAttrs *ctxAttrs) { - m_glContext = WXGLCreateContext(win->GetWXGLPixelFormat(), - other ? other->m_glContext : NULL); + const int* contextAttribs = NULL; + int ctxSize = 0; + + if ( ctxAttrs ) + { + contextAttribs = ctxAttrs->GetGLAttrs(); + ctxSize = ctxAttrs->GetSize(); + } + else if ( win->GetGLCTXAttrs().GetGLAttrs() ) + { + // If OpenGL context parameters were set at wxGLCanvas ctor, get them now + contextAttribs = win->GetGLCTXAttrs().GetGLAttrs(); + ctxSize = win->GetGLCTXAttrs().GetSize(); + } + // else use GPU driver defaults + + // Join canvas attributes and context attributes to ask for a pixel format + WXGLPixelFormat pf = WXGLChoosePixelFormat(win->GetGLDispAttrs().GetGLAttrs(), + win->GetGLDispAttrs().GetSize(), + contextAttribs, ctxSize); + + m_isOk = false; + + if ( pf ) + { + m_glContext = WXGLCreateContext(pf, other ? other->m_glContext : NULL); + if ( m_glContext ) + { + m_isOk = true; + } + + WXGLDestroyPixelFormat(pf); + } + if ( !m_isOk ) + wxLogMessage(_("Couldn't create OpenGL context")); } wxGLContext::~wxGLContext() @@ -61,6 +414,18 @@ wxIMPLEMENT_CLASS(wxGLCanvas, wxWindow); wxBEGIN_EVENT_TABLE(wxGLCanvas, wxWindow) wxEND_EVENT_TABLE() +wxGLCanvas::wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const wxPalette& palette) +{ + Create(parent, dispAttrs, id, pos, size, style, name, palette); +} + wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, const int *attribList, @@ -73,6 +438,58 @@ wxGLCanvas::wxGLCanvas(wxWindow *parent, Create(parent, id, pos, size, style, name, attribList, palette); } +bool wxGLCanvas::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const int *attribList, + const wxPalette& palette) +{ + // Separate 'pixel format' attributes. + // Also store context attributes for wxGLContext ctor + // If 'attribList' is NULL, ParseAttribList() will set defaults. + wxGLAttributes dispAttrs; + if ( ! ParseAttribList(attribList, dispAttrs, &m_GLCTXAttrs) ) + return false; + + return Create(parent, dispAttrs, id, pos, size, style, name, palette); +} + +bool wxGLCanvas::Create(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const wxPalette& WXUNUSED(palette)) +{ + m_glFormat = NULL; + // Don't allow an empty list + if ( !dispAttrs.GetGLAttrs() ) + { + wxFAIL_MSG("wxGLAttributes object is empty."); + return false; + } + + // Return false if any attribute is unsupported + if ( ! IsDisplaySupported(dispAttrs) ) + { + wxFAIL_MSG("Can't find a pixel format for the requested attributes"); + return false; + } + + // Make a copy of attributes. Will use at wxGLContext ctor + m_GLAttrs = dispAttrs; + + if ( !wxWindow::Create(parent, id, pos, size, style, name) ) + return false; + + return true; +} + #if WXWIN_COMPATIBILITY_2_8 wxGLCanvas::wxGLCanvas(wxWindow *parent, @@ -128,23 +545,36 @@ bool wxGLCanvas::IsAGLMultiSampleAvailable() return s_isMultiSampleAvailable != 0; } +/* static */ +bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs) +{ + WXGLPixelFormat testFormat = WXGLChoosePixelFormat(dispAttrs.GetGLAttrs(), dispAttrs.GetSize()); + if ( testFormat ) + { + WXGLDestroyPixelFormat(testFormat); + } + else + { + return false; + } + return true; +} + /* static */ bool wxGLCanvasBase::IsDisplaySupported(const int *attribList) { - WXGLPixelFormat glFormat = WXGLChoosePixelFormat(attribList); + wxGLAttributes dispAttrs; + ParseAttribList(attribList, dispAttrs); - if ( !glFormat ) - return false; - - WXGLDestroyPixelFormat(glFormat); - - return true; + return IsDisplaySupported(dispAttrs); } bool wxGLCanvasBase::IsExtensionSupported(const char *extension) { - // we need a valid context to query for extensions. - WXGLPixelFormat fmt = WXGLChoosePixelFormat(NULL); + // We need a valid context to query for extensions. Use a default one. + wxGLAttributes dispAttrs; + ParseAttribList(NULL, dispAttrs); // Sets defaults + WXGLPixelFormat fmt = WXGLChoosePixelFormat(dispAttrs.GetGLAttrs(), dispAttrs.GetSize()); WXGLContext ctx = WXGLCreateContext(fmt, NULL); if ( !ctx ) return false; diff --git a/src/unix/glx11.cpp b/src/unix/glx11.cpp index be024b63c7..52f756e259 100644 --- a/src/unix/glx11.cpp +++ b/src/unix/glx11.cpp @@ -64,6 +64,16 @@ #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 @@ -71,11 +81,6 @@ #define GLX_CONTEXT_FLAGS_ARB 0x2094 #define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 - -/* 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); #endif #ifndef GLX_ARB_create_context_profile @@ -93,79 +98,450 @@ typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) #define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 #endif -#ifndef GLX_EXT_create_context_es2_profile -#define GLX_EXT_create_context_es2_profile -#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT -#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000002 +#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_framebuffer_sRGB -#define GLX_ARB_framebuffer_sRGB -#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB -#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 +#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 *gc, const wxGLContext *other) +wxGLContext::wxGLContext(wxGLCanvas *win, + const wxGLContext *other, + const wxGLContextAttrs *ctxAttrs) { - if ( gc->GetGLXContextAttribs()[0] != 0 ) // OpenGL 3 context creation + const int* contextAttribs = NULL; + Bool x11Direct = True; + int renderType = GLX_RGBA_TYPE; + bool needsARB = false; + + if ( ctxAttrs ) { - XVisualInfo *vi = gc->GetXVisualInfo(); - wxCHECK_RET( vi, wxT("invalid visual for OpenGL") ); + 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 - // We need to create a temporary context to get the - // glXCreateContextAttribsARB function - GLXContext tempContext = glXCreateContext( wxGetX11Display(), vi, - NULL, - GL_TRUE ); - wxCHECK_RET( tempContext, wxT("Couldn't create OpenGL context") ); + m_isOk = false; - PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB - = (PFNGLXCREATECONTEXTATTRIBSARBPROC) - glXGetProcAddress((GLubyte *)"glXCreateContextAttribsARB"); - if ( !glXCreateContextAttribsARB ) - { - wxLogError(_("Core OpenGL profile is not supported by the OpenGL driver.")); - return; - } + Display* dpy = wxGetX11Display(); + XVisualInfo *vi = win->GetXVisualInfo(); + wxCHECK_RET( vi, "invalid visual for OpenGL" ); - GLXFBConfig *fbc = gc->GetGLXFBConfig(); - wxCHECK_RET( fbc, wxT("invalid GLXFBConfig 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" ); - m_glContext = glXCreateContextAttribsARB( wxGetX11Display(), fbc[0], - other ? other->m_glContext : None, - GL_TRUE, gc->GetGLXContextAttribs() ); + PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB + = (PFNGLXCREATECONTEXTATTRIBSARBPROC) + glXGetProcAddress((GLubyte *)"glXCreateContextAttribsARB"); - glXDestroyContext( wxGetX11Display(), tempContext ); + 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 = gc->GetGLXFBConfig(); - wxCHECK_RET( fbc, wxT("invalid GLXFBConfig for OpenGL") ); + GLXFBConfig *fbc = win->GetGLXFBConfig(); + wxCHECK_RET( fbc, "Invalid GLXFBConfig for OpenGL" ); - m_glContext = glXCreateNewContext( wxGetX11Display(), fbc[0], GLX_RGBA_TYPE, + m_glContext = glXCreateNewContext( dpy, fbc[0], renderType, other ? other->m_glContext : None, - GL_TRUE ); + x11Direct ); } else // GLX <= 1.2 { - XVisualInfo *vi = gc->GetXVisualInfo(); - wxCHECK_RET( vi, wxT("invalid visual for OpenGL") ); - - m_glContext = glXCreateContext( wxGetX11Display(), vi, + m_glContext = glXCreateContext( dpy, vi, other ? other->m_glContext : None, - GL_TRUE ); + x11Direct ); } - wxASSERT_MSG( m_glContext, wxT("Couldn't create OpenGL context") ); + // 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() @@ -213,14 +589,16 @@ wxGLCanvasX11::wxGLCanvasX11() { m_fbc = NULL; m_vi = NULL; - m_glxContextAttribs[0] = 0; } -bool wxGLCanvasX11::InitVisual(const int *attribList) +bool wxGLCanvasX11::InitVisual(const wxGLAttributes& dispAttrs) { - InitGLXContextAttribs(attribList, m_glxContextAttribs); - - return InitXVisualInfo(attribList, &m_fbc, &m_vi); + 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() @@ -258,276 +636,28 @@ bool wxGLCanvasX11::IsGLXMultiSampleAvailable() /* static */ -void wxGLCanvasX11::InitGLXContextAttribs(const int *wxattrs, int *wxctxattrs) +bool wxGLCanvasX11::InitXVisualInfo(const wxGLAttributes& dispAttrs, + GLXFBConfig** pFBC, + XVisualInfo** pXVisual) { - wxctxattrs[0] = 0; // default is legacy context - - if ( !wxattrs ) // default attribs - return; - - bool useGLCoreProfile = false; - - // the minimum gl core version would be 3.0 - int glVersionMajor = 3, - glVersionMinor = 0; - - for ( int arg = 0; wxattrs[arg] != 0; ) + // GLX_XX attributes + const int* attrsListGLX = dispAttrs.GetGLAttrs(); + if ( !attrsListGLX ) { - switch ( wxattrs[arg++] ) - { - case WX_GL_CORE_PROFILE: - useGLCoreProfile = true; - break; - - case WX_GL_MAJOR_VERSION: - glVersionMajor = wxattrs[arg++]; - break; - - case WX_GL_MINOR_VERSION: - glVersionMinor = wxattrs[arg++]; - break; - - default: break; - } - } - - if ( useGLCoreProfile ) - { - wxctxattrs[0] = GLX_CONTEXT_MAJOR_VERSION_ARB; - wxctxattrs[1] = glVersionMajor; - wxctxattrs[2] = GLX_CONTEXT_MINOR_VERSION_ARB; - wxctxattrs[3] = glVersionMinor; - wxctxattrs[4] = GLX_CONTEXT_FLAGS_ARB; - wxctxattrs[5] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; - wxctxattrs[6] = GLX_CONTEXT_PROFILE_MASK_ARB; - wxctxattrs[7] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; - wxctxattrs[8] = 0; // terminate - } -} - -/* static */ -bool -wxGLCanvasX11::ConvertWXAttrsToGL(const int *wxattrs, int *glattrs, size_t n) -{ - wxCHECK_MSG( n >= 16, false, wxT("GL attributes buffer too small") ); - - /* - 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. - */ - - if ( !wxattrs ) - { - size_t i = 0; - - // use double-buffered true colour by default - glattrs[i++] = GLX_DOUBLEBUFFER; - - if ( GetGLXVersion() < 13 ) - { - // default settings if attriblist = 0 - glattrs[i++] = GLX_RGBA; - glattrs[i++] = GLX_DEPTH_SIZE; glattrs[i++] = 1; - glattrs[i++] = GLX_RED_SIZE; glattrs[i++] = 1; - glattrs[i++] = GLX_GREEN_SIZE; glattrs[i++] = 1; - glattrs[i++] = GLX_BLUE_SIZE; glattrs[i++] = 1; - glattrs[i++] = GLX_ALPHA_SIZE; glattrs[i++] = 0; - } - else // recent GLX can choose the defaults on its own just fine - { - // we just need to have a value after GLX_DOUBLEBUFFER - glattrs[i++] = True; - } - - glattrs[i] = None; - - wxASSERT_MSG( i < n, wxT("GL attributes buffer too small") ); - } - else // have non-default attributes - { - size_t p = 0; - for ( int arg = 0; wxattrs[arg] != 0; ) - { - // check if we have any space left, knowing that we may insert 2 - // more elements during this loop iteration and we always need to - // terminate the list with None (hence -3) - if ( p > n - 3 ) - return false; - - // indicates whether we have a boolean attribute - bool isBoolAttr = false; - - switch ( wxattrs[arg++] ) - { - case WX_GL_BUFFER_SIZE: - glattrs[p++] = GLX_BUFFER_SIZE; - break; - - case WX_GL_LEVEL: - glattrs[p++] = GLX_LEVEL; - break; - - case WX_GL_RGBA: - if ( GetGLXVersion() >= 13 ) - { - // this is the default GLX_RENDER_TYPE anyhow - continue; - } - - glattrs[p++] = GLX_RGBA; - isBoolAttr = true; - break; - - case WX_GL_DOUBLEBUFFER: - glattrs[p++] = GLX_DOUBLEBUFFER; - isBoolAttr = true; - break; - - case WX_GL_STEREO: - glattrs[p++] = GLX_STEREO; - isBoolAttr = true; - break; - - case WX_GL_AUX_BUFFERS: - glattrs[p++] = GLX_AUX_BUFFERS; - break; - - case WX_GL_MIN_RED: - glattrs[p++] = GLX_RED_SIZE; - break; - - case WX_GL_MIN_GREEN: - glattrs[p++] = GLX_GREEN_SIZE; - break; - - case WX_GL_MIN_BLUE: - glattrs[p++] = GLX_BLUE_SIZE; - break; - - case WX_GL_MIN_ALPHA: - glattrs[p++] = GLX_ALPHA_SIZE; - break; - - case WX_GL_DEPTH_SIZE: - glattrs[p++] = GLX_DEPTH_SIZE; - break; - - case WX_GL_STENCIL_SIZE: - glattrs[p++] = GLX_STENCIL_SIZE; - break; - - case WX_GL_MIN_ACCUM_RED: - glattrs[p++] = GLX_ACCUM_RED_SIZE; - break; - - case WX_GL_MIN_ACCUM_GREEN: - glattrs[p++] = GLX_ACCUM_GREEN_SIZE; - break; - - case WX_GL_MIN_ACCUM_BLUE: - glattrs[p++] = GLX_ACCUM_BLUE_SIZE; - break; - - case WX_GL_MIN_ACCUM_ALPHA: - glattrs[p++] = GLX_ACCUM_ALPHA_SIZE; - break; - - case WX_GL_SAMPLE_BUFFERS: -#ifdef GLX_SAMPLE_BUFFERS_ARB - if ( IsGLXMultiSampleAvailable() ) - { - glattrs[p++] = GLX_SAMPLE_BUFFERS_ARB; - break; - } -#endif // GLX_SAMPLE_BUFFERS_ARB - // if it was specified just to disable it, no problem - if ( !wxattrs[arg++] ) - continue; - - // otherwise indicate that it's not supported - return false; - - case WX_GL_SAMPLES: -#ifdef GLX_SAMPLES_ARB - if ( IsGLXMultiSampleAvailable() ) - { - glattrs[p++] = GLX_SAMPLES_ARB; - break; - } -#endif // GLX_SAMPLES_ARB - - if ( !wxattrs[arg++] ) - continue; - - return false; - - // the following constants are context attribs - // ignore them - case WX_GL_CORE_PROFILE: - continue; - - case WX_GL_MAJOR_VERSION: - arg++; // skip int - continue; - - case WX_GL_MINOR_VERSION: - arg++; // skip int - continue; - - default: - wxLogDebug(wxT("Unsupported OpenGL attribute %d"), - wxattrs[arg - 1]); - continue; - } - - if ( isBoolAttr ) - { - // as explained above, for pre 1.3 API the attribute just needs - // to be present so we only add its value when using the new API - if ( GetGLXVersion() >= 13 ) - glattrs[p++] = True; - } - else // attribute with real (non-boolean) value - { - // copy attribute value as is - glattrs[p++] = wxattrs[arg++]; - } - } - - glattrs[p] = None; - } - - return true; -} - -/* static */ -bool -wxGLCanvasX11::InitXVisualInfo(const int *attribList, - GLXFBConfig **pFBC, - XVisualInfo **pXVisual) -{ - int data[512]; - if ( !ConvertWXAttrsToGL(attribList, data, WXSIZEOF(data)) ) + wxFAIL_MSG("wxGLAttributes object is empty."); return false; + } - Display * const dpy = wxGetX11Display(); + Display* dpy = wxGetX11Display(); if ( GetGLXVersion() >= 13 ) { int returned; - *pFBC = glXChooseFBConfig(dpy, DefaultScreen(dpy), data, &returned); + *pFBC = glXChooseFBConfig(dpy, DefaultScreen(dpy), attrsListGLX, &returned); if ( *pFBC ) { + // Use the first good match *pXVisual = glXGetVisualFromFBConfig(wxGetX11Display(), **pFBC); if ( !*pXVisual ) { @@ -539,21 +669,20 @@ wxGLCanvasX11::InitXVisualInfo(const int *attribList, else // GLX <= 1.2 { *pFBC = NULL; - *pXVisual = glXChooseVisual(dpy, DefaultScreen(dpy), data); + *pXVisual = glXChooseVisual(dpy, DefaultScreen(dpy), + wx_const_cast(int*, attrsListGLX) ); } return *pXVisual != NULL; } /* static */ -bool -wxGLCanvasBase::IsDisplaySupported(const int *attribList) +bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs) { GLXFBConfig *fbc = NULL; XVisualInfo *vi = NULL; - const bool - isSupported = wxGLCanvasX11::InitXVisualInfo(attribList, &fbc, &vi); + bool isSupported = wxGLCanvasX11::InitXVisualInfo(dispAttrs, &fbc, &vi); if ( fbc ) XFree(fbc); @@ -563,6 +692,15 @@ wxGLCanvasBase::IsDisplaySupported(const int *attribList) return isSupported; } +/* static */ +bool wxGLCanvasBase::IsDisplaySupported(const int *attribList) +{ + wxGLAttributes dispAttrs; + ParseAttribList(attribList, dispAttrs); + + return IsDisplaySupported(dispAttrs); +} + // ---------------------------------------------------------------------------- // default visual management // ---------------------------------------------------------------------------- @@ -574,8 +712,10 @@ GLXFBConfig *wxGLCanvasX11::ms_glFBCInfo = NULL; bool wxGLCanvasX11::InitDefaultVisualInfo(const int *attribList) { FreeDefaultVisualInfo(); + wxGLAttributes dispAttrs; + ParseAttribList(attribList, dispAttrs); - return InitXVisualInfo(attribList, &ms_glFBCInfo, &ms_glVisualInfo); + return InitXVisualInfo(dispAttrs, &ms_glFBCInfo, &ms_glVisualInfo); } /* static */ diff --git a/src/x11/glcanvas.cpp b/src/x11/glcanvas.cpp index d58cd1e31e..83652d4623 100644 --- a/src/x11/glcanvas.cpp +++ b/src/x11/glcanvas.cpp @@ -41,6 +41,18 @@ wxIMPLEMENT_CLASS(wxGLCanvas, wxWindow); +wxGLCanvas::wxGLCanvas(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const wxPalette& palette) +{ + Create(parent, dispAttrs, id, pos, size, style, name, palette); +} + wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, const int *attribList, @@ -60,12 +72,30 @@ bool wxGLCanvas::Create(wxWindow *parent, long style, const wxString& name, const int *attribList, + const wxPalette& palette) +{ + // Separate 'GLXFBConfig/XVisual' attributes. + // Also store context attributes for wxGLContext ctor + wxGLAttributes dispAttrs; + if ( ! ParseAttribList(attribList, dispAttrs, &m_GLCTXAttrs) ) + return false; + + return Create(parent, dispAttrs, id, pos, size, style, name, palette); +} + +bool wxGLCanvas::Create(wxWindow *parent, + const wxGLAttributes& dispAttrs, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, const wxPalette& WXUNUSED(palette)) { if ( !wxWindow::Create(parent, id, pos, size, style, name) ) return false; - if ( !InitVisual(attribList) ) + if ( !InitVisual(dispAttrs) ) return false; return true;