0027755: Visualization, V3d_View::ToPixMap() - fix image dump with MSAA turned on
[occt.git] / src / OpenGl / OpenGl_View_Redraw.cxx
index 068825c..7478fbb 100644 (file)
@@ -181,7 +181,7 @@ void OpenGl_View::drawBackground (const Handle(OpenGl_Workspace)& theWorkspace)
   // - gradient fill type is not Aspect_GFM_NONE and
   // - either background texture is no specified or it is drawn in Aspect_FM_CENTERED mode
   if (myBgGradientArray->IsDefined()
-    && (!myTextureParams->DoTextureMap()
+    && (!myTextureParams->Aspect()->ToMapTexture()
       || myBgTextureArray->TextureFillMethod() == Aspect_FM_CENTERED
       || myBgTextureArray->TextureFillMethod() == Aspect_FM_NONE))
   {
@@ -213,7 +213,7 @@ void OpenGl_View::drawBackground (const Handle(OpenGl_Workspace)& theWorkspace)
   // Drawing background image if it is defined
   // (texture is defined and fill type is not Aspect_FM_NONE)
   if (myBgTextureArray->IsDefined()
-   && myTextureParams->DoTextureMap())
+   && myTextureParams->Aspect()->ToMapTexture())
   {
     aCtx->core11fwd->glDisable (GL_BLEND);
 
@@ -250,6 +250,8 @@ void OpenGl_View::drawBackground (const Handle(OpenGl_Workspace)& theWorkspace)
 //=======================================================================
 void OpenGl_View::Redraw()
 {
+  const Standard_Boolean wasDisabledMSAA = myToDisableMSAA;
+  const Standard_Boolean hadFboBlit      = myHasFboBlit;
   if (myRenderParams.Method == Graphic3d_RM_RAYTRACING
   && !myCaps->vboDisable
   && !myCaps->keepArrayData)
@@ -292,7 +294,9 @@ void OpenGl_View::Redraw()
   Standard_Integer aSizeY = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeY() : myWindow->Height();
 
   // determine multisampling parameters
-  Standard_Integer aNbSamples = Max (Min (myRenderParams.NbMsaaSamples, aCtx->MaxMsaaSamples()), 0);
+  Standard_Integer aNbSamples = !myToDisableMSAA
+                              ? Max (Min (myRenderParams.NbMsaaSamples, aCtx->MaxMsaaSamples()), 0)
+                              : 0;
   if (aNbSamples != 0)
   {
     aNbSamples = OpenGl_Context::GetPowerOfTwo (aNbSamples, aCtx->MaxMsaaSamples());
@@ -314,13 +318,23 @@ void OpenGl_View::Redraw()
      || myMainSceneFbos[0]->GetVPSizeY() != aSizeY
      || myMainSceneFbos[0]->NbSamples()  != aNbSamples)
     {
+      if (!myTransientDrawToFront)
+      {
+        myImmediateSceneFbos[0]->Release (aCtx.operator->());
+        myImmediateSceneFbos[1]->Release (aCtx.operator->());
+        myImmediateSceneFbos[0]->ChangeViewport (0, 0);
+        myImmediateSceneFbos[1]->ChangeViewport (0, 0);
+      }
+
       // prepare FBOs containing main scene
       // for further blitting and rendering immediate presentations on top
       if (aCtx->core20fwd != NULL)
       {
         myMainSceneFbos[0]->Init (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, aNbSamples);
       }
-      if (!aCtx->caps->useSystemBuffer && myMainSceneFbos[0]->IsValid())
+      if (myTransientDrawToFront
+       && !aCtx->caps->useSystemBuffer
+       && myMainSceneFbos[0]->IsValid())
       {
         myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]);
       }
@@ -430,6 +444,10 @@ void OpenGl_View::Redraw()
     {
       anImmFbo = myImmediateSceneFbos[0].operator->();
     }
+    if (!myTransientDrawToFront)
+    {
+      anImmFbo = aMainFbo;
+    }
 
   #if !defined(GL_ES_VERSION_2_0)
     if (aMainFbo     == NULL
@@ -480,6 +498,13 @@ void OpenGl_View::Redraw()
   // bind default FBO
   bindDefaultFbo();
 
+  if (wasDisabledMSAA != myToDisableMSAA
+   || hadFboBlit      != myHasFboBlit)
+  {
+    // retry on error
+    Redraw();
+  }
+
   // Swap the buffers
   if (toSwap)
   {
@@ -677,7 +702,8 @@ void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, Open
   }
   else
   {
-    glClearColor (myBgColor.rgb[0], myBgColor.rgb[1], myBgColor.rgb[2], 0.0f);
+    const OpenGl_Vec4& aBgColor = myBgColor;
+    glClearColor (aBgColor.r(), aBgColor.g(), aBgColor.b(), 0.0f);
   }
 
   glClear (toClear);
@@ -696,7 +722,8 @@ bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProject
 {
   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
   GLboolean toCopyBackToFront = GL_FALSE;
-  if (!myTransientDrawToFront)
+  if (theDrawFbo == theReadFbo
+   && theDrawFbo != NULL)
   {
     myBackBufferRestored = Standard_False;
   }
@@ -779,11 +806,12 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
 
   // Update states of OpenGl_BVHTreeSelector (frustum culling algorithm).
   myBVHSelector.SetViewVolume (myCamera);
+  myBVHSelector.SetViewportSize (myWindow->Width(), myWindow->Height());
 
   const Handle(OpenGl_ShaderManager)& aManager   = aContext->ShaderManager();
   if (StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index()) != myLastLightSourceState)
   {
-    aManager->UpdateLightSourceStateTo (myShadingModel == Graphic3d_TOSM_NONE ? &OpenGl_NoShadingLight() : &myLights);
+    aManager->UpdateLightSourceStateTo (myShadingModel == Graphic3d_TOSM_NONE ? &myNoShadingLight : &myLights);
     myLastLightSourceState = StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index());
   }
 
@@ -892,7 +920,7 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
     glFogi(GL_FOG_MODE, GL_LINEAR);
     glFogf(GL_FOG_START, (Standard_ShortReal )aFogFrontConverted);
     glFogf(GL_FOG_END, (Standard_ShortReal )aFogBackConverted);
-    glFogfv(GL_FOG_COLOR, myFog.Color.rgb);
+    glFogfv(GL_FOG_COLOR, myFog.Color.GetData());
     glEnable(GL_FOG);
   }
   else if (aContext->core11 != NULL)
@@ -910,17 +938,6 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
 
   aManager->SetShadingModel (myShadingModel);
 
-  // Apply AntiAliasing
-  if (myAntiAliasing)
-    myWorkspace->NamedStatus |= OPENGL_NS_ANTIALIASING;
-  else
-    myWorkspace->NamedStatus &= ~OPENGL_NS_ANTIALIASING;
-
-  if (!aManager->IsEmpty())
-  {
-    aManager->UpdateClippingState();
-  }
-
   // Redraw 3d scene
   if (theProjection == Graphic3d_Camera::Projection_MonoLeftEye)
   {
@@ -932,8 +949,13 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
     aContext->ProjectionState.SetCurrent (myCamera->ProjectionStereoRightF());
     aContext->ApplyProjectionMatrix();
   }
+
+  myWorkspace->SetEnvironmentTexture (myTextureEnv);
+
   renderScene (theProjection, theOutputFBO, theToDrawImmediate);
 
+  myWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
+
   // ===============================
   //      Step 4: Trihedron
   // ===============================
@@ -943,18 +965,11 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
   // before drawing auxiliary stuff (trihedrons, overlayer)
   myWorkspace->ResetAppliedAspect();
 
-  aContext->ChangeClipping().RemoveAll (aContext);
 
-  if (!aManager->IsEmpty())
-  {
-    aManager->ResetMaterialStates();
-    aManager->RevertClippingState();
-
-    // We need to disable (unbind) all shaders programs to ensure
-    // that all objects without specified aspect will be drawn
-    // correctly (such as background)
-    aContext->BindProgram (NULL);
-  }
+  // We need to disable (unbind) all shaders programs to ensure
+  // that all objects without specified aspect will be drawn
+  // correctly (such as background)
+  aContext->BindProgram (NULL);
 
   // Render trihedron
   if (!theToDrawImmediate)
@@ -1005,40 +1020,6 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
     return;
 
   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
-  if ( (myWorkspace->NamedStatus & OPENGL_NS_2NDPASSNEED) == 0 )
-  {
-  #if !defined(GL_ES_VERSION_2_0)
-    const int anAntiAliasingMode = myWorkspace->AntiAliasingMode();
-  #endif
-
-    if ( !myAntiAliasing )
-    {
-    #if !defined(GL_ES_VERSION_2_0)
-      if (aCtx->core11 != NULL)
-      {
-        glDisable (GL_POINT_SMOOTH);
-      }
-      glDisable(GL_LINE_SMOOTH);
-      if( anAntiAliasingMode & 2 ) glDisable(GL_POLYGON_SMOOTH);
-    #endif
-      glBlendFunc (GL_ONE, GL_ZERO);
-      glDisable (GL_BLEND);
-    }
-    else
-    {
-    #if !defined(GL_ES_VERSION_2_0)
-      if (aCtx->core11 != NULL)
-      {
-        glEnable(GL_POINT_SMOOTH);
-      }
-      glEnable(GL_LINE_SMOOTH);
-      if( anAntiAliasingMode & 2 ) glEnable(GL_POLYGON_SMOOTH);
-    #endif
-      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-      glEnable (GL_BLEND);
-    }
-  }
-
   Standard_Boolean toRenderGL = theToDrawImmediate ||
     myRenderParams.Method != Graphic3d_RM_RAYTRACING ||
     myRaytraceInitStatus == OpenGl_RT_FAIL ||
@@ -1136,7 +1117,14 @@ void OpenGl_View::renderTrihedron (const Handle(OpenGl_Workspace) &theWorkspace)
   // display global trihedron
   if (myToShowTrihedron)
   {
+    // disable environment texture
+    Handle(OpenGl_Texture) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
+    theWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
+
     myTrihedron.Render (theWorkspace);
+
+    // restore environment texture
+    theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);
   }
   if (myToShowGradTrihedron)
   {
@@ -1209,6 +1197,8 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection,
       // add planes at loaded view matrix state
       aContext->ChangeClipping().AddView (aContext, aSlicingPlanes);
     }
