OSDN Git Service

ANDROID_EMU_ASYNC_SWAP extension searching + setting
authorLingfeng Yang <lfy@google.com>
Wed, 13 Jul 2016 23:26:10 +0000 (16:26 -0700)
committerLingfeng Yang <lfy@google.com>
Thu, 28 Jul 2016 17:05:20 +0000 (10:05 -0700)
In order for the async frame swapping feature to work
with all combinations of new/old emulators and system images,
one way to do it is to introduce an emulator-specific GL
extension. This is the same way the checksum calculation
support works.

This is a port to device/generic/goldfish-opengl, based on

https://googleplex-android-review.git.corp.google.com/#/c/1065345/

This is part of a sequential, multi-CL change. There is also
a corresponding multi-CL change on the host side:

https://android-review.googlesource.com/#/q/topic:emu-glsync-host

The changes in the system image are as follows:

platform/build:

https://googleplex-android-review.git.corp.google.com/1024926

device/generic/goldfish:

https://googleplex-android-review.git.corp.google.com/1230942

device/generic/goldfish-opengl:

https://googleplex-android-review.git.corp.google.com/1219535 <- this CL
https://googleplex-android-review.git.corp.google.com/1219536
https://googleplex-android-review.git.corp.google.com/1219537
https://googleplex-android-review.git.corp.google.com/1219538
https://googleplex-android-review.git.corp.google.com/1219539
https://googleplex-android-review.git.corp.google.com/1219570
https://googleplex-android-review.git.corp.google.com/1219571

Change-Id: Id07a72e5cb3397ff9d0b55788b8ad763c15050f3

system/OpenglSystemCommon/HostConnection.cpp
system/OpenglSystemCommon/HostConnection.h
system/egl/egl.cpp
system/egl/eglDisplay.cpp

index 4dcafca..2fb1eca 100644 (file)
@@ -33,6 +33,7 @@ HostConnection::HostConnection() :
     m_gl2Enc(NULL),
     m_rcEnc(NULL),
     m_checksumHelper(),
+    m_glExtensions(),
     m_grallocOnly(true)
 {
 }
@@ -142,11 +143,12 @@ GL2Encoder *HostConnection::gl2Encoder()
     return m_gl2Enc;
 }
 
-renderControl_encoder_context_t *HostConnection::rcEncoder()
+ExtendedRCEncoderContext *HostConnection::rcEncoder()
 {
     if (!m_rcEnc) {
-        m_rcEnc = new renderControl_encoder_context_t(m_stream, checksumHelper());
+        m_rcEnc = new ExtendedRCEncoderContext(m_stream, checksumHelper());
         setChecksumHelper(m_rcEnc);
+        queryAndSetSyncImpl(m_rcEnc);
     }
     return m_rcEnc;
 }
@@ -169,22 +171,35 @@ gl2_client_context_t *HostConnection::s_getGL2Context()
     return NULL;
 }
 
-void HostConnection::setChecksumHelper(renderControl_encoder_context_t *rcEnc) {
-    char *glExtensions = NULL;
+std::string HostConnection::queryGLExtensions(ExtendedRCEncoderContext *rcEnc) {
+    if (m_glExtensions.size() > 0) return m_glExtensions;
+
+    std::string extensions_buffer;
     int extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS, NULL, 0);
     if (extensionSize < 0) {
-        glExtensions = new char[-extensionSize];
-        extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS, glExtensions, -extensionSize);
+
+        extensions_buffer.resize(-extensionSize);
+        extensionSize = rcEnc->rcGetGLString(rcEnc, GL_EXTENSIONS,
+                                             &extensions_buffer[0], -extensionSize);
+
         if (extensionSize <= 0) {
-            delete [] glExtensions;
-            glExtensions = NULL;
+            return std::string();
         }
+
+        m_glExtensions += extensions_buffer;
+
+        return m_glExtensions;
     }
