0027607: Visualization - Implement adaptive screen space sampling in path tracing
[occt.git] / src / OpenGl / OpenGl_TileSampler.cxx
CommitLineData
3a9b5dc8 1// Created on: 2016-06-16
2// Created by: Denis BOGOLEPOV & Danila ULYANOV
3// Copyright (c) 2016 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 <OpenGl_Context.hxx>
17#include <OpenGl_TileSampler.hxx>
18#include <TCollection_ExtendedString.hxx>
19
20namespace
21{
22 //! Scale factor for estimating visual error.
23 static const float THE_SCALE_FACTOR = 1.0f / 1e6f;
24}
25
26//=======================================================================
27//function : OpenGl_TileSampler
28//purpose :
29//=======================================================================
30OpenGl_TileSampler::OpenGl_TileSampler()
31: mySample (0),
32 mySizeX (0),
33 mySizeY (0),
34 myTilesX (0),
35 myTilesY (0)
36{
37 mySampler.initFaure();
38}
39
40//=======================================================================
41//function : GrabVarianceMap
42//purpose :
43//=======================================================================
44void OpenGl_TileSampler::GrabVarianceMap (const Handle(OpenGl_Context)& theContext)
45{
46#if !defined(GL_ES_VERSION_2_0)
47 std::vector<GLint> aRawData (NbTiles(), 0);
48
49 theContext->core11fwd->glGetTexImage (GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_INT, &aRawData.front());
50 const GLenum anErr = theContext->core11fwd->glGetError();
51 if (anErr != GL_NO_ERROR)
52 {
53 theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
54 "Error! Failed to fetch visual error map from the GPU");
55 }
56 else
57 {
58 for (int aTileIdx = 0, aNbTiles = NbTiles(); aTileIdx < aNbTiles; ++aTileIdx)
59 {
60 myVarianceMap[aTileIdx] = aRawData[aTileIdx] * THE_SCALE_FACTOR;
61 }
62
63 for (int aX = 0; aX < myTilesX; ++aX)
64 {
65 for (int aY = 0; aY < myTilesY; ++aY)
66 {
67 ChangeTile (aX, aY) *= 1.0f / TileArea (aX, aY); // average error over the tile
68
69 if (aY > 0)
70 {
71 ChangeTile (aX, aY) += Tile (aX, aY - 1);
72 }
73 }
74 }
75
76 myMarginalMap.resize (myTilesX); // build marginal distribution
77 for (int aX = 0; aX < myTilesX; ++aX)
78 {
79 myMarginalMap[aX] = Tile (aX, myTilesY - 1);
80
81 if (aX > 0)
82 myMarginalMap[aX] += myMarginalMap[aX - 1];
83 }
84 }
85#else
86 // glGetTexImage() is unavailable on OpenGL ES, FBO + glReadPixels() can be used instead
87 (void )theContext;
88#endif
89}
90
91//=======================================================================
92//function : Sample
93//purpose :
94//=======================================================================
95void OpenGl_TileSampler::Sample (int& theOffsetX,
96 int& theOffsetY)
97{
98 int aX = 0;
99 int aY = 0;
100
101 const float aKsiX = mySampler.sample (0, mySample) * myMarginalMap.back();
102 for (; aX < myTilesX - 1; ++aX)
103 {
104 if (aKsiX <= myMarginalMap[aX])
105 {
106 break;
107 }
108 }
109
110 const float aKsiY = mySampler.sample (1, mySample) * Tile (aX, myTilesY - 1);
111 for (; aY < myTilesY - 1; ++aY)
112 {
113 if (aKsiY <= Tile (aX, aY))
114 {
115 break;
116 }
117 }
118
119 theOffsetX = aX * TileSize();
120 theOffsetY = aY * TileSize();
121
122 ++mySample;
123}
124
125//=======================================================================
126//function : SetSize
127//purpose :
128//=======================================================================
129void OpenGl_TileSampler::SetSize (const int theSizeX,
130 const int theSizeY)
131{
132 if (mySizeX == theSizeX
133 && mySizeY == theSizeY)
134 {
135 return;
136 }
137
138 mySizeX = theSizeX;
139 mySizeY = theSizeY;
140
141 myTilesX = static_cast<int> (ceilf (static_cast<float> (mySizeX) / TileSize()));
142 myTilesY = static_cast<int> (ceilf (static_cast<float> (mySizeY) / TileSize()));
143
144 myVarianceMap.resize (myTilesX * myTilesY);
145}
146
147//=======================================================================
148//function : Upload
149//purpose :
150//=======================================================================
151void OpenGl_TileSampler::Upload (const Handle(OpenGl_Context)& theContext,
152 const Handle(OpenGl_Texture)& theTexture,
153 bool theAdaptive)
154{
155 if (theTexture.IsNull())
156 {
157 return;
158 }
159
160 std::vector<GLint> aData (myTilesX * myTilesY * 2);
161 for (int aX = 0; aX < myTilesX; ++aX)
162 {
163 for (int aY = 0; aY < myTilesY; ++aY)
164 {
165 if (!theAdaptive)
166 {
167 aData[(aY * myTilesX + aX) * 2 + 0] = aX * TileSize();
168 aData[(aY * myTilesX + aX) * 2 + 1] = aY * TileSize();
169 }
170 else
171 {
172 Sample (aData[(aY * myTilesX + aX) * 2 + 0],
173 aData[(aY * myTilesX + aX) * 2 + 1]);
174 }
175 }
176 }
177
178 theTexture->Bind (theContext);
179
180 theContext->core11fwd->glTexImage2D (GL_TEXTURE_2D, 0, GL_RG32I, myTilesX, myTilesY, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, &aData.front());
181 const GLenum anErr = theContext->core11fwd->glGetError();
182 if (anErr != GL_NO_ERROR)
183 {
184 theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
185 "Error! Failed to upload tile offset map on the GPU");
186 }
187}