0030744: Visualization, TKOpenGl - stipple line does not work on OpenGL ES 2.0 IR-2019-07-27
authorkgv <kgv@opencascade.com>
Fri, 19 Jul 2019 13:35:23 +0000 (16:35 +0300)
committerbugmaster <bugmaster@opencascade.com>
Sat, 27 Jul 2019 09:05:35 +0000 (12:05 +0300)
OpenGl_ShaderManager now provides fallback stipple lines GLSL code for obsolete OpenGL ES 2.0 devices.
OpenGl_Caps has been extended by flags disallowing OpenGL extensions usage
and restricting upper OpenGL version to be used by OCCT for testing purposes.

src/OpenGl/OpenGl_Caps.cxx
src/OpenGl/OpenGl_Caps.hxx
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_GraphicDriver.cxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderProgram.cxx
src/OpenGl/OpenGl_ShaderProgram.hxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx

index 569abf5..b1b5d15 100755 (executable)
@@ -51,6 +51,9 @@ OpenGl_Caps::OpenGl_Caps()
 #else
   contextCompatible (Standard_False),
 #endif
+  contextNoExtensions (Standard_False),
+  contextMajorVersionUpper (-1),
+  contextMinorVersionUpper (-1),
   glslWarnings      (Standard_False),
   suppressExtraMsg  (Standard_True),
   glslDumpLevel     (OpenGl_ShaderProgramDumpLevel_Off)
@@ -76,6 +79,9 @@ OpenGl_Caps& OpenGl_Caps::operator= (const OpenGl_Caps& theCopy)
   contextSyncDebug  = theCopy.contextSyncDebug;
   contextNoAccel    = theCopy.contextNoAccel;
   contextCompatible = theCopy.contextCompatible;
+  contextNoExtensions = theCopy.contextNoExtensions;
+  contextMajorVersionUpper = theCopy.contextMajorVersionUpper;
+  contextMinorVersionUpper = theCopy.contextMinorVersionUpper;
   glslWarnings      = theCopy.glslWarnings;
   suppressExtraMsg  = theCopy.suppressExtraMsg;
   glslDumpLevel     = theCopy.glslDumpLevel;
index 6bdc98e..d5747be 100755 (executable)
@@ -107,6 +107,23 @@ public: //! @name context creation parameters
    */
   Standard_Boolean contextCompatible;
 
+  /**
+   * Disallow using OpenGL extensions.
+   * Should be used for debugging purposes only!
+   *
+   * OFF by default.
+   */
+  Standard_Boolean contextNoExtensions;
+
+  /**
+   * Synthetically restrict upper version of OpenGL functionality to be used.
+   * Should be used for debugging purposes only!
+   *
+   * (-1, -1) by default, which means no restriction.
+   */
+  Standard_Integer contextMajorVersionUpper;
+  Standard_Integer contextMinorVersionUpper;
+
 public: //! @name flags to activate verbose output
 
   //! Print GLSL program compilation/linkage warnings, if any. OFF by default.
index ef2a608..d22993d 100644 (file)
@@ -123,6 +123,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   hasTexRGBA8(Standard_True),
   hasFlatShading (OpenGl_FeatureInCore),
 #endif
+  hasGlslBitwiseOps  (OpenGl_FeatureNotAvailable),
   hasDrawBuffers     (OpenGl_FeatureNotAvailable),
   hasFloatBuffer     (OpenGl_FeatureNotAvailable),
   hasHalfFloatBuffer (OpenGl_FeatureNotAvailable),
@@ -749,6 +750,10 @@ Standard_Boolean OpenGl_Context::CheckExtension (const char* theExtName) const
 #endif
     return Standard_False;
   }
+  else if (caps->contextNoExtensions)
+  {
+    return Standard_False;
+  }
 
 #if !defined(GL_ES_VERSION_2_0)
   // available since OpenGL 3.0
@@ -1217,6 +1222,44 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   ReadGlVersion (myGlVerMajor, myGlVerMinor);
   myVendor = (const char* )::glGetString (GL_VENDOR);
   myVendor.LowerCase();