+
+    return std::string();
+}
+
+void HostConnection::setChecksumHelper(ExtendedRCEncoderContext *rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
     // check the host supported version
     uint32_t checksumVersion = 0;
     const char* checksumPrefix = ChecksumCalculator::getMaxVersionStrPrefix();
-    const char* glProtocolStr = glExtensions ?
-            strstr(glExtensions, checksumPrefix) : NULL;
+    const char* glProtocolStr = strstr(glExtensions.c_str(), checksumPrefix);
     if (glProtocolStr) {
         uint32_t maxVersion = ChecksumCalculator::getMaxVersion();
         sscanf(glProtocolStr+strlen(checksumPrefix), "%d", &checksumVersion);
@@ -196,5 +211,17 @@ void HostConnection::setChecksumHelper(renderControl_encoder_context_t *rcEnc) {
         rcEnc->rcSelectChecksumHelper(rcEnc, checksumVersion, 0);
         m_checksumHelper.setVersion(checksumVersion);
     }
-    delete [] glExtensions;
+}
+
+void HostConnection::queryAndSetSyncImpl(ExtendedRCEncoderContext *rcEnc) {
+    std::string glExtensions = queryGLExtensions(rcEnc);
+#if PLATFORM_SDK_VERSION <= 16
+    rcEnc->setSyncImpl(SYNC_IMPL_NONE);
+#else
+    if (glExtensions.find(kRCNativeSync) != std::string::npos) {
+        rcEnc->setSyncImpl(SYNC_IMPL_NATIVE_SYNC);
+    } else {
+        rcEnc->setSyncImpl(SYNC_IMPL_NONE);
+    }
+#endif
 }
index 70b757c..e01ec28 100644 (file)
@@ -27,6 +27,37 @@ class gl_client_context_t;
 class GL2Encoder;
 class gl2_client_context_t;
 
+// SyncImpl determines the presence of host/guest OpenGL fence sync
+// capabilities. It corresponds exactly to EGL_ANDROID_native_fence_sync
+// capability, but for the emulator, we need to make sure that
+// OpenGL pipe protocols match, so we use a special extension name
+// here.
+// SYNC_IMPL_NONE means that the native fence sync capability is
+// not present, and we will end up using the equivalent of glFinish
+// in order to preserve buffer swapping order.
+// SYNC_IMPL_NATIVE_SYNC means that we do have native fence sync
+// capability, and we will use a fence fd to synchronize buffer swaps.
+enum SyncImpl {
+    SYNC_IMPL_NONE = 0,
+    SYNC_IMPL_NATIVE_SYNC = 1
+};
+// Interface:
+// If this GL extension string shows up, we use
+// SYNC_IMPL_NATIVE_SYNC, otherwise we use SYNC_IMPL_NONE.
+static const char kRCNativeSync[] = "ANDROID_EMU_NATIVE_SYNC";
+
+// ExtendedRCEncoderContext is an extended version of renderControl_encoder_context_t
+// that will be used to track SyncImpl.
+class ExtendedRCEncoderContext : public renderControl_encoder_context_t {
+public:
+    ExtendedRCEncoderContext(IOStream *stream, ChecksumCalculator *checksumCalculator)
+        : renderControl_encoder_context_t(stream, checksumCalculator) { }
+    void setSyncImpl(SyncImpl syncImpl) { m_syncImpl = syncImpl; }
+    bool hasNativeSync() const { return m_syncImpl == SYNC_IMPL_NATIVE_SYNC; }
+private:
+    SyncImpl m_syncImpl;
+};
+
 class HostConnection
 {
 public:
@@ -36,7 +67,7 @@ public:
 
     GLEncoder *glEncoder();
     GL2Encoder *gl2Encoder();
-    renderControl_encoder_context_t *rcEncoder();
+    ExtendedRCEncoderContext *rcEncoder();
     ChecksumCalculator *checksumHelper() { return &m_checksumHelper; }
 
     void flush() {
@@ -56,17 +87,19 @@ private:
     static gl_client_context_t  *s_getGLContext();
     static gl2_client_context_t *s_getGL2Context();
 
-    std::string queryGLExtensions(renderControl_encoder_context_t *rcEnc);
+    std::string queryGLExtensions(ExtendedRCEncoderContext *rcEnc);
     // setProtocol initilizes GL communication protocol for checksums
     // should be called when m_rcEnc is created
-    void setChecksumHelper(renderControl_encoder_context_t *rcEnc);
+    void setChecksumHelper(ExtendedRCEncoderContext *rcEnc);
+    void queryAndSetSyncImpl(ExtendedRCEncoderContext *rcEnc);
 
 private:
     IOStream *m_stream;
     GLEncoder   *m_glEnc;
     GL2Encoder  *m_gl2Enc;
-    renderControl_encoder_context_t *m_rcEnc;
+    ExtendedRCEncoderContext *m_rcEnc;
     ChecksumCalculator m_checksumHelper;
+    std::string m_glExtensions;
     bool m_grallocOnly;
 };
 
index 87c3eb5..bebd1eb 100644 (file)
@@ -115,7 +115,7 @@ const char *  eglStrError(EGLint err)
 
 #define DEFINE_HOST_CONNECTION \
     HostConnection *hostCon = HostConnection::get(); \
-    renderControl_encoder_context_t *rcEnc = (hostCon ? hostCon->rcEncoder() : NULL)
+    ExtendedRCEncoderContext *rcEnc = (hostCon ? hostCon->rcEncoder() : NULL)
 
 #define DEFINE_AND_VALIDATE_HOST_CONNECTION(ret) \
     HostConnection *hostCon = HostConnection::get(); \
@@ -123,7 +123,7 @@ const char *  eglStrError(EGLint err)
         ALOGE("egl: Failed to get host connection\n"); \
         return ret; \
     } \
-    renderControl_encoder_context_t *rcEnc = hostCon->rcEncoder(); \
+    ExtendedRCEncoderContext *rcEnc = hostCon->rcEncoder(); \
     if (!rcEnc) { \
         ALOGE("egl: Failed to get renderControl encoder context\n"); \
         return ret; \
index 2ff3ad6..7097256 100644 (file)
@@ -17,6 +17,8 @@
 #include "HostConnection.h"
 #include <dlfcn.h>
 
+#include <string>
+
 static const int systemEGLVersionMajor = 1;
 static const int systemEGLVersionMinor = 4;
 static const char systemEGLVendor[] = "Google Android emulator";
@@ -29,6 +31,9 @@ static const char systemStaticEGLExtensions[] =
             "EGL_KHR_image_base "
             "EGL_KHR_gl_texture_2d_image ";
 
+// extensions to add dynamically depending on host-side support
+static const char kDynamicEGLExtNativeSync[] = "EGL_ANDROID_native_fence_sync ";
+
 static void *s_gles_lib = NULL;
 static void *s_gles2_lib = NULL;
 
@@ -278,14 +283,10 @@ static char *queryHostEGLString(EGLint name)
         if (rcEnc) {
             int n = rcEnc->rcQueryEGLString(rcEnc, name, NULL, 0);
             if (n < 0) {
-                // allocate space for the string with additional
-                // space charachter to be suffixed at the end.
-                char *str = (char *)malloc(-n+2);
+                // allocate space for the string.
+                char *str = (char *)malloc(-n);
                 n = rcEnc->rcQueryEGLString(rcEnc, name, str, -n);
                 if (n > 0) {
-                    // add extra space at end of string which will be
-                    // needed later when filtering the extension list.
-                    strcat(str, " ");
                     return str;
                 }
 
@@ -325,10 +326,27 @@ static char *buildExtensionString()
 
     int n = strlen(hostExt);
     if (n > 0) {
-        char *str;
-        asprintf(&str,"%s%s", systemStaticEGLExtensions, hostExt);
+        char *initialEGLExts;
+        char *finalEGLExts;
+
+        HostConnection *hcon = HostConnection::get();
+        // If we got here, we must have succeeded in queryHostEGLString
+        // and we thus should have a valid connection
+        assert(hcon);
+
+        asprintf(&initialEGLExts,"%s%s", systemStaticEGLExtensions, hostExt);
+
+        std::string dynamicEGLExtensions;
+
+        if (hcon->rcEncoder()->hasNativeSync() &&
+            !strstr(initialEGLExts, kDynamicEGLExtNativeSync)) {
+            dynamicEGLExtensions += kDynamicEGLExtNativeSync;
+        }
+
+        asprintf(&finalEGLExts, "%s%s", initialEGLExts, dynamicEGLExtensions.c_str());
+
         free((char*)hostExt);
-        return str;
+        return finalEGLExts;
     }
     else {
         free((char*)hostExt);