diff --git a/src/OpenGl/OpenGl_CappingAlgo.cxx b/src/OpenGl/OpenGl_CappingAlgo.cxx
index 628cab1432..50cc18661c 100755
--- a/src/OpenGl/OpenGl_CappingAlgo.cxx
+++ b/src/OpenGl/OpenGl_CappingAlgo.cxx
@@ -94,7 +94,7 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)&  theWork
     {
       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
       const Standard_Boolean isOn = (aPlane == aRenderPlane);
-      aContext->ChangeClipping().SetEnabled (aPlane, isOn);
+      aContext->ChangeClipping().SetEnabled (aContext, aPlane, isOn);
     }
 
     glClear (GL_STENCIL_BUFFER_BIT);
@@ -127,7 +127,7 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)&  theWork
     {
       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
       const Standard_Boolean isOn = (aPlane != aRenderPlane);
-      aContext->ChangeClipping().SetEnabled (aPlane, isOn);
+      aContext->ChangeClipping().SetEnabled (aContext, aPlane, isOn);
     }
 
     // render capping plane using the generated stencil mask
@@ -149,7 +149,7 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)&  theWork
   // enable clipping
   for (aCappingIt.Init (aContextPlanes); aCappingIt.More(); aCappingIt.Next())
   {
-    aContext->ChangeClipping().SetEnabled (aCappingIt.Value(), Standard_True);
+    aContext->ChangeClipping().SetEnabled (aContext, aCappingIt.Value(), Standard_True);
   }
 
   // restore rendering aspects
diff --git a/src/OpenGl/OpenGl_CappingPlaneResource.cxx b/src/OpenGl/OpenGl_CappingPlaneResource.cxx
index 89443d68d9..b88e3fbcac 100755
--- a/src/OpenGl/OpenGl_CappingPlaneResource.cxx
+++ b/src/OpenGl/OpenGl_CappingPlaneResource.cxx
@@ -176,11 +176,10 @@ void OpenGl_CappingPlaneResource::UpdateTransform()
   Standard_ShortReal F[3] = { 0.0f, 0.0f, 0.0f };
 
   // project plane normal onto OX to find left vector
-  Standard_ShortReal aConfusion = (Standard_ShortReal)Precision::Confusion();
   Standard_ShortReal aProjLen = 
     sqrt (  (Standard_ShortReal)(anEquation[0] * anEquation[0])
           + (Standard_ShortReal)(anEquation[2] * anEquation[2]));
-  if (aProjLen < aConfusion)
+  if (aProjLen < ShortRealSmall())
   {
     L[0] = 1.0f;
   }
diff --git a/src/OpenGl/OpenGl_Clipping.cxx b/src/OpenGl/OpenGl_Clipping.cxx
index 9bfce4772d..37c7422837 100755
--- a/src/OpenGl/OpenGl_Clipping.cxx
+++ b/src/OpenGl/OpenGl_Clipping.cxx
@@ -14,8 +14,10 @@
 // commercial license or contractual agreement.
 
 #include <OpenGl_Clipping.hxx>
+
 #include <OpenGl_GlCore11.hxx>
 #include <OpenGl_Workspace.hxx>
+#include <OpenGl_Context.hxx>
 
 #if defined(GL_ES_VERSION_2_0)
   // id does not matter for GLSL-based clipping, just for consistency
@@ -48,42 +50,56 @@ void OpenGl_Clipping::Init (const Standard_Integer theMaxPlanes)
 }
 
 // =======================================================================
-// function : Add
+// function : add
 // purpose  :
 // =======================================================================
-void OpenGl_Clipping::Add (Graphic3d_SequenceOfHClipPlane& thePlanes,
-                           const EquationCoords& theCoordSpace,
-                           const Handle(OpenGl_Workspace)& theWS)
+void OpenGl_Clipping::add (const Handle(OpenGl_Context)&   theGlCtx,
+                           const EquationCoords&           theCoordSpace,
+                           Graphic3d_SequenceOfHClipPlane& thePlanes)
 {
-  Handle(OpenGl_Context) aContext = theWS->GetGlContext();
+  const bool toUseFfp = theGlCtx->core11 != NULL
+                     && theGlCtx->caps->ffpEnable;
+  if (!toUseFfp)
+  {
+    addLazy (theGlCtx, theCoordSpace, thePlanes);
+    return;
+  }
 
   if (EquationCoords_View == theCoordSpace)
   {
-    aContext->WorldViewState.Push();
-    aContext->WorldViewState.SetIdentity();
+    theGlCtx->WorldViewState.Push();
+    theGlCtx->WorldViewState.SetIdentity();
   }
 
   // Set either identity or pure view matrix.
-  aContext->ApplyWorldViewMatrix();
+  theGlCtx->ApplyWorldViewMatrix();
 
-  Add (thePlanes, theCoordSpace);
+  addLazy (theGlCtx, theCoordSpace, thePlanes);
 
   if (EquationCoords_View == theCoordSpace)
   {
-    aContext->WorldViewState.Pop();
+    theGlCtx->WorldViewState.Pop();
   }
 
   // Restore combined model-view matrix.
-  aContext->ApplyModelViewMatrix();
-
+  theGlCtx->ApplyModelViewMatrix();
 }
 
 // =======================================================================
