0031477: Visualization, TKOpenGl - fetch/wrap getBufferSubData() function from WebGL 2.0 IR-2020-05-29 WEEK-22
authorkgv <kgv@opencascade.com>
Thu, 28 May 2020 16:42:13 +0000 (19:42 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 29 May 2020 16:40:57 +0000 (19:40 +0300)
Added OpenGl_Context::GetBufferSubData() implementing getBufferSubData() based on capabilities of various APIs.
Added OpenGl_VertexBuffer::GetSubData() similar to OpenGl_VertexBuffer::SubData().

src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_GlCore30.hxx
src/OpenGl/OpenGl_VertexBuffer.cxx
src/OpenGl/OpenGl_VertexBuffer.hxx
src/OpenGl/OpenGl_VertexBufferCompat.cxx
src/OpenGl/OpenGl_VertexBufferCompat.hxx

index 4111e96..9ae0f0e 100644 (file)
@@ -65,6 +65,7 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Context,Standard_Transient)
 #endif
 
 #ifdef __EMSCRIPTEN__
+  #include <emscripten.h>
   #include <emscripten/html5.h>
 
   //! Check if WebGL extension is available and activate it
@@ -138,6 +139,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   core45     (NULL),
   core45back (NULL),
   caps   (!theCaps.IsNull() ? theCaps : new OpenGl_Caps()),
+  hasGetBufferData (Standard_False),
 #if defined(GL_ES_VERSION_2_0)
   hasHighp   (Standard_False),
   hasUintIndex(Standard_False),
@@ -1677,6 +1679,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   {
     core30    = (OpenGl_GlCore30*    )(&(*myFuncs));
     core30fwd = (OpenGl_GlCore30Fwd* )(&(*myFuncs));
+    hasGetBufferData = true;
   }
 
   // load OpenGL ES 3.1 new functions
@@ -2183,6 +2186,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
       core15 = (OpenGl_GlCore15* )(&(*myFuncs));
     }
     core15fwd = (OpenGl_GlCore15Fwd* )(&(*myFuncs));
+    hasGetBufferData = true;
   }
   else
   {
@@ -4613,6 +4617,36 @@ bool OpenGl_Context::SetSampleAlphaToCoverage (bool theToEnable)
 }
 
 // =======================================================================
+// function : GetBufferSubData
+// purpose  :
+// =======================================================================
+bool OpenGl_Context::GetBufferSubData (GLenum theTarget, GLintptr theOffset, GLsizeiptr theSize, void* theData)
+{
+  if (!hasGetBufferData)
+  {
+    return false;
+  }
+#ifdef __EMSCRIPTEN__
+  EM_ASM_(
+  {
+    Module.ctx.getBufferSubData($0, $1, HEAPU8.subarray($2, $2 + $3));
+  }, theTarget, theOffset, theData, theSize);
+  return true;
+#elif defined(GL_ES_VERSION_2_0)
+  if (void* aData = core30fwd->glMapBufferRange (theTarget, theOffset, theSize, GL_MAP_READ_BIT))
+  {
+    memcpy (theData, aData, theSize);
+    core30fwd->glUnmapBuffer (theTarget);
+    return true;
+  }
+  return false;
+#else
+  core15fwd->glGetBufferSubData (theTarget, theOffset, theSize, theData);
+  return true;
+#endif
+}
+
+// =======================================================================
 // function : DumpJson
 // purpose  :
 // =======================================================================
index fd16e49..aed802a 100644 (file)
@@ -987,6 +987,17 @@ public: //! @name methods to alter or retrieve current state
   //! Set line feater width.
   void SetLineFeather(Standard_ShortReal theValue) { myLineFeather = theValue; }
 
+  //! Wrapper over glGetBufferSubData(), implemented as:
+  //! - OpenGL 1.5+ (desktop) via glGetBufferSubData();
+  //! - OpenGL ES 3.0+ via glMapBufferRange();
+  //! - WebGL 2.0+ via gl.getBufferSubData().
+  //! @param theTarget [in] target buffer to map
+  //! @param theOffset [in] offset to the beginning of sub-data
+  //! @param theSize   [in] number of bytes to read
+  //! @param theData  [out] destination pointer to fill
+  //! @return FALSE if functionality is unavailable
+  Standard_EXPORT bool GetBufferSubData (GLenum theTarget, GLintptr theOffset, GLsizeiptr theSize, void* theData);
+
   //! Return Graphics Driver's vendor.
   const TCollection_AsciiString& Vendor() const { return myVendor; }
 
@@ -1044,6 +1055,7 @@ public: //! @name core profiles
 
 public: //! @name extensions
 
