]> OCCT Git - occt.git/commitdiff
0032101: Visualization, TKOpenGl - use GL_UNPACK_ROW_LENGTH within OpenGL ES 3.0...
authorkgv <kgv@opencascade.com>
Mon, 1 Feb 2021 17:46:00 +0000 (20:46 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 3 Feb 2021 15:26:28 +0000 (18:26 +0300)
Added OpenGl_Context::hasUnpackRowLength property for using GL_UNPACK_ROW_LENGTH in runtime.
OpenGl_Texture now uses GL_UNPACK_ROW_LENGTH on OpenGL ES 3.0 when necessary.
OpenGl_Texture::InitCubeMap() now allows uploading vertically-stacked cubemaps
without GL_UNPACK_ROW_LENGTH requirement.

src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_Font.cxx
src/OpenGl/OpenGl_FrameBuffer.cxx
src/OpenGl/OpenGl_Texture.cxx

index 9147d26bcf62c18d8d20cc661d17c9489e3fdd6e..7d8713a3034da50e25e37595e22b14bbf888b94b 100644 (file)
@@ -146,10 +146,14 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   caps   (!theCaps.IsNull() ? theCaps : new OpenGl_Caps()),
   hasGetBufferData (Standard_False),
 #if defined(GL_ES_VERSION_2_0)
+  hasPackRowLength (Standard_False),
+  hasUnpackRowLength (Standard_False),
   hasHighp   (Standard_False),
   hasUintIndex(Standard_False),
   hasTexRGBA8(Standard_False),
 #else
+  hasPackRowLength (Standard_True),
+  hasUnpackRowLength (Standard_True),
   hasHighp   (Standard_True),
   hasUintIndex(Standard_True),
   hasTexRGBA8(Standard_True),
@@ -1558,6 +1562,8 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   hasFboRenderMipmap = IsGlGreaterEqual (3, 0)
                     || CheckExtension ("GL_OES_fbo_render_mipmap");
   hasSRGBControl = CheckExtension ("GL_EXT_sRGB_write_control");
+  hasPackRowLength   = IsGlGreaterEqual (3, 0);
+  hasUnpackRowLength = IsGlGreaterEqual (3, 0); // || CheckExtension ("GL_EXT_unpack_subimage");
   // NPOT textures has limited support within OpenGL ES 2.0
   // which are relaxed by OpenGL ES 3.0 or some extensions
   //arbNPTW     = IsGlGreaterEqual (3, 0)
index 8bde7aaea4f9e13749e3fc939165be344e3251d8..04ce1e14850f87e044ea472cf2b2f5b7f26958a6 100644 (file)
@@ -1078,6 +1078,8 @@ public: //! @name core profiles
 public: //! @name extensions
 
   Standard_Boolean       hasGetBufferData;   //!< flag indicating if GetBufferSubData() is supported
+  Standard_Boolean       hasPackRowLength;   //!< supporting of GL_PACK_ROW_LENGTH   parameters (any desktop OpenGL; OpenGL ES 3.0)
+  Standard_Boolean       hasUnpackRowLength; //!< supporting of GL_UNPACK_ROW_LENGTH parameters (any desktop OpenGL; OpenGL ES 3.0)
   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
@@ -1085,7 +1087,7 @@ public: //! @name extensions
   Standard_Boolean       hasTexSRGB;         //!< sRGB texture    formats (desktop OpenGL 2.1, OpenGL ES 3.0 or GL_EXT_texture_sRGB)
   Standard_Boolean       hasFboSRGB;         //!< sRGB FBO render targets (desktop OpenGL 2.1, OpenGL ES 3.0)
   Standard_Boolean       hasSRGBControl;     //!< sRGB write control (any desktop OpenGL, OpenGL ES + GL_EXT_sRGB_write_control extension)
-  Standard_Boolean       hasFboRenderMipmap; //!< FBO render target could be non-zero mimap level of texture
+  Standard_Boolean       hasFboRenderMipmap; //!< FBO render target could be non-zero mipmap level of texture
   OpenGl_FeatureFlag     hasFlatShading;     //!< Complex flag indicating support of Flat shading (Graphic3d_TOSM_FACET) (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_standard_derivatives)
   OpenGl_FeatureFlag     hasGlslBitwiseOps;  //!< GLSL supports bitwise operations; OpenGL 3.0 / OpenGL ES 3.0 (GLSL 130 / GLSL ES 300) or OpenGL 2.1 + GL_EXT_gpu_shader4
   OpenGl_FeatureFlag     hasDrawBuffers;     //!< Complex flag indicating support of multiple draw buffers (desktop OpenGL 2.0, OpenGL ES 3.0, GL_ARB_draw_buffers, GL_EXT_draw_buffers)
@@ -1101,7 +1103,7 @@ public: //! @name extensions
   OpenGl_ArbTexBindless* arbTexBindless;     //!< GL_ARB_bindless_texture
   OpenGl_ArbTBO*         arbTBO;             //!< GL_ARB_texture_buffer_object (on desktop OpenGL - since 3.1 or as extension GL_ARB_texture_buffer_object; on OpenGL ES - since 3.2)
   Standard_Boolean       arbTboRGB32;        //!< GL_ARB_texture_buffer_object_rgb32 (3-component TBO), in core since 4.0
-  OpenGl_ArbIns*         arbIns;             //!< GL_ARB_draw_instanced (on desktop OpenGL - since 3.1 or as extebsion GL_ARB_draw_instanced; on OpenGL ES - since 3.0 or as extension GL_ANGLE_instanced_arrays to WebGL 1.0)
+  OpenGl_ArbIns*         arbIns;             //!< GL_ARB_draw_instanced (on desktop OpenGL - since 3.1 or as extension GL_ARB_draw_instanced; on OpenGL ES - since 3.0 or as extension GL_ANGLE_instanced_arrays to WebGL 1.0)
   OpenGl_ArbDbg*         arbDbg;             //!< GL_ARB_debug_output (on desktop OpenGL - since 4.3 or as extension GL_ARB_debug_output; on OpenGL ES - since 3.2 or as extension GL_KHR_debug)
   OpenGl_ArbFBO*         arbFBO;             //!< GL_ARB_framebuffer_object
   OpenGl_ArbFBOBlit*     arbFBOBlit;         //!< glBlitFramebuffer function, moved out from OpenGl_ArbFBO structure for compatibility with OpenGL ES 2.0
index 99471b8a11605a6e7faf1e28a7cd8cf25b7b09d9..a5e66273da5e9fc0b3d1869509c4c8396ccba317 100755 (executable)
@@ -204,14 +204,17 @@ bool OpenGl_Font::renderGlyph (const Handle(OpenGl_Context)& theCtx,
 
   aTexture->Bind (theCtx);
 #if !defined(GL_ES_VERSION_2_0)
-  glPixelStorei (GL_UNPACK_LSB_FIRST,  GL_FALSE);
-  glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+  theCtx->core11fwd->glPixelStorei (GL_UNPACK_LSB_FIRST,  GL_FALSE);
 #endif
-  glPixelStorei (GL_UNPACK_ALIGNMENT,  1);
+  if (theCtx->hasUnpackRowLength)
+  {
+    theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+  }
+  theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
 
-  glTexSubImage2D (GL_TEXTURE_2D, 0,
-                   myLastTilePx.Left, myLastTilePx.Top, (GLsizei )anImg.SizeX(), (GLsizei )anImg.SizeY(),
-                   aTexture->GetFormat(), GL_UNSIGNED_BYTE, anImg.Data());
+  theCtx->core11fwd->glTexSubImage2D (GL_TEXTURE_2D, 0,
+                                      myLastTilePx.Left, myLastTilePx.Top, (GLsizei )anImg.SizeX(), (GLsizei )anImg.SizeY(),
+                                      aTexture->GetFormat(), GL_UNSIGNED_BYTE, anImg.Data());
 
   OpenGl_Font::Tile aTile;
   aTile.uv.Left   = GLfloat(myLastTilePx.Left)                / GLfloat(aTexture->SizeX());
index 0956287b83f86c462eb3ed57e8fee9266cce5bff..0246700a945b4ce7614f94b2c94d505eb0f0a821 100644 (file)
@@ -953,16 +953,16 @@ Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& t
   else
   {
   #if !defined(GL_ES_VERSION_2_0)
-    glGetIntegerv (GL_READ_BUFFER, &aReadBufferPrev);
+    theGlCtx->core11fwd->glGetIntegerv (GL_READ_BUFFER, &aReadBufferPrev);
     GLint aDrawBufferPrev = GL_BACK;
-    glGetIntegerv (GL_DRAW_BUFFER, &aDrawBufferPrev);
+    theGlCtx->core11fwd->glGetIntegerv (GL_DRAW_BUFFER, &aDrawBufferPrev);
     glReadBuffer (aDrawBufferPrev);
   #endif
   }
 
   // setup alignment
-  const GLint anAligment   = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
-  glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
+  const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
+  theGlCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
   bool isBatchCopy = !theImage.IsTopDown();
 
   const GLint   anExtraBytes       = GLint(theImage.RowExtraBytes());
@@ -977,14 +977,15 @@ Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& t
     aPixelsWidth = 0;
     isBatchCopy  = false;
   }
-#if !defined(GL_ES_VERSION_2_0)
-  glPixelStorei (GL_PACK_ROW_LENGTH, aPixelsWidth);
-#else
-  if (aPixelsWidth != 0)
+  if (theGlCtx->hasPackRowLength)
+  {
+    theGlCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, aPixelsWidth);
+  }
+  else if (aPixelsWidth != 0)
   {
     isBatchCopy = false;
   }
