Merge GfxStreamBackend into virtio-gpu-gfxstream-renderer.h
These two both expose the C API of the library, and we want to move to a
stream_renderer_init instead of gfxstream_backend_init.
Keeps around GfxStreamBackend.h temporarily until downstreams have
replaced their references.
Bug: b/249823013
Test: presubmit & downstream
Change-Id: If919766d2d61694cea3b8cf5291fb5823f26b355
diff --git a/stream-servers/Android.bp b/stream-servers/Android.bp
index 2484f6a..6318cdc 100644
--- a/stream-servers/Android.bp
+++ b/stream-servers/Android.bp
@@ -81,7 +81,6 @@
"FrameBuffer.cpp",
"GfxStreamAgents.cpp",
"virtio-gpu-gfxstream-renderer.cpp",
- "GfxStreamBackend.cpp",
"GfxStreamBackendInitOverride.cpp",
"VirtioGpuTimelines.cpp",
],
diff --git a/stream-servers/CMakeLists.txt b/stream-servers/CMakeLists.txt
index 8849e58..3041363 100644
--- a/stream-servers/CMakeLists.txt
+++ b/stream-servers/CMakeLists.txt
@@ -108,7 +108,6 @@
add_library(
gfxstream_backend
SHARED
- GfxStreamBackend.cpp
virtio-gpu-gfxstream-renderer.cpp)
target_link_libraries(
diff --git a/stream-servers/GfxStreamBackend.cpp b/stream-servers/GfxStreamBackend.cpp
deleted file mode 100644
index de41e6d..0000000
--- a/stream-servers/GfxStreamBackend.cpp
+++ /dev/null
@@ -1,532 +0,0 @@
-// Copyright (C) 2018 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 "GfxStreamBackend.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <fstream>
-#include <string>
-
-#include "FrameBuffer.h"
-#include "GfxStreamAgents.h"
-#include "VkCommonOperations.h"
-#include "VulkanDispatch.h"
-#include "aemu/base/files/MemStream.h"
-#include "aemu/base/Metrics.h"
-#include "aemu/base/files/PathUtils.h"
-#include "aemu/base/system/System.h"
-#include "host-common/AndroidPipe.h"
-#include "host-common/FeatureControl.h"
-#include "host-common/GfxstreamFatalError.h"
-#include "host-common/HostmemIdMapping.h"
-#include "host-common/address_space_device.h"
-#include "host-common/address_space_device.hpp"
-#include "host-common/address_space_graphics.h"
-#include "host-common/address_space_graphics_types.h"
-#include "host-common/android_pipe_device.h"
-#include "host-common/feature_control.h"
-#include "host-common/globals.h"
-#include "host-common/opengl/emugl_config.h"
-#include "host-common/opengles-pipe.h"
-#include "host-common/opengles.h"
-#include "host-common/refcount-pipe.h"
-#include "host-common/vm_operations.h"
-#include "host-common/window_agent.h"
-#include "render_api.h"
-#include "snapshot/interface.h"
-#include "vk_util.h"
-
-using emugl::ABORT_REASON_OTHER;
-using emugl::FatalError;
-
-#define GFXSTREAM_DEBUG_LEVEL 1
-
-#if GFXSTREAM_DEBUG_LEVEL >= 1
-#define GFXS_LOG(fmt, ...) \
- do { \
- fprintf(stdout, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); \
- fflush(stdout); \
- } while (0)
-
-#else
-#define GFXS_LOG(fmt,...)
-#endif
-
-extern "C" {
-#include "host-common/goldfish_pipe.h"
-#include "virtio-gpu-gfxstream-renderer.h"
-} // extern "C"
-
-using android::AndroidPipe;
-using android::base::pj;
-using android::base::MetricsLogger;
-
-#ifdef _WIN32
-#define VG_EXPORT __declspec(dllexport)
-#else
-#define VG_EXPORT __attribute__((visibility("default")))
-#endif
-
-#define POST_CALLBACK_DISPLAY_TYPE_X 0
-#define POST_CALLBACK_DISPLAY_TYPE_WAYLAND_SHARED_MEM 1
-#define POST_CALLBACK_DISPLAY_TYPE_WINDOWS_HWND 2
-
-struct renderer_display_info;
-typedef void (*get_pixels_t)(void*, uint32_t, uint32_t);
-static get_pixels_t sGetPixelsFunc = 0;
-typedef void (*post_callback_t)(void*, uint32_t, int, int, int, int, int, unsigned char*);
-
-// For reading back rendered contents to display
-extern "C" VG_EXPORT void get_pixels(void* pixels, uint32_t bytes);
-
-static const GoldfishPipeServiceOps goldfish_pipe_service_ops = {
- // guest_open()
- [](GoldfishHwPipe* hwPipe) -> GoldfishHostPipe* {
- return static_cast<GoldfishHostPipe*>(
- android_pipe_guest_open(hwPipe));
- },
- // guest_open_with_flags()
- [](GoldfishHwPipe* hwPipe, uint32_t flags) -> GoldfishHostPipe* {
- return static_cast<GoldfishHostPipe*>(
- android_pipe_guest_open_with_flags(hwPipe, flags));
- },
- // guest_close()
- [](GoldfishHostPipe* hostPipe, GoldfishPipeCloseReason reason) {
- static_assert((int)GOLDFISH_PIPE_CLOSE_GRACEFUL ==
- (int)PIPE_CLOSE_GRACEFUL,
- "Invalid PIPE_CLOSE_GRACEFUL value");
- static_assert(
- (int)GOLDFISH_PIPE_CLOSE_REBOOT == (int)PIPE_CLOSE_REBOOT,
- "Invalid PIPE_CLOSE_REBOOT value");
- static_assert((int)GOLDFISH_PIPE_CLOSE_LOAD_SNAPSHOT ==
- (int)PIPE_CLOSE_LOAD_SNAPSHOT,
- "Invalid PIPE_CLOSE_LOAD_SNAPSHOT value");
- static_assert(
- (int)GOLDFISH_PIPE_CLOSE_ERROR == (int)PIPE_CLOSE_ERROR,
- "Invalid PIPE_CLOSE_ERROR value");
-
- android_pipe_guest_close(hostPipe,
- static_cast<PipeCloseReason>(reason));
- },
- // guest_pre_load()
- [](QEMUFile* file) { (void)file; },
- // guest_post_load()
- [](QEMUFile* file) { (void)file; },
- // guest_pre_save()
- [](QEMUFile* file) { (void)file; },
- // guest_post_save()
- [](QEMUFile* file) { (void)file; },
- // guest_load()
- [](QEMUFile* file,
- GoldfishHwPipe* hwPipe,
- char* force_close) -> GoldfishHostPipe* {
- (void)file;
- (void)hwPipe;
- (void)force_close;
- return nullptr;
- },
- // guest_save()
- [](GoldfishHostPipe* hostPipe, QEMUFile* file) {
- (void)hostPipe;
- (void)file;
- },
- // guest_poll()
- [](GoldfishHostPipe* hostPipe) {
- static_assert((int)GOLDFISH_PIPE_POLL_IN == (int)PIPE_POLL_IN,
- "invalid POLL_IN values");
- static_assert((int)GOLDFISH_PIPE_POLL_OUT == (int)PIPE_POLL_OUT,
- "invalid POLL_OUT values");
- static_assert((int)GOLDFISH_PIPE_POLL_HUP == (int)PIPE_POLL_HUP,
- "invalid POLL_HUP values");
-
- return static_cast<GoldfishPipePollFlags>(
- android_pipe_guest_poll(hostPipe));
- },
- // guest_recv()
- [](GoldfishHostPipe* hostPipe,
- GoldfishPipeBuffer* buffers,
- int numBuffers) -> int {
- // NOTE: Assumes that AndroidPipeBuffer and GoldfishPipeBuffer
- // have exactly the same layout.
- static_assert(
- sizeof(AndroidPipeBuffer) == sizeof(GoldfishPipeBuffer),
- "Invalid PipeBuffer sizes");
- // We can't use a static_assert with offsetof() because in msvc, it uses
- // reinterpret_cast.
- // TODO: Add runtime assertion instead?
- // https://developercommunity.visualstudio.com/content/problem/22196/static-assert-cannot-compile-constexprs-method-tha.html
-#ifndef _MSC_VER
- static_assert(offsetof(AndroidPipeBuffer, data) ==
- offsetof(GoldfishPipeBuffer, data),
- "Invalid PipeBuffer::data offsets");
- static_assert(offsetof(AndroidPipeBuffer, size) ==
- offsetof(GoldfishPipeBuffer, size),
- "Invalid PipeBuffer::size offsets");
-#endif
- return android_pipe_guest_recv(
- hostPipe, reinterpret_cast<AndroidPipeBuffer*>(buffers),
- numBuffers);
- },
- // guest_send()
- [](GoldfishHostPipe** hostPipe,
- const GoldfishPipeBuffer* buffers,
- int numBuffers) -> int {
- return android_pipe_guest_send(
- reinterpret_cast<void**>(hostPipe),
- reinterpret_cast<const AndroidPipeBuffer*>(buffers),
- numBuffers);
- },
- // guest_wake_on()
- [](GoldfishHostPipe* hostPipe, GoldfishPipeWakeFlags wakeFlags) {
- android_pipe_guest_wake_on(hostPipe, static_cast<int>(wakeFlags));
- },
- // dma_add_buffer()
- [](void* pipe, uint64_t paddr, uint64_t sz) {
- // not considered for virtio
- },
- // dma_remove_buffer()
- [](uint64_t paddr) {
- // not considered for virtio
- },
- // dma_invalidate_host_mappings()
- []() {
- // not considered for virtio
- },
- // dma_reset_host_mappings()
- []() {
- // not considered for virtio
- },
- // dma_save_mappings()
- [](QEMUFile* file) {
- (void)file;
- },
- // dma_load_mappings()
- [](QEMUFile* file) {
- (void)file;
- },
-};
-
-extern const QAndroidVmOperations* const gQAndroidVmOperations;
-
-static void default_post_callback(
- void* context, uint32_t displayId, int width, int height, int ydir, int format, int frame_type, unsigned char* pixels) {
- (void)context;
- (void)width;
- (void)height;
- (void)ydir;
- (void)format;
- (void)frame_type;
- (void)pixels;
- // no-op
-}
-
-extern "C" VG_EXPORT void gfxstream_backend_init(
- uint32_t display_width,
- uint32_t display_height,
- uint32_t display_type,
- void* renderer_cookie,
- int renderer_flags,
- struct virgl_renderer_callbacks* virglrenderer_callbacks,
- struct gfxstream_callbacks* gfxstreamcallbacks) {
-
- // Set metrics callbacks
- if (gfxstreamcallbacks) {
- if (gfxstreamcallbacks->add_instant_event) {
- MetricsLogger::add_instant_event_callback =
- gfxstreamcallbacks->add_instant_event;
- }
- if (gfxstreamcallbacks->add_instant_event_with_metric) {
- MetricsLogger::add_instant_event_with_metric_callback =
- gfxstreamcallbacks->add_instant_event_with_metric;
- }
- if (gfxstreamcallbacks->add_instant_event_with_descriptor) {
- MetricsLogger::add_instant_event_with_descriptor_callback =
- gfxstreamcallbacks->add_instant_event_with_descriptor;
- }
- if (gfxstreamcallbacks->add_vulkan_out_of_memory_event) {
- MetricsLogger::add_vulkan_out_of_memory_event =
- gfxstreamcallbacks->add_vulkan_out_of_memory_event;
- }
- if (gfxstreamcallbacks->set_annotation) {
- MetricsLogger::set_crash_annotation_callback =
- gfxstreamcallbacks->set_annotation;
- }
- if (gfxstreamcallbacks->abort) {
- emugl::setDieFunction(gfxstreamcallbacks->abort);
- }
- }
-
- // Set non product-specific callbacks
- vk_util::setVkCheckCallbacks(
- std::make_unique<vk_util::VkCheckCallbacks>(vk_util::VkCheckCallbacks{
- .onVkErrorOutOfMemory =
- [](VkResult result, const char* function, int line) {
- auto fb = FrameBuffer::getFB();
- if (!fb) {
- ERR("FrameBuffer not yet initialized. Dropping out of memory event");
- return;
- }
- fb->logVulkanOutOfMemory(result, function, line);
- },
- .onVkErrorOutOfMemoryOnAllocation =
- [](VkResult result, const char* function, int line,
- std::optional<uint64_t> allocationSize) {
- auto fb = FrameBuffer::getFB();
- if (!fb) {
- ERR("FrameBuffer not yet initialized. Dropping out of memory event");
- return;
- }
- fb->logVulkanOutOfMemory(result, function, line, allocationSize);
- }}));
-
- gfxstream_backend_init_product_override();
- // First we make some agents available.
-
- GFXS_LOG("start. display dimensions: width %u height %u, renderer flags: 0x%x", display_width,
- display_height, renderer_flags);
-
- // Flags processing
-
- // TODO: hook up "gfxstream egl" to the renderer flags
- // GFXSTREAM_RENDERER_FLAGS_USE_EGL_BIT in crosvm
- // as it's specified from launch_cvd.
- // At the moment, use ANDROID_GFXSTREAM_EGL=1
- // For test on GCE
- if (android::base::getEnvironmentVariable("ANDROID_GFXSTREAM_EGL") == "1") {
- android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1");
- android::base::setEnvironmentVariable("ANDROID_EMUGL_LOG_PRINT", "1");
- android::base::setEnvironmentVariable("ANDROID_EMUGL_VERBOSE", "1");
- }
- // end for test on GCE
-
- android::base::setEnvironmentVariable("ANDROID_EMU_HEADLESS", "1");
- android::base::setEnvironmentVariable("ANDROID_EMU_SANDBOX", "1");
- bool enableVk =
- !(renderer_flags & GFXSTREAM_RENDERER_FLAGS_NO_VK_BIT);
-
- bool egl2eglByEnv = android::base::getEnvironmentVariable("ANDROID_EGL_ON_EGL") == "1";
- bool egl2eglByFlag = renderer_flags & GFXSTREAM_RENDERER_FLAGS_USE_EGL_BIT;
- bool enable_egl2egl = egl2eglByFlag || egl2eglByEnv;
- if (enable_egl2egl) {
- android::base::setEnvironmentVariable("ANDROID_GFXSTREAM_EGL", "1");
- android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1");
- }
-
- bool surfaceless =
- renderer_flags & GFXSTREAM_RENDERER_FLAGS_USE_SURFACELESS_BIT;
- bool enableGlEs31Flag = renderer_flags & GFXSTREAM_RENDERER_FLAGS_ENABLE_GLES31_BIT;
- bool guestUsesAngle = renderer_flags & GFXSTREAM_RENDERER_FLAGS_GUEST_USES_ANGLE;
- bool useVulkanNativeSwapchain =
- renderer_flags & GFXSTREAM_RENDERER_FLAGS_VULKAN_NATIVE_SWAPCHAIN_BIT;
-
- GFXS_LOG("Vulkan enabled? %d", enableVk);
- GFXS_LOG("egl2egl enabled? %d", enable_egl2egl);
- GFXS_LOG("surfaceless? %d", surfaceless);
- GFXS_LOG("OpenGL ES 3.1 enabled? %d", enableGlEs31Flag);
- GFXS_LOG("guest using ANGLE? %d", guestUsesAngle);
- GFXS_LOG("use Vulkan native swapchain on the host? %d",
- useVulkanNativeSwapchain);
-
- // Need to manually set the GLES backend paths in gfxstream environment
- // because the library search paths are not automatically set to include
- // the directory in whioch the GLES backend resides.
-#if defined(__linux__)
-#define GFXSTREAM_LIB_SUFFIX ".so"
-#elif defined(__APPLE__)
-#define GFXSTREAM_LIB_SUFFIX ".dylib"
-#else // Windows
-#define GFXSTREAM_LIB_SUFFIX ".dll"
-#endif
-
- feature_set_enabled_override(
- kFeature_GLPipeChecksum, false);
- feature_set_enabled_override(
- kFeature_GLESDynamicVersion, true);
- feature_set_enabled_override(
- kFeature_PlayStoreImage, !enableGlEs31Flag);
- feature_set_enabled_override(
- kFeature_GLDMA, false);
- feature_set_enabled_override(
- kFeature_GLAsyncSwap, false);
- feature_set_enabled_override(
- kFeature_RefCountPipe, false);
- feature_set_enabled_override(
- kFeature_NoDelayCloseColorBuffer, true);
- feature_set_enabled_override(
- kFeature_NativeTextureDecompression, false);
- feature_set_enabled_override(
- kFeature_GLDirectMem, false);
- feature_set_enabled_override(
- kFeature_Vulkan, enableVk);
- feature_set_enabled_override(
- kFeature_VulkanSnapshots, false);
- feature_set_enabled_override(
- kFeature_VulkanNullOptionalStrings, true);
- feature_set_enabled_override(
- kFeature_VulkanShaderFloat16Int8, true);
- feature_set_enabled_override(
- kFeature_HostComposition, true);
- feature_set_enabled_override(
- kFeature_VulkanIgnoredHandles, true);
- feature_set_enabled_override(
- kFeature_VirtioGpuNext, true);
- feature_set_enabled_override(
- kFeature_VirtioGpuNativeSync, true);
- feature_set_enabled_override(
- kFeature_GuestUsesAngle, guestUsesAngle);
- feature_set_enabled_override(
- kFeature_VulkanQueueSubmitWithCommands, true);
- feature_set_enabled_override(kFeature_VulkanNativeSwapchain,
- useVulkanNativeSwapchain);
- feature_set_enabled_override(
- kFeature_VulkanBatchedDescriptorSetUpdate, true);
- // TODO: Strictly speaking, renderer_flags check is insufficient because
- // fence contexts require us to be running a new-enough guest kernel.
- feature_set_enabled_override(
- kFeature_VirtioGpuFenceContexts,
- (renderer_flags & GFXSTREAM_RENDERER_FLAGS_ASYNC_FENCE_CB));
- feature_set_enabled_override(kFeature_VulkanAstcLdrEmulation, true);
- feature_set_enabled_override(kFeature_VulkanEtc2Emulation, true);
- feature_set_enabled_override(kFeature_VulkanYcbcrEmulation, false);
- feature_set_enabled_override(kFeature_ExternalBlob, false);
-
- android::featurecontrol::productFeatureOverride();
-
- if (useVulkanNativeSwapchain && !enableVk) {
- GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) <<
- "can't enable vulkan native swapchain, Vulkan is disabled";
- }
-
- emugl::vkDispatch(false /* don't use test ICD */);
-
- auto androidHw = aemu_get_android_hw();
-
- androidHw->hw_gltransport_asg_writeBufferSize = 1048576;
- androidHw->hw_gltransport_asg_writeStepSize = 262144;
- androidHw->hw_gltransport_asg_dataRingSize = 524288;
- androidHw->hw_gltransport_drawFlushInterval = 10000;
-
- EmuglConfig config;
-
- // Make all the console agents available.
- android::emulation::injectGraphicsAgents(android::emulation::GfxStreamGraphicsAgentFactory());
-
- emuglConfig_init(&config, true /* gpu enabled */, "auto",
- enable_egl2egl ? "swiftshader_indirect" : "host",
- 64, /* bitness */
- surfaceless, /* no window */
- false, /* blacklisted */
- false, /* has guest renderer */
- WINSYS_GLESBACKEND_PREFERENCE_AUTO,
- true /* force host gpu vulkan */);
-
- emuglConfig_setupEnv(&config);
-
- android_prepareOpenglesEmulation();
-
- {
- static emugl::RenderLibPtr renderLibPtr = initLibrary();
- void* egldispatch = renderLibPtr->getEGLDispatch();
- void* glesv2Dispatch = renderLibPtr->getGLESv2Dispatch();
- android_setOpenglesEmulation(
- renderLibPtr.get(), egldispatch, glesv2Dispatch);
- }
-
- int maj;
- int min;
- android_startOpenglesRenderer(
- display_width, display_height, 1, 28,
- getGraphicsAgents()->vm,
- getGraphicsAgents()->emu,
- getGraphicsAgents()->multi_display,
- &maj, &min);
-
- char* vendor = nullptr;
- char* renderer = nullptr;
- char* version = nullptr;
-
- android_getOpenglesHardwareStrings(
- &vendor, &renderer, &version);
-
- GFXS_LOG("GL strings; [%s] [%s] [%s].\n",
- vendor, renderer, version);
-
- auto openglesRenderer = android_getOpenglesRenderer();
-
- if (!openglesRenderer) {
- GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No renderer started, fatal";
- }
-
- address_space_set_vm_operations(getGraphicsAgents()->vm);
- android_init_opengles_pipe();
- android_opengles_pipe_set_recv_mode(2 /* virtio-gpu */);
- android_init_refcount_pipe();
-
- sGetPixelsFunc = android_getReadPixelsFunc();
-
- pipe_virgl_renderer_init(renderer_cookie, renderer_flags, virglrenderer_callbacks);
-
- GFXS_LOG("Started renderer");
-}
-
-extern "C" VG_EXPORT void gfxstream_backend_setup_window(
- void* native_window_handle,
- int32_t window_x,
- int32_t window_y,
- int32_t window_width,
- int32_t window_height,
- int32_t fb_width,
- int32_t fb_height) {
- android_showOpenglesWindow(native_window_handle, window_x, window_y,
- window_width, window_height, fb_width, fb_height,
- 1.0f, 0, false, false);
-}
-
-extern "C" VG_EXPORT void gfxstream_backend_teardown() {
- android_finishOpenglesRenderer();
- android_hideOpenglesWindow();
- android_stopOpenglesRenderer(true);
-}
-
-extern "C" VG_EXPORT void gfxstream_backend_set_screen_mask(int width, int height, const unsigned char* rgbaData) {
- android_setOpenglesScreenMask(width, height, rgbaData);
-}
-
-extern "C" VG_EXPORT void get_pixels(void* pixels, uint32_t bytes) {
- //TODO: support display > 0
- sGetPixelsFunc(pixels, bytes, 0);
-}
-
-extern "C" VG_EXPORT void gfxstream_backend_getrender(char* buf, size_t bufSize, size_t* size) {
- const char* render = "";
- FrameBuffer* pFB = FrameBuffer::getFB();
- if (pFB) {
- const char* vendor = nullptr;
- const char* version = nullptr;
- pFB->getGLStrings(&vendor, &render, &version);
- }
- if (!buf || bufSize==0) {
- if (size) *size = strlen(render);
- return;
- }
- *buf = '\0';
- strncat(buf, render, bufSize - 1);
- if (size) *size = strlen(buf);
-}
-
-extern "C" const GoldfishPipeServiceOps* goldfish_pipe_get_service_ops() {
- return &goldfish_pipe_service_ops;
-}
-
diff --git a/stream-servers/GfxStreamBackend.h b/stream-servers/GfxStreamBackend.h
index 7dcf178..e0b5524 100644
--- a/stream-servers/GfxStreamBackend.h
+++ b/stream-servers/GfxStreamBackend.h
@@ -14,64 +14,6 @@
#pragma once
-#include <stddef.h>
-
-extern "C" {
+// To not break existing imports of GfxStreamBackend.h until they are
+// refactored downstream.
#include "virtio-gpu-gfxstream-renderer.h"
-#include "virgl_hw.h"
-} // extern "C"
-
-struct gfxstream_callbacks {
- /* Metrics callbacks */
- void (*add_instant_event)(int64_t event_code);
- void (*add_instant_event_with_descriptor)(int64_t event_code, int64_t descriptor);
- void (*add_instant_event_with_metric)(int64_t event_code, int64_t metric_value);
- void (*add_vulkan_out_of_memory_event)(int64_t result_code, uint32_t op_code,
- const char* function, uint32_t line,
- uint64_t allocation_size, bool is_host_side_result,
- bool is_allocation);
- void (*set_annotation)(const char* key, const char* value);
- void (*abort)();
-};
-
-extern "C" VG_EXPORT void gfxstream_backend_init(
- uint32_t display_width,
- uint32_t display_height,
- uint32_t display_type,
- void* renderer_cookie,
- int renderer_flags,
- struct virgl_renderer_callbacks* virglrenderer_callbacks,
- struct gfxstream_callbacks* gfxstreamcallbacks);
-
-extern "C" VG_EXPORT void gfxstream_backend_setup_window(
- void* native_window_handle,
- int32_t window_x,
- int32_t window_y,
- int32_t window_width,
- int32_t window_height,
- int32_t fb_width,
- int32_t fb_height);
-
-extern "C" VG_EXPORT void gfxstream_backend_teardown(void);
-
-// Get the gfxstream backend render information.
-// example:
-// /* Get the render string size */
-// size_t size = 0
-// gfxstream_backend_getrender(nullptr, 0, &size);
-//
-// /* add extra space for '\0' */
-// char * buf = malloc(size + 1);
-//
-// /* Get the result render string */
-// gfxstream_backend_getrender(buf, size+1, nullptr);
-//
-// if bufSize is less or equal the render string length, only bufSize-1 char copied.
-extern "C" VG_EXPORT void gfxstream_backend_getrender(
- char* buf,
- size_t bufSize,
- size_t* size);
-
-// A customization point that allows the downstream to call their own functions when
-// gfxstream_backend_init is called.
-void gfxstream_backend_init_product_override();
diff --git a/stream-servers/GfxStreamBackendInitOverride.cpp b/stream-servers/GfxStreamBackendInitOverride.cpp
index cb274b5..0b7d0dc 100644
--- a/stream-servers/GfxStreamBackendInitOverride.cpp
+++ b/stream-servers/GfxStreamBackendInitOverride.cpp
@@ -12,6 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "GfxStreamBackend.h"
+#include "virtio-gpu-gfxstream-renderer.h"
void gfxstream_backend_init_product_override() {}
\ No newline at end of file
diff --git a/stream-servers/gfxstream_unittest.cpp b/stream-servers/gfxstream_unittest.cpp
index e75170c..78beb9d 100644
--- a/stream-servers/gfxstream_unittest.cpp
+++ b/stream-servers/gfxstream_unittest.cpp
@@ -14,7 +14,7 @@
#include <gtest/gtest.h>
-#include "GfxStreamBackend.h"
+#include "virtio-gpu-gfxstream-renderer.h"
#include "host-common/testing/MockGraphicsAgentFactory.h"
#include "OSWindow.h"
#include "aemu/base/system/System.h"
diff --git a/stream-servers/virgl_hw.h b/stream-servers/virgl_hw.h
index d30e810..1543ba8 100644
--- a/stream-servers/virgl_hw.h
+++ b/stream-servers/virgl_hw.h
@@ -24,6 +24,8 @@
#ifndef VIRGL_HW_H
#define VIRGL_HW_H
+#include <stdint.h>
+
struct virgl_box {
uint32_t x, y, z;
uint32_t w, h, d;
diff --git a/stream-servers/virtio-gpu-gfxstream-renderer.cpp b/stream-servers/virtio-gpu-gfxstream-renderer.cpp
index 0f00ece..3e0fe3f 100644
--- a/stream-servers/virtio-gpu-gfxstream-renderer.cpp
+++ b/stream-servers/virtio-gpu-gfxstream-renderer.cpp
@@ -17,8 +17,11 @@
#include <type_traits>
#include <unordered_map>
+#include "FrameBuffer.h"
+#include "GfxStreamAgents.h"
#include "VirtioGpuTimelines.h"
#include "aemu/base/AlignedBuf.h"
+#include "aemu/base/Metrics.h"
#include "aemu/base/synchronization/Lock.h"
#include "aemu/base/memory/SharedMemory.h"
#include "aemu/base/ManagedDescriptor.hpp"
@@ -28,11 +31,16 @@
#include "host-common/HostmemIdMapping.h"
#include "host-common/address_space_device.h"
#include "host-common/android_pipe_common.h"
+#include "host-common/android_pipe_device.h"
#include "host-common/feature_control.h"
+#include "host-common/globals.h"
#include "host-common/linux_types.h"
#include "host-common/opengles.h"
+#include "host-common/opengles-pipe.h"
+#include "host-common/refcount-pipe.h"
#include "host-common/vm_operations.h"
#include "virtgpu_gfxstream_protocol.h"
+#include "vk_util.h"
extern "C" {
#include "virtio-gpu-gfxstream-renderer.h"
@@ -70,6 +78,23 @@
#endif // !VIRTIO_GOLDFISH_EXPORT_API
+#define GFXSTREAM_DEBUG_LEVEL 1
+
+#if GFXSTREAM_DEBUG_LEVEL >= 1
+#define GFXS_LOG(fmt, ...) \
+ do { \
+ fprintf(stdout, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); \
+ fflush(stdout); \
+ } while (0)
+
+#else
+#define GFXS_LOG(fmt,...)
+#endif
+
+#define POST_CALLBACK_DISPLAY_TYPE_X 0
+#define POST_CALLBACK_DISPLAY_TYPE_WAYLAND_SHARED_MEM 1
+#define POST_CALLBACK_DISPLAY_TYPE_WINDOWS_HWND 2
+
// Virtio Goldfish Pipe: Overview-----------------------------------------------
//
// Virtio Goldfish Pipe is meant for running goldfish pipe services with a
@@ -148,10 +173,12 @@
// linear buffer if necessary, and then perform a corresponding pip operation
// based on the box parameter's x and width values.
+using android::AndroidPipe;
using android::base::AutoLock;
using android::base::DescriptorType;
using android::base::Lock;
using android::base::ManagedDescriptor;
+using android::base::MetricsLogger;
using android::base::SharedMemory;
using android::emulation::HostmemIdMapping;
@@ -1928,6 +1955,453 @@
return sRenderer()->vulkanInfo(res_handle, vulkan_info);
}
+struct renderer_display_info;
+typedef void (*get_pixels_t)(void*, uint32_t, uint32_t);
+static get_pixels_t sGetPixelsFunc = 0;
+typedef void (*post_callback_t)(void*, uint32_t, int, int, int, int, int, unsigned char*);
+
+// For reading back rendered contents to display
+VG_EXPORT void get_pixels(void* pixels, uint32_t bytes);
+
+static const GoldfishPipeServiceOps goldfish_pipe_service_ops = {
+ // guest_open()
+ [](GoldfishHwPipe* hwPipe) -> GoldfishHostPipe* {
+ return static_cast<GoldfishHostPipe*>(
+ android_pipe_guest_open(hwPipe));
+ },
+ // guest_open_with_flags()
+ [](GoldfishHwPipe* hwPipe, uint32_t flags) -> GoldfishHostPipe* {
+ return static_cast<GoldfishHostPipe*>(
+ android_pipe_guest_open_with_flags(hwPipe, flags));
+ },
+ // guest_close()
+ [](GoldfishHostPipe* hostPipe, GoldfishPipeCloseReason reason) {
+ static_assert((int)GOLDFISH_PIPE_CLOSE_GRACEFUL ==
+ (int)PIPE_CLOSE_GRACEFUL,
+ "Invalid PIPE_CLOSE_GRACEFUL value");
+ static_assert(
+ (int)GOLDFISH_PIPE_CLOSE_REBOOT == (int)PIPE_CLOSE_REBOOT,
+ "Invalid PIPE_CLOSE_REBOOT value");
+ static_assert((int)GOLDFISH_PIPE_CLOSE_LOAD_SNAPSHOT ==
+ (int)PIPE_CLOSE_LOAD_SNAPSHOT,
+ "Invalid PIPE_CLOSE_LOAD_SNAPSHOT value");
+ static_assert(
+ (int)GOLDFISH_PIPE_CLOSE_ERROR == (int)PIPE_CLOSE_ERROR,
+ "Invalid PIPE_CLOSE_ERROR value");
+
+ android_pipe_guest_close(hostPipe,
+ static_cast<PipeCloseReason>(reason));
+ },
+ // guest_pre_load()
+ [](QEMUFile* file) { (void)file; },
+ // guest_post_load()
+ [](QEMUFile* file) { (void)file; },
+ // guest_pre_save()
+ [](QEMUFile* file) { (void)file; },
+ // guest_post_save()
+ [](QEMUFile* file) { (void)file; },
+ // guest_load()
+ [](QEMUFile* file,
+ GoldfishHwPipe* hwPipe,
+ char* force_close) -> GoldfishHostPipe* {
+ (void)file;
+ (void)hwPipe;
+ (void)force_close;
+ return nullptr;
+ },
+ // guest_save()
+ [](GoldfishHostPipe* hostPipe, QEMUFile* file) {
+ (void)hostPipe;
+ (void)file;
+ },
+ // guest_poll()
+ [](GoldfishHostPipe* hostPipe) {
+ static_assert((int)GOLDFISH_PIPE_POLL_IN == (int)PIPE_POLL_IN,
+ "invalid POLL_IN values");
+ static_assert((int)GOLDFISH_PIPE_POLL_OUT == (int)PIPE_POLL_OUT,
+ "invalid POLL_OUT values");
+ static_assert((int)GOLDFISH_PIPE_POLL_HUP == (int)PIPE_POLL_HUP,
+ "invalid POLL_HUP values");
+
+ return static_cast<GoldfishPipePollFlags>(
+ android_pipe_guest_poll(hostPipe));
+ },
+ // guest_recv()
+ [](GoldfishHostPipe* hostPipe,
+ GoldfishPipeBuffer* buffers,
+ int numBuffers) -> int {
+ // NOTE: Assumes that AndroidPipeBuffer and GoldfishPipeBuffer
+ // have exactly the same layout.
+ static_assert(
+ sizeof(AndroidPipeBuffer) == sizeof(GoldfishPipeBuffer),
+ "Invalid PipeBuffer sizes");
+ // We can't use a static_assert with offsetof() because in msvc, it uses
+ // reinterpret_cast.
+ // TODO: Add runtime assertion instead?
+ // https://developercommunity.visualstudio.com/content/problem/22196/static-assert-cannot-compile-constexprs-method-tha.html
+#ifndef _MSC_VER
+ static_assert(offsetof(AndroidPipeBuffer, data) ==
+ offsetof(GoldfishPipeBuffer, data),
+ "Invalid PipeBuffer::data offsets");
+ static_assert(offsetof(AndroidPipeBuffer, size) ==
+ offsetof(GoldfishPipeBuffer, size),
+ "Invalid PipeBuffer::size offsets");
+#endif
+ return android_pipe_guest_recv(
+ hostPipe, reinterpret_cast<AndroidPipeBuffer*>(buffers),
+ numBuffers);
+ },
+ // guest_send()
+ [](GoldfishHostPipe** hostPipe,
+ const GoldfishPipeBuffer* buffers,
+ int numBuffers) -> int {
+ return android_pipe_guest_send(
+ reinterpret_cast<void**>(hostPipe),
+ reinterpret_cast<const AndroidPipeBuffer*>(buffers),
+ numBuffers);
+ },
+ // guest_wake_on()
+ [](GoldfishHostPipe* hostPipe, GoldfishPipeWakeFlags wakeFlags) {
+ android_pipe_guest_wake_on(hostPipe, static_cast<int>(wakeFlags));
+ },
+ // dma_add_buffer()
+ [](void* pipe, uint64_t paddr, uint64_t sz) {
+ // not considered for virtio
+ },
+ // dma_remove_buffer()
+ [](uint64_t paddr) {
+ // not considered for virtio
+ },
+ // dma_invalidate_host_mappings()
+ []() {
+ // not considered for virtio
+ },
+ // dma_reset_host_mappings()
+ []() {
+ // not considered for virtio
+ },
+ // dma_save_mappings()
+ [](QEMUFile* file) {
+ (void)file;
+ },
+ // dma_load_mappings()
+ [](QEMUFile* file) {
+ (void)file;
+ },
+};
+
+extern const QAndroidVmOperations* const gQAndroidVmOperations;
+
+static void default_post_callback(
+ void* context, uint32_t displayId, int width, int height, int ydir, int format, int frame_type, unsigned char* pixels) {
+ (void)context;
+ (void)width;
+ (void)height;
+ (void)ydir;
+ (void)format;
+ (void)frame_type;
+ (void)pixels;
+ // no-op
+}
+
+VG_EXPORT void gfxstream_backend_init(
+ uint32_t display_width,
+ uint32_t display_height,
+ uint32_t display_type,
+ void* renderer_cookie,
+ int renderer_flags,
+ struct virgl_renderer_callbacks* virglrenderer_callbacks,
+ struct gfxstream_callbacks* gfxstreamcallbacks) {
+
+ // Set metrics callbacks
+ if (gfxstreamcallbacks) {
+ if (gfxstreamcallbacks->add_instant_event) {
+ MetricsLogger::add_instant_event_callback =
+ gfxstreamcallbacks->add_instant_event;
+ }
+ if (gfxstreamcallbacks->add_instant_event_with_metric) {
+ MetricsLogger::add_instant_event_with_metric_callback =
+ gfxstreamcallbacks->add_instant_event_with_metric;
+ }
+ if (gfxstreamcallbacks->add_instant_event_with_descriptor) {
+ MetricsLogger::add_instant_event_with_descriptor_callback =
+ gfxstreamcallbacks->add_instant_event_with_descriptor;
+ }
+ if (gfxstreamcallbacks->add_vulkan_out_of_memory_event) {
+ MetricsLogger::add_vulkan_out_of_memory_event =
+ gfxstreamcallbacks->add_vulkan_out_of_memory_event;
+ }
+ if (gfxstreamcallbacks->set_annotation) {
+ MetricsLogger::set_crash_annotation_callback =
+ gfxstreamcallbacks->set_annotation;
+ }
+ if (gfxstreamcallbacks->abort) {
+ emugl::setDieFunction(gfxstreamcallbacks->abort);
+ }
+ }
+
+ // Set non product-specific callbacks
+ vk_util::setVkCheckCallbacks(
+ std::make_unique<vk_util::VkCheckCallbacks>(vk_util::VkCheckCallbacks{
+ .onVkErrorOutOfMemory =
+ [](VkResult result, const char* function, int line) {
+ auto fb = FrameBuffer::getFB();
+ if (!fb) {
+ ERR("FrameBuffer not yet initialized. Dropping out of memory event");
+ return;
+ }
+ fb->logVulkanOutOfMemory(result, function, line);
+ },
+ .onVkErrorOutOfMemoryOnAllocation =
+ [](VkResult result, const char* function, int line,
+ std::optional<uint64_t> allocationSize) {
+ auto fb = FrameBuffer::getFB();
+ if (!fb) {
+ ERR("FrameBuffer not yet initialized. Dropping out of memory event");
+ return;
+ }
+ fb->logVulkanOutOfMemory(result, function, line, allocationSize);
+ }}));
+
+ gfxstream_backend_init_product_override();
+ // First we make some agents available.
+
+ GFXS_LOG("start. display dimensions: width %u height %u, renderer flags: 0x%x", display_width,
+ display_height, renderer_flags);
+
+ // Flags processing
+
+ // TODO: hook up "gfxstream egl" to the renderer flags
+ // GFXSTREAM_RENDERER_FLAGS_USE_EGL_BIT in crosvm
+ // as it's specified from launch_cvd.
+ // At the moment, use ANDROID_GFXSTREAM_EGL=1
+ // For test on GCE
+ if (android::base::getEnvironmentVariable("ANDROID_GFXSTREAM_EGL") == "1") {
+ android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1");
+ android::base::setEnvironmentVariable("ANDROID_EMUGL_LOG_PRINT", "1");
+ android::base::setEnvironmentVariable("ANDROID_EMUGL_VERBOSE", "1");
+ }
+ // end for test on GCE
+
+ android::base::setEnvironmentVariable("ANDROID_EMU_HEADLESS", "1");
+ android::base::setEnvironmentVariable("ANDROID_EMU_SANDBOX", "1");
+ bool enableVk =
+ !(renderer_flags & GFXSTREAM_RENDERER_FLAGS_NO_VK_BIT);
+
+ bool egl2eglByEnv = android::base::getEnvironmentVariable("ANDROID_EGL_ON_EGL") == "1";
+ bool egl2eglByFlag = renderer_flags & GFXSTREAM_RENDERER_FLAGS_USE_EGL_BIT;
+ bool enable_egl2egl = egl2eglByFlag || egl2eglByEnv;
+ if (enable_egl2egl) {
+ android::base::setEnvironmentVariable("ANDROID_GFXSTREAM_EGL", "1");
+ android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1");
+ }
+
+ bool surfaceless =
+ renderer_flags & GFXSTREAM_RENDERER_FLAGS_USE_SURFACELESS_BIT;
+ bool enableGlEs31Flag = renderer_flags & GFXSTREAM_RENDERER_FLAGS_ENABLE_GLES31_BIT;
+ bool guestUsesAngle = renderer_flags & GFXSTREAM_RENDERER_FLAGS_GUEST_USES_ANGLE;
+ bool useVulkanNativeSwapchain =
+ renderer_flags & GFXSTREAM_RENDERER_FLAGS_VULKAN_NATIVE_SWAPCHAIN_BIT;
+
+ GFXS_LOG("Vulkan enabled? %d", enableVk);
+ GFXS_LOG("egl2egl enabled? %d", enable_egl2egl);
+ GFXS_LOG("surfaceless? %d", surfaceless);
+ GFXS_LOG("OpenGL ES 3.1 enabled? %d", enableGlEs31Flag);
+ GFXS_LOG("guest using ANGLE? %d", guestUsesAngle);
+ GFXS_LOG("use Vulkan native swapchain on the host? %d",
+ useVulkanNativeSwapchain);
+
+ // Need to manually set the GLES backend paths in gfxstream environment
+ // because the library search paths are not automatically set to include
+ // the directory in whioch the GLES backend resides.
+#if defined(__linux__)
+#define GFXSTREAM_LIB_SUFFIX ".so"
+#elif defined(__APPLE__)
+#define GFXSTREAM_LIB_SUFFIX ".dylib"
+#else // Windows
+#define GFXSTREAM_LIB_SUFFIX ".dll"
+#endif
+
+ feature_set_enabled_override(
+ kFeature_GLPipeChecksum, false);
+ feature_set_enabled_override(
+ kFeature_GLESDynamicVersion, true);
+ feature_set_enabled_override(
+ kFeature_PlayStoreImage, !enableGlEs31Flag);
+ feature_set_enabled_override(
+ kFeature_GLDMA, false);
+ feature_set_enabled_override(
+ kFeature_GLAsyncSwap, false);
+ feature_set_enabled_override(
+ kFeature_RefCountPipe, false);
+ feature_set_enabled_override(
+ kFeature_NoDelayCloseColorBuffer, true);
+ feature_set_enabled_override(
+ kFeature_NativeTextureDecompression, false);
+ feature_set_enabled_override(
+ kFeature_GLDirectMem, false);
+ feature_set_enabled_override(
+ kFeature_Vulkan, enableVk);
+ feature_set_enabled_override(
+ kFeature_VulkanSnapshots, false);
+ feature_set_enabled_override(
+ kFeature_VulkanNullOptionalStrings, true);
+ feature_set_enabled_override(
+ kFeature_VulkanShaderFloat16Int8, true);
+ feature_set_enabled_override(
+ kFeature_HostComposition, true);
+ feature_set_enabled_override(
+ kFeature_VulkanIgnoredHandles, true);
+ feature_set_enabled_override(
+ kFeature_VirtioGpuNext, true);
+ feature_set_enabled_override(
+ kFeature_VirtioGpuNativeSync, true);
+ feature_set_enabled_override(
+ kFeature_GuestUsesAngle, guestUsesAngle);
+ feature_set_enabled_override(
+ kFeature_VulkanQueueSubmitWithCommands, true);
+ feature_set_enabled_override(kFeature_VulkanNativeSwapchain,
+ useVulkanNativeSwapchain);
+ feature_set_enabled_override(
+ kFeature_VulkanBatchedDescriptorSetUpdate, true);
+ // TODO: Strictly speaking, renderer_flags check is insufficient because
+ // fence contexts require us to be running a new-enough guest kernel.
+ feature_set_enabled_override(
+ kFeature_VirtioGpuFenceContexts,
+ (renderer_flags & GFXSTREAM_RENDERER_FLAGS_ASYNC_FENCE_CB));
+ feature_set_enabled_override(kFeature_VulkanAstcLdrEmulation, true);
+ feature_set_enabled_override(kFeature_VulkanEtc2Emulation, true);
+ feature_set_enabled_override(kFeature_VulkanYcbcrEmulation, false);
+ feature_set_enabled_override(kFeature_ExternalBlob, false);
+
+ android::featurecontrol::productFeatureOverride();
+
+ if (useVulkanNativeSwapchain && !enableVk) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) <<
+ "can't enable vulkan native swapchain, Vulkan is disabled";
+ }
+
+ emugl::vkDispatch(false /* don't use test ICD */);
+
+ auto androidHw = aemu_get_android_hw();
+
+ androidHw->hw_gltransport_asg_writeBufferSize = 1048576;
+ androidHw->hw_gltransport_asg_writeStepSize = 262144;
+ androidHw->hw_gltransport_asg_dataRingSize = 524288;
+ androidHw->hw_gltransport_drawFlushInterval = 10000;
+
+ EmuglConfig config;
+
+ // Make all the console agents available.
+ android::emulation::injectGraphicsAgents(android::emulation::GfxStreamGraphicsAgentFactory());
+
+ emuglConfig_init(&config, true /* gpu enabled */, "auto",
+ enable_egl2egl ? "swiftshader_indirect" : "host",
+ 64, /* bitness */
+ surfaceless, /* no window */
+ false, /* blocklisted */
+ false, /* has guest renderer */
+ WINSYS_GLESBACKEND_PREFERENCE_AUTO,
+ true /* force host gpu vulkan */);
+
+ emuglConfig_setupEnv(&config);
+
+ android_prepareOpenglesEmulation();
+
+ {
+ static emugl::RenderLibPtr renderLibPtr = initLibrary();
+ void* egldispatch = renderLibPtr->getEGLDispatch();
+ void* glesv2Dispatch = renderLibPtr->getGLESv2Dispatch();
+ android_setOpenglesEmulation(
+ renderLibPtr.get(), egldispatch, glesv2Dispatch);
+ }
+
+ int maj;
+ int min;
+ android_startOpenglesRenderer(
+ display_width, display_height, 1, 28,
+ getGraphicsAgents()->vm,
+ getGraphicsAgents()->emu,
+ getGraphicsAgents()->multi_display,
+ &maj, &min);
+
+ char* vendor = nullptr;
+ char* renderer = nullptr;
+ char* version = nullptr;
+
+ android_getOpenglesHardwareStrings(
+ &vendor, &renderer, &version);
+
+ GFXS_LOG("GL strings; [%s] [%s] [%s].\n",
+ vendor, renderer, version);
+
+ auto openglesRenderer = android_getOpenglesRenderer();
+
+ if (!openglesRenderer) {
+ GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No renderer started, fatal";
+ }
+
+ address_space_set_vm_operations(getGraphicsAgents()->vm);
+ android_init_opengles_pipe();
+ android_opengles_pipe_set_recv_mode(2 /* virtio-gpu */);
+ android_init_refcount_pipe();
+
+ sGetPixelsFunc = android_getReadPixelsFunc();
+
+ pipe_virgl_renderer_init(renderer_cookie, renderer_flags, virglrenderer_callbacks);
+
+ GFXS_LOG("Started renderer");
+}
+
+VG_EXPORT void gfxstream_backend_setup_window(
+ void* native_window_handle,
+ int32_t window_x,
+ int32_t window_y,
+ int32_t window_width,
+ int32_t window_height,
+ int32_t fb_width,
+ int32_t fb_height) {
+ android_showOpenglesWindow(native_window_handle, window_x, window_y,
+ window_width, window_height, fb_width, fb_height,
+ 1.0f, 0, false, false);
+}
+
+VG_EXPORT void gfxstream_backend_teardown() {
+ android_finishOpenglesRenderer();
+ android_hideOpenglesWindow();
+ android_stopOpenglesRenderer(true);
+}
+
+VG_EXPORT void gfxstream_backend_set_screen_mask(int width, int height, const unsigned char* rgbaData) {
+ android_setOpenglesScreenMask(width, height, rgbaData);
+}
+
+VG_EXPORT void get_pixels(void* pixels, uint32_t bytes) {
+ //TODO: support display > 0
+ sGetPixelsFunc(pixels, bytes, 0);
+}
+
+VG_EXPORT void gfxstream_backend_getrender(char* buf, size_t bufSize, size_t* size) {
+ const char* render = "";
+ FrameBuffer* pFB = FrameBuffer::getFB();
+ if (pFB) {
+ const char* vendor = nullptr;
+ const char* version = nullptr;
+ pFB->getGLStrings(&vendor, &render, &version);
+ }
+ if (!buf || bufSize==0) {
+ if (size) *size = strlen(render);
+ return;
+ }
+ *buf = '\0';
+ strncat(buf, render, bufSize - 1);
+ if (size) *size = strlen(buf);
+}
+
+const GoldfishPipeServiceOps* goldfish_pipe_get_service_ops() {
+ return &goldfish_pipe_service_ops;
+}
+
#define VIRGLRENDERER_API_PIPE_STRUCT_DEF(api) pipe_##api,
static struct virgl_renderer_virtio_interface s_virtio_interface = {
diff --git a/stream-servers/virtio-gpu-gfxstream-renderer.h b/stream-servers/virtio-gpu-gfxstream-renderer.h
index 0ba9e92..973d7ec 100644
--- a/stream-servers/virtio-gpu-gfxstream-renderer.h
+++ b/stream-servers/virtio-gpu-gfxstream-renderer.h
@@ -5,6 +5,9 @@
* implement an actual virtio goldfish pipe, but this hijacking of virgl is
* done in order to avoid any guest kernel changes. */
+#include <stddef.h>
+
+#include "virgl_hw.h"
#include "virglrenderer.h"
@@ -163,6 +166,61 @@
VG_EXPORT int stream_renderer_vulkan_info(uint32_t res_handle,
struct stream_renderer_vulkan_info *vulkan_info);
+struct gfxstream_callbacks {
+ /* Metrics callbacks */
+ void (*add_instant_event)(int64_t event_code);
+ void (*add_instant_event_with_descriptor)(int64_t event_code, int64_t descriptor);
+ void (*add_instant_event_with_metric)(int64_t event_code, int64_t metric_value);
+ void (*add_vulkan_out_of_memory_event)(int64_t result_code, uint32_t op_code,
+ const char* function, uint32_t line,
+ uint64_t allocation_size, bool is_host_side_result,
+ bool is_allocation);
+ void (*set_annotation)(const char* key, const char* value);
+ void (*abort)();
+};
+
+VG_EXPORT void gfxstream_backend_init(
+ uint32_t display_width,
+ uint32_t display_height,
+ uint32_t display_type,
+ void* renderer_cookie,
+ int renderer_flags,
+ struct virgl_renderer_callbacks* virglrenderer_callbacks,
+ struct gfxstream_callbacks* gfxstreamcallbacks);
+
+VG_EXPORT void gfxstream_backend_setup_window(
+ void* native_window_handle,
+ int32_t window_x,
+ int32_t window_y,
+ int32_t window_width,
+ int32_t window_height,
+ int32_t fb_width,
+ int32_t fb_height);
+
+VG_EXPORT void gfxstream_backend_teardown(void);
+
+// Get the gfxstream backend render information.
+// example:
+// /* Get the render string size */
+// size_t size = 0
+// gfxstream_backend_getrender(nullptr, 0, &size);
+//
+// /* add extra space for '\0' */
+// char * buf = malloc(size + 1);
+//
+// /* Get the result render string */
+// gfxstream_backend_getrender(buf, size+1, nullptr);
+//
+// if bufSize is less or equal the render string length, only bufSize-1 char copied.
+VG_EXPORT void gfxstream_backend_getrender(
+ char* buf,
+ size_t bufSize,
+ size_t* size);
+
+// A customization point that allows the downstream to call their own functions when
+// gfxstream_backend_init is called.
+void gfxstream_backend_init_product_override();
+
#else
#define VG_EXPORT