1 // Created on: 2016-06-16
2 // Created by: Denis BOGOLEPOV & Danila ULYANOV
3 // Copyright (c) 2016 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <OpenGl_Context.hxx>
17 #include <OpenGl_TileSampler.hxx>
18 #include <Graphic3d_RenderingParams.hxx>
19 #include <TCollection_ExtendedString.hxx>
21 //=======================================================================
22 //function : OpenGl_TileSampler
24 //=======================================================================
25 OpenGl_TileSampler::OpenGl_TileSampler()
31 mySampler.initFaure();
34 //=======================================================================
35 //function : GrabVarianceMap
37 //=======================================================================
38 void OpenGl_TileSampler::GrabVarianceMap (const Handle(OpenGl_Context)& theContext,
39 const Handle(OpenGl_Texture)& theTexture)
41 if (theTexture.IsNull())
46 myVarianceRaw.Init (0);
47 #if !defined(GL_ES_VERSION_2_0)
48 theTexture->Bind (theContext);
49 theContext->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, 1);
50 theContext->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
51 theContext->core11fwd->glGetTexImage (GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_INT, myVarianceRaw.ChangeData());
52 const GLenum anErr = theContext->core11fwd->glGetError();
53 theTexture->Unbind (theContext);
54 if (anErr != GL_NO_ERROR)
56 theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
57 "Error! Failed to fetch visual error map from the GPU");
61 // glGetTexImage() is unavailable on OpenGL ES, FBO + glReadPixels() can be used instead
65 const float aFactor = 1.0f / myScaleFactor;
66 for (Standard_Size aColIter = 0; aColIter < myVarianceMap.SizeX; ++aColIter)
68 for (Standard_Size aRowIter = 0; aRowIter < myVarianceMap.SizeY; ++aRowIter)
70 const int aRawValue = myVarianceRaw.Value (aRowIter, aColIter);
71 float& aTile = myVarianceMap.ChangeValue (aRowIter, aColIter);
72 aTile = aFactor * float(aRawValue);
73 aTile *= 1.0f / tileArea ((int )aColIter, (int )aRowIter); // average error over the tile
76 aTile += myVarianceMap.Value (aRowIter - 1, aColIter);
81 // build marginal distribution
82 for (Standard_Size aX = 0; aX < myVarianceMap.SizeX; ++aX)
84 myMarginalMap[aX] = myVarianceMap.Value (myVarianceMap.SizeY - 1, aX);
87 myMarginalMap[aX] += myMarginalMap[aX - 1];
92 //=======================================================================
93 //function : nextTileToSample
95 //=======================================================================
96 Graphic3d_Vec2i OpenGl_TileSampler::nextTileToSample()
98 Graphic3d_Vec2i aTile (0, 0);
99 const float aKsiX = mySampler.sample (0, myLastSample) * myMarginalMap.back();
100 for (; (size_t )aTile.x() < myMarginalMap.size() - 1; ++aTile.x())
102 if (aKsiX <= myMarginalMap[aTile.x()])
108 const float aKsiY = mySampler.sample (1, myLastSample) * myVarianceMap.Value (myVarianceMap.SizeY - 1, aTile.x());
109 for (; (size_t )aTile.y() < myVarianceMap.SizeY - 1; ++aTile.y())
111 if (aKsiY <= myVarianceMap.Value (aTile.y(), aTile.x()))
121 //=======================================================================
124 //=======================================================================
125 void OpenGl_TileSampler::SetSize (const Graphic3d_RenderingParams& theParams,
126 const Graphic3d_Vec2i& theSize)
134 myViewSize = theSize;
136 const int aTileSize = Max (theParams.RayTracingTileSize, 1);
137 const int aNbTilesX = Max (1, static_cast<int> (ceilf (static_cast<float> (theSize.x()) / aTileSize)));
138 const int aNbTilesY = Max (1, static_cast<int> (ceilf (static_cast<float> (theSize.y()) / aTileSize)));
139 if (myTileSize != aTileSize
140 || (int )myTiles.SizeX != aNbTilesX
141 || (int )myTiles.SizeY != aNbTilesY)
143 myTileSize = aTileSize;
144 myScaleFactor = 1.0e6f * (1024.0f / float(myTileSize * myTileSize));
146 Handle(NCollection_BaseAllocator) anAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
147 myTiles.SetTopDown (true);
148 myTiles.Init (anAlloc, aNbTilesX, aNbTilesY);
151 myVarianceMap.SetTopDown (true);
152 myVarianceMap.Init (myTiles.Allocator(), myTiles.SizeX, myTiles.SizeY);
153 myVarianceMap.Init (0.0f);
155 myVarianceRaw.SetTopDown (true);
156 myVarianceRaw.Init (myTiles.Allocator(), myTiles.SizeX, myTiles.SizeY);
157 myVarianceRaw.Init (0);
159 myOffsets.SetTopDown (true);
160 myOffsets.Init (myTiles.Allocator(), myTiles.SizeX, myTiles.SizeY);
161 myOffsets.Init (Graphic3d_Vec2i (-1, -1));
163 myMarginalMap.resize (myTiles.SizeX);
164 myMarginalMap.assign (myMarginalMap.size(), 0.0f);
167 // calculate a size of compact offsets texture optimal for rendering reduced number of tiles
168 Standard_Integer aNbShunkTilesX = (int )myTiles.SizeX, aNbShunkTilesY = (int )myTiles.SizeY;
169 if (theParams.NbRayTracingTiles > 0)
173 for (Standard_Integer anIdx = 0; aNbShunkTilesX * aNbShunkTilesY < theParams.NbRayTracingTiles; ++anIdx)
175 (anIdx % 2 == 0 ? aNbShunkTilesX : aNbShunkTilesY) <<= 1;
178 if ((int )myOffsetsShrunk.SizeX != aNbShunkTilesX
179 || (int )myOffsetsShrunk.SizeY != aNbShunkTilesY)
181 myOffsetsShrunk.SetTopDown (true);
182 myOffsetsShrunk.Init (myTiles.Allocator(), aNbShunkTilesX, aNbShunkTilesY);
183 myOffsetsShrunk.Init (Graphic3d_Vec2i (-1, -1));
187 //=======================================================================
188 //function : UploadOffsets
190 //=======================================================================
191 bool OpenGl_TileSampler::UploadOffsets (const Handle(OpenGl_Context)& theContext,
192 const Handle(OpenGl_Texture)& theOffsetsTexture,
193 const bool theAdaptive)
195 if (myTiles.IsEmpty())
201 Image_PixMapTypedData<Graphic3d_Vec2i>& anOffsets = theAdaptive ? myOffsetsShrunk : myOffsets;
202 anOffsets.Init (Graphic3d_Vec2i (-1, -1));
203 for (Standard_Size aRowIter = 0; aRowIter < anOffsets.SizeY; ++aRowIter)
205 for (Standard_Size aColIter = 0; aColIter < anOffsets.SizeX; ++aColIter)
207 Graphic3d_Vec2i& aRedirectTile = anOffsets.ChangeValue (aRowIter, aColIter);
208 aRedirectTile = theAdaptive ? nextTileToSample() : Graphic3d_Vec2i ((int )aColIter, (int )aRowIter);
209 myTiles.ChangeValue (aRedirectTile.y(), aRedirectTile.x()) += 1;
213 bool hasErrors = false;
214 if (!theOffsetsTexture.IsNull())
216 if (theOffsetsTexture->SizeX() != (int )anOffsets.SizeX
217 || theOffsetsTexture->SizeY() != (int )anOffsets.SizeY
218 || !theOffsetsTexture->IsValid())
220 theOffsetsTexture->Release (theContext.operator->());
221 if (!theOffsetsTexture->Init (theContext, GL_RG32I, GL_RG_INTEGER, GL_INT,
222 (int )anOffsets.SizeX, (int )anOffsets.SizeY, Graphic3d_TOT_2D))
227 if (theOffsetsTexture->IsValid())
229 theOffsetsTexture->Bind (theContext);
230 theContext->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
231 #if !defined(GL_ES_VERSION_2_0)
232 theContext->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
234 theContext->core11fwd->glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, (int )anOffsets.SizeX, (int )anOffsets.SizeY, GL_RG_INTEGER, GL_INT, anOffsets.Data());
235 if (theContext->core11fwd->glGetError() != GL_NO_ERROR)
238 theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
239 "Error! Failed to upload tile offset map on the GPU");
241 theOffsetsTexture->Unbind (theContext);