-#endif
+
   if (toConvRgba2Rgb)
   {
     Handle(NCollection_BaseAllocator) anAlloc = new NCollection_AlignedAllocator (16);
@@ -999,7 +1000,7 @@ Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& t
     {
       // Image_PixMap rows indexation always starts from the upper corner
       // while order in memory depends on the flag and processed by ChangeRow() method
-      glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, aRowBuffer.ChangeData());
+      theGlCtx->core11fwd->glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, aRowBuffer.ChangeData());
       const Image_ColorRGBA* aRowDataRgba = (const Image_ColorRGBA* )aRowBuffer.Data();
       if (theImage.Format() == Image_Format_BGR)
       {
@@ -1018,19 +1019,20 @@ Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& t
     {
       // Image_PixMap rows indexation always starts from the upper corner
       // while order in memory depends on the flag and processed by ChangeRow() method
-      glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, theImage.ChangeRow (aRow));
+      theGlCtx->core11fwd->glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, theImage.ChangeRow (aRow));
     }
   }
   else
   {
-    glReadPixels (0, 0, GLsizei (theImage.SizeX()), GLsizei (theImage.SizeY()), aFormat, aType, theImage.ChangeData());
+    theGlCtx->core11fwd->glReadPixels (0, 0, GLsizei (theImage.SizeX()), GLsizei (theImage.SizeY()), aFormat, aType, theImage.ChangeData());
   }
   const bool hasErrors = theGlCtx->ResetErrors (true);
 
