From 9eebb2eb231a66c45bef0bc02ec722bc91031d14 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 21 Apr 2010 17:16:13 +0000 Subject: [PATCH] From Ulrich Hertlien with little bits from Robert Osfield and Chris Hanson, added provisionl support for controlling sync to vblank. --- include/osgViewer/GraphicsWindow | 8 ++ include/osgViewer/ViewerEventHandlers | 8 +- .../osgViewer/api/Carbon/GraphicsWindowCarbon | 9 +- .../osgViewer/api/Win32/GraphicsWindowWin32 | 5 +- src/osgViewer/GraphicsWindowCarbon.cpp | 99 ++++++++-------- src/osgViewer/GraphicsWindowWin32.cpp | 109 ++++++++++++------ src/osgViewer/GraphicsWindowX11.cpp | 8 ++ src/osgViewer/Viewer.cpp | 5 +- 8 files changed, 160 insertions(+), 91 deletions(-) diff --git a/include/osgViewer/GraphicsWindow b/include/osgViewer/GraphicsWindow index 6b3384f6e..bea0d895a 100644 --- a/include/osgViewer/GraphicsWindow +++ b/include/osgViewer/GraphicsWindow @@ -134,6 +134,14 @@ class OSGVIEWER_EXPORT GraphicsWindow : public osg::GraphicsContext, public osgG /** Create a new mouse cursor from the usual bitmap data.*/ //virtual MouseCursor createCursor(const char *data, const char *mask, unsigned w, unsigned h, unsigned hotx, unsigned hoty) { osg::notify(osg::NOTICE)<<"GraphicsWindow::createCursor(..) not implemented."<vsync : true; } + public: /** Return whether a valid and usable GraphicsContext has been created.*/ diff --git a/include/osgViewer/ViewerEventHandlers b/include/osgViewer/ViewerEventHandlers index 3426faeb6..06910a9ec 100644 --- a/include/osgViewer/ViewerEventHandlers +++ b/include/osgViewer/ViewerEventHandlers @@ -68,7 +68,9 @@ class OSGVIEWER_EXPORT HelpHandler : public osgGA::GUIEventHandler }; -/** Event handler for adding on screen stats reporting to Viewers.*/ +/** + * Event handler for adding on screen stats reporting to Viewers. + */ class OSGVIEWER_EXPORT StatsHandler : public osgGA::GUIEventHandler { public: @@ -91,6 +93,9 @@ class OSGVIEWER_EXPORT StatsHandler : public osgGA::GUIEventHandler void setKeyEventPrintsOutStats(int key) { _keyEventPrintsOutStats = key; } int getKeyEventPrintsOutStats() const { return _keyEventPrintsOutStats; } + void setKeyEventToggleVSync(int key) { _keyEventToggleVSync = key; } + int getKeyEventToggleVSync() const { return _keyEventToggleVSync; } + double getBlockMultiplier() const { return _blockMultiplier; } void reset(); @@ -123,6 +128,7 @@ class OSGVIEWER_EXPORT StatsHandler : public osgGA::GUIEventHandler int _keyEventTogglesOnScreenStats; int _keyEventPrintsOutStats; + int _keyEventToggleVSync; int _statsType; diff --git a/include/osgViewer/api/Carbon/GraphicsWindowCarbon b/include/osgViewer/api/Carbon/GraphicsWindowCarbon index 1a7cb02ae..693e53476 100644 --- a/include/osgViewer/api/Carbon/GraphicsWindowCarbon +++ b/include/osgViewer/api/Carbon/GraphicsWindowCarbon @@ -36,7 +36,8 @@ class GraphicsWindowCarbon : public osgViewer::GraphicsWindow, public osgViewer: _initialized(false), _realized(false), _ownsWindow(true), - _currentCursor(RightArrowCursor) + _currentCursor(RightArrowCursor), + _currentVSync(true) { _traits = traits; @@ -108,7 +109,10 @@ class GraphicsWindowCarbon : public osgViewer::GraphicsWindow, public osgViewer: virtual void setWindowName (const std::string & name); virtual void useCursor(bool cursorOn); virtual void setCursor(MouseCursor mouseCursor); - + + /** Set sync-to-vblank. */ + virtual void setSyncToVBlank(bool on); + WindowRef getNativeWindowRef() { return _window; } bool handleMouseEvent(EventRef theEvent); @@ -168,6 +172,7 @@ class GraphicsWindowCarbon : public osgViewer::GraphicsWindow, public osgViewer: bool _closeRequested; UInt32 _lastModifierKeys; MouseCursor _currentCursor; + bool _currentVSync; }; } diff --git a/include/osgViewer/api/Win32/GraphicsWindowWin32 b/include/osgViewer/api/Win32/GraphicsWindowWin32 index 548f7f924..927c6a236 100644 --- a/include/osgViewer/api/Win32/GraphicsWindowWin32 +++ b/include/osgViewer/api/Win32/GraphicsWindowWin32 @@ -86,7 +86,10 @@ class OSGVIEWER_EXPORT GraphicsWindowWin32 : public osgViewer::GraphicsWindow, p /** Set mouse cursor to a specific shape.*/ virtual void setCursor(MouseCursor cursor); - + + /** Set sync-to-vblank. */ + virtual void setSyncToVBlank(bool on); + /** Handle a native (Win32) windowing event as received from the system */ virtual LRESULT handleNativeWindowingEvent( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); diff --git a/src/osgViewer/GraphicsWindowCarbon.cpp b/src/osgViewer/GraphicsWindowCarbon.cpp index 12b345f35..d5368d253 100644 --- a/src/osgViewer/GraphicsWindowCarbon.cpp +++ b/src/osgViewer/GraphicsWindowCarbon.cpp @@ -345,19 +345,18 @@ void GraphicsWindowCarbon::installEventHandler() { bool GraphicsWindowCarbon::realizeImplementation() { - if (!_initialized) init(); if (!_initialized) return false; if (!_traits) return false; - - OSG_NOTIFY(osg::INFO) << "GraphicsWindowCarbon:: realizeIMplementation" << std::endl; + + osg::notify(osg::INFO) << "GraphicsWindowCarbon::realizeImplementation" << std::endl; setWindowDecoration(_traits->windowDecoration); useCursor(_traits->useCursor); // move the window to the right screen DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); - int screenLeft(0), screenTop(0); + int screenLeft = 0, screenTop = 0; if (wsi) { wsi->getScreenTopLeft((*_traits), screenLeft, screenTop); @@ -377,10 +376,10 @@ bool GraphicsWindowCarbon::realizeImplementation() err = CreateNewWindow(kDocumentWindowClass, attr, &bounds, &_window); if (err) { - OSG_NOTIFY(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation() failed creating a window: " << err << std::endl; + OSG_NOTIFY(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation: failed to create window: " << err << std::endl; return false; } else { - OSG_NOTIFY(osg::INFO) << "GraphicsWindowCarbon::realizeImplementation() - window created with bounds(" << bounds.top << ", " << bounds.left << ", " << bounds.bottom << ", " << bounds.right << ")" << std::endl; + OSG_NOTIFY(osg::INFO) << "GraphicsWindowCarbon::realizeImplementation: window created with bounds(" << bounds.top << ", " << bounds.left << ", " << bounds.bottom << ", " << bounds.right << ")" << std::endl; } } else { @@ -407,10 +406,8 @@ bool GraphicsWindowCarbon::realizeImplementation() } _context = aglCreateContext (_pixelFormat, sharedContextCarbon); - - if (!_context) { - OSG_NOTIFY(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation failed creating a context: " << aglGetError() << std::endl; + OSG_NOTIFY(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation: failed to create context: " << aglGetError() << std::endl; return false; } @@ -441,17 +438,18 @@ bool GraphicsWindowCarbon::realizeImplementation() #endif if (cgerr != kCGLNoError ) { - OSG_NOTIFY(osg::INFO) << "GraphicsWindowCarbon:: Multi-threaded OpenGL Execution not available" << std::endl; + OSG_NOTIFY(osg::INFO) << "GraphicsWindowCarbon::realizeImplementation: multi-threaded OpenGL Execution not available" << std::endl; } } - + InitCursor(); - - //enable vsync + + // enable vsync if (_traits->vsync) { GLint swap = 1; aglSetInteger (_context, AGL_SWAP_INTERVAL, &swap); } + _currentVSync = _traits->vsync; _realized = true; return _realized; @@ -485,7 +483,7 @@ void GraphicsWindowCarbon::closeImplementation() // OSG_NOTIFY(osg::INFO) << "GraphicsWindowCarbon::closeImplementation" << std::endl; _valid = false; _realized = false; - + // there's a possibility that the MenubarController is destructed already, so prevent a crash: MenubarController* mbc = MenubarController::instance(); if (mbc) mbc->detachWindow(this); @@ -495,7 +493,7 @@ void GraphicsWindowCarbon::closeImplementation() aglDestroyPixelFormat(_pixelFormat); _pixelFormat = NULL; } - + if (_context) { aglSetDrawable(_context, NULL); @@ -503,7 +501,7 @@ void GraphicsWindowCarbon::closeImplementation() aglDestroyContext(_context); _context = NULL; } - + if (_ownsWindow && _window) DisposeWindow(_window); _window = NULL; } @@ -512,6 +510,16 @@ void GraphicsWindowCarbon::closeImplementation() void GraphicsWindowCarbon::swapBuffersImplementation() { + // check for vsync change + if (_traits.valid() && _traits->vsync != _currentVSync) + { + const bool on = _traits->vsync; + GLint swap = (on ? 1 : 0); + aglSetInteger (_context, AGL_SWAP_INTERVAL, &swap); + osg::notify(osg::NOTICE) << "GraphicsWindowCarbon: VSync=" << (on ? "on" : "off") << std::endl; + _currentVSync = on; + } + aglSwapBuffers(_context); } @@ -566,7 +574,7 @@ bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent) if (mouseButton==3) mouseButton = 2; else if (mouseButton==2) mouseButton = 3; - // check tablet pointer device and map it to a musebutton + // check tablet pointer device and map it to a mouse button TabletProximityRec theTabletRecord; // The Tablet Proximity Record // Extract the Tablet Proximity reccord from the event. if(noErr == GetEventParameter(theEvent, kEventParamTabletProximityRec, @@ -585,7 +593,7 @@ bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent) pointerType = osgGA::GUIEventAdapter::PUCK; break; - case 3: //eraser + case 3: // eraser pointerType = osgGA::GUIEventAdapter::ERASER; break; @@ -615,8 +623,8 @@ bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent) { case kEventMouseDown: { - float mx =wheresMyMouse.h; - float my =wheresMyMouse.v; + float mx = wheresMyMouse.h; + float my = wheresMyMouse.v; transformMouseXY(mx, my); lastEmulatedMouseButton = 0; @@ -641,8 +649,8 @@ bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent) break; case kEventMouseUp: { - float mx =wheresMyMouse.h; - float my =wheresMyMouse.v; + float mx = wheresMyMouse.h; + float my = wheresMyMouse.v; transformMouseXY(mx, my); if (lastEmulatedMouseButton > 0) { getEventQueue()->mouseButtonRelease(mx, my, lastEmulatedMouseButton); @@ -662,11 +670,10 @@ bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent) sizeof(TabletPointRec), NULL, (void *)&theTabletRecord)) { getEventQueue()->penPressure(theTabletRecord.pressure / 65535.0f); - } - float mx =wheresMyMouse.h; - float my =wheresMyMouse.v; + float mx = wheresMyMouse.h; + float my = wheresMyMouse.v; transformMouseXY(mx, my); getEventQueue()->mouseMotion(mx, my); } @@ -705,23 +712,23 @@ bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent) case 11: { enum - { + { kEventParamMouseWheelSmoothVerticalDelta = 'saxy', // typeSInt32 kEventParamMouseWheelSmoothHorizontalDelta = 'saxx' // typeSInt32 - }; + }; SInt32 scroll_delta_x = 0; SInt32 scroll_delta_y = 0; OSErr err = noErr; err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothVerticalDelta, typeLongInteger, NULL, sizeof(scroll_delta_y), NULL, &scroll_delta_y ); err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothHorizontalDelta, typeLongInteger, NULL, sizeof(scroll_delta_x), NULL, &scroll_delta_x ); - + if ((scroll_delta_x != 0) || (scroll_delta_y != 0)) { getEventQueue()->mouseScroll2D( scroll_delta_x, scroll_delta_y); } } break; - + default: return false; } @@ -759,15 +766,16 @@ bool GraphicsWindowCarbon::handleKeyboardEvent(EventRef theEvent) case kEventRawKeyDown: case kEventRawKeyRepeat: { + //osg::notify(osg::INFO) << "GraphicsWindowCarbon::keyPress Up" << std::endl; //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask); - OSG_NOTIFY(osg::INFO) << "GraphicsWindowCarbon::keyPress" << std::endl; + //OSG_NOTIFY(osg::INFO) << "GraphicsWindowCarbon::keyPress" << std::endl; getEventQueue()->keyPress(keychar); break; } case kEventRawKeyUp: { - OSG_NOTIFY(osg::INFO) << "GraphicsWindowCarbon::keyPress" << std::endl; + //OSG_NOTIFY(osg::INFO) << "GraphicsWindowCarbon::keyPress" << std::endl; //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask); getEventQueue()->keyRelease(keychar); break; @@ -940,34 +948,24 @@ void GraphicsWindowCarbon::grabFocus() void GraphicsWindowCarbon::grabFocusIfPointerInWindow() { // TODO: implement - OSG_NOTIFY(osg::ALWAYS) << "GraphicsWindowCarbon::grabFocusIfPointerInWindow" << std::endl; + OSG_NOTIFY(osg::ALWAYS) << "GraphicsWindowCarbon::grabFocusIfPointerInWindow: not implemented" << std::endl; } void GraphicsWindowCarbon::useCursor(bool cursorOn) { - if (_traits.valid()) _traits->useCursor = cursorOn; DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); if (wsi == NULL) { - OSG_NOTIFY(osg::WARN) << "GraphicsWindowCarbon::useCursor :: could not get OSXCarbonWindowingSystemInterface" << std::endl; + OSG_NOTIFY(osg::WARN) << "GraphicsWindowCarbon::useCursor: could not get OSXCarbonWindowingSystemInterface" << std::endl; return; } CGDirectDisplayID displayId = wsi->getDisplayID((*_traits)); - CGDisplayErr err = kCGErrorSuccess; - switch (cursorOn) - { - case true: - err = CGDisplayShowCursor(displayId); - break; - case false: - err = CGDisplayHideCursor(displayId); - break; - } + CGDisplayErr err = (cursorOn ? CGDisplayShowCursor(displayId) : CGDisplayHideCursor(displayId)); if (err != kCGErrorSuccess) { - OSG_NOTIFY(osg::WARN) << "GraphicsWindowCarbon::useCursor failed with " << err << std::endl; + OSG_NOTIFY(osg::WARN) << "GraphicsWindowCarbon::useCursor: failed with " << err << std::endl; } } @@ -975,9 +973,10 @@ void GraphicsWindowCarbon::useCursor(bool cursorOn) // FIXME: I used deprecated functions, but don't know if there are any substitutable newer functions... void GraphicsWindowCarbon::setCursor(MouseCursor mouseCursor) { - UInt32 cursor; if (_currentCursor == mouseCursor) return; + + UInt32 cursor; switch (mouseCursor) { case NoCursor: @@ -1009,6 +1008,12 @@ void GraphicsWindowCarbon::setCursor(MouseCursor mouseCursor) ShowCursor(); } +void GraphicsWindowCarbon::setSyncToVBlank(bool on) +{ + if (_traits.valid()) { + _traits->vsync = on; + } +} void GraphicsWindowCarbon::setWindowName (const std::string& name) { @@ -1026,7 +1031,7 @@ void GraphicsWindowCarbon::requestWarpPointer(float x,float y) DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); if (wsi == NULL) { - OSG_NOTIFY(osg::WARN) << "GraphicsWindowCarbon::useCursor :: could not get OSXCarbonWindowingSystemInterface" << std::endl; + OSG_NOTIFY(osg::WARN) << "GraphicsWindowCarbon::useCursor: could not get OSXCarbonWindowingSystemInterface" << std::endl; return; } diff --git a/src/osgViewer/GraphicsWindowWin32.cpp b/src/osgViewer/GraphicsWindowWin32.cpp index e5971661e..8b71e7c40 100644 --- a/src/osgViewer/GraphicsWindowWin32.cpp +++ b/src/osgViewer/GraphicsWindowWin32.cpp @@ -1778,46 +1778,53 @@ bool GraphicsWindowWin32::realizeImplementation() init(); if (!_initialized) return false; } - { - - if (_traits.valid() && _traits->sharedContext) - { - GraphicsHandleWin32* graphicsHandleWin32 = dynamic_cast(_traits->sharedContext); - if (graphicsHandleWin32) - { - struct RestoreContext - { - RestoreContext() - { - _hdc = wglGetCurrentDC(); - _hglrc = wglGetCurrentContext(); - } - ~RestoreContext() - { - if (_hdc) - { - wglMakeCurrent(_hdc,_hglrc); - } - } - protected: - HDC _hdc; - HGLRC _hglrc; - } restoreContext; - - _realized = true; - bool result = makeCurrent(); - _realized = false; - if (!result) + if (_traits.valid() && (_traits->sharedContext || _traits->vsync)) + { + // make context current so we can test capabilities and set up context sharing + struct RestoreContext + { + RestoreContext() + { + _hdc = wglGetCurrentDC(); + _hglrc = wglGetCurrentContext(); + } + ~RestoreContext() + { + if (_hdc) { - return false; - } - if (!wglShareLists(graphicsHandleWin32->getWGLContext(), getWGLContext())) - { - reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to share OpenGL context", _traits->screenNum, ::GetLastError()); - return false; + wglMakeCurrent(_hdc,_hglrc); } } + protected: + HDC _hdc; + HGLRC _hglrc; + } restoreContext; + + _realized = true; + bool result = makeCurrent(); + _realized = false; + + if (!result) + { + return false; + } + + // set up sharing of contexts if required + GraphicsHandleWin32* graphicsHandleWin32 = dynamic_cast(_traits->sharedContext); + if (graphicsHandleWin32) + { + if (!wglShareLists(graphicsHandleWin32->getWGLContext(), getWGLContext())) + { + reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to share OpenGL context", _traits->screenNum, ::GetLastError()); + return false; + } + } + + // if vysnc should be on then enable it. + if (_traits->vsync) + { + setSyncToVBlank(_traits->vsync); } } @@ -2164,6 +2171,36 @@ HCURSOR GraphicsWindowWin32::getOrCreateCursor(MouseCursor mouseCursor) return _mouseCursorMap[mouseCursor]; } +void GraphicsWindowWin32::setSyncToVBlank( bool on ) +{ + if (_traits.valid()) + { + _traits->vsync = on; + } + +#if 0 + // we ought to properly check if the extension is listed as supported rather than just + // if the function pointer resolves through wglGetProcAddress, but in practice everything + // supports this extension + typedef BOOL (APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int ); + PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0; + + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" ); + if( wglSwapIntervalEXT ) + { + int swapInterval = (on ? 1 : 0); + wglSwapIntervalEXT(swapInterval); + OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank " << (on ? "on" : "off") << std::endl; + } + else + { + OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not supported" << std::endl; + } +#else + OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not yet implemented."<< std::endl; +#endf +} + void GraphicsWindowWin32::adaptKey( WPARAM wParam, LPARAM lParam, int& keySymbol, unsigned int& modifierMask ) { modifierMask = 0; diff --git a/src/osgViewer/GraphicsWindowX11.cpp b/src/osgViewer/GraphicsWindowX11.cpp index caa2a8ef8..31d442411 100644 --- a/src/osgViewer/GraphicsWindowX11.cpp +++ b/src/osgViewer/GraphicsWindowX11.cpp @@ -1066,6 +1066,14 @@ void GraphicsWindowX11::swapBuffersImplementation() eglSwapBuffers( _eglDisplay, _eglSurface ); checkEGLError("after eglSwapBuffers()"); #else +#if 0 + if (_traits.valid() && _traits->vsync) { + + unsigned int counter; + glXGetVideoSyncSGI(&counter); + glXWaitVideoSyncSGI(1, 0, &counter); + } +#endif glXSwapBuffers( _display, _window ); #endif diff --git a/src/osgViewer/Viewer.cpp b/src/osgViewer/Viewer.cpp index f0a55a086..10f71ddce 100644 --- a/src/osgViewer/Viewer.cpp +++ b/src/osgViewer/Viewer.cpp @@ -211,13 +211,11 @@ Viewer::~Viewer() { //OSG_NOTIFY(osg::NOTICE)<<"Viewer::~Viewer()"<