support EGL_ANDROID_native_fence_sync via virtio-gpu
regardless of api transport type, we can now support native fence sync
via virtio-gpu
Bug: 156130048
Change-Id: I93801428ede7fdcf1cf28240a4e4f560912f4a4a
diff --git a/system/OpenglSystemCommon/EmulatorFeatureInfo.h b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
index 626048f..f1505fe 100644
--- a/system/OpenglSystemCommon/EmulatorFeatureInfo.h
+++ b/system/OpenglSystemCommon/EmulatorFeatureInfo.h
@@ -105,6 +105,9 @@
// Vulkan free memory sync
static const char kVulkanFreeMemorySync[] = "ANDROID_EMU_vulkan_free_memory_sync";
+// virtio-gpu syncfd support
+static const char kVirtioGpuNativeSync[] = "ANDROID_EMU_virtio_gpu_native_sync";
+
// Struct describing available emulator features
struct EmulatorFeatureInfo {
@@ -123,7 +126,8 @@
hasAsyncUnmapBuffer (false),
hasVirtioGpuNext (false),
hasSharedSlotsHostMemoryAllocator(false),
- hasVulkanFreeMemorySync(false)
+ hasVulkanFreeMemorySync(false),
+ hasVirtioGpuNativeSync(false)
{ }
SyncImpl syncImpl;
@@ -141,6 +145,7 @@
bool hasVirtioGpuNext;
bool hasSharedSlotsHostMemoryAllocator;
bool hasVulkanFreeMemorySync;
+ bool hasVirtioGpuNativeSync;
};
enum HostConnectionType {
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index b9c97c9..7a888d0 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -354,7 +354,9 @@
m_checksumHelper(),
m_glExtensions(),
m_grallocOnly(true),
- m_noHostError(false) { }
+ m_noHostError(false),
+ m_rendernodeFd(-1),
+ m_rendernodeFdOwned(false) { }
HostConnection::~HostConnection()
{
@@ -370,6 +372,10 @@
delete m_glEnc;
delete m_gl2Enc;
delete m_rcEnc;
+
+ if (m_rendernodeFdOwned) {
+ close(m_rendernodeFd);
+ }
}
// static
@@ -459,6 +465,8 @@
con->m_connectionType = HOST_CONNECTION_VIRTIO_GPU;
con->m_grallocType = GRALLOC_TYPE_MINIGBM;
con->m_stream = stream;
+ con->m_rendernodeFdOwned = false;
+ con->m_rendernodeFdOwned = stream->getRendernodeFd();
MinigbmGralloc* m = new MinigbmGralloc;
m->setFd(stream->getRendernodeFd());
con->m_grallocHelper = m;
@@ -481,6 +489,8 @@
con->m_connectionType = HOST_CONNECTION_VIRTIO_GPU_PIPE;
con->m_grallocType = getGrallocTypeFromProperty();
con->m_stream = stream;
+ con->m_rendernodeFdOwned = false;
+ con->m_rendernodeFdOwned = stream->getRendernodeFd();
switch (con->m_grallocType) {
case GRALLOC_TYPE_RANCHU:
con->m_grallocHelper = &m_goldfishGralloc;
@@ -615,6 +625,7 @@
queryAndSetVirtioGpuNext(m_rcEnc);
queryHasSharedSlotsHostMemoryAllocator(m_rcEnc);
queryAndSetVulkanFreeMemorySync(m_rcEnc);
+ queryAndSetVirtioGpuNativeSync(m_rcEnc);
if (m_processPipe) {
m_processPipe->processPipeInit(m_connectionType, m_rcEnc);
}
@@ -622,6 +633,30 @@
return m_rcEnc;
}
+int HostConnection::getOrCreateRendernodeFd() {
+ if (m_rendernodeFd >= 0) return m_rendernodeFd;
+#ifdef __Fuchsia__
+ return -1;
+#else
+#ifdef VIRTIO_GPU
+ m_rendernodeFd = VirtioGpuPipeStream::openRendernode();
+ if (m_rendernodeFd < 0) {
+ ALOGE("%s: failed to create secondary "
+ "rendernode for host connection. "
+ "error: %s (%d)\n", __FUNCTION__,
+ strerror(errno), errno);
+ return -1;
+ }
+
+ // Remember to close it on exit
+ m_rendernodeFdOwned = true;
+ return m_rendernodeFd;
+#else
+ return -1;
+#endif
+#endif
+}
+
gl_client_context_t *HostConnection::s_getGLContext()
{
EGLThreadInfo *ti = getEGLThreadInfo();
@@ -832,3 +867,11 @@
rcEnc->featureInfo()->hasVulkanFreeMemorySync = true;
}
}
+
+void HostConnection::queryAndSetVirtioGpuNativeSync(ExtendedRCEncoderContext* rcEnc) {
+ std::string glExtensions = queryGLExtensions(rcEnc);
+ if (glExtensions.find(kVirtioGpuNativeSync) != std::string::npos) {
+ rcEnc->featureInfo()->hasVirtioGpuNativeSync = true;
+ }
+}
+
diff --git a/system/OpenglSystemCommon/HostConnection.h b/system/OpenglSystemCommon/HostConnection.h
index 02c8681..6acefee 100644
--- a/system/OpenglSystemCommon/HostConnection.h
+++ b/system/OpenglSystemCommon/HostConnection.h
@@ -55,6 +55,7 @@
bool hasNativeSync() const { return m_featureInfo.syncImpl >= SYNC_IMPL_NATIVE_SYNC_V2; }
bool hasNativeSyncV3() const { return m_featureInfo.syncImpl >= SYNC_IMPL_NATIVE_SYNC_V3; }
bool hasNativeSyncV4() const { return m_featureInfo.syncImpl >= SYNC_IMPL_NATIVE_SYNC_V4; }
+ bool hasVirtioGpuNativeSync() const { return m_featureInfo.hasVirtioGpuNativeSync; }
bool hasHostCompositionV1() const {
return m_featureInfo.hostComposition == HOST_COMPOSITION_V1; }
bool hasHostCompositionV2() const {
@@ -152,6 +153,12 @@
GL2Encoder *gl2Encoder();
goldfish_vk::VkEncoder *vkEncoder();
ExtendedRCEncoderContext *rcEncoder();
+
+ // Returns rendernode fd, in case the stream is virtio-gpu based.
+ // Otherwise, attempts to create a rendernode fd assuming
+ // virtio-gpu is available.
+ int getOrCreateRendernodeFd();
+
ChecksumCalculator *checksumHelper() { return &m_checksumHelper; }
Gralloc *grallocHelper() { return m_grallocHelper; }
@@ -206,6 +213,7 @@
void queryAndSetVirtioGpuNext(ExtendedRCEncoderContext *rcEnc);
void queryHasSharedSlotsHostMemoryAllocator(ExtendedRCEncoderContext *rcEnc);
void queryAndSetVulkanFreeMemorySync(ExtendedRCEncoderContext *rcEnc);
+ void queryAndSetVirtioGpuNativeSync(ExtendedRCEncoderContext *rcEnc);
private:
HostConnectionType m_connectionType;
@@ -226,6 +234,8 @@
#else
mutable android::Mutex m_lock;
#endif
+ int m_rendernodeFd;
+ bool m_rendernodeFdOwned;
};
#endif
diff --git a/system/OpenglSystemCommon/VirtioGpuPipeStream.cpp b/system/OpenglSystemCommon/VirtioGpuPipeStream.cpp
index d3618f3..238d555 100644
--- a/system/OpenglSystemCommon/VirtioGpuPipeStream.cpp
+++ b/system/OpenglSystemCommon/VirtioGpuPipeStream.cpp
@@ -74,7 +74,7 @@
int VirtioGpuPipeStream::connect(const char* serviceName)
{
if (m_fd < 0) {
- m_fd = drmOpenRender(RENDERNODE_MINOR);
+ m_fd = VirtioGpuPipeStream::openRendernode();
if (m_fd < 0) {
ERR("%s: failed with fd %d (%s)", __func__, m_fd, strerror(errno));
return -1;
@@ -154,6 +154,15 @@
return 0;
}
+int VirtioGpuPipeStream::openRendernode() {
+ int fd = drmOpenRender(RENDERNODE_MINOR);
+ if (fd < 0) {
+ ERR("%s: failed with fd %d (%s)", __func__, fd, strerror(errno));
+ return -1;
+ }
+ return fd;
+}
+
uint64_t VirtioGpuPipeStream::initProcessPipe() {
connect("pipe:GLProcessPipe");
int32_t confirmInt = 100;
diff --git a/system/OpenglSystemCommon/VirtioGpuPipeStream.h b/system/OpenglSystemCommon/VirtioGpuPipeStream.h
index 3f3c537..91c76fc 100644
--- a/system/OpenglSystemCommon/VirtioGpuPipeStream.h
+++ b/system/OpenglSystemCommon/VirtioGpuPipeStream.h
@@ -33,6 +33,7 @@
explicit VirtioGpuPipeStream(size_t bufsize = 10000);
~VirtioGpuPipeStream();
int connect(const char* serviceName = 0);
+ static int openRendernode();
uint64_t initProcessPipe();
virtual void *allocBuffer(size_t minSize);
diff --git a/system/egl/Android.mk b/system/egl/Android.mk
index 6e239b2..a5e1c1f 100644
--- a/system/egl/Android.mk
+++ b/system/egl/Android.mk
@@ -23,7 +23,12 @@
ifneq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
LOCAL_SHARED_LIBRARIES += libdl
-endif
+ifeq (true,$(BUILD_EMULATOR_VULKAN))
+LOCAL_CFLAGS += -DVIRTIO_GPU
+LOCAL_C_INCLUDES += external/libdrm
+LOCAL_SHARED_LIBRARIES += libdrm
+endif # BUILD_EMULATOR_VULKAN
+endif # GOLDFISH_OPENGL_BUILD_FOR_HOST
ifneq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
ifdef IS_AT_LEAST_OPM1
diff --git a/system/egl/CMakeLists.txt b/system/egl/CMakeLists.txt
index 08db0c8..301ef62 100644
--- a/system/egl/CMakeLists.txt
+++ b/system/egl/CMakeLists.txt
@@ -1,7 +1,7 @@
# This is an autogenerated file! Do not edit!
# instead run make from .../device/generic/goldfish-opengl
# which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/egl/Android.mk" "597fba46fce0876a62ef3c0bc8f3a0264503214b62b0b0da092ee90fe60f09e1")
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/egl/Android.mk" "729a65bbc7934fa79a239b55b801e4ebaa44d02c2deeab7ab43e42196376c7c7")
set(EGL_emulation_src eglDisplay.cpp egl.cpp ClientAPIExts.cpp)
android_add_library(TARGET EGL_emulation SHARED LICENSE Apache-2.0 SRC eglDisplay.cpp egl.cpp ClientAPIExts.cpp)
target_include_directories(EGL_emulation PRIVATE ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon/bionic-include ${GOLDFISH_DEVICE_ROOT}/system/OpenglSystemCommon ${GOLDFISH_DEVICE_ROOT}/bionic/libc/private ${GOLDFISH_DEVICE_ROOT}/bionic/libc/platform ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/shared/gralloc_cb/include ${GOLDFISH_DEVICE_ROOT}/shared/GoldfishAddressSpace/include ${GOLDFISH_DEVICE_ROOT}/system/renderControl_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv2_enc ${GOLDFISH_DEVICE_ROOT}/system/GLESv1_enc ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/shared/qemupipe/include-types ${GOLDFISH_DEVICE_ROOT}/shared/qemupipe/include ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest)
diff --git a/system/egl/egl.cpp b/system/egl/egl.cpp
index 834207b..fbd2405 100644
--- a/system/egl/egl.cpp
+++ b/system/egl/egl.cpp
@@ -43,6 +43,12 @@
#include <GLES3/gl31.h>
+#ifdef VIRTIO_GPU
+#include <drm/virtgpu_drm.h>
+#include <xf86drm.h>
+#include <poll.h>
+#endif // VIRTIO_GPU
+
#if PLATFORM_SDK_VERSION < 18
#define override
#endif
@@ -494,6 +500,101 @@
return sync_handle;
}
+// our cmd
+#define VIRTIO_GPU_NATIVE_SYNC_CREATE_EXPORT_FD 0x9000
+#define VIRTIO_GPU_NATIVE_SYNC_CREATE_IMPORT_FD 0x9001
+
+// createNativeSync_virtioGpu()
+// creates an OpenGL sync object on the host
+// using rcCreateSyncKHR.
+// If necessary, a native fence FD will be exported or imported.
+// Returns a handle to the host-side FenceSync object.
+static uint64_t createNativeSync_virtioGpu(
+ EGLenum type,
+ const EGLint* attrib_list,
+ int num_actual_attribs,
+ bool destroy_when_signaled,
+ int fd_in,
+ int* fd_out) {
+#ifndef VIRTIO_GPU
+ ALOGE("%s: Error: called with no virtio-gpu support built in\n", __func__);
+ return 0;
+#else
+ DEFINE_HOST_CONNECTION;
+
+ uint64_t sync_handle;
+ uint64_t thread_handle;
+
+ EGLint* actual_attribs =
+ (EGLint*)(num_actual_attribs == 0 ? NULL : attrib_list);
+
+ // Create a normal sync obj
+ rcEnc->rcCreateSyncKHR(rcEnc, type,
+ actual_attribs,
+ num_actual_attribs * sizeof(EGLint),
+ destroy_when_signaled,
+ &sync_handle,
+ &thread_handle);
+
+ // Import fence fd; dup and close
+ if (type == EGL_SYNC_NATIVE_FENCE_ANDROID && fd_in >= 0) {
+ int importedFd = dup(fd_in);
+
+ if (importedFd < 0) {
+ ALOGE("%s: error: failed to dup imported fd. original: %d errno %d\n",
+ __func__, fd_in, errno);
+ }
+
+ *fd_out = importedFd;
+
+ if (close(fd_in)) {
+ ALOGE("%s: error: failed to close imported fd. original: %d errno %d\n",
+ __func__, fd_in, errno);
+ }
+
+ } else if (type == EGL_SYNC_NATIVE_FENCE_ANDROID && fd_in < 0) {
+ // Export fence fd
+
+ uint32_t sync_handle_lo = (uint32_t)sync_handle;
+ uint32_t sync_handle_hi = (uint32_t)(sync_handle >> 32);
+
+ uint32_t cmdDwords[3] = {
+ VIRTIO_GPU_NATIVE_SYNC_CREATE_EXPORT_FD,
+ sync_handle_lo,
+ sync_handle_hi,
+ };
+
+ drm_virtgpu_execbuffer createSyncExport = {
+ .flags = VIRTGPU_EXECBUF_FENCE_FD_OUT,
+ .size = 3 * sizeof(uint32_t),
+ .command = (uint64_t)(cmdDwords),
+ .bo_handles = 0,
+ .num_bo_handles = 0,
+ .fence_fd = -1,
+ };
+
+ int queue_work_err =
+ drmIoctl(
+ hostCon->getOrCreateRendernodeFd(),
+ DRM_IOCTL_VIRTGPU_EXECBUFFER, &createSyncExport);
+
+ if (queue_work_err) {
+ ERR("%s: failed with %d executing command buffer (%s)", __func__,
+ queue_work_err, strerror(errno));
+ return 0;
+ }
+
+ *fd_out = createSyncExport.fence_fd;
+
+ DPRINT("virtio-gpu: got native fence fd=%d queue_work_err=%d",
+ *fd_out, queue_work_err);
+
+ }
+
+ return sync_handle;
+#endif
+}
+
// createGoldfishOpenGLNativeSync() is for creating host-only sync objects
// that are needed by only this goldfish opengl driver,
// such as in swapBuffers().
@@ -544,7 +645,16 @@
eglWaitClient();
nativeWindow->queueBuffer(nativeWindow, buffer);
#else
- if (rcEnc->hasNativeSync()) {
+ if (rcEnc->hasVirtioGpuNativeSync()) {
+ rcEnc->rcFlushWindowColorBufferAsync(rcEnc, rcSurface);
+ createNativeSync_virtioGpu(EGL_SYNC_NATIVE_FENCE_ANDROID,
+ NULL /* empty attrib list */,
+ 0 /* 0 attrib count */,
+ true /* destroy when signaled. this is host-only
+ and there will only be one waiter */,
+ -1 /* we want a new fd */,
+ &presentFenceFd);
+ } else if (rcEnc->hasNativeSync()) {
rcEnc->rcFlushWindowColorBufferAsync(rcEnc, rcSurface);
createGoldfishOpenGLNativeSync(&presentFenceFd);
} else {
@@ -2097,7 +2207,8 @@
if ((type != EGL_SYNC_FENCE_KHR &&
type != EGL_SYNC_NATIVE_FENCE_ANDROID) ||
(type != EGL_SYNC_FENCE_KHR &&
- !rcEnc->hasNativeSync())) {
+ !rcEnc->hasNativeSync() &&
+ !rcEnc->hasVirtioGpuNativeSync())) {
setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
}
@@ -2150,14 +2261,23 @@
uint64_t sync_handle = 0;
int newFenceFd = -1;
- if (rcEnc->hasNativeSync()) {
+ if (rcEnc->hasVirtioGpuNativeSync()) {
sync_handle =
- createNativeSync(type, attrib_list, num_actual_attribs,
- false /* don't destroy when signaled on the host;
- let the guest clean this up,
- because the guest called eglCreateSyncKHR. */,
- inputFenceFd,
- &newFenceFd);
+ createNativeSync_virtioGpu(
+ type, attrib_list, num_actual_attribs,
+ false /* don't destroy when signaled on the host;
+ let the guest clean this up,
+ because the guest called eglCreateSyncKHR. */,
+ inputFenceFd, &newFenceFd);
+ } else if (rcEnc->hasNativeSync()) {
+ sync_handle =
+ createNativeSync(
+ type, attrib_list, num_actual_attribs,
+ false /* don't destroy when signaled on the host;
+ let the guest clean this up,
+ because the guest called eglCreateSyncKHR. */,
+ inputFenceFd,
+ &newFenceFd);
} else {
// Just trigger a glFinish if the native sync on host
@@ -2170,17 +2290,21 @@
if (type == EGL_SYNC_NATIVE_FENCE_ANDROID) {
syncRes->type = EGL_SYNC_NATIVE_FENCE_ANDROID;
- if (inputFenceFd < 0) {
+ if (rcEnc->hasVirtioGpuNativeSync()) {
syncRes->android_native_fence_fd = newFenceFd;
} else {
- DPRINT("has input fence fd %d",
- inputFenceFd);
- syncRes->android_native_fence_fd = inputFenceFd;
+ if (inputFenceFd < 0) {
+ syncRes->android_native_fence_fd = newFenceFd;
+ } else {
+ DPRINT("has input fence fd %d",
+ inputFenceFd);
+ syncRes->android_native_fence_fd = inputFenceFd;
+ }
}
} else {
syncRes->type = EGL_SYNC_FENCE_KHR;
syncRes->android_native_fence_fd = -1;
- if (!rcEnc->hasNativeSync()) {
+ if (!rcEnc->hasNativeSync() && !rcEnc->hasVirtioGpuNativeSync()) {
syncRes->status = EGL_SIGNALED_KHR;
}
}
@@ -2206,7 +2330,7 @@
if (sync) {
DEFINE_HOST_CONNECTION;
- if (rcEnc->hasNativeSync()) {
+ if (rcEnc->hasVirtioGpuNativeSync() || rcEnc->hasNativeSync()) {
rcEnc->rcDestroySyncKHR(rcEnc, sync->handle);
}
delete sync;
@@ -2233,7 +2357,7 @@
DEFINE_HOST_CONNECTION;
EGLint retval;
- if (rcEnc->hasNativeSync()) {
+ if (rcEnc->hasVirtioGpuNativeSync() || rcEnc->hasNativeSync()) {
retval = rcEnc->rcClientWaitSyncKHR
(rcEnc, sync->handle, flags, timeout);
} else {
@@ -2272,7 +2396,7 @@
} else {
// ask the host again
DEFINE_HOST_CONNECTION;
- if (rcEnc->hasNativeSyncV4()) {
+ if (rcEnc->hasVirtioGpuNativeSync() || rcEnc->hasNativeSyncV4()) {
if (rcEnc->rcIsSyncSignaled(rcEnc, sync->handle)) {
sync->status = EGL_SIGNALED_KHR;
}
@@ -2317,7 +2441,7 @@
}
DEFINE_HOST_CONNECTION;
- if (rcEnc->hasNativeSyncV3()) {
+ if (rcEnc->hasVirtioGpuNativeSync() || rcEnc->hasNativeSyncV3()) {
EGLSync_t* sync = (EGLSync_t*)eglsync;
rcEnc->rcWaitSyncKHR(rcEnc, sync->handle, flags);
}
diff --git a/system/egl/eglDisplay.cpp b/system/egl/eglDisplay.cpp
index b3f14da..2508f48 100644
--- a/system/egl/eglDisplay.cpp
+++ b/system/egl/eglDisplay.cpp
@@ -357,11 +357,11 @@
std::string dynamicEGLExtensions;
- if (hcon->rcEncoder()->hasNativeSync() &&
+ if ((hcon->rcEncoder()->hasVirtioGpuNativeSync() || hcon->rcEncoder()->hasNativeSync()) &&
!strstr(initialEGLExts, kDynamicEGLExtNativeSync)) {
dynamicEGLExtensions += kDynamicEGLExtNativeSync;
- if (hcon->rcEncoder()->hasNativeSyncV3()) {
+ if (hcon->rcEncoder()->hasVirtioGpuNativeSync() || hcon->rcEncoder()->hasNativeSyncV3()) {
dynamicEGLExtensions += kDynamicEGLExtWaitSync;
}
}