1 //
2 // Copyright 2019 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/hdx/oitVolumeRenderTask.h"
27 #include "pxr/imaging/hdx/package.h"
28 #include "pxr/imaging/hdx/oitBufferAccessor.h"
29
30 #include "pxr/imaging/hd/renderPassState.h"
31 #include "pxr/imaging/hd/rprimCollection.h"
32 #include "pxr/imaging/hd/sceneDelegate.h"
33
34 #include "pxr/imaging/hdSt/renderPassShader.h"
35
36 #include "pxr/imaging/glf/diagnostic.h"
37
38 PXR_NAMESPACE_OPEN_SCOPE
39
HdxOitVolumeRenderTask(HdSceneDelegate * delegate,SdfPath const & id)40 HdxOitVolumeRenderTask::HdxOitVolumeRenderTask(
41 HdSceneDelegate* delegate, SdfPath const& id)
42 : HdxRenderTask(delegate, id)
43 , _oitVolumeRenderPassShader(
44 std::make_shared<HdStRenderPassShader>(
45 HdxPackageRenderPassOitVolumeShader()))
46 , _isOitEnabled(HdxOitBufferAccessor::IsOitEnabled())
47 {
48 }
49
50 HdxOitVolumeRenderTask::~HdxOitVolumeRenderTask() = default;
51
52 void
_Sync(HdSceneDelegate * delegate,HdTaskContext * ctx,HdDirtyBits * dirtyBits)53 HdxOitVolumeRenderTask::_Sync(
54 HdSceneDelegate* delegate,
55 HdTaskContext* ctx,
56 HdDirtyBits* dirtyBits)
57 {
58 HD_TRACE_FUNCTION();
59 HF_MALLOC_TAG_FUNCTION();
60
61 if (_isOitEnabled) {
62 HdxRenderTask::_Sync(delegate, ctx, dirtyBits);
63 }
64 }
65
66 void
Prepare(HdTaskContext * ctx,HdRenderIndex * renderIndex)67 HdxOitVolumeRenderTask::Prepare(HdTaskContext* ctx,
68 HdRenderIndex* renderIndex)
69 {
70 HD_TRACE_FUNCTION();
71 HF_MALLOC_TAG_FUNCTION();
72
73 // OIT buffers take up significant GPU resources. Skip if there are no
74 // oit draw items (i.e. no volumetric draw items)
75 if (_isOitEnabled && HdxRenderTask::_HasDrawItems()) {
76 HdxRenderTask::Prepare(ctx, renderIndex);
77 HdxOitBufferAccessor(ctx).RequestOitBuffers();
78
79 if (HdRenderPassStateSharedPtr const state = _GetRenderPassState(ctx)) {
80 _oitVolumeRenderPassShader->UpdateAovInputTextures(
81 state->GetAovInputBindings(),
82 renderIndex);
83 }
84 }
85 }
86
87 void
Execute(HdTaskContext * ctx)88 HdxOitVolumeRenderTask::Execute(HdTaskContext* ctx)
89 {
90 HD_TRACE_FUNCTION();
91 HF_MALLOC_TAG_FUNCTION();
92
93 GLF_GROUP_FUNCTION();
94
95 if (!_isOitEnabled || !HdxRenderTask::_HasDrawItems()) {
96 return;
97 }
98
99 //
100 // Pre Execute Setup
101 //
102
103 HdxOitBufferAccessor oitBufferAccessor(ctx);
104
105 oitBufferAccessor.RequestOitBuffers();
106 oitBufferAccessor.InitializeOitBuffersIfNecessary();
107
108 HdRenderPassStateSharedPtr renderPassState = _GetRenderPassState(ctx);
109 if (!TF_VERIFY(renderPassState)) return;
110
111 HdStRenderPassState* extendedState =
112 dynamic_cast<HdStRenderPassState*>(renderPassState.get());
113 if (!TF_VERIFY(extendedState, "OIT only works with HdSt")) {
114 return;
115 }
116
117 extendedState->SetUseSceneMaterials(true);
118 renderPassState->SetDepthFunc(HdCmpFuncAlways);
119 // Setting cull style for consistency even though it is hard-coded in
120 // shaders/volume.glslfx.
121 renderPassState->SetCullStyle(HdCullStyleBack);
122
123 if(!oitBufferAccessor.AddOitBufferBindings(_oitVolumeRenderPassShader)) {
124 TF_CODING_ERROR(
125 "No OIT buffers allocated but needed by OIT volume render task");
126 return;
127 }
128
129 // We render into a SSBO -- not MSSA compatible
130 bool oldMSAA = glIsEnabled(GL_MULTISAMPLE);
131 glDisable(GL_MULTISAMPLE);
132 // XXX When rendering HdStPoints we set GL_POINTS and assume that
133 // GL_POINT_SMOOTH is enabled by default. This renders circles instead
134 // of squares. However, when toggling MSAA off (above) we see GL_POINTS
135 // start to render squares (driver bug?).
136 // For now we always enable GL_POINT_SMOOTH.
137 // XXX Switch points rendering to emit quad with FS that draws circle.
138 bool oldPointSmooth = glIsEnabled(GL_POINT_SMOOTH);
139 glEnable(GL_POINT_SMOOTH);
140
141 // XXX
142 //
143 // To show volumes that intersect the far clipping plane, we might consider
144 // calling glEnable(GL_DEPTH_CLAMP) here.
145
146 // XXX HdxRenderTask::Prepare calls HdStRenderPassState::Prepare.
147 // This sets the cullStyle for the render pass shader.
148 // Since Oit uses a custom render pass shader, we must manually
149 // set cullStyle.
150 _oitVolumeRenderPassShader->SetCullStyle(
151 renderPassState->GetCullStyle());
152
153 //
154 // Translucent pixels pass
155 //
156 extendedState->SetRenderPassShader(_oitVolumeRenderPassShader);
157 renderPassState->SetEnableDepthMask(false);
158 renderPassState->SetColorMasks({HdRenderPassState::ColorMaskNone});
159 HdxRenderTask::Execute(ctx);
160
161 //
162 // Post Execute Restore
163 //
164
165 if (oldMSAA) {
166 glEnable(GL_MULTISAMPLE);
167 }
168
169 if (!oldPointSmooth) {
170 glDisable(GL_POINT_SMOOTH);
171 }
172 }
173
174
175 PXR_NAMESPACE_CLOSE_SCOPE
176