0028572: Modeling Algorithms - Wrong result of the mkface command
[occt.git] / src / OpenGl / OpenGl_View_Redraw.cxx
1 // Created on: 2011-09-20
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <stdio.h>
17 #include <stdlib.h>
18
19 #include <OpenGl_GlCore11.hxx>
20
21 #include <Aspect_XRSession.hxx>
22 #include <Graphic3d_GraphicDriver.hxx>
23 #include <Graphic3d_StructureManager.hxx>
24 #include <Graphic3d_TextureParams.hxx>
25 #include <Graphic3d_Texture2Dmanual.hxx>
26 #include <Graphic3d_TransformUtils.hxx>
27 #include <Image_AlienPixMap.hxx>
28
29 #include <NCollection_Mat4.hxx>
30
31 #include <OpenGl_Context.hxx>
32 #include <OpenGl_FrameStats.hxx>
33 #include <OpenGl_Matrix.hxx>
34 #include <OpenGl_Workspace.hxx>
35 #include <OpenGl_View.hxx>
36 #include <OpenGl_GraduatedTrihedron.hxx>
37 #include <OpenGl_PrimitiveArray.hxx>
38 #include <OpenGl_ShaderManager.hxx>
39 #include <OpenGl_ShaderProgram.hxx>
40 #include <OpenGl_Structure.hxx>
41 #include <OpenGl_ArbFBO.hxx>
42
43 #include "../Textures/Textures_EnvLUT.pxx"
44
45 namespace
46 {
47   //! Format Frame Buffer format for logging messages.
48   static TCollection_AsciiString printFboFormat (const Handle(OpenGl_FrameBuffer)& theFbo)
49   {
50     return TCollection_AsciiString() + theFbo->GetInitVPSizeX() + "x" + theFbo->GetInitVPSizeY() + "@" + theFbo->NbSamples();
51   }
52
53   //! Return TRUE if Frame Buffer initialized has failed with the same parameters.
54   static bool checkWasFailedFbo (const Handle(OpenGl_FrameBuffer)& theFboToCheck,
55                                  Standard_Integer theSizeX,
56                                  Standard_Integer theSizeY,
57                                  Standard_Integer theNbSamples)
58   {
59     return !theFboToCheck->IsValid()
60         &&  theFboToCheck->GetInitVPSizeX() == theSizeX
61         &&  theFboToCheck->GetInitVPSizeY() == theSizeY
62         &&  theFboToCheck->NbSamples()      == theNbSamples;
63   }
64
65   //! Return TRUE if Frame Buffer initialized has failed with the same parameters.
66   static bool checkWasFailedFbo (const Handle(OpenGl_FrameBuffer)& theFboToCheck,
67                                  const Handle(OpenGl_FrameBuffer)& theFboRef)
68   {
69     return checkWasFailedFbo (theFboToCheck, theFboRef->GetVPSizeX(), theFboRef->GetVPSizeY(), theFboRef->NbSamples());
70   }
71 }
72
73 //=======================================================================
74 //function : drawBackground
75 //purpose  :
76 //=======================================================================
77 void OpenGl_View::drawBackground (const Handle(OpenGl_Workspace)& theWorkspace,
78                                   Graphic3d_Camera::Projection theProjection)
79 {
80   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
81   const Standard_Boolean wasUsedZBuffer = theWorkspace->SetUseZBuffer (Standard_False);
82   if (wasUsedZBuffer)
83   {
84     aCtx->core11fwd->glDisable (GL_DEPTH_TEST);
85   }
86
87   if (myBackgroundType == Graphic3d_TOB_CUBEMAP)
88   {
89     myCubeMapParams->Aspect()->ShaderProgram()->PushVariableInt ("uZCoeff", myBackgroundCubeMap->ZIsInverted() ? -1 : 1);
90     myCubeMapParams->Aspect()->ShaderProgram()->PushVariableInt ("uYCoeff", myBackgroundCubeMap->IsTopDown() ? 1 : -1);
91     const OpenGl_Aspects* anOldAspectFace = theWorkspace->SetAspects (myCubeMapParams);
92
93     myBackgrounds[Graphic3d_TOB_CUBEMAP]->Render (theWorkspace, theProjection);
94
95     theWorkspace->SetAspects (anOldAspectFace);
96   }
97   else if (myBackgroundType == Graphic3d_TOB_GRADIENT
98         || myBackgroundType == Graphic3d_TOB_TEXTURE)
99   {
100     // Drawing background gradient if:
101     // - gradient fill type is not Aspect_GFM_NONE and
102     // - either background texture is no specified or it is drawn in Aspect_FM_CENTERED mode
103     if (myBackgrounds[Graphic3d_TOB_GRADIENT]->IsDefined()
104       && (!myTextureParams->Aspect()->ToMapTexture()
105         || myBackgrounds[Graphic3d_TOB_TEXTURE]->TextureFillMethod() == Aspect_FM_CENTERED
106         || myBackgrounds[Graphic3d_TOB_TEXTURE]->TextureFillMethod() == Aspect_FM_NONE))
107     {
108       myBackgrounds[Graphic3d_TOB_GRADIENT]->Render(theWorkspace, theProjection);
109     }
110
111     // Drawing background image if it is defined
112     // (texture is defined and fill type is not Aspect_FM_NONE)
113     if (myBackgrounds[Graphic3d_TOB_TEXTURE]->IsDefined()
114       && myTextureParams->Aspect()->ToMapTexture())
115     {
116       aCtx->core11fwd->glDisable (GL_BLEND);
117
118       const OpenGl_Aspects* anOldAspectFace = theWorkspace->SetAspects (myTextureParams);
119       myBackgrounds[Graphic3d_TOB_TEXTURE]->Render (theWorkspace, theProjection);
120       theWorkspace->SetAspects (anOldAspectFace);
121     }
122   }
123
124   if (wasUsedZBuffer)
125   {
126     theWorkspace->SetUseZBuffer (Standard_True);
127     aCtx->core11fwd->glEnable (GL_DEPTH_TEST);
128   }
129 }
130
131 //=======================================================================
132 //function : Redraw
133 //purpose  :
134 //=======================================================================
135 void OpenGl_View::Redraw()
136 {
137   const Standard_Boolean wasDisabledMSAA = myToDisableMSAA;
138   const Standard_Boolean hadFboBlit      = myHasFboBlit;
139   if (myRenderParams.Method == Graphic3d_RM_RAYTRACING
140   && !myCaps->vboDisable
141   && !myCaps->keepArrayData)
142   {
143     // caps are shared across all views, thus we need to invalidate all of them
144     // if (myWasRedrawnGL) { myStructureManager->SetDeviceLost(); }
145     myDriver->setDeviceLost();
146     myCaps->keepArrayData = Standard_True;
147   }
148
149   if (!myWorkspace->Activate())
150   {
151     return;
152   }
153
154   // implicitly disable VSync when using HMD composer (can be mirrored in window for debugging)
155   myWindow->SetSwapInterval (IsActiveXR());
156
157   ++myFrameCounter;
158   const Graphic3d_StereoMode   aStereoMode  = myRenderParams.StereoMode;
159   Graphic3d_Camera::Projection aProjectType = myCamera->ProjectionType();
160   const Handle(OpenGl_Context)& aCtx        = myWorkspace->GetGlContext();
161   aCtx->FrameStats()->FrameStart (myWorkspace->View(), false);
162   aCtx->SetLineFeather (myRenderParams.LineFeather);
163
164   const Standard_Integer anSRgbState = aCtx->ToRenderSRGB() ? 1 : 0;
165   if (mySRgbState != -1
166    && mySRgbState != anSRgbState)
167   {
168     releaseSrgbResources (aCtx);
169     initTextureEnv (aCtx);
170   }
171   mySRgbState = anSRgbState;
172   aCtx->ShaderManager()->UpdateSRgbState();
173
174   // release pending GL resources
175   aCtx->ReleaseDelayed();
176
177   // fetch OpenGl context state
178   aCtx->FetchState();
179
180   OpenGl_FrameBuffer* aFrameBuffer = myFBO.get();
181   bool toSwap = aCtx->IsRender()
182             && !aCtx->caps->buffersNoSwap
183             &&  aFrameBuffer == NULL
184             &&  (!IsActiveXR() || myRenderParams.ToMirrorComposer);
185
186   Standard_Integer aSizeX = myWindow->Width();
187   Standard_Integer aSizeY = myWindow->Height();
188   if (aFrameBuffer != NULL)
189   {
190     aSizeX = aFrameBuffer->GetVPSizeX();
191     aSizeY = aFrameBuffer->GetVPSizeY();
192   }
193   else if (IsActiveXR())
194   {
195     aSizeX = myXRSession->RecommendedViewport().x();
196     aSizeY = myXRSession->RecommendedViewport().y();
197   }
198
199   const Standard_Integer aRendSizeX = Standard_Integer(myRenderParams.RenderResolutionScale * aSizeX + 0.5f);
200   const Standard_Integer aRendSizeY = Standard_Integer(myRenderParams.RenderResolutionScale * aSizeY + 0.5f);
201   if (aSizeX < 1
202    || aSizeY < 1
203    || aRendSizeX < 1
204    || aRendSizeY < 1)
205   {
206     myBackBufferRestored = Standard_False;
207     myIsImmediateDrawn   = Standard_False;
208     return;
209   }
210
211   // determine multisampling parameters
212   Standard_Integer aNbSamples = !myToDisableMSAA && aSizeX == aRendSizeX
213                               ? Max (Min (myRenderParams.NbMsaaSamples, aCtx->MaxMsaaSamples()), 0)
214                               : 0;
215   if (aNbSamples != 0)
216   {
217     aNbSamples = OpenGl_Context::GetPowerOfTwo (aNbSamples, aCtx->MaxMsaaSamples());
218   }
219
220   bool toUseOit = myRenderParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT
221                && checkOitCompatibility (aCtx, aNbSamples > 0);
222
223   const bool toInitImmediateFbo = myTransientDrawToFront
224                                && (!aCtx->caps->useSystemBuffer || (toUseOit && HasImmediateStructures()));
225
226   if ( aFrameBuffer == NULL
227    && !aCtx->DefaultFrameBuffer().IsNull()
228    &&  aCtx->DefaultFrameBuffer()->IsValid())
229   {
230     aFrameBuffer = aCtx->DefaultFrameBuffer().operator->();
231   }
232
233   if (myHasFboBlit
234    && (myTransientDrawToFront
235     || aProjectType == Graphic3d_Camera::Projection_Stereo
236     || aNbSamples != 0
237     || toUseOit
238     || aSizeX != aRendSizeX))
239   {
240     if (myMainSceneFbos[0]->GetVPSizeX() != aRendSizeX
241      || myMainSceneFbos[0]->GetVPSizeY() != aRendSizeY
242      || myMainSceneFbos[0]->NbSamples()  != aNbSamples)
243     {
244       if (!myTransientDrawToFront)
245       {
246         myImmediateSceneFbos[0]->Release (aCtx.operator->());
247         myImmediateSceneFbos[1]->Release (aCtx.operator->());
248         myImmediateSceneFbos[0]->ChangeViewport (0, 0);
249         myImmediateSceneFbos[1]->ChangeViewport (0, 0);
250       }
251
252       // prepare FBOs containing main scene
253       // for further blitting and rendering immediate presentations on top
254       if (aCtx->core20fwd != NULL)
255       {
256         const bool wasFailedMain0 = checkWasFailedFbo (myMainSceneFbos[0], aRendSizeX, aRendSizeY, aNbSamples);
257         if (!myMainSceneFbos[0]->Init (aCtx, aRendSizeX, aRendSizeY, myFboColorFormat, myFboDepthFormat, aNbSamples)
258          && !wasFailedMain0)
259         {
260           TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! Main FBO "
261                                           + printFboFormat (myMainSceneFbos[0]) + " initialization has failed";
262           aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
263         }
264       }
265     }
266     if (myMainSceneFbos[0]->IsValid() && (toInitImmediateFbo || myImmediateSceneFbos[0]->IsValid()))
267     {
268       const bool wasFailedImm0 = checkWasFailedFbo (myImmediateSceneFbos[0], myMainSceneFbos[0]);
269       if (!myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0])
270        && !wasFailedImm0)
271       {
272         TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! Immediate FBO "
273                                         + printFboFormat (myImmediateSceneFbos[0]) + " initialization has failed";
274         aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
275       }
276     }
277   }
278   else
279   {
280     myMainSceneFbos     [0]->Release (aCtx.operator->());
281     myMainSceneFbos     [1]->Release (aCtx.operator->());
282     myImmediateSceneFbos[0]->Release (aCtx.operator->());
283     myImmediateSceneFbos[1]->Release (aCtx.operator->());
284     myXrSceneFbo           ->Release (aCtx.operator->());
285     myMainSceneFbos     [0]->ChangeViewport (0, 0);
286     myMainSceneFbos     [1]->ChangeViewport (0, 0);
287     myImmediateSceneFbos[0]->ChangeViewport (0, 0);
288     myImmediateSceneFbos[1]->ChangeViewport (0, 0);
289     myXrSceneFbo           ->ChangeViewport (0, 0);
290   }
291
292   bool hasXRBlitFbo = false;
293   if (aProjectType == Graphic3d_Camera::Projection_Stereo
294    && IsActiveXR()
295    && myMainSceneFbos[0]->IsValid())
296   {
297     if (aNbSamples != 0
298      || aSizeX != aRendSizeX)
299     {
300       hasXRBlitFbo = myXrSceneFbo->InitLazy (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, 0);
301       if (!hasXRBlitFbo)
302       {
303         TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! VR FBO "
304                                         + printFboFormat (myXrSceneFbo) + " initialization has failed";
305         aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
306       }
307     }
308   }
309   else if (aProjectType == Graphic3d_Camera::Projection_Stereo
310         && myMainSceneFbos[0]->IsValid())
311   {
312     const bool wasFailedMain1 = checkWasFailedFbo (myMainSceneFbos[1], myMainSceneFbos[0]);
313     if (!myMainSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0])
314      && !wasFailedMain1)
315     {
316       TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! Main FBO (second) "
317                                       + printFboFormat (myMainSceneFbos[1]) + " initialization has failed";
318       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
319     }
320     if (!myMainSceneFbos[1]->IsValid())
321     {
322       // no enough memory?
323       aProjectType = Graphic3d_Camera::Projection_Perspective;
324     }
325     else if (!myTransientDrawToFront)
326     {
327       //
328     }
329     else if (!aCtx->HasStereoBuffers() || aStereoMode != Graphic3d_StereoMode_QuadBuffer)
330     {
331       const bool wasFailedImm0 = checkWasFailedFbo (myImmediateSceneFbos[0], myMainSceneFbos[0]);
332       const bool wasFailedImm1 = checkWasFailedFbo (myImmediateSceneFbos[1], myMainSceneFbos[0]);
333       if (!myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0])
334        && !wasFailedImm0)
335       {
336         TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! Immediate FBO (first) "
337                                         + printFboFormat (myImmediateSceneFbos[0]) + " initialization has failed";
338         aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
339       }
340       if (!myImmediateSceneFbos[1]->InitLazy (aCtx, *myMainSceneFbos[0])
341        && !wasFailedImm1)
342       {
343         TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "Error! Immediate FBO (first) "
344                                         + printFboFormat (myImmediateSceneFbos[1]) + " initialization has failed";
345         aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
346       }
347       if (!myImmediateSceneFbos[0]->IsValid()
348        || !myImmediateSceneFbos[1]->IsValid())
349       {
350         aProjectType = Graphic3d_Camera::Projection_Perspective;
351       }
352     }
353   }
354   if (!hasXRBlitFbo)
355   {
356     myXrSceneFbo->Release (aCtx.get());
357     myXrSceneFbo->ChangeViewport (0, 0);
358   }
359
360   // process PBR environment
361   if (myShadingModel == Graphic3d_TOSM_PBR
362    || myShadingModel == Graphic3d_TOSM_PBR_FACET)
363   {
364     if (!myPBREnvironment.IsNull()
365       && myPBREnvironment->SizesAreDifferent (myRenderParams.PbrEnvPow2Size,
366                                               myRenderParams.PbrEnvSpecMapNbLevels))
367     {
368       myPBREnvironment->Release (aCtx.get());
369       myPBREnvironment.Nullify();
370       myPBREnvState = OpenGl_PBREnvState_NONEXISTENT;
371       myPBREnvRequest = OpenGl_PBREnvRequest_BAKE;
372       ++myLightsRevision;
373     }
374
375     if (myPBREnvState == OpenGl_PBREnvState_NONEXISTENT
376      && aCtx->HasPBR())
377     {
378       myPBREnvironment = OpenGl_PBREnvironment::Create (aCtx, myRenderParams.PbrEnvPow2Size, myRenderParams.PbrEnvSpecMapNbLevels);
379       myPBREnvState = myPBREnvironment.IsNull() ? OpenGl_PBREnvState_UNAVAILABLE : OpenGl_PBREnvState_CREATED;
380       if (myPBREnvState == OpenGl_PBREnvState_CREATED)
381       {
382         Handle(OpenGl_Texture) anEnvLUT;
383         static const TCollection_AsciiString THE_SHARED_ENV_LUT_KEY("EnvLUT");
384         if (!aCtx->GetResource (THE_SHARED_ENV_LUT_KEY, anEnvLUT))
385         {
386           Handle(Graphic3d_TextureParams) aParams = new Graphic3d_TextureParams();
387           aParams->SetFilter (Graphic3d_TOTF_BILINEAR);
388           aParams->SetRepeat (Standard_False);
389           aParams->SetTextureUnit (aCtx->PBREnvLUTTexUnit());
390           anEnvLUT = new OpenGl_Texture(THE_SHARED_ENV_LUT_KEY, aParams);
391           Handle(Image_PixMap) aPixMap = new Image_PixMap();
392           aPixMap->InitWrapper (Image_Format_RGF, (Standard_Byte*)Textures_EnvLUT, Textures_EnvLUTSize, Textures_EnvLUTSize);
393           OpenGl_TextureFormat aTexFormat = OpenGl_TextureFormat::FindFormat (aCtx, aPixMap->Format(), false);
394         #if defined(GL_ES_VERSION_2_0)
395           // GL_RG32F is not texture-filterable format on OpenGL ES without OES_texture_float_linear extension.
396           // GL_RG16F is texture-filterable since OpenGL ES 3.0 and can be initialized from 32-bit floats.
397           // Note that it is expected that GL_RG16F has enough precision for this table, so that it can be used also on desktop OpenGL.
398           //if (!aCtx->hasTexFloatLinear)
399           aTexFormat.SetInternalFormat (GL_RG16F);
400         #endif
401           if (!aTexFormat.IsValid()
402            || !anEnvLUT->Init (aCtx, aTexFormat, Graphic3d_Vec2i((Standard_Integer)Textures_EnvLUTSize), Graphic3d_TOT_2D, aPixMap.get()))
403           {
404             aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Failed allocation of LUT for PBR");
405             anEnvLUT.Nullify();
406           }
407           aCtx->ShareResource (THE_SHARED_ENV_LUT_KEY, anEnvLUT);
408         }
409         if (!anEnvLUT.IsNull())
410         {
411           anEnvLUT->Bind (aCtx);
412         }
413         myWorkspace->ApplyAspects();
414       }
415     }
416     processPBREnvRequest (aCtx);
417   }
418
419   // create color and coverage accumulation buffers required for OIT algorithm
420   if (toUseOit)
421   {
422     Standard_Integer anFboIt = 0;
423     for (; anFboIt < 2; ++anFboIt)
424     {
425       Handle(OpenGl_FrameBuffer)& aMainSceneFbo          = myMainSceneFbos        [anFboIt];
426       Handle(OpenGl_FrameBuffer)& aMainSceneFboOit       = myMainSceneFbosOit     [anFboIt];
427       Handle(OpenGl_FrameBuffer)& anImmediateSceneFbo    = myImmediateSceneFbos   [anFboIt];
428       Handle(OpenGl_FrameBuffer)& anImmediateSceneFboOit = myImmediateSceneFbosOit[anFboIt];
429       if (aMainSceneFbo->IsValid()
430        && (aMainSceneFboOit->GetVPSizeX() != aRendSizeX
431         || aMainSceneFboOit->GetVPSizeY() != aRendSizeY
432         || aMainSceneFboOit->NbSamples()  != aNbSamples))
433       {
434         Standard_Integer aColorConfig = 0;
435         for (;;) // seemly responding to driver limitation (GL_FRAMEBUFFER_UNSUPPORTED)
436         {
437           if (myFboOitColorConfig.IsEmpty())
438           {
439             if (!chooseOitColorConfiguration (aCtx, aColorConfig++, myFboOitColorConfig))
440             {
441               break;
442             }
443           }
444           if (aMainSceneFboOit->Init (aCtx, aRendSizeX, aRendSizeY, myFboOitColorConfig, aMainSceneFbo->DepthStencilTexture(), aNbSamples))
445           {
446             break;
447           }
448           myFboOitColorConfig.Clear();
449         }
450         if (!aMainSceneFboOit->IsValid())
451         {
452           break;
453         }
454       }
455       else if (!aMainSceneFbo->IsValid())
456       {
457         aMainSceneFboOit->Release (aCtx.operator->());
458         aMainSceneFboOit->ChangeViewport (0, 0);
459       }
460
461       if (anImmediateSceneFbo->IsValid()
462        && (anImmediateSceneFboOit->GetVPSizeX() != aRendSizeX
463         || anImmediateSceneFboOit->GetVPSizeY() != aRendSizeY
464         || anImmediateSceneFboOit->NbSamples()  != aNbSamples))
465       {
466         if (!anImmediateSceneFboOit->Init (aCtx, aRendSizeX, aRendSizeY, myFboOitColorConfig,
467                                            anImmediateSceneFbo->DepthStencilTexture(), aNbSamples))
468         {
469           break;
470         }
471       }
472       else if (!anImmediateSceneFbo->IsValid())
473       {
474         anImmediateSceneFboOit->Release (aCtx.operator->());
475         anImmediateSceneFboOit->ChangeViewport (0, 0);
476       }
477     }
478     if (anFboIt == 0) // only the first OIT framebuffer is mandatory
479     {
480       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
481                          "Initialization of float texture framebuffer for use with\n"
482                          "  blended order-independent transparency rendering algorithm has failed.\n"
483                          "  Blended order-independent transparency will not be available.\n");
484       if (aNbSamples > 0)
485       {
486         myToDisableOITMSAA = Standard_True;
487       }
488       else
489       {
490         myToDisableOIT     = Standard_True;
491       }
492       toUseOit = false;
493     }
494   }
495   if (!toUseOit && myMainSceneFbosOit[0]->IsValid())
496   {
497     myMainSceneFbosOit     [0]->Release (aCtx.operator->());
498     myMainSceneFbosOit     [1]->Release (aCtx.operator->());
499     myImmediateSceneFbosOit[0]->Release (aCtx.operator->());
500     myImmediateSceneFbosOit[1]->Release (aCtx.operator->());
501     myMainSceneFbosOit     [0]->ChangeViewport (0, 0);
502     myMainSceneFbosOit     [1]->ChangeViewport (0, 0);
503     myImmediateSceneFbosOit[0]->ChangeViewport (0, 0);
504     myImmediateSceneFbosOit[1]->ChangeViewport (0, 0);
505   }
506
507   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
508   {
509     OpenGl_FrameBuffer* aMainFbos[2] =
510     {
511       myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL,
512       myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL
513     };
514     OpenGl_FrameBuffer* aMainFbosOit[2] =
515     {
516       myMainSceneFbosOit[0]->IsValid() ? myMainSceneFbosOit[0].operator->() : NULL,
517       myMainSceneFbosOit[1]->IsValid() ? myMainSceneFbosOit[1].operator->() :
518         myMainSceneFbosOit[0]->IsValid() ? myMainSceneFbosOit[0].operator->() : NULL
519     };
520
521     OpenGl_FrameBuffer* anImmFbos[2] =
522     {
523       myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
524       myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
525     };
526     OpenGl_FrameBuffer* anImmFbosOit[2] =
527     {
528       myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL,
529       myImmediateSceneFbosOit[1]->IsValid() ? myImmediateSceneFbosOit[1].operator->() :
530         myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL
531     };
532
533     if (IsActiveXR())
534     {
535       // use single frame for both views - caching main scene content makes no sense
536       // when head position is expected to be updated each frame redraw with high accuracy
537       aMainFbos[1]    = aMainFbos[0];
538       aMainFbosOit[1] = aMainFbosOit[0];
539       anImmFbos[0]    = aMainFbos[0];
540       anImmFbos[1]    = aMainFbos[1];
541       anImmFbosOit[0] = aMainFbosOit[0];
542       anImmFbosOit[1] = aMainFbosOit[1];
543     }
544     else if (!myTransientDrawToFront)
545     {
546       anImmFbos   [0] = aMainFbos   [0];
547       anImmFbos   [1] = aMainFbos   [1];
548       anImmFbosOit[0] = aMainFbosOit[0];
549       anImmFbosOit[1] = aMainFbosOit[1];
550     }
551     else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
552           || aStereoMode == Graphic3d_StereoMode_QuadBuffer)
553     {
554       anImmFbos   [0] = NULL;
555       anImmFbos   [1] = NULL;
556       anImmFbosOit[0] = NULL;
557       anImmFbosOit[1] = NULL;
558     }
559
560   #if !defined(GL_ES_VERSION_2_0)
561     aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
562   #endif
563     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
564                          aMainFbos[0] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
565
566     redraw (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], aMainFbosOit[0]);
567     myBackBufferRestored = Standard_True;
568     myIsImmediateDrawn   = Standard_False;
569   #if !defined(GL_ES_VERSION_2_0)
570     aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
571   #endif
572     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
573                          anImmFbos[0] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
574     if (!redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], anImmFbos[0], anImmFbosOit[0]))
575     {
576       toSwap = false;
577     }
578     else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip && toSwap)
579     {
580       aCtx->SwapBuffers();
581     }
582
583     if (IsActiveXR())
584     {
585       // push Left frame to HMD display composer
586       OpenGl_FrameBuffer* anXRFbo = hasXRBlitFbo ? myXrSceneFbo.get() : aMainFbos[0];
587       if (anXRFbo != aMainFbos[0])
588       {
589         blitBuffers (aMainFbos[0], anXRFbo); // resize or resolve MSAA samples
590       }
591     #if !defined(GL_ES_VERSION_2_0)
592       const Aspect_GraphicsLibrary aGraphicsLib = Aspect_GraphicsLibrary_OpenGL;
593     #else
594       const Aspect_GraphicsLibrary aGraphicsLib = Aspect_GraphicsLibrary_OpenGLES;
595     #endif
596       myXRSession->SubmitEye ((void* )(size_t )anXRFbo->ColorTexture()->TextureId(),
597                               aGraphicsLib, Aspect_ColorSpace_sRGB, Aspect_Eye_Left);
598     }
599
600   #if !defined(GL_ES_VERSION_2_0)
601     aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
602   #endif
603     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
604                          aMainFbos[1] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
605
606     redraw (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], aMainFbosOit[1]);
607     myBackBufferRestored = Standard_True;
608     myIsImmediateDrawn   = Standard_False;
609     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
610                          anImmFbos[1] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
611     if (!redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], anImmFbos[1], anImmFbosOit[1]))
612     {
613       toSwap = false;
614     }
615
616     if (IsActiveXR())
617     {
618       // push Right frame to HMD display composer
619       OpenGl_FrameBuffer* anXRFbo = hasXRBlitFbo ? myXrSceneFbo.get() : aMainFbos[1];
620       if (anXRFbo != aMainFbos[1])
621       {
622         blitBuffers (aMainFbos[1], anXRFbo); // resize or resolve MSAA samples
623       }
624     #if !defined(GL_ES_VERSION_2_0)
625       const Aspect_GraphicsLibrary aGraphicsLib = Aspect_GraphicsLibrary_OpenGL;
626     #else
627       const Aspect_GraphicsLibrary aGraphicsLib = Aspect_GraphicsLibrary_OpenGLES;
628     #endif
629       myXRSession->SubmitEye ((void* )(size_t )anXRFbo->ColorTexture()->TextureId(),
630                               aGraphicsLib, Aspect_ColorSpace_sRGB, Aspect_Eye_Right);
631       ::glFinish();
632
633       if (myRenderParams.ToMirrorComposer)
634       {
635         blitBuffers (anXRFbo, aFrameBuffer, myToFlipOutput);
636       }
637     }
638     else if (anImmFbos[0] != NULL)
639     {
640       aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(), 1.0f);
641       drawStereoPair (aFrameBuffer);
642     }
643   }
644   else
645   {
646     OpenGl_FrameBuffer* aMainFbo    = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : aFrameBuffer;
647     OpenGl_FrameBuffer* aMainFboOit = myMainSceneFbosOit[0]->IsValid() ? myMainSceneFbosOit[0].operator->() : NULL;
648     OpenGl_FrameBuffer* anImmFbo    = aFrameBuffer;
649     OpenGl_FrameBuffer* anImmFboOit = NULL;
650     if (!myTransientDrawToFront)
651     {
652       anImmFbo    = aMainFbo;
653       anImmFboOit = aMainFboOit;
654     }
655     else if (myImmediateSceneFbos[0]->IsValid())
656     {
657       anImmFbo    = myImmediateSceneFbos[0].operator->();
658       anImmFboOit = myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL;
659     }
660
661   #if !defined(GL_ES_VERSION_2_0)
662     if (aMainFbo == NULL)
663     {
664       aCtx->SetReadDrawBuffer (GL_BACK);
665     }
666   #endif
667     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
668                          aMainFbo != aFrameBuffer ? myRenderParams.RenderResolutionScale : 1.0f);
669
670     redraw (aProjectType, aMainFbo, aMainFboOit);
671     myBackBufferRestored = Standard_True;
672     myIsImmediateDrawn   = Standard_False;
673     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
674                          anImmFbo != aFrameBuffer ? myRenderParams.RenderResolutionScale : 1.0f);
675     if (!redrawImmediate (aProjectType, aMainFbo, anImmFbo, anImmFboOit))
676     {
677       toSwap = false;
678     }
679
680     if (anImmFbo != NULL
681      && anImmFbo != aFrameBuffer)
682     {
683       blitBuffers (anImmFbo, aFrameBuffer, myToFlipOutput);
684     }
685   }
686
687   if (myRenderParams.Method == Graphic3d_RM_RAYTRACING
688    && myRenderParams.IsGlobalIlluminationEnabled)
689   {
690     myAccumFrames++;
691   }
692
693   // bind default FBO
694   bindDefaultFbo();
695
696   if (wasDisabledMSAA != myToDisableMSAA
697    || hadFboBlit      != myHasFboBlit)
698   {
699     // retry on error
700     Redraw();
701   }
702
703   // reset state for safety
704   aCtx->BindProgram (Handle(OpenGl_ShaderProgram)());
705   if (aCtx->caps->ffpEnable)
706   {
707     aCtx->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
708   }
709
710   // Swap the buffers
711   if (toSwap)
712   {
713     aCtx->SwapBuffers();
714     if (!myMainSceneFbos[0]->IsValid())
715     {
716       myBackBufferRestored = Standard_False;
717     }
718   }
719   else
720   {
721     aCtx->core11fwd->glFlush();
722   }
723
724   // reset render mode state
725   aCtx->FetchState();
726   aCtx->FrameStats()->FrameEnd (myWorkspace->View(), false);
727
728   myWasRedrawnGL = Standard_True;
729 }
730
731 // =======================================================================
732 // function : RedrawImmediate
733 // purpose  :
734 // =======================================================================
735 void OpenGl_View::RedrawImmediate()
736 {
737   if (!myWorkspace->Activate())
738     return;
739
740   // no special handling of HMD display, since it will force full Redraw() due to no frame caching (myBackBufferRestored)
741   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
742   if (!myTransientDrawToFront
743    || !myBackBufferRestored
744    || (aCtx->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid()))
745   {
746     Redraw();
747     return;
748   }
749
750   const Graphic3d_StereoMode   aStereoMode  = myRenderParams.StereoMode;
751   Graphic3d_Camera::Projection aProjectType = myCamera->ProjectionType();
752   OpenGl_FrameBuffer*          aFrameBuffer = myFBO.get();
753   aCtx->FrameStats()->FrameStart (myWorkspace->View(), true);
754
755   if ( aFrameBuffer == NULL
756    && !aCtx->DefaultFrameBuffer().IsNull()
757    &&  aCtx->DefaultFrameBuffer()->IsValid())
758   {
759     aFrameBuffer = aCtx->DefaultFrameBuffer().operator->();
760   }
761
762   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
763   {
764     if (myMainSceneFbos[0]->IsValid()
765     && !myMainSceneFbos[1]->IsValid())
766     {
767       aProjectType = Graphic3d_Camera::Projection_Perspective;
768     }
769   }
770
771   bool toSwap = false;
772   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
773   {
774     OpenGl_FrameBuffer* aMainFbos[2] =
775     {
776       myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL,
777       myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL
778     };
779     OpenGl_FrameBuffer* anImmFbos[2] =
780     {
781       myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
782       myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
783     };
784     OpenGl_FrameBuffer* anImmFbosOit[2] =
785     {
786       myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL,
787       myImmediateSceneFbosOit[1]->IsValid() ? myImmediateSceneFbosOit[1].operator->() :
788         myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL
789     };
790     if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
791      || aStereoMode == Graphic3d_StereoMode_QuadBuffer)
792     {
793       anImmFbos[0]    = NULL;
794       anImmFbos[1]    = NULL;
795       anImmFbosOit[0] = NULL;
796       anImmFbosOit[1] = NULL;
797     }
798
799     if (aCtx->arbFBO != NULL)
800     {
801       aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
802     }
803   #if !defined(GL_ES_VERSION_2_0)
804     if (anImmFbos[0] == NULL)
805     {
806       aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
807     }
808   #endif
809
810     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
811                          anImmFbos[0] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
812     toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye,
813                               aMainFbos[0],
814                               anImmFbos[0],
815                               anImmFbosOit[0],
816                               Standard_True) || toSwap;
817     if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
818     &&  toSwap
819     && !aCtx->caps->buffersNoSwap)
820     {
821       aCtx->SwapBuffers();
822     }
823
824     if (aCtx->arbFBO != NULL)
825     {
826       aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
827     }
828   #if !defined(GL_ES_VERSION_2_0)
829     if (anImmFbos[1] == NULL)
830     {
831       aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
832     }
833   #endif
834     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
835                          anImmFbos[1] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
836     toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye,
837                               aMainFbos[1],
838                               anImmFbos[1],
839                               anImmFbosOit[1],
840                               Standard_True) || toSwap;
841     if (anImmFbos[0] != NULL)
842     {
843       drawStereoPair (aFrameBuffer);
844     }
845   }
846   else
847   {
848     OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL;
849     OpenGl_FrameBuffer* anImmFbo = aFrameBuffer;
850     OpenGl_FrameBuffer* anImmFboOit = NULL;
851     if (myImmediateSceneFbos[0]->IsValid())
852     {
853       anImmFbo    = myImmediateSceneFbos[0].operator->();
854       anImmFboOit = myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL;
855     }
856   #if !defined(GL_ES_VERSION_2_0)
857     if (aMainFbo == NULL)
858     {
859       aCtx->SetReadDrawBuffer (GL_BACK);
860     }
861   #endif
862     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
863                          anImmFbo != aFrameBuffer ? myRenderParams.RenderResolutionScale : 1.0f);
864     toSwap = redrawImmediate (aProjectType,
865                               aMainFbo,
866                               anImmFbo,
867                               anImmFboOit,
868                               Standard_True) || toSwap;
869     if (anImmFbo != NULL
870      && anImmFbo != aFrameBuffer)
871     {
872       blitBuffers (anImmFbo, aFrameBuffer, myToFlipOutput);
873     }
874   }
875
876   // bind default FBO
877   bindDefaultFbo();
878
879   // reset state for safety
880   aCtx->BindProgram (Handle(OpenGl_ShaderProgram)());
881   if (aCtx->caps->ffpEnable)
882   {
883     aCtx->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
884   }
885
886   if (toSwap && !aCtx->caps->buffersNoSwap)
887   {
888     aCtx->SwapBuffers();
889   }
890   else
891   {
892     aCtx->core11fwd->glFlush();
893   }
894   aCtx->FrameStats()->FrameEnd (myWorkspace->View(), true);
895
896   myWasRedrawnGL = Standard_True;
897 }
898
899 // =======================================================================
900 // function : redraw
901 // purpose  :
902 // =======================================================================
903 void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection,
904                           OpenGl_FrameBuffer*                theReadDrawFbo,
905                           OpenGl_FrameBuffer*                theOitAccumFbo)
906 {
907   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
908   if (theReadDrawFbo != NULL)
909   {
910     theReadDrawFbo->BindBuffer    (aCtx);
911     theReadDrawFbo->SetupViewport (aCtx);
912   }
913   else
914   {
915     const Standard_Integer aViewport[4] = { 0, 0, myWindow->Width(), myWindow->Height() };
916     aCtx->ResizeViewport (aViewport);
917   }
918
919   // request reset of material
920   aCtx->ShaderManager()->UpdateMaterialState();
921
922   myWorkspace->UseZBuffer()    = Standard_True;
923   myWorkspace->UseDepthWrite() = Standard_True;
924   GLbitfield toClear = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
925   glDepthFunc (GL_LEQUAL);
926   glDepthMask (GL_TRUE);
927   glEnable (GL_DEPTH_TEST);
928
929 #if !defined(GL_ES_VERSION_2_0)
930   glClearDepth (1.0);
931 #else
932   glClearDepthf (1.0f);
933 #endif
934
935   const OpenGl_Vec4 aBgColor = aCtx->Vec4FromQuantityColor (myBgColor);
936   glClearColor (aBgColor.r(), aBgColor.g(), aBgColor.b(), 0.0f);
937
938   glClear (toClear);
939
940   render (theProjection, theReadDrawFbo, theOitAccumFbo, Standard_False);
941 }
942
943 // =======================================================================
944 // function : redrawMonoImmediate
945 // purpose  :
946 // =======================================================================
947 bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProjection,
948                                    OpenGl_FrameBuffer*                theReadFbo,
949                                    OpenGl_FrameBuffer*                theDrawFbo,
950                                    OpenGl_FrameBuffer*                theOitAccumFbo,
951                                    const Standard_Boolean             theIsPartialUpdate)
952 {
953   const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
954   GLboolean toCopyBackToFront = GL_FALSE;
955   if (theDrawFbo == theReadFbo
956    && theDrawFbo != NULL
957    && theDrawFbo->IsValid())
958   {
959     myBackBufferRestored = Standard_False;
960     theDrawFbo->BindBuffer (aCtx);
961   }
962   else if (theReadFbo != NULL
963         && theReadFbo->IsValid()
964         && aCtx->IsRender())
965   {
966     if (!blitBuffers (theReadFbo, theDrawFbo))
967     {
968       return true;
969     }
970   }
971   else if (theDrawFbo == NULL)
972   {
973   #if !defined(GL_ES_VERSION_2_0)
974     aCtx->core11fwd->glGetBooleanv (GL_DOUBLEBUFFER, &toCopyBackToFront);
975   #endif
976     if (toCopyBackToFront
977      && myTransientDrawToFront)
978     {
979       if (!HasImmediateStructures()
980        && !theIsPartialUpdate)
981       {
982         // prefer Swap Buffers within Redraw in compatibility mode (without FBO)
983         return true;
984       }
985       if (!copyBackToFront())
986       {
987         toCopyBackToFront    = GL_FALSE;
988         myBackBufferRestored = Standard_False;
989       }
990     }
991     else
992     {
993       toCopyBackToFront    = GL_FALSE;
994       myBackBufferRestored = Standard_False;
995     }
996   }
997   else
998   {
999     myBackBufferRestored = Standard_False;
1000   }
1001   myIsImmediateDrawn = Standard_True;
1002
1003   myWorkspace->UseZBuffer()    = Standard_True;
1004   myWorkspace->UseDepthWrite() = Standard_True;
1005   glDepthFunc (GL_LEQUAL);
1006   glDepthMask (GL_TRUE);
1007   glEnable (GL_DEPTH_TEST);
1008 #if !defined(GL_ES_VERSION_2_0)
1009   glClearDepth (1.0);
1010 #else
1011   glClearDepthf (1.0f);
1012 #endif
1013
1014   render (theProjection, theDrawFbo, theOitAccumFbo, Standard_True);
1015
1016   return !toCopyBackToFront;
1017 }
1018
1019 //=======================================================================
1020 //function : Render
1021 //purpose  :
1022 //=======================================================================
1023 void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
1024                           OpenGl_FrameBuffer*          theOutputFBO,
1025                           OpenGl_FrameBuffer*          theOitAccumFbo,
1026                           const Standard_Boolean       theToDrawImmediate)
1027 {
1028   // ==================================
1029   //      Step 1: Prepare for render
1030   // ==================================
1031
1032   const Handle(OpenGl_Context)& aContext = myWorkspace->GetGlContext();
1033   aContext->SetAllowSampleAlphaToCoverage (myRenderParams.ToEnableAlphaToCoverage
1034                                         && theOutputFBO != NULL
1035                                         && theOutputFBO->NbSamples() != 0);
1036
1037 #if !defined(GL_ES_VERSION_2_0)
1038   // Disable current clipping planes
1039   if (aContext->core11 != NULL)
1040   {
1041     const Standard_Integer aMaxPlanes = aContext->MaxClipPlanes();
1042     for (Standard_Integer aClipPlaneId = GL_CLIP_PLANE0; aClipPlaneId < GL_CLIP_PLANE0 + aMaxPlanes; ++aClipPlaneId)
1043     {
1044       aContext->core11fwd->glDisable (aClipPlaneId);
1045     }
1046   }
1047 #endif
1048
1049   // update states of OpenGl_BVHTreeSelector (frustum culling algorithm);
1050   // note that we pass here window dimensions ignoring Graphic3d_RenderingParams::RenderResolutionScale
1051   myBVHSelector.SetViewVolume (myCamera);
1052   myBVHSelector.SetViewportSize (myWindow->Width(), myWindow->Height(), myRenderParams.ResolutionRatio());
1053   myBVHSelector.CacheClipPtsProjections();
1054
1055   const Handle(OpenGl_ShaderManager)& aManager = aContext->ShaderManager();
1056   const Handle(Graphic3d_LightSet)&   aLights  = myShadingModel == Graphic3d_TOSM_UNLIT ? myNoShadingLight : myLights;
1057   Standard_Size aLightsRevision = 0;
1058   if (!aLights.IsNull())
1059   {
1060     aLightsRevision = aLights->UpdateRevision();
1061   }
1062   if (StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index()) != myLastLightSourceState
1063    || aLightsRevision != myLightsRevision)
1064   {
1065     myLightsRevision = aLightsRevision;
1066     aManager->UpdateLightSourceStateTo (aLights, SpecIBLMapLevels());
1067     myLastLightSourceState = StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index());
1068   }
1069
1070   // Update matrices if camera has changed.
1071   Graphic3d_WorldViewProjState aWVPState = myCamera->WorldViewProjState();
1072   if (myWorldViewProjState != aWVPState)
1073   {
1074     myAccumFrames = 0;
1075     myWorldViewProjState = aWVPState;
1076   }
1077
1078   myLocalOrigin.SetCoord (0.0, 0.0, 0.0);
1079   aContext->SetCamera (myCamera);
1080   if (aManager->ModelWorldState().Index() == 0)
1081   {
1082     aContext->ShaderManager()->UpdateModelWorldStateTo (OpenGl_Mat4());
1083   }
1084
1085   // ====================================
1086   //      Step 2: Redraw background
1087   // ====================================
1088
1089   // Render background
1090   if (!theToDrawImmediate)
1091   {
1092     drawBackground (myWorkspace, theProjection);
1093   }
1094
1095 #if !defined(GL_ES_VERSION_2_0)
1096   // Switch off lighting by default
1097   if (aContext->core11 != NULL
1098    && aContext->caps->ffpEnable)
1099   {
1100     glDisable(GL_LIGHTING);
1101   }
1102 #endif
1103
1104   // =================================
1105   //      Step 3: Redraw main plane
1106   // =================================
1107
1108   // Setup face culling
1109   GLboolean isCullFace = GL_FALSE;
1110   if (myBackfacing != Graphic3d_TOBM_AUTOMATIC)
1111   {
1112     isCullFace = glIsEnabled (GL_CULL_FACE);
1113     if (myBackfacing == Graphic3d_TOBM_DISABLE)
1114     {
1115       glEnable (GL_CULL_FACE);
1116       glCullFace (GL_BACK);
1117     }
1118     else
1119       glDisable (GL_CULL_FACE);
1120   }
1121
1122 #if !defined(GL_ES_VERSION_2_0)
1123   // if the view is scaled normal vectors are scaled to unit
1124   // length for correct displaying of shaded objects
1125   const gp_Pnt anAxialScale = aContext->Camera()->AxialScale();
1126   if (anAxialScale.X() != 1.F ||
1127       anAxialScale.Y() != 1.F ||
1128       anAxialScale.Z() != 1.F)
1129   {
1130     aContext->SetGlNormalizeEnabled (Standard_True);
1131   }
1132   else
1133   {
1134     aContext->SetGlNormalizeEnabled (Standard_False);
1135   }
1136 #endif
1137
1138   aManager->SetShadingModel (OpenGl_ShaderManager::PBRShadingModelFallback (myShadingModel, checkPBRAvailability()));
1139
1140   // Redraw 3d scene
1141   if (theProjection == Graphic3d_Camera::Projection_MonoLeftEye)
1142   {
1143     aContext->ProjectionState.SetCurrent (aContext->Camera()->ProjectionStereoLeftF());
1144     aContext->ApplyProjectionMatrix();
1145   }
1146   else if (theProjection == Graphic3d_Camera::Projection_MonoRightEye)
1147   {
1148     aContext->ProjectionState.SetCurrent (aContext->Camera()->ProjectionStereoRightF());
1149     aContext->ApplyProjectionMatrix();
1150   }
1151
1152   myWorkspace->SetEnvironmentTexture (myTextureEnv);
1153
1154   renderScene (theProjection, theOutputFBO, theOitAccumFbo, theToDrawImmediate);
1155
1156   myWorkspace->SetEnvironmentTexture (Handle(OpenGl_TextureSet)());
1157
1158   // ===============================
1159   //      Step 4: Trihedron
1160   // ===============================
1161
1162   // Resetting GL parameters according to the default aspects
1163   // in order to synchronize GL state with the graphic driver state
1164   // before drawing auxiliary stuff (trihedrons, overlayer)
1165   myWorkspace->ResetAppliedAspect();
1166
1167   // Render trihedron
1168   if (!theToDrawImmediate)
1169   {
1170     renderTrihedron (myWorkspace);
1171
1172     // Restore face culling
1173     if (myBackfacing != Graphic3d_TOBM_AUTOMATIC)
1174     {
1175       if (isCullFace)
1176       {
1177         glEnable (GL_CULL_FACE);
1178         glCullFace (GL_BACK);
1179       }
1180       else
1181         glDisable (GL_CULL_FACE);
1182     }
1183   }
1184   else
1185   {
1186     renderFrameStats();
1187   }
1188
1189   myWorkspace->ResetAppliedAspect();
1190   aContext->SetAllowSampleAlphaToCoverage (false);
1191   aContext->SetSampleAlphaToCoverage (false);
1192
1193   // reset FFP state for safety
1194   aContext->BindProgram (Handle(OpenGl_ShaderProgram)());
1195   if (aContext->caps->ffpEnable)
1196   {
1197     aContext->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
1198   }
1199
1200   // ==============================================================
1201   //      Step 6: Keep shader manager informed about last View
1202   // ==============================================================
1203
1204   if (!aManager.IsNull())
1205   {
1206     aManager->SetLastView (this);
1207   }
1208 }
1209
1210 // =======================================================================
1211 // function : InvalidateBVHData
1212 // purpose  :
1213 // =======================================================================
1214 void OpenGl_View::InvalidateBVHData (const Graphic3d_ZLayerId theLayerId)
1215 {
1216   myZLayers.InvalidateBVHData (theLayerId);
1217 }
1218
1219 //=======================================================================
1220 //function : renderStructs
1221 //purpose  :
1222 //=======================================================================
1223 void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
1224                                  OpenGl_FrameBuffer*          theReadDrawFbo,
1225                                  OpenGl_FrameBuffer*          theOitAccumFbo,
1226                                  const Standard_Boolean       theToDrawImmediate)
1227 {
1228   myZLayers.UpdateCulling (myWorkspace, theToDrawImmediate);
1229   if ( myZLayers.NbStructures() <= 0 )
1230     return;
1231
1232   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
1233   Standard_Boolean toRenderGL = theToDrawImmediate ||
1234     myRenderParams.Method != Graphic3d_RM_RAYTRACING ||
1235     myRaytraceInitStatus == OpenGl_RT_FAIL ||
1236     aCtx->IsFeedback();
1237
1238   if (!toRenderGL)
1239   {
1240     const Standard_Integer aSizeX = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeX() : myWindow->Width();
1241     const Standard_Integer aSizeY = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeY() : myWindow->Height();
1242
1243     toRenderGL = !initRaytraceResources (aSizeX, aSizeY, aCtx)
1244               || !updateRaytraceGeometry (OpenGl_GUM_CHECK, myId, aCtx);
1245
1246     toRenderGL |= !myIsRaytraceDataValid; // if no ray-trace data use OpenGL
1247
1248     if (!toRenderGL)
1249     {
1250       myOpenGlFBO ->InitLazy (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, 0);
1251
1252       if (theReadDrawFbo != NULL)
1253         theReadDrawFbo->UnbindBuffer (aCtx);
1254
1255       // Prepare preliminary OpenGL output
1256       if (aCtx->arbFBOBlit != NULL)
1257       {
1258         // Render bottom OSD layer
1259         myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Bottom, theReadDrawFbo, theOitAccumFbo);
1260
1261         const Standard_Integer aPrevFilter = myWorkspace->RenderFilter() & ~(Standard_Integer )(OpenGl_RenderFilter_NonRaytraceableOnly);
1262         myWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_NonRaytraceableOnly);
1263         {
1264           if (theReadDrawFbo != NULL)
1265           {
1266             theReadDrawFbo->BindDrawBuffer (aCtx);
1267           }
1268           else
1269           {
1270             aCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, 0);
1271             aCtx->SetFrameBufferSRGB (false);
1272           }
1273
1274           // Render non-polygonal elements in default layer
1275           myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_RayTracable, theReadDrawFbo, theOitAccumFbo);
1276         }
1277         myWorkspace->SetRenderFilter (aPrevFilter);
1278       }
1279
1280       if (theReadDrawFbo != NULL)
1281       {
1282         theReadDrawFbo->BindBuffer (aCtx);
1283       }
1284       else
1285       {
1286         aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, 0);
1287         aCtx->SetFrameBufferSRGB (false);
1288       }
1289
1290       // Reset OpenGl aspects state to default to avoid enabling of
1291       // backface culling which is not supported in ray-tracing.
1292       myWorkspace->ResetAppliedAspect();
1293
1294       // Ray-tracing polygonal primitive arrays
1295       raytrace (aSizeX, aSizeY, theProjection, theReadDrawFbo, aCtx);
1296
1297       // Render upper (top and topmost) OpenGL layers
1298       myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Upper, theReadDrawFbo, theOitAccumFbo);
1299     }
1300   }
1301
1302   // Redraw 3D scene using OpenGL in standard
1303   // mode or in case of ray-tracing failure
1304   if (toRenderGL)
1305   {
1306     myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_All, theReadDrawFbo, theOitAccumFbo);
1307
1308     // Set flag that scene was redrawn by standard pipeline
1309     myWasRedrawnGL = Standard_True;
1310   }
1311 }
1312
1313 //=======================================================================
1314 //function : renderTrihedron
1315 //purpose  :
1316 //=======================================================================
1317 void OpenGl_View::renderTrihedron (const Handle(OpenGl_Workspace) &theWorkspace)
1318 {
1319   if (myToShowGradTrihedron)
1320   {
1321     myGraduatedTrihedron.Render (theWorkspace);
1322   }
1323 }
1324
1325 //=======================================================================
1326 //function : renderFrameStats
1327 //purpose  :
1328 //=======================================================================
1329 void OpenGl_View::renderFrameStats()
1330 {
1331   if (myRenderParams.ToShowStats
1332    && myRenderParams.CollectedStats != Graphic3d_RenderingParams::PerfCounters_NONE)
1333   {
1334     myFrameStatsPrs.Update (myWorkspace);
1335     myFrameStatsPrs.Render (myWorkspace);
1336   }
1337 }
1338
1339 // =======================================================================
1340 // function : Invalidate
1341 // purpose  :
1342 // =======================================================================
1343 void OpenGl_View::Invalidate()
1344 {
1345   myBackBufferRestored = Standard_False;
1346 }
1347
1348 //=======================================================================
1349 //function : renderScene
1350 //purpose  :
1351 //=======================================================================
1352 void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection,
1353                                OpenGl_FrameBuffer*          theReadDrawFbo,
1354                                OpenGl_FrameBuffer*          theOitAccumFbo,
1355                                const Standard_Boolean       theToDrawImmediate)
1356 {
1357   const Handle(OpenGl_Context)& aContext = myWorkspace->GetGlContext();
1358
1359   // Specify clipping planes in view transformation space
1360   aContext->ChangeClipping().Reset (myClipPlanes);
1361   if (!myClipPlanes.IsNull()
1362    && !myClipPlanes->IsEmpty())
1363   {
1364     aContext->ShaderManager()->UpdateClippingState();
1365   }
1366
1367   renderStructs (theProjection, theReadDrawFbo, theOitAccumFbo, theToDrawImmediate);
1368   aContext->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
1369
1370   // Apply restored view matrix.
1371   aContext->ApplyWorldViewMatrix();
1372
1373   aContext->ChangeClipping().Reset (Handle(Graphic3d_SequenceOfHClipPlane)());
1374   if (!myClipPlanes.IsNull()
1375    && !myClipPlanes->IsEmpty())
1376   {
1377     aContext->ShaderManager()->RevertClippingState();
1378   }
1379 }
1380
1381 // =======================================================================
1382 // function : bindDefaultFbo
1383 // purpose  :
1384 // =======================================================================
1385 void OpenGl_View::bindDefaultFbo (OpenGl_FrameBuffer* theCustomFbo)
1386 {
1387   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
1388   OpenGl_FrameBuffer* anFbo = (theCustomFbo != NULL && theCustomFbo->IsValid())
1389                             ?  theCustomFbo
1390                             : (!aCtx->DefaultFrameBuffer().IsNull()
1391                              && aCtx->DefaultFrameBuffer()->IsValid()
1392                               ? aCtx->DefaultFrameBuffer().operator->()
1393                               : NULL);
1394   if (anFbo != NULL)
1395   {
1396     anFbo->BindBuffer (aCtx);
1397     anFbo->SetupViewport (aCtx);
1398   }
1399   else
1400   {
1401   #if !defined(GL_ES_VERSION_2_0)
1402     aCtx->SetReadDrawBuffer (GL_BACK);
1403   #else
1404     if (aCtx->arbFBO != NULL)
1405     {
1406       aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
1407     }
1408   #endif
1409     const Standard_Integer aViewport[4] = { 0, 0, myWindow->Width(), myWindow->Height() };
1410     aCtx->ResizeViewport (aViewport);
1411   }
1412 }
1413
1414 // =======================================================================
1415 // function : initBlitQuad
1416 // purpose  :
1417 // =======================================================================
1418 OpenGl_VertexBuffer* OpenGl_View::initBlitQuad (const Standard_Boolean theToFlip)
1419 {
1420   OpenGl_VertexBuffer* aVerts = NULL;
1421   if (!theToFlip)
1422   {
1423     aVerts = &myFullScreenQuad;
1424     if (!aVerts->IsValid())
1425     {
1426       OpenGl_Vec4 aQuad[4] =
1427       {
1428         OpenGl_Vec4( 1.0f, -1.0f, 1.0f, 0.0f),
1429         OpenGl_Vec4( 1.0f,  1.0f, 1.0f, 1.0f),
1430         OpenGl_Vec4(-1.0f, -1.0f, 0.0f, 0.0f),
1431         OpenGl_Vec4(-1.0f,  1.0f, 0.0f, 1.0f)
1432       };
1433       aVerts->Init (myWorkspace->GetGlContext(), 4, 4, aQuad[0].GetData());
1434     }
1435   }
1436   else
1437   {
1438     aVerts = &myFullScreenQuadFlip;
1439     if (!aVerts->IsValid())
1440     {
1441       OpenGl_Vec4 aQuad[4] =
1442       {
1443         OpenGl_Vec4( 1.0f, -1.0f, 1.0f, 1.0f),
1444         OpenGl_Vec4( 1.0f,  1.0f, 1.0f, 0.0f),
1445         OpenGl_Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1446         OpenGl_Vec4(-1.0f,  1.0f, 0.0f, 0.0f)
1447       };
1448       aVerts->Init (myWorkspace->GetGlContext(), 4, 4, aQuad[0].GetData());
1449     }
1450   }
1451   return aVerts;
1452 }
1453
1454 // =======================================================================
1455 // function : blitBuffers
1456 // purpose  :
1457 // =======================================================================
1458 bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
1459                                OpenGl_FrameBuffer*    theDrawFbo,
1460                                const Standard_Boolean theToFlip)
1461 {
1462   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
1463   const Standard_Integer aReadSizeX = theReadFbo != NULL ? theReadFbo->GetVPSizeX() : myWindow->Width();
1464   const Standard_Integer aReadSizeY = theReadFbo != NULL ? theReadFbo->GetVPSizeY() : myWindow->Height();
1465   const Standard_Integer aDrawSizeX = theDrawFbo != NULL ? theDrawFbo->GetVPSizeX() : myWindow->Width();
1466   const Standard_Integer aDrawSizeY = theDrawFbo != NULL ? theDrawFbo->GetVPSizeY() : myWindow->Height();
1467   if (theReadFbo == NULL || aCtx->IsFeedback())
1468   {
1469     return false;
1470   }
1471   else if (theReadFbo == theDrawFbo)
1472   {
1473     return true;
1474   }
1475
1476   // clear destination before blitting
1477   if (theDrawFbo != NULL
1478   &&  theDrawFbo->IsValid())
1479   {
1480     theDrawFbo->BindBuffer (aCtx);
1481   }
1482   else
1483   {
1484     aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
1485     aCtx->SetFrameBufferSRGB (false);
1486   }
1487   const Standard_Integer aViewport[4] = { 0, 0, aDrawSizeX, aDrawSizeY };
1488   aCtx->ResizeViewport (aViewport);
1489
1490 #if !defined(GL_ES_VERSION_2_0)
1491   aCtx->core20fwd->glClearDepth  (1.0);
1492 #else
1493   aCtx->core20fwd->glClearDepthf (1.0f);
1494 #endif
1495   aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1496
1497   const bool toApplyGamma = aCtx->ToRenderSRGB() != aCtx->IsFrameBufferSRGB();
1498   if (aCtx->arbFBOBlit != NULL
1499   && !toApplyGamma
1500   &&  theReadFbo->NbSamples() != 0)
1501   {
1502     GLbitfield aCopyMask = 0;
1503     theReadFbo->BindReadBuffer (aCtx);
1504     if (theDrawFbo != NULL
1505      && theDrawFbo->IsValid())
1506     {
1507       theDrawFbo->BindDrawBuffer (aCtx);
1508       if (theDrawFbo->HasColor()
1509        && theReadFbo->HasColor())
1510       {
1511         aCopyMask |= GL_COLOR_BUFFER_BIT;
1512       }
1513       if (theDrawFbo->HasDepth()
1514        && theReadFbo->HasDepth())
1515       {
1516         aCopyMask |= GL_DEPTH_BUFFER_BIT;
1517       }
1518     }
1519     else
1520     {
1521       if (theReadFbo->HasColor())
1522       {
1523         aCopyMask |= GL_COLOR_BUFFER_BIT;
1524       }
1525       if (theReadFbo->HasDepth())
1526       {
1527         aCopyMask |= GL_DEPTH_BUFFER_BIT;
1528       }
1529       aCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
1530       aCtx->SetFrameBufferSRGB (false);
1531     }
1532
1533     // we don't copy stencil buffer here... does it matter for performance?
1534     aCtx->arbFBOBlit->glBlitFramebuffer (0, 0, aReadSizeX, aReadSizeY,
1535                                          0, 0, aDrawSizeX, aDrawSizeY,
1536                                          aCopyMask, GL_NEAREST);
1537     const int anErr = ::glGetError();
1538     if (anErr != GL_NO_ERROR)
1539     {
1540       // glBlitFramebuffer() might fail in several cases:
1541       // - Both FBOs have MSAA and they are samples number does not match.
1542       //   OCCT checks that this does not happen,
1543       //   however some graphics drivers provide an option for overriding MSAA.
1544       //   In this case window MSAA might be non-zero (and application can not check it)
1545       //   and might not match MSAA of our offscreen FBOs.
1546       // - Pixel formats of FBOs do not match.
1547       //   This also might happen with window has pixel format,
1548       //   e.g. Mesa fails blitting RGBA8 -> RGB8 while other drivers support this conversion.
1549       TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "FBO blitting has failed [Error #" + anErr + "]\n"
1550                                       + "  Please check your graphics driver settings or try updating driver.";
1551       if (theReadFbo->NbSamples() != 0)
1552       {
1553         myToDisableMSAA = true;
1554         aMsg += "\n  MSAA settings should not be overridden by driver!";
1555       }
1556       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1557                          GL_DEBUG_TYPE_ERROR,
1558                          0,
1559                          GL_DEBUG_SEVERITY_HIGH,
1560                          aMsg);
1561     }
1562
1563     if (theDrawFbo != NULL
1564      && theDrawFbo->IsValid())
1565     {
1566       theDrawFbo->BindBuffer (aCtx);
1567     }
1568     else
1569     {
1570       aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
1571       aCtx->SetFrameBufferSRGB (false);
1572     }
1573   }
1574   else
1575   {
1576     aCtx->core20fwd->glDepthFunc (GL_ALWAYS);
1577     aCtx->core20fwd->glDepthMask (GL_TRUE);
1578     aCtx->core20fwd->glEnable (GL_DEPTH_TEST);
1579   #if defined(GL_ES_VERSION_2_0)
1580     if (!aCtx->IsGlGreaterEqual (3, 0)
1581      && !aCtx->extFragDepth)
1582     {
1583       aCtx->core20fwd->glDisable (GL_DEPTH_TEST);
1584     }
1585   #endif
1586
1587     aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
1588
1589     const Graphic3d_TypeOfTextureFilter aFilter = (aDrawSizeX == aReadSizeX && aDrawSizeY == aReadSizeY) ? Graphic3d_TOTF_NEAREST : Graphic3d_TOTF_BILINEAR;
1590     const GLint aFilterGl = aFilter == Graphic3d_TOTF_NEAREST ? GL_NEAREST : GL_LINEAR;
1591
1592     OpenGl_VertexBuffer* aVerts = initBlitQuad (theToFlip);
1593     const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
1594     if (aVerts->IsValid()
1595      && aManager->BindFboBlitProgram (theReadFbo != NULL ? theReadFbo->NbSamples() : 0, toApplyGamma))
1596     {
1597       aCtx->SetSampleAlphaToCoverage (false);
1598       theReadFbo->ColorTexture()->Bind (aCtx, Graphic3d_TextureUnit_0);
1599       if (theReadFbo->ColorTexture()->Sampler()->Parameters()->Filter() != aFilter)
1600       {
1601         theReadFbo->ColorTexture()->Sampler()->Parameters()->SetFilter (aFilter);
1602         aCtx->core20fwd->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilterGl);
1603         aCtx->core20fwd->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilterGl);
1604       }
1605
1606       theReadFbo->DepthStencilTexture()->Bind (aCtx, Graphic3d_TextureUnit_1);
1607       if (theReadFbo->DepthStencilTexture()->Sampler()->Parameters()->Filter() != aFilter)
1608       {
1609         theReadFbo->DepthStencilTexture()->Sampler()->Parameters()->SetFilter (aFilter);
1610         aCtx->core20fwd->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilterGl);
1611         aCtx->core20fwd->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilterGl);
1612       }
1613
1614       aVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS);
1615
1616       aCtx->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
1617
1618       aVerts->UnbindVertexAttrib (aCtx, Graphic3d_TOA_POS);
1619       theReadFbo->DepthStencilTexture()->Unbind (aCtx, Graphic3d_TextureUnit_1);
1620       theReadFbo->ColorTexture()       ->Unbind (aCtx, Graphic3d_TextureUnit_0);
1621       aCtx->BindProgram (NULL);
1622     }
1623     else
1624     {
1625       TCollection_ExtendedString aMsg = TCollection_ExtendedString()
1626         + "Error! FBO blitting has failed";
1627       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1628                          GL_DEBUG_TYPE_ERROR,
1629                          0,
1630                          GL_DEBUG_SEVERITY_HIGH,
1631                          aMsg);
1632       myHasFboBlit = Standard_False;
1633       theReadFbo->Release (aCtx.operator->());
1634       return true;
1635     }
1636   }
1637   return true;
1638 }
1639
1640 // =======================================================================
1641 // function : drawStereoPair
1642 // purpose  :
1643 // =======================================================================
1644 void OpenGl_View::drawStereoPair (OpenGl_FrameBuffer* theDrawFbo)
1645 {
1646   const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
1647   bindDefaultFbo (theDrawFbo);
1648   OpenGl_FrameBuffer* aPair[2] =
1649   {
1650     myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
1651     myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
1652   };
1653   if (aPair[0] == NULL
1654   ||  aPair[1] == NULL
1655   || !myTransientDrawToFront)
1656   {
1657     aPair[0] = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL;
1658     aPair[1] = myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL;
1659   }
1660
1661   if (aPair[0] == NULL
1662    || aPair[1] == NULL)
1663   {
1664     return;
1665   }
1666
1667   if (aPair[0]->NbSamples() != 0)
1668   {
1669     // resolve MSAA buffers before drawing
1670     if (!myOpenGlFBO ->InitLazy (aCtx, aPair[0]->GetVPSizeX(), aPair[0]->GetVPSizeY(), myFboColorFormat, myFboDepthFormat, 0)
1671      || !myOpenGlFBO2->InitLazy (aCtx, aPair[0]->GetVPSizeX(), aPair[0]->GetVPSizeY(), myFboColorFormat, 0, 0))
1672     {
1673       aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1674                          GL_DEBUG_TYPE_ERROR,
1675                          0,
1676                          GL_DEBUG_SEVERITY_HIGH,
1677                          "Error! Unable to allocate FBO for blitting stereo pair");
1678       bindDefaultFbo (theDrawFbo);
1679       return;
1680     }
1681
1682     if (!blitBuffers (aPair[0], myOpenGlFBO .operator->(), Standard_False)
1683      || !blitBuffers (aPair[1], myOpenGlFBO2.operator->(), Standard_False))
1684     {
1685       bindDefaultFbo (theDrawFbo);
1686       return;
1687     }
1688
1689     aPair[0] = myOpenGlFBO .operator->();
1690     aPair[1] = myOpenGlFBO2.operator->();
1691     bindDefaultFbo (theDrawFbo);
1692   }
1693
1694   struct
1695   {
1696     Standard_Integer left;
1697     Standard_Integer top;
1698     Standard_Integer right;
1699     Standard_Integer bottom;
1700     Standard_Integer dx() { return right  - left; }
1701     Standard_Integer dy() { return bottom - top; }
1702   } aGeom;
1703
1704   myWindow->PlatformWindow()->Position (aGeom.left, aGeom.top, aGeom.right, aGeom.bottom);
1705
1706   Standard_Boolean toReverse = myRenderParams.ToReverseStereo;
1707   const Standard_Boolean isOddY = (aGeom.top + aGeom.dy()) % 2 == 1;
1708   const Standard_Boolean isOddX =  aGeom.left % 2 == 1;
1709   if (isOddY
1710    && (myRenderParams.StereoMode == Graphic3d_StereoMode_RowInterlaced
1711     || myRenderParams.StereoMode == Graphic3d_StereoMode_ChessBoard))
1712   {
1713     toReverse = !toReverse;
1714   }
1715   if (isOddX
1716    && (myRenderParams.StereoMode == Graphic3d_StereoMode_ColumnInterlaced
1717     || myRenderParams.StereoMode == Graphic3d_StereoMode_ChessBoard))
1718   {
1719     toReverse = !toReverse;
1720   }
1721
1722   if (toReverse)
1723   {
1724     std::swap (aPair[0], aPair[1]);
1725   }
1726
1727   aCtx->core20fwd->glDepthFunc (GL_ALWAYS);
1728   aCtx->core20fwd->glDepthMask (GL_TRUE);
1729   aCtx->core20fwd->glEnable (GL_DEPTH_TEST);
1730
1731   aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
1732   OpenGl_VertexBuffer* aVerts = initBlitQuad (myToFlipOutput);
1733
1734   const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
1735   if (aVerts->IsValid()
1736    && aManager->BindStereoProgram (myRenderParams.StereoMode))
1737   {
1738     if (myRenderParams.StereoMode == Graphic3d_StereoMode_Anaglyph)
1739     {
1740       OpenGl_Mat4 aFilterL, aFilterR;
1741       aFilterL.SetDiagonal (Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
1742       aFilterR.SetDiagonal (Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
1743       switch (myRenderParams.AnaglyphFilter)
1744       {
1745         case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple:
1746         {
1747           aFilterL.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
1748           aFilterR.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
1749           aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
1750           break;
1751         }
1752         case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized:
1753         {
1754           aFilterL.SetRow (0, Graphic3d_Vec4 ( 0.4154f,      0.4710f,      0.16666667f, 0.0f));
1755           aFilterL.SetRow (1, Graphic3d_Vec4 (-0.0458f,     -0.0484f,     -0.0257f,     0.0f));
1756           aFilterL.SetRow (2, Graphic3d_Vec4 (-0.0547f,     -0.0615f,      0.0128f,     0.0f));
1757           aFilterL.SetRow (3, Graphic3d_Vec4 ( 0.0f,         0.0f,         0.0f,        0.0f));
1758           aFilterR.SetRow (0, Graphic3d_Vec4 (-0.01090909f, -0.03636364f, -0.00606061f, 0.0f));
1759           aFilterR.SetRow (1, Graphic3d_Vec4 ( 0.37560000f,  0.73333333f,  0.01111111f, 0.0f));
1760           aFilterR.SetRow (2, Graphic3d_Vec4 (-0.06510000f, -0.12870000f,  1.29710000f, 0.0f));
1761           aFilterR.SetRow (3, Graphic3d_Vec4 ( 0.0f,                0.0f,  0.0f,        0.0f));
1762           break;
1763         }
1764         case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple:
1765         {
1766           aFilterL.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
1767           aFilterL.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
1768           aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
1769           break;
1770         }
1771         case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized:
1772         {
1773           aFilterL.SetRow (0, Graphic3d_Vec4 ( 1.062f, -0.205f,  0.299f, 0.0f));
1774           aFilterL.SetRow (1, Graphic3d_Vec4 (-0.026f,  0.908f,  0.068f, 0.0f));
1775           aFilterL.SetRow (2, Graphic3d_Vec4 (-0.038f, -0.173f,  0.022f, 0.0f));
1776           aFilterL.SetRow (3, Graphic3d_Vec4 ( 0.0f,    0.0f,    0.0f,   0.0f));
1777           aFilterR.SetRow (0, Graphic3d_Vec4 (-0.016f, -0.123f, -0.017f, 0.0f));
1778           aFilterR.SetRow (1, Graphic3d_Vec4 ( 0.006f,  0.062f, -0.017f, 0.0f));
1779           aFilterR.SetRow (2, Graphic3d_Vec4 ( 0.094f,  0.185f,  0.911f, 0.0f));
1780           aFilterR.SetRow (3, Graphic3d_Vec4 ( 0.0f,    0.0f,    0.0f,   0.0f));
1781           break;
1782         }
1783         case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple:
1784         {
1785           aFilterR.SetRow (0, Graphic3d_Vec4 (1.0f, 0.0f, 0.0f, 0.0f));
1786           aFilterL.SetRow (1, Graphic3d_Vec4 (0.0f, 1.0f, 0.0f, 0.0f));
1787           aFilterR.SetRow (2, Graphic3d_Vec4 (0.0f, 0.0f, 1.0f, 0.0f));
1788           break;
1789         }
1790         case Graphic3d_RenderingParams::Anaglyph_UserDefined:
1791         {
1792           aFilterL = myRenderParams.AnaglyphLeft;
1793           aFilterR = myRenderParams.AnaglyphRight;
1794           break;
1795         }
1796       }
1797       aCtx->ActiveProgram()->SetUniform (aCtx, "uMultL", aFilterL);
1798       aCtx->ActiveProgram()->SetUniform (aCtx, "uMultR", aFilterR);
1799     }
1800
1801     aPair[0]->ColorTexture()->Bind (aCtx, Graphic3d_TextureUnit_0);
1802     aPair[1]->ColorTexture()->Bind (aCtx, Graphic3d_TextureUnit_1);
1803     aVerts->BindVertexAttrib (aCtx, 0);
1804
1805     aCtx->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
1806
1807     aVerts->UnbindVertexAttrib (aCtx, 0);
1808     aPair[1]->ColorTexture()->Unbind (aCtx, Graphic3d_TextureUnit_1);
1809     aPair[0]->ColorTexture()->Unbind (aCtx, Graphic3d_TextureUnit_0);
1810   }
1811   else
1812   {
1813     TCollection_ExtendedString aMsg = TCollection_ExtendedString()
1814       + "Error! Anaglyph has failed";
1815     aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1816                        GL_DEBUG_TYPE_ERROR,
1817                        0,
1818                        GL_DEBUG_SEVERITY_HIGH,
1819                        aMsg);
1820   }
1821 }
1822
1823 // =======================================================================
1824 // function : copyBackToFront
1825 // purpose  :
1826 // =======================================================================
1827 bool OpenGl_View::copyBackToFront()
1828 {
1829   myIsImmediateDrawn = Standard_False;
1830 #if !defined(GL_ES_VERSION_2_0)
1831   const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
1832   if (aCtx->core11 == NULL)
1833   {
1834     return false;
1835   }
1836
1837   OpenGl_Mat4 aProjectMat;
1838   Graphic3d_TransformUtils::Ortho2D (aProjectMat,
1839                                      0.0f, static_cast<GLfloat> (myWindow->Width()),
1840                                      0.0f, static_cast<GLfloat> (myWindow->Height()));
1841
1842   aCtx->WorldViewState.Push();
1843   aCtx->ProjectionState.Push();
1844
1845   aCtx->WorldViewState.SetIdentity();
1846   aCtx->ProjectionState.SetCurrent (aProjectMat);
1847
1848   aCtx->ApplyProjectionMatrix();
1849   aCtx->ApplyWorldViewMatrix();
1850
1851   // synchronize FFP state before copying pixels
1852   aCtx->BindProgram (Handle(OpenGl_ShaderProgram)());
1853   aCtx->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
1854   aCtx->DisableFeatures();
1855
1856   switch (aCtx->DrawBuffer())
1857   {
1858     case GL_BACK_LEFT:
1859     {
1860       aCtx->SetReadBuffer (GL_BACK_LEFT);
1861       aCtx->SetDrawBuffer (GL_FRONT_LEFT);
1862       break;
1863     }
1864     case GL_BACK_RIGHT:
1865     {
1866       aCtx->SetReadBuffer (GL_BACK_RIGHT);
1867       aCtx->SetDrawBuffer (GL_FRONT_RIGHT);
1868       break;
1869     }
1870     default:
1871     {
1872       aCtx->SetReadBuffer (GL_BACK);
1873       aCtx->SetDrawBuffer (GL_FRONT);
1874       break;
1875     }
1876   }
1877
1878   aCtx->core11->glRasterPos2i (0, 0);
1879   aCtx->core11->glCopyPixels  (0, 0, myWindow->Width() + 1, myWindow->Height() + 1, GL_COLOR);
1880   //aCtx->core11->glCopyPixels  (0, 0, myWidth + 1, myHeight + 1, GL_DEPTH);
1881
1882   aCtx->EnableFeatures();
1883
1884   aCtx->WorldViewState.Pop();
1885   aCtx->ProjectionState.Pop();
1886   aCtx->ApplyProjectionMatrix();
1887
1888   // read/write from front buffer now
1889   aCtx->SetReadBuffer (aCtx->DrawBuffer());
1890   return true;
1891 #else
1892   return false;
1893 #endif
1894 }
1895
1896 // =======================================================================
1897 // function : checkOitCompatibility
1898 // purpose  :
1899 // =======================================================================
1900 Standard_Boolean OpenGl_View::checkOitCompatibility (const Handle(OpenGl_Context)& theGlContext,
1901                                                      const Standard_Boolean theMSAA)
1902 {
1903   // determine if OIT is supported by current OpenGl context
1904   Standard_Boolean& aToDisableOIT = theMSAA ? myToDisableMSAA : myToDisableOIT;
1905   if (aToDisableOIT)
1906   {
1907     return Standard_False;
1908   }
1909
1910   TCollection_ExtendedString aCompatibilityMsg;
1911   if (theGlContext->hasFloatBuffer     == OpenGl_FeatureNotAvailable
1912    && theGlContext->hasHalfFloatBuffer == OpenGl_FeatureNotAvailable)
1913   {
1914     aCompatibilityMsg += "OpenGL context does not support floating-point RGBA color buffer format.\n";
1915   }
1916   if (theMSAA && theGlContext->hasSampleVariables == OpenGl_FeatureNotAvailable)
1917   {
1918     aCompatibilityMsg += "Current version of GLSL does not support built-in sample variables.\n";
1919   }
1920   if (theGlContext->hasDrawBuffers == OpenGl_FeatureNotAvailable)
1921   {
1922     aCompatibilityMsg += "OpenGL context does not support multiple draw buffers.\n";
1923   }
1924   if (aCompatibilityMsg.IsEmpty())
1925   {
1926     return Standard_True;
1927   }
1928
1929   aCompatibilityMsg += "  Blended order-independent transparency will not be available.\n";
1930   theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1931                           GL_DEBUG_TYPE_ERROR,
1932                           0,
1933                           GL_DEBUG_SEVERITY_HIGH,
1934                           aCompatibilityMsg);
1935
1936   aToDisableOIT = Standard_True;
1937   return Standard_False;
1938 }
1939
1940 // =======================================================================
1941 // function : chooseOitColorConfiguration
1942 // purpose  :
1943 // =======================================================================
1944 bool OpenGl_View::chooseOitColorConfiguration (const Handle(OpenGl_Context)& theGlContext,
1945                                                const Standard_Integer theConfigIndex,
1946                                                OpenGl_ColorFormats& theFormats)
1947 {
1948   theFormats.Clear();
1949   switch (theConfigIndex)
1950   {
1951     case 0: // choose best applicable color format combination
1952     {
1953       theFormats.Append (theGlContext->hasHalfFloatBuffer != OpenGl_FeatureNotAvailable ? GL_RGBA16F : GL_RGBA32F);
1954       theFormats.Append (theGlContext->hasHalfFloatBuffer != OpenGl_FeatureNotAvailable ? GL_R16F    : GL_R32F);
1955       return true;
1956     }
1957     case 1: // choose non-optimal applicable color format combination
1958     {
1959       theFormats.Append (theGlContext->hasHalfFloatBuffer != OpenGl_FeatureNotAvailable ? GL_RGBA16F : GL_RGBA32F);
1960       theFormats.Append (theGlContext->hasHalfFloatBuffer != OpenGl_FeatureNotAvailable ? GL_RGBA16F : GL_RGBA32F);
1961       return true;
1962     }
1963   }
1964   return false; // color combination does not exist
1965 }
1966
1967 // =======================================================================
1968 // function : checkPBRAvailability
1969 // purpose  :
1970 // =======================================================================
1971 Standard_Boolean OpenGl_View::checkPBRAvailability() const
1972 {
1973   return myWorkspace->GetGlContext()->HasPBR()
1974       && !myPBREnvironment.IsNull();
1975 }
1976
1977 // =======================================================================
1978 // function : bakePBREnvironment
1979 // purpose  :
1980 // =======================================================================
1981 void OpenGl_View::bakePBREnvironment (const Handle(OpenGl_Context)& theCtx)
1982 {
1983   const Handle(OpenGl_TextureSet)& aTextureSet = myCubeMapParams->TextureSet (theCtx);
1984   if (!aTextureSet.IsNull()
1985    && !aTextureSet->IsEmpty())
1986   {
1987     myPBREnvironment->Bake (theCtx,
1988                             aTextureSet->First(),
1989                             myBackgroundCubeMap->ZIsInverted(),
1990                             myBackgroundCubeMap->IsTopDown(),
1991                             myRenderParams.PbrEnvBakingDiffNbSamples,
1992                             myRenderParams.PbrEnvBakingSpecNbSamples,
1993                             myRenderParams.PbrEnvBakingProbability);
1994   }
1995   else
1996   {
1997     myPBREnvironment->Clear (theCtx);
1998   }
1999 }
2000
2001 // =======================================================================
2002 // function : clearPBREnvironment
2003 // purpose  :
2004 // =======================================================================
2005 void OpenGl_View::clearPBREnvironment (const Handle(OpenGl_Context)& theCtx)
2006 {
2007   myPBREnvironment->Clear (theCtx);
2008 }
2009
2010 // =======================================================================
2011 // function : clearPBREnvironment
2012 // purpose  :
2013 // =======================================================================
2014 void OpenGl_View::processPBREnvRequest (const Handle(OpenGl_Context)& theCtx)
2015 {
2016   if (myPBREnvState == OpenGl_PBREnvState_CREATED)
2017   {
2018     switch (myPBREnvRequest)
2019     {
2020       case OpenGl_PBREnvRequest_NONE:  return;
2021       case OpenGl_PBREnvRequest_BAKE:  bakePBREnvironment  (theCtx); break;
2022       case OpenGl_PBREnvRequest_CLEAR: clearPBREnvironment (theCtx); break;
2023     }
2024   }
2025   myPBREnvRequest = OpenGl_PBREnvRequest_NONE;
2026 }