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