From 32ff31df1418e563aca5cbd5107dcf4fd1a49ead Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Tue, 6 Feb 2024 09:30:24 +0100 Subject: [PATCH] App: fix systematic black view 3D on macOS --- src/app/main.cpp | 5 +-- src/app/widget_occ_view.cpp | 63 ++++++++++++++++++++------------ src/app/widget_occ_view.h | 3 ++ src/app/widget_occ_view_impl.cpp | 39 +++++++++----------- 4 files changed, 61 insertions(+), 49 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index d7eed7ab..c71d8d04 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -409,6 +409,7 @@ static void initGui(GuiApplication* guiApp) if (!glVersion.isNull() && glVersion.majorVersion() >= 2) { // Requires at least OpenGL version >= 2.0 setFunctionCreateGraphicsDriver(&QOpenGLWidgetOccView::createCompatibleGraphicsDriver); IWidgetOccView::setCreator(&QOpenGLWidgetOccView::create); + QOpenGLWidgetOccView::staticInitialization(); } else { qWarning() << "Can't use QOpenGLWidget because OpenGL version is too old"; @@ -613,10 +614,6 @@ int main(int argc, char* argv[]) #endif // Configure and create Qt application object -#if defined(Q_OS_WIN) - // Never use ANGLE on Windows, since OCCT 3D Viewer does not expect this - QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL); -#endif QCoreApplication::setOrganizationName("Fougue Ltd"); QCoreApplication::setOrganizationDomain("www.fougue.pro"); QCoreApplication::setApplicationName("Mayo"); diff --git a/src/app/widget_occ_view.cpp b/src/app/widget_occ_view.cpp index f907f500..28045bb1 100644 --- a/src/app/widget_occ_view.cpp +++ b/src/app/widget_occ_view.cpp @@ -13,8 +13,10 @@ #include "occt_window.h" +#include #include #if OCC_VERSION_HEX >= 0x070600 +# include # include #endif @@ -45,13 +47,14 @@ IWidgetOccView* IWidgetOccView::create(const Handle_V3d_View& view, QWidget* par bool QOpenGLWidgetOccView_isCoreProfile(); void QOpenGLWidgetOccView_createOpenGlContext(std::function fnCallback); Handle_Graphic3d_GraphicDriver QOpenGLWidgetOccView_createCompatibleGraphicsDriver(); -bool QOpenGLWidgetOccView_wrapFrameBuffer(const Handle_Graphic3d_GraphicDriver&); -Graphic3d_Vec2i QOpenGLWidgetOccView_getDefaultframeBufferViewportSize(const Handle_Graphic3d_GraphicDriver&); +bool QOpenGLWidgetOccView_wrapFrameBuffer(const Handle_Graphic3d_CView&); +Graphic3d_Vec2i QOpenGLWidgetOccView_getDefaultframeBufferViewportSize(const Handle_Graphic3d_CView&); static Handle_Aspect_NeutralWindow createNativeWindow([[maybe_unused]] QWidget* widget) { auto window = new Aspect_NeutralWindow; + window->SetVirtual(true); // On non-Windows systems Aspect_Drawable is aliased to 'unsigned long' so can't init with nullptr Aspect_Drawable nativeWin = 0; #ifdef Q_OS_WIN @@ -65,6 +68,24 @@ static Handle_Aspect_NeutralWindow createNativeWindow([[maybe_unused]] QWidget* return window; } +// Returns QSurfaceFormat object suitable for QOpenGLWidgetOccView +static QSurfaceFormat createQSurfaceFormat() +{ + QSurfaceFormat glFormat; + glFormat.setDepthBufferSize(24); + glFormat.setStencilBufferSize(8); + if (QOpenGLWidgetOccView_isCoreProfile()) + glFormat.setVersion(4, 5); + + glFormat.setProfile( + QOpenGLWidgetOccView_isCoreProfile() ? + QSurfaceFormat::CoreProfile : + QSurfaceFormat::CompatibilityProfile + ); + + return glFormat; +} + QOpenGLWidgetOccView::QOpenGLWidgetOccView(const Handle_V3d_View& view, QWidget* parent) : QOpenGLWidget(parent), IWidgetOccView(view) @@ -75,24 +96,7 @@ QOpenGLWidgetOccView::QOpenGLWidgetOccView(const Handle_V3d_View& view, QWidget* this->setUpdatesEnabled(true); this->setUpdateBehavior(QOpenGLWidget::NoPartialUpdate); - QSurfaceFormat glFormat; - glFormat.setDepthBufferSize(24); - glFormat.setStencilBufferSize(8); - if (QOpenGLWidgetOccView_isCoreProfile()) - glFormat.setVersion(4, 5); - - glFormat.setProfile( - QOpenGLWidgetOccView_isCoreProfile() ? - QSurfaceFormat::CoreProfile : - QSurfaceFormat::CompatibilityProfile - ); - // Use QtOccFrameBuffer fallback - // To request sRGBColorSpace colorspace to meet OCCT expectations then consider code below: - // #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) - // glFormat.setColorSpace(QSurfaceFormat::sRGBColorSpace); - // this->setTextureFormat(GL_SRGB8_ALPHA8); - // #endif - this->setFormat(glFormat); + this->setFormat(createQSurfaceFormat()); } void QOpenGLWidgetOccView::redraw() @@ -110,6 +114,19 @@ Handle_Graphic3d_GraphicDriver QOpenGLWidgetOccView::createCompatibleGraphicsDri return QOpenGLWidgetOccView_createCompatibleGraphicsDriver(); } +void QOpenGLWidgetOccView::staticInitialization() +{ +#if defined(Q_OS_WIN) + // Never use ANGLE on Windows, since OCCT 3D Viewer does not expect this + QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL); +#endif + +#ifdef Q_OS_MAC + // Suppress Qt warning "QCocoaGLContext: Falling back to unshared context" + QSurfaceFormat::setDefaultFormat(createQSurfaceFormat()); +#endif +} + void QOpenGLWidgetOccView::initializeGL() { const QRect wrect = this->rect(); @@ -129,12 +146,12 @@ void QOpenGLWidgetOccView::paintGL() if (!this->v3dView()->Window()) return; - const Handle(Graphic3d_GraphicDriver)& driver = this->v3dView()->Viewer()->Driver(); - if (!QOpenGLWidgetOccView_wrapFrameBuffer(driver)) + const Handle_Graphic3d_CView& cview = this->v3dView()->View(); + if (!QOpenGLWidgetOccView_wrapFrameBuffer(cview)) return; Graphic3d_Vec2i viewSizeOld; - const Graphic3d_Vec2i viewSizeNew = QOpenGLWidgetOccView_getDefaultframeBufferViewportSize(driver); + const Graphic3d_Vec2i viewSizeNew = QOpenGLWidgetOccView_getDefaultframeBufferViewportSize(cview); auto window = Handle_Aspect_NeutralWindow::DownCast(this->v3dView()->Window()); window->Size(viewSizeOld.x(), viewSizeOld.y()); if (viewSizeNew != viewSizeOld) { diff --git a/src/app/widget_occ_view.h b/src/app/widget_occ_view.h index 0f7f3e8a..e172dfc7 100644 --- a/src/app/widget_occ_view.h +++ b/src/app/widget_occ_view.h @@ -23,6 +23,8 @@ namespace Mayo { // IWidgetOccView does not handle input devices interaction like keyboard and mouse class IWidgetOccView { public: + virtual ~IWidgetOccView() = default; + const Handle_V3d_View& v3dView() const { return m_view; } virtual void redraw() = 0; @@ -54,6 +56,7 @@ class QOpenGLWidgetOccView : public QOpenGLWidget, public IWidgetOccView { static QOpenGLWidgetOccView* create(const Handle_V3d_View& view, QWidget* parent); static Handle_Graphic3d_GraphicDriver createCompatibleGraphicsDriver(); + static void staticInitialization(); protected: // -- QOpenGLWidget diff --git a/src/app/widget_occ_view_impl.cpp b/src/app/widget_occ_view_impl.cpp index d85711ce..79d4d8b7 100644 --- a/src/app/widget_occ_view_impl.cpp +++ b/src/app/widget_occ_view_impl.cpp @@ -13,6 +13,8 @@ # include # include # include +# include +# include #endif #include @@ -66,11 +68,17 @@ class QtOccFrameBuffer : public OpenGl_FrameBuffer { } }; +Handle_OpenGl_Context QOpenGLWidgetOccView_getOpenGlContext(const Handle_Graphic3d_CView& view) +{ + Handle_OpenGl_View glView = Handle_OpenGl_View::DownCast(view); + return glView->GlWindow()->GetGlContext(); +} + } // namespace bool QOpenGLWidgetOccView_isCoreProfile() { - return false; + return true; } void QOpenGLWidgetOccView_createOpenGlContext(std::function fnCallback) @@ -94,33 +102,20 @@ Handle_Graphic3d_GraphicDriver QOpenGLWidgetOccView_createCompatibleGraphicsDriv gfxDriver->ChangeOptions().buffersOpaqueAlpha = true; // Offscreen FBOs should be always used gfxDriver->ChangeOptions().useSystemBuffer = false; -#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) - Message::SendWarning( - "Warning! Qt 5.10+ is required for sRGB setup.\n" - "Colors in 3D Viewer might look incorrect (Qt " QT_VERSION_STR " is used).\n" - ); - gfxDriver->ChangeOptions().sRGBDisable = true; -#endif - return gfxDriver; } -bool QOpenGLWidgetOccView_wrapFrameBuffer(const Handle_Graphic3d_GraphicDriver& gfxDriver) +bool QOpenGLWidgetOccView_wrapFrameBuffer(const Handle_Graphic3d_CView& view) { // Wrap FBO created by QOpenGLWidget - auto driver = Handle_OpenGl_GraphicDriver::DownCast(gfxDriver); - if (!driver) - return false; - - const Handle_OpenGl_Context& glCtx = driver->GetSharedContext(); - Handle_OpenGl_FrameBuffer defaultFbo = glCtx->DefaultFrameBuffer(); + Handle_OpenGl_Context glContext = QOpenGLWidgetOccView_getOpenGlContext(view); + Handle_OpenGl_FrameBuffer defaultFbo = glContext->DefaultFrameBuffer(); if (!defaultFbo) { - //defaultFbo = new OpenGl_FrameBuffer; defaultFbo = new QtOccFrameBuffer; - glCtx->SetDefaultFrameBuffer(defaultFbo); + glContext->SetDefaultFrameBuffer(defaultFbo); } - if (!defaultFbo->InitWrapper(glCtx)) { + if (!defaultFbo->InitWrapper(glContext)) { defaultFbo.Nullify(); Message::SendFail() << "Default FBO wrapper creation failed"; return false; @@ -129,10 +124,10 @@ bool QOpenGLWidgetOccView_wrapFrameBuffer(const Handle_Graphic3d_GraphicDriver& return true; } -Graphic3d_Vec2i QOpenGLWidgetOccView_getDefaultframeBufferViewportSize(const Handle_Graphic3d_GraphicDriver& gfxDriver) +Graphic3d_Vec2i QOpenGLWidgetOccView_getDefaultframeBufferViewportSize(const Handle_Graphic3d_CView& view) { - auto driver = Handle_OpenGl_GraphicDriver::DownCast(gfxDriver); - return driver->GetSharedContext()->DefaultFrameBuffer()->GetVPSize(); + Handle_OpenGl_Context glContext = QOpenGLWidgetOccView_getOpenGlContext(view); + return glContext->DefaultFrameBuffer()->GetVPSize(); } #endif // OCC_VERSION_HEX >= 0x070600