• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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