1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #include "pxr/imaging/garch/glApi.h"
25
26 #include "pxr/imaging/glf/diagnostic.h"
27
28 #include "pxr/imaging/hdSt/immediateDrawBatch.h"
29
30 #include "pxr/imaging/hdSt/bufferArrayRange.h"
31 #include "pxr/imaging/hdSt/commandBuffer.h"
32 #include "pxr/imaging/hdSt/drawItem.h"
33 #include "pxr/imaging/hdSt/drawItemInstance.h"
34 #include "pxr/imaging/hdSt/geometricShader.h"
35 #include "pxr/imaging/hdSt/glslProgram.h"
36 #include "pxr/imaging/hdSt/renderPassState.h"
37 #include "pxr/imaging/hdSt/resourceRegistry.h"
38 #include "pxr/imaging/hdSt/shaderCode.h"
39
40 #include "pxr/imaging/hd/debugCodes.h"
41 #include "pxr/imaging/hd/mesh.h"
42 #include "pxr/imaging/hd/perfLog.h"
43 #include "pxr/imaging/hd/tokens.h"
44
45 #include "pxr/base/tf/diagnostic.h"
46
47 PXR_NAMESPACE_OPEN_SCOPE
48
49
HdSt_ImmediateDrawBatch(HdStDrawItemInstance * drawItemInstance)50 HdSt_ImmediateDrawBatch::HdSt_ImmediateDrawBatch(
51 HdStDrawItemInstance * drawItemInstance)
52 : HdSt_DrawBatch(drawItemInstance)
53 {
54 _Init(drawItemInstance);
55 }
56
57 void
_Init(HdStDrawItemInstance * drawItemInstance)58 HdSt_ImmediateDrawBatch::_Init(HdStDrawItemInstance * drawItemInstance)
59 {
60 HdSt_DrawBatch::_Init(drawItemInstance);
61 drawItemInstance->SetBatchIndex(0);
62 drawItemInstance->SetBatch(this);
63 _bufferArraysHash =
64 drawItemInstance->GetDrawItem()->GetBufferArraysHash();
65 }
66
~HdSt_ImmediateDrawBatch()67 HdSt_ImmediateDrawBatch::~HdSt_ImmediateDrawBatch()
68 {
69 }
70
71 HdSt_DrawBatch::ValidationResult
Validate(bool deepValidation)72 HdSt_ImmediateDrawBatch::Validate(bool deepValidation)
73 {
74 if (!TF_VERIFY(!_drawItemInstances.empty())) {
75 return ValidationResult::RebuildAllBatches;
76 }
77
78 HdStDrawItem const* batchItem = _drawItemInstances.front()->GetDrawItem();
79
80 // check the hash to see if anything's been reallocated/migrated.
81 // note that we just need to compare the hash of the first item,
82 // since draw items are aggregated and ensure that they are sharing
83 // the same buffer arrays.
84 size_t bufferArraysHash = batchItem->GetBufferArraysHash();
85 if (_bufferArraysHash != bufferArraysHash) {
86 _bufferArraysHash = bufferArraysHash;
87 return ValidationResult::RebuildBatch;
88 }
89
90 // Deep validation is flagged explicitly when a drawItem has changes to
91 // its BARs (e.g. buffer spec, aggregation) or when its
92 // surface shader or geometric shader changes.
93 if (deepValidation) {
94 HD_TRACE_SCOPE("Immediate draw batch deep validation");
95
96 // look through all draw items to be still compatible
97
98 size_t numDrawItemInstances = _drawItemInstances.size();
99 for (size_t item = 0; item < numDrawItemInstances; ++item) {
100 HdStDrawItem const * drawItem
101 = _drawItemInstances[item]->GetDrawItem();
102
103 if (!TF_VERIFY(drawItem->GetGeometricShader())) {
104 return ValidationResult::RebuildAllBatches;
105 }
106
107 if (!_IsAggregated(batchItem, drawItem)) {
108 return ValidationResult::RebuildAllBatches;
109 }
110 }
111 }
112
113 return ValidationResult::ValidBatch;
114 }
115
116 void
PrepareDraw(HdStRenderPassStateSharedPtr const & renderPassState,HdStResourceRegistrySharedPtr const & resourceRegistry)117 HdSt_ImmediateDrawBatch::PrepareDraw(
118 HdStRenderPassStateSharedPtr const &renderPassState,
119 HdStResourceRegistrySharedPtr const &resourceRegistry)
120 {
121 }
122
123 static int
_GetElementOffset(HdBufferArrayRangeSharedPtr const & range)124 _GetElementOffset(HdBufferArrayRangeSharedPtr const& range)
125 {
126 return range? range->GetElementOffset() : 0;
127 }
128
129 void
ExecuteDraw(HdStRenderPassStateSharedPtr const & renderPassState,HdStResourceRegistrySharedPtr const & resourceRegistry)130 HdSt_ImmediateDrawBatch::ExecuteDraw(
131 HdStRenderPassStateSharedPtr const &renderPassState,
132 HdStResourceRegistrySharedPtr const &resourceRegistry)
133 {
134 HD_TRACE_FUNCTION();
135 GLF_GROUP_FUNCTION();
136
137 HdStBufferArrayRangeSharedPtr indexBarCurrent;
138 HdStBufferArrayRangeSharedPtr topVisBarCurrent;
139 HdStBufferArrayRangeSharedPtr elementBarCurrent;
140 HdStBufferArrayRangeSharedPtr vertexBarCurrent;
141 HdStBufferArrayRangeSharedPtr varyingBarCurrent;
142 HdStBufferArrayRangeSharedPtr constantBarCurrent;
143 HdStBufferArrayRangeSharedPtr fvarBarCurrent;
144 HdStBufferArrayRangeSharedPtr instanceIndexBarCurrent;
145 HdStBufferArrayRangeSharedPtr shaderBarCurrent;
146 std::vector<HdStBufferArrayRangeSharedPtr> instanceBarCurrents;
147
148 if (_drawItemInstances.empty()) return;
149
150 if (!glUseProgram) return; // glew initialized
151
152 // bind program
153 _DrawingProgram & program = _GetDrawingProgram(renderPassState,
154 /*indirect=*/false,
155 resourceRegistry);
156
157 HdStGLSLProgramSharedPtr const &glslProgram = program.GetGLSLProgram();
158 if (!TF_VERIFY(glslProgram)) return;
159 if (!TF_VERIFY(glslProgram->Validate())) return;
160
161 const HdSt_ResourceBinder &binder = program.GetBinder();
162 const HdStShaderCodeSharedPtrVector &shaders = program.GetComposedShaders();
163
164 GLuint programId = glslProgram->GetProgram()->GetRawResource();
165 TF_VERIFY(programId);
166
167 glUseProgram(programId);
168
169 for (HdStShaderCodeSharedPtr const & shader : shaders) {
170 shader->BindResources(programId, binder, *renderPassState);
171 }
172
173 // Set up geometric shader states
174 // all batch item should have the same geometric shader.
175 HdSt_GeometricShaderSharedPtr const &geometricShader
176 = program.GetGeometricShader();
177 geometricShader->BindResources(programId, binder, *renderPassState);
178
179 size_t numItemsDrawn = 0;
180 for (HdStDrawItemInstance const * drawItemInstance : _drawItemInstances) {
181 if(!drawItemInstance->IsVisible()) {
182 continue;
183 }
184
185 HdStDrawItem const * drawItem = drawItemInstance->GetDrawItem();
186
187 ++numItemsDrawn;
188
189 //
190 // index buffer data
191 //
192 HdBufferArrayRangeSharedPtr const & indexBar_ =
193 drawItem->GetTopologyRange();
194
195 HdStBufferArrayRangeSharedPtr indexBar =
196 std::static_pointer_cast<HdStBufferArrayRange>(indexBar_);
197
198 if (indexBar && (!indexBar->IsAggregatedWith(indexBarCurrent))) {
199 binder.UnbindBufferArray(indexBarCurrent);
200 binder.BindBufferArray(indexBar);
201 indexBarCurrent = indexBar;
202 }
203
204 //
205 // topology visibility buffer data
206 //
207 HdBufferArrayRangeSharedPtr const &
208 topVisBar_ = drawItem->GetTopologyVisibilityRange();
209
210 HdStBufferArrayRangeSharedPtr topVisBar =
211 std::static_pointer_cast<HdStBufferArrayRange>(topVisBar_);
212
213 if (topVisBar && (!topVisBar->IsAggregatedWith(topVisBarCurrent))) {
214 binder.UnbindInterleavedBuffer(topVisBarCurrent,
215 HdTokens->topologyVisibility);
216 binder.BindInterleavedBuffer(topVisBar,
217 HdTokens->topologyVisibility);
218 topVisBarCurrent = topVisBar;
219 }
220
221 //
222 // per-face buffer data (fetched through ElementID in primitiveParam)
223 //
224 HdBufferArrayRangeSharedPtr const & elementBar_ =
225 drawItem->GetElementPrimvarRange();
226
227 HdStBufferArrayRangeSharedPtr elementBar =
228 std::static_pointer_cast<HdStBufferArrayRange>(elementBar_);
229
230 if (elementBar && (!elementBar->IsAggregatedWith(elementBarCurrent))) {
231 binder.UnbindBufferArray(elementBarCurrent);
232 binder.BindBufferArray(elementBar);
233 elementBarCurrent = elementBar;
234 }
235
236 //
237 // vertex attrib buffer data
238 //
239 HdBufferArrayRangeSharedPtr const & vertexBar_ =
240 drawItem->GetVertexPrimvarRange();
241
242 HdStBufferArrayRangeSharedPtr vertexBar =
243 std::static_pointer_cast<HdStBufferArrayRange>(vertexBar_);
244
245 if (vertexBar && (!vertexBar->IsAggregatedWith(vertexBarCurrent))) {
246 binder.UnbindBufferArray(vertexBarCurrent);
247 binder.BindBufferArray(vertexBar);
248 vertexBarCurrent = vertexBar;
249 }
250
251 //
252 // varying buffer data
253 //
254 HdBufferArrayRangeSharedPtr const & varyingBar_ =
255 drawItem->GetVaryingPrimvarRange();
256
257 HdStBufferArrayRangeSharedPtr varyingBar =
258 std::static_pointer_cast<HdStBufferArrayRange>(varyingBar_);
259
260 if (varyingBar && (!varyingBar->IsAggregatedWith(varyingBarCurrent))) {
261 binder.UnbindBufferArray(varyingBarCurrent);
262 binder.BindBufferArray(varyingBar);
263 varyingBarCurrent = varyingBar;
264 }
265
266 //
267 // constant (uniform) buffer data
268 //
269 HdBufferArrayRangeSharedPtr const & constantBar_ =
270 drawItem->GetConstantPrimvarRange();
271
272 HdStBufferArrayRangeSharedPtr constantBar =
273 std::static_pointer_cast<HdStBufferArrayRange>(constantBar_);
274
275 if (constantBar && (!constantBar->IsAggregatedWith(constantBarCurrent))) {
276 binder.UnbindConstantBuffer(constantBarCurrent);
277 binder.BindConstantBuffer(constantBar);
278 constantBarCurrent = constantBar;
279 }
280
281 //
282 // facevarying buffer data
283 //
284 HdBufferArrayRangeSharedPtr const & fvarBar_ =
285 drawItem->GetFaceVaryingPrimvarRange();
286
287 HdStBufferArrayRangeSharedPtr fvarBar =
288 std::static_pointer_cast<HdStBufferArrayRange>(fvarBar_);
289
290 if (fvarBar && (!fvarBar->IsAggregatedWith(fvarBarCurrent))) {
291 binder.UnbindBufferArray(fvarBarCurrent);
292 binder.BindBufferArray(fvarBar);
293 fvarBarCurrent = fvarBar;
294 }
295
296 //
297 // instance buffer data
298 //
299 int instancerNumLevels = drawItem->GetInstancePrimvarNumLevels();
300 int instanceIndexWidth = instancerNumLevels + 1;
301 for (int i = 0; i < instancerNumLevels; ++i) {
302 HdBufferArrayRangeSharedPtr const & instanceBar_ =
303 drawItem->GetInstancePrimvarRange(i);
304
305 HdStBufferArrayRangeSharedPtr instanceBar =
306 std::static_pointer_cast<HdStBufferArrayRange>(instanceBar_);
307
308 if (instanceBar) {
309 if (static_cast<size_t>(i) >= instanceBarCurrents.size()) {
310 instanceBarCurrents.push_back(instanceBar);
311 binder.BindInstanceBufferArray(instanceBar, i);
312 continue;
313 } else if (!instanceBar->IsAggregatedWith(
314 instanceBarCurrents[i])) {
315 binder.UnbindInstanceBufferArray(instanceBarCurrents[i], i);
316 binder.BindInstanceBufferArray(instanceBar, i);
317 }
318 instanceBarCurrents[i] = instanceBar;
319 }
320 }
321
322 //
323 // instance index indirection buffer
324 //
325 HdBufferArrayRangeSharedPtr const & instanceIndexBar_ =
326 drawItem->GetInstanceIndexRange();
327
328 HdStBufferArrayRangeSharedPtr instanceIndexBar =
329 std::static_pointer_cast<HdStBufferArrayRange>(instanceIndexBar_);
330
331 if (instanceIndexBar &&
332 (!instanceIndexBar->IsAggregatedWith(instanceIndexBarCurrent))) {
333 binder.UnbindBufferArray(instanceIndexBarCurrent);
334 binder.BindBufferArray(instanceIndexBar);
335 instanceIndexBarCurrent = instanceIndexBar;
336 }
337
338 //
339 // shader buffer
340 //
341 HdBufferArrayRangeSharedPtr const & shaderBar_ =
342 !program.GetMaterialNetworkShader()
343 ? HdStBufferArrayRangeSharedPtr()
344 : program.GetMaterialNetworkShader()->GetShaderData();
345 HdStBufferArrayRangeSharedPtr shaderBar =
346 std::static_pointer_cast<HdStBufferArrayRange> (shaderBar_);
347
348 // shaderBar isn't needed when the material is overridden
349 if (shaderBar && (!shaderBar->IsAggregatedWith(shaderBarCurrent))) {
350 if (shaderBarCurrent) {
351 binder.UnbindBuffer(HdTokens->materialParams,
352 shaderBarCurrent->GetResource());
353 }
354 binder.BindBuffer(HdTokens->materialParams,
355 shaderBar->GetResource());
356 shaderBarCurrent = shaderBar;
357 }
358
359 //
360 // shader textures
361 //
362 if (program.GetMaterialNetworkShader()) {
363 program.GetMaterialNetworkShader()->BindResources(
364 programId, binder, *renderPassState);
365 }
366
367 /*
368 Drawing coord is a unified cursor which locates a subset of
369 aggregated buffer in GPU. The primary role of drawing coord is
370 to provide a way to access buffers from glsl shader code.
371
372 We have some aggregated buffers of different granularities.
373 They are associated to class/variability specifiers in GL/prman spec.
374 ( see http://renderman.pixar.com/view/Appnote22 )
375
376 | | drawing coord | hd buffer | OpenGL | PRMan |
377 ----------------------------------------------------------------------
378 | 0 | ModelDC | (reserved) | uniform | constant |
379 | 1 | ConstantDC | constantBar | uniform | constant |
380 | 2 | VertexDC | vertexBar |gl_BaseVertex(^)| vertex/varying |
381 | 3 | ElementDC | elementBar | (*) | uniform |
382 | 4 | PrimitiveDC | indexBar | gl_PrimitiveID | (*) |
383 | 5 | FVarDC | fvarBar | gl_PrimitiveID | facevarying |
384 | 6 | InstanceIndex | inst-idxBar | (gl_InstanceID)| n/a |
385 | 7 | ShaderDC | shaderBar | uniform | |
386 | 8 | TopVisDC | topVisBar | | |
387 | 9 | VaryingDC | varyingBar |gl_BaseVertex(^)| varying |
388 | 10| InstanceDC[0] | instanceBar | (gl_InstanceID)| constant |
389 | 11| InstanceDC[1] | instanceBar | (gl_InstanceID)| constant |
390 |...| ... | instanceBar | (gl_InstanceID)| constant |
391 ----------------------------------------------------------------------
392
393 We put these offsets into 4 variables,
394 - ivec4 drawingCoord0 {ModelDC, ConstantDC, ElementDC, PrimitiveDC}
395 - ivec4 drawingCoord1 {FVarDC, InstanceIndex, ShaderDC, VertexDC}
396 - ivec2 drawingCoord2 {TopoVisibilityDC, VaryingDC}
397 - int[] drawingCoordI (InstanceDC)
398 so that the shaders can access any of these aggregated data.
399
400 (^) gl_BaseVertex requires GLSL 4.60 or the ARB_shader_draw_parameters
401 extension. We simply plumb the baseVertex(Offset) as a generic
402 solution.
403 (*) primitiveParam buffer can be used to reinterpret GL-primitive
404 ID back to element ID.
405 */
406
407 int vertexOffset = 0;
408 int vertexCount = 0;
409 if (vertexBar) {
410 vertexOffset = vertexBar->GetElementOffset();
411 vertexCount = vertexBar->GetNumElements();
412 }
413
414 //
415 // Get parameters from our buffer range objects to
416 // allow drawing to access the correct elements from
417 // aggregated buffers.
418 //
419 int numIndicesPerPrimitive = geometricShader->GetPrimitiveIndexSize();
420 int indexCount = indexBar ? indexBar->GetNumElements() * numIndicesPerPrimitive : 0;
421 int firstIndex = indexBar ? indexBar->GetElementOffset() * numIndicesPerPrimitive : 0;
422 int baseVertex = vertexOffset;
423 int instanceCount = instanceIndexBar
424 ? instanceIndexBar->GetNumElements()/instanceIndexWidth : 1;
425
426 // if delegate fails to get vertex primvars, it could be empty.
427 // skip the drawitem to prevent drawing uninitialized vertices.
428 if (vertexCount == 0) continue;
429
430 // update standalone uniforms
431 int drawingCoord0[4] = {
432 0, // reserved for modelBar
433 _GetElementOffset(constantBar),
434 _GetElementOffset(elementBar),
435 _GetElementOffset(indexBar),
436 };
437 int drawingCoord1[4] = {
438 _GetElementOffset(fvarBar),
439 _GetElementOffset(instanceIndexBar),
440 _GetElementOffset(shaderBar),
441 baseVertex
442 };
443 int drawingCoord2[2] = {
444 _GetElementOffset(topVisBar),
445 _GetElementOffset(varyingBar),
446 };
447 binder.BindUniformi(HdTokens->drawingCoord0, 4, drawingCoord0);
448 binder.BindUniformi(HdTokens->drawingCoord1, 4, drawingCoord1);
449 binder.BindUniformi(HdTokens->drawingCoord2, 2, drawingCoord2);
450
451 // instance coordinates
452 std::vector<int> instanceDrawingCoords(instancerNumLevels);
453 for (int i = 0; i < instancerNumLevels; ++i) {
454 instanceDrawingCoords[i] =
455 _GetElementOffset(instanceBarCurrents[i]);
456 }
457 if (instancerNumLevels > 0) {
458 binder.BindUniformArrayi(HdTokens->drawingCoordI,
459 instancerNumLevels, &instanceDrawingCoords[0]);
460 }
461
462 if (indexCount > 0 && indexBar) {
463 glDrawElementsInstancedBaseVertex(
464 geometricShader->GetPrimitiveMode(),
465 indexCount,
466 GL_UNSIGNED_INT, // GL_INT is invalid: indexBar->GetResource(HdTokens->indices)->GetGLDataType(),
467 (void *)(firstIndex * sizeof(uint32_t)),
468 instanceCount,
469 baseVertex);
470 } else if (vertexCount > 0) {
471 glDrawArraysInstanced(
472 geometricShader->GetPrimitiveMode(),
473 baseVertex,
474 vertexCount,
475 instanceCount);
476 }
477
478 if (program.GetMaterialNetworkShader()) {
479 program.GetMaterialNetworkShader()->UnbindResources(
480 programId, binder, *renderPassState);
481 }
482
483 HD_PERF_COUNTER_INCR(HdPerfTokens->drawCalls);
484 }
485
486 HD_PERF_COUNTER_ADD(HdTokens->itemsDrawn, numItemsDrawn);
487
488 for (HdStShaderCodeSharedPtr const & shader : shaders) {
489 shader->UnbindResources(programId, binder, *renderPassState);
490 }
491 geometricShader->UnbindResources(programId, binder, *renderPassState);
492
493 // unbind (make non resident all bindless buffers)
494 if (constantBarCurrent)
495 binder.UnbindConstantBuffer(constantBarCurrent);
496 if (vertexBarCurrent)
497 binder.UnbindBufferArray(vertexBarCurrent);
498 if (varyingBarCurrent)
499 binder.UnbindBufferArray(varyingBarCurrent);
500 if (elementBarCurrent)
501 binder.UnbindBufferArray(elementBarCurrent);
502 if (fvarBarCurrent)
503 binder.UnbindBufferArray(fvarBarCurrent);
504 for (size_t i = 0; i < instanceBarCurrents.size(); ++i) {
505 binder.UnbindInstanceBufferArray(instanceBarCurrents[i], i);
506 }
507 if (instanceIndexBarCurrent)
508 binder.UnbindBufferArray(instanceIndexBarCurrent);
509 if (indexBarCurrent)
510 binder.UnbindBufferArray(indexBarCurrent);
511 if (topVisBarCurrent)
512 binder.UnbindBufferArray(topVisBarCurrent);
513 if (shaderBarCurrent) {
514 binder.UnbindBuffer(HdTokens->materialParams,
515 shaderBarCurrent->GetResource());
516 }
517
518 glUseProgram(0);
519 }
520
521 PXR_NAMESPACE_CLOSE_SCOPE
522
523