Improve wxQt OpenGL canvas implementation:

- Support wxGLContext::SetCurrent.
- Pass GL canvas attributes via ParseAttribList to handle defaults.
- Remove OpenGL not implemented message.
- Prevent QGLWidget from changing OpenGL state before we paint.
- Set Qt::StrongFocus for wxQtGLWidget to allow keyboard input.
- Use QtCanPaintWithoutActivePainter to fix wxPaintDCImpl assert when using wxGLCanvas.
This commit is contained in:
Alex Shvartzkop 2024-01-10 02:41:59 +03:00
parent 57349c2aaa
commit 966b6e9460
5 changed files with 184 additions and 69 deletions

View file

@ -24,6 +24,9 @@ public:
virtual bool SetCurrent(const wxGLCanvas& win) const override; virtual bool SetCurrent(const wxGLCanvas& win) const override;
private:
QGLContext* m_glContext = nullptr;
wxDECLARE_CLASS(wxGLContext); wxDECLARE_CLASS(wxGLContext);
}; };
@ -78,7 +81,9 @@ public:
virtual bool SwapBuffers() override; virtual bool SwapBuffers() override;
static bool ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format); virtual bool QtCanPaintWithoutActivePainter() const override;
static bool ConvertWXAttrsToQtGL(const wxGLAttributes &glattrs, const wxGLContextAttrs ctxAttrs, QGLFormat &format);
private: private:
wxDECLARE_CLASS(wxGLCanvas); wxDECLARE_CLASS(wxGLCanvas);

View file

@ -151,6 +151,7 @@ public:
void QtSetPicture( QPicture* pict ); void QtSetPicture( QPicture* pict );
QPainter *QtGetPainter(); QPainter *QtGetPainter();
virtual bool QtCanPaintWithoutActivePainter() const;
virtual bool QtHandlePaintEvent ( QWidget *handler, QPaintEvent *event ); virtual bool QtHandlePaintEvent ( QWidget *handler, QPaintEvent *event );
virtual bool QtHandleResizeEvent ( QWidget *handler, QResizeEvent *event ); virtual bool QtHandleResizeEvent ( QWidget *handler, QResizeEvent *event );

View file

@ -126,7 +126,7 @@ wxPaintDCImpl::wxPaintDCImpl( wxDC *owner )
wxPaintDCImpl::wxPaintDCImpl( wxDC *owner, wxWindow *win ) wxPaintDCImpl::wxPaintDCImpl( wxDC *owner, wxWindow *win )
: wxWindowDCImpl( owner, win ) : wxWindowDCImpl( owner, win )
{ {
wxCHECK_RET( m_isWindowPainter, wxCHECK_RET( m_isWindowPainter || win->QtCanPaintWithoutActivePainter(),
"wxPaintDC can't be created outside wxEVT_PAINT handler" ); "wxPaintDC can't be created outside wxEVT_PAINT handler" );
} }

View file

