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 
25 #include "pxr/imaging/garch/glApi.h"
26 
27 #include "pxr/imaging/glf/contextCaps.h"
28 #include "pxr/imaging/glf/glContext.h"
29 #include "pxr/imaging/glf/testGLContext.h"
30 
31 #include "pxr/imaging/hd/changeTracker.h"
32 #include "pxr/imaging/hd/driver.h"
33 #include "pxr/imaging/hd/engine.h"
34 #include "pxr/imaging/hd/tokens.h"
35 
36 #include "pxr/imaging/hd/camera.h"
37 #include "pxr/imaging/hdSt/light.h"
38 #include "pxr/imaging/hdSt/renderDelegate.h"
39 #include "pxr/imaging/hdSt/renderPass.h"
40 #include "pxr/imaging/hdSt/renderPassState.h"
41 
42 #include "pxr/imaging/hdx/unitTestDelegate.h"
43 
44 #include "pxr/imaging/hgi/hgi.h"
45 #include "pxr/imaging/hgi/tokens.h"
46 
47 #include "pxr/base/tf/errorMark.h"
48 
49 #include <iostream>
50 #include <memory>
51 
52 #define VERIFY_PERF_COUNT(token, count) \
53             TF_VERIFY(perfLog.GetCounter(token) == count, \
54                     "expected %d found %.0f", \
55                     count,\
56                     perfLog.GetCounter(token));
57 
58 PXR_NAMESPACE_USING_DIRECTIVE
59 
60 class Hd_TestTask final : public HdTask
61 {
62 public:
Hd_TestTask(HdRenderPassSharedPtr const & renderPass,HdRenderPassStateSharedPtr const & renderPassState)63     Hd_TestTask(HdRenderPassSharedPtr const &renderPass,
64                 HdRenderPassStateSharedPtr const &renderPassState)
65     : HdTask(SdfPath::EmptyPath())
66     , _renderPass(renderPass)
67     , _renderPassState(renderPassState)
68     {
69     }
70 
Sync(HdSceneDelegate *,HdTaskContext *,HdDirtyBits *)71     virtual void Sync(HdSceneDelegate*,
72                       HdTaskContext*,
73                       HdDirtyBits*) override
74     {
75         _renderPass->Sync();
76     }
77 
Prepare(HdTaskContext * ctx,HdRenderIndex * renderIndex)78     virtual void Prepare(HdTaskContext* ctx,
79                          HdRenderIndex* renderIndex) override
80     {
81         _renderPassState->Prepare(renderIndex->GetResourceRegistry());
82     }
83 
Execute(HdTaskContext * ctx)84     virtual void Execute(HdTaskContext* ctx) override
85     {
86         _renderPass->Execute(_renderPassState, GetRenderTags());
87     }
88 
89 private:
90     HdRenderPassSharedPtr _renderPass;
91     HdRenderPassStateSharedPtr _renderPassState;
92 };
93 
CameraAndLightTest()94 static void CameraAndLightTest()
95 {
96     // Hgi and HdDriver should be constructed before HdEngine to ensure they
97     // are destructed last. Hgi may be used during engine/delegate destruction.
98     HgiUniquePtr hgi = Hgi::CreatePlatformDefaultHgi();
99     HdDriver driver{HgiTokens->renderDriver, VtValue(hgi.get())};
100 
101     HdStRenderDelegate renderDelegate;
102     std::unique_ptr<HdRenderIndex> index(
103         HdRenderIndex::New(&renderDelegate, {&driver}));
104     TF_VERIFY(index);
105     std::unique_ptr<Hdx_UnitTestDelegate> delegate(
106                                          new Hdx_UnitTestDelegate(index.get()));
107 
108     HdChangeTracker& tracker = index->GetChangeTracker();
109     HdPerfLog& perfLog = HdPerfLog::GetInstance();
110     perfLog.Enable();
111     HdRprimCollection collection(HdTokens->geometry,
112         HdReprSelector(HdReprTokens->hull));
113     HdRenderPassStateSharedPtr renderPassState(new HdStRenderPassState());
114     HdRenderPassSharedPtr renderPass(
115         new HdSt_RenderPass(index.get(), collection));
116     HdEngine engine;
117 
118     HdTaskSharedPtr drawTask = std::make_shared<Hd_TestTask>(renderPass,
119                                                              renderPassState);
120     HdTaskSharedPtrVector tasks = { drawTask };
121 
122     GfMatrix4d tx(1.0f);
123     tx.SetRow(3, GfVec4f(5, 0, 5, 1.0));
124     SdfPath cube("/geometry");
125     delegate->AddCube(cube, tx);
126 
127     SdfPath camera("/camera_test");
128     SdfPath light("/light");
129 
130     delegate->AddCamera(camera);
131     delegate->AddLight(light, GlfSimpleLight());
132     delegate->SetLight(light, HdLightTokens->shadowCollection,
133                       VtValue(HdRprimCollection(HdTokens->geometry,
134                                         HdReprSelector(HdReprTokens->hull))));
135 
136     engine.Execute(index.get(), &tasks);
137 
138     VERIFY_PERF_COUNT(HdPerfTokens->rebuildBatches, 1);
139 
140     // Update camera matrix
141     delegate->SetCamera(camera, GfMatrix4d(2), GfMatrix4d(2));
142     tracker.MarkSprimDirty(camera, HdCamera::DirtyViewMatrix);
143     tracker.MarkSprimDirty(camera, HdCamera::DirtyProjMatrix);
144 
145     engine.Execute(index.get(), &tasks);
146 
147     // batch should not be rebuilt
148     VERIFY_PERF_COUNT(HdPerfTokens->rebuildBatches, 1);
149 
150     // Update shadow collection
151     delegate->SetLight(light, HdLightTokens->shadowCollection,
152                       VtValue(HdRprimCollection(HdTokens->geometry,
153                         HdReprSelector(HdReprTokens->refined))));
154     tracker.MarkSprimDirty(light, HdLight::DirtyCollection);
155 
156     engine.Execute(index.get(), &tasks);
157 
158     // batch rebuilt
159     VERIFY_PERF_COUNT(HdPerfTokens->rebuildBatches, 2);
160 
161     // Update shadow collection again with the same data
162     delegate->SetLight(light, HdLightTokens->shadowCollection,
163                       VtValue(HdRprimCollection(HdTokens->geometry,
164                                 HdReprSelector(HdReprTokens->refined))));
165     tracker.MarkSprimDirty(light, HdLight::DirtyCollection);
166 
167     engine.Execute(index.get(), &tasks);
168 
169     // batch should not be rebuilt
170     VERIFY_PERF_COUNT(HdPerfTokens->rebuildBatches, 2);
171 }
172 
main()173 int main()
174 {
175     TfErrorMark mark;
176 
177     // Test uses ContextCaps, so need to create a GL instance.
178     GlfTestGLContext::RegisterGLContextCallbacks();
179     GarchGLApiLoad();
180     GlfSharedGLContextScopeHolder sharedContext;
181     GlfContextCaps::InitInstance();
182 
183     CameraAndLightTest();
184 
185     TF_VERIFY(mark.IsClean());
186 
187     if (mark.IsClean()) {
188         std::cout << "OK" << std::endl;
189         return EXIT_SUCCESS;
190     } else {
191         std::cout << "FAILED" << std::endl;
192         return EXIT_FAILURE;
193     }
194 }
195 
196