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