+  Standard_Boolean       hasGetBufferData;   //!< flag indicating if GetBufferSubData() is supported
   Standard_Boolean       hasHighp;           //!< highp in GLSL ES fragment shader is supported
   Standard_Boolean       hasUintIndex;       //!< GLuint for index buffer is supported (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_element_index_uint)
   Standard_Boolean       hasTexRGBA8;        //!< always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_rgb8_rgba8
index cede88f..f9cb9ad 100644 (file)
@@ -132,6 +132,18 @@ public: //! @name OpenGL 3.0 additives to 2.1
   using theBaseClass_t::glVertexAttribI4ubv;
   using theBaseClass_t::glVertexAttribI4usv;
 #endif
+
+#if defined(GL_ES_VERSION_2_0)
+  // the following functions from OpenGL 1.5 have been added only in OpenGL ES 3.0
+  using theBaseClass_t::glGenQueries;
+  using theBaseClass_t::glDeleteQueries;
+  using theBaseClass_t::glIsQuery;
+  using theBaseClass_t::glBeginQuery;
+  using theBaseClass_t::glEndQuery;
+  using theBaseClass_t::glGetQueryiv;
+  using theBaseClass_t::glGetQueryObjectuiv;
+  using theBaseClass_t::glUnmapBuffer;
+#endif
 };
 
 //! OpenGL 3.0 core based on 2.1 version.
index 1727817..35b3621 100644 (file)
@@ -161,6 +161,33 @@ bool OpenGl_VertexBuffer::subData (const Handle(OpenGl_Context)& theGlCtx,
 }
 
 // =======================================================================
+// function : getSubData
+// purpose  :
+// =======================================================================
+bool OpenGl_VertexBuffer::getSubData (const Handle(OpenGl_Context)& theGlCtx,
+                                      const GLsizei theElemFrom,
+                                      const GLsizei theElemsNb,
+                                      void*         theData,
+                                      const GLenum  theDataType)
+{
+  if (!IsValid() || myDataType != theDataType
+   || theElemFrom < 0 || ((theElemFrom + theElemsNb) > myElemsNb)
+   || !theGlCtx->hasGetBufferData)
+  {
+    return false;
+  }
+
+  Bind (theGlCtx);
+  const size_t  aDataSize = sizeOfGlType (theDataType);
+  const GLintptr anOffset = GLintptr (theElemFrom) * GLintptr  (myComponentsNb) * aDataSize;
+  const GLsizeiptr  aSize = GLsizeiptr(theElemsNb) * GLsizeiptr(myComponentsNb) * aDataSize;
+  bool isDone = theGlCtx->GetBufferSubData (GetTarget(), anOffset, aSize, theData);
+  isDone = isDone && (glGetError() == GL_NO_ERROR);
+  Unbind (theGlCtx);
+  return isDone;
+}
+
+// =======================================================================
 // function : BindVertexAttrib
 // purpose  :
 // =======================================================================
index 72f7232..65c1389 100644 (file)
@@ -154,6 +154,20 @@ public:
     return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_FLOAT);
   }
 
+  //! Read back buffer sub-range.
+  //! Notice that VBO will be unbound after this call.
+  //! Function reads portion of data from this VBO using glGetBufferSubData().
+  //! @param theElemFrom [in] element id from which replace buffer data (>=0);
+  //! @param theElemsNb  [in] elements count (theElemFrom + theElemsNb <= GetElemsNb());
+  //! @param theData    [out] destination pointer to GLfloat data.
+  bool GetSubData (const Handle(OpenGl_Context)& theGlCtx,
+                   const GLsizei theElemFrom,
+                   const GLsizei theElemsNb,
+                   GLfloat* theData)
+  {
+    return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_FLOAT);
+  }
+
   //! Notice that VBO will be unbound after this call.
   //! Function replaces portion of data within this VBO using glBufferSubData().
   //! The VBO should be initialized before call.
@@ -168,6 +182,20 @@ public:
     return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_INT);
   }
 
+  //! Read back buffer sub-range.
+  //! Notice that VBO will be unbound after this call.
+  //! Function reads portion of data from this VBO using glGetBufferSubData().
+  //! @param theElemFrom [in] element id from which replace buffer data (>=0);
+  //! @param theElemsNb  [in] elements count (theElemFrom + theElemsNb <= GetElemsNb());
+  //! @param theData    [out] destination pointer to GLuint data.
+  bool GetSubData (const Handle(OpenGl_Context)& theGlCtx,
+                   const GLsizei theElemFrom,
+                   const GLsizei theElemsNb,
+                   GLuint* theData)
+  {
+    return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_INT);
+  }
+
   //! Notice that VBO will be unbound after this call.
   //! Function replaces portion of data within this VBO using glBufferSubData().
   //! The VBO should be initialized before call.