+
+  if (caps->contextMajorVersionUpper != -1)
+  {
+    // synthetically restrict OpenGL version for testing
+    Standard_Integer aCtxVer[2] = { myGlVerMajor, myGlVerMinor };
+    bool isLowered = false;
+    if (myGlVerMajor > caps->contextMajorVersionUpper)
+    {
+      isLowered = true;
+      myGlVerMajor = caps->contextMajorVersionUpper;
+    #if defined(GL_ES_VERSION_2_0)
+      switch (myGlVerMajor)
+      {
+        case 2: myGlVerMinor = 0; break;
+      }
+    #else
+      switch (myGlVerMajor)
+      {
+        case 1: myGlVerMinor = 5; break;
+        case 2: myGlVerMinor = 1; break;
+        case 3: myGlVerMinor = 3; break;
+      }
+    #endif
+    }
+    if (caps->contextMinorVersionUpper != -1
+     && myGlVerMinor > caps->contextMinorVersionUpper)
+    {
+      isLowered = true;
+      myGlVerMinor = caps->contextMinorVersionUpper;
+    }
+    if (isLowered)
+    {
+      PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                   TCollection_AsciiString ("OpenGL version ") + aCtxVer[0] + "." + aCtxVer[1]
+                   + " has been lowered to " + myGlVerMajor + "." + myGlVerMinor);
+    }
+  }
+
   if (!caps->ffpEnable
    && !IsGlGreaterEqual (2, 0))
   {
@@ -1436,6 +1479,9 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   hasSampleVariables = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
                        oesSampleVariables ? OpenGl_FeatureInExtensions
                                           : OpenGl_FeatureNotAvailable;
+  hasGlslBitwiseOps = IsGlGreaterEqual (3, 0)
+                    ? OpenGl_FeatureInCore
+                    : OpenGl_FeatureNotAvailable;
   // without hasHighp, dFdx/dFdy precision is considered too low for flat shading (visual artifacts)
   hasFlatShading = IsGlGreaterEqual (3, 0)
                  ? OpenGl_FeatureInCore
@@ -1474,6 +1520,12 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
                    arbDrawBuffers ? OpenGl_FeatureInExtensions 
                                   : OpenGl_FeatureNotAvailable;
 
+  hasGlslBitwiseOps = IsGlGreaterEqual (3, 0)
+                    ? OpenGl_FeatureInCore
+                    : CheckExtension ("GL_EXT_gpu_shader4")
+                     ? OpenGl_FeatureInExtensions
+                     : OpenGl_FeatureNotAvailable;
+
   hasFloatBuffer = hasHalfFloatBuffer =  IsGlGreaterEqual (3, 0) ? OpenGl_FeatureInCore :
                                          CheckExtension ("GL_ARB_color_buffer_float") ? OpenGl_FeatureInExtensions
                                                                                       : OpenGl_FeatureNotAvailable;
@@ -2989,9 +3041,16 @@ void OpenGl_Context::DiagnosticInformation (TColStd_IndexedDataMapOfStringString
 
   if ((theFlags & Graphic3d_DiagnosticInfo_Device) != 0)
   {
+    Standard_Integer aDriverVer[2] = {};
+    ReadGlVersion (aDriverVer[0], aDriverVer[1]);
     addInfo (theDict, "GLvendor",    (const char*)::glGetString (GL_VENDOR));
     addInfo (theDict, "GLdevice",    (const char*)::glGetString (GL_RENDERER));
     addInfo (theDict, "GLversion",   (const char*)::glGetString (GL_VERSION));
+    if (myGlVerMajor != aDriverVer[0]
+     || myGlVerMinor != aDriverVer[1])
+    {
+      addInfo (theDict, "GLversionOcct", TCollection_AsciiString (myGlVerMajor) + "." + TCollection_AsciiString (myGlVerMinor));
+    }
     if (IsGlGreaterEqual (2, 0))
     {
       addInfo (theDict, "GLSLversion", (const char*)::glGetString (GL_SHADING_LANGUAGE_VERSION));
@@ -3496,8 +3555,23 @@ void OpenGl_Context::SetTypeOfLine (const Aspect_TypeOfLine  theType,
 
   if (!myActiveProgram.IsNull())
   {
-    myActiveProgram->SetUniform (this, "uPattern", aPattern);
-    myActiveProgram->SetUniform (this, "uFactor",  theFactor);
+    if (const OpenGl_ShaderUniformLocation aPatternLoc = myActiveProgram->GetStateLocation (OpenGl_OCCT_LINE_STIPPLE_PATTERN))
+    {
+      if (hasGlslBitwiseOps != OpenGl_FeatureNotAvailable)
+      {
+        myActiveProgram->SetUniform (this, aPatternLoc, aPattern);
+      }
+      else
+      {
+        Standard_Integer aPatArr[16] = {};
+        for (unsigned int aBit = 0; aBit < 16; ++aBit)
+        {
+          aPatArr[aBit] = ((unsigned int)(aPattern) & (1U << aBit)) != 0 ? 1 : 0;
+        }
+        myActiveProgram->SetUniform (this, aPatternLoc, 16, aPatArr);
+      }
+      myActiveProgram->SetUniform (this, myActiveProgram->GetStateLocation (OpenGl_OCCT_LINE_STIPPLE_FACTOR), theFactor);
+    }
     return;
   }
 
index b4c5ca8..187416b 100644 (file)
@@ -889,6 +889,7 @@ public: //! @name extensions
   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
   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)
   OpenGl_FeatureFlag     hasFloatBuffer;     //!< Complex flag indicating support of float color buffer format (desktop OpenGL 3.0, GL_ARB_color_buffer_float, GL_EXT_color_buffer_float)
   OpenGl_FeatureFlag     hasHalfFloatBuffer; //!< Complex flag indicating support of half-float color buffer format (desktop OpenGL 3.0, GL_ARB_color_buffer_float, GL_EXT_color_buffer_half_float)
index ea2d2fb..2e7e49b 100644 (file)
@@ -303,7 +303,10 @@ Standard_Boolean OpenGl_GraphicDriver::InitContext()
     ::Message::DefaultMessenger()->Send ("Error: EGL does not provide OpenGL ES client!", Message_Fail);
     return Standard_False;
   }
-  myEglContext = (Aspect_RenderingContext )eglCreateContext ((EGLDisplay )myEglDisplay, myEglConfig, EGL_NO_CONTEXT, anEglCtxAttribs3);
+  if (myCaps->contextMajorVersionUpper != 2)
+  {
+    myEglContext = (Aspect_RenderingContext )eglCreateContext ((EGLDisplay )myEglDisplay, myEglConfig, EGL_NO_CONTEXT, anEglCtxAttribs3);
+  }
   if ((EGLContext )myEglContext == EGL_NO_CONTEXT)
   {
     myEglContext = (Aspect_RenderingContext )eglCreateContext ((EGLDisplay )myEglDisplay, myEglConfig, EGL_NO_CONTEXT, anEglCtxAttribs2);
index 9dcdbc2..2ee0420 100644 (file)
@@ -1505,6 +1505,8 @@ int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgr
                                               bool theUsesDerivates) const
 {
   int aBits = theBits;
+  const bool toUseDerivates = theUsesDerivates
+                          || (theBits & OpenGl_PO_StippleLine) != 0;
 #if !defined(GL_ES_VERSION_2_0)
   if (myContext->core32 != NULL)
   {
@@ -1518,19 +1520,15 @@ int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgr
       {
         theProgram->SetHeader ("#version 130");
       }
-      else if (myContext->CheckExtension ("GL_EXT_gpu_shader4"))
+      else if (myContext->CheckExtension ("GL_EXT_gpu_shader4")) // myContext->hasGlslBitwiseOps == OpenGl_FeatureInExtensions
       {
         // GL_EXT_gpu_shader4 defines GLSL type "unsigned int", while core GLSL specs define type "uint"
         theProgram->SetHeader ("#extension GL_EXT_gpu_shader4 : enable\n"
                                "#define uint unsigned int");
       }
-      else
-      {
-        aBits = aBits & ~OpenGl_PO_StippleLine;
-      }
     }
   }
-  (void )theUsesDerivates;
+  (void )toUseDerivates;
 #else
   // prefer "100 es" on OpenGL ES 3.0- devices (save the features unavailable before "300 es")
   // and    "300 es" on OpenGL ES 3.1+ devices
@@ -1557,10 +1555,13 @@ int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgr
       else
       {
         aBits = aBits & ~OpenGl_PO_WriteOit;
-        aBits = aBits & ~OpenGl_PO_StippleLine;
+        if (!myContext->oesStdDerivatives)
+        {
+          aBits = aBits & ~OpenGl_PO_StippleLine;
+        }
       }
     }
-    if (theUsesDerivates)
+    if (toUseDerivates)
     {
       if (myContext->IsGlGreaterEqual (3, 0))
       {
@@ -1819,28 +1820,34 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
     const Standard_Integer aBits = defaultGlslVersion (aProgramSrc, "unlit", theBits);
     if ((aBits & OpenGl_PO_StippleLine) != 0)
     {
-      aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("int   uPattern", Graphic3d_TOS_FRAGMENT));
-      aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("float uFactor",  Graphic3d_TOS_FRAGMENT));
+      if (myContext->hasGlslBitwiseOps != OpenGl_FeatureNotAvailable)
+      {
+        aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("int   occStipplePattern", Graphic3d_TOS_FRAGMENT));
+      }
+      else
+      {
+        aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("bool  occStipplePattern[16]", Graphic3d_TOS_FRAGMENT));
+      }
+      aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("float occStippleFactor",  Graphic3d_TOS_FRAGMENT));
       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 occViewport", Graphic3d_TOS_VERTEX));
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 ScreenSpaceCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
       aSrcVertEndMain =
         EOL"  vec2 aPosition   = gl_Position.xy / gl_Position.w;"
         EOL"  aPosition        = aPosition * 0.5 + 0.5;"
         EOL"  ScreenSpaceCoord = aPosition.xy * occViewport.zw + occViewport.xy;";
