1 // Copyright (C) 2016 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "RenderChannelImpl.h"
15
16 #include "RenderThread.h"
17 #include "aemu/base/synchronization/Lock.h"
18
19 #include <algorithm>
20 #include <utility>
21
22 #include <assert.h>
23 #include <string.h>
24
25 #define EMUGL_DEBUG_LEVEL 0
26 #include "host-common/debug.h"
27
28 namespace gfxstream {
29
30 using Buffer = RenderChannel::Buffer;
31 using IoResult = android::base::BufferQueueResult;
32 using State = RenderChannel::State;
33 using AutoLock = android::base::AutoLock;
34
35 // These constants correspond to the capacities of buffer queues
36 // used by each RenderChannelImpl instance. Benchmarking shows that
37 // it's important to have a large queue for guest -> host transfers,
38 // but a much smaller one works for host -> guest ones.
39 // Note: 32-bit Windows just doesn't have enough RAM to allocate optimal
40 // capacity.
41 #if defined(_WIN32) && !defined(_WIN64)
42 static constexpr size_t kGuestToHostQueueCapacity = 32U;
43 #else
44 static constexpr size_t kGuestToHostQueueCapacity = 1024U;
45 #endif
46 static constexpr size_t kHostToGuestQueueCapacity = 16U;
47
RenderChannelImpl(android::base::Stream * loadStream,uint32_t contextId)48 RenderChannelImpl::RenderChannelImpl(android::base::Stream* loadStream, uint32_t contextId)
49 : mFromGuest(kGuestToHostQueueCapacity, mLock),
50 mToGuest(kHostToGuestQueueCapacity, mLock) {
51 if (loadStream) {
52 mFromGuest.onLoadLocked(loadStream);
53 mToGuest.onLoadLocked(loadStream);
54 mState = (State)loadStream->getBe32();
55 mWantedEvents = (State)loadStream->getBe32();
56 #ifndef NDEBUG
57 // Make sure we're in a consistent state after loading.
58 const auto state = mState;
59 updateStateLocked();
60 assert(state == mState);
61 #endif
62 } else {
63 updateStateLocked();
64 }
65 mRenderThread.reset(new RenderThread(this, loadStream, contextId));
66 mRenderThread->start();
67 }
68
setEventCallback(EventCallback && callback)69 void RenderChannelImpl::setEventCallback(EventCallback&& callback) {
70 mEventCallback = std::move(callback);
71 notifyStateChangeLocked();
72 }
73
setWantedEvents(State state)74 void RenderChannelImpl::setWantedEvents(State state) {
75 D("state=%d", (int)state);
76 AutoLock lock(mLock);
77 mWantedEvents |= state;
78 notifyStateChangeLocked();
79 }
80
state() const81 RenderChannel::State RenderChannelImpl::state() const {
82 AutoLock lock(mLock);
83 return mState;
84 }
85
tryWrite(Buffer && buffer)86 IoResult RenderChannelImpl::tryWrite(Buffer&& buffer) {
87 D("buffer size=%d", (int)buffer.size());
88 AutoLock lock(mLock);
89 auto result = mFromGuest.tryPushLocked(std::move(buffer));
90 updateStateLocked();
91 DD("mFromGuest.tryPushLocked() returned %d, state %d", (int)result,
92 (int)mState);
93 return result;
94 }
95
waitUntilWritable()96 void RenderChannelImpl::waitUntilWritable() {
97 AutoLock lock(mLock);
98 mFromGuest.waitUntilPushableLocked();
99 }
100
tryRead(Buffer * buffer)101 IoResult RenderChannelImpl::tryRead(Buffer* buffer) {
102 D("enter");
103 AutoLock lock(mLock);
104 auto result = mToGuest.tryPopLocked(buffer);
105 updateStateLocked();
106 DD("mToGuest.tryPopLocked() returned %d, buffer size %d, state %d",
107 (int)result, (int)buffer->size(), (int)mState);
108 return result;
109 }
110
readBefore(Buffer * buffer,Duration waitUntilUs)111 IoResult RenderChannelImpl::readBefore(Buffer* buffer, Duration waitUntilUs) {
112 D("enter");
113 AutoLock lock(mLock);
114 auto result = mToGuest.popLockedBefore(buffer, waitUntilUs);
115 updateStateLocked();
116 DD("mToGuest.popLockedBefore() returned %d, buffer size %d, state %d",
117 (int)result, (int)buffer->size(), (int)mState);
118 return result;
119 }
120
waitUntilReadable()121 void RenderChannelImpl::waitUntilReadable() {
122 AutoLock lock(mLock);
123 mToGuest.waitUntilPopableLocked();
124 }
125
stop()126 void RenderChannelImpl::stop() {
127 D("enter");
128 AutoLock lock(mLock);
129 mFromGuest.closeLocked();
130 mToGuest.closeLocked();
131 mEventCallback = [](State state) {};
132 }
133
writeToGuest(Buffer && buffer)134 bool RenderChannelImpl::writeToGuest(Buffer&& buffer) {
135 D("buffer size=%d", (int)buffer.size());
136 AutoLock lock(mLock);
137 IoResult result = mToGuest.pushLocked(std::move(buffer));
138 updateStateLocked();
139 D("mToGuest.pushLocked() returned %d, state %d", (int)result, (int)mState);
140 notifyStateChangeLocked();
141 return result == IoResult::Ok;
142 }
143
readFromGuest(Buffer * buffer,bool blocking)144 IoResult RenderChannelImpl::readFromGuest(Buffer* buffer, bool blocking) {
145 D("enter");
146 AutoLock lock(mLock);
147 IoResult result;
148 if (blocking) {
149 result = mFromGuest.popLocked(buffer);
150 } else {
151 result = mFromGuest.tryPopLocked(buffer);
152 }
153 updateStateLocked();
154 DD("mFromGuest.%s() return %d, buffer size %d, state %d",
155 blocking ? "popLocked" : "tryPopLocked", (int)result,
156 (int)buffer->size(), (int)mState);
157 notifyStateChangeLocked();
158 return result;
159 }
160
stopFromHost()161 void RenderChannelImpl::stopFromHost() {
162 D("enter");
163
164 AutoLock lock(mLock);
165 mFromGuest.closeLocked();
166 mToGuest.closeLocked();
167 mState |= State::Stopped;
168 notifyStateChangeLocked();
169 mEventCallback = [](State state) {};
170 }
171
isStopped() const172 bool RenderChannelImpl::isStopped() const {
173 AutoLock lock(mLock);
174 return (mState & State::Stopped) != 0;
175 }
176
renderThread() const177 RenderThread* RenderChannelImpl::renderThread() const {
178 return mRenderThread.get();
179 }
180
pausePreSnapshot()181 void RenderChannelImpl::pausePreSnapshot() {
182 AutoLock lock(mLock);
183 mFromGuest.setSnapshotModeLocked(true);
184 mToGuest.setSnapshotModeLocked(true);
185 }
186
resume()187 void RenderChannelImpl::resume() {
188 AutoLock lock(mLock);
189 mFromGuest.setSnapshotModeLocked(false);
190 mToGuest.setSnapshotModeLocked(false);
191 }
192
~RenderChannelImpl()193 RenderChannelImpl::~RenderChannelImpl() {
194 // Make sure the render thread is stopped before the channel is gone.
195 mRenderThread->wait();
196 }
197
updateStateLocked()198 void RenderChannelImpl::updateStateLocked() {
199 State state = RenderChannel::State::Empty;
200
201 if (mToGuest.canPopLocked()) {
202 state |= State::CanRead;
203 }
204 if (mFromGuest.canPushLocked()) {
205 state |= State::CanWrite;
206 }
207 if (mToGuest.isClosedLocked()) {
208 state |= State::Stopped;
209 }
210 mState = state;
211 }
212
notifyStateChangeLocked()213 void RenderChannelImpl::notifyStateChangeLocked() {
214 // Always report stop events, event if not explicitly asked for.
215 State available = mState & (mWantedEvents | State::Stopped);
216 if (available != 0) {
217 D("callback with %d", (int)available);
218 mWantedEvents &= ~mState;
219 mEventCallback(available);
220 }
221 }
222
onSave(android::base::Stream * stream)223 void RenderChannelImpl::onSave(android::base::Stream* stream) {
224 D("enter");
225 AutoLock lock(mLock);
226 mFromGuest.onSaveLocked(stream);
227 mToGuest.onSaveLocked(stream);
228 stream->putBe32(static_cast<uint32_t>(mState));
229 stream->putBe32(static_cast<uint32_t>(mWantedEvents));
230 lock.unlock();
231 mRenderThread->save(stream);
232 }
233
234 } // namespace gfxstream
235