-  glPixelStorei (GL_PACK_ALIGNMENT,  1);
-#if !defined(GL_ES_VERSION_2_0)
-  glPixelStorei (GL_PACK_ROW_LENGTH, 0);
-#endif
+  theGlCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, 1);
+  if (theGlCtx->hasPackRowLength)
+  {
+    theGlCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
+  }
 
   if (!theFbo.IsNull() && theFbo->IsValid())
   {
index 939e5bc99125673981c767340e0d0a7065bdcffe..68e44560bcd701bba94ae300efa8769a9207bb22 100644 (file)
@@ -25,6 +25,8 @@
 #include <Image_PixMap.hxx>
 #include <Image_SupportedFormats.hxx>
 
+#include <algorithm>
+
 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource)
 
 namespace
@@ -33,23 +35,26 @@ namespace
 //! Simple class to reset unpack alignment settings
 struct OpenGl_UnpackAlignmentSentry
 {
-
   //! Reset unpack alignment settings to safe values
-  static void Reset()
+  static void Reset (const OpenGl_Context& theCtx)
   {
-    glPixelStorei (GL_UNPACK_ALIGNMENT,  1);
-  #if !defined(GL_ES_VERSION_2_0)
-    glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
-  #endif
+    theCtx.core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+    if (theCtx.hasUnpackRowLength)
+    {
+      theCtx.core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+    }
   }
 
-  OpenGl_UnpackAlignmentSentry() {}
+  OpenGl_UnpackAlignmentSentry (const Handle(OpenGl_Context)& theCtx)
+  : myCtx (theCtx.get()) {}
 
   ~OpenGl_UnpackAlignmentSentry()
   {
-    Reset();
+    Reset (*myCtx);
   }
 
+private:
+  OpenGl_Context* myCtx;
 };
 
 //! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