@@ -182,6 +210,20 @@ public:
     return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_SHORT);
   }
 
+  //! Read back buffer sub-range.
+  //! Notice that VBO will be unbound after this call.
+  //! Function reads portion of data from this VBO using glGetBufferSubData().
+  //! @param theElemFrom [in] element id from which replace buffer data (>=0);
+  //! @param theElemsNb  [in] elements count (theElemFrom + theElemsNb <= GetElemsNb());
+  //! @param theData    [out] destination pointer to GLushort data.
+  bool GetSubData (const Handle(OpenGl_Context)& theGlCtx,
+                   const GLsizei theElemFrom,
+                   const GLsizei theElemsNb,
+                   GLushort* theData)
+  {
+    return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_SHORT);
+  }
+
   //! Notice that VBO will be unbound after this call.
   //! Function replaces portion of data within this VBO using glBufferSubData().
   //! The VBO should be initialized before call.
@@ -196,6 +238,20 @@ public:
     return subData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_BYTE);
   }
 
+  //! Read back buffer sub-range.
+  //! Notice that VBO will be unbound after this call.
+  //! Function reads portion of data from this VBO using glGetBufferSubData().
+  //! @param theElemFrom [in] element id from which replace buffer data (>=0);
+  //! @param theElemsNb  [in] elements count (theElemFrom + theElemsNb <= GetElemsNb());
+  //! @param theData    [out] destination pointer to GLubyte data.
+  bool GetSubData (const Handle(OpenGl_Context)& theGlCtx,
+                   const GLsizei theElemFrom,
+                   const GLsizei theElemsNb,
+                   GLubyte* theData)
+  {
+    return getSubData (theGlCtx, theElemFrom, theElemsNb, theData, GL_UNSIGNED_BYTE);
+  }
+
   //! Bind this VBO to active GLSL program.
   Standard_EXPORT void BindVertexAttrib (const Handle(OpenGl_Context)& theGlCtx,
                                          const GLuint                  theAttribLoc) const;
@@ -286,6 +342,13 @@ public: //! @name advanced methods
                                         const void*    theData,
                                         const GLenum   theDataType);
 
+  //! Read back buffer sub-range.
+  Standard_EXPORT virtual bool getSubData (const Handle(OpenGl_Context)& theGlCtx,
+                                           const GLsizei theElemFrom,
+                                           const GLsizei theElemsNb,
+                                           void*         theData,
+                                           const GLenum  theDataType);
+
   //! Setup array pointer - either for active GLSL program OpenGl_Context::ActiveProgram()
   //! or for FFP using bindFixed() when no program bound.
   static void bindAttribute (const Handle(OpenGl_Context)&   theGlCtx,
index 1b11c3b..2ba9a1d 100644 (file)
@@ -175,3 +175,27 @@ bool OpenGl_VertexBufferCompat::subData (const Handle(OpenGl_Context)& ,
   memcpy (myData->ChangeData() + anOffset, theData, aNbBytes);
   return true;
 }
+
+// =======================================================================
+// function : getSubData
+// purpose  :
+// =======================================================================
+bool OpenGl_VertexBufferCompat::getSubData (const Handle(OpenGl_Context)& ,
+                                            const GLsizei theElemFrom,
+                                            const GLsizei theElemsNb,
+                                            void* theData,
+                                            const GLenum  theDataType)
+{
+  if (!IsValid() || myDataType != theDataType
+   || theElemFrom < 0 || ((theElemFrom + theElemsNb) > myElemsNb)
+   || theData == NULL)
+  {
+    return false;
+  }
+
+  const size_t aDataSize = sizeOfGlType (theDataType);
+  const size_t anOffset  = size_t(theElemFrom) * size_t(myComponentsNb) * aDataSize;
+  const size_t aNbBytes  = size_t(theElemsNb)  * size_t(myComponentsNb) * aDataSize;
+  memcpy (theData, myData->Data() + anOffset, aNbBytes);
+  return true;
+}
index 331dbe6..f7c3957 100644 (file)
@@ -82,6 +82,13 @@ public: //! @name advanced methods
                                         const void*    theData,
                                         const GLenum   theDataType) Standard_OVERRIDE;
 
+  //! Read back buffer sub-range.
+  Standard_EXPORT virtual bool getSubData (const Handle(OpenGl_Context)& theGlCtx,
+                                           const GLsizei theElemFrom,
+                                           const GLsizei theElemsNb,
+                                           void* theData,
+                                           const GLenum  theDataType) Standard_OVERRIDE;
+
 protected:
 
   Handle(NCollection_Buffer) myData; //!< buffer data