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/bufferArrayRange.h"
29 #include "pxr/imaging/hdSt/drawItem.h"
30 #include "pxr/imaging/hdSt/glConversions.h"
31 #include "pxr/imaging/hdSt/hgiConversions.h"
32 #include "pxr/imaging/hdSt/fallbackLightingShader.h"
33 #include "pxr/imaging/hdSt/renderBuffer.h"
34 #include "pxr/imaging/hdSt/renderPassShader.h"
35 #include "pxr/imaging/hdSt/renderPassState.h"
36 #include "pxr/imaging/hdSt/resourceRegistry.h"
37 #include "pxr/imaging/hdSt/shaderCode.h"
38
39 #include "pxr/imaging/hd/aov.h"
40 #include "pxr/imaging/hd/changeTracker.h"
41 #include "pxr/imaging/hd/renderIndex.h"
42 #include "pxr/imaging/hd/tokens.h"
43 #include "pxr/imaging/hd/vtBufferSource.h"
44
45 #include "pxr/imaging/hgi/graphicsCmdsDesc.h"
46
47 #include "pxr/base/gf/frustum.h"
48 #include "pxr/base/tf/staticTokens.h"
49 #include "pxr/base/tf/stringUtils.h"
50 #include "pxr/base/vt/array.h"
51
52 #include <boost/functional/hash.hpp>
53
54 PXR_NAMESPACE_OPEN_SCOPE
55
56
57 TF_DEFINE_PRIVATE_TOKENS(
58 _tokens,
59 (renderPassState)
60 );
61
HdStRenderPassState()62 HdStRenderPassState::HdStRenderPassState()
63 : HdStRenderPassState(std::make_shared<HdStRenderPassShader>())
64 {
65 }
66
HdStRenderPassState(HdStRenderPassShaderSharedPtr const & renderPassShader)67 HdStRenderPassState::HdStRenderPassState(
68 HdStRenderPassShaderSharedPtr const &renderPassShader)
69 : HdRenderPassState()
70 , _renderPassShader(renderPassShader)
71 , _fallbackLightingShader(std::make_shared<HdSt_FallbackLightingShader>())
72 , _clipPlanesBufferSize(0)
73 , _alphaThresholdCurrent(0)
74 , _resolveMultiSampleAov(true)
75 , _useSceneMaterials(true)
76 {
77 _lightingShader = _fallbackLightingShader;
78 }
79
80 HdStRenderPassState::~HdStRenderPassState() = default;
81
82 bool
_UseAlphaMask() const83 HdStRenderPassState::_UseAlphaMask() const
84 {
85 return (_alphaThreshold > 0.0f);
86 }
87
88 static
89 GfVec4f
_ComputeDataWindow(const CameraUtilFraming & framing,const GfVec4f & fallbackViewport)90 _ComputeDataWindow(
91 const CameraUtilFraming &framing,
92 const GfVec4f &fallbackViewport)
93 {
94 if (framing.IsValid()) {
95 const GfRect2i &dataWindow = framing.dataWindow;
96 return GfVec4f(
97 dataWindow.GetMinX(),
98 dataWindow.GetMinY(),
99 dataWindow.GetWidth(),
100 dataWindow.GetHeight());
101 }
102
103 return fallbackViewport;
104 }
105
106 void
Prepare(HdResourceRegistrySharedPtr const & resourceRegistry)107 HdStRenderPassState::Prepare(
108 HdResourceRegistrySharedPtr const &resourceRegistry)
109 {
110 HD_TRACE_FUNCTION();
111 HF_MALLOC_TAG_FUNCTION();
112 GLF_GROUP_FUNCTION();
113
114 HdRenderPassState::Prepare(resourceRegistry);
115
116 HdStResourceRegistrySharedPtr const& hdStResourceRegistry =
117 std::static_pointer_cast<HdStResourceRegistry>(resourceRegistry);
118
119 VtVec4fArray clipPlanes;
120 TF_FOR_ALL(it, GetClipPlanes()) {
121 clipPlanes.push_back(GfVec4f(*it));
122 }
123 GLint glMaxClipPlanes;
124 glGetIntegerv(GL_MAX_CLIP_PLANES, &glMaxClipPlanes);
125 size_t maxClipPlanes = (size_t)glMaxClipPlanes;
126 if (clipPlanes.size() >= maxClipPlanes) {
127 clipPlanes.resize(maxClipPlanes);
128 }
129
130 // allocate bar if not exists
131 if (!_renderPassStateBar ||
132 (_clipPlanesBufferSize != clipPlanes.size()) ||
133 _alphaThresholdCurrent != _alphaThreshold) {
134 HdBufferSpecVector bufferSpecs;
135
136 // note: InterleavedMemoryManager computes the offsets in the packed
137 // struct of following entries, which CodeGen generates the struct
138 // definition into GLSL source in accordance with.
139 HdType matType = HdVtBufferSource::GetDefaultMatrixType();
140
141 bufferSpecs.emplace_back(
142 HdShaderTokens->worldToViewMatrix,
143 HdTupleType{matType, 1});
144 bufferSpecs.emplace_back(
145 HdShaderTokens->worldToViewInverseMatrix,
146 HdTupleType{matType, 1});
147 bufferSpecs.emplace_back(
148 HdShaderTokens->projectionMatrix,
149 HdTupleType{matType, 1});
150 bufferSpecs.emplace_back(
151 HdShaderTokens->overrideColor,
152 HdTupleType{HdTypeFloatVec4, 1});
153 bufferSpecs.emplace_back(
154 HdShaderTokens->wireframeColor,
155 HdTupleType{HdTypeFloatVec4, 1});
156 bufferSpecs.emplace_back(
157 HdShaderTokens->maskColor,
158 HdTupleType{HdTypeFloatVec4, 1});
159 bufferSpecs.emplace_back(
160 HdShaderTokens->indicatorColor,
161 HdTupleType{HdTypeFloatVec4, 1});
162 bufferSpecs.emplace_back(
163 HdShaderTokens->pointColor,
164 HdTupleType{HdTypeFloatVec4, 1});
165 bufferSpecs.emplace_back(
166 HdShaderTokens->pointSize,
167 HdTupleType{HdTypeFloat, 1});
168 bufferSpecs.emplace_back(
169 HdShaderTokens->pointSelectedSize,
170 HdTupleType{HdTypeFloat, 1});
171 bufferSpecs.emplace_back(
172 HdShaderTokens->lightingBlendAmount,
173 HdTupleType{HdTypeFloat, 1});
174
175 if (_UseAlphaMask()) {
176 bufferSpecs.emplace_back(
177 HdShaderTokens->alphaThreshold,
178 HdTupleType{HdTypeFloat, 1});
179 }
180 _alphaThresholdCurrent = _alphaThreshold;
181
182 bufferSpecs.emplace_back(
183 HdShaderTokens->tessLevel,
184 HdTupleType{HdTypeFloat, 1});
185 bufferSpecs.emplace_back(
186 HdShaderTokens->viewport,
187 HdTupleType{HdTypeFloatVec4, 1});
188
189 if (clipPlanes.size() > 0) {
190 bufferSpecs.emplace_back(
191 HdShaderTokens->clipPlanes,
192 HdTupleType{HdTypeFloatVec4, clipPlanes.size()});
193 }
194 _clipPlanesBufferSize = clipPlanes.size();
195
196 // allocate interleaved buffer
197 _renderPassStateBar =
198 hdStResourceRegistry->AllocateUniformBufferArrayRange(
199 HdTokens->drawingShader, bufferSpecs, HdBufferArrayUsageHint());
200
201 HdStBufferArrayRangeSharedPtr _renderPassStateBar_ =
202 std::static_pointer_cast<HdStBufferArrayRange> (_renderPassStateBar);
203
204 // add buffer binding request
205 _renderPassShader->AddBufferBinding(
206 HdBindingRequest(HdBinding::UBO, _tokens->renderPassState,
207 _renderPassStateBar_, /*interleaved=*/true));
208 }
209
210 // Lighting hack supports different blending amounts, but we are currently
211 // only using the feature to turn lighting on and off.
212 float lightingBlendAmount = (_lightingEnabled ? 1.0f : 0.0f);
213
214 GfMatrix4d const& worldToViewMatrix = GetWorldToViewMatrix();
215 GfMatrix4d projMatrix = GetProjectionMatrix();
216
217 HdBufferSourceSharedPtrVector sources = {
218 std::make_shared<HdVtBufferSource>(
219 HdShaderTokens->worldToViewMatrix,
220 worldToViewMatrix),
221 std::make_shared<HdVtBufferSource>(
222 HdShaderTokens->worldToViewInverseMatrix,
223 worldToViewMatrix.GetInverse()),
224 std::make_shared<HdVtBufferSource>(
225 HdShaderTokens->projectionMatrix,
226 projMatrix),
227 // Override color alpha component is used as the amount to blend in the
228 // override color over the top of the regular fragment color.
229 std::make_shared<HdVtBufferSource>(
230 HdShaderTokens->overrideColor,
231 VtValue(_overrideColor)),
232 std::make_shared<HdVtBufferSource>(
233 HdShaderTokens->wireframeColor,
234 VtValue(_wireframeColor)),
235 std::make_shared<HdVtBufferSource>(
236 HdShaderTokens->maskColor,
237 VtValue(_maskColor)),
238 std::make_shared<HdVtBufferSource>(
239 HdShaderTokens->indicatorColor,
240 VtValue(_indicatorColor)),
241 std::make_shared<HdVtBufferSource>(
242 HdShaderTokens->pointColor,
243 VtValue(_pointColor)),
244 std::make_shared<HdVtBufferSource>(
245 HdShaderTokens->pointSize,
246 VtValue(_pointSize)),
247 std::make_shared<HdVtBufferSource>(
248 HdShaderTokens->pointSelectedSize,
249 VtValue(_pointSelectedSize)),
250 std::make_shared<HdVtBufferSource>(
251 HdShaderTokens->lightingBlendAmount,
252 VtValue(lightingBlendAmount))
253 };
254
255 if (_UseAlphaMask()) {
256 sources.push_back(
257 std::make_shared<HdVtBufferSource>(
258 HdShaderTokens->alphaThreshold,
259 VtValue(_alphaThreshold)));
260 }
261
262 sources.push_back(
263 std::make_shared<HdVtBufferSource>(
264 HdShaderTokens->tessLevel,
265 VtValue(_tessLevel)));
266 sources.push_back(
267 std::make_shared<HdVtBufferSource>(
268 HdShaderTokens->viewport,
269 VtValue(
270 _ComputeDataWindow(
271 _framing, _viewport))));
272
273 if (clipPlanes.size() > 0) {
274 sources.push_back(
275 std::make_shared<HdVtBufferSource>(
276 HdShaderTokens->clipPlanes,
277 VtValue(clipPlanes),
278 clipPlanes.size()));
279 }
280
281 hdStResourceRegistry->AddSources(_renderPassStateBar, std::move(sources));
282
283 // notify view-transform to the lighting shader to update its uniform block
284 _lightingShader->SetCamera(worldToViewMatrix, projMatrix);
285
286 // Update cull style on renderpass shader
287 // (Note that the geometric shader overrides the render pass's cullStyle
288 // opinion if the prim has an opinion).
289 _renderPassShader->SetCullStyle(_cullStyle);
290 }
291
292 void
SetResolveAovMultiSample(bool state)293 HdStRenderPassState::SetResolveAovMultiSample(bool state)
294 {
295 _resolveMultiSampleAov = state;
296 }
297
298 bool
GetResolveAovMultiSample() const299 HdStRenderPassState::GetResolveAovMultiSample() const
300 {
301 return _resolveMultiSampleAov;
302 }
303
304 void
SetLightingShader(HdStLightingShaderSharedPtr const & lightingShader)305 HdStRenderPassState::SetLightingShader(HdStLightingShaderSharedPtr const &lightingShader)
306 {
307 if (lightingShader) {
308 _lightingShader = lightingShader;
309 } else {
310 _lightingShader = _fallbackLightingShader;
311 }
312 }
313
314 void
SetRenderPassShader(HdStRenderPassShaderSharedPtr const & renderPassShader)315 HdStRenderPassState::SetRenderPassShader(HdStRenderPassShaderSharedPtr const &renderPassShader)
316 {
317 _renderPassShader = renderPassShader;
318 if (_renderPassStateBar) {
319
320 HdStBufferArrayRangeSharedPtr _renderPassStateBar_ =
321 std::static_pointer_cast<HdStBufferArrayRange> (_renderPassStateBar);
322
323 _renderPassShader->AddBufferBinding(
324 HdBindingRequest(HdBinding::UBO, _tokens->renderPassState,
325 _renderPassStateBar_, /*interleaved=*/true));
326 }
327 }
328
329 void
SetUseSceneMaterials(bool state)330 HdStRenderPassState::SetUseSceneMaterials(bool state)
331 {
332 _useSceneMaterials = state;
333 }
334
335 HdStShaderCodeSharedPtrVector
GetShaders() const336 HdStRenderPassState::GetShaders() const
337 {
338 HdStShaderCodeSharedPtrVector shaders;
339 shaders.reserve(2);
340 shaders.push_back(_lightingShader);
341 shaders.push_back(_renderPassShader);
342 return shaders;
343 }
344
345 // Note: The geometric shader may override the state set below if necessary,
346 // including disabling h/w culling altogether.
347 // Disabling h/w culling is required to handle instancing wherein
348 // instanceScale/instanceTransform can flip the xform handedness.
349 namespace {
350
351 void
_SetGLCullState(HdCullStyle cullstyle)352 _SetGLCullState(HdCullStyle cullstyle)
353 {
354 switch (cullstyle) {
355 case HdCullStyleFront:
356 case HdCullStyleFrontUnlessDoubleSided:
357 glEnable(GL_CULL_FACE);
358 glCullFace(GL_FRONT);
359 break;
360 case HdCullStyleBack:
361 case HdCullStyleBackUnlessDoubleSided:
362 glEnable(GL_CULL_FACE);
363 glCullFace(GL_BACK);
364 break;
365 case HdCullStyleNothing:
366 case HdCullStyleDontCare:
367 default:
368 // disable culling
369 glDisable(GL_CULL_FACE);
370 break;
371 }
372 }
373
374 void
_SetColorMask(int drawBufferIndex,HdRenderPassState::ColorMask const & mask)375 _SetColorMask(int drawBufferIndex, HdRenderPassState::ColorMask const& mask)
376 {
377 bool colorMask[4] = {true, true, true, true};
378 switch (mask)
379 {
380 case HdStRenderPassState::ColorMaskNone:
381 colorMask[0] = colorMask[1] = colorMask[2] = colorMask[3] = false;
382 break;
383 case HdStRenderPassState::ColorMaskRGB:
384 colorMask[3] = false;
385 break;
386 default:
387 ; // no-op
388 }
389
390 if (drawBufferIndex == -1) {
391 glColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
392 } else {
393 glColorMaski((uint32_t) drawBufferIndex,
394 colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
395 }
396 }
397
398 } // anonymous namespace
399
400 void
Bind()401 HdStRenderPassState::Bind()
402 {
403 GLF_GROUP_FUNCTION();
404
405 if (!glBlendColor) {
406 return;
407 }
408
409 // notify view-transform to the lighting shader to update its uniform block
410 // this needs to be done in execute as a multi camera setup may have been
411 // synced with a different view matrix baked in for shadows.
412 // SetCamera will no-op if the transforms are the same as before.
413 _lightingShader->SetCamera(GetWorldToViewMatrix(),
414 GetProjectionMatrix());
415
416 // when adding another GL state change here, please document
417 // which states to be altered at the comment in the header file
418
419 // Apply polygon offset to whole pass.
420 if (!GetDepthBiasUseDefault()) {
421 if (GetDepthBiasEnabled()) {
422 glEnable(GL_POLYGON_OFFSET_FILL);
423 glPolygonOffset(_depthBiasSlopeFactor, _depthBiasConstantFactor);
424 } else {
425 glDisable(GL_POLYGON_OFFSET_FILL);
426 }
427 }
428
429 if (GetEnableDepthTest()) {
430 glEnable(GL_DEPTH_TEST);
431 glDepthFunc(HdStGLConversions::GetGlDepthFunc(_depthFunc));
432 glDepthMask(GetEnableDepthMask()); // depth writes are enabled only
433 // when the test is enabled.
434 } else {
435 glDisable(GL_DEPTH_TEST);
436 }
437
438 // Stencil
439 if (GetStencilEnabled()) {
440 glEnable(GL_STENCIL_TEST);
441 glStencilFunc(HdStGLConversions::GetGlStencilFunc(_stencilFunc),
442 _stencilRef, _stencilMask);
443 glStencilOp(HdStGLConversions::GetGlStencilOp(_stencilFailOp),
444 HdStGLConversions::GetGlStencilOp(_stencilZFailOp),
445 HdStGLConversions::GetGlStencilOp(_stencilZPassOp));
446 } else {
447 glDisable(GL_STENCIL_TEST);
448 }
449
450 // Face culling
451 _SetGLCullState(_cullStyle);
452
453 // Line width
454 if (_lineWidth > 0) {
455 glLineWidth(_lineWidth);
456 }
457
458 // Blending
459 if (_blendEnabled) {
460 glEnable(GL_BLEND);
461 glBlendEquationSeparate(
462 HdStGLConversions::GetGlBlendOp(_blendColorOp),
463 HdStGLConversions::GetGlBlendOp(_blendAlphaOp));
464 glBlendFuncSeparate(
465 HdStGLConversions::GetGlBlendFactor(_blendColorSrcFactor),
466 HdStGLConversions::GetGlBlendFactor(_blendColorDstFactor),
467 HdStGLConversions::GetGlBlendFactor(_blendAlphaSrcFactor),
468 HdStGLConversions::GetGlBlendFactor(_blendAlphaDstFactor));
469 glBlendColor(_blendConstantColor[0],
470 _blendConstantColor[1],
471 _blendConstantColor[2],
472 _blendConstantColor[3]);
473 } else {
474 glDisable(GL_BLEND);
475 }
476
477 if (_alphaToCoverageEnabled) {
478 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
479 glEnable(GL_SAMPLE_ALPHA_TO_ONE);
480 } else {
481 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
482 }
483
484 glEnable(GL_PROGRAM_POINT_SIZE);
485 GLint glMaxClipPlanes;
486 glGetIntegerv(GL_MAX_CLIP_PLANES, &glMaxClipPlanes);
487 for (size_t i = 0; i < GetClipPlanes().size(); ++i) {
488 if (i >= (size_t)glMaxClipPlanes) {
489 break;
490 }
491 glEnable(GL_CLIP_DISTANCE0 + i);
492 }
493
494 if (_colorMaskUseDefault) {
495 // Enable color writes for all components for all attachments.
496 _SetColorMask(-1, ColorMaskRGBA);
497 } else {
498 if (_colorMasks.size() == 1) {
499 // Use the same color mask for all attachments.
500 _SetColorMask(-1, _colorMasks[0]);
501 } else {
502 for (size_t i = 0; i < _colorMasks.size(); i++) {
503 _SetColorMask(i, _colorMasks[i]);
504 }
505 }
506 }
507 }
508
509 void
Unbind()510 HdStRenderPassState::Unbind()
511 {
512 GLF_GROUP_FUNCTION();
513 // restore back to the GL defaults
514
515 if (!glBlendColor) {
516 return;
517 }
518
519 glDisable(GL_CULL_FACE);
520 glDisable(GL_POLYGON_OFFSET_FILL);
521 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
522 glDisable(GL_SAMPLE_ALPHA_TO_ONE);
523 glDisable(GL_PROGRAM_POINT_SIZE);
524 glEnable(GL_DEPTH_TEST);
525 glDisable(GL_STENCIL_TEST);
526 glDepthFunc(GL_LESS);
527 glPolygonOffset(0, 0);
528 glLineWidth(1.0f);
529
530 glDisable(GL_BLEND);
531 glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
532 glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);
533 glBlendColor(0.0f, 0.0f, 0.0f, 0.0f);
534
535 for (size_t i = 0; i < GetClipPlanes().size(); ++i) {
536 glDisable(GL_CLIP_DISTANCE0 + i);
537 }
538
539 glColorMask(true, true, true, true);
540 glDepthMask(true);
541 }
542
543 void
SetCameraFramingState(GfMatrix4d const & worldToViewMatrix,GfMatrix4d const & projectionMatrix,GfVec4d const & viewport,ClipPlanesVector const & clipPlanes)544 HdStRenderPassState::SetCameraFramingState(GfMatrix4d const &worldToViewMatrix,
545 GfMatrix4d const &projectionMatrix,
546 GfVec4d const &viewport,
547 ClipPlanesVector const & clipPlanes)
548 {
549 if (_camera) {
550 // If a camera handle was set, reset it.
551 _camera = nullptr;
552 }
553
554 _worldToViewMatrix = worldToViewMatrix;
555 _projectionMatrix = projectionMatrix;
556 _viewport = GfVec4f((float)viewport[0], (float)viewport[1],
557 (float)viewport[2], (float)viewport[3]);
558 _clipPlanes = clipPlanes;
559 }
560
561 size_t
GetShaderHash() const562 HdStRenderPassState::GetShaderHash() const
563 {
564 size_t hash = 0;
565 if (_lightingShader) {
566 boost::hash_combine(hash, _lightingShader->ComputeHash());
567 }
568 if (_renderPassShader) {
569 boost::hash_combine(hash, _renderPassShader->ComputeHash());
570 }
571 boost::hash_combine(hash, GetClipPlanes().size());
572 boost::hash_combine(hash, _UseAlphaMask());
573 return hash;
574 }
575
576 static
577 HdRenderBuffer *
_GetRenderBuffer(const HdRenderPassAovBinding & aov,const HdRenderIndex * const renderIndex)578 _GetRenderBuffer(const HdRenderPassAovBinding& aov,
579 const HdRenderIndex * const renderIndex)
580 {
581 if (aov.renderBuffer) {
582 return aov.renderBuffer;
583 }
584
585 return
586 dynamic_cast<HdRenderBuffer*>(
587 renderIndex->GetBprim(
588 HdPrimTypeTokens->renderBuffer,
589 aov.renderBufferId));
590 }
591
592 // Clear values are always vec4f in HgiGraphicsCmdDesc.
593 static
_ToVec4f(const VtValue & v)594 GfVec4f _ToVec4f(const VtValue &v)
595 {
596 if (v.IsHolding<float>()) {
597 const float depth = v.UncheckedGet<float>();
598 return GfVec4f(depth,0,0,0);
599 }
600 if (v.IsHolding<double>()) {
601 const double val = v.UncheckedGet<double>();
602 return GfVec4f(val);
603 }
604 if (v.IsHolding<GfVec2f>()) {
605 const GfVec2f val = v.UncheckedGet<GfVec2f>();
606 return GfVec4f(val[0], val[1], 0.0, 1.0);
607 }
608 if (v.IsHolding<GfVec2d>()) {
609 const GfVec2d val = v.UncheckedGet<GfVec2d>();
610 return GfVec4f(val[0], val[1], 0.0, 1.0);
611 }
612 if (v.IsHolding<GfVec3f>()) {
613 const GfVec3f val = v.UncheckedGet<GfVec3f>();
614 return GfVec4f(val[0], val[1], val[2], 1.0);
615 }
616 if (v.IsHolding<GfVec3d>()) {
617 const GfVec3d val = v.UncheckedGet<GfVec3d>();
618 return GfVec4f(val[0], val[1], val[2], 1.0);
619 }
620 if (v.IsHolding<GfVec4f>()) {
621 return v.UncheckedGet<GfVec4f>();
622 }
623 if (v.IsHolding<GfVec4d>()) {
624 return GfVec4f(v.UncheckedGet<GfVec4d>());
625 }
626
627 TF_CODING_ERROR("Unsupported clear value for draw target attachment.");
628 return GfVec4f(0.0);
629 }
630
631 HgiGraphicsCmdsDesc
MakeGraphicsCmdsDesc(const HdRenderIndex * const renderIndex) const632 HdStRenderPassState::MakeGraphicsCmdsDesc(
633 const HdRenderIndex * const renderIndex) const
634 {
635 const HdRenderPassAovBindingVector& aovBindings = GetAovBindings();
636
637 static const size_t maxColorTex = 8;
638 const bool useMultiSample = GetUseAovMultiSample();
639 const bool resolveMultiSample = GetResolveAovMultiSample();
640
641 HgiGraphicsCmdsDesc desc;
642
643 // If the AOV bindings have not changed that does NOT mean the
644 // graphicsCmdsDescriptor will not change. The HdRenderBuffer may be
645 // resized at any time, which will destroy and recreate the HgiTextureHandle
646 // that backs the render buffer and was attached for graphics encoding.
647
648 for (const HdRenderPassAovBinding& aov : aovBindings) {
649 HdRenderBuffer * const renderBuffer =
650 _GetRenderBuffer(aov, renderIndex);
651
652
653 if (!TF_VERIFY(renderBuffer, "Invalid render buffer")) {
654 continue;
655 }
656
657 const bool multiSampled =
658 useMultiSample && renderBuffer->IsMultiSampled();
659 const VtValue rv = renderBuffer->GetResource(multiSampled);
660
661 if (!TF_VERIFY(rv.IsHolding<HgiTextureHandle>(),
662 "Invalid render buffer texture")) {
663 continue;
664 }
665
666 // Get render target texture
667 HgiTextureHandle hgiTexHandle = rv.UncheckedGet<HgiTextureHandle>();
668
669 // Get resolve texture target.
670 HgiTextureHandle hgiResolveHandle;
671 if (multiSampled && resolveMultiSample) {
672 VtValue resolveRes = renderBuffer->GetResource(/*ms*/false);
673 if (!TF_VERIFY(resolveRes.IsHolding<HgiTextureHandle>())) {
674 continue;
675 }
676 hgiResolveHandle = resolveRes.UncheckedGet<HgiTextureHandle>();
677 }
678
679 HgiAttachmentDesc attachmentDesc;
680
681 attachmentDesc.format = hgiTexHandle->GetDescriptor().format;
682 attachmentDesc.usage = hgiTexHandle->GetDescriptor().usage;
683
684 // We need to use LoadOpLoad instead of DontCare because we can have
685 // multiple render passes that use the same attachments.
686 // For example, translucent renders after opaque so we must load the
687 // opaque results before rendering translucent objects.
688 HgiAttachmentLoadOp loadOp = aov.clearValue.IsEmpty() ?
689 HgiAttachmentLoadOpLoad :
690 HgiAttachmentLoadOpClear;
691
692 attachmentDesc.loadOp = loadOp;
693
694 // Don't store multisample images. Only store the resolved versions.
695 // This saves a bunch of bandwith (especially on tiled gpu's).
696 attachmentDesc.storeOp = (multiSampled && resolveMultiSample) ?
697 HgiAttachmentStoreOpDontCare :
698 HgiAttachmentStoreOpStore;
699
700 if (!aov.clearValue.IsEmpty()) {
701 attachmentDesc.clearValue = _ToVec4f(aov.clearValue);
702 }
703
704 // HdSt expresses blending per RenderPassState, where Hgi expresses
705 // blending per-attachment. Transfer pass blend state to attachments.
706 attachmentDesc.blendEnabled = _blendEnabled;
707 attachmentDesc.srcColorBlendFactor=HgiBlendFactor(_blendColorSrcFactor);
708 attachmentDesc.dstColorBlendFactor=HgiBlendFactor(_blendColorDstFactor);
709 attachmentDesc.colorBlendOp = HgiBlendOp(_blendColorOp);
710 attachmentDesc.srcAlphaBlendFactor=HgiBlendFactor(_blendAlphaSrcFactor);
711 attachmentDesc.dstAlphaBlendFactor=HgiBlendFactor(_blendAlphaDstFactor);
712 attachmentDesc.alphaBlendOp = HgiBlendOp(_blendAlphaOp);
713
714 if (HdAovHasDepthSemantic(aov.aovName)) {
715 desc.depthAttachmentDesc = std::move(attachmentDesc);
716 desc.depthTexture = hgiTexHandle;
717 if (hgiResolveHandle) {
718 desc.depthResolveTexture = hgiResolveHandle;
719 }
720 } else if (TF_VERIFY(desc.colorAttachmentDescs.size() < maxColorTex,
721 "Too many aov bindings for color attachments"))
722 {
723 desc.colorAttachmentDescs.push_back(std::move(attachmentDesc));
724 desc.colorTextures.push_back(hgiTexHandle);
725 if (hgiResolveHandle) {
726 desc.colorResolveTextures.push_back(hgiResolveHandle);
727 }
728 }
729 }
730
731 return desc;
732 }
733
734 PXR_NAMESPACE_CLOSE_SCOPE
735