@@ -161,7 +166,7 @@ void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
 
   if (theGlCtx->IsValid())
   {
-    glDeleteTextures (1, &myTextureId);
+    theGlCtx->core11fwd->glDeleteTextures (1, &myTextureId);
   }
   myTextureId = NO_TEXTURE;
   mySizeX = mySizeY = mySizeZ = 0;
@@ -192,7 +197,7 @@ void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
     theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
   }
   mySampler->Bind (theCtx, theTextureUnit);
-  glBindTexture (myTarget, myTextureId);
+  theCtx->core11fwd->glBindTexture (myTarget, myTextureId);
 }
 
 // =======================================================================
@@ -207,7 +212,7 @@ void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
     theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
   }
   mySampler->Unbind (theCtx, theTextureUnit);
-  glBindTexture (myTarget, NO_TEXTURE);
+  theCtx->core11fwd->glBindTexture (myTarget, NO_TEXTURE);
 }
 
 //=======================================================================
@@ -340,25 +345,31 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
 #endif
 
 #if !defined(GL_ES_VERSION_2_0)
-  GLint aTestWidth  = 0, aTestHeight = 0;
+  GLint aTestWidth = 0, aTestHeight = 0;
 #endif
   GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
 
   // setup the alignment
-  OpenGl_UnpackAlignmentSentry anUnpackSentry;
+  OpenGl_UnpackAlignmentSentry anUnpackSentry (theCtx);
   (void)anUnpackSentry; // avoid compiler warning
 
   if (aDataPtr != NULL)
   {
     const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
     theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
-
-  #if !defined(GL_ES_VERSION_2_0)
-    // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
     const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
     const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
-    theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
-  #endif
+    if (theCtx->hasUnpackRowLength)
+    {
+      theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
+    }
+    else if (anExtraBytes >= anAligment)
+    {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
+                           TCollection_AsciiString ("Error: unsupported image stride within OpenGL ES 2.0 [") + myResourceId +"]");
+      Release (theCtx.get());
+      return false;
+    }
   }
 
   myTarget = aTarget;
