1 //
2 // Copyright 2018 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/hd/renderThread.h"
25 #include "pxr/base/tf/diagnostic.h"
26
27 PXR_NAMESPACE_OPEN_SCOPE
28
HdRenderThread()29 HdRenderThread::HdRenderThread()
30 : _renderCallback(_DefaultRenderCallback)
31 , _shutdownCallback(_DefaultShutdownCallback)
32 , _requestedState(StateInitial)
33 , _stopRequested(false)
34 , _pauseRender(false)
35 , _rendering(false)
36 {
37 }
38
~HdRenderThread()39 HdRenderThread::~HdRenderThread()
40 {
41 StopThread();
42 }
43
44 void
SetRenderCallback(std::function<void ()> renderCallback)45 HdRenderThread::SetRenderCallback(std::function<void()> renderCallback)
46 {
47 _renderCallback = renderCallback;
48 }
49
50 void
SetShutdownCallback(std::function<void ()> shutdownCallback)51 HdRenderThread::SetShutdownCallback(std::function<void()> shutdownCallback)
52 {
53 _shutdownCallback = shutdownCallback;
54 }
55
56 void
StartThread()57 HdRenderThread::StartThread()
58 {
59 if (_renderThread.joinable()) {
60 TF_CODING_ERROR("StartThread() called while render thread is "
61 "already running");
62 return;
63 }
64
65 _requestedState = StateIdle;
66 _renderThread = std::thread(&HdRenderThread::_RenderLoop, this);
67 }
68
69 void
StopThread()70 HdRenderThread::StopThread()
71 {
72 if (!_renderThread.joinable()) {
73 return;
74 }
75
76 {
77 _enableRender.clear();
78 std::unique_lock<std::mutex> lock(_requestedStateMutex);
79 _requestedState = StateTerminated;
80 _requestedStateCV.notify_one();
81 }
82 _renderThread.join();
83 }
84
85 bool
IsThreadRunning()86 HdRenderThread::IsThreadRunning()
87 {
88 return _renderThread.joinable();
89 }
90
91 void
StartRender()92 HdRenderThread::StartRender()
93 {
94 if (!IsRendering()) {
95 std::unique_lock<std::mutex> lock(_requestedStateMutex);
96 _enableRender.test_and_set();
97 _requestedState = StateRendering;
98 _rendering.store(true);
99 _requestedStateCV.notify_one();
100 }
101 }
102
103 void
StopRender()104 HdRenderThread::StopRender()
105 {
106 if (IsRendering()) {
107 _enableRender.clear();
108 std::unique_lock<std::mutex> lock(_requestedStateMutex);
109 _requestedState = StateIdle;
110 _rendering.store(false);
111 }
112 }
113
114 bool
IsRendering()115 HdRenderThread::IsRendering()
116 {
117 return _rendering.load();
118 }
119
120 void
PauseRender()121 HdRenderThread::PauseRender()
122 {
123 _pauseDirty.store(true);
124 _pauseRender.store(true);
125 }
126
127 void
ResumeRender()128 HdRenderThread::ResumeRender()
129 {
130 _pauseDirty.store(true);
131 _pauseRender.store(false);
132 }
133
134 bool
IsStopRequested()135 HdRenderThread::IsStopRequested()
136 {
137 if (!_enableRender.test_and_set()) {
138 _stopRequested = true;
139 }
140
141 return _stopRequested;
142 }
143
144 bool
IsPauseRequested()145 HdRenderThread::IsPauseRequested()
146 {
147 return _pauseRender.load();
148 }
149
150 bool
IsPauseDirty()151 HdRenderThread::IsPauseDirty() {
152 return _pauseDirty.exchange(false);
153 }
154
155 std::unique_lock<std::mutex>
LockFramebuffer()156 HdRenderThread::LockFramebuffer()
157 {
158 return std::unique_lock<std::mutex>(_frameBufferMutex);
159 }
160
161 void
_RenderLoop()162 HdRenderThread::_RenderLoop()
163 {
164 while (1) {
165 std::unique_lock<std::mutex> lock(_requestedStateMutex);
166 _requestedStateCV.wait(lock, [this]() {
167 return _requestedState != StateIdle;
168 });
169 if (_requestedState == StateRendering) {
170 _renderCallback();
171 _stopRequested = false;
172 _rendering.store(false);
173 _requestedState = StateIdle;
174 }
175 else if (_requestedState == StateTerminated) {
176 break;
177 }
178 }
179 _shutdownCallback();
180 }
181
182 /*static*/
183 void
_DefaultRenderCallback()184 HdRenderThread::_DefaultRenderCallback()
185 {
186 TF_CODING_ERROR("StartThread() called without a render callback set");
187 }
188
189 /*static*/
190 void
_DefaultShutdownCallback()191 HdRenderThread::_DefaultShutdownCallback()
192 {
193 }
194
195 PXR_NAMESPACE_CLOSE_SCOPE
196
197