-      aSrcFragMainGetColor =
-        EOL"  vec2 anAxis = vec2 (0.0);"
+      aSrcFragMainGetColor = TCollection_AsciiString()
+      + EOL"  vec2 anAxis = vec2 (0.0, 1.0);"
         EOL"  if (abs (dFdx (ScreenSpaceCoord.x)) - abs (dFdy (ScreenSpaceCoord.y)) > 0.001)" 
         EOL"  {"
         EOL"    anAxis = vec2 (1.0, 0.0);"
         EOL"  }"
-        EOL"  else"
-        EOL"  {"
-        EOL"    anAxis = vec2 (0.0, 1.0);"
-        EOL"  }"
         EOL"  float aRotatePoint = dot (gl_FragCoord.xy, anAxis);"
-        EOL"  uint  aBit         = uint (floor (aRotatePoint / uFactor + 0.5)) & 15U;"
-        EOL"  if ((uint (uPattern) & (1U << aBit)) == 0U) discard;"
-        EOL"  vec4 aColor = getFinalColor();"
+      + (myContext->hasGlslBitwiseOps != OpenGl_FeatureNotAvailable
+       ? EOL"  uint aBit = uint (floor (aRotatePoint / occStippleFactor + 0.5)) & 15U;"
+         EOL"  if ((uint (occStipplePattern) & (1U << aBit)) == 0U) discard;"
+       : EOL"  int aBit = int (mod (floor (aRotatePoint / occStippleFactor + 0.5), 16.0));"
+         EOL"  if (!occStipplePattern[aBit]) discard;")
+      + EOL"  vec4 aColor = getFinalColor();"
         EOL"  if (aColor.a <= 0.1) discard;"
         EOL"  occSetFragColor (aColor);";
     }