+
+    aContext->ShaderManager()->UpdateClippingState();
   }
 
 #ifdef _WIN32
@@ -1238,13 +1228,10 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection,
 
     if (!aUserPlanes.IsEmpty())
     {
-      aContext->ChangeClipping().AddWorldLazy (aContext, aUserPlanes);
+      aContext->ChangeClipping().AddWorld (aContext, aUserPlanes);
     }
 
-    if (!aContext->ShaderManager()->IsEmpty())
-    {
-      aContext->ShaderManager()->UpdateClippingState();
-    }
+    aContext->ShaderManager()->UpdateClippingState();
   }
 
 #if !defined(GL_ES_VERSION_2_0)
@@ -1258,7 +1245,7 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection,
                                    THE_DEFAULT_AMBIENT[3]);
     GLenum aLightGlId = GL_LIGHT0;
 
-    OpenGl_ListOfLight::Iterator aLightIt (myShadingModel == Graphic3d_TOSM_NONE ? OpenGl_NoShadingLight() : myLights);
+    OpenGl_ListOfLight::Iterator aLightIt (myShadingModel == Graphic3d_TOSM_NONE ? myNoShadingLight : myLights);
     for (; aLightIt.More(); aLightIt.Next())
     {
       bindLight (aLightIt.Value(), aLightGlId, anAmbientColor, myWorkspace);
@@ -1283,89 +1270,64 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection,
   // Clear status bitfields
   myWorkspace->NamedStatus &= ~(OPENGL_NS_2NDPASSNEED | OPENGL_NS_2NDPASSDO);
 
-  // Update state of surface detail level
-  myWorkspace->GetGlContext()->ShaderManager()->UpdateSurfaceDetailStateTo (mySurfaceDetail);
+  // First pass
+  renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
+  myWorkspace->DisableTexture();
 
-  // Added PCT for handling of textures
-  switch (mySurfaceDetail)
+  // Second pass
+  if (myWorkspace->NamedStatus & OPENGL_NS_2NDPASSNEED)
   {
-    case Graphic3d_TOD_NONE:
-      myWorkspace->NamedStatus |= OPENGL_NS_FORBIDSETTEX;
-      myWorkspace->DisableTexture();
-      // Render the view
-      renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
-      break;
+    myWorkspace->NamedStatus |= OPENGL_NS_2NDPASSDO;
 
-    case Graphic3d_TOD_ENVIRONMENT:
-      myWorkspace->NamedStatus |= OPENGL_NS_FORBIDSETTEX;
-      if (myRenderParams.Method != Graphic3d_RM_RAYTRACING)
-      {
-        myWorkspace->EnableTexture (myTextureEnv);
-      }
-      // Render the view
-      renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
-      myWorkspace->DisableTexture();
-      break;
+    // Remember OpenGl properties
+    GLint aSaveBlendDst = GL_ONE_MINUS_SRC_ALPHA, aSaveBlendSrc = GL_SRC_ALPHA;
+    GLint aSaveZbuffFunc;
+    GLboolean aSaveZbuffWrite;
+    glGetBooleanv (GL_DEPTH_WRITEMASK, &aSaveZbuffWrite);
+    glGetIntegerv (GL_DEPTH_FUNC, &aSaveZbuffFunc);
+  #if !defined(GL_ES_VERSION_2_0)
+    glGetIntegerv (GL_BLEND_DST, &aSaveBlendDst);
+    glGetIntegerv (GL_BLEND_SRC, &aSaveBlendSrc);
+  #endif
+    GLboolean wasZbuffEnabled = glIsEnabled (GL_DEPTH_TEST);
+    GLboolean wasBlendEnabled = glIsEnabled (GL_BLEND);
 
-    case Graphic3d_TOD_ALL:
-      // First pass
-      myWorkspace->NamedStatus &= ~OPENGL_NS_FORBIDSETTEX;
-      // Render the view
-      renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
-      myWorkspace->DisableTexture();
+    // Change the properties for second rendering pass
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glEnable (GL_BLEND);
 
-      // Second pass
-      if (myWorkspace->NamedStatus & OPENGL_NS_2NDPASSNEED)
-      {
-        myWorkspace->NamedStatus |= OPENGL_NS_2NDPASSDO;
-        if (myRenderParams.Method != Graphic3d_RM_RAYTRACING)
-        {
-          myWorkspace->EnableTexture (myTextureEnv);
-        }
+    glDepthFunc (GL_EQUAL);
+    glDepthMask (GL_FALSE);
+    glEnable (GL_DEPTH_TEST);
 
-        // Remember OpenGl properties
-        GLint aSaveBlendDst = GL_ONE_MINUS_SRC_ALPHA, aSaveBlendSrc = GL_SRC_ALPHA;
-        GLint aSaveZbuffFunc;
-        GLboolean aSaveZbuffWrite;
-        glGetBooleanv (GL_DEPTH_WRITEMASK, &aSaveZbuffWrite);
-        glGetIntegerv (GL_DEPTH_FUNC, &aSaveZbuffFunc);
-      #if !defined(GL_ES_VERSION_2_0)
-        glGetIntegerv (GL_BLEND_DST, &aSaveBlendDst);
-        glGetIntegerv (GL_BLEND_SRC, &aSaveBlendSrc);
-      #endif
-        GLboolean wasZbuffEnabled = glIsEnabled (GL_DEPTH_TEST);
-        GLboolean wasBlendEnabled = glIsEnabled (GL_BLEND);
-
-        // Change the properties for second rendering pass
-        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-        glEnable (GL_BLEND);
-
-        glDepthFunc (GL_EQUAL);
-        glDepthMask (GL_FALSE);
-        glEnable (GL_DEPTH_TEST);
-
-        myWorkspace->NamedStatus |= OPENGL_NS_FORBIDSETTEX;
-
-        // Render the view
-        renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
-        myWorkspace->DisableTexture();
-
-        // Restore properties back
-        glBlendFunc (aSaveBlendSrc, aSaveBlendDst);
-        if (!wasBlendEnabled)
-          glDisable (GL_BLEND);
-
-        glDepthFunc (aSaveZbuffFunc);
-        glDepthMask (aSaveZbuffWrite);
-        if (!wasZbuffEnabled)
-          glDisable (GL_DEPTH_FUNC);
-      }
-      break;
+    // Render the view
+    renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
+    myWorkspace->DisableTexture();
+
+    // Restore properties back
+    glBlendFunc (aSaveBlendSrc, aSaveBlendDst);
+    if (!wasBlendEnabled)
+      glDisable (GL_BLEND);
+
+    glDepthFunc (aSaveZbuffFunc);
+    glDepthMask (aSaveZbuffWrite);
+    if (!wasZbuffEnabled)
+      glDisable (GL_DEPTH_FUNC);
   }
 
   // Apply restored view matrix.
   aContext->ApplyWorldViewMatrix();
 
+  aContext->ChangeClipping().RemoveAll (aContext);
+  if (!myClipPlanes.IsEmpty())
+  {
+    aContext->ShaderManager()->RevertClippingState();
+  }
+  if (myZClip.Back.IsOn || myZClip.Front.IsOn)
+  {
+    aContext->ShaderManager()->RevertClippingState();
+  }
+
 #ifdef _WIN32
   // set printing scale/tiling transformation
   if (!aPrintContext.IsNull())
@@ -1392,6 +1354,7 @@ void OpenGl_View::bindDefaultFbo (OpenGl_FrameBuffer* theCustomFbo)
   if (anFbo != NULL)
   {
     anFbo->BindBuffer (aCtx);
+    anFbo->SetupViewport (aCtx);
   }
   else
   {
@@ -1403,8 +1366,8 @@ void OpenGl_View::bindDefaultFbo (OpenGl_FrameBuffer* theCustomFbo)
       aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
     }
   #endif
+    aCtx->core11fwd->glViewport (0, 0, myWindow->Width(), myWindow->Height());
   }
