aboutsummaryrefslogtreecommitdiff
path: root/src/gfxstream/host/RendererImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gfxstream/host/RendererImpl.cpp')
-rw-r--r--src/gfxstream/host/RendererImpl.cpp742
1 files changed, 742 insertions, 0 deletions
diff --git a/src/gfxstream/host/RendererImpl.cpp b/src/gfxstream/host/RendererImpl.cpp
new file mode 100644
index 00000000000..33972b4a3bc
--- /dev/null
+++ b/src/gfxstream/host/RendererImpl.cpp
@@ -0,0 +1,742 @@
+// 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 <assert.h>
+
+#include <algorithm>
+#include <utility>
+#include <variant>
+
+#include "FrameBuffer.h"
+#include "RenderChannelImpl.h"
+#include "RenderThread.h"
+#include "aemu/base/system/System.h"
+#include "aemu/base/threads/WorkerThread.h"
+#include "host-common/logging.h"
+#include "snapshot/common.h"
+
+#if GFXSTREAM_ENABLE_HOST_GLES
+#include "gl/EmulatedEglFenceSync.h"
+#endif
+
+namespace gfxstream {
+
+// 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()
+ : mCleanupWorker([](Cmd cmd) {
+ using android::base::WorkerProcessingResult;
+ struct {
+ WorkerProcessingResult operator()(CleanProcessResources resources) {
+ FrameBuffer::getFB()->cleanupProcGLObjects(resources.puid);
+ // resources.resource are destroyed automatically when going out of the scope.
+ return WorkerProcessingResult::Continue;
+ }
+ WorkerProcessingResult operator()(Exit) {
+ return WorkerProcessingResult::Stop;
+ }
+ } visitor;
+ return std::visit(visitor, std::move(cmd));
+ }) {
+ mCleanupWorker.start();
+ }
+
+ ~ProcessCleanupThread() {
+ mCleanupWorker.enqueue(Exit{});
+ }
+
+ void cleanup(uint64_t processId, std::unique_ptr<ProcessResources> resource) {
+ mCleanupWorker.enqueue(CleanProcessResources{
+ .puid = processId,
+ .resource = std::move(resource),
+ });
+ }
+
+ void stop() {
+ mCleanupWorker.enqueue(Exit{});
+ mCleanupWorker.join();
+ }
+
+ void waitForCleanup() {
+ mCleanupWorker.waitQueuedItems();
+ }
+
+private:
+ struct CleanProcessResources {
+ uint64_t puid;
+ std::unique_ptr<ProcessResources> resource;
+ };
+ struct Exit {};
+ using Cmd = std::variant<CleanProcessResources, Exit>;
+ DISALLOW_COPY_AND_ASSIGN(ProcessCleanupThread);
+
+ android::base::WorkerThread<Cmd> mCleanupWorker;
+};
+
+RendererImpl::RendererImpl() {
+ mCleanupThread.reset(new ProcessCleanupThread());
+}
+
+RendererImpl::~RendererImpl() {
+ stop(true);
+ // We can't finish until the loader render thread has
+ // completed else can get a crash at the end of the destructor.
+ if (mLoaderRenderThread) {
+ mLoaderRenderThread->wait();
+ }
+ mRenderWindow.reset();
+}
+
+bool RendererImpl::initialize(int width, int height, bool useSubWindow, bool egl2egl) {
+ if (android::base::getEnvironmentVariable("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();
+ }
+ mCleanupThread->waitForCleanup();
+ 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, uint32_t virtioGpuContextId) {
+ const auto channel =
+ std::make_shared<RenderChannelImpl>(loadStream, virtioGpuContextId);
+ {
+ 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();
+ }
+
+ GL_LOG("Started new RenderThread (total %" PRIu64 ") @%p",
+ static_cast<uint64_t>(mChannels.size()), channel->renderThread());
+ }
+
+ return channel;
+}
+
+void RendererImpl::addListener(FrameBufferChangeEventListener* listener) {
+ mRenderWindow->addListener(listener);
+}
+
+void RendererImpl::removeListener(FrameBufferChangeEventListener* listener) {
+ mRenderWindow->removeListener(listener);
+}
+
+void* RendererImpl::addressSpaceGraphicsConsumerCreate(
+ struct asg_context context,
+ android::base::Stream* loadStream,
+ android::emulation::asg::ConsumerCallbacks callbacks,
+ uint32_t contextId, uint32_t capsetId,
+ std::optional<std::string> nameOpt) {
+ auto thread = new RenderThread(context, loadStream, callbacks, contextId,
+ capsetId, std::move(nameOpt));
+ thread->start();
+ android::base::AutoLock lock(mAddressSpaceRenderThreadLock);
+ mAddressSpaceRenderThreads.emplace(thread);
+ return (void*)thread;
+}
+
+void RendererImpl::addressSpaceGraphicsConsumerDestroy(void* consumer) {
+ RenderThread* thread = (RenderThread*)consumer;
+ {
+ android::base::AutoLock lock(mAddressSpaceRenderThreadLock);
+ mAddressSpaceRenderThreads.erase(thread);
+ }
+ thread->wait();
+ delete thread;
+}
+
+void RendererImpl::addressSpaceGraphicsConsumerPreSave(void* consumer) {
+ RenderThread* thread = (RenderThread*)consumer;
+ thread->pausePreSnapshot();
+}
+
+void RendererImpl::addressSpaceGraphicsConsumerSave(void* consumer, android::base::Stream* stream) {
+ RenderThread* thread = (RenderThread*)consumer;
+ thread->save(stream);
+}
+
+void RendererImpl::addressSpaceGraphicsConsumerPostSave(void* consumer) {
+ RenderThread* thread = (RenderThread*)consumer;
+ thread->resume(true);
+}
+
+void RendererImpl::addressSpaceGraphicsConsumerRegisterPostLoadRenderThread(void* consumer) {
+ RenderThread* thread = (RenderThread*)consumer;
+ mAdditionalPostLoadRenderThreads.push_back(thread);
+}
+
+void RendererImpl::pauseAllPreSave() {
+ {
+ android::base::AutoLock lock(mChannelsLock);
+ if (mStopped) {
+ return;
+ }
+ for (const auto& c : mChannels) {
+ c->renderThread()->pausePreSnapshot();
+ }
+ }
+ {
+ android::base::AutoLock lock(mAddressSpaceRenderThreadLock);
+ for (const auto& thread : mAddressSpaceRenderThreads) {
+ thread->pausePreSnapshot();
+ }
+ }
+ waitForProcessCleanup();
+}
+
+void RendererImpl::resumeAll(bool waitForSave) {
+ {
+ android::base::AutoLock lock(mAddressSpaceRenderThreadLock);
+ for (const auto t : mAdditionalPostLoadRenderThreads) {
+ t->resume(waitForSave);
+ }
+ }
+ {
+ android::base::AutoLock lock(mChannelsLock);
+ if (mStopped) {
+ return;
+ }
+ for (const auto& c : mChannels) {
+ c->renderThread()->resume(waitForSave);
+ }
+ for (const auto& thread : mAddressSpaceRenderThreads) {
+ thread->resume(waitForSave);
+ }
+ mAdditionalPostLoadRenderThreads.clear();
+ }
+
+ 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);
+}
+
+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);
+#if GFXSTREAM_ENABLE_HOST_GLES
+ gl::EmulatedEglFenceSync::onLoad(stream);
+#endif
+
+ return res;
+}
+
+void RendererImpl::fillGLESUsages(android_studio::EmulatorGLESUsages* usages) {
+ auto fb = FrameBuffer::getFB();
+#if GFXSTREAM_ENABLE_HOST_GLES
+ if (fb) fb->fillGLESUsages(usages);
+#endif
+}
+
+int RendererImpl::getScreenshot(unsigned int nChannels, unsigned int* width, unsigned int* height,
+ uint8_t* pixels, size_t* cPixels, int displayId = 0,
+ int desiredWidth = 0, int desiredHeight = 0,
+ int desiredRotation = 0, Rect rect = {{0, 0}, {0, 0}}) {
+ auto fb = FrameBuffer::getFB();
+ if (fb) {
+ return fb->getScreenshot(nChannels, width, height, pixels, cPixels,
+ displayId, desiredWidth, desiredHeight,
+ desiredRotation, rect);
+ }
+ *cPixels = 0;
+ return -1;
+}
+
+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::onGuestGraphicsProcessCreate(uint64_t puid) {
+ FrameBuffer::getFB()->createGraphicsProcessResources(puid);
+}
+
+void RendererImpl::cleanupProcGLObjects(uint64_t puid) {
+ std::unique_ptr<ProcessResources> resource =
+ FrameBuffer::getFB()->removeGraphicsProcessResources(puid);
+ mCleanupThread->cleanup(puid, std::move(resource));
+}
+
+static struct AndroidVirtioGpuOps sVirtioGpuOps = {
+ .create_buffer_with_handle =
+ [](uint64_t size, uint32_t handle) {
+ FrameBuffer::getFB()->createBufferWithHandle(size, handle);
+ },
+ .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_buffer = [](uint32_t handle) { FrameBuffer::getFB()->closeBuffer(handle); },
+ .close_color_buffer = [](uint32_t handle) { FrameBuffer::getFB()->closeColorBuffer(handle); },
+ .update_buffer =
+ [](uint32_t handle, uint64_t offset, uint64_t size, void* bytes) {
+ FrameBuffer::getFB()->updateBuffer(handle, offset, size, bytes);
+ },
+ .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_buffer =
+ [](uint32_t handle, uint64_t offset, uint64_t size, void* bytes) {
+ FrameBuffer::getFB()->readBuffer(handle, offset, size, bytes);
+ },
+ .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); },
+ .async_post_color_buffer =
+ [](uint32_t handle, CpuCompletionCallback cb) {
+ FrameBuffer::getFB()->postWithCallback(handle, cb);
+ },
+ .repost = []() { FrameBuffer::getFB()->repost(); },
+#if GFXSTREAM_ENABLE_HOST_GLES
+ .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, void* metadata) {
+ FrameBuffer::getFB()->swapTexturesAndUpdateColorBuffer(
+ colorbufferhandle, x, y, width, height, format, type, texture_type, textures);
+ },
+#endif
+ .get_last_posted_color_buffer =
+ []() { return FrameBuffer::getFB()->getLastPostedColorBuffer(); },
+#if GFXSTREAM_ENABLE_HOST_GLES
+ .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); },
+#endif
+ .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(guestManaged);
+ },
+#if GFXSTREAM_ENABLE_HOST_GLES
+ .async_wait_for_gpu_with_cb =
+ [](uint64_t eglsync, FenceCompletionCallback cb) {
+ FrameBuffer::getFB()->asyncWaitForGpuWithCb(eglsync, cb);
+ },
+#endif
+ .async_wait_for_gpu_vulkan_with_cb =
+ [](uint64_t device, uint64_t fence, FenceCompletionCallback cb) {
+ FrameBuffer::getFB()->asyncWaitForGpuVulkanWithCb(device, fence, cb);
+ },
+ .async_wait_for_gpu_vulkan_qsri_with_cb =
+ [](uint64_t image, FenceCompletionCallback cb) {
+ FrameBuffer::getFB()->asyncWaitForGpuVulkanQsriWithCb(image, cb);
+ },
+ .wait_for_gpu_vulkan_qsri =
+ [](uint64_t image) { FrameBuffer::getFB()->waitForGpuVulkanQsri(image); },
+ .update_color_buffer_from_framework_format =
+ [](uint32_t handle, int x, int y, int width, int height, uint32_t fwkFormat,
+ uint32_t format, uint32_t type, void* pixels, void* pMetadata) {
+ FrameBuffer::getFB()->updateColorBufferFromFrameworkFormat(
+ handle, x, y, width, height, (FrameworkFormat)fwkFormat, format, type, pixels,
+ pMetadata);
+ },
+ .platform_import_resource =
+ [](uint32_t handle, uint32_t info, void* resource) {
+ return FrameBuffer::getFB()->platformImportResource(handle, info, resource);
+ },
+ .platform_resource_info =
+ [](uint32_t handle, int32_t* width, int32_t* height, int32_t* internal_format) {
+ return FrameBuffer::getFB()->getColorBufferInfo(handle, width, height, internal_format);
+ },
+#if GFXSTREAM_ENABLE_HOST_GLES
+ .platform_create_shared_egl_context =
+ []() { return FrameBuffer::getFB()->platformCreateSharedEglContext(); },
+ .platform_destroy_shared_egl_context =
+ [](void* context) {
+ return FrameBuffer::getFB()->platformDestroySharedEglContext(context);
+ },
+#endif
+};
+
+struct AndroidVirtioGpuOps* RendererImpl::getVirtioGpuOps() {
+ return &sVirtioGpuOps;
+}
+
+void RendererImpl::snapshotOperationCallback(int op, int 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;
+ }
+}
+
+void RendererImpl::setVsyncHz(int vsyncHz) {
+ if (mRenderWindow) {
+ mRenderWindow->setVsyncHz(vsyncHz);
+ }
+}
+
+void RendererImpl::setDisplayConfigs(int configId, int w, int h,
+ int dpiX, int dpiY) {
+ if (mRenderWindow) {
+ mRenderWindow->setDisplayConfigs(configId, w, h, dpiX, dpiY);
+ }
+}
+
+void RendererImpl::setDisplayActiveConfig(int configId) {
+ if (mRenderWindow) {
+ mRenderWindow->setDisplayActiveConfig(configId);
+ }
+}
+
+const void* RendererImpl::getEglDispatch() {
+#if GFXSTREAM_ENABLE_HOST_GLES
+ return FrameBuffer::getFB()->getEglDispatch();
+#else
+ return nullptr;
+#endif
+}
+
+const void* RendererImpl::getGles2Dispatch() {
+#if GFXSTREAM_ENABLE_HOST_GLES
+ return FrameBuffer::getFB()->getGles2Dispatch();
+#else
+ return nullptr;
+#endif
+}
+
+} // namespace gfxstream