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/glf/contextCaps.h"
25 #include "pxr/imaging/glf/simpleShadowArray.h"
26
27 #include "pxr/imaging/hdSt/codeGen.h"
28 #include "pxr/imaging/hdSt/geometricShader.h"
29 #include "pxr/imaging/hdSt/glConversions.h"
30 #include "pxr/imaging/hdSt/glslProgram.h"
31 #include "pxr/imaging/hdSt/package.h"
32 #include "pxr/imaging/hdSt/resourceBinder.h"
33 #include "pxr/imaging/hdSt/shaderCode.h"
34 #include "pxr/imaging/hdSt/tokens.h"
35
36 #include "pxr/imaging/hd/binding.h"
37 #include "pxr/imaging/hd/instanceRegistry.h"
38 #include "pxr/imaging/hd/resourceRegistry.h"
39 #include "pxr/imaging/hd/tokens.h"
40 #include "pxr/imaging/hd/vtBufferSource.h"
41
42 #include "pxr/imaging/hio/glslfx.h"
43
44 #include "pxr/base/tf/iterator.h"
45 #include "pxr/base/tf/staticTokens.h"
46
47 #include <boost/functional/hash.hpp>
48
49 #include <sstream>
50
51 #include <opensubdiv/osd/glslPatchShaderSource.h>
52
53 PXR_NAMESPACE_OPEN_SCOPE
54
55
56 TF_DEFINE_PRIVATE_TOKENS(
57 _tokens,
58 ((_double, "double"))
59 ((_float, "float"))
60 ((_int, "int"))
61 ((_uint, "uint"))
62 (hd_vec3)
63 (hd_vec3_get)
64 (hd_vec3_set)
65 (hd_ivec3)
66 (hd_ivec3_get)
67 (hd_ivec3_set)
68 (hd_dvec3)
69 (hd_dvec3_get)
70 (hd_dvec3_set)
71 (hd_mat3)
72 (hd_mat3_get)
73 (hd_mat3_set)
74 (hd_dmat3)
75 (hd_dmat3_get)
76 (hd_dmat3_set)
77 (hd_vec4_2_10_10_10_get)
78 (hd_vec4_2_10_10_10_set)
79 (hd_half2_get)
80 (hd_half2_set)
81 (hd_half4_get)
82 (hd_half4_set)
83 (inPrimvars)
84 (uvec2)
85 (uvec3)
86 (uvec4)
87 (ivec2)
88 (ivec3)
89 (ivec4)
90 (outPrimvars)
91 (vec2)
92 (vec3)
93 (vec4)
94 (dvec2)
95 (dvec3)
96 (dvec4)
97 (mat3)
98 (mat4)
99 (dmat3)
100 (dmat4)
101 (packed_2_10_10_10)
102 (packed_half2)
103 (packed_half4)
104 ((ptexTextureSampler, "ptexTextureSampler"))
105 (isamplerBuffer)
106 (samplerBuffer)
107 );
108
HdSt_CodeGen(HdSt_GeometricShaderPtr const & geometricShader,HdStShaderCodeSharedPtrVector const & shaders,TfToken const & materialTag)109 HdSt_CodeGen::HdSt_CodeGen(HdSt_GeometricShaderPtr const &geometricShader,
110 HdStShaderCodeSharedPtrVector const &shaders,
111 TfToken const &materialTag)
112 : _geometricShader(geometricShader), _shaders(shaders),
113 _materialTag(materialTag)
114 {
115 TF_VERIFY(geometricShader);
116 }
117
HdSt_CodeGen(HdStShaderCodeSharedPtrVector const & shaders)118 HdSt_CodeGen::HdSt_CodeGen(HdStShaderCodeSharedPtrVector const &shaders)
119 : _geometricShader(), _shaders(shaders)
120 {
121 }
122
123 HdSt_CodeGen::ID
ComputeHash() const124 HdSt_CodeGen::ComputeHash() const
125 {
126 HD_TRACE_FUNCTION();
127 HF_MALLOC_TAG_FUNCTION();
128
129 ID hash = _geometricShader ? _geometricShader->ComputeHash() : 0;
130 boost::hash_combine(hash, _metaData.ComputeHash());
131 boost::hash_combine(hash, HdStShaderCode::ComputeHash(_shaders));
132 boost::hash_combine(hash, _materialTag.Hash());
133
134 return hash;
135 }
136
137 static
138 std::string
_GetPtexTextureShaderSource()139 _GetPtexTextureShaderSource()
140 {
141 static std::string source =
142 HioGlslfx(HdStPackagePtexTextureShader()).GetSource(
143 _tokens->ptexTextureSampler);
144 return source;
145 }
146
147 // TODO: Shuffle code to remove these declarations.
148 static void _EmitDeclaration(std::stringstream &str,
149 TfToken const &name,
150 TfToken const &type,
151 HdBinding const &binding,
152 int arraySize=0);
153
154 static void _EmitStructAccessor(std::stringstream &str,
155 TfToken const &structName,
156 TfToken const &name,
157 TfToken const &type,
158 int arraySize,
159 const char *index);
160
161 static void _EmitComputeAccessor(std::stringstream &str,
162 TfToken const &name,
163 TfToken const &type,
164 HdBinding const &binding,
165 const char *index);
166
167 static void _EmitComputeMutator(std::stringstream &str,
168 TfToken const &name,
169 TfToken const &type,
170 HdBinding const &binding,
171 const char *index);
172
173 static void _EmitAccessor(std::stringstream &str,
174 TfToken const &name,
175 TfToken const &type,
176 HdBinding const &binding,
177 const char *index=NULL);
178 /*
179 1. If the member is a scalar consuming N basic machine units,
180 the base alignment is N.
181 2. If the member is a two- or four-component vector with components
182 consuming N basic machine units, the base alignment is 2N or 4N,
183 respectively.
184 3. If the member is a three-component vector with components
185 consuming N basic machine units, the base alignment is 4N.
186 4. If the member is an array of scalars or vectors, the base
187 alignment and array stride are set to match the base alignment of
188 a single array element, according to rules (1), (2), and (3), and
189 rounded up to the base alignment of a vec4. The array may have
190 padding at the end; the base offset of the member following the
191 array is rounded up to the next multiple of the base alignment.
192
193 9. If the member is a structure, the base alignment of the structure
194 is <N>, where <N> is the largest base alignment value of any of its
195 members, and rounded up to the base alignment of a vec4. The
196 individual members of this sub-structure are then assigned offsets
197 by applying this set of rules recursively, where the base offset of
198 the first member of the sub-structure is equal to the aligned offset
199 of the structure. The structure may have padding at the end; the
200 base offset of the member following the sub-structure is rounded up
201 to the next multiple of the base alignment of the structure.
202
203 When using the std430 storage layout, shader storage blocks will be
204 laid out in buffer storage identically to uniform and shader storage
205 blocks using the std140 layout, except that the base alignment and
206 stride of arrays of scalars and vectors in rule 4 and of structures
207 in rule 9 are not rounded up a multiple of the base alignment of a
208 vec4.
209
210 i.e. rule 3 is still applied in std430. we use an array of 3-element
211 struct instead of vec3/dvec3 to avoid this undesirable padding.
212
213 struct instanceData0 {
214 float x, y, z;
215 }
216 buffer buffer0 {
217 instanceData0 data[];
218 };
219 */
220
221 static const char *
_GetPackedTypeDefinitions()222 _GetPackedTypeDefinitions()
223 {
224 return "struct hd_ivec3 { int x, y, z; };\n"
225 "struct hd_vec3 { float x, y, z; };\n"
226 "struct hd_dvec3 { double x, y, z; };\n"
227 "struct hd_mat3 { float m00, m01, m02,\n"
228 " m10, m11, m12,\n"
229 " m20, m21, m22; };\n"
230 "struct hd_dmat3 { double m00, m01, m02,\n"
231 " m10, m11, m12,\n"
232 " m20, m21, m22; };\n"
233 "ivec3 hd_ivec3_get(hd_ivec3 v) { return ivec3(v.x, v.y, v.z); }\n"
234 "ivec3 hd_ivec3_get(ivec3 v) { return v; }\n"
235 "vec3 hd_vec3_get(hd_vec3 v) { return vec3(v.x, v.y, v.z); }\n"
236 "vec3 hd_vec3_get(vec3 v) { return v; }\n"
237 "dvec3 hd_dvec3_get(hd_dvec3 v) { return dvec3(v.x, v.y, v.z); }\n"
238 "dvec3 hd_dvec3_get(dvec3 v) { return v; }\n"
239 "mat3 hd_mat3_get(hd_mat3 v) { return mat3(v.m00, v.m01, v.m02,\n"
240 " v.m10, v.m11, v.m12,\n"
241 " v.m20, v.m21, v.m22); }\n"
242 "mat3 hd_mat3_get(mat3 v) { return v; }\n"
243 "dmat3 hd_dmat3_get(hd_dmat3 v) { return dmat3(v.m00, v.m01, v.m02,\n"
244 " v.m10, v.m11, v.m12,\n"
245 " v.m20, v.m21, v.m22); }\n"
246 "dmat3 hd_dmat3_get(dmat3 v) { return v; }\n"
247 "hd_ivec3 hd_ivec3_set(hd_ivec3 v) { return v; }\n"
248 "hd_ivec3 hd_ivec3_set(ivec3 v) { return hd_ivec3(v.x, v.y, v.z); }\n"
249 "hd_vec3 hd_vec3_set(hd_vec3 v) { return v; }\n"
250 "hd_vec3 hd_vec3_set(vec3 v) { return hd_vec3(v.x, v.y, v.z); }\n"
251 "hd_dvec3 hd_dvec3_set(hd_dvec3 v) { return v; }\n"
252 "hd_dvec3 hd_dvec3_set(dvec3 v) { return hd_dvec3(v.x, v.y, v.z); }\n"
253 "hd_mat3 hd_mat3_set(hd_mat3 v) { return v; }\n"
254 "hd_mat3 hd_mat3_set(mat3 v) { return hd_mat3(v[0][0], v[0][1], v[0][2],\n"
255 " v[1][0], v[1][1], v[1][2],\n"
256 " v[2][0], v[2][1], v[2][2]); }\n"
257 "hd_dmat3 hd_dmat3_set(hd_dmat3 v) { return v; }\n"
258 "hd_dmat3 hd_dmat3_set(dmat3 v) { return hd_dmat3(v[0][0], v[0][1], v[0][2],\n"
259 " v[1][0], v[1][1], v[1][2],\n"
260 " v[2][0], v[2][1], v[2][2]); }\n"
261 // helper functions for 410 specification
262 // applying a swizzle operator on int and float is not allowed in 410.
263 "int hd_int_get(int v) { return v; }\n"
264 "int hd_int_get(ivec2 v) { return v.x; }\n"
265 "int hd_int_get(ivec3 v) { return v.x; }\n"
266 "int hd_int_get(ivec4 v) { return v.x; }\n"
267 // udim helper function
268 "vec3 hd_sample_udim(vec2 v) {\n"
269 "vec2 vf = floor(v);\n"
270 "return vec3(v.x - vf.x, v.y - vf.y, clamp(vf.x, 0.0, 10.0) + 10.0 * vf.y);\n"
271 "}\n"
272
273 // -------------------------------------------------------------------
274 // Packed HdType implementation.
275
276 // XXX: this could be improved!
277 "vec4 hd_vec4_2_10_10_10_get(int v) {\n"
278 " ivec4 unpacked = ivec4((v & 0x3ff) << 22, (v & 0xffc00) << 12,\n"
279 " (v & 0x3ff00000) << 2, (v & 0xc0000000));\n"
280 " return vec4(unpacked) / 2147483647.0; }\n"
281 "int hd_vec4_2_10_10_10_set(vec4 v) {\n"
282 " return ( (int(v.x * 511.0) & 0x3ff) |\n"
283 " ((int(v.y * 511.0) & 0x3ff) << 10) |\n"
284 " ((int(v.z * 511.0) & 0x3ff) << 20) |\n"
285 " ((int(v.w) & 0x1) << 30)); }\n"
286 // half2 and half4 accessors (note that half and half3 are unsupported)
287 "vec2 hd_half2_get(uint v) {\n"
288 " return unpackHalf2x16(v); }\n"
289 "uint hd_half2_set(vec2 v) {\n"
290 " return packHalf2x16(v); }\n"
291 "vec4 hd_half4_get(uvec2 v) {\n"
292 " return vec4(unpackHalf2x16(v.x), unpackHalf2x16(v.y)); }\n"
293 "uvec2 hd_half4_set(vec4 v) {\n"
294 " return uvec2(packHalf2x16(v.xy), packHalf2x16(v.zw)); }\n"
295 ;
296 }
297
298 static TfToken const &
_GetPackedType(TfToken const & token,bool packedAlignment)299 _GetPackedType(TfToken const &token, bool packedAlignment)
300 {
301 if (packedAlignment) {
302 if (token == _tokens->ivec3) {
303 return _tokens->hd_ivec3;
304 } else if (token == _tokens->vec3) {
305 return _tokens->hd_vec3;
306 } else if (token == _tokens->dvec3) {
307 return _tokens->hd_dvec3;
308 } else if (token == _tokens->mat3) {
309 return _tokens->hd_mat3;
310 } else if (token == _tokens->dmat3) {
311 return _tokens->hd_dmat3;
312 }
313 }
314 if (token == _tokens->packed_2_10_10_10) {
315 return _tokens->_int;
316 }
317 if (token == _tokens->packed_half2) {
318 return _tokens->_uint;
319 }
320 if (token == _tokens->packed_half4) {
321 return _tokens->uvec2;
322 }
323 return token;
324 }
325
326 static TfToken const &
_GetUnpackedType(TfToken const & token,bool packedAlignment)327 _GetUnpackedType(TfToken const &token, bool packedAlignment)
328 {
329 if (token == _tokens->packed_2_10_10_10) {
330 return _tokens->vec4;
331 }
332 if (token == _tokens->packed_half2) {
333 return _tokens->vec2;
334 }
335 if (token == _tokens->packed_half4) {
336 return _tokens->vec4;
337 }
338 return token;
339 }
340
341 static TfToken const &
_GetPackedTypeAccessor(TfToken const & token,bool packedAlignment)342 _GetPackedTypeAccessor(TfToken const &token, bool packedAlignment)
343 {
344 if (packedAlignment) {
345 if (token == _tokens->ivec3) {
346 return _tokens->hd_ivec3_get;
347 } else if (token == _tokens->vec3) {
348 return _tokens->hd_vec3_get;
349 } else if (token == _tokens->dvec3) {
350 return _tokens->hd_dvec3_get;
351 } else if (token == _tokens->mat3) {
352 return _tokens->hd_mat3_get;
353 } else if (token == _tokens->dmat3) {
354 return _tokens->hd_dmat3_get;
355 }
356 }
357 if (token == _tokens->packed_2_10_10_10) {
358 return _tokens->hd_vec4_2_10_10_10_get;
359 }
360 if (token == _tokens->packed_half2) {
361 return _tokens->hd_half2_get;
362 }
363 if (token == _tokens->packed_half4) {
364 return _tokens->hd_half4_get;
365 }
366 return token;
367 }
368
369 static TfToken const &
_GetPackedTypeMutator(TfToken const & token,bool packedAlignment)370 _GetPackedTypeMutator(TfToken const &token, bool packedAlignment)
371 {
372 if (packedAlignment) {
373 if (token == _tokens->ivec3) {
374 return _tokens->hd_ivec3_set;
375 } else if (token == _tokens->vec3) {
376 return _tokens->hd_vec3_set;
377 } else if (token == _tokens->dvec3) {
378 return _tokens->hd_dvec3_set;
379 } else if (token == _tokens->mat3) {
380 return _tokens->hd_mat3_set;
381 } else if (token == _tokens->dmat3) {
382 return _tokens->hd_dmat3_set;
383 }
384 }
385 if (token == _tokens->packed_2_10_10_10) {
386 return _tokens->hd_vec4_2_10_10_10_set;
387 }
388 if (token == _tokens->packed_half2) {
389 return _tokens->hd_half2_set;
390 }
391 if (token == _tokens->packed_half4) {
392 return _tokens->hd_half4_set;
393 }
394 return token;
395 }
396
397 static TfToken const &
_GetFlatType(TfToken const & token)398 _GetFlatType(TfToken const &token)
399 {
400 if (token == _tokens->ivec2) {
401 return _tokens->_int;
402 } else if (token == _tokens->ivec3) {
403 return _tokens->_int;
404 } else if (token == _tokens->ivec4) {
405 return _tokens->_int;
406 } else if (token == _tokens->vec2) {
407 return _tokens->_float;
408 } else if (token == _tokens->vec3) {
409 return _tokens->_float;
410 } else if (token == _tokens->vec4) {
411 return _tokens->_float;
412 } else if (token == _tokens->dvec2) {
413 return _tokens->_double;
414 } else if (token == _tokens->dvec3) {
415 return _tokens->_double;
416 } else if (token == _tokens->dvec4) {
417 return _tokens->_double;
418 } else if (token == _tokens->mat3) {
419 return _tokens->_float;
420 } else if (token == _tokens->mat4) {
421 return _tokens->_float;
422 } else if (token == _tokens->dmat3) {
423 return _tokens->_double;
424 } else if (token == _tokens->dmat4) {
425 return _tokens->_double;
426 }
427 return token;
428 }
429
430 namespace {
431 struct LayoutQualifier {
LayoutQualifier__anon82e156170111::LayoutQualifier432 LayoutQualifier(HdBinding const &binding) :
433 binding(binding) {
434 }
435 friend std::ostream & operator << (std::ostream & out,
436 const LayoutQualifier &lq);
437 HdBinding binding;
438 };
operator <<(std::ostream & out,const LayoutQualifier & lq)439 std::ostream & operator << (std::ostream & out, const LayoutQualifier &lq)
440 {
441 GlfContextCaps const &caps = GlfContextCaps::GetInstance();
442 int location = lq.binding.GetLocation();
443
444 switch (lq.binding.GetType()) {
445 case HdBinding::VERTEX_ATTR:
446 case HdBinding::DRAW_INDEX:
447 case HdBinding::DRAW_INDEX_INSTANCE:
448 case HdBinding::DRAW_INDEX_INSTANCE_ARRAY:
449 // ARB_explicit_attrib_location is supported since GL 3.3
450 out << "layout (location = " << location << ") ";
451 break;
452 case HdBinding::UNIFORM:
453 case HdBinding::UNIFORM_ARRAY:
454 case HdBinding::BINDLESS_UNIFORM:
455 case HdBinding::BINDLESS_SSBO_RANGE:
456 if (caps.explicitUniformLocation) {
457 out << "layout (location = " << location << ") ";
458 }
459 break;
460 case HdBinding::TEXTURE_2D:
461 case HdBinding::BINDLESS_TEXTURE_2D:
462 case HdBinding::TEXTURE_FIELD:
463 case HdBinding::BINDLESS_TEXTURE_FIELD:
464 case HdBinding::TEXTURE_UDIM_ARRAY:
465 case HdBinding::BINDLESS_TEXTURE_UDIM_ARRAY:
466 case HdBinding::TEXTURE_UDIM_LAYOUT:
467 case HdBinding::BINDLESS_TEXTURE_UDIM_LAYOUT:
468 case HdBinding::TEXTURE_PTEX_TEXEL:
469 case HdBinding::BINDLESS_TEXTURE_PTEX_TEXEL:
470 case HdBinding::TEXTURE_PTEX_LAYOUT:
471 case HdBinding::BINDLESS_TEXTURE_PTEX_LAYOUT:
472 if (caps.shadingLanguage420pack) {
473 out << "layout (binding = "
474 << lq.binding.GetTextureUnit() << ") ";
475 } else if (caps.explicitUniformLocation) {
476 out << "layout (location = " << location << ") ";
477 }
478 break;
479 case HdBinding::SSBO:
480 out << "layout (std430, binding = " << location << ") ";
481 break;
482 case HdBinding::UBO:
483 if (caps.shadingLanguage420pack) {
484 out << "layout (std140, binding = " << location << ") ";
485 } else {
486 out << "layout (std140)";
487 }
488 break;
489 default:
490 break;
491 }
492 return out;
493 }
494 }
495
496 HdStGLSLProgramSharedPtr
Compile(HdStResourceRegistry * const registry)497 HdSt_CodeGen::Compile(HdStResourceRegistry*const registry)
498 {
499 HD_TRACE_FUNCTION();
500 HF_MALLOC_TAG_FUNCTION();
501
502 // shader sources
503 // geometric shader owns main()
504 std::string vertexShader =
505 _geometricShader->GetSource(HdShaderTokens->vertexShader);
506 std::string tessControlShader =
507 _geometricShader->GetSource(HdShaderTokens->tessControlShader);
508 std::string tessEvalShader =
509 _geometricShader->GetSource(HdShaderTokens->tessEvalShader);
510 std::string geometryShader =
511 _geometricShader->GetSource(HdShaderTokens->geometryShader);
512 std::string fragmentShader =
513 _geometricShader->GetSource(HdShaderTokens->fragmentShader);
514
515 bool hasVS = (!vertexShader.empty());
516 bool hasTCS = (!tessControlShader.empty());
517 bool hasTES = (!tessEvalShader.empty());
518 bool hasGS = (!geometryShader.empty());
519 bool hasFS = (!fragmentShader.empty());
520
521 // create GLSL program.
522 HdStGLSLProgramSharedPtr glslProgram =
523 std::make_shared<HdStGLSLProgram>(HdTokens->drawingShader, registry);
524
525 // initialize autogen source buckets
526 _genCommon.str(""); _genVS.str(""); _genTCS.str(""); _genTES.str("");
527 _genGS.str(""); _genFS.str(""); _genCS.str("");
528 _procVS.str(""); _procTCS.str(""), _procTES.str(""), _procGS.str("");
529
530 // GLSL version.
531 GlfContextCaps const &caps = GlfContextCaps::GetInstance();
532 _genCommon << "#version " << caps.glslVersion << "\n";
533
534 if (caps.bindlessBufferEnabled) {
535 _genCommon << "#extension GL_NV_shader_buffer_load : require\n"
536 << "#extension GL_NV_gpu_shader5 : require\n";
537 }
538 if (caps.bindlessTextureEnabled) {
539 _genCommon << "#extension GL_ARB_bindless_texture : require\n";
540 }
541 // XXX: Skip checking the context caps for whether the bindless texture
542 // extension is available when bindless shadow maps are enabled. This needs
543 // to be done because GlfSimpleShadowArray is used internally in a manner
544 // wherein context caps initialization might not have happened.
545 if (GlfSimpleShadowArray::GetBindlessShadowMapsEnabled()) {
546 _genCommon << "#extension GL_ARB_bindless_texture : require\n";
547 }
548 if (caps.glslVersion < 460 && caps.shaderDrawParametersEnabled) {
549 _genCommon << "#extension GL_ARB_shader_draw_parameters : require\n";
550 }
551 if (caps.glslVersion < 430 && caps.explicitUniformLocation) {
552 _genCommon << "#extension GL_ARB_explicit_uniform_location : require\n";
553 }
554 if (caps.glslVersion < 420 && caps.shadingLanguage420pack) {
555 _genCommon << "#extension GL_ARB_shading_language_420pack : require\n";
556 }
557
558 // Used in glslfx files to determine if it is using new/old
559 // imaging system. It can also be used as API guards when
560 // we need new versions of Storm shading.
561 _genCommon << "#define HD_SHADER_API " << HD_SHADER_API << "\n";
562
563 // XXX: this is a hacky workaround for experimental support of GL 3.3
564 // the double is used in hd_dvec3 akin, so we are likely able to
565 // refactor that helper functions.
566 if (caps.glslVersion < 400) {
567 _genCommon << "#define double float\n"
568 << "#define dvec2 vec2\n"
569 << "#define dvec3 vec3\n"
570 << "#define dvec4 vec4\n"
571 << "#define dmat4 mat4\n";
572 }
573
574 // XXX: this macro is still used in GlobalUniform.
575 _genCommon << "#define MAT4 " <<
576 HdStGLConversions::GetGLSLTypename(
577 HdVtBufferSource::GetDefaultMatrixType()) << "\n";
578 // a trick to tightly pack unaligned data (vec3, etc) into SSBO/UBO.
579 _genCommon << _GetPackedTypeDefinitions();
580
581 if (_materialTag == HdStMaterialTagTokens->masked) {
582 _genFS << "#define HD_MATERIAL_TAG_MASKED 1\n";
583 }
584
585 // ------------------
586 // Custom Buffer Bindings
587 // ----------------------
588 // For custom buffer bindings, more code can be generated; a full spec is
589 // emitted based on the binding declaration.
590 TF_FOR_ALL(binDecl, _metaData.customBindings) {
591 _genCommon << "#define "
592 << binDecl->name << "_Binding "
593 << binDecl->binding.GetLocation() << "\n";
594 _genCommon << "#define HD_HAS_" << binDecl->name << " 1\n";
595
596 // typeless binding doesn't need declaration nor accessor.
597 if (binDecl->dataType.IsEmpty()) continue;
598
599 _EmitDeclaration(_genCommon,
600 binDecl->name,
601 binDecl->dataType,
602 binDecl->binding);
603 _EmitAccessor(_genCommon,
604 binDecl->name,
605 binDecl->dataType,
606 binDecl->binding,
607 (binDecl->binding.GetType() == HdBinding::UNIFORM)
608 ? NULL : "localIndex");
609 }
610
611 std::stringstream declarations;
612 std::stringstream accessors;
613 TF_FOR_ALL(it, _metaData.customInterleavedBindings) {
614 // note: _constantData has been sorted by offset in HdSt_ResourceBinder.
615 // XXX: not robust enough, should consider padding and layouting rules
616 // to match with the logic in HdInterleavedMemoryManager if we
617 // want to use a layouting policy other than default padding.
618
619 HdBinding binding = it->first;
620 TfToken typeName(TfStringPrintf("CustomBlockData%d", binding.GetValue()));
621 TfToken varName = it->second.blockName;
622
623 declarations << "struct " << typeName << " {\n";
624
625 // dbIt is StructEntry { name, dataType, offset, numElements }
626 TF_FOR_ALL (dbIt, it->second.entries) {
627 _genCommon << "#define HD_HAS_" << dbIt->name << " 1\n";
628 declarations << " " << _GetPackedType(dbIt->dataType, false)
629 << " " << dbIt->name;
630 if (dbIt->arraySize > 1) {
631 _genCommon << "#define HD_NUM_" << dbIt->name
632 << " " << dbIt->arraySize << "\n";
633 declarations << "[" << dbIt->arraySize << "]";
634 }
635 declarations << ";\n";
636
637 _EmitStructAccessor(accessors, varName,
638 dbIt->name, dbIt->dataType, dbIt->arraySize,
639 NULL);
640 }
641
642 declarations << "};\n";
643 _EmitDeclaration(declarations, varName, typeName, binding);
644 }
645 _genCommon << declarations.str()
646 << accessors.str();
647
648 // HD_NUM_PATCH_VERTS, HD_NUM_PRIMTIIVE_VERTS
649 if (_geometricShader->IsPrimTypePatches()) {
650 _genCommon << "#define HD_NUM_PATCH_VERTS "
651 << _geometricShader->GetPrimitiveIndexSize() << "\n";
652 _genCommon << "#define HD_NUM_PATCH_EVAL_VERTS "
653 << _geometricShader->GetNumPatchEvalVerts() << "\n";
654 }
655 _genCommon << "#define HD_NUM_PRIMITIVE_VERTS "
656 << _geometricShader->GetNumPrimitiveVertsForGeometryShader()
657 << "\n";
658
659 // include ptex utility (if needed)
660 TF_FOR_ALL (it, _metaData.shaderParameterBinding) {
661 HdBinding::Type bindingType = it->first.GetType();
662 if (bindingType == HdBinding::TEXTURE_PTEX_TEXEL ||
663 bindingType == HdBinding::BINDLESS_TEXTURE_PTEX_TEXEL) {
664 _genCommon << _GetPtexTextureShaderSource();
665 break;
666 }
667 }
668
669 TF_FOR_ALL (it, _metaData.topologyVisibilityData) {
670 TF_FOR_ALL (pIt, it->second.entries) {
671 _genCommon << "#define HD_HAS_" << pIt->name << " 1\n";
672 }
673 }
674
675 // primvar existence macros
676
677 // XXX: this is temporary, until we implement the fallback value definition
678 // for any primvars used in glslfx.
679 // Note that this #define has to be considered in the hash computation
680 // since it changes the source code. However we have already combined the
681 // entries of instanceData into the hash value, so it's not needed to be
682 // added separately, at least in current usage.
683 TF_FOR_ALL (it, _metaData.constantData) {
684 TF_FOR_ALL (pIt, it->second.entries) {
685 _genCommon << "#define HD_HAS_" << pIt->name << " 1\n";
686 }
687 }
688 TF_FOR_ALL (it, _metaData.instanceData) {
689 _genCommon << "#define HD_HAS_INSTANCE_" << it->second.name << " 1\n";
690 _genCommon << "#define HD_HAS_"
691 << it->second.name << "_" << it->second.level << " 1\n";
692 }
693 _genCommon << "#define HD_INSTANCER_NUM_LEVELS "
694 << _metaData.instancerNumLevels << "\n"
695 << "#define HD_INSTANCE_INDEX_WIDTH "
696 << (_metaData.instancerNumLevels+1) << "\n";
697 if (!_geometricShader->IsPrimTypePoints()) {
698 TF_FOR_ALL (it, _metaData.elementData) {
699 _genCommon << "#define HD_HAS_" << it->second.name << " 1\n";
700 }
701 if (hasGS) {
702 TF_FOR_ALL (it, _metaData.fvarData) {
703 _genCommon << "#define HD_HAS_" << it->second.name << " 1\n";
704 }
705 }
706 }
707 TF_FOR_ALL (it, _metaData.vertexData) {
708 _genCommon << "#define HD_HAS_" << it->second.name << " 1\n";
709 }
710 TF_FOR_ALL (it, _metaData.varyingData) {
711 _genCommon << "#define HD_HAS_" << it->second.name << " 1\n";
712 }
713 TF_FOR_ALL (it, _metaData.shaderParameterBinding) {
714 // XXX: HdBinding::PRIMVAR_REDIRECT won't define an accessor if it's
715 // an alias of like-to-like, so we want to suppress the HD_HAS_* flag
716 // as well.
717
718 // For PRIMVAR_REDIRECT, the HD_HAS_* flag will be defined after
719 // the corresponding HdGet_* function.
720
721 // XXX: (HYD-1882) The #define HD_HAS_... for a primvar
722 // redirect will be defined immediately after the primvar
723 // redirect HdGet_... in the loop over
724 // _metaData.shaderParameterBinding below. Given that this
725 // loop is not running in a canonical order (e.g., textures
726 // first, then primvar redirects, ...) and that the texture is
727 // picking up the HD_HAS_... flag, the answer to the following
728 // question is random:
729 //
730 // If there is a texture trying to use a primvar called NAME
731 // for coordinates and there is a primvar redirect called NAME,
732 // will the texture use it or not?
733 //
734 HdBinding::Type bindingType = it->first.GetType();
735 if (bindingType != HdBinding::PRIMVAR_REDIRECT) {
736 _genCommon << "#define HD_HAS_" << it->second.name << " 1\n";
737 }
738
739 // For any texture shader parameter we also emit the texture
740 // coordinates associated with it
741 if (bindingType == HdBinding::TEXTURE_2D ||
742 bindingType == HdBinding::BINDLESS_TEXTURE_2D ||
743 bindingType == HdBinding::TEXTURE_UDIM_ARRAY ||
744 bindingType == HdBinding::BINDLESS_TEXTURE_UDIM_ARRAY) {
745 _genCommon
746 << "#define HD_HAS_COORD_" << it->second.name << " 1\n";
747 }
748 }
749
750 // mixin shaders
751 _genCommon << _geometricShader->GetSource(HdShaderTokens->commonShaderSource);
752 TF_FOR_ALL(it, _shaders) {
753 _genCommon << (*it)->GetSource(HdShaderTokens->commonShaderSource);
754 }
755
756 // Needed for patch-based face-varying primvar refinement
757 if (_geometricShader->GetFvarPatchType() ==
758 HdSt_GeometricShader::FvarPatchType::PATCH_BSPLINE ||
759 _geometricShader->GetFvarPatchType() ==
760 HdSt_GeometricShader::FvarPatchType::PATCH_BOXSPLINETRIANGLE) {
761 _genGS << "#define OSD_PATCH_BASIS_GLSL\n";
762 _genGS <<
763 OpenSubdiv::Osd::GLSLPatchShaderSource::GetPatchBasisShaderSource();
764 }
765
766 // Barycentric coordinates
767 if (hasGS) {
768 _genGS << "noperspective out vec3 hd_barycentricCoord;\n";
769 _genFS << "noperspective in vec3 hd_barycentricCoord;\n"
770 "vec3 GetBarycentricCoord() {\n"
771 " return hd_barycentricCoord;\n"
772 "}\n";
773 }
774
775 // prep interstage plumbing function
776 _procVS << "void ProcessPrimvars() {\n";
777 _procTCS << "void ProcessPrimvars() {\n";
778 _procTES << "float ProcessPrimvar(float inPv0, float inPv1, float inPv2, float inPv3, vec4 basis, vec2 uv);\n";
779 _procTES << "vec2 ProcessPrimvar(vec2 inPv0, vec2 inPv1, vec2 inPv2, vec2 inPv3, vec4 basis, vec2 uv);\n";
780 _procTES << "vec3 ProcessPrimvar(vec3 inPv0, vec3 inPv1, vec3 inPv2, vec3 inPv3, vec4 basis, vec2 uv);\n";
781 _procTES << "vec4 ProcessPrimvar(vec4 inPv0, vec4 inPv1, vec4 inPv3, vec4 inPv3, vec4 basis, vec2 uv);\n";
782 _procTES << "void ProcessPrimvars(vec4 basis, int i0, int i1, int i2, int i3, vec2 uv) {\n";
783 // geometry shader plumbing
784 switch(_geometricShader->GetPrimitiveType())
785 {
786 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_COARSE_QUADS:
787 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_COARSE_TRIANGLES:
788 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_REFINED_QUADS:
789 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_REFINED_TRIANGLES:
790 {
791 _procGS << "vec4 GetPatchCoord(int index);\n"
792 << "void ProcessPrimvars(int index) {\n"
793 << " vec2 localST = GetPatchCoord(index).xy;\n";
794 break;
795 }
796 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_BSPLINE:
797 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_BOXSPLINETRIANGLE:
798 {
799 _procGS << "void ProcessPrimvars(int index, vec2 tessST) {\n"
800 << " vec2 localST = tessST;\n";
801 break;
802 }
803 default: // points, basis curves
804 // do nothing. no additional code needs to be generated.
805 ;
806 }
807 switch(_geometricShader->GetPrimitiveType())
808 {
809 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_COARSE_QUADS:
810 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_REFINED_QUADS:
811 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_BSPLINE:
812 {
813 // These correspond to built-in fragment shader barycentric coords
814 // except reversed for the second triangle in the quad. Each quad is
815 // split into two triangles with indices (3,0,2) and (1,2,0).
816 _procGS << " const vec3 coords[4] = vec3[](\n"
817 << " vec3(0,0,1), vec3(1,0,0), vec3(0,1,0), vec3(1,0,0)\n"
818 << " );\n"
819 << " hd_barycentricCoord = coords[index];\n";
820 break;
821 }
822 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_COARSE_TRIANGLES:
823 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_REFINED_TRIANGLES:
824 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_BOXSPLINETRIANGLE:
825 {
826 // These correspond to built-in fragment shader barycentric coords.
827 _procGS << " const vec3 coords[3] = vec3[](\n"
828 << " vec3(1,0,0), vec3(0,1,0), vec3(0,0,1)\n"
829 << " );\n"
830 << " hd_barycentricCoord = coords[index];\n";
831 break;
832 }
833 default: // points, basis curves
834 // do nothing. no additional code needs to be generated.
835 ;
836 }
837
838 // generate drawing coord and accessors
839 _GenerateDrawingCoord();
840
841 // generate primvars
842 _GenerateConstantPrimvar();
843 _GenerateInstancePrimvar();
844 _GenerateElementPrimvar();
845 _GenerateVertexAndFaceVaryingPrimvar(hasGS);
846
847 _GenerateTopologyVisibilityParameters();
848
849 //generate shader parameters (is going last since it has primvar redirects)
850 _GenerateShaderParameters();
851
852 // finalize buckets
853 _procVS << "}\n";
854 _procGS << "}\n";
855 _procTCS << "}\n";
856 _procTES << "}\n";
857
858 // insert interstage primvar plumbing procs into genVS/TCS/TES/GS
859 _genVS << _procVS.str();
860 _genTCS << _procTCS.str();
861 _genTES << _procTES.str();
862 _genGS << _procGS.str();
863
864
865 // other shaders (renderpass, lighting, surface) first
866 TF_FOR_ALL(it, _shaders) {
867 HdStShaderCodeSharedPtr const &shader = *it;
868 if (hasVS)
869 _genVS << shader->GetSource(HdShaderTokens->vertexShader);
870 if (hasTCS)
871 _genTCS << shader->GetSource(HdShaderTokens->tessControlShader);
872 if (hasTES)
873 _genTES << shader->GetSource(HdShaderTokens->tessEvalShader);
874 if (hasGS)
875 _genGS << shader->GetSource(HdShaderTokens->geometryShader);
876 if (hasFS)
877 _genFS << shader->GetSource(HdShaderTokens->fragmentShader);
878 }
879
880 // OpenSubdiv tessellation shader (if required)
881 if (tessControlShader.find("OsdPerPatchVertexBezier") != std::string::npos) {
882 _genTCS << OpenSubdiv::Osd::GLSLPatchShaderSource::GetCommonShaderSource();
883 _genTCS << "MAT4 GetWorldToViewMatrix();\n";
884 _genTCS << "MAT4 GetProjectionMatrix();\n";
885 _genTCS << "float GetTessLevel();\n";
886 // we apply modelview in the vertex shader, so the osd shaders doesn't need
887 // to apply again.
888 _genTCS << "mat4 OsdModelViewMatrix() { return mat4(1); }\n";
889 _genTCS << "mat4 OsdProjectionMatrix() { return mat4(GetProjectionMatrix()); }\n";
890 _genTCS << "int OsdPrimitiveIdBase() { return 0; }\n";
891 _genTCS << "float OsdTessLevel() { return GetTessLevel(); }\n";
892 }
893 if (tessEvalShader.find("OsdPerPatchVertexBezier") != std::string::npos) {
894 _genTES << OpenSubdiv::Osd::GLSLPatchShaderSource::GetCommonShaderSource();
895 _genTES << "mat4 OsdModelViewMatrix() { return mat4(1); }\n";
896 }
897 if (geometryShader.find("OsdInterpolatePatchCoord") != std::string::npos) {
898 _genGS << OpenSubdiv::Osd::GLSLPatchShaderSource::GetCommonShaderSource();
899 }
900
901 // geometric shader
902 _genVS << vertexShader;
903 _genTCS << tessControlShader;
904 _genTES << tessEvalShader;
905 _genGS << geometryShader;
906 _genFS << fragmentShader;
907
908 // Sanity check that if you provide a control shader, you have also provided
909 // an evaluation shader (and vice versa)
910 if (hasTCS ^ hasTES) {
911 TF_CODING_ERROR(
912 "tessControlShader and tessEvalShader must be provided together.");
913 hasTCS = hasTES = false;
914 };
915
916 bool shaderCompiled = false;
917 // compile shaders
918 // note: _vsSource, _fsSource etc are used for diagnostics (see header)
919 if (hasVS) {
920 _vsSource = _genCommon.str() + _genVS.str();
921 if (!glslProgram->CompileShader(HgiShaderStageVertex, _vsSource)) {
922 return HdStGLSLProgramSharedPtr();
923 }
924 shaderCompiled = true;
925 }
926 if (hasFS) {
927 _fsSource = _genCommon.str() + _genFS.str();
928 if (!glslProgram->CompileShader(HgiShaderStageFragment, _fsSource)) {
929 return HdStGLSLProgramSharedPtr();
930 }
931 shaderCompiled = true;
932 }
933 if (hasTCS) {
934 _tcsSource = _genCommon.str() + _genTCS.str();
935 if (!glslProgram->CompileShader(
936 HgiShaderStageTessellationControl, _tcsSource)) {
937 return HdStGLSLProgramSharedPtr();
938 }
939 shaderCompiled = true;
940 }
941 if (hasTES) {
942 _tesSource = _genCommon.str() + _genTES.str();
943 if (!glslProgram->CompileShader(
944 HgiShaderStageTessellationEval, _tesSource)) {
945 return HdStGLSLProgramSharedPtr();
946 }
947 shaderCompiled = true;
948 }
949 if (hasGS) {
950 _gsSource = _genCommon.str() + _genGS.str();
951 if (!glslProgram->CompileShader(HgiShaderStageGeometry, _gsSource)) {
952 return HdStGLSLProgramSharedPtr();
953 }
954 shaderCompiled = true;
955 }
956
957 if (!shaderCompiled) {
958 return HdStGLSLProgramSharedPtr();
959 }
960
961 return glslProgram;
962 }
963
964 HdStGLSLProgramSharedPtr
CompileComputeProgram(HdStResourceRegistry * const registry)965 HdSt_CodeGen::CompileComputeProgram(HdStResourceRegistry*const registry)
966 {
967 HD_TRACE_FUNCTION();
968 HF_MALLOC_TAG_FUNCTION();
969
970 // initialize autogen source buckets
971 _genCommon.str(""); _genVS.str(""); _genTCS.str(""); _genTES.str("");
972 _genGS.str(""); _genFS.str(""); _genCS.str("");
973 _procVS.str(""); _procTCS.str(""), _procTES.str(""), _procGS.str("");
974
975 // GLSL version.
976 GlfContextCaps const &caps = GlfContextCaps::GetInstance();
977 _genCommon << "#version " << caps.glslVersion << "\n";
978
979 if (caps.bindlessBufferEnabled) {
980 _genCommon << "#extension GL_NV_shader_buffer_load : require\n"
981 << "#extension GL_NV_gpu_shader5 : require\n";
982 }
983 if (caps.bindlessTextureEnabled) {
984 _genCommon << "#extension GL_ARB_bindless_texture : require\n";
985 }
986 if (caps.glslVersion < 430 && caps.explicitUniformLocation) {
987 _genCommon << "#extension GL_ARB_explicit_uniform_location : require\n";
988 }
989 if (caps.glslVersion < 420 && caps.shadingLanguage420pack) {
990 _genCommon << "#extension GL_ARB_shading_language_420pack : require\n";
991 }
992
993 // default workgroup size (must follow #extension directives)
994 _genCommon << "layout(local_size_x = 1, local_size_y = 1) in;\n";
995
996 // Used in glslfx files to determine if it is using new/old
997 // imaging system. It can also be used as API guards when
998 // we need new versions of Storm shading.
999 _genCommon << "#define HD_SHADER_API " << HD_SHADER_API << "\n";
1000
1001 // a trick to tightly pack unaligned data (vec3, etc) into SSBO/UBO.
1002 _genCommon << _GetPackedTypeDefinitions();
1003
1004 std::stringstream uniforms;
1005 std::stringstream declarations;
1006 std::stringstream accessors;
1007
1008 uniforms << "// Uniform block\n";
1009
1010 HdBinding uboBinding(HdBinding::UBO, 0);
1011 uniforms << LayoutQualifier(uboBinding);
1012 uniforms << "uniform ubo_" << uboBinding.GetLocation() << " {\n";
1013
1014 accessors << "// Read-Write Accessors & Mutators\n";
1015 uniforms << " int vertexOffset; // offset in aggregated buffer\n";
1016 TF_FOR_ALL(it, _metaData.computeReadWriteData) {
1017 TfToken const &name = it->second.name;
1018 HdBinding const &binding = it->first;
1019 TfToken const &dataType = it->second.dataType;
1020
1021 // For now, SSBO bindings use a flat type encoding.
1022 TfToken declDataType =
1023 (binding.GetType() == HdBinding::SSBO
1024 ? _GetFlatType(dataType) : dataType);
1025
1026 uniforms << " int " << name << "Offset;\n";
1027 uniforms << " int " << name << "Stride;\n";
1028
1029 _EmitDeclaration(declarations,
1030 name,
1031 declDataType,
1032 binding, 0);
1033 // getter & setter
1034 {
1035 std::stringstream indexing;
1036 indexing << "(localIndex + vertexOffset)"
1037 << " * " << name << "Stride"
1038 << " + " << name << "Offset";
1039 _EmitComputeAccessor(accessors, name, dataType, binding,
1040 indexing.str().c_str());
1041 _EmitComputeMutator(accessors, name, dataType, binding,
1042 indexing.str().c_str());
1043 }
1044 }
1045 accessors << "// Read-Only Accessors\n";
1046 // no vertex offset for constant data
1047 TF_FOR_ALL(it, _metaData.computeReadOnlyData) {
1048 TfToken const &name = it->second.name;
1049 HdBinding const &binding = it->first;
1050 TfToken const &dataType = it->second.dataType;
1051
1052 // For now, SSBO bindings use a flat type encoding.
1053 TfToken declDataType =
1054 (binding.GetType() == HdBinding::SSBO
1055 ? _GetFlatType(dataType) : dataType);
1056
1057 uniforms << " int " << name << "Offset;\n";
1058 uniforms << " int " << name << "Stride;\n";
1059
1060 _EmitDeclaration(declarations,
1061 name,
1062 declDataType,
1063 binding, 0);
1064 // getter
1065 {
1066 std::stringstream indexing;
1067 // no vertex offset for constant data
1068 indexing << "(localIndex)"
1069 << " * " << name << "Stride"
1070 << " + " << name << "Offset";
1071 _EmitComputeAccessor(accessors, name, dataType, binding,
1072 indexing.str().c_str());
1073 }
1074 }
1075 uniforms << "};\n";
1076
1077 _genCommon << uniforms.str()
1078 << declarations.str()
1079 << accessors.str();
1080
1081 // other shaders (renderpass, lighting, surface) first
1082 TF_FOR_ALL(it, _shaders) {
1083 HdStShaderCodeSharedPtr const &shader = *it;
1084 _genCS << shader->GetSource(HdShaderTokens->computeShader);
1085 }
1086
1087 // main
1088 _genCS << "void main() {\n";
1089 _genCS << " int computeCoordinate = int(gl_GlobalInvocationID.x);\n";
1090 _genCS << " compute(computeCoordinate);\n";
1091 _genCS << "}\n";
1092
1093 // create GLSL program.
1094 HdStGLSLProgramSharedPtr glslProgram =
1095 std::make_shared<HdStGLSLProgram>(HdTokens->computeShader, registry);
1096
1097 // compile shaders
1098 {
1099 _csSource = _genCommon.str() + _genCS.str();
1100 if (!glslProgram->CompileShader(HgiShaderStageCompute, _csSource)) {
1101 HgiShaderProgramHandle const& prg = glslProgram->GetProgram();
1102 std::string const& logString = prg->GetCompileErrors();
1103 TF_WARN("Failed to compile compute shader: %s",
1104 logString.c_str());
1105 return HdStGLSLProgramSharedPtr();
1106 }
1107 }
1108
1109 return glslProgram;
1110 }
1111
_EmitDeclaration(std::stringstream & str,TfToken const & name,TfToken const & type,HdBinding const & binding,int arraySize)1112 static void _EmitDeclaration(std::stringstream &str,
1113 TfToken const &name,
1114 TfToken const &type,
1115 HdBinding const &binding,
1116 int arraySize)
1117 {
1118 /*
1119 [vertex attribute]
1120 layout (location = <location>) in <type> <name>;
1121 [uniform]
1122 layout (location = <location>) uniform <type> <name>;
1123 [SSBO]
1124 layout (std430, binding = <location>) buffer buffer_<location> {
1125 <type> <name>[];
1126 };
1127 [Bindless Uniform]
1128 layout (location = <location>) uniform <type> *<name>;
1129
1130 */
1131 HdBinding::Type bindingType = binding.GetType();
1132
1133 if (!TF_VERIFY(!name.IsEmpty())) return;
1134 if (!TF_VERIFY(!type.IsEmpty(),
1135 "Unknown dataType for %s",
1136 name.GetText())) return;
1137
1138 if (arraySize > 0) {
1139 if (!TF_VERIFY(bindingType == HdBinding::UNIFORM_ARRAY ||
1140 bindingType == HdBinding::DRAW_INDEX_INSTANCE_ARRAY ||
1141 bindingType == HdBinding::UBO ||
1142 bindingType == HdBinding::SSBO ||
1143 bindingType == HdBinding::BINDLESS_SSBO_RANGE ||
1144 bindingType == HdBinding::BINDLESS_UNIFORM)) {
1145 // XXX: SSBO and BINDLESS_UNIFORM don't need arraySize, but for the
1146 // workaround of UBO allocation we're passing arraySize = 2
1147 // for all bindingType.
1148 return;
1149 }
1150 }
1151
1152 // layout qualifier (if exists)
1153 str << LayoutQualifier(binding);
1154
1155 switch (bindingType) {
1156 case HdBinding::VERTEX_ATTR:
1157 case HdBinding::DRAW_INDEX:
1158 case HdBinding::DRAW_INDEX_INSTANCE:
1159 str << "in " << _GetPackedType(type, false) << " " << name << ";\n";
1160 break;
1161 case HdBinding::DRAW_INDEX_INSTANCE_ARRAY:
1162 str << "in " << _GetPackedType(type, false) << " " << name
1163 << "[" << arraySize << "];\n";
1164 break;
1165 case HdBinding::UNIFORM:
1166 str << "uniform " << _GetPackedType(type, false) << " " << name << ";\n";
1167 break;
1168 case HdBinding::UNIFORM_ARRAY:
1169 str << "uniform " << _GetPackedType(type, false) << " " << name
1170 << "[" << arraySize << "];\n";
1171 break;
1172 case HdBinding::UBO:
1173 // note: ubo_ prefix is used in HdResourceBinder::IntrospectBindings.
1174 str << "uniform ubo_" << name << " {\n"
1175 << " " << _GetPackedType(type, true)
1176 << " " << name;
1177 if (arraySize > 0) {
1178 str << "[" << arraySize << "];\n";
1179 } else {
1180 str << ";\n";
1181 }
1182 str << "};\n";
1183 break;
1184 case HdBinding::SSBO:
1185 str << "buffer buffer_" << binding.GetLocation() << " {\n"
1186 << " " << _GetPackedType(type, true)
1187 << " " << name << "[];\n"
1188 << "};\n";
1189 break;
1190 case HdBinding::BINDLESS_SSBO_RANGE:
1191 str << "uniform " << _GetPackedType(type, true)
1192 << " *" << name << ";\n";
1193 break;
1194 case HdBinding::BINDLESS_UNIFORM:
1195 str << "uniform " << _GetPackedType(type, true)
1196 << " *" << name << ";\n";
1197 break;
1198 default:
1199 TF_CODING_ERROR("Unknown binding type %d, for %s\n",
1200 binding.GetType(), name.GetText());
1201 break;
1202 }
1203 }
1204
_EmitDeclaration(std::stringstream & str,HdSt_ResourceBinder::MetaData::BindingDeclaration const & bindingDeclaration,int arraySize=0)1205 static void _EmitDeclaration(
1206 std::stringstream &str,
1207 HdSt_ResourceBinder::MetaData::BindingDeclaration const &bindingDeclaration,
1208 int arraySize=0)
1209 {
1210 _EmitDeclaration(str,
1211 bindingDeclaration.name,
1212 bindingDeclaration.dataType,
1213 bindingDeclaration.binding,
1214 arraySize);
1215 }
1216
_EmitStructAccessor(std::stringstream & str,TfToken const & structName,TfToken const & name,TfToken const & type,int arraySize,const char * index=NULL)1217 static void _EmitStructAccessor(std::stringstream &str,
1218 TfToken const &structName,
1219 TfToken const &name,
1220 TfToken const &type,
1221 int arraySize,
1222 const char *index = NULL)
1223 {
1224 // index != NULL if the struct is an array
1225 // arraySize > 1 if the struct entry is an array.
1226 if (index) {
1227 if (arraySize > 1) {
1228 str << _GetUnpackedType(type, false) << " HdGet_" << name
1229 << "(int arrayIndex, int localIndex) {\n"
1230 // storing to a local variable to avoid the nvidia-driver
1231 // bug #1561110 (fixed in 346.59)
1232 << " int index = " << index << ";\n"
1233 << " return "
1234 << _GetPackedTypeAccessor(type, false) << "("
1235 << structName << "[index]." << name << "[arrayIndex]);\n}\n";
1236 } else {
1237 str << _GetUnpackedType(type, false) << " HdGet_" << name
1238 << "(int localIndex) {\n"
1239 << " int index = " << index << ";\n"
1240 << " return "
1241 << _GetPackedTypeAccessor(type, false) << "("
1242 << structName << "[index]." << name << ");\n}\n";
1243 }
1244 } else {
1245 if (arraySize > 1) {
1246 str << _GetUnpackedType(type, false) << " HdGet_" << name
1247 << "(int arrayIndex, int localIndex) { return "
1248 << _GetPackedTypeAccessor(type, false) << "("
1249 << structName << "." << name << "[arrayIndex]);}\n";
1250 } else {
1251 str << _GetUnpackedType(type, false) << " HdGet_" << name
1252 << "(int localIndex) { return "
1253 << _GetPackedTypeAccessor(type, false) << "("
1254 << structName << "." << name << ");}\n";
1255 }
1256 }
1257 // GLSL spec doesn't allow default parameter. use function overload instead.
1258 // default to localIndex=0
1259 if (arraySize > 1) {
1260 str << _GetUnpackedType(type, false) << " HdGet_" << name
1261 << "(int arrayIndex)"
1262 << " { return HdGet_" << name << "(arrayIndex, 0); }\n";
1263 } else {
1264 str << _GetUnpackedType(type, false) << " HdGet_" << name << "()"
1265 << " { return HdGet_" << name << "(0); }\n";
1266 }
1267 }
1268
_EmitBufferAccessor(std::stringstream & str,TfToken const & name,TfToken const & type,const char * index)1269 static void _EmitBufferAccessor(std::stringstream &str,
1270 TfToken const &name,
1271 TfToken const &type,
1272 const char *index)
1273 {
1274 if (index) {
1275 str << _GetUnpackedType(type, false) << " HdGet_" << name
1276 << "(int localIndex) {\n"
1277 << " int index = " << index << ";\n"
1278 << " return "
1279 << _GetPackedTypeAccessor(type, true) << "("
1280 << name << "[index]);\n}\n";
1281 }
1282 str << _GetUnpackedType(type, false) << " HdGet_" << name << "()"
1283 << " { return HdGet_" << name << "(0); }\n";
1284 }
1285
_GetSwizzleString(TfToken const & type,std::string const & swizzle=std::string ())1286 static std::string _GetSwizzleString(TfToken const& type,
1287 std::string const& swizzle=std::string())
1288 {
1289 if (!swizzle.empty()) {
1290 return "." + swizzle;
1291 }
1292 if (type == _tokens->vec4 || type == _tokens->ivec4) {
1293 return "";
1294 }
1295 if (type == _tokens->vec3 || type == _tokens->ivec3) {
1296 return ".xyz";
1297 }
1298 if (type == _tokens->vec2 || type == _tokens->ivec2) {
1299 return ".xy";
1300 }
1301 if (type == _tokens->_float || type == _tokens->_int) {
1302 return ".x";
1303 }
1304 if (type == _tokens->packed_2_10_10_10) {
1305 return ".x";
1306 }
1307
1308 return "";
1309 }
1310
_GetNumComponents(TfToken const & type)1311 static int _GetNumComponents(TfToken const& type)
1312 {
1313 int numComponents = 1;
1314 if (type == _tokens->vec2 || type == _tokens->ivec2) {
1315 numComponents = 2;
1316 } else if (type == _tokens->vec3 || type == _tokens->ivec3) {
1317 numComponents = 3;
1318 } else if (type == _tokens->vec4 || type == _tokens->ivec4) {
1319 numComponents = 4;
1320 } else if (type == _tokens->mat3 || type == _tokens->dmat3) {
1321 numComponents = 9;
1322 } else if (type == _tokens->mat4 || type == _tokens->dmat4) {
1323 numComponents = 16;
1324 }
1325
1326 return numComponents;
1327 }
1328
_EmitComputeAccessor(std::stringstream & str,TfToken const & name,TfToken const & type,HdBinding const & binding,const char * index)1329 static void _EmitComputeAccessor(
1330 std::stringstream &str,
1331 TfToken const &name,
1332 TfToken const &type,
1333 HdBinding const &binding,
1334 const char *index)
1335 {
1336 if (index) {
1337 str << _GetUnpackedType(type, false)
1338 << " HdGet_" << name << "(int localIndex) {\n";
1339 if (binding.GetType() == HdBinding::SSBO) {
1340 str << " int index = " << index << ";\n";
1341 str << " return " << _GetPackedTypeAccessor(type, false) << "("
1342 << _GetPackedType(type, false) << "(";
1343 int numComponents = _GetNumComponents(type);
1344 for (int c = 0; c < numComponents; ++c) {
1345 if (c > 0) {
1346 str << ",\n ";
1347 }
1348 str << name << "[index + " << c << "]";
1349 }
1350 str << "));\n}\n";
1351 } else if (binding.GetType() == HdBinding::BINDLESS_SSBO_RANGE) {
1352 str << " return " << _GetPackedTypeAccessor(type, true) << "("
1353 << name << "[localIndex]);\n}\n";
1354 } else {
1355 str << " return " << _GetPackedTypeAccessor(type, true) << "("
1356 << name << "[localIndex]);\n}\n";
1357 }
1358 } else {
1359 // non-indexed, only makes sense for uniform or vertex.
1360 if (binding.GetType() == HdBinding::UNIFORM ||
1361 binding.GetType() == HdBinding::VERTEX_ATTR) {
1362 str << _GetUnpackedType(type, false)
1363 << " HdGet_" << name << "(int localIndex) { return ";
1364 str << _GetPackedTypeAccessor(type, true) << "(" << name << ");}\n";
1365 }
1366 }
1367 // GLSL spec doesn't allow default parameter. use function overload instead.
1368 // default to locaIndex=0
1369 str << _GetUnpackedType(type, false) << " HdGet_" << name << "()"
1370 << " { return HdGet_" << name << "(0); }\n";
1371
1372 }
1373
_EmitComputeMutator(std::stringstream & str,TfToken const & name,TfToken const & type,HdBinding const & binding,const char * index)1374 static void _EmitComputeMutator(
1375 std::stringstream &str,
1376 TfToken const &name,
1377 TfToken const &type,
1378 HdBinding const &binding,
1379 const char *index)
1380 {
1381 if (index) {
1382 str << "void"
1383 << " HdSet_" << name << "(int localIndex, "
1384 << _GetUnpackedType(type, false) << " value) {\n";
1385 if (binding.GetType() == HdBinding::SSBO) {
1386 str << " int index = " << index << ";\n";
1387 str << " " << _GetPackedType(type, false) << " packedValue = "
1388 << _GetPackedTypeMutator(type, false) << "(value);\n";
1389 int numComponents = _GetNumComponents(_GetPackedType(type, false));
1390 if (numComponents == 1) {
1391 str << " "
1392 << name << "[index] = packedValue;\n";
1393 } else {
1394 for (int c = 0; c < numComponents; ++c) {
1395 str << " "
1396 << name << "[index + " << c << "] = "
1397 << "packedValue[" << c << "];\n";
1398 }
1399 }
1400 } else if (binding.GetType() == HdBinding::BINDLESS_SSBO_RANGE) {
1401 str << name << "[localIndex] = "
1402 << _GetPackedTypeMutator(type, true) << "(value);\n";
1403 } else {
1404 TF_WARN("mutating non-SSBO not supported");
1405 }
1406 str << "}\n";
1407 } else {
1408 TF_WARN("mutating non-indexed data not supported");
1409 }
1410 // XXX Don't output a default mutator as we don't want accidental overwrites
1411 // of compute read-write data.
1412 // GLSL spec doesn't allow default parameter. use function overload instead.
1413 // default to locaIndex=0
1414 //str << "void HdSet_" << name << "(" << type << " value)"
1415 // << " { HdSet_" << name << "(0, value); }\n";
1416
1417 }
1418
_EmitAccessor(std::stringstream & str,TfToken const & name,TfToken const & type,HdBinding const & binding,const char * index)1419 static void _EmitAccessor(std::stringstream &str,
1420 TfToken const &name,
1421 TfToken const &type,
1422 HdBinding const &binding,
1423 const char *index)
1424 {
1425 if (index) {
1426 str << _GetUnpackedType(type, false)
1427 << " HdGet_" << name << "(int localIndex) {\n"
1428 << " int index = " << index << ";\n"
1429 << " return " << _GetPackedTypeAccessor(type, true) << "("
1430 << name << "[index]);\n}\n";
1431 } else {
1432 // non-indexed, only makes sense for uniform or vertex.
1433 if (binding.GetType() == HdBinding::UNIFORM ||
1434 binding.GetType() == HdBinding::VERTEX_ATTR) {
1435 str << _GetUnpackedType(type, false)
1436 << " HdGet_" << name << "(int localIndex) { return ";
1437 str << _GetPackedTypeAccessor(type, true) << "(" << name << ");}\n";
1438 }
1439 }
1440 // GLSL spec doesn't allow default parameter. use function overload instead.
1441 // default to locaIndex=0
1442 str << _GetUnpackedType(type, false) << " HdGet_" << name << "()"
1443 << " { return HdGet_" << name << "(0); }\n";
1444
1445 }
1446
_EmitTextureAccessors(std::stringstream & accessors,HdSt_ResourceBinder::MetaData::ShaderParameterAccessor const & acc,std::string const & swizzle,int const dim,bool const hasTextureTransform,bool const hasTextureScaleAndBias,bool const isBindless)1447 static void _EmitTextureAccessors(
1448 std::stringstream &accessors,
1449 HdSt_ResourceBinder::MetaData::ShaderParameterAccessor const &acc,
1450 std::string const &swizzle,
1451 int const dim,
1452 bool const hasTextureTransform,
1453 bool const hasTextureScaleAndBias,
1454 bool const isBindless)
1455 {
1456 GlfContextCaps const &caps = GlfContextCaps::GetInstance();
1457
1458 TfToken const &name = acc.name;
1459
1460 // Forward declare texture scale and bias
1461 if (hasTextureScaleAndBias) {
1462 accessors
1463 << "#ifdef HD_HAS_" << name << "_" << HdStTokens->scale << "\n"
1464 << "vec4 HdGet_" << name << "_" << HdStTokens->scale << "();\n"
1465 << "#endif\n"
1466 << "#ifdef HD_HAS_" << name << "_" << HdStTokens->bias << "\n"
1467 << "vec4 HdGet_" << name << "_" << HdStTokens->bias << "();\n"
1468 << "#endif\n";
1469 }
1470
1471 if (!isBindless) {
1472 // a function returning sampler requires bindless_texture
1473 if (caps.bindlessTextureEnabled) {
1474 accessors
1475 << "sampler" << dim << "D\n"
1476 << "HdGetSampler_" << name << "() {\n"
1477 << " return sampler" << dim << "d_" << name << ";"
1478 << "}\n";
1479 } else {
1480 accessors
1481 << "#define HdGetSampler_" << name << "()"
1482 << " sampler" << dim << "d_" << name << "\n";
1483 }
1484 } else {
1485 if (caps.bindlessTextureEnabled) {
1486 accessors
1487 << "sampler" << dim << "D\n"
1488 << "HdGetSampler_" << name << "() {\n"
1489 << " int shaderCoord = GetDrawingCoord().shaderCoord; \n"
1490 << " return sampler" << dim << "D("
1491 << " shaderData[shaderCoord]." << name << ");\n"
1492 << "}\n";
1493 }
1494 }
1495
1496 TfToken const &dataType = acc.dataType;
1497
1498 if (hasTextureTransform) {
1499 // Declare an eye to sampling transform and define function
1500 // to initialize it.
1501 const std::string eyeToSamplingTransform =
1502 "eyeTo" + name.GetString() + "SamplingTransform";
1503
1504 // Computations in eye space are done with float precision, so the
1505 // eye to sampling transform is mat4.
1506 // Note that the multiplication that yiels this sampling transform
1507 // might be done using higher precision.
1508 accessors
1509 << "mat4 " << eyeToSamplingTransform << ";\n"
1510 << "\n"
1511 << "void Process_" << eyeToSamplingTransform
1512 << "(MAT4 instanceModelViewInverse) { \n"
1513 << " int shaderCoord = GetDrawingCoord().shaderCoord; \n"
1514 << " " << eyeToSamplingTransform << " = mat4(\n"
1515 << " MAT4(shaderData[shaderCoord]."
1516 << name << HdSt_ResourceBindingSuffixTokens->samplingTransform
1517 << ") * instanceModelViewInverse);\n"
1518 << "}\n";
1519 }
1520
1521 accessors
1522 << _GetUnpackedType(dataType, false)
1523 << " HdGet_" << name << "(vec" << dim << " coord) {\n"
1524 << " int shaderCoord = GetDrawingCoord().shaderCoord; \n";
1525
1526 if (hasTextureTransform) {
1527 const std::string eyeToSamplingTransform =
1528 "eyeTo" + name.GetString() + "SamplingTransform";
1529
1530 accessors
1531 << " vec4 c = " << eyeToSamplingTransform
1532 << " * vec4(coord, 1);\n"
1533 << " vec3 sampleCoord = c.xyz / c.w;\n";
1534 } else {
1535 accessors
1536 << " vec" << dim << " sampleCoord = coord;\n";
1537 }
1538
1539 if (hasTextureScaleAndBias) {
1540 accessors
1541 << " " << _GetUnpackedType(dataType, false)
1542 << " result = "
1543 << _GetPackedTypeAccessor(dataType, false)
1544 << "((texture(HdGetSampler_" << name << "(), sampleCoord)\n"
1545 << "#ifdef HD_HAS_" << name << "_" << HdStTokens->scale << "\n"
1546 << " * HdGet_" << name << "_" << HdStTokens->scale << "()\n"
1547 << "#endif\n"
1548 << "#ifdef HD_HAS_" << name << "_" << HdStTokens->bias << "\n"
1549 << " + HdGet_" << name << "_" << HdStTokens->bias << "()\n"
1550 << "#endif\n"
1551 << ")" << swizzle << ");\n";
1552 } else {
1553 accessors
1554 << " " << _GetUnpackedType(dataType, false)
1555 << " result = "
1556 << _GetPackedTypeAccessor(dataType, false)
1557 << "(texture(HdGetSampler_" << name << "(), sampleCoord)"
1558 << swizzle << ");\n";
1559 }
1560
1561 if (acc.processTextureFallbackValue) {
1562 // Check whether texture is valid (using NAME_valid)
1563 //
1564 // Note that the OpenGL standard says that the
1565 // implicit derivatives (for accessing the right
1566 // mip-level) are undefined if the texture look-up
1567 // happens in a non-uniform control block, thus the
1568 // texture lookup is unconditionally assigned to
1569 // result outside of the if-block.
1570 //
1571 if (isBindless) {
1572 accessors
1573 << " if (shaderData[shaderCoord]." << name
1574 << " != uvec2(0, 0)) {\n";
1575 } else {
1576 accessors
1577 << " if (shaderData[shaderCoord]." << name
1578 << HdSt_ResourceBindingSuffixTokens->valid
1579 << ") {\n";
1580 }
1581
1582 if (hasTextureScaleAndBias) {
1583 accessors
1584 << " return result;\n"
1585 << " } else {\n"
1586 << " return ("
1587 << _GetPackedTypeAccessor(dataType, false)
1588 << "(shaderData[shaderCoord]."
1589 << name
1590 << HdSt_ResourceBindingSuffixTokens->fallback << ")\n"
1591 << "#ifdef HD_HAS_" << name << "_" << HdStTokens->scale << "\n"
1592 << " * HdGet_" << name << "_" << HdStTokens->scale
1593 << "()" << swizzle << "\n"
1594 << "#endif\n"
1595 << "#ifdef HD_HAS_" << name << "_" << HdStTokens->bias << "\n"
1596 << " + HdGet_" << name << "_" << HdStTokens->bias
1597 << "()" << swizzle << "\n"
1598 << "#endif\n"
1599 << ");\n"
1600 << " }\n";
1601 } else {
1602 accessors
1603 << " return result;\n"
1604 << " } else {\n"
1605 << " return "
1606 << _GetPackedTypeAccessor(dataType, false)
1607 << "(shaderData[shaderCoord]."
1608 << name
1609 << HdSt_ResourceBindingSuffixTokens->fallback << ");\n"
1610 << " }\n";
1611 }
1612 } else {
1613 accessors
1614 << " return result;\n";
1615 }
1616
1617 accessors
1618 << "}\n";
1619
1620 TfTokenVector const &inPrimvars = acc.inPrimvars;
1621
1622 // Forward declare getter for inPrimvars in case it's a transform2d
1623 if (!inPrimvars.empty()) {
1624 accessors
1625 << "#if defined(HD_HAS_" << inPrimvars[0] << ")\n"
1626 << "vec" << dim << " HdGet_" << inPrimvars[0] << "(int localIndex);\n"
1627 << "#endif\n";
1628 }
1629
1630 // Create accessor for texture coordinates based on texture param name
1631 // vec2 HdGetCoord_name(int localIndex)
1632 accessors
1633 << "vec" << dim << " HdGetCoord_" << name << "(int localIndex) {\n"
1634 << " return \n";
1635 if (!inPrimvars.empty()) {
1636 accessors
1637 << "#if defined(HD_HAS_" << inPrimvars[0] <<")\n"
1638 << " HdGet_" << inPrimvars[0] << "(localIndex).xy\n"
1639 << "#else\n"
1640 << " vec" << dim << "(0.0)\n"
1641 << "#endif\n";
1642 } else {
1643 accessors
1644 << " vec" << dim << "(0.0)\n";
1645 }
1646 accessors << ";}\n";
1647
1648 // vec2 HdGetCoord_name()
1649 accessors
1650 << "vec" << dim << " HdGetCoord_" << name << "() {"
1651 << " return HdGetCoord_" << name << "(0); }\n";
1652
1653 // vec4 HdGet_name(int localIndex)
1654 accessors
1655 << _GetUnpackedType(dataType, false)
1656 << " HdGet_" << name
1657 << "(int localIndex) { return HdGet_" << name << "("
1658 << "HdGetCoord_" << name << "(localIndex)); }\n";
1659
1660 // vec4 HdGet_name()
1661 accessors
1662 << _GetUnpackedType(dataType, false)
1663 << " HdGet_" << name
1664 << "() { return HdGet_" << name << "(0); }\n";
1665
1666 // Emit pre-multiplication by alpha indicator
1667 if (acc.isPremultiplied) {
1668 accessors << "#define " << name << "_IS_PREMULTIPLIED 1\n";
1669 }
1670 }
1671
1672 // Accessing face varying primvar data of a vertex in the GS requires special
1673 // case handling for refinement while providing a branchless solution.
1674 // When dealing with vertices on a refined face when the face-varying data has
1675 // not been refined, we use the patch coord to get its parametrization on the
1676 // sanitized (coarse) "ptex" face, and interpolate based on the face primitive
1677 // type (bilinear for quad faces, barycentric for tri faces).
1678 // When face varying data has been refined and the fvar patch type is quad or
1679 // tri, we still use bilinear or barycentric interpolation, respectively, but
1680 // we do it over the refined face and use refined face-varying values, accessed
1681 // using the refined face-varying indices.
1682 // When the fvar patch type is b-spline or box-spline, we solve over 16 or 12
1683 // refined values, respectively, also accessed via the refined indices, getting
1684 // the weights from OsdEvaluatePatchBasisNormalized().
_EmitFVarGSAccessor(std::stringstream & str,TfToken const & name,TfToken const & type,HdBinding const & binding,HdSt_GeometricShader::PrimitiveType const & primType,HdSt_GeometricShader::FvarPatchType const & fvarPatchType,int fvarChannel)1685 static void _EmitFVarGSAccessor(
1686 std::stringstream &str,
1687 TfToken const &name,
1688 TfToken const &type,
1689 HdBinding const &binding,
1690 HdSt_GeometricShader::PrimitiveType const& primType,
1691 HdSt_GeometricShader::FvarPatchType const& fvarPatchType,
1692 int fvarChannel)
1693 {
1694 // emit an internal getter for accessing the coarse fvar data (corresponding
1695 // to the refined face, in the case of refinement)
1696 str << _GetUnpackedType(type, false)
1697 << " HdGet_" << name << "_Coarse(int localIndex) {\n";
1698 if ((fvarPatchType ==
1699 HdSt_GeometricShader::FvarPatchType::PATCH_COARSE_QUADS) ||
1700 (fvarPatchType ==
1701 HdSt_GeometricShader::FvarPatchType::PATCH_COARSE_TRIANGLES)) {
1702 str << " int fvarIndex = GetFVarIndex(localIndex);\n";
1703 } else {
1704 str << " int fvarIndex = GetDrawingCoord().fvarCoord + localIndex;\n";
1705 }
1706 str << " return " << _GetPackedTypeAccessor(type, true) << "("
1707 << name << "[fvarIndex]);\n}\n";
1708
1709 // emit the (public) accessor for the fvar data, accounting for refinement
1710 // interpolation
1711 str << _GetUnpackedType(type, false)
1712 << " HdGet_" << name << "(int localIndex, vec2 st) {\n";
1713
1714 if (fvarPatchType ==
1715 HdSt_GeometricShader::FvarPatchType::PATCH_BSPLINE) {
1716 str << " int patchType = OSD_PATCH_DESCRIPTOR_REGULAR;\n";
1717 } else if (fvarPatchType ==
1718 HdSt_GeometricShader::FvarPatchType::PATCH_BOXSPLINETRIANGLE) {
1719 str << " int patchType = OSD_PATCH_DESCRIPTOR_LOOP;\n";
1720 }
1721
1722 switch (fvarPatchType) {
1723 case HdSt_GeometricShader::FvarPatchType::PATCH_COARSE_QUADS:
1724 {
1725 // linear interpolation within a quad.
1726 str << " return mix("
1727 << "mix(" << "HdGet_" << name << "_Coarse(0),"
1728 << "HdGet_" << name << "_Coarse(1), st.x),"
1729 << "mix(" << "HdGet_" << name << "_Coarse(3),"
1730 << "HdGet_" << name << "_Coarse(2), st.x), "
1731 << "st.y);\n}\n";
1732 break;
1733 }
1734 case HdSt_GeometricShader::FvarPatchType::PATCH_COARSE_TRIANGLES:
1735 {
1736 // barycentric interpolation within a triangle.
1737 str << " return ("
1738 << "HdGet_" << name << "_Coarse(0) * (1-st.x-st.y)"
1739 << " + HdGet_" << name << "_Coarse(1) * st.x"
1740 << " + HdGet_" << name << "_Coarse(2) * st.y);\n}\n";
1741 break;
1742 }
1743 case HdSt_GeometricShader::FvarPatchType::PATCH_REFINED_QUADS:
1744 {
1745 // linear interpolation between 4 refined primvars
1746 str << " ivec4 indices = HdGet_fvarIndices" << fvarChannel
1747 << "();\n"
1748 << " return mix("
1749 << "mix(" << "HdGet_" << name << "_Coarse(indices[0]),"
1750 << "HdGet_" << name << "_Coarse(indices[1]), st.s),"
1751 << "mix(" << "HdGet_" << name << "_Coarse(indices[3]),"
1752 << "HdGet_" << name << "_Coarse(indices[2]), st.s), "
1753 << "st.t);\n}\n";
1754 break;
1755 }
1756 case HdSt_GeometricShader::FvarPatchType::PATCH_REFINED_TRIANGLES:
1757 {
1758 // barycentric interpolation between 3 refined primvars
1759 str << " ivec3 indices = HdGet_fvarIndices" << fvarChannel
1760 << "();\n"
1761 << " return ("
1762 << "HdGet_" << name << "_Coarse(indices[0]) * (1-st.s-st.t)"
1763 << " + HdGet_" << name << "_Coarse(indices[1]) * st.s"
1764 << " + HdGet_" << name << "_Coarse(indices[2]) * st.t);\n}\n";
1765 break;
1766 }
1767 case HdSt_GeometricShader::FvarPatchType::PATCH_BSPLINE:
1768 case HdSt_GeometricShader::FvarPatchType::PATCH_BOXSPLINETRIANGLE:
1769 {
1770 // evaluation of a bspline/box spline patch
1771 str << " ivec2 fvarPatchParam = HdGet_fvarPatchParam"
1772 << fvarChannel << "();\n"
1773 << " OsdPatchParam param = OsdPatchParamInit(fvarPatchParam.x,"
1774 << " fvarPatchParam.y, 0);\n"
1775 << " float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], "
1776 << "wDvv[20];\n"
1777 << " OsdEvaluatePatchBasisNormalized(patchType, param,"
1778 << " st.s, st.t, wP, wDu, wDv, wDuu, wDuv, wDvv);\n"
1779 << " " << _GetUnpackedType(type, false) << " result = "
1780 << _GetUnpackedType(type, false) << "(0);\n"
1781 << " for (int i = 0; i < HD_NUM_PATCH_VERTS; ++i) {\n"
1782 << " int fvarIndex = HdGet_fvarIndices" << fvarChannel
1783 << "(i);\n"
1784 << " " << _GetUnpackedType(type, false) << " cv = "
1785 << _GetUnpackedType(type, false) << "(HdGet_" << name
1786 << "_Coarse(fvarIndex));\n"
1787 << " result += wP[i] * cv;\n"
1788 << " }\n"
1789 << " return result;\n}\n";
1790 break;
1791 }
1792 case HdSt_GeometricShader::FvarPatchType::PATCH_NONE:
1793 {
1794 str << " return HdGet_" << name << "_Coarse(localIndex);\n}\n";
1795 break;
1796 }
1797 default:
1798 {
1799 // emit a default version for compilation sake
1800 str << " return HdGet_" << name << "_Coarse(localIndex);\n}\n";
1801
1802 TF_CODING_ERROR("Face varing bindings for unexpected for"
1803 " HdSt_GeometricShader::PrimitiveType %d",
1804 (int)primType);
1805 }
1806 }
1807
1808 str << "vec4 GetPatchCoord(int index);\n"
1809 << _GetUnpackedType(type, false)
1810 << " HdGet_" << name << "(int localIndex) {\n";
1811
1812 switch (fvarPatchType) {
1813 case HdSt_GeometricShader::FvarPatchType::PATCH_COARSE_QUADS:
1814 case HdSt_GeometricShader::FvarPatchType::PATCH_COARSE_TRIANGLES:
1815 {
1816 str << " vec2 localST = GetPatchCoord(localIndex).xy;\n";
1817 break;
1818 }
1819 case HdSt_GeometricShader::FvarPatchType::PATCH_BSPLINE:
1820 {
1821 // Compute localST in normalized patch param space
1822 str << " ivec2 fvarPatchParam = HdGet_fvarPatchParam"
1823 << fvarChannel << "();\n"
1824 << " OsdPatchParam param = OsdPatchParamInit(fvarPatchParam.x,"
1825 << " fvarPatchParam.y, 0);\n"
1826 << " vec2 unnormalized = GetPatchCoord(localIndex).xy;\n"
1827 << " float uv[2] = float[2](unnormalized.x, unnormalized.y);\n"
1828 << " OsdPatchParamNormalize(param, uv);\n"
1829 << " vec2 localST = vec2(uv[0], uv[1]);\n";
1830 break;
1831 }
1832 case HdSt_GeometricShader::FvarPatchType::PATCH_BOXSPLINETRIANGLE:
1833 {
1834 // Compute localST in normalized patch param space
1835 str << " ivec2 fvarPatchParam = HdGet_fvarPatchParam"
1836 << fvarChannel << "();\n"
1837 << " OsdPatchParam param = OsdPatchParamInit(fvarPatchParam.x,"
1838 << " fvarPatchParam.y, 0);\n"
1839 << " vec2 unnormalized = GetPatchCoord(localIndex).xy;\n"
1840 << " float uv[2] = float[2](unnormalized.x, unnormalized.y);\n"
1841 << " OsdPatchParamNormalizeTriangle(param, uv);\n"
1842 << " vec2 localST = vec2(uv[0], uv[1]);\n";
1843 break;
1844 }
1845 case HdSt_GeometricShader::FvarPatchType::PATCH_REFINED_QUADS:
1846 {
1847 str << " vec2 lut[4] = vec2[4](vec2(0,0), vec2(1,0), "
1848 << "vec2(1,1), vec2(0,1));\n"
1849 << " vec2 localST = lut[localIndex];\n";
1850 break;
1851 }
1852 case HdSt_GeometricShader::FvarPatchType::PATCH_REFINED_TRIANGLES:
1853 {
1854 str << " vec2 lut[3] = vec2[3](vec2(0,0), vec2(1,0), vec2(0,1));\n"
1855 << " vec2 localST = lut[localIndex];\n";
1856 break;
1857 }
1858 default:
1859 {
1860 str << " vec2 localST = vec2(0);\n";
1861 }
1862 }
1863 str << " return HdGet_" << name << "(localIndex, localST);\n}\n";
1864
1865 // XXX: We shouldn't emit the default (argument free) accessor version,
1866 // since that doesn't make sense within a GS. Once we fix the XXX in
1867 // _GenerateShaderParameters, we should remove this.
1868 str << _GetUnpackedType(type, false) << " HdGet_" << name << "()"
1869 << " { return HdGet_" << name << "(0); }\n";
1870 }
1871
1872 void
_GenerateDrawingCoord()1873 HdSt_CodeGen::_GenerateDrawingCoord()
1874 {
1875 TF_VERIFY(_metaData.drawingCoord0Binding.binding.IsValid());
1876 TF_VERIFY(_metaData.drawingCoord1Binding.binding.IsValid());
1877 TF_VERIFY(_metaData.drawingCoord2Binding.binding.IsValid());
1878
1879 /*
1880 hd_drawingCoord is a struct of integer offsets to locate the primvars
1881 in buffer arrays at the current rendering location.
1882
1883 struct hd_drawingCoord {
1884 int modelCoord; // (reserved) model parameters
1885 int constantCoord; // constant primvars (per object)
1886 int vertexCoord; // vertex primvars (per vertex)
1887 int elementCoord; // element primvars (per face/curve)
1888 int primitiveCoord; // primitive ids (per tri/quad/line)
1889 int fvarCoord; // fvar primvars (per face-vertex)
1890 int shaderCoord; // shader parameters (per shader/object)
1891 int topologyVisibilityCoord // topological visibility data (per face/point)
1892 int varyingCoord; // varying primvars (per vertex)
1893 int instanceIndex[]; // (see below)
1894 int instanceCoords[]; // (see below)
1895 };
1896
1897 instanceIndex[0] : global instance ID (used for ID rendering)
1898 [1] : instance index for level = 0
1899 [2] : instance index for level = 1
1900 ...
1901 instanceCoords[0] : instanceDC for level = 0
1902 instanceCoords[1] : instanceDC for level = 1
1903 ...
1904
1905 We also have a drawingcoord for vertex primvars. Currently it's not
1906 being passed into shader since the vertex shader takes pre-offsetted
1907 vertex arrays and no needs to apply offset in shader (except gregory
1908 patch drawing etc. In that case gl_BaseVertexARB can be used under
1909 GL_ARB_shader_draw_parameters extention)
1910
1911 gl_InstanceID is available only in vertex shader, so codegen
1912 takes care of applying an offset for each instance for the later
1913 stage. On the other hand, gl_PrimitiveID is available in all stages
1914 except vertex shader, and since tess/geometry shaders may or may not
1915 exist, we don't apply an offset of primitiveID during interstage
1916 plumbing to avoid overlap. Instead, GetDrawingCoord() applies
1917 primitiveID if necessary.
1918
1919 XXX:
1920 Ideally we should use an interface block like:
1921
1922 in DrawingCoord {
1923 flat hd_drawingCoord drawingCoord;
1924 } inDrawingCoord;
1925 out DrawingCoord {
1926 flat hd_drawingCoord drawingCoord;
1927 } outDrawingCoord;
1928
1929 then the fragment shader can take the same input regardless the
1930 existence of tess/geometry shaders. However it seems the current
1931 driver (331.79) doesn't handle multiple interface blocks
1932 appropriately, it fails matching and ends up undefined results at
1933 consuming shader.
1934
1935 > OpenGL 4.4 Core profile
1936 > 7.4.1 Shader Interface Matching
1937 >
1938 > When multiple shader stages are active, the outputs of one stage form
1939 > an interface with the inputs of the next stage. At each such
1940 > interface, shader inputs are matched up against outputs from the
1941 > previous stage:
1942 >
1943 > An output block is considered to match an input block in the
1944 > subsequent shader if the two blocks have the same block name, and
1945 > the members of the block match exactly in name, type, qualification,
1946 > and declaration order.
1947 >
1948 > An output variable is considered to match an input variable in the
1949 > subsequent shader if:
1950 > - the two variables match in name, type, and qualification; or
1951 > - the two variables are declared with the same location and
1952 > component layout qualifiers and match in type and qualification.
1953
1954 We use non-block variable for drawingCoord as a workaround of this
1955 problem for now. There is a caveat we can't use the same name for input
1956 and output, the subsequent shader has to be aware which stage writes
1957 the drawingCoord.
1958
1959 for example:
1960 drawingCoord--(VS)--vsDrawingCoord--(GS)--gsDrawingCoord--(FS)
1961 drawingCoord--(VS)------------------------vsDrawingCoord--(FS)
1962
1963 Fortunately the compiler is smart enough to optimize out unused
1964 attributes. If the VS writes the same value into two attributes:
1965
1966 drawingCoord--(VS)--vsDrawingCoord--(GS)--gsDrawingCoord--(FS)
1967 (VS)--gsDrawingCoord--------gsDrawingCoord--(FS)
1968
1969 The fragment shader can always take gsDrawingCoord. The following code
1970 does such a plumbing work.
1971
1972 */
1973
1974 // common
1975 //
1976 // note: instanceCoords should be [HD_INSTANCER_NUM_LEVELS], but since
1977 // GLSL doesn't allow [0] declaration, we use +1 value (WIDTH)
1978 // for the sake of simplicity.
1979 _genCommon << "struct hd_drawingCoord { \n"
1980 << " int modelCoord; \n"
1981 << " int constantCoord; \n"
1982 << " int vertexCoord; \n"
1983 << " int elementCoord; \n"
1984 << " int primitiveCoord; \n"
1985 << " int fvarCoord; \n"
1986 << " int shaderCoord; \n"
1987 << " int topologyVisibilityCoord; \n"
1988 << " int varyingCoord; \n"
1989 << " int instanceIndex[HD_INSTANCE_INDEX_WIDTH]; \n"
1990 << " int instanceCoords[HD_INSTANCE_INDEX_WIDTH]; \n"
1991 << "};\n";
1992
1993 _genCommon << "hd_drawingCoord GetDrawingCoord();\n"; // forward declaration
1994
1995 // vertex shader
1996
1997 // [immediate]
1998 // layout (location=x) uniform ivec4 drawingCoord0;
1999 // layout (location=y) uniform ivec4 drawingCoord1;
2000 // layout (location=z) uniform int drawingCoordI[N];
2001 // [indirect]
2002 // layout (location=x) in ivec4 drawingCoord0
2003 // layout (location=y) in ivec4 drawingCoord1
2004 // layout (location=z) in ivec2 drawingCoord2
2005 // layout (location=w) in int drawingCoordI[N]
2006 _EmitDeclaration(_genVS, _metaData.drawingCoord0Binding);
2007 _EmitDeclaration(_genVS, _metaData.drawingCoord1Binding);
2008 _EmitDeclaration(_genVS, _metaData.drawingCoord2Binding);
2009 if (_metaData.drawingCoordIBinding.binding.IsValid()) {
2010 _EmitDeclaration(_genVS, _metaData.drawingCoordIBinding,
2011 /*arraySize=*/std::max(1, _metaData.instancerNumLevels));
2012 }
2013
2014 // instance index indirection
2015 _genCommon << "struct hd_instanceIndex { int indices[HD_INSTANCE_INDEX_WIDTH]; };\n";
2016
2017 if (_metaData.instanceIndexArrayBinding.binding.IsValid()) {
2018 // << layout (location=x) uniform (int|ivec[234]) *instanceIndices;
2019 _EmitDeclaration(_genCommon, _metaData.instanceIndexArrayBinding);
2020
2021 // << layout (location=x) uniform (int|ivec[234]) *culledInstanceIndices;
2022 _EmitDeclaration(_genCommon, _metaData.culledInstanceIndexArrayBinding);
2023
2024 /// if \p cullingPass is true, CodeGen generates GetInstanceIndex()
2025 /// such that it refers instanceIndices buffer (before culling).
2026 /// Otherwise, GetInstanceIndex() looks up culledInstanceIndices.
2027
2028 _genVS << "int GetInstanceIndexCoord() {\n"
2029 << " return drawingCoord1.y + gl_InstanceID * HD_INSTANCE_INDEX_WIDTH; \n"
2030 << "}\n";
2031
2032 if (_geometricShader->IsFrustumCullingPass()) {
2033 // for frustum culling: use instanceIndices.
2034 _genVS << "hd_instanceIndex GetInstanceIndex() {\n"
2035 << " int offset = GetInstanceIndexCoord();\n"
2036 << " hd_instanceIndex r;\n"
2037 << " for (int i = 0; i < HD_INSTANCE_INDEX_WIDTH; ++i)\n"
2038 << " r.indices[i] = instanceIndices[offset+i];\n"
2039 << " return r;\n"
2040 << "}\n";
2041 _genVS << "void SetCulledInstanceIndex(uint instanceID) {\n"
2042 << " for (int i = 0; i < HD_INSTANCE_INDEX_WIDTH; ++i)\n"
2043 << " culledInstanceIndices[drawingCoord1.y + instanceID*HD_INSTANCE_INDEX_WIDTH+i]"
2044 << " = instanceIndices[drawingCoord1.y + gl_InstanceID*HD_INSTANCE_INDEX_WIDTH+i];\n"
2045 << "}\n";
2046 } else {
2047 // for drawing: use culledInstanceIndices.
2048 _EmitAccessor(_genVS, _metaData.culledInstanceIndexArrayBinding.name,
2049 _metaData.culledInstanceIndexArrayBinding.dataType,
2050 _metaData.culledInstanceIndexArrayBinding.binding,
2051 "GetInstanceIndexCoord()+localIndex");
2052 _genVS << "hd_instanceIndex GetInstanceIndex() {\n"
2053 << " int offset = GetInstanceIndexCoord();\n"
2054 << " hd_instanceIndex r;\n"
2055 << " for (int i = 0; i < HD_INSTANCE_INDEX_WIDTH; ++i)\n"
2056 << " r.indices[i] = HdGet_culledInstanceIndices(/*localIndex=*/i);\n"
2057 << " return r;\n"
2058 << "}\n";
2059 }
2060 } else {
2061 _genVS << "hd_instanceIndex GetInstanceIndex() {"
2062 << " hd_instanceIndex r; r.indices[0] = 0; return r; }\n";
2063 if (_geometricShader->IsFrustumCullingPass()) {
2064 _genVS << "void SetCulledInstanceIndex(uint instance) "
2065 "{ /*no-op*/ }\n";
2066 }
2067 }
2068
2069 _genVS << "flat out hd_drawingCoord vsDrawingCoord;\n"
2070 // XXX: see the comment above why we need both vs and gs outputs.
2071 << "flat out hd_drawingCoord gsDrawingCoord;\n";
2072
2073 _genVS << "hd_drawingCoord GetDrawingCoord() { hd_drawingCoord dc; \n"
2074 << " dc.modelCoord = drawingCoord0.x; \n"
2075 << " dc.constantCoord = drawingCoord0.y; \n"
2076 << " dc.elementCoord = drawingCoord0.z; \n"
2077 << " dc.primitiveCoord = drawingCoord0.w; \n"
2078 << " dc.fvarCoord = drawingCoord1.x; \n"
2079 << " dc.shaderCoord = drawingCoord1.z; \n"
2080 << " dc.vertexCoord = drawingCoord1.w; \n"
2081 << " dc.topologyVisibilityCoord = drawingCoord2.x; \n"
2082 << " dc.varyingCoord = drawingCoord2.y; \n"
2083 << " dc.instanceIndex = GetInstanceIndex().indices;\n";
2084
2085 if (_metaData.drawingCoordIBinding.binding.IsValid()) {
2086 _genVS << " for (int i = 0; i < HD_INSTANCER_NUM_LEVELS; ++i) {\n"
2087 << " dc.instanceCoords[i] = drawingCoordI[i] \n"
2088 << " + dc.instanceIndex[i+1]; \n"
2089 << " }\n";
2090 }
2091
2092 _genVS << " return dc;\n"
2093 << "}\n";
2094
2095 // note: GL spec says tessellation input array size must be equal to
2096 // gl_MaxPatchVertices, which is used for intrinsic declaration
2097 // of built-in variables:
2098 // in gl_PerVertex {} gl_in[gl_MaxPatchVertices];
2099
2100 // tess control shader
2101 _genTCS << "flat in hd_drawingCoord vsDrawingCoord[gl_MaxPatchVertices];\n"
2102 << "flat out hd_drawingCoord tcsDrawingCoord[HD_NUM_PATCH_EVAL_VERTS];\n"
2103 << "hd_drawingCoord GetDrawingCoord() { \n"
2104 << " hd_drawingCoord dc = vsDrawingCoord[0];\n"
2105 << " dc.primitiveCoord += gl_PrimitiveID;\n"
2106 << " return dc;\n"
2107 << "}\n";
2108 // tess eval shader
2109 _genTES << "flat in hd_drawingCoord tcsDrawingCoord[gl_MaxPatchVertices];\n"
2110 << "flat out hd_drawingCoord vsDrawingCoord;\n"
2111 << "flat out hd_drawingCoord gsDrawingCoord;\n"
2112 << "hd_drawingCoord GetDrawingCoord() { \n"
2113 << " hd_drawingCoord dc = tcsDrawingCoord[0]; \n"
2114 << " dc.primitiveCoord += gl_PrimitiveID; \n"
2115 << " return dc;\n"
2116 << "}\n";
2117
2118 // geometry shader ( VSdc + gl_PrimitiveIDIn )
2119 _genGS << "flat in hd_drawingCoord vsDrawingCoord[HD_NUM_PRIMITIVE_VERTS];\n"
2120 << "flat out hd_drawingCoord gsDrawingCoord;\n"
2121 << "hd_drawingCoord GetDrawingCoord() { \n"
2122 << " hd_drawingCoord dc = vsDrawingCoord[0]; \n"
2123 << " dc.primitiveCoord += gl_PrimitiveIDIn; \n"
2124 << " return dc; \n"
2125 << "}\n";
2126
2127 // fragment shader ( VSdc + gl_PrimitiveID )
2128 // note that gsDrawingCoord isn't offsetted by gl_PrimitiveIDIn
2129 _genFS << "flat in hd_drawingCoord gsDrawingCoord;\n"
2130 << "hd_drawingCoord GetDrawingCoord() { \n"
2131 << " hd_drawingCoord dc = gsDrawingCoord; \n"
2132 << " dc.primitiveCoord += gl_PrimitiveID; \n"
2133 << " return dc; \n"
2134 << "}\n";
2135
2136 // drawing coord plumbing.
2137 // Note that copying from [0] for multiple input source since the
2138 // drawingCoord is flat (no interpolation required).
2139 _procVS << " vsDrawingCoord = GetDrawingCoord();\n"
2140 << " gsDrawingCoord = GetDrawingCoord();\n";
2141 _procTCS << " tcsDrawingCoord[gl_InvocationID] = "
2142 << " vsDrawingCoord[gl_InvocationID];\n";
2143 _procTES << " vsDrawingCoord = tcsDrawingCoord[0];\n"
2144 << " gsDrawingCoord = tcsDrawingCoord[0];\n";
2145 _procGS << " gsDrawingCoord = vsDrawingCoord[0];\n";
2146
2147 }
2148 void
_GenerateConstantPrimvar()2149 HdSt_CodeGen::_GenerateConstantPrimvar()
2150 {
2151 /*
2152 // --------- constant data declaration ----------
2153 struct ConstantData0 {
2154 mat4 transform;
2155 mat4 transformInverse;
2156 mat4 instancerTransform[2];
2157 vec3 displayColor;
2158 vec4 primID;
2159 };
2160 // bindless
2161 layout (location=0) uniform ConstantData0 *constantData0;
2162 // not bindless
2163 layout (std430, binding=0) buffer {
2164 constantData0 constantData0[];
2165 };
2166
2167 // --------- constant data accessors ----------
2168 mat4 HdGet_transform(int localIndex) {
2169 return constantData0[GetConstantCoord()].transform;
2170 }
2171 vec3 HdGet_displayColor(int localIndex) {
2172 return constantData0[GetConstantCoord()].displayColor;
2173 }
2174
2175 */
2176
2177 std::stringstream declarations;
2178 std::stringstream accessors;
2179 TF_FOR_ALL (it, _metaData.constantData) {
2180 // note: _constantData has been sorted by offset in HdSt_ResourceBinder.
2181 // XXX: not robust enough, should consider padding and layouting rules
2182 // to match with the logic in HdInterleavedMemoryManager if we
2183 // want to use a layouting policy other than default padding.
2184
2185 HdBinding binding = it->first;
2186 TfToken typeName(TfStringPrintf("ConstantData%d", binding.GetValue()));
2187 TfToken varName = it->second.blockName;
2188
2189 declarations << "struct " << typeName << " {\n";
2190
2191 TF_FOR_ALL (dbIt, it->second.entries) {
2192 if (!TF_VERIFY(!dbIt->dataType.IsEmpty(),
2193 "Unknown dataType for %s",
2194 dbIt->name.GetText())) {
2195 continue;
2196 }
2197
2198 declarations << " " << _GetPackedType(dbIt->dataType, false)
2199 << " " << dbIt->name;
2200 if (dbIt->arraySize > 1) {
2201 declarations << "[" << dbIt->arraySize << "]";
2202 }
2203
2204 declarations << ";\n";
2205
2206 _EmitStructAccessor(accessors, varName, dbIt->name, dbIt->dataType,
2207 dbIt->arraySize,
2208 "GetDrawingCoord().constantCoord");
2209 }
2210 declarations << "};\n";
2211
2212 // XXX: passing arraySize=2 to cheat driver to not tell actual size.
2213 // we should compute the actual size or maximum size if possible.
2214 _EmitDeclaration(declarations, varName, typeName, binding, /*arraySize=*/1);
2215 }
2216 _genCommon << declarations.str()
2217 << accessors.str();
2218 }
2219
2220 void
_GenerateInstancePrimvar()2221 HdSt_CodeGen::_GenerateInstancePrimvar()
2222 {
2223 /*
2224 // --------- instance data declaration ----------
2225 // bindless
2226 layout (location=X) uniform vec4 *data;
2227 // not bindless
2228 layout (std430, binding=X) buffer buffer_X {
2229 vec4 data[];
2230 };
2231
2232 // --------- instance data accessors ----------
2233 vec3 HdGet_translate(int localIndex=0) {
2234 return instanceData0[GetInstanceCoord()].translate;
2235 }
2236 */
2237
2238 std::stringstream declarations;
2239 std::stringstream accessors;
2240
2241 struct LevelEntries {
2242 TfToken dataType;
2243 std::vector<int> levels;
2244 };
2245 std::map<TfToken, LevelEntries> nameAndLevels;
2246
2247 TF_FOR_ALL (it, _metaData.instanceData) {
2248 HdBinding binding = it->first;
2249 TfToken const &dataType = it->second.dataType;
2250 int level = it->second.level;
2251
2252 nameAndLevels[it->second.name].dataType = dataType;
2253 nameAndLevels[it->second.name].levels.push_back(level);
2254
2255 std::stringstream n;
2256 n << it->second.name << "_" << level;
2257 TfToken name(n.str());
2258 n.str("");
2259 n << "GetDrawingCoord().instanceCoords[" << level << "]";
2260
2261 // << layout (location=x) uniform float *translate_0;
2262 _EmitDeclaration(declarations, name, dataType, binding);
2263 _EmitAccessor(accessors, name, dataType, binding, n.str().c_str());
2264
2265 }
2266
2267 /*
2268 accessor taking level as a parameter.
2269 note that instance primvar may or may not be defined for each level.
2270 we expect level is an unrollable constant to optimize out branching.
2271
2272 vec3 HdGetInstance_translate(int level, vec3 defaultValue) {
2273 if (level == 0) return HdGet_translate_0();
2274 // level==1 is not defined. use default
2275 if (level == 2) return HdGet_translate_2();
2276 if (level == 3) return HdGet_translate_3();
2277 return defaultValue;
2278 }
2279 */
2280 TF_FOR_ALL (it, nameAndLevels) {
2281 accessors << _GetUnpackedType(it->second.dataType, false)
2282 << " HdGetInstance_" << it->first << "(int level, "
2283 << _GetUnpackedType(it->second.dataType, false)
2284 << " defaultValue) {\n";
2285 TF_FOR_ALL (levelIt, it->second.levels) {
2286 accessors << " if (level == " << *levelIt << ") "
2287 << "return HdGet_" << it->first << "_" << *levelIt << "();\n";
2288 }
2289
2290 accessors << " return defaultValue;\n"
2291 << "}\n";
2292 }
2293 /*
2294 common accessor, if the primvar is defined on the instancer but not
2295 the rprim.
2296
2297 #if !defined(HD_HAS_translate)
2298 #define HD_HAS_translate 1
2299 vec3 HdGet_translate(int localIndex) {
2300 // 0 is the lowest level for which this is defined
2301 return HdGet_translate_0();
2302 }
2303 vec3 HdGet_translate() {
2304 return HdGet_translate(0);
2305 }
2306 #endif
2307 */
2308 TF_FOR_ALL (it, nameAndLevels) {
2309 accessors << "#if !defined(HD_HAS_" << it->first << ")\n"
2310 << "#define HD_HAS_" << it->first << " 1\n"
2311 << _GetUnpackedType(it->second.dataType, false)
2312 << " HdGet_" << it->first << "(int localIndex) {\n"
2313 << " return HdGet_" << it->first << "_"
2314 << it->second.levels.front() << "();\n"
2315 << "}\n"
2316 << _GetUnpackedType(it->second.dataType, false)
2317 << " HdGet_" << it->first << "() { return HdGet_"
2318 << it->first << "(0); }\n"
2319 << "#endif\n";
2320 }
2321
2322
2323 _genCommon << declarations.str()
2324 << accessors.str();
2325 }
2326
2327 void
_GenerateElementPrimvar()2328 HdSt_CodeGen::_GenerateElementPrimvar()
2329 {
2330 /*
2331 Accessing uniform primvar data:
2332 ===============================
2333 Uniform primvar data is authored at the subprimitive (also called element or
2334 face below) granularity.
2335 To access uniform primvar data (say color), there are two indirections in
2336 the lookup because of aggregation in the buffer layout.
2337 ----------------------------------------------------
2338 color | prim0 colors | prim1 colors | .... | primN colors|
2339 ----------------------------------------------------
2340 For each prim, GetDrawingCoord().elementCoord holds the start index into
2341 this buffer.
2342
2343 For an unrefined prim, the subprimitive ID is simply the gl_PrimitiveID.
2344 For a refined prim, gl_PrimitiveID corresponds to the refined element ID.
2345
2346 To map a refined face to its coarse face, Storm builds a "primitive param"
2347 buffer (more details in the section below). This buffer is also aggregated,
2348 and for each subprimitive, GetDrawingCoord().primitiveCoord gives us the
2349 index into this buffer (meaning it has already added the gl_PrimitiveID)
2350
2351 To have a single codepath for both cases, we build the primitive param
2352 buffer for unrefined prims as well, and effectively index the uniform
2353 primvar using:
2354 drawCoord.elementCoord + primitiveParam[ drawCoord.primitiveCoord ]
2355
2356 The code generated looks something like:
2357
2358 // --------- primitive param declaration ----------
2359 struct PrimitiveData { int elementID; }
2360 layout (std430, binding=?) buffer PrimitiveBuffer {
2361 PrimitiveData primitiveData[];
2362 };
2363
2364 // --------- indirection accessors ---------
2365 // Gives us the "coarse" element ID
2366 int GetElementID() {
2367 return primitiveData[GetPrimitiveCoord()].elementID;
2368 }
2369
2370 // Adds the offset to the start of the uniform primvar data for the prim
2371 int GetAggregatedElementID() {
2372 return GetElementID() + GetDrawingCoord().elementCoord;\n"
2373 }
2374
2375 // --------- uniform primvar declaration ---------
2376 struct ElementData0 {
2377 vec3 displayColor;
2378 };
2379 layout (std430, binding=?) buffer buffer0 {
2380 ElementData0 elementData0[];
2381 };
2382
2383 // ---------uniform primvar data accessor ---------
2384 vec3 HdGet_displayColor(int localIndex) {
2385 return elementData0[GetAggregatedElementID()].displayColor;
2386 }
2387
2388 */
2389
2390 // Primitive Param buffer layout:
2391 // ==============================
2392 // Depending on the prim, one of following is used:
2393 //
2394 // 1. basis curves
2395 // 1 int : curve index
2396 //
2397 // This lets us translate a basis curve segment to its curve id.
2398 // A basis curve is made up for 'n' curves, each of which have a varying
2399 // number of segments.
2400 // (see hdSt/basisCurvesComputations.cpp)
2401 //
2402 // 2. mesh specific
2403 // a. tris
2404 // 1 int : coarse face index + edge flag
2405 // (see hd/meshUtil.h,cpp)
2406 //
2407 // b. quads coarse
2408 // 2 ints : coarse face index + edge flag
2409 // ptex index
2410 // (see hd/meshUtil.h,cpp)
2411 //
2412 // c. tris & quads uniformly refined
2413 // 3 ints : coarse face index + edge flag
2414 // Far::PatchParam::field0 (includes ptex index)
2415 // Far::PatchParam::field1
2416 // (see hdSt/subdivision.cpp)
2417 //
2418 // d. patch adaptively refined
2419 // 4 ints : coarse face index + edge flag
2420 // Far::PatchParam::field0 (includes ptex index)
2421 // Far::PatchParam::field1
2422 // sharpness (float)
2423 // (see hdSt/subdivision.cpp)
2424 // -----------------------------------------------------------------------
2425 // note: decoding logic of primitiveParam has to match with
2426 // HdMeshTopology::DecodeFaceIndexFromPrimitiveParam()
2427 //
2428 // PatchParam is defined as ivec3 (see opensubdiv/far/patchParam.h)
2429 // Field0 | Bits | Content
2430 // -----------|:----:|---------------------------------------------------
2431 // faceId | 28 | the faceId of the patch (Storm uses ptexIndex)
2432 // transition | 4 | transition edge mask encoding
2433 //
2434 // Field1 | Bits | Content
2435 // -----------|:----:|---------------------------------------------------
2436 // level | 4 | the subdivision level of the patch
2437 // nonquad | 1 | whether patch is refined from a non-quad face
2438 // regular | 1 | whether patch is regular
2439 // unused | 1 | unused
2440 // boundary | 5 | boundary mask encoding
2441 // v | 10 | log2 value of u parameter at first patch corner
2442 // u | 10 | log2 value of v parameter at first patch corner
2443 //
2444 // Field2 (float) sharpness
2445 //
2446 // whereas adaptive patches have PatchParams computed by OpenSubdiv,
2447 // we need to construct PatchParams for coarse tris and quads.
2448 // Currently it's enough to fill just faceId for coarse quads for
2449 // ptex shading.
2450
2451 std::stringstream declarations;
2452 std::stringstream accessors;
2453
2454 if (_metaData.primitiveParamBinding.binding.IsValid()) {
2455
2456 HdBinding binding = _metaData.primitiveParamBinding.binding;
2457 _EmitDeclaration(declarations, _metaData.primitiveParamBinding);
2458 _EmitAccessor(accessors, _metaData.primitiveParamBinding.name,
2459 _metaData.primitiveParamBinding.dataType, binding,
2460 "GetDrawingCoord().primitiveCoord");
2461
2462 if (_geometricShader->IsPrimTypePoints()) {
2463 // do nothing.
2464 // e.g. if a prim's geomstyle is points and it has a valid
2465 // primitiveParamBinding, we don't generate any of the
2466 // accessor methods.
2467 ;
2468 }
2469 else if (_geometricShader->IsPrimTypeBasisCurves()) {
2470 // straight-forward indexing to get the segment's curve id
2471 accessors
2472 << "int GetElementID() {\n"
2473 << " return (hd_int_get(HdGet_primitiveParam()));\n"
2474 << "}\n";
2475 accessors
2476 << "int GetAggregatedElementID() {\n"
2477 << " return GetElementID()\n"
2478 << " + GetDrawingCoord().elementCoord;\n"
2479 << "}\n";
2480 }
2481 else if (_geometricShader->IsPrimTypeMesh()) {
2482 // GetPatchParam, GetEdgeFlag
2483 switch (_geometricShader->GetPrimitiveType()) {
2484 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_REFINED_QUADS:
2485 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_REFINED_TRIANGLES:
2486 {
2487 // refined quads (catmulClark uniform subdiv) or
2488 // refined tris (loop uniform subdiv)
2489 accessors
2490 << "ivec3 GetPatchParam() {\n"
2491 << " return ivec3(HdGet_primitiveParam().y, \n"
2492 << " HdGet_primitiveParam().z, 0);\n"
2493 << "}\n";
2494 accessors
2495 << "int GetEdgeFlag() {\n"
2496 << " return (HdGet_primitiveParam().x & 3);\n"
2497 << "}\n";
2498 break;
2499 }
2500
2501 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_BSPLINE:
2502 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_BOXSPLINETRIANGLE:
2503 {
2504 // "adaptive" subdivision generates refined patches
2505 // (tessellated triangles)
2506 accessors
2507 << "ivec3 GetPatchParam() {\n"
2508 << " return ivec3(HdGet_primitiveParam().y, \n"
2509 << " HdGet_primitiveParam().z, \n"
2510 << " HdGet_primitiveParam().w);\n"
2511 << "}\n";
2512 accessors
2513 << "int GetEdgeFlag() {\n"
2514 << " return (HdGet_primitiveParam().x & 3);\n"
2515 << "}\n";
2516 break;
2517 }
2518
2519 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_COARSE_QUADS:
2520 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_COARSE_TRIANGLES:
2521 {
2522 // coarse quads or coarse triangles
2523 // ptexId matches the primitiveID for quadrangulated or
2524 // triangulated meshes, the other fields can be left as 0.
2525 // When there are geom subsets, we can no longer use the
2526 // primitiveId and instead use a buffer source generated
2527 // per subset draw item containing the coarse face indices.
2528 accessors
2529 << "#if defined(HD_HAS_coarseFaceIndex)\n"
2530 << "int HdGet_coarseFaceIndex();\n"
2531 << "#endif\n"
2532 << "ivec3 GetPatchParam() {\n"
2533 << "#if defined(HD_HAS_coarseFaceIndex)\n "
2534 << " return ivec3(HdGet_coarseFaceIndex().x, 0, 0);\n"
2535 << "#else\n "
2536 << " return ivec3(gl_PrimitiveID, 0, 0);\n"
2537 << "#endif\n"
2538 << "}\n";
2539 // edge flag encodes edges which have been
2540 // introduced by quadrangulation or triangulation
2541 accessors
2542 << "int GetEdgeFlag() {\n"
2543 << " return (HdGet_primitiveParam() & 3);\n"
2544 << "}\n";
2545 break;
2546 }
2547
2548 default:
2549 {
2550 TF_CODING_ERROR("HdSt_GeometricShader::PrimitiveType %d is "
2551 "unexpected in _GenerateElementPrimvar().",
2552 (int)_geometricShader->GetPrimitiveType());
2553 }
2554 }
2555
2556 // GetFVarIndex
2557 if (_geometricShader->GetFvarPatchType() ==
2558 HdSt_GeometricShader::FvarPatchType::PATCH_COARSE_TRIANGLES)
2559 {
2560 // note that triangulated meshes don't have ptexIndex.
2561 // Here we're passing primitiveID as ptexIndex PatchParam
2562 // since Hd_TriangulateFaceVaryingComputation unrolls facevaring
2563 // primvars for each triangles.
2564 accessors
2565 << "int GetFVarIndex(int localIndex) {\n"
2566 << " int fvarCoord = GetDrawingCoord().fvarCoord;\n"
2567 << " int ptexIndex = GetPatchParam().x & 0xfffffff;\n"
2568 << " return fvarCoord + ptexIndex * 3 + localIndex;\n"
2569 << "}\n";
2570 } else if (_geometricShader->GetFvarPatchType() ==
2571 HdSt_GeometricShader::FvarPatchType::PATCH_COARSE_QUADS) {
2572 accessors
2573 << "int GetFVarIndex(int localIndex) {\n"
2574 << " int fvarCoord = GetDrawingCoord().fvarCoord;\n"
2575 << " int ptexIndex = GetPatchParam().x & 0xfffffff;\n"
2576 << " return fvarCoord + ptexIndex * 4 + localIndex;\n"
2577 << "}\n";
2578 }
2579
2580 // ElementID getters
2581 accessors
2582 << "int GetElementID() {\n"
2583 << " return (hd_int_get(HdGet_primitiveParam()) >> 2);\n"
2584 << "}\n";
2585
2586 accessors
2587 << "int GetAggregatedElementID() {\n"
2588 << " return GetElementID()\n"
2589 << " + GetDrawingCoord().elementCoord;\n"
2590 << "}\n";
2591 }
2592 else {
2593 TF_CODING_ERROR("HdSt_GeometricShader::PrimitiveType %d is "
2594 "unexpected in _GenerateElementPrimvar().",
2595 (int)_geometricShader->GetPrimitiveType());
2596 }
2597 } else {
2598 // no primitiveParamBinding
2599
2600 // XXX: this is here only to keep the compiler happy, we don't expect
2601 // users to call them -- we really should restructure whatever is
2602 // necessary to avoid having to do this and thus guarantee that users
2603 // can never call bogus versions of these functions.
2604
2605 // Use a fallback of -1, so that points aren't selection highlighted
2606 // when face 0 is selected. This would be the case if we returned 0,
2607 // since the selection highlighting code is repr-agnostic.
2608 // It is safe to do this for points, since we don't generate accessors
2609 // for element primvars, and thus don't use it as an index into
2610 // elementCoord.
2611 if (_geometricShader->IsPrimTypePoints()) {
2612 accessors
2613 << "int GetElementID() {\n"
2614 << " return -1;\n"
2615 << "}\n";
2616 } else {
2617 accessors
2618 << "int GetElementID() {\n"
2619 << " return 0;\n"
2620 << "}\n";
2621 }
2622 accessors
2623 << "int GetAggregatedElementID() {\n"
2624 << " return GetElementID();\n"
2625 << "}\n";
2626 accessors
2627 << "int GetEdgeFlag() {\n"
2628 << " return 0;\n"
2629 << "}\n";
2630 accessors
2631 << "ivec3 GetPatchParam() {\n"
2632 << " return ivec3(0, 0, 0);\n"
2633 << "}\n";
2634 accessors
2635 << "int GetFVarIndex(int localIndex) {\n"
2636 << " return 0;\n"
2637 << "}\n";
2638 }
2639 declarations
2640 << "int GetElementID();\n"
2641 << "int GetAggregatedElementID();\n";
2642
2643
2644 if (_metaData.edgeIndexBinding.binding.IsValid()) {
2645
2646 HdBinding binding = _metaData.edgeIndexBinding.binding;
2647
2648 _EmitDeclaration(declarations, _metaData.edgeIndexBinding);
2649 _EmitAccessor(accessors, _metaData.edgeIndexBinding.name,
2650 _metaData.edgeIndexBinding.dataType, binding,
2651 "GetDrawingCoord().primitiveCoord");
2652 }
2653
2654 if (_metaData.coarseFaceIndexBinding.binding.IsValid()) {
2655 _genCommon << "#define HD_HAS_"
2656 << _metaData.coarseFaceIndexBinding.name << " 1\n";
2657
2658 const HdBinding &binding = _metaData.coarseFaceIndexBinding.binding;
2659
2660 _EmitDeclaration(declarations, _metaData.coarseFaceIndexBinding);
2661 _EmitAccessor(accessors, _metaData.coarseFaceIndexBinding.name,
2662 _metaData.coarseFaceIndexBinding.dataType, binding,
2663 "GetDrawingCoord().primitiveCoord + localIndex");
2664 }
2665
2666 switch (_geometricShader->GetPrimitiveType()) {
2667 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_REFINED_QUADS:
2668 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_REFINED_TRIANGLES:
2669 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_BSPLINE:
2670 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_BOXSPLINETRIANGLE:
2671 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_COARSE_QUADS:
2672 case HdSt_GeometricShader::PrimitiveType::PRIM_MESH_COARSE_TRIANGLES:
2673 // This is no longer used by Storm but is generated for backward
2674 // compatibility with production shaders.
2675 accessors
2676 << "int GetAuthoredEdgeId(int primitiveEdgeId) {\n"
2677 << " return primitiveEdgeId;\n"
2678 << "}\n";
2679 break;
2680 default:
2681 // The functions below are used in picking (id render) and/or
2682 // selection highlighting, and are expected to be defined.
2683 // Generate fallback versions when we aren't rendering meshes.
2684 accessors
2685 << "int GetAuthoredEdgeId(int primitiveEdgeId) {\n"
2686 << " return -1;\n"
2687 << "}\n";
2688 accessors
2689 << "int GetPrimitiveEdgeId() {\n"
2690 << " return -1;\n"
2691 << "}\n";
2692 accessors
2693 << "float GetSelectedEdgeOpacity() {\n"
2694 << " return 0.0;\n"
2695 << "}\n";
2696 break;
2697 }
2698
2699 declarations
2700 << "int GetPrimitiveEdgeId();\n"
2701 << "float GetSelectedEdgeOpacity();\n";
2702
2703 // Uniform primvar data declarations & accessors
2704 if (!_geometricShader->IsPrimTypePoints()) {
2705 TF_FOR_ALL (it, _metaData.elementData) {
2706 HdBinding binding = it->first;
2707 TfToken const &name = it->second.name;
2708 TfToken const &dataType = it->second.dataType;
2709
2710 _EmitDeclaration(declarations, name, dataType, binding);
2711 // AggregatedElementID gives us the buffer index post batching, which
2712 // is what we need for accessing element (uniform) primvar data.
2713 _EmitAccessor(accessors, name, dataType, binding,"GetAggregatedElementID()");
2714 }
2715 }
2716
2717 for (size_t i = 0; i < _metaData.fvarIndicesBindings.size(); ++i) {
2718 if (!_metaData.fvarIndicesBindings[i].binding.IsValid()) {
2719 continue;
2720 }
2721
2722 HdBinding binding = _metaData.fvarIndicesBindings[i].binding;
2723 TfToken name = _metaData.fvarIndicesBindings[i].name;
2724 _EmitDeclaration(declarations, name,
2725 _metaData.fvarIndicesBindings[i].dataType,
2726 _metaData.fvarIndicesBindings[i].binding, 0);
2727
2728 if (_geometricShader->GetFvarPatchType() ==
2729 HdSt_GeometricShader::FvarPatchType::PATCH_BSPLINE ||
2730 _geometricShader->GetFvarPatchType() ==
2731 HdSt_GeometricShader::FvarPatchType::PATCH_BOXSPLINETRIANGLE) {
2732 _EmitAccessor(accessors, name,
2733 _metaData.fvarIndicesBindings[i].dataType, binding,
2734 "GetDrawingCoord().primitiveCoord * HD_NUM_PATCH_VERTS + "
2735 "localIndex");
2736 } else {
2737 _EmitAccessor(accessors,name,
2738 _metaData.fvarIndicesBindings[i].dataType, binding,
2739 "GetDrawingCoord().primitiveCoord + localIndex");
2740 }
2741 }
2742
2743 for (size_t i = 0; i < _metaData.fvarPatchParamBindings.size(); ++i) {
2744 if (!_metaData.fvarPatchParamBindings[i].binding.IsValid()) {
2745 continue;
2746 }
2747
2748 HdBinding binding = _metaData.fvarPatchParamBindings[i].binding;
2749 TfToken name = _metaData.fvarPatchParamBindings[i].name;
2750 _EmitDeclaration(declarations, name,
2751 _metaData.fvarPatchParamBindings[i].dataType,
2752 _metaData.fvarPatchParamBindings[i].binding, 0);
2753
2754 // Only need fvar patch param for bspline or box spline patches
2755 if (_geometricShader->GetFvarPatchType() ==
2756 HdSt_GeometricShader::FvarPatchType::PATCH_BSPLINE ||
2757 _geometricShader->GetFvarPatchType() ==
2758 HdSt_GeometricShader::FvarPatchType::PATCH_BOXSPLINETRIANGLE) {
2759 _EmitAccessor(accessors, name,
2760 _metaData.fvarPatchParamBindings[i].dataType, binding,
2761 "GetDrawingCoord().primitiveCoord + localIndex");
2762 }
2763 }
2764
2765 // Emit primvar declarations and accessors.
2766 _genTCS << declarations.str()
2767 << accessors.str();
2768 _genTES << declarations.str()
2769 << accessors.str();
2770 _genGS << declarations.str()
2771 << accessors.str();
2772 _genFS << declarations.str()
2773 << accessors.str();
2774 }
2775
2776 void
_GenerateVertexAndFaceVaryingPrimvar(bool hasGS)2777 HdSt_CodeGen::_GenerateVertexAndFaceVaryingPrimvar(bool hasGS)
2778 {
2779 // VS specific accessor for the "vertex drawing coordinate"
2780 // Even though we currently always plumb vertexCoord as part of the drawing
2781 // coordinate, we expect clients to use this accessor when querying the base
2782 // vertex offset for a draw call.
2783 GlfContextCaps const &caps = GlfContextCaps::GetInstance();
2784 _genVS << "int GetBaseVertexOffset() {\n";
2785 if (caps.shaderDrawParametersEnabled) {
2786 if (caps.glslVersion < 460) { // use ARB extension
2787 _genVS << " return gl_BaseVertexARB;\n";
2788 } else {
2789 _genVS << " return gl_BaseVertex;\n";
2790 }
2791 } else {
2792 _genVS << " return GetDrawingCoord().vertexCoord;\n";
2793 }
2794 _genVS << "}\n";
2795
2796 // Vertex, Varying, and FVar primvar flow into the fragment shader as
2797 // per-fragment attribute data that has been interpolated by the rasterizer,
2798 // and hence have similarities for code gen.
2799 // While vertex primvar are authored per vertex and require plumbing
2800 // through all shader stages, fVar is emitted only in the GS stage.
2801 // Varying primvar are bound in the VS via buffer array but are processed as
2802 // vertex data for the rest of the stages.
2803 /*
2804 // --------- vertex data declaration (VS) ----------
2805 layout (location = 0) in vec3 normals;
2806 layout (location = 1) in vec3 points;
2807
2808 out Primvars {
2809 vec3 normals;
2810 vec3 points;
2811 } outPrimvars;
2812
2813 void ProcessPrimvars() {
2814 outPrimvars.normals = normals;
2815 outPrimvars.points = points;
2816 }
2817
2818 // --------- geometry stage plumbing -------
2819 in Primvars {
2820 vec3 normals;
2821 vec3 points;
2822 } inPrimvars[];
2823 out Primvars {
2824 vec3 normals;
2825 vec3 points;
2826 } outPrimvars;
2827
2828 void ProcessPrimvars(int index) {
2829 outPrimvars = inPrimvars[index];
2830 }
2831
2832 // --------- vertex/varying data accessors (used in GS/FS) ---
2833 in Primvars {
2834 vec3 normals;
2835 vec3 points;
2836 } inPrimvars;
2837 vec3 HdGet_normals(int localIndex=0) {
2838 return inPrimvars.normals;
2839 }
2840 */
2841
2842 std::stringstream vertexInputs;
2843 std::stringstream interstageVertexData;
2844 std::stringstream accessorsVS, accessorsTCS, accessorsTES,
2845 accessorsGS, accessorsFS;
2846
2847 // vertex
2848 TF_FOR_ALL (it, _metaData.vertexData) {
2849 HdBinding binding = it->first;
2850 TfToken const &name = it->second.name;
2851 TfToken const &dataType = it->second.dataType;
2852
2853 // future work:
2854 // with ARB_enhanced_layouts extention, it's possible
2855 // to use "component" qualifier to declare offsetted primvars
2856 // in interleaved buffer.
2857 _EmitDeclaration(vertexInputs, name, dataType, binding);
2858
2859 interstageVertexData << " " << _GetPackedType(dataType, false)
2860 << " " << name << ";\n";
2861
2862 // primvar accessors
2863 _EmitAccessor(accessorsVS, name, dataType, binding);
2864
2865 _EmitStructAccessor(accessorsTCS, _tokens->inPrimvars,
2866 name, dataType, /*arraySize=*/1, "gl_InvocationID");
2867 _EmitStructAccessor(accessorsTES, _tokens->inPrimvars,
2868 name, dataType, /*arraySize=*/1, "localIndex");
2869 _EmitStructAccessor(accessorsGS, _tokens->inPrimvars,
2870 name, dataType, /*arraySize=*/1, "localIndex");
2871 _EmitStructAccessor(accessorsFS, _tokens->inPrimvars,
2872 name, dataType, /*arraySize=*/1);
2873
2874 // interstage plumbing
2875 _procVS << " outPrimvars." << name
2876 << " = " << name << ";\n";
2877 _procTCS << " outPrimvars[gl_InvocationID]." << name
2878 << " = inPrimvars[gl_InvocationID]." << name << ";\n";
2879 _procTES << " outPrimvars." << name
2880 << " = basis[0] * inPrimvars[i0]." << name
2881 << " + basis[1] * inPrimvars[i1]." << name
2882 << " + basis[2] * inPrimvars[i2]." << name
2883 << " + basis[3] * inPrimvars[i3]." << name << ";\n";
2884 _procGS << " outPrimvars." << name
2885 << " = inPrimvars[index]." << name << ";\n";
2886 }
2887
2888 /*
2889 // --------- varying data declaration (VS) ----------------
2890 layout (std430, binding=?) buffer buffer0 {
2891 vec3 displayColor[];
2892 };
2893
2894 vec3 HdGet_displayColor(int localIndex) {
2895 int index = GetDrawingCoord().varyingCoord + gl_VertexID -
2896 GetBaseVertexOffset();
2897 return vec3(displayColor[index]);
2898 }
2899 vec3 HdGet_displayColor() { return HdGet_displayColor(0); }
2900
2901 out Primvars {
2902 vec3 displayColor;
2903 } outPrimvars;
2904
2905 void ProcessPrimvars() {
2906 outPrimvars.displayColor = HdGet_displayColor();
2907 }
2908
2909 // --------- fragment stage plumbing -------
2910 in Primvars {
2911 vec3 displayColor;
2912 } inPrimvars;
2913 */
2914
2915 std::stringstream varyingDeclarations;
2916
2917 TF_FOR_ALL (it, _metaData.varyingData) {
2918 HdBinding binding = it->first;
2919 TfToken const &name = it->second.name;
2920 TfToken const &dataType = it->second.dataType;
2921
2922 _EmitDeclaration(varyingDeclarations, name, dataType, binding);
2923
2924 interstageVertexData << " " << _GetPackedType(dataType, false)
2925 << " " << name << ";\n";
2926
2927 // primvar accessors
2928 _EmitBufferAccessor(accessorsVS, name, dataType,
2929 "GetDrawingCoord().varyingCoord + gl_VertexID - GetBaseVertexOffset()");
2930 _EmitStructAccessor(accessorsTCS, _tokens->inPrimvars,
2931 name, dataType, /*arraySize=*/1, "gl_InvocationID");
2932 _EmitStructAccessor(accessorsTES, _tokens->inPrimvars,
2933 name, dataType, /*arraySize=*/1, "localIndex");
2934 _EmitStructAccessor(accessorsGS, _tokens->inPrimvars,
2935 name, dataType, /*arraySize=*/1, "localIndex");
2936 _EmitStructAccessor(accessorsFS, _tokens->inPrimvars,
2937 name, dataType, /*arraySize=*/1);
2938
2939 // interstage plumbing
2940 _procVS << " outPrimvars." << name
2941 << " = " << "HdGet_" << name << "();\n";
2942 _procTCS << " outPrimvars[gl_InvocationID]." << name
2943 << " = inPrimvars[gl_InvocationID]." << name << ";\n";
2944 _procTES << " outPrimvars." << name << " = ProcessPrimvar("
2945 << "inPrimvars[i0]." << name
2946 << ", inPrimvars[i1]." << name
2947 << ", inPrimvars[i2]." << name
2948 << ", inPrimvars[i3]." << name
2949 << ", basis, uv);\n";
2950 _procGS << " outPrimvars." << name
2951 << " = inPrimvars[index]." << name << ";\n";
2952 }
2953
2954 /*
2955 // --------- facevarying data declaration ----------------
2956 layout (std430, binding=?) buffer buffer0 {
2957 vec2 map1[];
2958 };
2959 layout (std430, binding=?) buffer buffer1 {
2960 float map2_u[];
2961 };
2962
2963 // --------- geometry stage plumbing -------
2964 out Primvars {
2965 ...
2966 vec2 map1;
2967 float map2_u;
2968 } outPrimvars;
2969
2970 void ProcessPrimvars(int index) {
2971 outPrimvars.map1 = HdGet_map1(index, localST);
2972 outPrimvars.map2_u = HdGet_map2_u(index, localST);
2973 }
2974
2975 // --------- fragment stage plumbing -------
2976 in Primvars {
2977 ...
2978 vec2 map1;
2979 float map2_u;
2980 } inPrimvars;
2981
2982 // --------- facevarying data accessors ----------
2983 // in geometry shader
2984 // unrefined internal accessor
2985 vec2 HdGet_map1_Coarse(int localIndex) {
2986 int fvarIndex = GetFVarIndex(localIndex);
2987 return vec2(map1[fvarIndex]);
2988 }
2989 // unrefined public accessors
2990 vec2 HdGet_map1(int localIndex, vec2 st) {
2991 int fvarIndex = GetFVarIndex(localIndex);
2992 return (HdGet_map1_Coarse(0) * ...);
2993 }
2994 vec2 HdGet_map1(int localIndex) {
2995 vec2 localST = GetPatchCoord(localIndex).xy;
2996 return HdGet_map1(localIndex, localST);
2997 }
2998
2999 // refined internal accessor
3000 vec2 HdGet_map1_Coarse(int localIndex) {
3001 int fvarIndex = GetDrawingCoord().fvarCoord + localIndex;
3002 return vec2(map1[fvarIndex]);
3003 }
3004 // refined public accessors
3005 vec2 HdGet_map1(int localIndex, vec2 st) {
3006 ivec4 indices = HdGet_fvarIndices0();
3007 return mix(mix(HdGet_map1_Coarse(indices[0])...);
3008 }
3009 // refined quads:
3010 vec2 HdGet_map1(int localIndex) {
3011 vec2 lut[4] = vec2[4](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
3012 vec2 localST = lut[localIndex];\n";
3013 return HdGet_map1(localIndex, localST);
3014 }
3015 // refined triangles:
3016 vec2 HdGet_map1(int localIndex) {
3017 vec2 lut[3] = vec2[3](vec2(0,0), vec2(1,0), vec2(0,1));
3018 vec2 localST = lut[localIndex];\n";
3019 return HdGet_map1(localIndex, localST);
3020 }
3021
3022 // refined public accessor for b-spline/box-spline patches
3023 vec2 HdGet_map1(int localIndex, vec2 st) {
3024 int patchType = OSD_PATCH_DESCRIPTOR_REGULAR; // b-spline patches
3025 // OR int patchType = OSD_PATCH_DESCRIPTOR_LOOP; for box-spline
3026 ivec2 fvarPatchParam = HdGet_fvarPatchParam0();
3027 OsdPatchParam param = OsdPatchParamInit(fvarPatchParam.x,
3028 fvarPatchParam.y, 0);
3029 float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
3030 OsdEvaluatePatchBasisNormalized(patchType, param, st.s,
3031 st.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
3032 vec2 result = vec2(0);
3033 for (int i = 0; i < HD_NUM_PATCH_VERTS; ++i) {
3034 int fvarIndex = HdGet_fvarIndices0(i);
3035 vec2 cv = vec2(HdGet_map1_Coarse(fvarIndex));
3036 result += wP[i] * cv;
3037 }
3038 return result;
3039 }
3040
3041 // in fragment shader
3042 vec2 HdGet_map1() {
3043 return inPrimvars.map1;
3044 }
3045 */
3046
3047 // face varying
3048 std::stringstream fvarDeclarations;
3049 std::stringstream interstageFVarData;
3050
3051 if (hasGS) {
3052 // FVar primvars are emitted only by the GS.
3053 // If the GS isn't active, we can skip processing them.
3054 TF_FOR_ALL (it, _metaData.fvarData) {
3055 HdBinding binding = it->first;
3056 TfToken const &name = it->second.name;
3057 TfToken const &dataType = it->second.dataType;
3058 const int channel = it->second.channel;
3059
3060 _EmitDeclaration(fvarDeclarations, name, dataType, binding);
3061
3062 interstageFVarData << " " << _GetPackedType(dataType, false)
3063 << " " << name << ";\n";
3064
3065 // primvar accessors (only in GS and FS)
3066 _EmitFVarGSAccessor(accessorsGS, name, dataType, binding,
3067 _geometricShader->GetPrimitiveType(),
3068 _geometricShader->GetFvarPatchType(),
3069 channel);
3070
3071 _EmitStructAccessor(accessorsFS, _tokens->inPrimvars, name, dataType,
3072 /*arraySize=*/1, NULL);
3073
3074 if (_geometricShader->GetFvarPatchType() ==
3075 HdSt_GeometricShader::FvarPatchType::PATCH_BSPLINE ||
3076 _geometricShader->GetFvarPatchType() ==
3077 HdSt_GeometricShader::FvarPatchType::PATCH_BOXSPLINETRIANGLE) {
3078 _procGS << " outPrimvars." << name
3079 <<" = HdGet_" << name << "(index, localST);\n";
3080 } else {
3081 _procGS << " outPrimvars." << name
3082 <<" = HdGet_" << name << "(index);\n";
3083 }
3084
3085 }
3086 }
3087
3088 if (!interstageVertexData.str().empty()) {
3089 _genVS << vertexInputs.str()
3090 << varyingDeclarations.str()
3091 << "out Primvars {\n"
3092 << interstageVertexData.str()
3093 << "} outPrimvars;\n"
3094 << accessorsVS.str();
3095
3096 _genTCS << "in Primvars {\n"
3097 << interstageVertexData.str()
3098 << "} inPrimvars[gl_MaxPatchVertices];\n"
3099 << "out Primvars {\n"
3100 << interstageVertexData.str()
3101 << "} outPrimvars[HD_NUM_PATCH_EVAL_VERTS];\n"
3102 << accessorsTCS.str();
3103
3104 _genTES << "in Primvars {\n"
3105 << interstageVertexData.str()
3106 << "} inPrimvars[gl_MaxPatchVertices];\n"
3107 << "out Primvars {\n"
3108 << interstageVertexData.str()
3109 << "} outPrimvars;\n"
3110 << accessorsTES.str();
3111
3112 _genGS << fvarDeclarations.str()
3113 << "in Primvars {\n"
3114 << interstageVertexData.str()
3115 << "} inPrimvars[HD_NUM_PRIMITIVE_VERTS];\n"
3116 << "out Primvars {\n"
3117 << interstageVertexData.str()
3118 << interstageFVarData.str()
3119 << "} outPrimvars;\n"
3120 << accessorsGS.str();
3121
3122 _genFS << "in Primvars {\n"
3123 << interstageVertexData.str()
3124 << interstageFVarData.str()
3125 << "} inPrimvars;\n"
3126 << accessorsFS.str();
3127 }
3128
3129 // ---------
3130 _genFS << "vec4 GetPatchCoord(int index);\n";
3131 _genFS << "vec4 GetPatchCoord() { return GetPatchCoord(0); }\n";
3132
3133 _genGS << "vec4 GetPatchCoord(int localIndex);\n";
3134 }
3135
3136 void
_GenerateShaderParameters()3137 HdSt_CodeGen::_GenerateShaderParameters()
3138 {
3139 /*
3140 ------------- Declarations -------------
3141
3142 // shader parameter buffer
3143 struct ShaderData {
3144 <type> <name>;
3145 vec4 diffuseColor; // fallback uniform
3146 sampler2D kdTexture; // uv texture (bindless texture)
3147 sampler2DArray ptexTexels; // ptex texels (bindless texture)
3148 usamplerBuffer ptexLayouts; // ptex layouts (bindless texture)
3149 };
3150
3151 // bindless buffer
3152 layout (location=0) uniform ShaderData *shaderData;
3153 // not bindless buffer
3154 layout (std430, binding=0) buffer {
3155 ShaderData shaderData[];
3156 };
3157
3158 // non bindless textures
3159 uniform sampler2D samplers_2d[N];
3160 uniform sampler2DArray samplers_2darray[N];
3161 uniform isamplerBuffer isamplerBuffers[N];
3162
3163 ------------- Accessors -------------
3164
3165 * fallback value
3166 <type> HdGet_<name>(int localIndex=0) {
3167 return shaderData[GetDrawingCoord().shaderCoord].<name>
3168 }
3169
3170 * primvar redirect
3171 <type> HdGet_<name>(int localIndex=0) {
3172 return HdGet_<inPrimvars>().xxx;
3173 }
3174
3175 * bindless 2D texture
3176 <type> HdGet_<name>(int localIndex=0) {
3177 return texture(sampler2D(shaderData[GetDrawingCoord().shaderCoord].<name>), <inPrimvars>).xxx;
3178 }
3179
3180 * non-bindless 2D texture
3181 <type> HdGet_<name>(int localIndex=0) {
3182 return texture(samplers_2d[<offset> + drawIndex * <stride>], <inPrimvars>).xxx;
3183 }
3184
3185 * bindless Ptex texture
3186 <type> HdGet_<name>(int localIndex=0) {
3187 return GlopPtexTextureLookup(<name>_Data, <name>_Packing, GetPatchCoord()).xxx;
3188 }
3189
3190 * non-bindless Ptex texture
3191 <type> HdGet_<name>(int localIndex=0) {
3192 return GlopPtexTextureLookup(
3193 samplers_2darray[<offset_ptex_texels> + drawIndex * <stride>],
3194 usamplerBuffers[<offset_ptex_layouts> + drawIndex * <stride>],
3195 GetPatchCoord()).xxx;
3196 }
3197
3198 * bindless Ptex texture with patchcoord
3199 <type> HdGet_<name>(vec4 patchCoord) {
3200 return GlopPtexTextureLookup(<name>_Data, <name>_Packing, patchCoord).xxx;
3201 }
3202
3203 * non-bindless Ptex texture
3204 <type> HdGet_<name>(vec4 patchCoord) {
3205 return GlopPtexTextureLookup(
3206 samplers_2darray[<offset_ptex_texels> + drawIndex * <stride>],
3207 usamplerBuffers[<offset_ptex_layouts> + drawIndex * <stride>],
3208 patchCoord).xxx;
3209 }
3210
3211 * transform2d
3212 vec2 HdGet_<name>(int localIndex=0) {
3213 float angleRad = HdGet_<name>_rotation() * 3.1415926f / 180.f;
3214 mat2 rotMat = mat2(cos(angleRad), sin(angleRad),
3215 -sin(angleRad), cos(angleRad));
3216 #if defined(HD_HAS_<primvarName>)
3217 return vec2(HdGet_<name>_translation() + rotMat *
3218 (HdGet_<name>_scale() * HdGet_<primvarName>(localIndex)));
3219 #else
3220 int shaderCoord = GetDrawingCoord().shaderCoord;
3221 return vec2(HdGet_<name>_translation() + rotMat *
3222 (HdGet_<name>_scale() * shaderData[shaderCoord].<name>_fallback.xy));
3223 #endif
3224 }
3225
3226 */
3227
3228 std::stringstream declarations;
3229 std::stringstream accessors;
3230
3231 GlfContextCaps const &caps = GlfContextCaps::GetInstance();
3232
3233 TfToken typeName("ShaderData");
3234 TfToken varName("shaderData");
3235
3236 // for shader parameters, we create declarations and accessors separetely.
3237 TF_FOR_ALL (it, _metaData.shaderData) {
3238 HdBinding binding = it->first;
3239
3240 declarations << "struct " << typeName << " {\n";
3241
3242 TF_FOR_ALL (dbIt, it->second.entries) {
3243 declarations << " " << _GetPackedType(dbIt->dataType, false)
3244 << " " << dbIt->name
3245 << ";\n";
3246
3247 }
3248 declarations << "};\n";
3249
3250 // for array delaration, SSBO and bindless uniform can use [].
3251 // UBO requires the size [N].
3252 // XXX: [1] is a hack to cheat driver not telling the actual size.
3253 // may not work some GPUs.
3254 // XXX: we only have 1 shaderData entry (interleaved).
3255 int arraySize = (binding.GetType() == HdBinding::UBO) ? 1 : 0;
3256 _EmitDeclaration(declarations, varName, typeName, binding, arraySize);
3257
3258 break;
3259 }
3260
3261 // Non-field redirect accessors.
3262 TF_FOR_ALL (it, _metaData.shaderParameterBinding) {
3263
3264 // adjust datatype
3265 std::string swizzle = _GetSwizzleString(it->second.dataType,
3266 it->second.swizzle);
3267
3268 HdBinding::Type bindingType = it->first.GetType();
3269 if (bindingType == HdBinding::FALLBACK) {
3270 // vec4 HdGet_name(int localIndex)
3271 accessors
3272 << _GetUnpackedType(it->second.dataType, false)
3273 << " HdGet_" << it->second.name << "(int localIndex) {\n"
3274 << " int shaderCoord = GetDrawingCoord().shaderCoord; \n"
3275 << " return "
3276 << _GetPackedTypeAccessor(it->second.dataType, false)
3277 << "(shaderData[shaderCoord]."
3278 << it->second.name << HdSt_ResourceBindingSuffixTokens->fallback
3279 << swizzle
3280 << ");\n"
3281 << "}\n";
3282
3283 // vec4 HdGet_name()
3284 accessors
3285 << _GetUnpackedType(it->second.dataType, false)
3286 << " HdGet_" << it->second.name
3287 << "() { return HdGet_" << it->second.name << "(0); }\n";
3288
3289 } else if (bindingType == HdBinding::BINDLESS_TEXTURE_2D) {
3290 // a function returning sampler requires bindless_texture
3291
3292 _EmitTextureAccessors(
3293 accessors, it->second, swizzle,
3294 /* dim = */ 2,
3295 /* hasTextureTransform = */ false,
3296 /* hasTextureScaleAndBias = */ true,
3297 /* isBindless = */ true);
3298
3299 } else if (bindingType == HdBinding::TEXTURE_2D) {
3300
3301 declarations
3302 << LayoutQualifier(it->first)
3303 << "uniform sampler2D sampler2d_" << it->second.name << ";\n";
3304
3305 _EmitTextureAccessors(
3306 accessors, it->second, swizzle,
3307 /* dim = */ 2,
3308 /* hasTextureTransform = */ false,
3309 /* hasTextureScaleAndBias = */ true,
3310 /* isBindless = */ false);
3311
3312 } else if (bindingType == HdBinding::BINDLESS_TEXTURE_FIELD) {
3313
3314 _EmitTextureAccessors(
3315 accessors, it->second, swizzle,
3316 /* dim = */ 3,
3317 /* hasTextureTransform = */ true,
3318 /* hasTextureScaleAndBias = */ false,
3319 /* isBindless = */ true);
3320
3321 } else if (bindingType == HdBinding::TEXTURE_FIELD) {
3322
3323 declarations
3324 << LayoutQualifier(it->first)
3325 << "uniform sampler3D sampler3d_" << it->second.name << ";\n";
3326
3327 _EmitTextureAccessors(
3328 accessors, it->second, swizzle,
3329 /* dim = */ 3,
3330 /* hasTextureTransform = */ true,
3331 /* hasTextureScaleAndBias = */ false,
3332 /* isBindless = */ false);
3333
3334 } else if (bindingType == HdBinding::BINDLESS_TEXTURE_UDIM_ARRAY) {
3335 accessors
3336 << "#ifdef HD_HAS_" << it->second.name << "_"
3337 << HdStTokens->scale << "\n"
3338 << "vec4 HdGet_" << it->second.name << "_"
3339 << HdStTokens->scale << "();\n"
3340 << "#endif\n"
3341 << "#ifdef HD_HAS_" << it->second.name << "_"
3342 << HdStTokens->bias << "\n"
3343 << "vec4 HdGet_" << it->second.name << "_"
3344 << HdStTokens->bias << "();\n"
3345 << "#endif\n";
3346
3347 // a function returning sampler requires bindless_texture
3348 if (caps.bindlessTextureEnabled) {
3349 accessors
3350 << "sampler2DArray\n"
3351 << "HdGetSampler_" << it->second.name << "() {\n"
3352 << " int shaderCoord = GetDrawingCoord().shaderCoord; \n"
3353 << " return sampler2DArray(shaderData[shaderCoord]."
3354 << it->second.name << ");\n"
3355 << "}\n";
3356 }
3357 accessors
3358 << it->second.dataType
3359 << " HdGet_" << it->second.name << "()" << " {\n"
3360 << " int shaderCoord = GetDrawingCoord().shaderCoord;\n";
3361 if (!it->second.inPrimvars.empty()) {
3362 accessors
3363 << " vec3 c = vec3(0.0, 0.0, 0.0);\n"
3364 << "#if defined(HD_HAS_"
3365 << it->second.inPrimvars[0] << ")\n"
3366 << " uvec2 handle = shaderData[shaderCoord]."
3367 << it->second.name
3368 << HdSt_ResourceBindingSuffixTokens->layout << ";\n"
3369 << " if (handle != uvec2(0)) {\n"
3370 << " c = hd_sample_udim(HdGet_"
3371 << it->second.inPrimvars[0] << "().xy);\n"
3372 << " c.z = "
3373 << "texelFetch(sampler1D(handle), int(c.z), 0).x - 1;\n"
3374 << " }\n"
3375 << "#endif\n";
3376 } else {
3377 accessors
3378 << " vec3 c = vec3(0.0, 0.0, 0.0);\n";
3379 }
3380 accessors
3381 << " vec4 ret = vec4(0, 0, 0, 0);\n"
3382 << " if (c.z >= -0.5) {\n"
3383 << " uvec2 handleTexels = shaderData[shaderCoord]."
3384 << it->second.name << ";\n"
3385 << " if (handleTexels != uvec2(0)) {\n"
3386 << " ret = texture(sampler2DArray(handleTexels), c);\n"
3387 << " }\n }\n"
3388 << " return (ret\n"
3389 << "#ifdef HD_HAS_" << it->second.name << "_"
3390 << HdStTokens->scale << "\n"
3391 << " * HdGet_" << it->second.name << "_"
3392 << HdStTokens->scale << "()\n"
3393 << "#endif\n"
3394 << "#ifdef HD_HAS_" << it->second.name << "_"
3395 << HdStTokens->bias << "\n"
3396 << " + HdGet_" << it->second.name << "_"
3397 << HdStTokens->bias << "()\n"
3398 << "#endif\n"
3399 << " )" << swizzle << ";\n}\n";
3400
3401 // Create accessor for texture coordinates based on param name
3402 // vec2 HdGetCoord_name()
3403 accessors
3404 << "vec2 HdGetCoord_" << it->second.name << "() {\n"
3405 << " return \n";
3406 if (!it->second.inPrimvars.empty()) {
3407 accessors
3408 << "#if defined(HD_HAS_" << it->second.inPrimvars[0] <<")\n"
3409 << " HdGet_" << it->second.inPrimvars[0] << "().xy;\n"
3410 << "#else\n"
3411 << " vec2(0.0, 0.0)\n"
3412 << "#endif\n";
3413 } else {
3414 accessors
3415 << " vec2(0.0, 0.0)\n";
3416 }
3417 accessors << "; }\n";
3418
3419 // Emit pre-multiplication by alpha indicator
3420 if (it->second.isPremultiplied) {
3421 accessors
3422 << "#define " << it->second.name << "_IS_PREMULTIPLIED 1\n";
3423 }
3424 } else if (bindingType == HdBinding::TEXTURE_UDIM_ARRAY) {
3425 accessors
3426 << "#ifdef HD_HAS_" << it->second.name << "_"
3427 << HdStTokens->scale << "\n"
3428 << "vec4 HdGet_" << it->second.name << "_"
3429 << HdStTokens->scale << "();\n"
3430 << "#endif\n"
3431 << "#ifdef HD_HAS_" << it->second.name << "_"
3432 << HdStTokens->bias << "\n"
3433 << "vec4 HdGet_" << it->second.name << "_"
3434 << HdStTokens->bias << "();\n"
3435 << "#endif\n";
3436
3437 declarations
3438 << LayoutQualifier(it->first)
3439 << "uniform sampler2DArray sampler2dArray_"
3440 << it->second.name << ";\n";
3441
3442 // a function returning sampler requires bindless_texture
3443 if (caps.bindlessTextureEnabled) {
3444 accessors
3445 << "sampler2DArray\n"
3446 << "HdGetSampler_" << it->second.name << "() {\n"
3447 << " return sampler2dArray_" << it->second.name << ";"
3448 << "}\n";
3449 } else {
3450 accessors
3451 << "#define HdGetSampler_" << it->second.name << "()"
3452 << " sampler2dArray_" << it->second.name << "\n";
3453 }
3454 // vec4 HdGet_name(vec2 coord) { vec3 c = hd_sample_udim(coord);
3455 // c.z = texelFetch(sampler1d_name_layout, int(c.z), 0).x - 1;
3456 // vec4 ret = vec4(0, 0, 0, 0);
3457 // if (c.z >= -0.5) { ret = texture(sampler2dArray_name, c); }
3458 // return (ret
3459 // #ifdef HD_HAS_name_scale
3460 // * HdGet_name_scale()
3461 // #endif
3462 // #ifdef HD_HAS_name_bias
3463 // + HdGet_name_bias()
3464 // #endif
3465 // ).xyz; }
3466 accessors
3467 << it->second.dataType
3468 << " HdGet_" << it->second.name
3469 << "(vec2 coord) { vec3 c = hd_sample_udim(coord);\n"
3470 << " c.z = texelFetch(sampler1d_"
3471 << it->second.name << HdSt_ResourceBindingSuffixTokens->layout
3472 << ", int(c.z), 0).x - 1;\n"
3473 << " vec4 ret = vec4(0, 0, 0, 0);\n"
3474 << " if (c.z >= -0.5) { ret = texture(sampler2dArray_"
3475 << it->second.name << ", c); }\n return (ret\n"
3476 << "#ifdef HD_HAS_" << it->second.name << "_"
3477 << HdStTokens->scale << "\n"
3478 << " * HdGet_" << it->second.name << "_"
3479 << HdStTokens->scale << "()\n"
3480 << "#endif\n"
3481 << "#ifdef HD_HAS_" << it->second.name << "_"
3482 << HdStTokens->bias << "\n"
3483 << " + HdGet_" << it->second.name << "_"
3484 << HdStTokens->bias << "()\n"
3485 << "#endif\n"
3486 << " )" << swizzle << ";\n}\n";
3487
3488 // Create accessor for texture coordinates based on param name
3489 // vec2 HdGetCoord_name()
3490 accessors
3491 << "vec2 HdGetCoord_" << it->second.name << "() {\n"
3492 << " return \n";
3493 if (!it->second.inPrimvars.empty()) {
3494 accessors
3495 << "#if defined(HD_HAS_" << it->second.inPrimvars[0] <<")\n"
3496 << " HdGet_" << it->second.inPrimvars[0] << "().xy\n"
3497 << "#else\n"
3498 << " vec2(0.0, 0.0)\n"
3499 << "#endif\n";
3500 } else {
3501 accessors
3502 << " vec2(0.0, 0.0)\n";
3503 }
3504 accessors << "; }\n";
3505
3506 // vec4 HdGet_name() { return HdGet_name(HdGetCoord_name()); }
3507 accessors
3508 << it->second.dataType
3509 << " HdGet_" << it->second.name
3510 << "() { return HdGet_" << it->second.name << "("
3511 << "HdGetCoord_" << it->second.name << "()); }\n";
3512
3513 // Emit pre-multiplication by alpha indicator
3514 if (it->second.isPremultiplied) {
3515 accessors
3516 << "#define " << it->second.name << "_IS_PREMULTIPLIED 1\n";
3517 }
3518 } else if (bindingType == HdBinding::TEXTURE_UDIM_LAYOUT) {
3519 declarations
3520 << LayoutQualifier(it->first)
3521 << "uniform sampler1D sampler1d_" << it->second.name << ";\n";
3522 } else if (bindingType == HdBinding::BINDLESS_TEXTURE_PTEX_TEXEL) {
3523 accessors
3524 << _GetUnpackedType(it->second.dataType, false)
3525 << " HdGet_" << it->second.name << "(int localIndex) {\n"
3526 << " int shaderCoord = GetDrawingCoord().shaderCoord; \n"
3527 << " return " << _GetPackedTypeAccessor(it->second.dataType, false)
3528 << "(PtexTextureLookup("
3529 << "sampler2DArray(shaderData[shaderCoord]."
3530 << it->second.name << "),"
3531 << "usampler1DArray(shaderData[shaderCoord]."
3532 << it->second.name << HdSt_ResourceBindingSuffixTokens->layout
3533 <<"), "
3534 << "GetPatchCoord(localIndex))" << swizzle << ");\n"
3535 << "}\n"
3536 << _GetUnpackedType(it->second.dataType, false)
3537 << " HdGet_" << it->second.name << "()"
3538 << "{ return HdGet_" << it->second.name << "(0); }\n"
3539 << _GetUnpackedType(it->second.dataType, false)
3540 << " HdGet_" << it->second.name << "(vec4 patchCoord) {\n"
3541 << " int shaderCoord = GetDrawingCoord().shaderCoord; \n"
3542 << " return " << _GetPackedTypeAccessor(it->second.dataType, false)
3543 << "(PtexTextureLookup("
3544 << "sampler2DArray(shaderData[shaderCoord]."
3545 << it->second.name << "),"
3546 << "usampler1DArray(shaderData[shaderCoord]."
3547 << it->second.name << HdSt_ResourceBindingSuffixTokens->layout
3548 << "), "
3549 << "patchCoord)" << swizzle << ");\n"
3550 << "}\n";
3551
3552 // Emit pre-multiplication by alpha indicator
3553 if (it->second.isPremultiplied) {
3554 accessors
3555 << "#define " << it->second.name << "_IS_PREMULTIPLIED 1\n";
3556 }
3557 } else if (bindingType == HdBinding::TEXTURE_PTEX_TEXEL) {
3558 declarations
3559 << LayoutQualifier(it->first)
3560 << "uniform sampler2DArray sampler2darray_"
3561 << it->second.name << ";\n";
3562 accessors
3563 << _GetUnpackedType(it->second.dataType, false)
3564 << " HdGet_" << it->second.name << "(int localIndex) {\n"
3565 << " return " << _GetPackedTypeAccessor(it->second.dataType, false)
3566 << "(PtexTextureLookup("
3567 << "sampler2darray_" << it->second.name << ", "
3568 << "usampler1darray_"
3569 << it->second.name << HdSt_ResourceBindingSuffixTokens->layout
3570 << ", "
3571 << "GetPatchCoord(localIndex))" << swizzle << ");\n"
3572 << "}\n"
3573 << _GetUnpackedType(it->second.dataType, false)
3574 << " HdGet_" << it->second.name << "()"
3575 << "{ return HdGet_" << it->second.name << "(0); }\n"
3576 << _GetUnpackedType(it->second.dataType, false)
3577 << " HdGet_" << it->second.name << "(vec4 patchCoord) {\n"
3578 << " return " << _GetPackedTypeAccessor(it->second.dataType, false)
3579 << "(PtexTextureLookup("
3580 << "sampler2darray_" << it->second.name << ", "
3581 << "usampler1darray_"
3582 << it->second.name << HdSt_ResourceBindingSuffixTokens->layout
3583 << ", "
3584 << "patchCoord)" << swizzle << ");\n"
3585 << "}\n";
3586
3587 // Emit pre-multiplication by alpha indicator
3588 if (it->second.isPremultiplied) {
3589 accessors
3590 << "#define " << it->second.name << "_IS_PREMULTIPLIED 1\n";
3591 }
3592 } else if (bindingType == HdBinding::BINDLESS_TEXTURE_PTEX_LAYOUT) {
3593 //accessors << _GetUnpackedType(it->second.dataType) << "(0)";
3594 } else if (bindingType == HdBinding::TEXTURE_PTEX_LAYOUT) {
3595 declarations
3596 << LayoutQualifier(HdBinding(it->first.GetType(),
3597 it->first.GetLocation(),
3598 it->first.GetTextureUnit()))
3599 << "uniform usampler1DArray usampler1darray_"
3600 << it->second.name << ";\n";
3601 } else if (bindingType == HdBinding::PRIMVAR_REDIRECT) {
3602 // Create an HdGet_INPUTNAME for the shader to access a primvar
3603 // for which a HdGet_PRIMVARNAME was already generated earlier.
3604
3605 // XXX: shader and primvar name collisions are a problem!
3606 // (see, e.g., HYD-1800).
3607 if (it->second.name == it->second.inPrimvars[0]) {
3608 // Avoid the following:
3609 // If INPUTNAME and PRIMVARNAME are the same and the
3610 // primvar exists, we would generate two functions
3611 // both called HdGet_PRIMVAR, one to read the primvar
3612 // (based on _metaData.constantData) and one for the
3613 // primvar redirect here.
3614 accessors
3615 << "#if !defined(HD_HAS_" << it->second.name << ")\n";
3616 }
3617
3618 accessors
3619 << _GetUnpackedType(it->second.dataType, false)
3620 << " HdGet_" << it->second.name << "() {\n"
3621 // If primvar exists, use it
3622 << "#if defined(HD_HAS_" << it->second.inPrimvars[0] << ")\n"
3623 << " return HdGet_" << it->second.inPrimvars[0] << "();\n"
3624 << "#else\n"
3625 // Otherwise use default value.
3626 << " int shaderCoord = GetDrawingCoord().shaderCoord;\n"
3627 << " return "
3628 << _GetPackedTypeAccessor(it->second.dataType, false)
3629 << "(shaderData[shaderCoord]."
3630 << it->second.name << HdSt_ResourceBindingSuffixTokens->fallback
3631 << swizzle << ");\n"
3632 << "#endif\n"
3633 << "\n}\n"
3634 << "#define HD_HAS_" << it->second.name << " 1\n";
3635
3636 if (it->second.name == it->second.inPrimvars[0]) {
3637 accessors
3638 << "#endif\n";
3639 }
3640 } else if (bindingType == HdBinding::TRANSFORM_2D) {
3641 // Forward declare rotation, scale, and translation
3642 accessors
3643 << "float HdGet_" << it->second.name << "_"
3644 << HdStTokens->rotation << "();\n"
3645 << "vec2 HdGet_" << it->second.name << "_"
3646 << HdStTokens->scale << "();\n"
3647 << "vec2 HdGet_" << it->second.name << "_"
3648 << HdStTokens->translation << "();\n";
3649
3650 // vec2 HdGet_name(int localIndex)
3651 accessors
3652 << _GetUnpackedType(it->second.dataType, false)
3653 << " HdGet_" << it->second.name << "(int localIndex) {\n"
3654 << " float angleRad = HdGet_" << it->second.name << "_"
3655 << HdStTokens->rotation << "()"
3656 << " * 3.1415926f / 180.f;\n"
3657 << " mat2 rotMat = mat2(cos(angleRad), sin(angleRad), "
3658 << "-sin(angleRad), cos(angleRad)); \n";
3659 // If primvar exists, use it
3660 if (!it->second.inPrimvars.empty()) {
3661 accessors
3662 << "#if defined(HD_HAS_" << it->second.inPrimvars[0] << ")\n"
3663 << " return vec2(HdGet_" << it->second.name << "_"
3664 << HdStTokens->translation << "() + rotMat * (HdGet_"
3665 << it->second.name << "_" << HdStTokens->scale << "() * "
3666 << "HdGet_" << it->second.inPrimvars[0] << "(localIndex)));\n"
3667 << "#else\n";
3668 }
3669 // Otherwise use default value.
3670 accessors
3671 << " int shaderCoord = GetDrawingCoord().shaderCoord;\n"
3672 << " return vec2(HdGet_" << it->second.name << "_"
3673 << HdStTokens->translation << "() + rotMat * (HdGet_"
3674 << it->second.name << "_" << HdStTokens->scale << "() * "
3675 << "shaderData[shaderCoord]." << it->second.name
3676 << HdSt_ResourceBindingSuffixTokens->fallback << swizzle
3677 << "));\n";
3678 if (!it->second.inPrimvars.empty()) {
3679 accessors << "#endif\n";
3680 }
3681 accessors << "}\n";
3682
3683 // vec2 HdGet_name()
3684 accessors
3685 << _GetUnpackedType(it->second.dataType, false)
3686 << " HdGet_" << it->second.name << "() {\n"
3687 << " return HdGet_" << it->second.name << "(0);\n"
3688 << "}\n";
3689 }
3690 }
3691
3692
3693 accessors
3694 << "void ProcessSamplingTransforms("
3695 << "MAT4 instanceModelViewInverse) {\n";
3696
3697 TF_FOR_ALL (it, _metaData.shaderParameterBinding) {
3698 const HdBinding::Type bindingType = it->first.GetType();
3699
3700 if ( bindingType == HdBinding::TEXTURE_FIELD ||
3701 bindingType == HdBinding::BINDLESS_TEXTURE_FIELD) {
3702
3703 const std::string eyeToSamplingTransform =
3704 "eyeTo" + it->second.name.GetString() + "SamplingTransform";
3705
3706 accessors
3707 << " Process_" << eyeToSamplingTransform
3708 << "(instanceModelViewInverse);\n";
3709 }
3710 }
3711
3712 accessors
3713 << "}\n";
3714
3715 // Field redirect accessors, need to access above field textures.
3716 TF_FOR_ALL (it, _metaData.shaderParameterBinding) {
3717 HdBinding::Type bindingType = it->first.GetType();
3718
3719 if (bindingType == HdBinding::FIELD_REDIRECT) {
3720
3721 // adjust datatype
3722 std::string swizzle = _GetSwizzleString(it->second.dataType);
3723
3724 const TfToken fieldName =
3725 it->second.inPrimvars.empty()
3726 ? TfToken("FIELDNAME_WAS_NOT_SPECIFIED")
3727 : it->second.inPrimvars[0];
3728
3729 // Create an HdGet_INPUTNAME(vec3) for the shader to access a
3730 // field texture HdGet_FIELDNAMETexture(vec3).
3731 accessors
3732 << _GetUnpackedType(it->second.dataType, false)
3733 << " HdGet_" << it->second.name << "(vec3 coord) {\n"
3734 // If field exists, use it
3735 << "#if defined(HD_HAS_"
3736 << fieldName << HdSt_ResourceBindingSuffixTokens->texture
3737 << ")\n"
3738 << " return HdGet_"
3739 << fieldName << HdSt_ResourceBindingSuffixTokens->texture
3740 << "(coord)"
3741 << swizzle << ";\n"
3742 << "#else\n"
3743 // Otherwise use default value.
3744 << " int shaderCoord = GetDrawingCoord().shaderCoord;\n"
3745 << " return "
3746 << _GetPackedTypeAccessor(it->second.dataType, false)
3747 << "(shaderData[shaderCoord]."
3748 << it->second.name << HdSt_ResourceBindingSuffixTokens->fallback
3749 << ");\n"
3750 << "#endif\n"
3751 << "\n}\n";
3752 }
3753 }
3754
3755 _genFS << declarations.str()
3756 << accessors.str();
3757
3758 _genGS << declarations.str()
3759 << accessors.str();
3760 }
3761
3762 void
_GenerateTopologyVisibilityParameters()3763 HdSt_CodeGen::_GenerateTopologyVisibilityParameters()
3764 {
3765 std::stringstream declarations;
3766 std::stringstream accessors;
3767 TF_FOR_ALL (it, _metaData.topologyVisibilityData) {
3768 // See note in _GenerateConstantPrimvar re: padding.
3769 HdBinding binding = it->first;
3770 TfToken typeName(TfStringPrintf("TopologyVisibilityData%d",
3771 binding.GetValue()));
3772 TfToken varName = it->second.blockName;
3773
3774 declarations << "struct " << typeName << " {\n";
3775
3776 TF_FOR_ALL (dbIt, it->second.entries) {
3777 if (!TF_VERIFY(!dbIt->dataType.IsEmpty(),
3778 "Unknown dataType for %s",
3779 dbIt->name.GetText())) {
3780 continue;
3781 }
3782
3783 declarations << " " << _GetPackedType(dbIt->dataType, false)
3784 << " " << dbIt->name;
3785 if (dbIt->arraySize > 1) {
3786 declarations << "[" << dbIt->arraySize << "]";
3787 }
3788
3789 declarations << ";\n";
3790
3791 _EmitStructAccessor(accessors, varName, dbIt->name, dbIt->dataType,
3792 dbIt->arraySize,
3793 "GetDrawingCoord().topologyVisibilityCoord");
3794 }
3795 declarations << "};\n";
3796
3797 _EmitDeclaration(declarations, varName, typeName, binding,
3798 /*arraySize=*/1);
3799 }
3800 _genCommon << declarations.str()
3801 << accessors.str();
3802 }
3803
3804 PXR_NAMESPACE_CLOSE_SCOPE
3805
3806