Hi, I have created a OSG-Qt Widget (based on the QOSGWidget example) that uses threaded rendering so the rendering doesn't block Qt's main thread. This works fine on my own achine, which has an ATI card (and never seems to use the GPU according to the StasHandler). However, one of my co-developers has an NVIDIA card and for some reason the osg::GraphicsContext::createGraphicsContext call we use returns NULL on his machine.
I have added the class below. The line that seems to cause the problem is at the bottom of the cpp file (at the end of this mail) Is there anything I missed there? I hope someone has encountered and solved this problem before... Regards, Job Mulder //////////////////////////// h file /////////////////////////// #ifndef OSGVIEWERWIDGET_H #define OSGVIEWERWIDGET_H class QPaintEvent; class QResizeEvent; class QCloseEvent; class QShowEvent; class QHideEvent; #include <osgViewer/Viewer> #include <osgViewer/GraphicsWindow> #include <QtOpenGL/QGLWidget> #include <QThread> #include <QSize> class OsgViewerWidget : public osgViewer::Viewer, public QGLWidget { private: class OsgWidgetThread : public QThread { public: OsgWidgetThread(OsgViewerWidget* parent); protected: virtual void run(); OsgViewerWidget* m_osgWidget; }; public: OsgViewerWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); virtual ~OsgViewerWidget(); virtual void updateCamera(); virtual void paintEvent(QPaintEvent*); virtual void resizeEvent(QResizeEvent*); virtual void closeEvent(QCloseEvent*); virtual void showEvent(QShowEvent*); // virtual void hideEvent(QHideEvent*); void threadMain(); protected: virtual void handleStateUpdatesThreaded(void); virtual void initializeThreaded(void); bool isThreadInitComplete() const; void createContext(); osgViewer::GraphicsWindow* getGraphicsWindow() const; OsgWidgetThread m_thread; volatile bool m_terminating; volatile bool m_resize; volatile bool m_threadStarted; QSize m_size; osg::ref_ptr<osgViewer::GraphicsWindow> m_graphicsWindow; }; #endif // OSGVIEWERWIDGET_H //////////////////////////// cpp file /////////////////////////// #include "osgviewerwidget.h" #include <osgViewer/ViewerEventHandlers> #include <osgViewer/api/Win32/GraphicsWindowWin32> typedef osgViewer::GraphicsWindowWin32::WindowData WindowData; #include <osgGA/TrackballManipulator> #include <QResizeEvent> #include <QCloseEvent> #include <QShowEvent> /*! \class OsgViewerWidget::OsgWidgetThread \brief A simple thread handler for the OsgViewerWidget. It starts the thread function of OsgViewerWidget. */ /*! \brief Constructor, does not start anything, just initializes The thread is started by OsgViewerWidget. */ OsgViewerWidget::OsgWidgetThread::OsgWidgetThread(OsgViewerWidget* parent) : QThread(parent) , m_osgWidget(parent) { } /*! \brief The main function of the OsgWidgetThread. \details The function is just a wrapper for the OsgViewerWidget main thread function */ void OsgViewerWidget::OsgWidgetThread::run() { m_osgWidget->threadMain(); } /*! \class OsgViewerWidget \brief An OSG viewer contained in a Qt Widget. The class handles the actual drawing of the scenegraph in a separate thread. Any inheriting classes should make sure to do the same by overloading the \a handleStateUpdatesThreaded function and calling the base function for the standard state updates such as resizing and closing */ /*! \brief Constructor, initializes the widget and starts the render thread */ OsgViewerWidget::OsgViewerWidget(QWidget* parent, Qt::WindowFlags f) : QGLWidget( parent, 0, f ) , m_thread(this) , m_terminating(false) , m_resize(false) , m_threadStarted(false) { setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_PaintUnclipped); setAttribute(Qt::WA_TranslucentBackground); setFocusPolicy(Qt::ClickFocus); setAutoFillBackground(false); setThreadingModel(osgViewer::Viewer::SingleThreaded); // we already handle the multi-threading ourselves } /*! \brief Destructor, stops the render thread if it was still running */ OsgViewerWidget::~OsgViewerWidget() { m_terminating = true; m_thread.wait(); } /*! \brief Start the render thread when showing the window */ void OsgViewerWidget::showEvent(QShowEvent*) { m_thread.start(); } /*! \brief Wait for thread initialization to complete */ bool OsgViewerWidget::isThreadInitComplete() const { return m_threadStarted; } /*! \brief Update the camera, usually to match a new window size */ void OsgViewerWidget::updateCamera() { getCamera()->setViewport(new osg::Viewport(0,0,width(),height())); getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(width())/static_cast<double>(height()), 1.0f, 10000.0f); getCamera()->setGraphicsContext(m_graphicsWindow.get()); } /*! \brief The paint event is deliberately empty so Qt does not corrupt the display All actual painting is done in the render thread */ void OsgViewerWidget::paintEvent(QPaintEvent* event) { } /*! \brief Handle the resize event by scheduling a threaded resize */ void OsgViewerWidget::resizeEvent(QResizeEvent* event) { m_size = event->size(); m_resize = true; } /*! \brief Handle the close event by ending the render thread and waiting for it */ void OsgViewerWidget::closeEvent(QCloseEvent* event) { m_terminating = true; m_thread.wait(); event->accept(); } /*! \brief Update state change messages coming from other threads in the render thread This function handles things like resize events in the render thread so they're thread-safe and don't interfere with the actual drawing. Subclasses should overload this function and call it if they want to define their own thread-safe handling. If the events handled by the base function need to be handled by the subclass, make sure to handle them before calling the function and make sure to update the relevant boolean. Currently only \a m_resize is checked by this function */ void OsgViewerWidget::handleStateUpdatesThreaded(void) { if (m_resize) { osgViewer::GraphicsWindow* gw = m_graphicsWindow.get(); if (gw) { gw->getEventQueue()->windowResize(0, 0, m_size.width(), m_size.height() ); gw->resized(0, 0, m_size.width(), m_size.height()); } updateCamera(); m_resize = false; } } /*! \brief This function performs the user-specific initialization of the widget Typically this means setting up a statshandler and camera manipulator, which is what the default implementation does. */ void OsgViewerWidget::initializeThreaded(void) { setCameraManipulator(new osgGA::TrackballManipulator); addEventHandler(new osgViewer::StatsHandler); } /*! \brief The main render thread of the widget. \todo Maybe bundle these for multiple widgets to reduce thread-count? */ void OsgViewerWidget::threadMain() { createContext(); initializeThreaded(); m_threadStarted = true; while(!m_terminating) { handleStateUpdatesThreaded(); frame(); QThread::yieldCurrentThread(); } } /*! \brief Return the graphics window of the OSG part */ osgViewer::GraphicsWindow* OsgViewerWidget::getGraphicsWindow() const { return m_graphicsWindow.get(); } /*! \brief Create the display context for the OSG viewer This is based on the QOSGWidget example code and may include some redundant code. */ void OsgViewerWidget::createContext() { osg::DisplaySettings* ds = osg::DisplaySettings::instance(); osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; traits->readDISPLAY(); if (traits->displayNum<0) traits->displayNum = 0; traits->windowName = "osgViewerQt"; traits->screenNum = 0; traits->x = x(); traits->y = y(); traits->width = width(); traits->height = height(); traits->alpha = ds->getMinimumNumAlphaBits(); traits->stencil = ds->getMinimumNumStencilBits(); traits->windowDecoration = false; traits->doubleBuffer = true; traits->sharedContext = 0; traits->sampleBuffers = ds->getMultiSamples(); traits->samples = ds->getNumMultiSamples(); traits->inheritedWindowData = new WindowData(winId()); if (ds->getStereo()) { switch(ds->getStereoMode()) { case(osg::DisplaySettings::QUAD_BUFFER): traits->quadBufferStereo = true; break; case(osg::DisplaySettings::VERTICAL_INTERLACE): case(osg::DisplaySettings::CHECKERBOARD): case(osg::DisplaySettings::HORIZONTAL_INTERLACE): traits->stencil = 8; break; default: break; } } osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get()); m_graphicsWindow = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get()); } _______________________________________________ osg-users mailing list osg-users@lists.openscenegraph.org http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org