From 6997ff1c8854824a6370dba63aecab98dc14d4a9 Mon Sep 17 00:00:00 2001
From: mnv <mnv@opencascade.com>
Date: Mon, 1 Oct 2018 13:53:37 +0300
Subject: [PATCH] 0029020: Visualization, V3d_View - workaround image dump
 issue on Intel OpenGL driver

Implemented workaround for dump images with width >= 5462 pix on Intel OpenGl driver.
Changes according to OpenGl_Context::myVendor field in lowercase.
---
 src/Graphic3d/Graphic3d_TypeOfLimit.hxx |  3 +++
 src/OpenGl/OpenGl_Context.cxx           | 18 ++++++++++++++++--
 src/OpenGl/OpenGl_Context.hxx           |  8 ++++++++
 src/OpenGl/OpenGl_GraphicDriver.cxx     |  6 ++++++
 src/OpenGl/OpenGl_ShaderManager.cxx     |  2 +-
 src/V3d/V3d_View.cxx                    | 22 +++++++++++++++-------
 tests/bugs/vis/bug29020                 | 20 ++++++++++++++++++++
 7 files changed, 69 insertions(+), 10 deletions(-)
 create mode 100644 tests/bugs/vis/bug29020

diff --git a/src/Graphic3d/Graphic3d_TypeOfLimit.hxx b/src/Graphic3d/Graphic3d_TypeOfLimit.hxx
index 6770049ea5..6c9f208dc2 100644
--- a/src/Graphic3d/Graphic3d_TypeOfLimit.hxx
+++ b/src/Graphic3d/Graphic3d_TypeOfLimit.hxx
@@ -21,6 +21,8 @@ enum Graphic3d_TypeOfLimit
   Graphic3d_TypeOfLimit_MaxNbClipPlanes,                //!< maximum number of active clipping planes
   Graphic3d_TypeOfLimit_MaxNbViews,                     //!< maximum number of views
   Graphic3d_TypeOfLimit_MaxTextureSize,                 //!< maximum size of texture
+  Graphic3d_TypeOfLimit_MaxViewDumpSizeX,               //!< maximum width  for image dump
+  Graphic3d_TypeOfLimit_MaxViewDumpSizeY,               //!< maximum height for image dump
   Graphic3d_TypeOfLimit_MaxCombinedTextureUnits,        //!< maximum number of combined texture units for multitexturing
   Graphic3d_TypeOfLimit_MaxMsaa,                        //!< maximum number of MSAA samples
   Graphic3d_TypeOfLimit_HasRayTracing,                  //!< indicates whether ray tracing is supported
@@ -29,6 +31,7 @@ enum Graphic3d_TypeOfLimit
   Graphic3d_TypeOfLimit_HasBlendedOit,                  //!< indicates whether necessary GL extensions for Weighted, Blended OIT available (without MSAA).
   Graphic3d_TypeOfLimit_HasBlendedOitMsaa,              //!< indicates whether necessary GL extensions for Weighted, Blended OIT available (with MSAA).
   Graphic3d_TypeOfLimit_HasFlatShading,                 //!< indicates whether Flat shading (Graphic3d_TOSM_FACET) is supported
+  Graphic3d_TypeOfLimit_IsWorkaroundFBO,                //!< indicates whether workaround for Intel driver problem with empty FBO for images with big width is applyed.
   Graphic3d_TypeOfLimit_NB                              //!< number of elements in this enumeration
 };
 
diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx
index 3498381c7f..125102fe75 100644
--- a/src/OpenGl/OpenGl_Context.cxx
+++ b/src/OpenGl/OpenGl_Context.cxx
@@ -158,6 +158,8 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myTexClamp   (GL_CLAMP_TO_EDGE),
   myMaxTexDim  (1024),
   myMaxTexCombined (1),
+  myMaxDumpSizeX (1024),
+  myMaxDumpSizeY (1024),
   myMaxClipPlanes (6),
   myMaxMsaaSamples(0),
   myMaxDrawBuffers (1),
@@ -1192,6 +1194,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   myMaxColorAttachments = 1;
   ReadGlVersion (myGlVerMajor, myGlVerMinor);
   myVendor = (const char* )::glGetString (GL_VENDOR);
+  myVendor.LowerCase();
   if (!caps->ffpEnable
    && !IsGlGreaterEqual (2, 0))
   {
@@ -1212,7 +1215,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   const bool isCoreProfile = false;
 #else
 
-  if (myVendor.Search ("NVIDIA") != -1)
+  if (myVendor.Search ("nvidia") != -1)
   {
     // Buffer detailed info: Buffer object 1 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW)
     // will use VIDEO memory as the source for buffer object operations.
@@ -1415,7 +1418,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
                    ? OpenGl_FeatureInExtensions
                    : OpenGl_FeatureNotAvailable);
   if (!IsGlGreaterEqual (3, 1)
-    && myVendor.Search("Qualcomm") != -1)
+    && myVendor.Search("qualcomm") != -1)
   {
     // dFdx/dFdy are completely broken on tested Adreno devices with versions below OpenGl ES 3.1
     hasFlatShading = OpenGl_FeatureNotAvailable;
@@ -1472,6 +1475,16 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &myMaxTexCombined);
   }
 
