/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #ifndef OSG_GRAPHICSCONTEXT #define OSG_GRAPHICSCONTEXT 1 #include #include #include #include namespace osg { // forward declare osg::Camera class Camera; /** Base class for providing Windowing API agnostic access to creating and managing graphics context.*/ class OSG_EXPORT GraphicsContext : public Object { public: struct OSG_EXPORT ScreenIdentifier { ScreenIdentifier(); ScreenIdentifier(int in_screenNum); ScreenIdentifier(const std::string& in_hostName,int in_displayNum, int in_screenNum); /** Return the display name in the form hostName::displayNum:screenNum. */ std::string displayName() const; /** Read the DISPLAY environmental variable, and set the ScreenIdentifier accordingly. * Note, if either of displayNum or screenNum are not defined then -1 is set respectively to * signify that this parameter has not been set. When parameters are undefined one can call * call setUndefinedScreenDetailsToDefaultScreen() after readDISPLAY() to ensure valid values. */ void readDISPLAY(); /** Set the screenIndentifier from the displayName string. * Note, if either of displayNum or screenNum are not defined then -1 is set to * signify that this parameter has not been set. When parameters are undefined one can call * call setUndefinedScreenDetailsToDefaultScreen() after readDISPLAY() to ensure valid values. */ void setScreenIdentifier(const std::string& displayName); /** Set any undefined displayNum or screenNum values (i.e. -1) to the default display & screen of 0 respectively.*/ void setUndefinedScreenDetailsToDefaultScreen() { if (displayNum<0) displayNum = 0; if (screenNum<0) screenNum = 0; } std::string hostName; int displayNum; int screenNum; }; /** GraphicsContext Traits object provides the specification of what type of graphics context is required.*/ struct OSG_EXPORT Traits : public osg::Referenced, public ScreenIdentifier { Traits(DisplaySettings* ds=0); // graphics context original and size int x; int y; int width; int height; // provide a hint as to which WindowingSystemInterface implementation to use, i.e. "X11", "Win32", "Cocoa", "Carbon" etc. // if the windowingSystemPreference string is empty (default) then return the first available WindowingSystemInterface that // has been registered with the osg::GraphiccsContext::WindowingSystemInterfaces singleton // if the windowingSystemPreference string is not empty then return the first WindowingSystemInterface that matches std::string windowingSystemPreference; // window decoration and behaviour std::string windowName; bool windowDecoration; bool supportsResize; // buffer depths, 0 equals off. unsigned int red; unsigned int blue; unsigned int green; unsigned int alpha; unsigned int depth; unsigned int stencil; // multi sample parameters unsigned int sampleBuffers; unsigned int samples; // buffer configuration bool pbuffer; bool quadBufferStereo; bool doubleBuffer; // render to texture GLenum target; GLenum format; unsigned int level; unsigned int face; unsigned int mipMapGeneration; // V-sync bool vsync; // Swap Group bool swapGroupEnabled; GLuint swapGroup; GLuint swapBarrier; // use multithreaded OpenGL-engine (OS X only) bool useMultiThreadedOpenGLEngine; // enable cursor bool useCursor; // settings used in set up of graphics context, only presently used by GL3 build of OSG. std::string glContextVersion; unsigned int glContextFlags; unsigned int glContextProfileMask; /** return true if glContextVersion is set in the form major.minor, and assign the appropriate major and minor values to the associated parameters.*/ bool getContextVersion(unsigned int& major, unsigned int& minor) const; // shared context osg::observer_ptr sharedContext; osg::ref_ptr inheritedWindowData; // ask the GraphicsWindow implementation to set the pixel format of an inherited window bool setInheritedWindowPixelFormat; // X11 hint whether to override the window managers window size/position redirection bool overrideRedirect; DisplaySettings::SwapMethod swapMethod; // hint of what affinity to use for any thrads associated with the graphics context created using these Traits OpenThreads::Affinity affinity; }; /** Simple resolution structure used by WindowingSystemInterface to get and set screen resolution. * Note the '0' value stands for 'unset'. */ struct ScreenSettings { ScreenSettings() : width(0), height(0), refreshRate(0), colorDepth(0) {} ScreenSettings(int in_width, int in_height, double in_refreshRate=0, unsigned int in_colorDepth=0) : width(in_width), height(in_height), refreshRate(in_refreshRate), colorDepth(in_colorDepth) {} int width; int height; double refreshRate; ///< Screen refresh rate, in Hz. unsigned int colorDepth; ///< RGB(A) color buffer depth. }; typedef std::vector ScreenSettingsList; /** Callback to be implemented to provide access to Windowing API's ability to create Windows/pbuffers.*/ struct WindowingSystemInterface : public osg::Referenced { void setName(const std::string& name) { _name = name; } const std::string& getName() const { return _name; } virtual unsigned int getNumScreens(const ScreenIdentifier& screenIdentifier = ScreenIdentifier()) = 0; virtual void getScreenSettings(const ScreenIdentifier& screenIdentifier, ScreenSettings & resolution) = 0; virtual bool setScreenSettings(const ScreenIdentifier& /*screenIdentifier*/, const ScreenSettings & /*resolution*/) { return false; } virtual void enumerateScreenSettings(const ScreenIdentifier& screenIdentifier, ScreenSettingsList & resolutionList) = 0; virtual void setDisplaySettings(DisplaySettings*) {} virtual osg::DisplaySettings* getDisplaySettings() const { return 0; } virtual GraphicsContext* createGraphicsContext(Traits* traits) = 0; /** Gets screen resolution without using the ScreenResolution structure. * \deprecated Provided only for backward compatibility. */ inline void getScreenResolution(const ScreenIdentifier& screenIdentifier, unsigned int& width, unsigned int& height) { ScreenSettings settings; getScreenSettings(screenIdentifier, settings); width = settings.width; height = settings.height; } /** Sets screen resolution without using the ScreenSettings structure. * \deprecated Provided only for backward compatibility. */ inline bool setScreenResolution(const ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height) { return setScreenSettings(screenIdentifier, ScreenSettings(width, height)); } /** \deprecated Provided only for backward compatibility. */ inline bool setScreenRefreshRate(const ScreenIdentifier& screenIdentifier, double refreshRate) { ScreenSettings settings; getScreenSettings(screenIdentifier, settings); settings.refreshRate = refreshRate; return setScreenSettings(screenIdentifier, settings); } protected: WindowingSystemInterface() {} virtual ~WindowingSystemInterface() {} std::string _name; }; class OSG_EXPORT WindowingSystemInterfaces : public osg::Referenced { public: WindowingSystemInterfaces(); typedef std::vector< osg::ref_ptr > Interfaces; Interfaces& getInterfaces() { return _interfaces; } void addWindowingSystemInterface(WindowingSystemInterface* wsInterface); void removeWindowingSystemInterface(WindowingSystemInterface* wsInterface); /** get named WindowingSystemInterface if one is available, otherwise return 0; */ WindowingSystemInterface* getWindowingSystemInterface(const std::string& name = ""); private: virtual ~WindowingSystemInterfaces(); Interfaces _interfaces; }; static osg::ref_ptr& getWindowingSystemInterfaces(); /** Get the default WindowingSystemInterface for this OS*/ static WindowingSystemInterface* getWindowingSystemInterface(const std::string& name = ""); /** Create a graphics context for a specified set of traits.*/ static GraphicsContext* createGraphicsContext(Traits* traits); /** Create a contextID for a new graphics context, this contextID is used to set up the osg::State associate with context. * Automatically increments the usage count of the contextID to 1.*/ static unsigned int createNewContextID(); /** Get the current max ContextID.*/ static unsigned int getMaxContextID(); /** Increment the usage count associate with a contextID. The usage count specifies how many graphics contexts a specific contextID is shared between.*/ static void incrementContextIDUsageCount(unsigned int contextID); /** Decrement the usage count associate with a contextID. Once the contextID goes to 0 the contextID is then free to be reused.*/ static void decrementContextIDUsageCount(unsigned int contextID); typedef std::vector GraphicsContexts; /** Get all the registered graphics contexts.*/ static GraphicsContexts getAllRegisteredGraphicsContexts(); /** Get all the registered graphics contexts associated with a specific contextID.*/ static GraphicsContexts getRegisteredGraphicsContexts(unsigned int contextID); /** Get the GraphicsContext for doing background compilation for GraphicsContexts associated with specified contextID.*/ static void setCompileContext(unsigned int contextID, GraphicsContext* gc); /** Get existing or create a new GraphicsContext to do background compilation for GraphicsContexts associated with specified contextID.*/ static GraphicsContext* getOrCreateCompileContext(unsigned int contextID); /** Get the GraphicsContext for doing background compilation for GraphicsContexts associated with specified contextID.*/ static GraphicsContext* getCompileContext(unsigned int contextID); public: /** Add operation to end of OperationQueue.*/ void add(Operation* operation); /** Remove operation from OperationQueue.*/ void remove(Operation* operation); /** Remove named operation from OperationQueue.*/ void remove(const std::string& name); /** Remove all operations from OperationQueue.*/ void removeAllOperations(); /** Run the operations. */ virtual void runOperations(); typedef std::list< ref_ptr > GraphicsOperationQueue; /** Get the operations queue, note you must use the OperationsMutex when accessing the queue.*/ GraphicsOperationQueue& getOperationsQueue() { return _operations; } /** Get the operations queue mutex.*/ OpenThreads::Mutex* getOperationsMutex() { return &_operationsMutex; } /** Get the operations queue block used to mark an empty queue, if you end items into the empty queue you must release this block.*/ osg::RefBlock* getOperationsBlock() { return _operationsBlock.get(); } /** Get the current operations that is being run.*/ Operation* getCurrentOperation() { return _currentOperation.get(); } public: /** Get the traits of the GraphicsContext.*/ inline const Traits* getTraits() const { return _traits.get(); } /** Return whether a valid and usable GraphicsContext has been created.*/ virtual bool valid() const = 0; /** Set the State object which tracks the current OpenGL state for this graphics context.*/ inline void setState(State* state) { _state = state; } /** Get the State object which tracks the current OpenGL state for this graphics context.*/ inline State* getState() { return _state.get(); } /** Get the const State object which tracks the current OpenGL state for this graphics context.*/ inline const State* getState() const { return _state.get(); } /** Sets the clear color. */ inline void setClearColor(const Vec4& color) { _clearColor = color; } /** Returns the clear color. */ inline const Vec4& getClearColor() const { return _clearColor; } /** Set the clear mask used in glClear(..). * Defaults to 0 - so no clear is done by default by the GraphicsContext, instead the Cameras attached to the GraphicsContext will do the clear. * GraphicsContext::setClearMask() is useful for when the Camera Viewports don't cover the whole context, so the context will fill in the gaps. */ inline void setClearMask(GLbitfield mask) { _clearMask = mask; } /** Get the clear mask.*/ inline GLbitfield getClearMask() const { return _clearMask; } /** Do an OpenGL clear of the full graphics context/window. * Note, must only be called from a thread with this context current.*/ virtual void clear(); double getTimeSinceLastClear() const { return osg::Timer::instance()->delta_s(_lastClearTick, osg::Timer::instance()->tick()); } /** Realize the GraphicsContext.*/ bool realize(); /** close the graphics context. * close(bool) stops any associated graphics threads, releases the contextID for the GraphicsContext then * optional calls closeImplementation() to do the actual deletion of the graphics. This call is made optional * as there are times when the graphics context has already been deleted externally and only the OSG side * of the its data need to be closed down. */ void close(bool callCloseImplementation=true); /** swap the front and back buffers.*/ void swapBuffers(); /** Return true if the graphics context has been realized and is ready to use.*/ inline bool isRealized() const { return isRealizedImplementation(); } /** Make this graphics context current. * Implemented by calling makeCurrentImplementation(). * Returns true on success. */ bool makeCurrent(); /** Make this graphics context current with specified read context. * Implemented by calling makeContextCurrentImplementation(). * Returns true on success. */ bool makeContextCurrent(GraphicsContext* readContext); /** Release the graphics context. * Returns true on success. */ bool releaseContext(); /** Return true if the current thread has this OpenGL graphics context.*/ inline bool isCurrent() const { return _threadOfLastMakeCurrent == OpenThreads::Thread::CurrentThreadId(); } /** Bind the graphics context to associated texture.*/ inline void bindPBufferToTexture(GLenum buffer) { bindPBufferToTextureImplementation(buffer); } /** Create a graphics thread to the graphics context, so that the thread handles all OpenGL operations.*/ void createGraphicsThread(); /** Assign a graphics thread to the graphics context, so that the thread handles all OpenGL operations.*/ void setGraphicsThread(GraphicsThread* gt); /** Get the graphics thread assigned the graphics context.*/ GraphicsThread* getGraphicsThread() { return _graphicsThread.get(); } /** Get the const graphics thread assigned the graphics context.*/ const GraphicsThread* getGraphicsThread() const { return _graphicsThread.get(); } /** Realize the GraphicsContext implementation, * Pure virtual - must be implemented by concrete implementations of GraphicsContext. */ virtual bool realizeImplementation() = 0; /** Return true if the graphics context has been realized, and is ready to use, implementation. * Pure virtual - must be implemented by concrete implementations of GraphicsContext. */ virtual bool isRealizedImplementation() const = 0; /** Close the graphics context implementation. * Pure virtual - must be implemented by concrete implementations of GraphicsContext. */ virtual void closeImplementation() = 0; /** Make this graphics context current implementation. * Pure virtual - must be implemented by concrete implementations of GraphicsContext. */ virtual bool makeCurrentImplementation() = 0; /** Make this graphics context current with specified read context implementation. * Pure virtual - must be implemented by concrete implementations of GraphicsContext. */ virtual bool makeContextCurrentImplementation(GraphicsContext* readContext) = 0; /** Release the graphics context implementation.*/ virtual bool releaseContextImplementation() = 0; /** Pure virtual, Bind the graphics context to associated texture implementation. * Pure virtual - must be implemented by concrete implementations of GraphicsContext. */ virtual void bindPBufferToTextureImplementation(GLenum buffer) = 0; struct SwapCallback : public osg::Referenced { virtual void swapBuffersImplementation(GraphicsContext* gc) = 0; }; /** Set the swap callback which overrides the * GraphicsContext::swapBuffersImplementation(), allowing * developers to provide custom behavior for swap. * The callback must call * GraphicsContext::swapBuffersImplementation() */ void setSwapCallback(SwapCallback* rc) { _swapCallback = rc; } /** Get the swap callback which overrides the GraphicsContext::swapBuffersImplementation().*/ SwapCallback* getSwapCallback() { return _swapCallback.get(); } /** Get the const swap callback which overrides the GraphicsContext::swapBuffersImplementation().*/ const SwapCallback* getSwapCallback() const { return _swapCallback.get(); } /** Convenience method for handling whether to call swapbuffers callback or the standard context swapBuffersImplementation. * swapBuffersCallbackOrImplementation() is called by swapBuffers() and osg::SwapBuffersOperation, end users should normally * call swapBuffers() rather than swapBuffersCallbackOrImplementation(). */ void swapBuffersCallbackOrImplementation() { if (_state.valid()) _state->frameCompleted(); if (_swapCallback.valid()) _swapCallback->swapBuffersImplementation(this); else swapBuffersImplementation(); } /** Swap the front and back buffers implementation. * Pure virtual - must be implemented by concrete implementations of GraphicsContext. */ virtual void swapBuffersImplementation() = 0; /** resized method should be called when the underlying window has been resized and the GraphicsWindow and associated Cameras must be updated to keep in sync with the new size. */ void resized(int x, int y, int width, int height) { if (_resizedCallback.valid()) _resizedCallback->resizedImplementation(this, x, y, width, height); else resizedImplementation(x, y, width, height); } struct ResizedCallback : public osg::Referenced { virtual void resizedImplementation(GraphicsContext* gc, int x, int y, int width, int height) = 0; }; /** Set the resized callback which overrides the GraphicsConext::realizedImplementation(), allow developers to provide custom behavior * in response to a window being resized.*/ void setResizedCallback(ResizedCallback* rc) { _resizedCallback = rc; } /** Get the resized callback which overrides the GraphicsConext::realizedImplementation().*/ ResizedCallback* getResizedCallback() { return _resizedCallback.get(); } /** Get the const resized callback which overrides the GraphicsConext::realizedImplementation().*/ const ResizedCallback* getResizedCallback() const { return _resizedCallback.get(); } /** resized implementation, by default resizes the viewports and aspect ratios the cameras associated with the graphics Window. */ virtual void resizedImplementation(int x, int y, int width, int height); typedef std::list< osg::Camera* > Cameras; /** Get the list of cameras associated with this graphics context.*/ Cameras& getCameras() { return _cameras; } /** Get the const list of cameras associated with this graphics context.*/ const Cameras& getCameras() const { return _cameras; } /** set the default FBO-id, this id will be used when the rendering-backend is finished with RTT FBOs */ void setDefaultFboId(GLuint i) { _defaultFboId = i; } GLuint getDefaultFboId() const { return _defaultFboId; } public: virtual bool isSameKindAs(const Object* object) const { return dynamic_cast(object)!=0; } virtual const char* libraryName() const { return "osg"; } virtual const char* className() const { return "GraphicsContext"; } protected: GraphicsContext(); GraphicsContext(const GraphicsContext&, const osg::CopyOp&); virtual ~GraphicsContext(); virtual Object* cloneType() const { return 0; } virtual Object* clone(const CopyOp&) const { return 0; } /** Register a GraphicsContext.*/ static void registerGraphicsContext(GraphicsContext* gc); /** Unregister a GraphicsContext.*/ static void unregisterGraphicsContext(GraphicsContext* gc); void addCamera(osg::Camera* camera); void removeCamera(osg::Camera* camera); Cameras _cameras; friend class osg::Camera; ref_ptr _traits; ref_ptr _state; Vec4 _clearColor; GLbitfield _clearMask; size_t _threadOfLastMakeCurrent; OpenThreads::Mutex _operationsMutex; osg::ref_ptr _operationsBlock; GraphicsOperationQueue _operations; osg::ref_ptr _currentOperation; ref_ptr _graphicsThread; ref_ptr _resizedCallback; ref_ptr _swapCallback; Timer_t _lastClearTick; GLuint _defaultFboId; }; //#include class OSG_EXPORT SyncSwapBuffersCallback : public GraphicsContext::SwapCallback { public: SyncSwapBuffersCallback(); virtual void swapBuffersImplementation(GraphicsContext* gc); GLsync _previousSync; }; template struct WindowingSystemInterfaceProxy { WindowingSystemInterfaceProxy(const std::string& name) { _wsi = new T; _wsi->setName(name); osg::GraphicsContext::getWindowingSystemInterfaces()->addWindowingSystemInterface(_wsi.get()); } ~WindowingSystemInterfaceProxy() { osg::GraphicsContext::getWindowingSystemInterfaces()->removeWindowingSystemInterface(_wsi.get()); } osg::ref_ptr _wsi; }; // Internal use only - compile on C90 compilers, which prohibit empty macro arguments. #define _OSG_GRAPHICSCONTEXT_NO_ATTRIBS #define REGISTER_WINDOWINGSYSTEMINTERFACE2(ext, classname, attribs) \ extern "C" attribs void graphicswindow_##ext(void) {} \ static osg::WindowingSystemInterfaceProxy s_proxy_##classname(#ext); #define REGISTER_WINDOWINGSYSTEMINTERFACE(ext, classname) \ REGISTER_WINDOWINGSYSTEMINTERFACE2(ext, classname, _OSG_GRAPHICSCONTEXT_NO_ATTRIBS) } #endif