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