1 //
2 //   Copyright 2015 Pixar
3 //
4 //   Licensed under the Apache License, Version 2.0 (the "Apache License")
5 //   with the following modification; you may not use this file except in
6 //   compliance with the Apache License and the following modification to it:
7 //   Section 6. Trademarks. is deleted and replaced with:
8 //
9 //   6. Trademarks. This License does not grant permission to use the trade
10 //      names, trademarks, service marks, or product names of the Licensor
11 //      and its affiliates, except as required to comply with Section 4(c) of
12 //      the License and to reproduce the content of the NOTICE file.
13 //
14 //   You may obtain a copy of the Apache License at
15 //
16 //       http://www.apache.org/licenses/LICENSE-2.0
17 //
18 //   Unless required by applicable law or agreed to in writing, software
19 //   distributed under the Apache License with the above modification is
20 //   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 //   KIND, either express or implied. See the Apache License for the specific
22 //   language governing permissions and limitations under the Apache License.
23 //
24 
25 #include "glLoader.h"
26 
27 #include "sceneBase.h"
28 
29 #include "../../regression/common/far_utils.h"
30 
31 #include <opensubdiv/far/patchTableFactory.h>
32 #include <opensubdiv/far/stencilTableFactory.h>
33 
34 #include <limits>
35 
36 using namespace OpenSubdiv;
37 
38 
SceneBase(Options const & options)39 SceneBase::SceneBase(Options const &options)
40     : _options(options),
41       _indexBuffer(0), _patchParamTexture(0) {
42 }
43 
~SceneBase()44 SceneBase::~SceneBase() {
45     if (_indexBuffer) glDeleteBuffers(1, &_indexBuffer);
46     if (_patchParamTexture) glDeleteTextures(1, &_patchParamTexture);
47 
48     for (int i = 0; i < (int)_patchTables.size(); ++i) {
49         delete _patchTables[i];
50     }
51 }
52 
53 void
AddTopology(Shape const * shape,int level,bool varying)54 SceneBase::AddTopology(Shape const *shape, int level, bool varying) {
55     Far::PatchTable const * patchTable = NULL;
56     int numVerts = createStencilTable(shape, level, varying, &patchTable);
57 
58     // centering rest position
59     float pmin[3] = { std::numeric_limits<float>::max(),
60                       std::numeric_limits<float>::max(),
61                       std::numeric_limits<float>::max() };
62     float pmax[3] = { -std::numeric_limits<float>::max(),
63                       -std::numeric_limits<float>::max(),
64                       -std::numeric_limits<float>::max() };
65     int nverts = shape->GetNumVertices();
66     for (int i = 0; i < nverts; ++i) {
67         for (int j = 0; j < 3; ++j) {
68             float v = shape->verts[i*3+j];
69             pmin[j] = std::min(v, pmin[j]);
70             pmax[j] = std::max(v, pmax[j]);
71         }
72     }
73     float center[3] = { (pmax[0]+pmin[0])*0.5f,
74                         (pmax[1]+pmin[1])*0.5f,
75                         pmin[2] };
76     float radius = sqrt((pmax[0]-pmin[0])*(pmax[0]-pmin[0]) +
77                         (pmax[1]-pmin[1])*(pmax[1]-pmin[1]) +
78                         (pmax[2]-pmin[2])*(pmax[2]-pmin[2]));
79 
80     std::vector<float> restPosition(shape->verts);
81     for (size_t i=0; i < restPosition.size()/3; ++i) {
82         for (int j = 0; j < 3; ++j) {
83             restPosition[i*3+j] = (shape->verts[i*3+j] - center[j])/radius;
84         }
85     }
86 
87     // store topology
88     Topology topology;
89     topology.numVerts = numVerts;
90     topology.restPosition = restPosition;
91     _topologies.push_back(topology);
92 
93     // store patch.
94     // PatchTables is used later to be spliced into the index buffer.
95     _patchTables.push_back(patchTable);
96 }
97 
98 int
createStencilTable(Shape const * shape,int level,bool varying,OpenSubdiv::Far::PatchTable const ** patchTableOut)99 SceneBase::createStencilTable(Shape const *shape, int level, bool varying,
100                               OpenSubdiv::Far::PatchTable const **patchTableOut) {
101 
102     Far::TopologyRefiner * refiner = 0;
103     {
104         Sdc::SchemeType type = GetSdcType(*shape);
105         Sdc::Options options = GetSdcOptions(*shape);
106 
107         refiner = Far::TopologyRefinerFactory<Shape>::Create(
108             *shape, Far::TopologyRefinerFactory<Shape>::Options(type, options));
109         assert(refiner);
110     }
111 
112     // Adaptive refinement currently supported only for catmull-clark scheme
113 
114     if (_options.adaptive) {
115         Far::TopologyRefiner::AdaptiveOptions options(level);
116         refiner->RefineAdaptive(options);
117     } else {
118         Far::TopologyRefiner::UniformOptions options(level);
119         options.fullTopologyInLastLevel = true;
120         refiner->RefineUniform(options);
121     }
122 
123     Far::StencilTable const * vertexStencils=0, * varyingStencils=0;
124     {
125         Far::StencilTableFactory::Options options;
126         options.generateOffsets = true;
127         options.generateIntermediateLevels = _options.adaptive;
128 
129         vertexStencils = Far::StencilTableFactory::Create(*refiner, options);
130 
131         if (varying) {
132             varyingStencils = Far::StencilTableFactory::Create(*refiner, options);
133         }
134 
135         assert(vertexStencils);
136     }
137 
138     Far::PatchTable const * patchTable = NULL;
139     {
140         Far::PatchTableFactory::Options poptions(level);
141         if (_options.endCap == kEndCapBSplineBasis) {
142             poptions.SetEndCapType(
143                 Far::PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS);
144         } else {
145             poptions.SetEndCapType(
146                 Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS);
147         }
148         patchTable = Far::PatchTableFactory::Create(*refiner, poptions);
149     }
150     *patchTableOut = patchTable;
151 
152     // append local points to stencils
153     {
154         if (Far::StencilTable const *vertexStencilsWithLocalPoints =
155             Far::StencilTableFactory::AppendLocalPointStencilTable(
156                 *refiner,
157                 vertexStencils,
158                 patchTable->GetLocalPointStencilTable())) {
159             delete vertexStencils;
160             vertexStencils = vertexStencilsWithLocalPoints;
161         }
162         if (varyingStencils) {
163             if (Far::StencilTable const *varyingStencilsWithLocalPoints =
164                 Far::StencilTableFactory::AppendLocalPointStencilTable(
165                     *refiner,
166                     varyingStencils,
167                     patchTable->GetLocalPointVaryingStencilTable())) {
168                 delete varyingStencils;
169                 varyingStencils = varyingStencilsWithLocalPoints;
170             }
171         }
172     }
173     int numControlVertices = refiner->GetLevel(0).GetNumVertices();
174 
175     _stencilTableSize = createMeshRefiner(vertexStencils, varyingStencils,
176                                           numControlVertices);
177     // note: refiner takes ownership of vertexStencils, varyingStencils, patchTable
178 
179     delete refiner;
180     return numControlVertices + vertexStencils->GetNumStencils();
181 }
182 
183 int
AddObjects(int numObjects)184 SceneBase::AddObjects(int numObjects) {
185 
186     _objects.clear();
187 
188     int numTopologies = (int)_topologies.size();
189     int vertsOffset = 0;
190 
191     for (int i = 0; i < numObjects; ++i) {
192 
193         Object obj;
194         obj.topologyIndex = i % numTopologies;
195         obj.vertsOffset = vertsOffset;
196         _objects.push_back(obj);
197 
198         vertsOffset += _topologies[obj.topologyIndex].numVerts;
199     }
200 
201     // invalidate batch
202     for (int i = 0; i < (int)_batches.size(); ++i) {
203         glDeleteBuffers(1, &_batches[i].dispatchBuffer);
204     }
205     _batches.clear();
206 
207     return vertsOffset;
208 }
209 
210 size_t
CreateIndexBuffer()211 SceneBase::CreateIndexBuffer() {
212     if (_indexBuffer == 0) {
213         glGenBuffers(1, &_indexBuffer);
214     }
215 
216     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
217     std::vector<int> buffer;
218     std::vector<unsigned int> ppBuffer;
219 
220     int numTopologies = (int)_topologies.size();
221     for (int i = 0; i < numTopologies; ++i) {
222         Far::PatchTable const *patchTable = _patchTables[i];
223 
224         int nPatchArrays = patchTable->GetNumPatchArrays();
225 
226         _topologies[i].patchArrays.clear();
227 
228         // for each patchArray
229         for (int j = 0; j < nPatchArrays; ++j) {
230 
231             SceneBase::PatchArray patchArray;
232             patchArray.desc = patchTable->GetPatchArrayDescriptor(j);
233             patchArray.numPatches = patchTable->GetNumPatches(j);
234             patchArray.indexOffset = (int)buffer.size();
235             patchArray.primitiveIDOffset = (int)ppBuffer.size()/3;
236 
237             _topologies[i].patchArrays.push_back(patchArray);
238 
239             // indices
240             Far::ConstIndexArray indices = patchTable->GetPatchArrayVertices(j);
241             for (int k = 0; k < indices.size(); ++k) {
242                 buffer.push_back(indices[k]);
243             }
244 
245             // patchParams
246             Far::ConstPatchParamArray patchParams = patchTable->GetPatchParams(j);
247             // XXX: needs sharpness interface for patcharray or put sharpness into patchParam.
248             for (int k = 0; k < patchParams.size(); ++k) {
249                 float sharpness = 0.0;
250                 ppBuffer.push_back(patchParams[k].field0);
251                 ppBuffer.push_back(patchParams[k].field1);
252                 ppBuffer.push_back(*((unsigned int *)&sharpness));
253             }
254         }
255 #if 0
256         // XXX: we'll remove below APIs from Far::PatchTable.
257         //      use GetPatchParams(patchArray) instead as above.
258 
259         // patch param (all in one)
260         Far::PatchParamTable const &patchParamTable =
261             patchTable->GetPatchParamTable();
262         std::vector<int> const &sharpnessIndexTable =
263             patchTable->GetSharpnessIndexTable();
264         std::vector<float> const &sharpnessValues =
265             patchTable->GetSharpnessValues();
266 
267         int npatches = (int)patchParamTable.size();
268         for (int i = 0; i < npatches; ++i) {
269             float sharpness = 0.0;
270             if (i < (int)sharpnessIndexTable.size()) {
271                 sharpness = sharpnessIndexTable[i] >= 0 ?
272                     sharpnessValues[sharpnessIndexTable[i]] : 0.0f;
273             }
274             ppBuffer.push_back(patchParamTable[i].faceIndex);
275             ppBuffer.push_back(patchParamTable[i].bitField.field);
276             ppBuffer.push_back(*((unsigned int *)&sharpness));
277         }
278 #endif
279     }
280 
281     glBufferData(GL_ELEMENT_ARRAY_BUFFER,
282                  (int)buffer.size()*sizeof(int), &buffer[0], GL_STATIC_DRAW);
283 
284     // patchParam is currently expected to be texture (it can be SSBO)
285     GLuint texBuffer = 0;
286     glGenBuffers(1, &texBuffer);
287     glBindBuffer(GL_ARRAY_BUFFER, texBuffer);
288     glBufferData(GL_ARRAY_BUFFER, ppBuffer.size()*sizeof(unsigned int),
289                  &ppBuffer[0], GL_STATIC_DRAW);
290 
291     if (_patchParamTexture == 0) {
292         glGenTextures(1, &_patchParamTexture);
293     }
294     glBindTexture(GL_TEXTURE_BUFFER, _patchParamTexture);
295     glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32I, texBuffer);
296     glBindTexture(GL_TEXTURE_BUFFER, 0);
297 
298     glDeleteBuffers(1, &texBuffer);
299 
300     return buffer.size()*sizeof(int) + ppBuffer.size()*sizeof(int);
301 }
302 
303 void
buildBatches()304 SceneBase::buildBatches() {
305 
306     int numObjects = (int)_objects.size();
307     for (int i = 0; i < (int)_batches.size(); ++i) {
308         glDeleteBuffers(1, &_batches[i].dispatchBuffer);
309     }
310     _batches.clear();
311 
312     typedef std::map<Far::PatchDescriptor, std::vector<int> > StagingBatches;
313     StagingBatches stagingBatches;
314 
315     for (int i = 0; i < numObjects; ++i) {
316         // get patchArrays from topology
317         SceneBase::PatchArrayVector const &patchArrays =
318             _topologies[_objects[i].topologyIndex].patchArrays;
319 
320         // for each patchArray:
321         for (int j = 0; j < (int)patchArrays.size(); ++j) {
322             SceneBase::PatchArray const &patchArray = patchArrays[j];
323 
324             // find batch for the descriptor
325             std::vector<int> &command = stagingBatches[patchArray.desc];
326 
327             int nPatch = patchArray.numPatches;
328             int baseVertex = GetVertsOffset(i);
329 
330             command.push_back(nPatch * patchArray.desc.GetNumControlVertices());
331             command.push_back(1);
332             command.push_back(patchArray.indexOffset);
333             command.push_back(baseVertex);
334             command.push_back(0);
335 
336             command.push_back(patchArray.primitiveIDOffset);
337         }
338     }
339     int stride = sizeof(int)*6; // not 5, since we interleave primitiveIDOffset
340 
341     for (StagingBatches::iterator it = stagingBatches.begin();
342          it != stagingBatches.end(); ++it) {
343 
344         Batch batch;
345         glGenBuffers(1, &batch.dispatchBuffer);
346 
347         glBindBuffer(GL_DRAW_INDIRECT_BUFFER, batch.dispatchBuffer);
348         glBufferData(GL_DRAW_INDIRECT_BUFFER,
349                      it->second.size()*sizeof(int),
350                      &it->second[0], GL_STATIC_DRAW);
351 
352         batch.desc = it->first;
353         batch.count = (int)it->second.size()/6;
354         batch.stride = stride;
355 
356         _batches.push_back(batch);
357     }
358     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
359 }
360