index 9b10c93..b7cb81d 100755 (executable)
@@ -81,6 +81,8 @@ Standard_CString OpenGl_ShaderProgram::PredefinedKeywords[] =
   "occViewport",           // OpenGl_OCCT_VIEWPORT
   "occLineWidth",          // OpenGl_OCCT_LINE_WIDTH
   "occLineFeather",        // OpenGl_OCCT_LINE_FEATHER
+  "occStipplePattern",     // OpenGl_OCCT_LINE_STIPPLE_PATTERN
+  "occStippleFactor",      // OpenGl_OCCT_LINE_STIPPLE_FACTOR
   "occWireframeColor",     // OpenGl_OCCT_WIREFRAME_COLOR
   "occIsQuadMode",         // OpenGl_OCCT_QUAD_MODE_STATE
 
index 15523f4..8016c6e 100755 (executable)
@@ -79,6 +79,8 @@ enum OpenGl_StateVariable
   OpenGl_OCCT_VIEWPORT,
   OpenGl_OCCT_LINE_WIDTH,
   OpenGl_OCCT_LINE_FEATHER,
+  OpenGl_OCCT_LINE_STIPPLE_PATTERN, // occStipplePattern
+  OpenGl_OCCT_LINE_STIPPLE_FACTOR,  // occStippleFactor
   OpenGl_OCCT_WIREFRAME_COLOR,
   OpenGl_OCCT_QUAD_MODE_STATE,
 
