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
m_gl2Enc(NULL),
m_rcEnc(NULL),
m_checksumHelper(),
+ m_glExtensions(),
m_grallocOnly(true)
{
}
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;
}
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);
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
}
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:
GLEncoder *glEncoder();
GL2Encoder *gl2Encoder();
- renderControl_encoder_context_t *rcEncoder();
+ ExtendedRCEncoderContext *rcEncoder();
ChecksumCalculator *checksumHelper() { return &m_checksumHelper; }
void flush() {
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;
};
#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(); \
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; \
#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";
"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;
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;
}
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);