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

Reply via email to