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