1 // Copyright 2020 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 "host-common/opengl/OpenglEsPipe.h"
15
16 #include "aemu/base/Optional.h"
17 #include "aemu/base/files/PathUtils.h"
18 #include "aemu/base/files/StreamSerializing.h"
19 #include "aemu/base/threads/FunctorThread.h"
20 #include "aemu/base/system/System.h"
21 #include "host-common/globals.h"
22 // #include "loadpng.h"
23 #include "host-common/opengl/GLProcessPipe.h"
24 #include "host-common/opengles-pipe.h"
25 #include "host-common/opengles.h"
26 // #include "snapshot/Loader.h"
27 // #include "snapshot/Saver.h"
28 // #include "snapshot/Snapshotter.h"
29
30 #include <atomic>
31
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 // Set to 1 or 2 for debug traces
37 #define DEBUG 0
38
39 #if DEBUG >= 1
40 #define D(...) printf(__VA_ARGS__), printf("\n"), fflush(stdout)
41 #else
42 #define D(...) ((void)0)
43 #endif
44
45 #if DEBUG >= 2
46 #define DD(...) printf(__VA_ARGS__), printf("\n"), fflush(stdout)
47 #else
48 #define DD(...) ((void)0)
49 #endif
50
51 using ChannelBuffer = gfxstream::RenderChannel::Buffer;
52 using gfxstream::RenderChannel;
53 using gfxstream::RenderChannelPtr;
54 using ChannelState = gfxstream::RenderChannel::State;
55 using IoResult = gfxstream::RenderChannel::IoResult;
56 // using android::base::Stopwatch;
57 // using android::snapshot::Snapshotter;
58
59 #define OPENGL_SAVE_VERSION 1
60
61 namespace android {
62 namespace opengl {
63
64 // TODO (b/138549350): See if Android/Fuchsia pipe protocols can be unified
65 // to give the best performance in each guest OS.
66 enum class RecvMode {
67 Android = 0,
68 Fuchsia = 1,
69 VirtioGpu = 2,
70 };
71
72 static RecvMode recvMode = RecvMode::Android;
73
74 namespace {
75
76 class EmuglPipe : public AndroidPipe {
77 public:
78
79 //////////////////////////////////////////////////////////////////////////
80 // The pipe service class for this implementation.
81 class Service : public AndroidPipe::Service {
82 public:
Service()83 Service() : AndroidPipe::Service("opengles") {}
84
85 // Create a new EmuglPipe instance.
create(void * hwPipe,const char * args,AndroidPipeFlags flags)86 AndroidPipe* create(void* hwPipe, const char* args, AndroidPipeFlags flags) override {
87 return createPipe(hwPipe, this, args, flags);
88 }
89
canLoad() const90 bool canLoad() const override { return true; }
91
preLoad(android::base::Stream * stream)92 virtual void preLoad(android::base::Stream* stream) override {
93 // #ifdef SNAPSHOT_PROFILE
94 // mLoadMeter.restartUs();
95 // #endif
96 // const bool hasRenderer = stream->getByte();
97 // const auto& renderer = android_getOpenglesRenderer();
98 // if (hasRenderer != (bool)renderer) {
99 // // die?
100 // return;
101 // }
102 // if (!hasRenderer) {
103 // return;
104 // }
105 // int version = stream->getBe32();
106 // (void)version;
107 // renderer->load(stream, Snapshotter::get().loader().textureLoader());
108 // #ifdef SNAPSHOT_PROFILE
109 // printf("OpenglEs preload time: %lld ms\n",
110 // (long long)(mLoadMeter.elapsedUs() / 1000));
111 // #endif
112 }
113
postLoad(android::base::Stream * stream)114 void postLoad(android::base::Stream* stream) override {
115 if (const auto& renderer = android_getOpenglesRenderer()) {
116 renderer->resumeAll();
117 }
118 #ifdef SNAPSHOT_PROFILE
119 printf("OpenglEs total load time: %lld ms\n",
120 (long long)(mLoadMeter.elapsedUs() / 1000));
121 #endif
122 }
123
preSave(android::base::Stream * stream)124 void preSave(android::base::Stream* stream) override {
125 // #ifdef SNAPSHOT_PROFILE
126 // mSaveMeter.restartUs();
127 // #endif
128 // if (const auto& renderer = android_getOpenglesRenderer()) {
129 // renderer->pauseAllPreSave();
130 // stream->putByte(1);
131 // stream->putBe32(OPENGL_SAVE_VERSION);
132 // renderer->save(stream,
133 // Snapshotter::get().saver().textureSaver());
134 //
135 // writeScreenshot(*renderer);
136 // } else {
137 // stream->putByte(0);
138 // }
139 }
140
postSave(android::base::Stream * stream)141 void postSave(android::base::Stream* stream) override {
142 if (const auto& renderer = android_getOpenglesRenderer()) {
143 renderer->resumeAll();
144 }
145 #ifdef SNAPSHOT_PROFILE
146 printf("OpenglEs total save time: %lld ms\n",
147 (long long)(mSaveMeter.elapsedUs() / 1000));
148 #endif
149 }
150
load(void * hwPipe,const char * args,android::base::Stream * stream)151 virtual AndroidPipe* load(void* hwPipe,
152 const char* args,
153 android::base::Stream* stream) override {
154 return createPipe(hwPipe, this, args, ANDROID_PIPE_DEFAULT, stream);
155 }
156
157 private:
createPipe(void * hwPipe,Service * service,const char * args,AndroidPipeFlags flags,android::base::Stream * loadStream=nullptr)158 static AndroidPipe* createPipe(
159 void* hwPipe,
160 Service* service,
161 const char* args,
162 AndroidPipeFlags flags,
163 android::base::Stream* loadStream = nullptr) {
164 const auto& renderer = android_getOpenglesRenderer();
165 if (!renderer) {
166 // This should never happen, unless there is a bug in the
167 // emulator's initialization, or the system image, or we're
168 // loading from an incompatible snapshot.
169 D("Trying to open the OpenGLES pipe without GPU emulation!");
170 return nullptr;
171 }
172
173 auto pipe = new EmuglPipe(hwPipe, service, renderer, flags, loadStream);
174 if (!pipe->mIsWorking) {
175 delete pipe;
176 pipe = nullptr;
177 }
178 return pipe;
179 }
180
writeScreenshot(gfxstream::Renderer & renderer)181 void writeScreenshot(gfxstream::Renderer& renderer) {
182 // #if SNAPSHOT_PROFILE > 1
183 // Stopwatch sw;
184 // #endif
185 // if (!mSnapshotCallbackRegistered) {
186 // // We have to wait for the screenshot saving thread, but
187 // // there's no need to join it too soon: it is ok to only
188 // // block when the rest of snapshot saving is complete.
189 // // Snapshotter::get().addOperationCallback(
190 // // [this](Snapshotter::Operation op,
191 // // Snapshotter::Stage stage) {
192 // // if (op == Snapshotter::Operation::Save &&
193 // // stage == Snapshotter::Stage::End) {
194 // // if (mScreenshotSaver) {
195 // // mScreenshotSaver->wait();
196 // // mScreenshotSaver.clear();
197 // // }
198 // // }
199 // // });
200 // mSnapshotCallbackRegistered = true;
201 // }
202 // // always do 4 channel screenshot because swiftshader_indirect
203 // // has issues with 3 channels
204 // const unsigned int nChannels = 4;
205 // unsigned int width;
206 // unsigned int height;
207 // std::vector<unsigned char> pixels;
208 // renderer.getScreenshot(nChannels, &width, &height, pixels);
209 // #if SNAPSHOT_PROFILE > 1
210 // printf("Screenshot load texture time %lld ms\n",
211 // (long long)(sw.elapsedUs() / 1000));
212 // #endif
213 // if (width > 0 && height > 0) {
214 // std::string dataDir =
215 // Snapshotter::get().saver().snapshot().dataDir();
216 // mScreenshotSaver.emplace([nChannels, width, height,
217 // dataDir = std::move(dataDir),
218 // pixels = std::move(pixels)] {
219 // #if SNAPSHOT_PROFILE > 1
220 // Stopwatch sw;
221 // #endif
222 // std::string fileName = android::base::PathUtils::join(
223 // dataDir, "screenshot.png");
224 // // TODO: fix the screenshot rotation?
225 // savepng(fileName.c_str(), nChannels, width, height,
226 // SKIN_ROTATION_0,
227 // const_cast<unsigned char*>(pixels.data()));
228 // #if SNAPSHOT_PROFILE > 1
229 // printf("Screenshot image write time %lld ms\n",
230 // (long long)(sw.elapsedUs() / 1000));
231 // #endif
232 // });
233 // mScreenshotSaver->start();
234 // }
235 }
236
237 base::Optional<base::FunctorThread> mScreenshotSaver;
238 #ifdef SNAPSHOT_PROFILE
239 Stopwatch mSaveMeter;
240 Stopwatch mLoadMeter;
241 #endif
242 };
243
244 /////////////////////////////////////////////////////////////////////////
245 // Constructor, check that |mIsWorking| is true after this call to verify
246 // that everything went well.
EmuglPipe(void * hwPipe,Service * service,const gfxstream::RendererPtr & renderer,AndroidPipeFlags flags,android::base::Stream * loadStream=nullptr)247 EmuglPipe(void* hwPipe, Service* service, const gfxstream::RendererPtr& renderer,
248 AndroidPipeFlags flags, android::base::Stream* loadStream = nullptr)
249 : AndroidPipe(hwPipe, service) {
250 bool isWorking = true;
251 if (loadStream) {
252 DD("%s: loading GLES pipe state for hwpipe=%p", __func__, mHwPipe);
253 isWorking = (bool)loadStream->getBe32();
254 android::base::loadBuffer(loadStream, &mDataForReading);
255 mDataForReadingLeft = loadStream->getBe32();
256 }
257
258 uint32_t virtioGpuContextId = -1;
259 if (flags & ANDROID_PIPE_VIRTIO_GPU_BIT) {
260 virtioGpuContextId = (uint32_t)(uintptr_t)hwPipe;
261 }
262
263 mChannel = renderer->createRenderChannel(loadStream, virtioGpuContextId);
264 if (!mChannel) {
265 D("Failed to create an OpenGLES pipe channel!");
266 return;
267 }
268
269 mIsWorking = isWorking;
270 mChannel->setEventCallback([this](RenderChannel::State events) {
271 onChannelHostEvent(events);
272 });
273 }
274
275 //////////////////////////////////////////////////////////////////////////
276 // Overriden AndroidPipe methods
277
onSave(android::base::Stream * stream)278 virtual void onSave(android::base::Stream* stream) override {
279 DD("%s: saving GLES pipe state for hwpipe=%p", __FUNCTION__, mHwPipe);
280 stream->putBe32(mIsWorking);
281 android::base::saveBuffer(stream, mDataForReading);
282 stream->putBe32(mDataForReadingLeft);
283
284 mChannel->onSave(stream);
285 }
286
onGuestClose(PipeCloseReason reason)287 virtual void onGuestClose(PipeCloseReason reason) override {
288 D("%s", __func__);
289 mIsWorking = false;
290 mChannel->stop();
291 // Make sure there's no operation scheduled for this pipe instance to
292 // run on the main thread.
293 abortPendingOperation();
294 delete this;
295 }
296
onGuestPoll() const297 virtual unsigned onGuestPoll() const override {
298 DD("%s", __func__);
299
300 unsigned ret = 0;
301 if (mDataForReadingLeft > 0) {
302 ret |= PIPE_POLL_IN;
303 }
304 ChannelState state = mChannel->state();
305 if ((state & ChannelState::CanRead) != 0) {
306 ret |= PIPE_POLL_IN;
307 }
308 if ((state & ChannelState::CanWrite) != 0) {
309 ret |= PIPE_POLL_OUT;
310 }
311 if ((state & ChannelState::Stopped) != 0) {
312 ret |= PIPE_POLL_HUP;
313 }
314 DD("%s: returning %d", __func__, ret);
315 return ret;
316 }
317
onGuestRecv(AndroidPipeBuffer * buffers,int numBuffers)318 virtual int onGuestRecv(AndroidPipeBuffer* buffers,
319 int numBuffers) override {
320 DD("%s", __func__);
321
322 // Consume the pipe's dataForReading, then put the next received data
323 // piece there. Repeat until the buffers are full or we're out of data
324 // in the channel.
325 int len = 0;
326 size_t buffOffset = 0;
327
328 auto buff = buffers;
329 const auto buffEnd = buff + numBuffers;
330 while (buff != buffEnd) {
331 if (mDataForReadingLeft == 0) {
332 if (android::opengl::recvMode == android::opengl::RecvMode::Android) {
333 // No data left, read a new chunk from the channel.
334 int spinCount = 20;
335 for (;;) {
336
337 auto result = mChannel->tryRead(&mDataForReading);
338 if (result == IoResult::Ok) {
339 mDataForReadingLeft = mDataForReading.size();
340 break;
341 }
342 DD("%s: tryRead() failed with %d", __func__, (int)result);
343 if (len > 0) {
344 DD("%s: returning %d bytes", __func__, (int)len);
345 return len;
346 }
347 // This failed either because the channel was stopped
348 // from the host, or if there was no data yet in the
349 if (result == IoResult::Error) {
350 return PIPE_ERROR_IO;
351 }
352 // Spin a little before declaring there is nothing
353 // to read. Many GL calls are much faster than the
354 // whole host-to-guest-to-host transition.
355 if (--spinCount > 0) {
356 continue;
357 }
358 DD("%s: returning PIPE_ERROR_AGAIN", __func__);
359 return PIPE_ERROR_AGAIN;
360 }
361 } else if (android::opengl::recvMode == android::opengl::RecvMode::Fuchsia) {
362 // No data left, return if we already received some data,
363 // otherwise read a new chunk from the channel.
364 if (len > 0) {
365 DD("%s: returning %d bytes", __func__, (int)len);
366 return len;
367 }
368 // Block a little before declaring there is nothing
369 // to read. This gives the render thread a chance to
370 // process pending data before we return control to
371 // the guest. The amount of time we block here should
372 // be kept at a minimum. It's preferred to instead have
373 // the guest block on work that takes a significant
374 // amount of time.
375
376 const RenderChannel::Duration kBlockAtMostUs = 100;
377 auto currTime = android::base::getUnixTimeUs();
378 auto result = mChannel->readBefore(&mDataForReading, currTime + kBlockAtMostUs);
379
380 if (result != IoResult::Ok) {
381 DD("%s: tryRead() failed with %d", __func__, (int)result);
382 // This failed either because the channel was stopped
383 // from the host, or if there was no data yet in the
384 // channel.
385 if (len > 0) {
386 DD("%s: returning %d bytes", __func__, (int)len);
387 return len;
388 }
389 if (result == IoResult::Error) {
390 return PIPE_ERROR_IO;
391 }
392
393 DD("%s: returning PIPE_ERROR_AGAIN", __func__);
394 return PIPE_ERROR_AGAIN;
395 }
396 mDataForReadingLeft = mDataForReading.size();
397 } else { // Virtio-gpu
398 // No data left, return if we already received some data,
399 // otherwise read a new chunk from the channel.
400 if (len > 0) {
401 DD("%s: returning %d bytes", __func__, (int)len);
402 return len;
403 }
404 // Block a little before declaring there is nothing
405 // to read. This gives the render thread a chance to
406 // process pending data before we return control to
407 // the guest. The amount of time we block here should
408 // be kept at a minimum. It's preferred to instead have
409 // the guest block on work that takes a significant
410 // amount of time.
411
412 const RenderChannel::Duration kBlockAtMostUs = 10000;
413 auto currTime = android::base::getUnixTimeUs();
414 auto result = mChannel->readBefore(&mDataForReading, currTime + kBlockAtMostUs);
415
416 if (result != IoResult::Ok) {
417 DD("%s: tryRead() failed with %d", __func__, (int)result);
418 // This failed either because the channel was stopped
419 // from the host, or if there was no data yet in the
420 // channel.
421 if (len > 0) {
422 DD("%s: returning %d bytes", __func__, (int)len);
423 return len;
424 }
425 if (result == IoResult::Error) {
426 return PIPE_ERROR_IO;
427 }
428
429 DD("%s: returning PIPE_ERROR_AGAIN", __func__);
430 return PIPE_ERROR_AGAIN;
431 }
432 mDataForReadingLeft = mDataForReading.size();
433 }
434 }
435
436 const size_t curSize = std::min<size_t>(buff->size - buffOffset,
437 mDataForReadingLeft);
438 memcpy(buff->data + buffOffset,
439 mDataForReading.data() +
440 (mDataForReading.size() - mDataForReadingLeft),
441 curSize);
442
443 len += curSize;
444 mDataForReadingLeft -= curSize;
445 buffOffset += curSize;
446 if (buffOffset == buff->size) {
447 ++buff;
448 buffOffset = 0;
449 }
450 }
451
452 DD("%s: received %d bytes", __func__, (int)len);
453 return len;
454 }
455
onGuestSend(const AndroidPipeBuffer * buffers,int numBuffers,void ** newPipePtr)456 virtual int onGuestSend(const AndroidPipeBuffer* buffers,
457 int numBuffers,
458 void** newPipePtr) override {
459 DD("%s", __func__);
460
461 if (!mIsWorking) {
462 DD("%s: pipe already closed!", __func__);
463 return PIPE_ERROR_IO;
464 }
465
466 // Count the total bytes to send.
467 int count = 0;
468 for (int n = 0; n < numBuffers; ++n) {
469 count += buffers[n].size;
470 }
471
472 // Copy everything into a single ChannelBuffer.
473 ChannelBuffer outBuffer;
474 outBuffer.resize_noinit(count);
475 auto ptr = outBuffer.data();
476 for (int n = 0; n < numBuffers; ++n) {
477 memcpy(ptr, buffers[n].data, buffers[n].size);
478 ptr += buffers[n].size;
479 }
480
481 D("%s: %p sending %d bytes to host", __func__, this, count);
482 // Send it through the channel.
483 auto result = mChannel->tryWrite(std::move(outBuffer));
484 if (result != IoResult::Ok) {
485 D("%s: tryWrite() failed with %d", __func__, (int)result);
486 return result == IoResult::Error ? PIPE_ERROR_IO : PIPE_ERROR_AGAIN;
487 }
488
489 return count;
490 }
491
onGuestWantWakeOn(int flags)492 virtual void onGuestWantWakeOn(int flags) override {
493 DD("%s: flags=%d", __func__, flags);
494
495 // Translate |flags| into ChannelState flags.
496 ChannelState wanted = ChannelState::Empty;
497 if (flags & PIPE_WAKE_READ) {
498 wanted |= ChannelState::CanRead;
499 }
500 if (flags & PIPE_WAKE_WRITE) {
501 wanted |= ChannelState::CanWrite;
502 }
503
504 // Signal events that are already available now.
505 ChannelState state = mChannel->state();
506 ChannelState available = state & wanted;
507 DD("%s: state=%d wanted=%d available=%d", __func__, (int)state,
508 (int)wanted, (int)available);
509 if (available != ChannelState::Empty) {
510 DD("%s: signaling events %d", __func__, (int)available);
511 signalState(available);
512 wanted &= ~available;
513 }
514
515 // Ask the channel to be notified of remaining events.
516 if (wanted != ChannelState::Empty) {
517 DD("%s: waiting for events %d", __func__, (int)wanted);
518 mChannel->setWantedEvents(wanted);
519 }
520 }
521
522 private:
523 // Called to signal the guest that read/write wake events occured.
524 // Note: this can be called from either the guest or host render
525 // thread.
signalState(ChannelState state)526 void signalState(ChannelState state) {
527 int wakeFlags = 0;
528 if ((state & ChannelState::CanRead) != 0) {
529 wakeFlags |= PIPE_WAKE_READ;
530 }
531 if ((state & ChannelState::CanWrite) != 0) {
532 wakeFlags |= PIPE_WAKE_WRITE;
533 }
534 if (wakeFlags != 0) {
535 this->signalWake(wakeFlags);
536 }
537 }
538
539 // Called when an i/o event occurs on the render channel
onChannelHostEvent(ChannelState state)540 void onChannelHostEvent(ChannelState state) {
541 D("%s: events %d (working %d)", __func__, (int)state, (int)mIsWorking);
542 // NOTE: This is called from the host-side render thread.
543 // but closeFromHost() and signalWake() can be called from
544 // any thread.
545 if (!mIsWorking) {
546 return;
547 }
548 if ((state & ChannelState::Stopped) != 0) {
549 this->closeFromHost();
550 return;
551 }
552 signalState(state);
553 }
554
555 // A RenderChannel pointer used for communication.
556 RenderChannelPtr mChannel;
557
558 // Set to |true| if the pipe is in working state, |false| means we're not
559 // initialized or the pipe is closed.
560 bool mIsWorking = false;
561
562 // These two variables serve as a reading buffer for the guest.
563 // Each time we get a read request, first we extract a single chunk from
564 // the |mChannel| into here, and then copy its content into the
565 // guest-supplied memory.
566 // If guest didn't have enough room for the whole buffer, we track the
567 // number of remaining bytes in |mDataForReadingLeft| for the next read().
568 uint32_t mDataForReadingLeft = 0;
569 ChannelBuffer mDataForReading;
570
571 DISALLOW_COPY_ASSIGN_AND_MOVE(EmuglPipe);
572 };
573
574 } // namespace
575
registerPipeService()576 void registerPipeService() {
577 android::AndroidPipe::Service::add(std::make_unique<EmuglPipe::Service>());
578 registerGLProcessPipeService();
579 }
580
pipeSetRecvMode(int mode)581 void pipeSetRecvMode(int mode) {
582 recvMode = (RecvMode)mode;
583 }
584
585 } // namespace opengl
586 } // namespace android
587
588 // Declared in android/opengles-pipe.h
android_init_opengles_pipe()589 void android_init_opengles_pipe() {
590 android::opengl::registerPipeService();
591 }
592
android_opengles_pipe_set_recv_mode(int mode)593 void android_opengles_pipe_set_recv_mode(int mode) {
594 android::opengl::pipeSetRecvMode(mode);
595 }
596
597