From 59515ca600bbaa9fdcf7e501bb60104ea54cf35f Mon Sep 17 00:00:00 2001 From: kgv Date: Fri, 19 Jul 2019 16:35:23 +0300 Subject: [PATCH] 0030744: Visualization, TKOpenGl - stipple line does not work on OpenGL ES 2.0 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 | 6 ++ src/OpenGl/OpenGl_Caps.hxx | 17 +++++ src/OpenGl/OpenGl_Context.cxx | 78 +++++++++++++++++++- src/OpenGl/OpenGl_Context.hxx | 1 + src/OpenGl/OpenGl_GraphicDriver.cxx | 5 +- src/OpenGl/OpenGl_ShaderManager.cxx | 45 ++++++----- src/OpenGl/OpenGl_ShaderProgram.cxx | 2 + src/OpenGl/OpenGl_ShaderProgram.hxx | 2 + src/ViewerTest/ViewerTest_ViewerCommands.cxx | 46 +++++++++++- 9 files changed, 179 insertions(+), 23 deletions(-) diff --git a/src/OpenGl/OpenGl_Caps.cxx b/src/OpenGl/OpenGl_Caps.cxx index 569abf5e75..b1b5d152a2 100755 --- a/src/OpenGl/OpenGl_Caps.cxx +++ b/src/OpenGl/OpenGl_Caps.cxx @@ -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; diff --git a/src/OpenGl/OpenGl_Caps.hxx b/src/OpenGl/OpenGl_Caps.hxx index 6bdc98e92e..d5747be4c1 100755 --- a/src/OpenGl/OpenGl_Caps.hxx +++ b/src/OpenGl/OpenGl_Caps.hxx @@ -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. diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index ef2a608da6..d22993dc01 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -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; } diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx index b4c5ca85f7..187416bedc 100644 --- a/src/OpenGl/OpenGl_Context.hxx +++ b/src/OpenGl/OpenGl_Context.hxx @@ -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) diff --git a/src/OpenGl/OpenGl_GraphicDriver.cxx b/src/OpenGl/OpenGl_GraphicDriver.cxx index ea2d2fbe53..2e7e49b10f 100644 --- a/src/OpenGl/OpenGl_GraphicDriver.cxx +++ b/src/OpenGl/OpenGl_GraphicDriver.cxx @@ -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); diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index 9dcdbc22fd..2ee04208b8 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -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);"; } diff --git a/src/OpenGl/OpenGl_ShaderProgram.cxx b/src/OpenGl/OpenGl_ShaderProgram.cxx index 9b10c93b86..b7cb81d16f 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.cxx +++ b/src/OpenGl/OpenGl_ShaderProgram.cxx @@ -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 diff --git a/src/OpenGl/OpenGl_ShaderProgram.hxx b/src/OpenGl/OpenGl_ShaderProgram.hxx index 15523f4bee..8016c6e82c 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.hxx +++ b/src/OpenGl/OpenGl_ShaderProgram.hxx @@ -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, diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 79ed5dd232..7b3fa8f15e 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -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." -- 2.20.1