index 79ed5dd..7b3fa8f 100644 (file)
@@ -1658,8 +1658,9 @@ TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft
       // alternatively we can disable buffer swap at all, but this might be inappropriate for testing
       //ViewerTest_myDefaultCaps.buffersNoSwap = true;
     }
-    aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection());
+    aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection(), false);
     aGraphicDriver->ChangeOptions() = ViewerTest_myDefaultCaps;
+    aGraphicDriver->InitContext();
 
     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
     toCreateViewer = Standard_True;
@@ -6626,6 +6627,8 @@ static int VCaps (Draw_Interpretor& theDI,
     theDI << "Compatible:" << (aCaps->contextCompatible ? "1" : "0") << "\n";
     theDI << "Stereo:  " << (aCaps->contextStereo ? "1" : "0") << "\n";
     theDI << "WinBuffer: " << (aCaps->useSystemBuffer ? "1" : "0") << "\n";
+    theDI << "NoExt:"    << (aCaps->contextNoExtensions ? "1" : "0") << "\n";
+    theDI << "MaxVersion:" << aCaps->contextMajorVersionUpper << "." << aCaps->contextMinorVersionUpper << "\n";
     return 0;
   }
 
@@ -6769,6 +6772,44 @@ static int VCaps (Draw_Interpretor& theDI,
       }
       aCaps->contextStereo = toEnable;
     }
+    else if (anArgCase == "-noext"
+          || anArgCase == "-noextensions"
+          || anArgCase == "-noextension")
+    {
+      Standard_Boolean toDisable = Standard_True;
+      if (++anArgIter < theArgNb
+      && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toDisable))
+      {
+        --anArgIter;
+      }
+      aCaps->contextNoExtensions = toDisable;
+    }
+    else if (anArgCase == "-maxversion"
+          || anArgCase == "-upperversion"
+          || anArgCase == "-limitversion")
+    {
+      Standard_Integer aVer[2] = { -2, -1 };
+      for (Standard_Integer aValIter = 0; aValIter < 2; ++aValIter)
+      {
+        if (anArgIter + 1 < theArgNb)
+        {
+          const TCollection_AsciiString aStr (theArgVec[anArgIter + 1]);
+          if (aStr.IsIntegerValue())
+          {
+            aVer[aValIter] = aStr.IntegerValue();
+            ++anArgIter;
+          }
+        }
+      }
+      if (aVer[0] < -1
+       || aVer[1] < -1)
+      {
+        std::cout << "Syntax error at '" << anArgCase << "'\n";
+        return 1;
+      }
+      aCaps->contextMajorVersionUpper = aVer[0];
+      aCaps->contextMinorVersionUpper = aVer[1];
+    }
     else
     {
       std::cout << "Error: unknown argument '" << anArg << "'\n";
@@ -13713,6 +13754,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n\t\t:       [-vsync {0|1}] [-useWinBuffer {0|1}]"
     "\n\t\t:       [-quadBuffer {0|1}] [-stereo {0|1}]"
     "\n\t\t:       [-softMode {0|1}] [-noupdate|-update]"
+    "\n\t\t:       [-noExtensions {0|1}] [-maxVersion Major Minor]"
     "\n\t\t: Modify particular graphic driver options:"
     "\n\t\t:  FFP      - use fixed-function pipeline instead of"
     "\n\t\t:             built-in GLSL programs"
@@ -13727,6 +13769,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n\t\t:  softMode          - software OpenGL implementation"
     "\n\t\t:  compatibleProfile - backward-compatible profile"
     "\n\t\t:  quadbuffer        - QuadBuffer"
+    "\n\t\t:  noExtensions      - disallow usage of extensions"
+    "\n\t\t:  maxVersion        - force upper OpenGL version to be used"
     "\n\t\t: Unlike vrenderparams, these parameters control alternative"
     "\n\t\t: rendering paths producing the same visual result when"
     "\n\t\t: possible."