@ -16,26 +16,20 @@
#include <QtWidgets/QGestureRecognizer> #include <QtWidgets/QGestureRecognizer>
#include <QtWidgets/QGestureEvent> #include <QtWidgets/QGestureEvent>
#if defined(__VISUALC__)
#pragma message("OpenGL support is not implemented in wxQt")
#else
#warning "OpenGL support is not implemented in wxQt"
#endif
wxGCC_WARNING_SUPPRESS(unused-parameter) wxGCC_WARNING_SUPPRESS(unused-parameter)
class wxQtGLWidget : public wxQtEventSignalHandler< QGLWidget, wxGLCanvas > class wxQtGLWidget : public wxQtEventSignalHandler< QGLWidget, wxGLCanvas >
{ {
public: public:
wxQtGLWidget(wxWindow *parent, wxGLCanvas *handler, QGLFormat format) wxQtGLWidget(wxWindow *parent, wxGLCanvas *handler, QGLFormat format)
: wxQtEventSignalHandler<QGLWidget,wxGLCanvas>(parent, handler) : wxQtEventSignalHandler<QGLWidget, wxGLCanvas>(parent, handler)
{ {
setFormat(format); setFormat(format);
setAutoBufferSwap( false ); setAutoBufferSwap(false);
} setFocusPolicy(Qt::StrongFocus);
}
protected: protected:
virtual void showEvent ( QShowEvent * event ) override;
virtual void hideEvent ( QHideEvent * event ) override;
virtual void resizeEvent ( QResizeEvent * event ) override; virtual void resizeEvent ( QResizeEvent * event ) override;
virtual void paintEvent ( QPaintEvent * event ) override; virtual void paintEvent ( QPaintEvent * event ) override;
@ -43,16 +37,6 @@ protected:
virtual void paintGL() override; virtual void paintGL() override;
}; };
void wxQtGLWidget::showEvent ( QShowEvent * event )
{
QGLWidget::showEvent( event );
}
void wxQtGLWidget::hideEvent ( QHideEvent * event )
{
QGLWidget::hideEvent( event );
}
void wxQtGLWidget::resizeEvent ( QResizeEvent * event ) void wxQtGLWidget::resizeEvent ( QResizeEvent * event )
{ {
QGLWidget::resizeEvent(event); QGLWidget::resizeEvent(event);
@ -84,6 +68,7 @@ wxGLContextAttrs& wxGLContextAttrs::CoreProfile()
{ {
// AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB, // AddAttribBits(GLX_CONTEXT_PROFILE_MASK_ARB,
// GLX_CONTEXT_CORE_PROFILE_BIT_ARB); // GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
AddAttribute(wx_GL_COMPAT_PROFILE);
SetNeedsARB(); SetNeedsARB();
return *this; return *this;
} }
@ -92,6 +77,9 @@ wxGLContextAttrs& wxGLContextAttrs::MajorVersion(int val)
{ {
if ( val > 0 ) if ( val > 0 )
{ {
AddAttribute(WX_GL_MAJOR_VERSION);
AddAttribute(val);
if ( val >= 3 ) if ( val >= 3 )
SetNeedsARB(); SetNeedsARB();
} }
@ -102,12 +90,15 @@ wxGLContextAttrs& wxGLContextAttrs::MinorVersion(int val)
{ {
if ( val >= 0 ) if ( val >= 0 )
{ {
AddAttribute(WX_GL_MINOR_VERSION);
AddAttribute(val);
} }
return *this; return *this;
} }
wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile() wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile()
{ {
AddAttribute(wx_GL_COMPAT_PROFILE);
SetNeedsARB(); SetNeedsARB();
return *this; return *this;
} }
@ -168,7 +159,7 @@ wxGLContextAttrs& wxGLContextAttrs::PlatformDefaults()
void wxGLContextAttrs::EndList() void wxGLContextAttrs::EndList()
{ {
// AddAttribute(None); AddAttribute(0);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -190,6 +181,7 @@ void wxGLContextAttrs::EndList()
wxGLAttributes& wxGLAttributes::RGBA() wxGLAttributes& wxGLAttributes::RGBA()
{ {
AddAttribute(WX_GL_RGBA);
return *this; return *this;
} }
@ -197,24 +189,28 @@ wxGLAttributes& wxGLAttributes::BufferSize(int val)
{ {
if ( val >= 0 ) if ( val >= 0 )
{ {
AddAttribute(WX_GL_BUFFER_SIZE);
AddAttribute(val);
} }
return *this; return *this;
} }
wxGLAttributes& wxGLAttributes::Level(int val) wxGLAttributes& wxGLAttributes::Level(int val)
{ {
// AddAttribute(GLX_LEVEL); AddAttribute(WX_GL_LEVEL);
AddAttribute(val); AddAttribute(val);
return *this; return *this;
} }
wxGLAttributes& wxGLAttributes::DoubleBuffer() wxGLAttributes& wxGLAttributes::DoubleBuffer()
{ {
AddAttribute(WX_GL_DOUBLEBUFFER);
return *this; return *this;
} }
wxGLAttributes& wxGLAttributes::Stereo() wxGLAttributes& wxGLAttributes::Stereo()
{ {
AddAttribute(WX_GL_STEREO);
return *this; return *this;
} }
@ -222,6 +218,8 @@ wxGLAttributes& wxGLAttributes::AuxBuffers(int val)
{ {
if ( val >= 0 ) if ( val >= 0 )
{ {
AddAttribute(WX_GL_AUX_BUFFERS);
AddAttribute(val);
} }
return *this; return *this;
} }
@ -230,15 +228,23 @@ wxGLAttributes& wxGLAttributes::MinRGBA(int mRed, int mGreen, int mBlue, int mAl
{ {
if ( mRed >= 0) if ( mRed >= 0)
{ {
AddAttribute(WX_GL_MIN_RED);
AddAttribute(mRed);
} }
if ( mGreen >= 0) if ( mGreen >= 0)
{ {
AddAttribute(WX_GL_MIN_GREEN);
AddAttribute(mGreen);
} }
if ( mBlue >= 0) if ( mBlue >= 0)
{ {
AddAttribute(WX_GL_MIN_BLUE);
AddAttribute(mBlue);
} }
if ( mAlpha >= 0) if ( mAlpha >= 0)
{ {
AddAttribute(WX_GL_MIN_ALPHA);
AddAttribute(mAlpha);
} }
return *this; return *this;
} }
@ -247,6 +253,8 @@ wxGLAttributes& wxGLAttributes::Depth(int val)
{ {
if ( val >= 0 ) if ( val >= 0 )
{ {
AddAttribute(WX_GL_DEPTH_SIZE);
AddAttribute(val);
} }
return *this; return *this;
} }
@ -255,6 +263,8 @@ wxGLAttributes& wxGLAttributes::Stencil(int val)
{ {
if ( val >= 0 ) if ( val >= 0 )
{ {
AddAttribute(WX_GL_DEPTH_SIZE);
AddAttribute(val);
} }
return *this; return *this;
} }
@ -263,40 +273,44 @@ wxGLAttributes& wxGLAttributes::MinAcumRGBA(int mRed, int mGreen, int mBlue, int
{ {
if ( mRed >= 0) if ( mRed >= 0)
{ {
AddAttribute(WX_GL_MIN_ACCUM_RED);
AddAttribute(mRed);
} }
if ( mGreen >= 0) if ( mGreen >= 0)
{ {
AddAttribute(WX_GL_MIN_ACCUM_GREEN);
AddAttribute(mGreen);
} }
if ( mBlue >= 0) if ( mBlue >= 0)
{ {
AddAttribute(WX_GL_MIN_ACCUM_BLUE);
AddAttribute(mBlue);
} }
if ( mAlpha >= 0) if ( mAlpha >= 0)
{ {
AddAttribute(WX_GL_MIN_ACCUM_ALPHA);
AddAttribute(mAlpha);
} }
return *this; return *this;
} }
wxGLAttributes& wxGLAttributes::SampleBuffers(int val) wxGLAttributes& wxGLAttributes::SampleBuffers(int val)
{ {
#ifdef GLX_SAMPLE_BUFFERS_ARB if ( val >= 0 )
if ( val >= 0 && wxGLCanvasX11::IsGLXMultiSampleAvailable() )
{ {
AddAttribute(GLX_SAMPLE_BUFFERS_ARB); AddAttribute(WX_GL_SAMPLE_BUFFERS);
AddAttribute(val); AddAttribute(val);
} }
#endif
return *this; return *this;
} }
wxGLAttributes& wxGLAttributes::Samplers(int val) wxGLAttributes& wxGLAttributes::Samplers(int val)
{ {
#ifdef GLX_SAMPLES_ARB if ( val >= 0 )
if ( val >= 0 && wxGLCanvasX11::IsGLXMultiSampleAvailable() )
{ {
AddAttribute(GLX_SAMPLES_ARB); AddAttribute(WX_GL_SAMPLES);
AddAttribute(val); AddAttribute(val);
} }
#endif
return *this; return *this;
} }
@ -309,11 +323,12 @@ wxGLAttributes& wxGLAttributes::FrameBuffersRGB()
void wxGLAttributes::EndList() void wxGLAttributes::EndList()
{ {
AddAttribute(0);
} }
wxGLAttributes& wxGLAttributes::PlatformDefaults() wxGLAttributes& wxGLAttributes::PlatformDefaults()
{ {
// No GLX specific values // No Qt specific values
return *this; return *this;
} }
@ -324,15 +339,33 @@ wxGLAttributes& wxGLAttributes::PlatformDefaults()
wxIMPLEMENT_CLASS(wxGLContext, wxWindow); wxIMPLEMENT_CLASS(wxGLContext, wxWindow);
wxGLContext::wxGLContext(wxGLCanvas *WXUNUSED(win), const wxGLContext* WXUNUSED(other), const wxGLContextAttrs *WXUNUSED(ctxAttrs)) wxGLContext::wxGLContext(wxGLCanvas *win,
const wxGLContext *other,
const wxGLContextAttrs *ctxAttrs)
{ {
QGLWidget *qglWidget = static_cast<QGLWidget *>(win->GetHandle());
m_glContext = qglWidget->context();
if (m_glContext != nullptr)
{
m_isOk = true;
}
} }
bool wxGLContext::SetCurrent(const wxGLCanvas&) const bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
{ {
// I think I must destroy and recreate the QGLWidget to change the context? QGLWidget *qglWidget = static_cast<QGLWidget *>(win.GetHandle());
// win->GetHandle()->makeCurrent(); QGLContext *context = qglWidget->context();
return false;
if (context != m_glContext)
{
// I think I must destroy and recreate the QGLWidget to change the context?
wxLogDebug("Calling wxGLContext::SetCurrent with a different canvas is not supported in wxQt");
return false;
}
qglWidget->makeCurrent();
return true;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -403,8 +436,11 @@ bool wxGLCanvas::Create(wxWindow *parent,
const wxString& name, const wxString& name,
const wxPalette& palette) const wxPalette& palette)
{ {
wxLogError("Missing implementation of " + wxString(__FUNCTION__)); const int* attrsList = dispAttrs.GetGLAttrs();
return false;
wxCHECK_MSG(attrsList, false, "wxGLAttributes object is empty.");
return Create(parent, id, pos, size, style, name, attrsList, palette);
} }
bool wxGLCanvas::Create(wxWindow *parent, bool wxGLCanvas::Create(wxWindow *parent,
@ -421,17 +457,35 @@ bool wxGLCanvas::Create(wxWindow *parent,
#endif // wxUSE_PALETTE #endif // wxUSE_PALETTE
wxUnusedVar(palette); // Unused when wxDEBUG_LEVEL==0 wxUnusedVar(palette); // Unused when wxDEBUG_LEVEL==0
QGLFormat format; // Separate display/context attributes, set defaults.
if (!wxGLCanvas::ConvertWXAttrsToQtGL(attribList, format)) wxGLAttributes dispAttrs;
wxGLContextAttrs ctxAttrs;
if (!ParseAttribList(attribList, dispAttrs, &ctxAttrs))
return false; return false;
QGLFormat format;
if (!wxGLCanvas::ConvertWXAttrsToQtGL(dispAttrs, ctxAttrs, format))
return false;
// Return false if any attribute is unsupported
if ( !IsDisplaySupported(attribList) )
{
wxFAIL_MSG("Can't find a pixel format for the requested attributes");
return false;
}
m_qtWindow = new wxQtGLWidget(parent, this, format); m_qtWindow = new wxQtGLWidget(parent, this, format);
// Create and register a custom pan recognizer, available to all instances of this class. // Create and register a custom pan recognizer, available to all instances of this class.
QGestureRecognizer* pPanRecognizer = new PanGestureRecognizer(); QGestureRecognizer* pPanRecognizer = new PanGestureRecognizer();
QGestureRecognizer::registerRecognizer(pPanRecognizer); QGestureRecognizer::registerRecognizer(pPanRecognizer);
return wxWindow::Create( parent, id, pos, size, style, name ); if ( !wxWindow::Create( parent, id, pos, size, style, name ) )
return false;
SetBackgroundStyle(wxBG_STYLE_PAINT);
return true;
} }
bool wxGLCanvas::SwapBuffers() bool wxGLCanvas::SwapBuffers()
@ -440,11 +494,16 @@ bool wxGLCanvas::SwapBuffers()
return true; return true;
} }
/* static */ bool wxGLCanvas::QtCanPaintWithoutActivePainter() const
bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format)
{ {
if (!wxattrs) return true;
return true; }
/* static */
bool wxGLCanvas::ConvertWXAttrsToQtGL(const wxGLAttributes &wxGLAttrs, const wxGLContextAttrs wxCtxAttrs, QGLFormat &format)
{
const int *glattrs = wxGLAttrs.GetGLAttrs();
const int *ctxattrs = wxCtxAttrs.GetGLAttrs();
// set default parameters to false // set default parameters to false
format.setDoubleBuffer(false); format.setDoubleBuffer(false);
@ -452,14 +511,16 @@ bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format)
format.setAlpha(false); format.setAlpha(false);
format.setStencil(false); format.setStencil(false);
for ( int arg = 0; wxattrs[arg] != 0; arg++ ) for (int arg = 0; glattrs && glattrs[arg] != 0; arg++)
{ {
// indicates whether we have a boolean attribute // indicates whether we have a boolean attribute
bool isBoolAttr = false; bool isBoolAttr = false;
int v = wxattrs[arg+1]; int v = glattrs[arg+1];
switch ( wxattrs[arg] ) switch ( glattrs[arg] )
{ {
// Pixel format attributes
case WX_GL_BUFFER_SIZE: case WX_GL_BUFFER_SIZE:
format.setRgba(false); format.setRgba(false);
// I do not know how to set the buffer size, so fail // I do not know how to set the buffer size, so fail
@ -489,7 +550,7 @@ bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format)
return false; return false;
case WX_GL_MIN_RED: case WX_GL_MIN_RED:
format.setRedBufferSize(v*8); format.setRedBufferSize(v);
break; break;
case WX_GL_MIN_GREEN: case WX_GL_MIN_GREEN:
@ -532,17 +593,54 @@ bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format)
// can we somehow indicate if it's not supported? // can we somehow indicate if it's not supported?
break; break;
case WX_GL_MAJOR_VERSION:
format.setVersion ( v,0 );
break;
default: default:
wxLogDebug(wxT("Unsupported OpenGL attribute %d"), wxLogDebug(wxT("Unsupported OpenGL attribute %d"),
wxattrs[arg]); glattrs[arg]);
continue; continue;
} }
if ( !isBoolAttr ) { if ( !isBoolAttr )
{
if ( !v )
return false; // zero parameter
arg++;
}
}
for (int arg = 0; ctxattrs && ctxattrs[arg] != 0; arg++)
{
// indicates whether we have a boolean attribute
bool isBoolAttr = false;
int v = ctxattrs[arg+1];
switch ( ctxattrs[arg] )
{
// Context attributes
case WX_GL_MAJOR_VERSION:
format.setVersion ( v, format.minorVersion() );
break;
case WX_GL_MINOR_VERSION:
format.setVersion ( format.majorVersion(), v );
break;
case WX_GL_CORE_PROFILE:
format.setProfile(QGLFormat::CoreProfile);
break;
case wx_GL_COMPAT_PROFILE:
format.setProfile(QGLFormat::CompatibilityProfile);
break;
default:
wxLogDebug(wxT("Unsupported OpenGL attribute %d"),
ctxattrs[arg]);
continue;
}
if ( !isBoolAttr )
{
if ( !v ) if ( !v )
return false; // zero parameter return false; // zero parameter
arg++; arg++;
@ -553,23 +651,29 @@ bool wxGLCanvas::ConvertWXAttrsToQtGL(const int *wxattrs, QGLFormat &format)
} }
/* static */ /* static */
bool bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs)
wxGLCanvasBase::IsDisplaySupported(const int *attribList)
{ {
QGLFormat format; const int* attrsList = dispAttrs.GetGLAttrs();
if (!wxGLCanvas::ConvertWXAttrsToQtGL(attribList, format)) wxCHECK_MSG(attrsList, false, "wxGLAttributes object is empty.");
return false;
return QGLWidget(format).isValid(); return IsDisplaySupported(attrsList);
} }
/* static */ /* static */
bool bool wxGLCanvasBase::IsDisplaySupported(const int *attribList)
wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs)
{ {
wxLogError("Missing implementation of " + wxString(__FUNCTION__)); // Separate display/context attributes, set defaults.
return false; wxGLAttributes dispAttrs;
wxGLContextAttrs ctxAttrs;
if (!ParseAttribList(attribList, dispAttrs, &ctxAttrs))
return false;
QGLFormat format;
if (!wxGLCanvas::ConvertWXAttrsToQtGL(dispAttrs, ctxAttrs, format))
return false;
return QGLWidget(format).isValid();
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View file

@ -1830,6 +1830,11 @@ QPainter *wxWindowQt::QtGetPainter()
return m_qtPainter.get(); return m_qtPainter.get();
} }
bool wxWindowQt::QtCanPaintWithoutActivePainter() const
{
return false;
}
bool wxWindowQt::EnableTouchEvents(int eventsMask) bool wxWindowQt::EnableTouchEvents(int eventsMask)
{ {
wxCHECK_MSG( GetHandle(), false, "can't be called before creating the window" ); wxCHECK_MSG( GetHandle(), false, "can't be called before creating the window" );