-  aCtx->core11fwd->glViewport (0, 0, myWindow->Width(), myWindow->Height());
 }
 
 // =======================================================================
@@ -1520,6 +1483,32 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
     aCtx->arbFBOBlit->glBlitFramebuffer (0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(),
                                          0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(),
                                          aCopyMask, GL_NEAREST);
+    const int anErr = ::glGetError();
+    if (anErr != GL_NO_ERROR)
+    {
+      // glBlitFramebuffer() might fail in several cases:
+      // - Both FBOs have MSAA and they are samples number does not match.
+      //   OCCT checks that this does not happen,
+      //   however some graphics drivers provide an option for overriding MSAA.
+      //   In this case window MSAA might be non-zero (and application can not check it)
+      //   and might not match MSAA of our offscreen FBOs.
+      // - Pixel formats of FBOs do not match.
+      //   This also might happen with window has pixel format,
+      //   e.g. Mesa fails blitting RGBA8 -> RGB8 while other drivers support this conversion.
+      TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "FBO blitting has failed [Error #" + anErr + "]\n"
+                                      + "  Please check your graphics driver settings or try updating driver.";
+      if (theReadFbo->NbSamples() != 0)
+      {
+        myToDisableMSAA = true;
+        aMsg += "\n  MSAA settings should not be overridden by driver!";
+      }
+      aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
+                         GL_DEBUG_TYPE_ERROR,
+                         0,
+                         GL_DEBUG_SEVERITY_HIGH,
+                         aMsg);
+    }
+
     if (theDrawFbo != NULL
      && theDrawFbo->IsValid())
     {