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