-// function : Add
+// function : addLazy
 // purpose  :
 // =======================================================================
-void OpenGl_Clipping::Add (Graphic3d_SequenceOfHClipPlane& thePlanes, const EquationCoords& theCoordSpace)
+void OpenGl_Clipping::addLazy (const Handle(OpenGl_Context)&   theGlCtx,
+                               const EquationCoords&           theCoordSpace,
+                               Graphic3d_SequenceOfHClipPlane& thePlanes)
 {
+#if !defined(GL_ES_VERSION_2_0)
+  const bool toUseFfp = theGlCtx->core11 != NULL
+                     && theGlCtx->caps->ffpEnable;
+#else
+  (void )theGlCtx;
+#endif
+
   Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (thePlanes);
   while (aPlaneIt.More() && myEmptyPlaneIds->HasFree())
   {
@@ -99,8 +115,11 @@ void OpenGl_Clipping::Add (Graphic3d_SequenceOfHClipPlane& thePlanes, const Equa
     myPlaneStates.Bind (aPlane, PlaneProps (theCoordSpace, anID, Standard_True));
 
   #if !defined(GL_ES_VERSION_2_0)
-    ::glEnable ((GLenum)anID);
-    ::glClipPlane ((GLenum)anID, aPlane->GetEquation());
+    if (toUseFfp)
+    {
+      ::glEnable ((GLenum)anID);
+      theGlCtx->core11->glClipPlane ((GLenum)anID, aPlane->GetEquation());
+    }
   #endif
     if (aPlane->IsCapping())
     {
@@ -127,8 +146,16 @@ void OpenGl_Clipping::Add (Graphic3d_SequenceOfHClipPlane& thePlanes, const Equa
 // function : Remove
 // purpose  :
 // =======================================================================
-void OpenGl_Clipping::Remove (const Graphic3d_SequenceOfHClipPlane& thePlanes)
+void OpenGl_Clipping::Remove (const Handle(OpenGl_Context)&         theGlCtx,
+                              const Graphic3d_SequenceOfHClipPlane& thePlanes)
 {
+#if !defined(GL_ES_VERSION_2_0)
+  const bool toUseFfp = theGlCtx->core11 != NULL
+                     && theGlCtx->caps->ffpEnable;
+#else
+  (void )theGlCtx;
+#endif
+
   Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (thePlanes);
   for (; aPlaneIt.More(); aPlaneIt.Next())
   {
@@ -143,7 +170,10 @@ void OpenGl_Clipping::Remove (const Graphic3d_SequenceOfHClipPlane& thePlanes)
     if (aProps.IsEnabled)
     {
     #if !defined(GL_ES_VERSION_2_0)
-      glDisable ((GLenum)anID);
+      if (toUseFfp)
+      {
+        ::glDisable ((GLenum)anID);
+      }
     #endif
       if (aPlane->IsCapping())
       {
@@ -179,8 +209,9 @@ void OpenGl_Clipping::Remove (const Graphic3d_SequenceOfHClipPlane& thePlanes)
 // function : SetEnabled
 // purpose  :
 // =======================================================================
-void OpenGl_Clipping::SetEnabled (const Handle(Graphic3d_ClipPlane)& thePlane,
-                                  const Standard_Boolean theIsEnabled)
+void OpenGl_Clipping::SetEnabled (const Handle(OpenGl_Context)&      theGlCtx,
+                                  const Handle(Graphic3d_ClipPlane)& thePlane,
+                                  const Standard_Boolean             theIsEnabled)
 {
   if (!Contains (thePlane))
   {
@@ -195,11 +226,16 @@ void OpenGl_Clipping::SetEnabled (const Handle(Graphic3d_ClipPlane)& thePlane,
 
 #if !defined(GL_ES_VERSION_2_0)
   GLenum anID = (GLenum)aProps.ContextID;
+  const bool toUseFfp = theGlCtx->core11 != NULL
+                     && theGlCtx->caps->ffpEnable;
 #endif
   if (theIsEnabled)
   {
   #if !defined(GL_ES_VERSION_2_0)
-    glEnable (anID);
+    if (toUseFfp)
+    {
+      ::glEnable (anID);
+    }
   #endif
     if (thePlane->IsCapping())
     {
@@ -213,7 +249,10 @@ void OpenGl_Clipping::SetEnabled (const Handle(Graphic3d_ClipPlane)& thePlane,
   else
   {
   #if !defined(GL_ES_VERSION_2_0)
-    glDisable (anID);
+    if (toUseFfp)
+    {
+      ::glDisable (anID);
+    }
   #endif
     if (thePlane->IsCapping())
     {
diff --git a/src/OpenGl/OpenGl_Clipping.hxx b/src/OpenGl/OpenGl_Clipping.hxx
index e7e1f10fc5..b59022162d 100755
--- a/src/OpenGl/OpenGl_Clipping.hxx
+++ b/src/OpenGl/OpenGl_Clipping.hxx
@@ -24,6 +24,7 @@
 #include <Standard_TypeDef.hxx>
 #include <OpenGl_Matrix.hxx>
 
+class OpenGl_Context;
 class OpenGl_Workspace;
 
 //! This class contains logics related to tracking and modification of clipping plane
@@ -107,14 +108,18 @@ public: //! @name clipping state modification commands
   //! to transform equation coordinates. The planes become enabled in the context.
   //! If the number of the passed planes exceeds capabilities of OpenGl, the last planes
   //! are simply ignored.
-  //! @param thePlanes [in/out] the list of planes to be added.
+  //!
+  //! Within FFP, method also temporarily resets ModelView matrix before calling glClipPlane().
+  //! Otherwise the method just redirects to addLazy().
+  //!
+  //! @param theGlCtx [in] context to access the matrices
+  //! @param theCoordSpace [in] the equation definition space
+  //! @param thePlanes [in/out] the list of planes to be added
   //! The list then provides information on which planes were really added to clipping state.
   //! This list then can be used to fall back to previous state.
-  //! @param theCoordSpace [in] the equation definition space.
-  //! @param theWS [in] the workspace to access the matrices.
-  Standard_EXPORT void Add (Graphic3d_SequenceOfHClipPlane& thePlanes,
-                            const EquationCoords& theCoordSpace,
-                            const Handle(OpenGl_Workspace)& theWS);
+  Standard_EXPORT void add (const Handle(OpenGl_Context)&   theGlCtx,
+                            const EquationCoords&           theCoordSpace,
+                            Graphic3d_SequenceOfHClipPlane& thePlanes);
 
   //! Add planes to the context clipping at the specified system of coordinates.
   //! This method assumes that appropriate matrix is already set in context state.
@@ -124,71 +129,66 @@ public: //! @name clipping state modification commands
   //! The list then provides information on which planes were really added to clipping state.
   //! This list then can be used to fall back to previous state.
   //! @param theCoordSpace [in] the equation definition space.
-  Standard_EXPORT void Add (Graphic3d_SequenceOfHClipPlane& thePlanes,
-                            const EquationCoords& theCoordSpace);
+  Standard_EXPORT void addLazy (const Handle(OpenGl_Context)&   theGlCtx,
+                                const EquationCoords&           theCoordSpace,
+                                Graphic3d_SequenceOfHClipPlane& thePlanes);
 
   //! Remove the passed set of clipping planes from the context state.
   //! @param thePlanes [in] the planes to remove from list.
-  Standard_EXPORT void Remove (const Graphic3d_SequenceOfHClipPlane& thePlanes);
+  Standard_EXPORT void Remove (const Handle(OpenGl_Context)&         theGlCtx,
+                               const Graphic3d_SequenceOfHClipPlane& thePlanes);
 
   //! Enable or disable clipping plane in the OpenGl context.
   //! @param thePlane [in] the plane to affect.
   //! @param theIsEnabled [in] the state of the plane.
-  Standard_EXPORT void SetEnabled (const Handle(Graphic3d_ClipPlane)& thePlane,
-                                   const Standard_Boolean theIsEnabled);
+  Standard_EXPORT void SetEnabled (const Handle(OpenGl_Context)&      theGlCtx,
+                                   const Handle(Graphic3d_ClipPlane)& thePlane,
+                                   const Standard_Boolean             theIsEnabled);
 
 public: //! @name Short-cuts
 
   //! Add planes to the context clipping at the view system of coordinates.
   //! If the number of the passed planes exceeds capabilities of OpenGl, the last planes
   //! are simply ignored.
-  //! @param thePlanes [in/out] the list of planes to be added.
+  //! @param theGlCtx [in] context to access the matrices
+  //! @param thePlanes [in/out] the list of planes to be added
   //! The list then provides information on which planes were really added to clipping state.
   //! This list then can be used to fall back to previous state.
-  //! @param theWS [in] the workspace to access the matrices.
-  inline void AddView (Graphic3d_SequenceOfHClipPlane& thePlanes, const Handle(OpenGl_Workspace)& theWS)
+  inline void AddView (const Handle(OpenGl_Context)&   theGlCtx,
+                       Graphic3d_SequenceOfHClipPlane& thePlanes)
   {
-    Add (thePlanes, EquationCoords_View, theWS);
-  }
-
-  //! Add planes to the context clipping at the view system of coordinates.
-  //! If the number of the passed planes exceeds capabilities of OpenGl, the last planes
-  //! are simply ignored.
-  //! @param thePlanes [in/out] the list of planes to be added.
-  //! The list then provides information on which planes were really added to clipping state.
-  //! This list then can be used to fall back to previous state.
-  inline void AddView (Graphic3d_SequenceOfHClipPlane& thePlanes)
-  {
-    Add (thePlanes, EquationCoords_View);
+    add (theGlCtx, EquationCoords_View, thePlanes);
   }
 
   //! Add planes to the context clipping at the world system of coordinates.
   //! If the number of the passed planes exceeds capabilities of OpenGl, the last planes
   //! are simply ignored.
-  //! @param thePlanes [in/out] the list of planes to be added.
+  //! @param theGlCtx [in] context to access the matrices
+  //! @param thePlanes [in/out] the list of planes to be added
   //! The list then provides information on which planes were really added to clipping state.
   //! This list then can be used to fall back to previous state.
-  //! @param theWS [in] the workspace to access the matrices.
-  inline void AddWorld (Graphic3d_SequenceOfHClipPlane& thePlanes, const Handle(OpenGl_Workspace)& theWS)
+  inline void AddWorld (const Handle(OpenGl_Context)&   theGlCtx,
+                        Graphic3d_SequenceOfHClipPlane& thePlanes)
   {
-    Add (thePlanes, EquationCoords_World, theWS);
+    add (theGlCtx, EquationCoords_World, thePlanes);
   }
 
   //! Add planes to the context clipping at the world system of coordinates.
   //! If the number of the passed planes exceeds capabilities of OpenGl, the last planes
   //! are simply ignored.
-  //! @param thePlanes [in/out] the list of planes to be added.
+  //! @param thePlanes [in/out] the list of planes to be added
   //! The list then provides information on which planes were really added to clipping state.
   //! This list then can be used to fall back to previous state.
-  inline void AddWorld (Graphic3d_SequenceOfHClipPlane& thePlanes)
+  inline void AddWorldLazy (const Handle(OpenGl_Context)&   theGlCtx,
+                            Graphic3d_SequenceOfHClipPlane& thePlanes)
   {
-    Add (thePlanes, EquationCoords_World);
+    addLazy (theGlCtx, EquationCoords_World, thePlanes);
   }
 
   //! Remove all of the planes from context state.
-  inline void RemoveAll()
+  inline void RemoveAll (const Handle(OpenGl_Context)& theGlCtx)
   {
-    Remove (Planes());
+    Remove (theGlCtx, Planes());
   }
 
 private:
diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx
index 53ef7a2630..2a960a2d87 100644
--- a/src/OpenGl/OpenGl_Context.cxx
+++ b/src/OpenGl/OpenGl_Context.cxx
@@ -29,6 +29,7 @@
 #include <OpenGl_FrameBuffer.hxx>
 #include <OpenGl_Sampler.hxx>
 #include <OpenGl_ShaderManager.hxx>
+#include <Graphic3d_TransformUtils.hxx>
 
 #include <Message_Messenger.hxx>
 
@@ -2584,6 +2585,53 @@ void OpenGl_Context::SetLineWidth (const Standard_ShortReal theWidth)
 #endif
 }
 
+// =======================================================================
+// function : SetTextureMatrix
+// purpose  :
+// =======================================================================
+void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams)
+{
+  if (theParams.IsNull())
+  {
+    return;
+  }
+  else if (!myActiveProgram.IsNull())
+  {
+    const GLint aUniLoc = myActiveProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_TRSF2D);
+    if (aUniLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
+    {
+      return;
+    }
+
+    // pack transformation parameters
+    OpenGl_Vec4 aTrsf[2];
+    aTrsf[0].xy() = theParams->Translation();
+    aTrsf[0].zw() = theParams->Scale();
+    aTrsf[1].x()  = std::sin (-theParams->Rotation() * static_cast<float> (M_PI / 180.0));
+    aTrsf[1].y()  = std::cos (-theParams->Rotation() * static_cast<float> (M_PI / 180.0));
+    myActiveProgram->SetUniform (this, aUniLoc, 2, aTrsf);
+    return;
+  }
+
+#if !defined(GL_ES_VERSION_2_0)
+  if (core11 != NULL)
+  {
+    GLint aMatrixMode = GL_TEXTURE;
+    ::glGetIntegerv (GL_MATRIX_MODE, &aMatrixMode);
+
+    core11->glMatrixMode (GL_TEXTURE);
+    OpenGl_Mat4 aTextureMat;
+    const Graphic3d_Vec2& aScale = theParams->Scale();
+    const Graphic3d_Vec2& aTrans = theParams->Translation();
+    Graphic3d_TransformUtils::Scale     (aTextureMat,  aScale.x(),  aScale.y(), 1.0f);
+    Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y(), 0.0f);
+    Graphic3d_TransformUtils::Rotate    (aTextureMat, -theParams->Rotation(), 0.0f, 0.0f, 1.0f);
+    core11->glLoadMatrixf (aTextureMat);
+    core11->glMatrixMode (aMatrixMode);
+  }
+#endif
+}
+
 // =======================================================================
 // function : SetPointSize
 // purpose  :
diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx
index 98a7fa979d..074f467e5d 100644
--- a/src/OpenGl/OpenGl_Context.hxx
+++ b/src/OpenGl/OpenGl_Context.hxx
@@ -554,6 +554,9 @@ public: //! @name methods to alter or retrieve current state
   //! Setup point size.
   Standard_EXPORT void SetPointSize (const Standard_ShortReal theSize);
 
+  //! Setup texture matrix to active GLSL program or to FFP global state using glMatrixMode (GL_TEXTURE).
+  Standard_EXPORT void SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams);
+
   //! Bind default Vertex Array Object
   Standard_EXPORT void BindDefaultVao();
 
diff --git a/src/OpenGl/OpenGl_LineAttributes.cxx b/src/OpenGl/OpenGl_LineAttributes.cxx
index 646a89d533..3ac75e415f 100644
--- a/src/OpenGl/OpenGl_LineAttributes.cxx
+++ b/src/OpenGl/OpenGl_LineAttributes.cxx
@@ -553,6 +553,11 @@ void OpenGl_LineAttributes::Init (const Handle(OpenGl_Context)& theGlCtx)
 void OpenGl_LineAttributes::SetTypeOfHatch (const int theType) const
 {
 #if !defined(GL_ES_VERSION_2_0)
+  if (myPatternBase == 0)
+  {
+    return;
+  }
+
   if (theType != 0)
   {
     glCallList ((GLuint )myPatternBase + (GLuint )theType);
diff --git a/src/OpenGl/OpenGl_PrimitiveArray.cxx b/src/OpenGl/OpenGl_PrimitiveArray.cxx
index d6a89a8506..c9767322e7 100644
--- a/src/OpenGl/OpenGl_PrimitiveArray.cxx
+++ b/src/OpenGl/OpenGl_PrimitiveArray.cxx
@@ -784,15 +784,22 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
         }
         default:
         {
+          const Handle(OpenGl_Texture)& aTexture = theWorkspace->ActiveTexture();
           const Standard_Boolean isLightOnFace = isLightOn
-                                              && (theWorkspace->ActiveTexture().IsNull()
-                                               || theWorkspace->ActiveTexture()->GetParams()->IsModulate());
-          aCtx->ShaderManager()->BindProgram (anAspectFace, theWorkspace->ActiveTexture(), isLightOnFace, hasVertColor, anAspectFace->ShaderProgramRes (aCtx));
+                                              && (aTexture.IsNull()
+                                               || aTexture->GetParams()->IsModulate());
+          aCtx->ShaderManager()->BindProgram (anAspectFace, aTexture, isLightOnFace, hasVertColor, anAspectFace->ShaderProgramRes (aCtx));
           break;
         }
       }
     }
 
+    if (!theWorkspace->ActiveTexture().IsNull()
+     && myDrawMode != GL_POINTS) // transformation is not supported within point sprites
+    {
+      aCtx->SetTextureMatrix (theWorkspace->ActiveTexture()->GetParams());
+    }
+
     aCtx->SetColor4fv (*(const OpenGl_Vec4* )(myDrawMode <= GL_LINE_STRIP ? aLineColor->rgb : anInteriorColor->rgb));
     if (myDrawMode == GL_LINES
      || myDrawMode == GL_LINE_STRIP)
diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx
index d1648192f0..5eb6e537c2 100644
--- a/src/OpenGl/OpenGl_ShaderManager.cxx
+++ b/src/OpenGl/OpenGl_ShaderManager.cxx
@@ -36,11 +36,20 @@ namespace
 
 #define EOL "\n"
 
-//! Definition of VertColor varying.
+//! Definition of TexCoord varying.
 const char THE_VARY_TexCoord_OUT[] =
-  EOL"THE_SHADER_OUT vec2 TexCoord;";
+  EOL"THE_SHADER_OUT vec4 TexCoord;";
 const char THE_VARY_TexCoord_IN[] =
-  EOL"THE_SHADER_IN  vec2 TexCoord;";
+  EOL"THE_SHADER_IN  vec4 TexCoord;";
+//! Compute TexCoord value in Vertex Shader
+const char THE_VARY_TexCoord_Trsf[] =
+  EOL"  float aRotSin = occTextureTrsf_RotationSin();"
+  EOL"  float aRotCos = occTextureTrsf_RotationCos();"
+  EOL"  vec2  aTex2   = (occTexCoord.xy + occTextureTrsf_Translation()) * occTextureTrsf_Scale();"
+  EOL"  vec2  aCopy   = aTex2;"
+  EOL"  aTex2.x = aCopy.x * aRotCos - aCopy.y * aRotSin;"
+  EOL"  aTex2.y = aCopy.x * aRotSin + aCopy.y * aRotCos;"
+  EOL"  TexCoord = vec4(aTex2, occTexCoord.zw);";
 
 //! Auxiliary function to transform normal
 const char THE_FUNC_transformNormal[] =
@@ -1026,8 +1035,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
 {
   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
-     + THE_VARY_TexCoord_OUT
-     + EOL"void main()"
+     + EOL"THE_SHADER_OUT vec2 TexCoord;"
+       EOL"void main()"
        EOL"{"
        EOL"  TexCoord = occTexCoord.st;"
        EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
@@ -1043,7 +1052,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
 #endif
 
   TCollection_AsciiString aSrcFrag = TCollection_AsciiString() +
-     + THE_VARY_TexCoord_IN
+     + EOL"THE_SHADER_IN vec2 TexCoord;"
      + aSrcGetAlpha
      + EOL"void main()"
        EOL"{"
@@ -1193,11 +1202,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad
     {
       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
-      aSrcVertExtraMain +=
-        EOL"  TexCoord = occTexCoord.st;";
+      aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
 
       aSrcFragGetColor =
-        EOL"vec4 getColor(void) { return occTexture2D(occActiveSampler, TexCoord.st); }";
+        EOL"vec4 getColor(void) { return occTexture2D(occActiveSampler, TexCoord.st / TexCoord.w); }";
     }
     else if ((theBits & OpenGl_PO_TextureEnv) != 0)
     {
@@ -1440,14 +1448,13 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
     {
       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
-      aSrcVertExtraMain +=
-        EOL"  TexCoord = occTexCoord.st;";
+      aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
 
       aSrcFragGetColor =
         EOL"vec4 getColor(void)"
         EOL"{"
         EOL"  vec4 aColor = gl_FrontFacing ? FrontColor : BackColor;"
-        EOL"  return occTexture2D(occActiveSampler, TexCoord.st) * aColor;"
+        EOL"  return occTexture2D(occActiveSampler, TexCoord.st / TexCoord.w) * aColor;"
         EOL"}";
     }
   }
@@ -1560,14 +1567,13 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
     {
       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
-      aSrcVertExtraMain +=
-        EOL"  TexCoord = occTexCoord.st;";
+      aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
 
       aSrcFragGetColor =
         EOL"vec4 getColor(void)"
         EOL"{"
         EOL"  vec4 aColor = " thePhongCompLight ";"
-        EOL"  return occTexture2D(occActiveSampler, TexCoord.st) * aColor;"
+        EOL"  return occTexture2D(occActiveSampler, TexCoord.st / TexCoord.w) * aColor;"
         EOL"}";
     }
   }
diff --git a/src/OpenGl/OpenGl_ShaderProgram.cxx b/src/OpenGl/OpenGl_ShaderProgram.cxx
index 8a1e8d29f3..9898ae3a6f 100755
--- a/src/OpenGl/OpenGl_ShaderProgram.cxx
+++ b/src/OpenGl/OpenGl_ShaderProgram.cxx
@@ -62,6 +62,7 @@ Standard_CString OpenGl_ShaderProgram::PredefinedKeywords[] =
   "occBackMaterial",       // OpenGl_OCCT_BACK_MATERIAL
   "occColor",              // OpenGl_OCCT_COLOR
 
+  "occTexTrsf2d",          // OpenGl_OCCT_TEXTURE_TRSF2D
   "occPointSize"           // OpenGl_OCCT_POINT_SIZE
 
 };
diff --git a/src/OpenGl/OpenGl_ShaderProgram.hxx b/src/OpenGl/OpenGl_ShaderProgram.hxx
index d49b13ed06..ebea3a311d 100755
--- a/src/OpenGl/OpenGl_ShaderProgram.hxx
+++ b/src/OpenGl/OpenGl_ShaderProgram.hxx
@@ -68,6 +68,7 @@ enum OpenGl_StateVariable
   OpenGl_OCCT_BACK_MATERIAL,
   OpenGl_OCCT_COLOR,
 
+  OpenGl_OCCT_TEXTURE_TRSF2D,
   OpenGl_OCCT_POINT_SIZE,
 
   // DON'T MODIFY THIS ITEM (insert new items before it)
diff --git a/src/OpenGl/OpenGl_Structure.cxx b/src/OpenGl/OpenGl_Structure.cxx
index c7a5699a24..69d2e4dac3 100644
--- a/src/OpenGl/OpenGl_Structure.cxx
+++ b/src/OpenGl/OpenGl_Structure.cxx
@@ -637,7 +637,7 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con
   if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty())
   {
     // add planes at loaded view matrix state
-    aCtx->ChangeClipping().AddWorld (*aUserPlanes, theWorkspace);
+    aCtx->ChangeClipping().AddWorld (aCtx, *aUserPlanes);
 
     // Set OCCT state uniform variables
     if (!aCtx->ShaderManager()->IsEmpty())
@@ -668,7 +668,7 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con
   // Revert structure clippings
   if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty())
   {
-    aCtx->ChangeClipping().Remove (*aUserPlanes);
+    aCtx->ChangeClipping().Remove (aCtx, *aUserPlanes);
 
     // Set OCCT state uniform variables
     if (!aCtx->ShaderManager()->IsEmpty())
diff --git a/src/OpenGl/OpenGl_View_Redraw.cxx b/src/OpenGl/OpenGl_View_Redraw.cxx
index 85af74fedb..f123f695ce 100644
--- a/src/OpenGl/OpenGl_View_Redraw.cxx
+++ b/src/OpenGl/OpenGl_View_Redraw.cxx
@@ -926,7 +926,7 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
   // before drawing auxiliary stuff (trihedrons, overlayer)
   myWorkspace->ResetAppliedAspect();
 
-  aContext->ChangeClipping().RemoveAll();
+  aContext->ChangeClipping().RemoveAll (aContext);
 
   if (!aManager->IsEmpty())
   {
@@ -1192,7 +1192,7 @@ void OpenGl_View::renderScene (OpenGl_FrameBuffer*    theReadDrawFbo,
       }
 
       // add planes at loaded view matrix state
-      aContext->ChangeClipping().AddView (aSlicingPlanes, myWorkspace);
+      aContext->ChangeClipping().AddView (aContext, aSlicingPlanes);
     }
   }
 
@@ -1223,7 +1223,7 @@ void OpenGl_View::renderScene (OpenGl_FrameBuffer*    theReadDrawFbo,
 
     if (!aUserPlanes.IsEmpty())
     {
-      aContext->ChangeClipping().AddWorld (aUserPlanes);
+      aContext->ChangeClipping().AddWorldLazy (aContext, aUserPlanes);
     }
 
     if (!aContext->ShaderManager()->IsEmpty())
diff --git a/src/OpenGl/OpenGl_Workspace.cxx b/src/OpenGl/OpenGl_Workspace.cxx
index 8b94e7264b..ede088caae 100644
--- a/src/OpenGl/OpenGl_Workspace.cxx
+++ b/src/OpenGl/OpenGl_Workspace.cxx
@@ -346,21 +346,8 @@ void OpenGl_Workspace::setTextureParams (Handle(OpenGl_Texture)&
   }
 
 #if !defined(GL_ES_VERSION_2_0)
-  GLint aMatrixMode = GL_TEXTURE;
   if (myGlContext->core11 != NULL)
   {
-    glGetIntegerv (GL_MATRIX_MODE, &aMatrixMode);
-
-    // setup texture matrix
-    glMatrixMode (GL_TEXTURE);
-    OpenGl_Mat4 aTextureMat;
-    const Graphic3d_Vec2& aScale = aParams->Scale();
-    const Graphic3d_Vec2& aTrans = aParams->Translation();
-    Graphic3d_TransformUtils::Scale     (aTextureMat,  aScale.x(),  aScale.y(), 1.0f);
-    Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y(), 0.0f);
-    Graphic3d_TransformUtils::Rotate    (aTextureMat, -aParams->Rotation(), 0.0f, 0.0f, 1.0f);
-    glLoadMatrixf (aTextureMat);
-
     GLint anEnvMode = GL_MODULATE; // lighting mode
     if (!aParams->IsModulate())
     {
@@ -573,12 +560,6 @@ void OpenGl_Workspace::setTextureParams (Handle(OpenGl_Texture)&
     default: break;
   }
 
-#if !defined(GL_ES_VERSION_2_0)
-  if (myGlContext->core11 != NULL)
-  {
-    glMatrixMode (aMatrixMode); // turn back active matrix
-  }
-#endif
   theTexture->SetParams (aParams);
 }
 
diff --git a/src/Shaders/Declarations.glsl b/src/Shaders/Declarations.glsl
index eb98ace021..6dd9f62c3d 100644
--- a/src/Shaders/Declarations.glsl
+++ b/src/Shaders/Declarations.glsl
@@ -107,6 +107,7 @@ uniform               vec4      occColor;              //!< color value (in case
 uniform THE_PREC_ENUM int       occDistinguishingMode; //!< Are front and back faces distinguished?
 uniform THE_PREC_ENUM int       occTextureEnable;      //!< Is texture enabled?
 uniform               sampler2D occActiveSampler;      //!< Current active sampler
+uniform               vec4      occTexTrsf2d[2];       //!< 2D texture transformation parameters
 uniform               float     occPointSize;          //!< point size
 
 // clipping planes state
diff --git a/src/Shaders/DeclarationsImpl.glsl b/src/Shaders/DeclarationsImpl.glsl
index 4c4754a030..eee338b6f0 100644
--- a/src/Shaders/DeclarationsImpl.glsl
+++ b/src/Shaders/DeclarationsImpl.glsl
@@ -50,3 +50,9 @@ vec4  occBackMaterial_Specular(void)      { return occBackMaterial[2]; }
 vec4  occBackMaterial_Emission(void)      { return occBackMaterial[3]; }
 float occBackMaterial_Shininess(void)     { return occBackMaterial[4].x; }
 float occBackMaterial_Transparency(void)  { return occBackMaterial[4].y; }
+
+// 2D texture coordinates transformation
+vec2  occTextureTrsf_Translation(void) { return occTexTrsf2d[0].xy; }
+vec2  occTextureTrsf_Scale(void)       { return occTexTrsf2d[0].zw; }
+float occTextureTrsf_RotationSin(void) { return occTexTrsf2d[1].x; }
+float occTextureTrsf_RotationCos(void) { return occTexTrsf2d[1].y; }
diff --git a/tests/demo/samples/dimensionsglsl b/tests/demo/samples/dimensionsglsl
new file mode 100644
index 0000000000..4c6446bece
--- /dev/null
+++ b/tests/demo/samples/dimensionsglsl
@@ -0,0 +1,5 @@
+source $env(CASROOT)/samples/tcl/dimensions.tcl
+vcaps -ffp 0
+vdump $imagedir/${test_image}.png
+
+puts "TEST COMPLETED"
diff --git a/tests/v3d/glsl/texture_trsf b/tests/v3d/glsl/texture_trsf
new file mode 100644
index 0000000000..ef3d9fb877
--- /dev/null
+++ b/tests/v3d/glsl/texture_trsf
@@ -0,0 +1,39 @@
+puts "========"
+puts "Texture 2D transformation"
+puts "========"
+
+set aTexture [locate_data_file bug26122_texture_trsf_ref.png]
+pload MODELING VISUALIZATION
+box b 1 1 1
+explode b F
+vclear
+vclose ALL
+vinit View1 w=512 h=512
+vtop
+vsetdispmode 1
+vdisplay b_6
+vfit
+
+vcaps -ffp 1
+vtexture b_6 $aTexture -modulate off
+vdump $::imagedir/${::casename}_identity_ffp.png
+vcaps -ffp 0
+vdump $::imagedir/${::casename}_identity_glsl.png
+
+vcaps -ffp 1
+vtexture b_6 $aTexture -origin 0.0 0.0 -scale 1.25 0.5
+vdump $::imagedir/${::casename}_scale_ffp.png
+vcaps -ffp 0
+vdump $::imagedir/${::casename}_scale_glsl.png
+
+vcaps -ffp 1
+vtexture b_6 $aTexture -origin 0.25 -0.25 -scale 1.0 1.0
+vdump $::imagedir/${::casename}_translate_ffp.png
+vcaps -ffp 0
+vdump $::imagedir/${::casename}_translate_glsl.png
+
+vcaps -ffp 1
+vtexture b_6 $aTexture -origin 0.25 -0.25 -scale 1.1 0.8
+vdump $::imagedir/${::casename}_ffp.png
+vcaps -ffp 0
+vdump $::imagedir/${::casename}_glsl.png