Start building libOpenglRender and add more host support files

Bug: 171711491
Change-Id: Ie1a6ca9cc5310e5ee2a72ae558450bcb4f2b9263
diff --git a/stream-servers/RendererImpl.cpp b/stream-servers/RendererImpl.cpp
new file mode 100644
index 0000000..7dd6508
--- /dev/null
+++ b/stream-servers/RendererImpl.cpp
@@ -0,0 +1,605 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "RendererImpl.h"
+
+#include "RenderChannelImpl.h"
+#include "RenderThread.h"
+
+#include "android/base/system/System.h"
+#include "android/utils/debug.h"
+
+#include "emugl/common/logging.h"
+#include "ErrorLog.h"
+#include "FenceSync.h"
+#include "FrameBuffer.h"
+
+#include <algorithm>
+#include <utility>
+
+#include <assert.h>
+
+namespace emugl {
+
+// kUseSubwindowThread is used to determine whether the RenderWindow should use
+// a separate thread to manage its subwindow GL/GLES context.
+// For now, this feature is disabled entirely for the following
+// reasons:
+//
+// - It must be disabled on Windows at all times, otherwise the main window
+//   becomes unresponsive after a few seconds of user interaction (e.g. trying
+//   to move it over the desktop). Probably due to the subtle issues around
+//   input on this platform (input-queue is global, message-queue is
+//   per-thread). Also, this messes considerably the display of the
+//   main window when running the executable under Wine.
+//
+// - On Linux/XGL and OSX/Cocoa, this used to be necessary to avoid corruption
+//   issues with the GL state of the main window when using the SDL UI.
+//   After the switch to Qt, this is no longer necessary and may actually cause
+//   undesired interactions between the UI thread and the RenderWindow thread:
+//   for example, in a multi-monitor setup the context might be recreated when
+//   dragging the window between monitors, triggering a Qt-specific callback
+//   in the context of RenderWindow thread, which will become blocked on the UI
+//   thread, which may in turn be blocked on something else.
+static const bool kUseSubwindowThread = false;
+
+// This object manages the cleanup of guest process resources when the process
+// exits. It runs the cleanup in a separate thread to never block the main
+// render thread for a low-priority task.
+class RendererImpl::ProcessCleanupThread {
+public:
+    ProcessCleanupThread()
+        : mCleanupThread([this]() {
+              while (const auto id = mCleanupProcessIds.receive()) {
+                  FrameBuffer::getFB()->cleanupProcGLObjects(*id);
+              }
+          }) {
+        mCleanupThread.start();
+    }
+
+    ~ProcessCleanupThread() {
+        mCleanupProcessIds.stop();
+        mCleanupThread.wait();
+    }
+
+    void cleanup(uint64_t processId) {
+        mCleanupProcessIds.send(processId);
+    }
+
+    void stop() {
+        mCleanupProcessIds.stop();
+    }
+
+    void waitForCleanup() {
+        mCleanupProcessIds.waitForEmpty();
+    }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(ProcessCleanupThread);
+
+    android::base::MessageChannel<uint64_t, 64> mCleanupProcessIds;
+    android::base::FunctorThread mCleanupThread;
+};
+
+RendererImpl::RendererImpl() {
+    mCleanupThread.reset(new ProcessCleanupThread());
+}
+
+RendererImpl::~RendererImpl() {
+    stop(true);
+    mRenderWindow.reset();
+}
+
+bool RendererImpl::initialize(int width, int height, bool useSubWindow, bool egl2egl) {
+    if (android::base::System::get()->envGet("ANDROID_EMUGL_VERBOSE") == "1") {
+        base_enable_verbose_logs();
+    }
+
+    if (mRenderWindow) {
+        return false;
+    }
+
+    std::unique_ptr<RenderWindow> renderWindow(new RenderWindow(
+            width, height, kUseSubwindowThread, useSubWindow, egl2egl));
+    if (!renderWindow) {
+        ERR("Could not create rendering window class\n");
+        GL_LOG("Could not create rendering window class");
+        return false;
+    }
+    if (!renderWindow->isValid()) {
+        ERR("Could not initialize emulated framebuffer\n");
+        return false;
+    }
+
+    mRenderWindow = std::move(renderWindow);
+    GL_LOG("OpenGL renderer initialized successfully");
+
+    // This render thread won't do anything but will only preload resources
+    // for the real threads to start faster.
+    mLoaderRenderThread.reset(new RenderThread(nullptr));
+    mLoaderRenderThread->start();
+
+    return true;
+}
+
+void RendererImpl::stop(bool wait) {
+    android::base::AutoLock lock(mChannelsLock);
+    mStopped = true;
+    auto channels = std::move(mChannels);
+    lock.unlock();
+
+    if (const auto fb = FrameBuffer::getFB()) {
+        fb->setShuttingDown();
+    }
+    for (const auto& c : channels) {
+        c->stopFromHost();
+    }
+    // We're stopping the renderer, so there's no need to clean up resources
+    // of some pending processes: we'll destroy everything soon.
+    mCleanupThread->stop();
+
+    mStoppedChannels.insert(mStoppedChannels.end(),
+                            std::make_move_iterator(channels.begin()),
+                            std::make_move_iterator(channels.end()));
+
+    if (!wait) {
+        return;
+    }
+
+    // Each render channel is referenced in the corresponing pipe object, so
+    // even if we clear the |channels| vector they could still be alive
+    // for a while. This means we need to make sure to wait for render thread
+    // exit explicitly.
+    for (const auto& c : mStoppedChannels) {
+        c->renderThread()->wait();
+    }
+    mStoppedChannels.clear();
+}
+
+void RendererImpl::finish() {
+    {
+        android::base::AutoLock lock(mChannelsLock);
+        mRenderWindow->setPaused(true);
+    }
+    cleanupRenderThreads();
+    {
+        android::base::AutoLock lock(mChannelsLock);
+        mRenderWindow->setPaused(false);
+    }
+}
+
+void RendererImpl::cleanupRenderThreads() {
+    android::base::AutoLock lock(mChannelsLock);
+    const auto channels = std::move(mChannels);
+    assert(mChannels.empty());
+    lock.unlock();
+    for (const auto& c : channels) {
+        // Please DO NOT notify the guest about this event (DO NOT call
+        // stopFromHost() ), because this is used to kill old threads when
+        // loading from a snapshot, and the newly loaded guest should not
+        // be notified for those behavior.
+        c->stop();
+    }
+    for (const auto& c : channels) {
+        c->renderThread()->wait();
+    }
+}
+
+void RendererImpl::waitForProcessCleanup() {
+    mCleanupThread->waitForCleanup();
+    // Recreate it to make sure we've started from scratch and that we've
+    // finished all in-progress cleanups as well.
+    mCleanupThread.reset(new ProcessCleanupThread());
+}
+
+RenderChannelPtr RendererImpl::createRenderChannel(
+        android::base::Stream* loadStream) {
+    const auto channel = std::make_shared<RenderChannelImpl>(loadStream);
+    {
+        android::base::AutoLock lock(mChannelsLock);
+
+        if (mStopped) {
+            return nullptr;
+        }
+
+        // Clean up the stopped channels.
+        mChannels.erase(
+                std::remove_if(mChannels.begin(), mChannels.end(),
+                               [](const std::shared_ptr<RenderChannelImpl>& c) {
+                                   return c->renderThread()->isFinished();
+                               }),
+                mChannels.end());
+        mChannels.emplace_back(channel);
+
+        // Take the time to check if our loader thread is done as well.
+        if (mLoaderRenderThread && mLoaderRenderThread->isFinished()) {
+            mLoaderRenderThread->wait();
+            mLoaderRenderThread.reset();
+        }
+
+        DBG("Started new RenderThread (total %" PRIu64 ") @%p\n",
+            static_cast<uint64_t>(mChannels.size()), channel->renderThread());
+    }
+
+    return channel;
+}
+
+void* RendererImpl::addressSpaceGraphicsConsumerCreate(
+    struct asg_context context,
+    android::emulation::asg::ConsumerCallbacks callbacks) {
+    auto thread = new RenderThread(context, callbacks);
+    thread->start();
+    return (void*)thread;
+}
+
+void RendererImpl::addressSpaceGraphicsConsumerDestroy(void* consumer) {
+    RenderThread* thread = (RenderThread*)consumer;
+    thread->wait();
+    delete thread;
+}
+
+void RendererImpl::pauseAllPreSave() {
+    android::base::AutoLock lock(mChannelsLock);
+    if (mStopped) {
+        return;
+    }
+    for (const auto& c : mChannels) {
+        c->renderThread()->pausePreSnapshot();
+    }
+    lock.unlock();
+    waitForProcessCleanup();
+}
+
+void RendererImpl::resumeAll() {
+    {
+        android::base::AutoLock lock(mChannelsLock);
+        if (mStopped) {
+            return;
+        }
+        for (const auto& c : mChannels) {
+            c->renderThread()->resume();
+        }
+    }
+
+    repaintOpenGLDisplay();
+}
+
+void RendererImpl::save(android::base::Stream* stream,
+                        const android::snapshot::ITextureSaverPtr& textureSaver) {
+    stream->putByte(mStopped);
+    if (mStopped) {
+        return;
+    }
+    auto fb = FrameBuffer::getFB();
+    assert(fb);
+    fb->onSave(stream, textureSaver);
+
+    FenceSync::onSave(stream);
+}
+
+bool RendererImpl::load(android::base::Stream* stream,
+                        const android::snapshot::ITextureLoaderPtr& textureLoader) {
+
+#ifdef SNAPSHOT_PROFILE
+    android::base::System::Duration startTime =
+            android::base::System::get()->getUnixTimeUs();
+#endif
+    waitForProcessCleanup();
+#ifdef SNAPSHOT_PROFILE
+    printf("Previous session cleanup time: %lld ms\n",
+           (long long)(android::base::System::get()
+                               ->getUnixTimeUs() -
+                       startTime) /
+                   1000);
+#endif
+
+    mStopped = stream->getByte();
+    if (mStopped) {
+        return true;
+    }
+    auto fb = FrameBuffer::getFB();
+    assert(fb);
+
+    bool res = true;
+
+    res = fb->onLoad(stream, textureLoader);
+    FenceSync::onLoad(stream);
+
+    return res;
+}
+
+void RendererImpl::fillGLESUsages(android_studio::EmulatorGLESUsages* usages) {
+    auto fb = FrameBuffer::getFB();
+    if (fb) fb->fillGLESUsages(usages);
+}
+
+void RendererImpl::getScreenshot(unsigned int nChannels, unsigned int* width,
+        unsigned int* height, std::vector<unsigned char>& pixels, int displayId,
+        int desiredWidth, int desiredHeight, SkinRotation desiredRotation) {
+    auto fb = FrameBuffer::getFB();
+    if (fb) fb->getScreenshot(nChannels, width, height, pixels, displayId,
+                              desiredWidth, desiredHeight, desiredRotation);
+}
+
+void RendererImpl::setMultiDisplay(uint32_t id,
+                                   int32_t x,
+                                   int32_t y,
+                                   uint32_t w,
+                                   uint32_t h,
+                                   uint32_t dpi,
+                                   bool add) {
+    auto fb = FrameBuffer::getFB();
+    if (fb) {
+        if (add) {
+            fb->createDisplay(&id);
+            fb->setDisplayPose(id, x, y, w, h, dpi);
+        } else {
+            fb->destroyDisplay(id);
+        }
+    }
+}
+
+void RendererImpl::setMultiDisplayColorBuffer(uint32_t id, uint32_t cb) {
+    auto fb = FrameBuffer::getFB();
+    if (fb) {
+        fb->setDisplayColorBuffer(id, cb);
+    }
+}
+
+RendererImpl::HardwareStrings RendererImpl::getHardwareStrings() {
+    assert(mRenderWindow);
+
+    const char* vendor = nullptr;
+    const char* renderer = nullptr;
+    const char* version = nullptr;
+    if (!mRenderWindow->getHardwareStrings(&vendor, &renderer, &version)) {
+        return {};
+    }
+    HardwareStrings res;
+    res.vendor = vendor ? vendor : "";
+    res.renderer = renderer ? renderer : "";
+    res.version = version ? version : "";
+    return res;
+}
+
+void RendererImpl::setPostCallback(RendererImpl::OnPostCallback onPost,
+                                   void* context,
+                                   bool useBgraReadback,
+                                   uint32_t displayId) {
+    assert(mRenderWindow);
+    mRenderWindow->setPostCallback(onPost, context, displayId, useBgraReadback);
+}
+
+bool RendererImpl::asyncReadbackSupported() {
+    assert(mRenderWindow);
+    return mRenderWindow->asyncReadbackSupported();
+}
+
+RendererImpl::ReadPixelsCallback
+RendererImpl::getReadPixelsCallback() {
+    assert(mRenderWindow);
+    return mRenderWindow->getReadPixelsCallback();
+}
+
+RendererImpl::FlushReadPixelPipeline
+RendererImpl::getFlushReadPixelPipeline() {
+    assert(mRenderWindow);
+    return mRenderWindow->getFlushReadPixelPipeline();
+}
+
+bool RendererImpl::showOpenGLSubwindow(FBNativeWindowType window,
+                                       int wx,
+                                       int wy,
+                                       int ww,
+                                       int wh,
+                                       int fbw,
+                                       int fbh,
+                                       float dpr,
+                                       float zRot,
+                                       bool deleteExisting,
+                                       bool hideWindow) {
+    assert(mRenderWindow);
+    return mRenderWindow->setupSubWindow(window, wx, wy, ww, wh, fbw, fbh, dpr,
+                                         zRot, deleteExisting, hideWindow);
+}
+
+bool RendererImpl::destroyOpenGLSubwindow() {
+    assert(mRenderWindow);
+    return mRenderWindow->removeSubWindow();
+}
+
+void RendererImpl::setOpenGLDisplayRotation(float zRot) {
+    assert(mRenderWindow);
+    mRenderWindow->setRotation(zRot);
+}
+
+void RendererImpl::setOpenGLDisplayTranslation(float px, float py) {
+    assert(mRenderWindow);
+    mRenderWindow->setTranslation(px, py);
+}
+
+void RendererImpl::repaintOpenGLDisplay() {
+    assert(mRenderWindow);
+    mRenderWindow->repaint();
+}
+
+bool RendererImpl::hasGuestPostedAFrame() {
+    if (mRenderWindow) {
+        return mRenderWindow->hasGuestPostedAFrame();
+    }
+    return false;
+}
+
+void RendererImpl::resetGuestPostedAFrame() {
+    if (mRenderWindow) {
+        mRenderWindow->resetGuestPostedAFrame();
+    }
+}
+
+void RendererImpl::setScreenMask(int width, int height, const unsigned char* rgbaData) {
+    assert(mRenderWindow);
+    mRenderWindow->setScreenMask(width, height, rgbaData);
+}
+
+void RendererImpl::cleanupProcGLObjects(uint64_t puid) {
+    mCleanupThread->cleanup(puid);
+}
+
+static struct AndroidVirtioGpuOps sVirtioGpuOps = {
+        .create_color_buffer_with_handle =
+                [](uint32_t width,
+                   uint32_t height,
+                   uint32_t format,
+                   uint32_t fwkFormat,
+                   uint32_t handle) {
+                    FrameBuffer::getFB()->createColorBufferWithHandle(
+                            width, height, (GLenum)format,
+                            (FrameworkFormat)fwkFormat, handle);
+                },
+        .open_color_buffer =
+                [](uint32_t handle) {
+                    FrameBuffer::getFB()->openColorBuffer(handle);
+                },
+        .close_color_buffer =
+                [](uint32_t handle) {
+                    FrameBuffer::getFB()->closeColorBuffer(handle);
+                },
+        .update_color_buffer =
+                [](uint32_t handle,
+                   int x,
+                   int y,
+                   int width,
+                   int height,
+                   uint32_t format,
+                   uint32_t type,
+                   void* pixels) {
+                    FrameBuffer::getFB()->updateColorBuffer(
+                            handle, x, y, width, height, format, type, pixels);
+                },
+        .read_color_buffer =
+                [](uint32_t handle,
+                   int x,
+                   int y,
+                   int width,
+                   int height,
+                   uint32_t format,
+                   uint32_t type,
+                   void* pixels) {
+                    FrameBuffer::getFB()->readColorBuffer(
+                            handle, x, y, width, height, format, type, pixels);
+                },
+        .read_color_buffer_yuv =
+                [](uint32_t handle,
+                   int x,
+                   int y,
+                   int width,
+                   int height,
+                   void* pixels,
+                   uint32_t pixels_size) {
+                    FrameBuffer::getFB()->readColorBufferYUV(
+                            handle, x, y, width, height, pixels, pixels_size);
+                },
+        .post_color_buffer =
+                [](uint32_t handle) { FrameBuffer::getFB()->post(handle); },
+        .repost = []() { FrameBuffer::getFB()->repost(); },
+        .create_yuv_textures =
+                [](uint32_t type,
+                   uint32_t count,
+                   int width,
+                   int height,
+                   uint32_t* output) {
+                    FrameBuffer::getFB()->createYUVTextures(type, count, width,
+                                                            height, output);
+                },
+        .destroy_yuv_textures =
+                [](uint32_t type, uint32_t count, uint32_t* textures) {
+                    FrameBuffer::getFB()->destroyYUVTextures(type, count,
+                                                             textures);
+                },
+        .update_yuv_textures =
+                [](uint32_t type,
+                   uint32_t* textures,
+                   void* privData,
+                   void* func) {
+                    FrameBuffer::getFB()->updateYUVTextures(type, textures,
+                                                            privData, func);
+                },
+        .swap_textures_and_update_color_buffer =
+                [](uint32_t colorbufferhandle,
+                   int x,
+                   int y,
+                   int width,
+                   int height,
+                   uint32_t format,
+                   uint32_t type,
+                   uint32_t texture_type,
+                   uint32_t* textures) {
+                    FrameBuffer::getFB()->swapTexturesAndUpdateColorBuffer(
+                            colorbufferhandle, x, y, width, height, format,
+                            type, texture_type, textures);
+                },
+        .get_last_posted_color_buffer = []() {
+            return FrameBuffer::getFB()->getLastPostedColorBuffer();
+        },
+        .bind_color_buffer_to_texture = [](uint32_t handle) {
+            FrameBuffer::getFB()->bindColorBufferToTexture2(handle);
+        },
+        .get_global_egl_context = []() {
+            return FrameBuffer::getFB()->getGlobalEGLContext();
+        },
+        .wait_for_gpu = [](uint64_t eglsync) {
+            FrameBuffer::getFB()->waitForGpu(eglsync);
+        },
+        .wait_for_gpu_vulkan = [](uint64_t device, uint64_t fence) {
+            FrameBuffer::getFB()->waitForGpuVulkan(device, fence);
+        },
+        .set_guest_managed_color_buffer_lifetime = [](bool guestManaged) {
+            FrameBuffer::getFB()->setGuestManagedColorBufferLifetime(true);
+        },
+};
+
+struct AndroidVirtioGpuOps* RendererImpl::getVirtioGpuOps() {
+    return &sVirtioGpuOps;
+}
+
+void RendererImpl::snapshotOperationCallback(
+        android::snapshot::Snapshotter::Operation op,
+        android::snapshot::Snapshotter::Stage stage) {
+    using namespace android::snapshot;
+    switch (op) {
+        case Snapshotter::Operation::Load:
+            if (stage == Snapshotter::Stage::Start) {
+#ifdef SNAPSHOT_PROFILE
+             android::base::System::Duration startTime =
+                     android::base::System::get()->getUnixTimeUs();
+#endif
+                mRenderWindow->setPaused(true);
+                cleanupRenderThreads();
+#ifdef SNAPSHOT_PROFILE
+                printf("Previous session suspend time: %lld ms\n",
+                       (long long)(android::base::System::get()
+                                           ->getUnixTimeUs() -
+                                   startTime) /
+                               1000);
+#endif
+            }
+            if (stage == Snapshotter::Stage::End) {
+                mRenderWindow->setPaused(false);
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+}  // namespace emugl