@@ -659,7 +670,7 @@ bool OpenGl_Texture::InitCompressed (const Handle(OpenGl_Context)& theCtx,
   applyDefaultSamplerParams (theCtx);
 
   // setup the alignment
-  OpenGl_UnpackAlignmentSentry::Reset();
+  OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
 
   Graphic3d_Vec2i aMipSizeXY (theImage.SizeX(), theImage.SizeY());
   const Standard_Byte* aData = theImage.FaceData()->Data();
@@ -667,7 +678,7 @@ bool OpenGl_Texture::InitCompressed (const Handle(OpenGl_Context)& theCtx,
   {
     const Standard_Integer aMipLength = theImage.MipMaps().Value (aMipIter);
     theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_2D, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
-    const GLenum aTexImgErr = glGetError();
+    const GLenum aTexImgErr = theCtx->core11fwd->glGetError();
     if (aTexImgErr != GL_NO_ERROR)
     {
       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
@@ -764,8 +775,8 @@ bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
   myNbSamples = 1;
   myMaxMipLevel = 0;
 
-  const GLsizei aSizeX    = Min (theCtx->MaxTextureSize(), theSizeX);
-  const GLsizei aSizeY    = Min (theCtx->MaxTextureSize(), theSizeY);
+  const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
+  const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
 
   Bind (theCtx);
   applyDefaultSamplerParams (theCtx);
@@ -774,19 +785,16 @@ bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
   mySizedFormat = theFormat.Internal();
 
   // setup the alignment
-  OpenGl_UnpackAlignmentSentry::Reset();
+  OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
 
   theCtx->core11fwd->glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
                                    aSizeX, aSizeY, 0,
                                    myTextFormat, GL_FLOAT, NULL);
 
-  GLint aTestSizeX = 0;
-  GLint aTestSizeY = 0;
-
+  GLint aTestSizeX = 0, aTestSizeY = 0;
   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH,  &aTestSizeX);
   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
-
   if (aTestSizeX == 0 || aTestSizeY == 0)
   {
     Unbind (theCtx);
@@ -796,7 +804,6 @@ bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
   theCtx->core11fwd->glTexImage2D (myTarget, 0, mySizedFormat,
                                    aSizeX, aSizeY, 0,
                                    myTextFormat, GL_FLOAT, NULL);
-
   if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
   {
     Unbind (theCtx);
@@ -805,7 +812,6 @@ bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
 
   mySizeX = aSizeX;
   mySizeY = aSizeY;
-
   Unbind (theCtx);
   return true;
 #else
@@ -865,7 +871,7 @@ bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
   mySizedFormat = theFormat.InternalFormat();
 
   // setup the alignment
-  OpenGl_UnpackAlignmentSentry::Reset();
+  OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
 
 #if !defined (GL_ES_VERSION_2_0)
   theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
@@ -960,7 +966,7 @@ bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)&    theCtx,
           }
         }
 
-        OpenGl_UnpackAlignmentSentry::Reset();
+        OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
       }
       else
       {
@@ -1047,7 +1053,7 @@ bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)&    theCtx,
         {
           const Standard_Integer aMipLength = aCompImage->MipMaps().Value (aMipIter);
           theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
-          const GLenum aTexImgErr = glGetError();
+          const GLenum aTexImgErr = theCtx->core11fwd->glGetError();
           if (aTexImgErr != GL_NO_ERROR)
           {
             theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
@@ -1073,32 +1079,34 @@ bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)&    theCtx,
 
       if (!anImage.IsNull())
       {
-#if !defined(GL_ES_VERSION_2_0)
         const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
-        theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
-
-        // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
         const GLint anExtraBytes = GLint(anImage->RowExtraBytes());
         const GLint aPixelsWidth = GLint(anImage->SizeRowBytes() / anImage->SizePixelBytes());
         const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0;
-        theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
-#else
-        Handle(Image_PixMap) aCopyImage = new Image_PixMap();
-        aCopyImage->InitTrash (theFormat, theSize, theSize);
-        for (unsigned int y = 0; y < theSize; ++y)
+        if (theCtx->hasUnpackRowLength)
+        {
+          theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
+        }
+
+        if (aRowLength > 0
+        && !theCtx->hasUnpackRowLength)
         {
-          for (unsigned int x = 0; x < theSize; ++x)
+          Handle(Image_PixMap) aCopyImage = new Image_PixMap();
+          aCopyImage->InitTrash (theFormat, theSize, theSize);
+          const Standard_Size aRowBytesPacked = std::min (aCopyImage->SizeRowBytes(), anImage->SizeRowBytes());
+          for (unsigned int y = 0; y < theSize; ++y)
           {
-            for (unsigned int aByte = 0; aByte < anImage->SizePixelBytes(); ++aByte)
-            {
-              aCopyImage->ChangeRawValue (y, x)[aByte] = anImage->RawValue (y, x)[aByte];
-            }
+            memcpy (aCopyImage->ChangeRow (y), anImage->ChangeRow (y), aRowBytesPacked);
           }
+          anImage = aCopyImage;
+          const GLint anAligment2 = Min((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
+          theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment2);
         }
-        anImage = aCopyImage;
-        const GLint anAligment = Min((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
-        theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
-#endif
+        else
+        {
+          theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
+        }
+
         aData = anImage->Data();
       }
       else
@@ -1118,7 +1126,7 @@ bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)&    theCtx,
                                      0, aFormat.PixelFormat(), aFormat.DataType(),
                                      aData);
 
-    OpenGl_UnpackAlignmentSentry::Reset();
+    OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
 
     const GLenum anErr = theCtx->core11fwd->glGetError();
     if (anErr != GL_NO_ERROR)
@@ -1278,7 +1286,10 @@ bool OpenGl_Texture::ImageDump (Image_PixMap& theImage,
 
   const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
   theCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
-  theCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
+  if (theCtx->hasPackRowLength)
+  {
+    theCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
+  }
   // glGetTextureImage() allows avoiding to binding texture id, but apparently requires clean FBO binding state...
   //if (theCtx->core45 != NULL) { theCtx->core45->glGetTextureImage (myTextureId, theLevel, aFormat.PixelFormat(), aFormat.DataType(), (GLsizei )theImage.SizeBytes(), theImage.ChangeData()); } else
   {