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