1 //
2 // Copyright 2016 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 #include "pxr/imaging/garch/glApi.h"
25 
26 #include "pxr/imaging/hdSt/geometricShader.h"
27 
28 #include "pxr/imaging/hdSt/debugCodes.h"
29 #include "pxr/imaging/hdSt/shaderKey.h"
30 #include "pxr/imaging/hdSt/resourceBinder.h"
31 
32 #include "pxr/imaging/hd/binding.h"
33 #include "pxr/imaging/hd/perfLog.h"
34 #include "pxr/imaging/hd/renderPassState.h"
35 #include "pxr/imaging/hd/tokens.h"
36 
37 #include "pxr/imaging/hio/glslfx.h"
38 
39 #include <boost/functional/hash.hpp>
40 
41 #include <iostream>
42 #include <string>
43 
44 PXR_NAMESPACE_OPEN_SCOPE
45 
46 
HdSt_GeometricShader(std::string const & glslfxString,PrimitiveType primType,HdCullStyle cullStyle,bool useHardwareFaceCulling,bool hasMirroredTransform,bool doubleSided,HdPolygonMode polygonMode,bool cullingPass,FvarPatchType fvarPatchType,SdfPath const & debugId,float lineWidth)47 HdSt_GeometricShader::HdSt_GeometricShader(std::string const &glslfxString,
48                                        PrimitiveType primType,
49                                        HdCullStyle cullStyle,
50                                        bool useHardwareFaceCulling,
51                                        bool hasMirroredTransform,
52                                        bool doubleSided,
53                                        HdPolygonMode polygonMode,
54                                        bool cullingPass,
55                                        FvarPatchType fvarPatchType,
56                                        SdfPath const &debugId,
57                                        float lineWidth)
58     : HdStShaderCode()
59     , _primType(primType)
60     , _cullStyle(cullStyle)
61     , _useHardwareFaceCulling(useHardwareFaceCulling)
62     , _hasMirroredTransform(hasMirroredTransform)
63     , _doubleSided(doubleSided)
64     , _polygonMode(polygonMode)
65     , _lineWidth(lineWidth)
66     , _frustumCullingPass(cullingPass)
67     , _fvarPatchType(fvarPatchType)
68     , _hash(0)
69 {
70     HD_TRACE_FUNCTION();
71     HF_MALLOC_TAG_FUNCTION();
72 
73     // XXX
74     // we will likely move this (the constructor or the entire class) into
75     // the base class (HdStShaderCode) at the end of refactoring, to be able to
76     // use same machinery other than geometric shaders.
77 
78     if (TfDebug::IsEnabled(HDST_DUMP_GLSLFX_CONFIG)) {
79         std::cout << debugId << "\n"
80                   << glslfxString << "\n";
81     }
82 
83     std::stringstream ss(glslfxString);
84     _glslfx.reset(new HioGlslfx(ss));
85     boost::hash_combine(_hash, _glslfx->GetHash());
86     boost::hash_combine(_hash, cullingPass);
87     boost::hash_combine(_hash, primType);
88     boost::hash_combine(_hash, fvarPatchType);
89     //
90     // note: Don't include cullStyle and polygonMode into the hash.
91     //      They are independent from the GLSL program.
92     //
93 }
94 
~HdSt_GeometricShader()95 HdSt_GeometricShader::~HdSt_GeometricShader()
96 {
97     // nothing
98 }
99 
100 /* virtual */
101 HdStShaderCode::ID
ComputeHash() const102 HdSt_GeometricShader::ComputeHash() const
103 {
104     return _hash;
105 }
106 
107 /* virtual */
108 std::string
GetSource(TfToken const & shaderStageKey) const109 HdSt_GeometricShader::GetSource(TfToken const &shaderStageKey) const
110 {
111     return _glslfx->GetSource(shaderStageKey);
112 }
113 
114 void
BindResources(const int program,HdSt_ResourceBinder const & binder,HdRenderPassState const & state)115 HdSt_GeometricShader::BindResources(const int program,
116                                     HdSt_ResourceBinder const &binder,
117                                     HdRenderPassState const &state)
118 {
119     if (_useHardwareFaceCulling) {
120         switch (_cullStyle) {
121             case HdCullStyleFront:
122                 glEnable(GL_CULL_FACE);
123                 if (_hasMirroredTransform) {
124                     glCullFace(GL_BACK);
125                 } else {
126                     glCullFace(GL_FRONT);
127                 }
128                 break;
129             case HdCullStyleFrontUnlessDoubleSided:
130                 if (!_doubleSided) {
131                     glEnable(GL_CULL_FACE);
132                     if (_hasMirroredTransform) {
133                         glCullFace(GL_BACK);
134                     } else {
135                         glCullFace(GL_FRONT);
136                     }
137                 }
138                 break;
139             case HdCullStyleBack:
140                 glEnable(GL_CULL_FACE);
141                 if (_hasMirroredTransform) {
142                     glCullFace(GL_FRONT);
143                 } else {
144                     glCullFace(GL_BACK);
145                 }
146                 break;
147             case HdCullStyleBackUnlessDoubleSided:
148                 if (!_doubleSided) {
149                     glEnable(GL_CULL_FACE);
150                     if (_hasMirroredTransform) {
151                         glCullFace(GL_FRONT);
152                     } else {
153                         glCullFace(GL_BACK);
154                     }
155                 }
156                 break;
157             case HdCullStyleNothing:
158                 glDisable(GL_CULL_FACE);
159                 break;
160             case HdCullStyleDontCare:
161             default:
162                 // Fallback to the renderPass opinion, but account for
163                 // combinations of parameters that require extra handling
164                 HdCullStyle cullstyle = state.GetCullStyle();
165                 if (_doubleSided &&
166                    (cullstyle == HdCullStyleBackUnlessDoubleSided ||
167                     cullstyle == HdCullStyleFrontUnlessDoubleSided)) {
168                     glDisable(GL_CULL_FACE);
169                 } else if (_hasMirroredTransform &&
170                     (cullstyle == HdCullStyleBack ||
171                      cullstyle == HdCullStyleBackUnlessDoubleSided)) {
172                     glEnable(GL_CULL_FACE);
173                     glCullFace(GL_FRONT);
174                 } else if (_hasMirroredTransform &&
175                     (cullstyle == HdCullStyleFront ||
176                      cullstyle == HdCullStyleFrontUnlessDoubleSided)) {
177                     glEnable(GL_CULL_FACE);
178                     glCullFace(GL_BACK);
179                 }
180                 break;
181         }
182     } else {
183         // Use fragment shader culling via discard.
184         glDisable(GL_CULL_FACE);
185 
186         if (_cullStyle != HdCullStyleDontCare) {
187             unsigned int cullStyle = _cullStyle;
188             binder.BindUniformui(HdShaderTokens->cullStyle, 1, &cullStyle);
189         } else {
190             // don't care -- use renderPass's fallback
191         }
192     }
193 
194     if (GetPrimitiveMode() == GL_PATCHES) {
195         glPatchParameteri(GL_PATCH_VERTICES, GetPrimitiveIndexSize());
196     }
197 
198     if (_polygonMode == HdPolygonModeLine) {
199         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
200         if (_lineWidth > 0) {
201             glLineWidth(_lineWidth);
202         }
203     }
204 }
205 
206 void
UnbindResources(const int program,HdSt_ResourceBinder const & binder,HdRenderPassState const & state)207 HdSt_GeometricShader::UnbindResources(const int program,
208                                       HdSt_ResourceBinder const &binder,
209                                       HdRenderPassState const &state)
210 {
211     if (_polygonMode == HdPolygonModeLine) {
212         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
213     }
214 
215     // Restore renderPass culling opinions
216     HdCullStyle cullstyle = state.GetCullStyle();
217     switch (cullstyle) {
218         case HdCullStyleFront:
219         case HdCullStyleFrontUnlessDoubleSided:
220             glEnable(GL_CULL_FACE);
221             glCullFace(GL_FRONT);
222             break;
223         case HdCullStyleBack:
224         case HdCullStyleBackUnlessDoubleSided:
225             glEnable(GL_CULL_FACE);
226             glCullFace(GL_BACK);
227             break;
228         case HdCullStyleNothing:
229         case HdCullStyleDontCare:
230         default:
231             glDisable(GL_CULL_FACE);
232             break;
233     }
234 }
235 
236 /*virtual*/
237 void
AddBindings(HdBindingRequestVector * customBindings)238 HdSt_GeometricShader::AddBindings(HdBindingRequestVector *customBindings)
239 {
240     // no-op
241 }
242 
243 GLenum
GetPrimitiveMode() const244 HdSt_GeometricShader::GetPrimitiveMode() const
245 {
246     GLenum primMode = GL_POINTS;
247 
248     switch (_primType)
249     {
250         case PrimitiveType::PRIM_POINTS:
251             primMode = GL_POINTS;
252             break;
253         case PrimitiveType::PRIM_BASIS_CURVES_LINES:
254             primMode = GL_LINES;
255             break;
256         case PrimitiveType::PRIM_MESH_COARSE_TRIANGLES:
257         case PrimitiveType::PRIM_MESH_REFINED_TRIANGLES:
258         case PrimitiveType::PRIM_VOLUME:
259             primMode = GL_TRIANGLES;
260             break;
261         case PrimitiveType::PRIM_MESH_COARSE_QUADS:
262         case PrimitiveType::PRIM_MESH_REFINED_QUADS:
263             primMode = GL_LINES_ADJACENCY;
264             break;
265         case PrimitiveType::PRIM_BASIS_CURVES_CUBIC_PATCHES:
266         case PrimitiveType::PRIM_BASIS_CURVES_LINEAR_PATCHES:
267         case PrimitiveType::PRIM_MESH_BSPLINE:
268         case PrimitiveType::PRIM_MESH_BOXSPLINETRIANGLE:
269             primMode = GL_PATCHES;
270             break;
271     }
272 
273     return primMode;
274 }
275 
276 int
GetPrimitiveIndexSize() const277 HdSt_GeometricShader::GetPrimitiveIndexSize() const
278 {
279     int primIndexSize = 1;
280 
281     switch (_primType)
282     {
283         case PrimitiveType::PRIM_POINTS:
284             primIndexSize = 1;
285             break;
286         case PrimitiveType::PRIM_BASIS_CURVES_LINES:
287         case PrimitiveType::PRIM_BASIS_CURVES_LINEAR_PATCHES:
288             primIndexSize = 2;
289             break;
290         case PrimitiveType::PRIM_MESH_COARSE_TRIANGLES:
291         case PrimitiveType::PRIM_MESH_REFINED_TRIANGLES:
292         case PrimitiveType::PRIM_VOLUME:
293             primIndexSize = 3;
294             break;
295         case PrimitiveType::PRIM_BASIS_CURVES_CUBIC_PATCHES:
296         case PrimitiveType::PRIM_MESH_COARSE_QUADS:
297         case PrimitiveType::PRIM_MESH_REFINED_QUADS:
298             primIndexSize = 4;
299             break;
300         case PrimitiveType::PRIM_MESH_BSPLINE:
301             primIndexSize = 16;
302             break;
303         case PrimitiveType::PRIM_MESH_BOXSPLINETRIANGLE:
304             primIndexSize = 12;
305             break;
306     }
307 
308     return primIndexSize;
309 }
310 
311 int
GetNumPatchEvalVerts() const312 HdSt_GeometricShader::GetNumPatchEvalVerts() const
313 {
314     int numPatchEvalVerts = 0;
315 
316     switch (_primType)
317     {
318         case PrimitiveType::PRIM_BASIS_CURVES_LINEAR_PATCHES:
319             numPatchEvalVerts = 2;
320             break;
321         case PrimitiveType::PRIM_BASIS_CURVES_CUBIC_PATCHES:
322             numPatchEvalVerts = 4;
323             break;
324         case PrimitiveType::PRIM_MESH_BSPLINE:
325             numPatchEvalVerts = 16;
326             break;
327         case PrimitiveType::PRIM_MESH_BOXSPLINETRIANGLE:
328             numPatchEvalVerts = 15;
329             break;
330         default:
331             numPatchEvalVerts = 0;
332             break;
333     }
334 
335     return numPatchEvalVerts;
336 }
337 
338 int
GetNumPrimitiveVertsForGeometryShader() const339 HdSt_GeometricShader::GetNumPrimitiveVertsForGeometryShader() const
340 {
341     int numPrimVerts = 1;
342 
343     switch (_primType)
344     {
345         case PrimitiveType::PRIM_POINTS:
346             numPrimVerts = 1;
347             break;
348         case PrimitiveType::PRIM_BASIS_CURVES_LINES:
349             numPrimVerts = 2;
350             break;
351         case PrimitiveType::PRIM_MESH_COARSE_TRIANGLES:
352         case PrimitiveType::PRIM_MESH_REFINED_TRIANGLES:
353         case PrimitiveType::PRIM_BASIS_CURVES_LINEAR_PATCHES:
354         case PrimitiveType::PRIM_BASIS_CURVES_CUBIC_PATCHES:
355         case PrimitiveType::PRIM_MESH_BSPLINE:
356         case PrimitiveType::PRIM_MESH_BOXSPLINETRIANGLE:
357         // for patches with tesselation, input to GS is still a series of tris
358         case PrimitiveType::PRIM_VOLUME:
359             numPrimVerts = 3;
360             break;
361         case PrimitiveType::PRIM_MESH_COARSE_QUADS:
362         case PrimitiveType::PRIM_MESH_REFINED_QUADS:
363             numPrimVerts = 4;
364             break;
365     }
366 
367     return numPrimVerts;
368 }
369 
370 /*static*/
371  HdSt_GeometricShaderSharedPtr
Create(HdSt_ShaderKey const & shaderKey,HdStResourceRegistrySharedPtr const & resourceRegistry)372  HdSt_GeometricShader::Create(
373     HdSt_ShaderKey const &shaderKey,
374     HdStResourceRegistrySharedPtr const &resourceRegistry)
375 {
376     // Use the shaderKey hash to deduplicate geometric shaders.
377     HdInstance<HdSt_GeometricShaderSharedPtr> geometricShaderInstance =
378         resourceRegistry->RegisterGeometricShader(shaderKey.ComputeHash());
379 
380     if (geometricShaderInstance.IsFirstInstance()) {
381         geometricShaderInstance.SetValue(
382             std::make_shared<HdSt_GeometricShader>(
383                 shaderKey.GetGlslfxString(),
384                 shaderKey.GetPrimitiveType(),
385                 shaderKey.GetCullStyle(),
386                 shaderKey.UseHardwareFaceCulling(),
387                 shaderKey.HasMirroredTransform(),
388                 shaderKey.IsDoubleSided(),
389                 shaderKey.GetPolygonMode(),
390                 shaderKey.IsFrustumCullingPass(),
391                 shaderKey.GetFvarPatchType(),
392                 /*debugId=*/SdfPath(),
393                 shaderKey.GetLineWidth()));
394     }
395     return geometricShaderInstance.GetValue();
396 }
397 
398 PXR_NAMESPACE_CLOSE_SCOPE
399 
400