+  GLint aMaxVPortSize[2] = {0, 0};
+  glGetIntegerv (GL_MAX_VIEWPORT_DIMS, aMaxVPortSize);
+  myMaxDumpSizeX = Min (aMaxVPortSize[0], myMaxTexDim);
+  myMaxDumpSizeY = Min (aMaxVPortSize[1], myMaxTexDim);
+  if (myVendor == "intel")
+  {
+    // Intel drivers have known bug with empty dump for images with width>=5462
+    myMaxDumpSizeX = Min (myMaxDumpSizeX, 4096);
+  }
+
   if (extAnis)
   {
     glGetIntegerv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &myAnisoMax);
@@ -2838,6 +2851,7 @@ void OpenGl_Context::DiagnosticInformation (TColStd_IndexedDataMapOfStringString
   if ((theFlags & Graphic3d_DiagnosticInfo_Limits) != 0)
   {
     addInfo (theDict, "Max texture size", TCollection_AsciiString(myMaxTexDim));
+    addInfo (theDict, "Max FBO dump size", TCollection_AsciiString() + myMaxDumpSizeX + "x" + myMaxDumpSizeY);
     addInfo (theDict, "Max combined texture units", TCollection_AsciiString(myMaxTexCombined));
     addInfo (theDict, "Max MSAA samples", TCollection_AsciiString(myMaxMsaaSamples));
   }
diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx
index 5f9b050230..064873eb3c 100644
--- a/src/OpenGl/OpenGl_Context.hxx
+++ b/src/OpenGl/OpenGl_Context.hxx
@@ -476,6 +476,12 @@ public:
   //! @return value for GL_MAX_SAMPLES
   Standard_Integer MaxMsaaSamples() const { return myMaxMsaaSamples; }
 
+  //! @return maximum FBO width for image dump
+  Standard_Integer MaxDumpSizeX() const { return myMaxDumpSizeX; }
+
+  //! @return maximum FBO height for image dump
+  Standard_Integer MaxDumpSizeY() const { return myMaxDumpSizeY; }
+
   //! @return value for GL_MAX_DRAW_BUFFERS
   Standard_Integer MaxDrawBuffers() const { return myMaxDrawBuffers; }
 
@@ -905,6 +911,8 @@ private: // context info
   Standard_Integer myTexClamp;             //!< either GL_CLAMP_TO_EDGE (1.2+) or GL_CLAMP (1.1)
   Standard_Integer myMaxTexDim;            //!< value for GL_MAX_TEXTURE_SIZE
   Standard_Integer myMaxTexCombined;       //!< value for GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
+  Standard_Integer myMaxDumpSizeX;         //!< maximum FBO width  for image dump
+  Standard_Integer myMaxDumpSizeY;         //!< maximum FBO height for image dump
   Standard_Integer myMaxClipPlanes;        //!< value for GL_MAX_CLIP_PLANES
   Standard_Integer myMaxMsaaSamples;       //!< value for GL_MAX_SAMPLES
   Standard_Integer myMaxDrawBuffers;       //!< value for GL_MAX_DRAW_BUFFERS
diff --git a/src/OpenGl/OpenGl_GraphicDriver.cxx b/src/OpenGl/OpenGl_GraphicDriver.cxx
index c6fbdc2860..23cba938f5 100644
--- a/src/OpenGl/OpenGl_GraphicDriver.cxx
+++ b/src/OpenGl/OpenGl_GraphicDriver.cxx
@@ -417,6 +417,10 @@ Standard_Integer OpenGl_GraphicDriver::InquireLimit (const Graphic3d_TypeOfLimit
       return !aCtx.IsNull() ? aCtx->MaxCombinedTextureUnits() : 1;
     case Graphic3d_TypeOfLimit_MaxMsaa:
       return !aCtx.IsNull() ? aCtx->MaxMsaaSamples() : 0;
+    case Graphic3d_TypeOfLimit_MaxViewDumpSizeX:
+      return !aCtx.IsNull() ? aCtx->MaxDumpSizeX() : 1024;
+    case Graphic3d_TypeOfLimit_MaxViewDumpSizeY:
+      return !aCtx.IsNull() ? aCtx->MaxDumpSizeY() : 1024;
     case Graphic3d_TypeOfLimit_HasRayTracing:
       return (!aCtx.IsNull() && aCtx->HasRayTracing()) ? 1 : 0;
     case Graphic3d_TypeOfLimit_HasRayTracingTextures:
@@ -433,6 +437,8 @@ Standard_Integer OpenGl_GraphicDriver::InquireLimit (const Graphic3d_TypeOfLimit
             && (InquireLimit (Graphic3d_TypeOfLimit_HasBlendedOit) == 1)) ? 1 : 0;
     case Graphic3d_TypeOfLimit_HasFlatShading:
       return !aCtx.IsNull() && aCtx->hasFlatShading != OpenGl_FeatureNotAvailable ? 1 : 0;
+    case Graphic3d_TypeOfLimit_IsWorkaroundFBO:
+      return !aCtx.IsNull() && aCtx->MaxTextureSize() != aCtx->MaxDumpSizeX() ? 1 : 0;
     case Graphic3d_TypeOfLimit_NB:
       return 0;
   }
diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx
index d89e2018e2..ac229f0e7c 100644
--- a/src/OpenGl/OpenGl_ShaderManager.cxx
+++ b/src/OpenGl/OpenGl_ShaderManager.cxx
@@ -2077,7 +2077,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
                             "Warning: flat shading requires OpenGL ES 3.0+ or GL_OES_standard_derivatives extension.");
   }
   else if (isFlatNormal
-        && myContext->Vendor().Search("Qualcomm") != -1)
+        && myContext->Vendor().Search("qualcomm") != -1)
   {
     // workaround Adreno driver bug computing reversed normal using dFdx/dFdy
     aDFdxSignReversion = "-";
diff --git a/src/V3d/V3d_View.cxx b/src/V3d/V3d_View.cxx
index 85faa0ecb2..3f3edbbe47 100644
--- a/src/V3d/V3d_View.cxx
+++ b/src/V3d/V3d_View.cxx
@@ -2753,19 +2753,27 @@ Standard_Boolean V3d_View::ToPixMap (Image_PixMap&               theImage,
 
   if (aFBOPtr.IsNull())
   {
-    Standard_Integer aMaxTexSize = MyViewer->Driver()->InquireLimit (Graphic3d_TypeOfLimit_MaxTextureSize);
-    if (theParams.TileSize > aMaxTexSize)
+    Standard_Integer aMaxTexSizeX = MyViewer->Driver()->InquireLimit (Graphic3d_TypeOfLimit_MaxViewDumpSizeX);
+    Standard_Integer aMaxTexSizeY = MyViewer->Driver()->InquireLimit (Graphic3d_TypeOfLimit_MaxViewDumpSizeY);
+    if (theParams.TileSize > aMaxTexSizeX
+     || theParams.TileSize > aMaxTexSizeY)
     {
       Message::DefaultMessenger()->Send (TCollection_AsciiString ("Image dump can not be performed - specified tile size (")
-                                                                 + theParams.TileSize + ") exceeds hardware limits (" + aMaxTexSize + ")", Message_Fail);
+                                                                 + theParams.TileSize + ") exceeds hardware limits (" + aMaxTexSizeX + "x" + aMaxTexSizeY + ")", Message_Fail);
       return Standard_False;
     }
 
-    if (aFBOVPSize.x() > aMaxTexSize
-     || aFBOVPSize.y() > aMaxTexSize)
+    if (aFBOVPSize.x() > aMaxTexSizeX
+     || aFBOVPSize.y() > aMaxTexSizeY)
     {
-      aFBOVPSize.x() = Min (aFBOVPSize.x(), aMaxTexSize);
-      aFBOVPSize.y() = Min (aFBOVPSize.y(), aMaxTexSize);
+      if (MyViewer->Driver()->InquireLimit (Graphic3d_TypeOfLimit_IsWorkaroundFBO))
+      {
+        Message::DefaultMessenger ()->Send (TCollection_AsciiString ("Warning, workaround for Intel driver problem with empty FBO for images with big width is applyed."), Message_Warning);
+      }
+      Message::DefaultMessenger()->Send (TCollection_AsciiString ("Info, tiling image dump is used, image size (")
+                                                                 + aFBOVPSize.x() + "x" + aFBOVPSize.y() + ") exceeds hardware limits (" + aMaxTexSizeX + "x" + aMaxTexSizeY + ")", Message_Info);
+      aFBOVPSize.x() = Min (aFBOVPSize.x(), aMaxTexSizeX);
+      aFBOVPSize.y() = Min (aFBOVPSize.y(), aMaxTexSizeY);
       isTiling = true;
     }
 
diff --git a/tests/bugs/vis/bug29020 b/tests/bugs/vis/bug29020
new file mode 100644
index 0000000000..c17ba2bf1d
--- /dev/null
+++ b/tests/bugs/vis/bug29020
@@ -0,0 +1,20 @@
+puts "========"
+puts "0029020: Visualization, V3d_View - workaround image dump issue on Intel OpenGL driver"
+puts "========"
+puts ""
+
+pload MODELING VISUALIZATION
+box b 1 1 1
+vclear
+vinit View1
+vdisplay -dispMode 1 b
+vtop
+vfit
+
+#Get max size of dumped image
+set anExpression {Max texture size: (\d+)}
+regexp $anExpression [vglinfo] _ match
+
+vdump $imagedir/${casename}_max_width.png -width $match -height 100
+
+vdump $imagedir/${casename}_max_height.png -width 100 -height $match