text: //
  // Copyright 2016 Pixar
  //
  // Licensed under the Apache License, Version 2.0 (the "Apache License")
  // with the following modification; you may not use this file except in
  // compliance with the Apache License and the following modification to it:
  // Section 6. Trademarks. is deleted and replaced with:
  //
  // 6. Trademarks. This License does not grant permission to use the trade
  //    names, trademarks, service marks, or product names of the Licensor
  //    and its affiliates, except as required to comply with Section 4(c) of
  //    the License and to reproduce the content of the NOTICE file.
  //
  // You may obtain a copy of the Apache License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the Apache License with the above modification is
  // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied. See the Apache License for the specific
  // language governing permissions and limitations under the Apache License.
  //
  #ifndef GLF_GLCONTEXT_H
  #define GLF_GLCONTEXT_H
  
  #include "pxr/base/arch/threads.h"
  #include <boost/noncopyable.hpp>
  #include <boost/shared_ptr.hpp>
  
  typedef boost::shared_ptr<class GlfGLContext> GlfGLContextSharedPtr;
  
  /// \class GlfGLContext glContext.h "pxr/imaging/glf/glContext.h"
  /// \brief Provides window system independent access to GL contexts.
  ///
  /// All OpenGL operation occurs within a current GL Context.  The GL
  /// contexts used by an application are allocated and managed by the window
  /// system interface layer, i.e. Qt, GLUT, GLX, etc.
  ///
  /// This class provides a way for lower-level OpenGL framework code to
  /// get useful information about the GL contexts in use by the application.
  ///
  /// This mechanism depends on the application code registering callbacks to
  /// provide access to its GL contexts.
  ///
  class GlfGLContext : public boost::noncopyable {
  public:
      virtual ~GlfGLContext();
  
      /// \brief Returns an instance for the current GL context.
      static GlfGLContextSharedPtr GetCurrentGLContext();
  
      /// \brief Returns an instance for the shared GL context.
      static GlfGLContextSharedPtr GetSharedGLContext();
  
      /// Makes \p context current if valid, otherwise makes no context current.
      static void MakeCurrent(const GlfGLContextSharedPtr& context);
  
      /// \brief Returns \c true if \a context1 and \a context2 are sharing.
      static bool AreSharing(GlfGLContextSharedPtr const & context1,
                             GlfGLContextSharedPtr const & context2);
  
      /// \brief Returns whether this interface has been initialized.
      static bool IsInitialized();
  
      /// \brief Returns \c true if this context is current.
      bool IsCurrent() const;
  
  private:
      /// \brief Makes this context current.
      ///
      /// If the context is not valid this does nothing.
      void MakeCurrent();
  
  public:
      /// \brief Makes no context current.
      static void DoneCurrent();
  
      /// \brief Returns \c true if this context is sharing with \a otherContext.
      bool IsSharing(GlfGLContextSharedPtr const & otherContext);
  
      /// \brief Returns \c true if this context is valid.
      virtual bool IsValid() const = 0;
  
  protected:
      GlfGLContext();
  
      /// \brief Makes this context current.
      virtual void _MakeCurrent() = 0;
  
      /// \brief Returns \c true if this context is sharing with \a rhs.
      virtual bool _IsSharing(const GlfGLContextSharedPtr& rhs) const = 0;
  
      /// \brief Returns \c true if this context is equal to \p rhs.
      virtual bool _IsEqual(const GlfGLContextSharedPtr& rhs) const = 0;
  };
  
  /// \class GlfGLContextScopeHolder GLContext.h "pxr/imaging/glf/glContext.h"
  /// \brief Helper class to make a GL context current.
  ///
  /// It is often useful to wrap a dynamic GL resource with a class interface.
  ///
  /// In addition to providing API to make it more convenient to use the
  /// underlying GL resource, the lifetime of the underlying resource can
  /// be tied to the lifetime of a wrapper object instance, e.g. allocate
  /// the GL resource during construction, delete the GL resource during
  /// destruction.
  ///
  /// While the construction and use of these kinds of wrapper objects is
  /// usually pretty safe and straightforward, it can be more difficult to
  /// manage destruction.  Specifically, it can be hard to guarantee that
  /// a suitable GL context is current at the time that a wrapper object
  /// instance is destroyed.  If a suitable context is not current, then
  /// it will not be possible to delete the underlying resource, which
  /// may cause the resource to remain allocated, which will then result
  /// in a resource leak.
  ///
  /// Typically, these GL resources are allocated from contexts which are
  /// sharing the GL resources.  In which case it is sufficient for any one
  /// one of the sharing contexts to be current in order to be able to safely
  /// delete the GL resource from the destructor of a wrapper object.
  ///
  /// GlfGLContext and GlfGLContextScopeHolder can help.
  ///
  /// When GlfGLContext has been initialized, i.e. when suitable context
  /// callbacks have been registered, we can use GlfGLContext to make
  /// a GL context current.
  ///
  /// GlfGLContextScopeHolder does this automatically for the duration
  /// of a code block.
  ///
  /// The underlying calls to make GL contexts current can be moderately
  /// expensive.  So, this mechanism should be used carefully.
  ///
  class GlfGLContextScopeHolder : boost::noncopyable {
  public:
      /// Make the given context current and restore the current context
      /// when this object is destroyed.
      explicit GlfGLContextScopeHolder(const GlfGLContextSharedPtr& newContext);
  
      ~GlfGLContextScopeHolder();
  
  protected:
      void _MakeNewContextCurrent();
      void _RestoreOldContext();
  
  private:
      GlfGLContextSharedPtr _newContext;
      GlfGLContextSharedPtr _oldContext;
  };
  
  /// \class GlfSharedGLContextScopeHolder GLContext.h "pxr/imaging/glf/glContext.h"
  /// \brief Helper class to make the shared GL context current.
  ///
  /// Example:
  ///
  /// \code
  ///     class MyTexture {
  ///     public:
  ///         MyTexture() : _textureId(0) {
  ///             // allocate from the shared context pool.
  ///             GlfSharedGLContextScopeHolder sharedContextScopeHolder;
  ///             glGenTextures(1, &_textureId);
  ///         }
  ///
  ///         ~MyTexture() {
  ///             // delete from the shared context pool.
  ///             GlfSharedGLContextScopeHolder sharedContextScopeHolder;
  ///             glDeleteTextures(1, &_texureId);
  ///             _textureId = 0;
  ///         }
  ///
  ///         // The caller is responsible for making sure that a suitable
  ///         // GL context is current before calling other methods.
  ///
  ///         void Bind() {
  ///             glBindTexture(GL_TEXTURE_2D, _textureId);
  ///         }
  ///
  ///         void Unbind() {
  ///             glBindTexture(GL_TEXTURE_2D, 0);
  ///         }
  ///
  ///         ...
  ///
  ///     private:
  ///         GLuint _textureId;
  ///
  ///     };
  /// \endcode
  ///
  class GlfSharedGLContextScopeHolder : private GlfGLContextScopeHolder {
  public:
      GlfSharedGLContextScopeHolder() :
          GlfGLContextScopeHolder(_GetSharedContext())
      {
          // Do nothing
      }
  
  private:
      static GlfGLContextSharedPtr _GetSharedContext()
      {
          if (GlfGLContext::IsInitialized()
  #ifdef MENV30
              // XXX skip this test for globaltrees until shared_code lands
              and ArchIsMainThread()
  #endif
              ) {
              return GlfGLContext::GetSharedGLContext();
          }
          return GlfGLContextSharedPtr();
      }
  };
  
  /// \class GlfGLContextRegistrationInterface
  /// \brief Interface for registering a GlfGLContext system.
  ///
  /// If you subclass GlfGLContext you should subclass this type and
  /// instantiate an instance on the heap.  It will be cleaned up
  /// automatically.
  class GlfGLContextRegistrationInterface : boost::noncopyable {
  public:
      virtual ~GlfGLContextRegistrationInterface();
  
      /// If this GLContext system supports a shared context this should
      /// return it.  This will be called at most once.
      virtual GlfGLContextSharedPtr GetShared() = 0;
  
      /// Whatever your GLContext system thinks is the current GL context
      /// may not really be the current context if another system has since
      /// changed the context.  This method should return what it thinks is
      /// the current context.  If it thinks there is no current context it
      /// should return \c NULL.
      virtual GlfGLContextSharedPtr GetCurrent() = 0;
  
  protected:
      GlfGLContextRegistrationInterface();
  };
  
  #endif
  