Merge "Temprorarily opt out libui from libcrt"
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index bab87ac..4da30e9 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -23,7 +23,6 @@
shared_libs: [
"liblog",
- "libcutils",
],
export_include_dirs: ["include"],
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 3328ad7..2a7d76e 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -18,12 +18,9 @@
#define LOG_TAG "GraphicsEnv"
#include <graphicsenv/GraphicsEnv.h>
-#include <sys/prctl.h>
-
#include <mutex>
#include <android/dlext.h>
-#include <cutils/properties.h>
#include <log/log.h>
// TODO(b/37049319) Get this from a header once one exists
@@ -49,14 +46,6 @@
return env;
}
-int GraphicsEnv::getCanLoadSystemLibraries() {
- if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
- // Return an integer value since this crosses library boundaries
- return 1;
- }
- return 0;
-}
-
void GraphicsEnv::setDriverPath(const std::string path) {
if (!mDriverPath.empty()) {
ALOGV("ignoring attempt to change driver path from '%s' to '%s'",
@@ -192,10 +181,4 @@
const char* android_getAngleAppPref() {
return android::GraphicsEnv::getInstance().getAngleAppPref();
}
-const char* android_getLayerPaths() {
- return android::GraphicsEnv::getInstance().getLayerPaths().c_str();
-}
-const char* android_getDebugLayers() {
- return android::GraphicsEnv::getInstance().getDebugLayers().c_str();
-}
}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 1783429..00e8fc0 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -29,8 +29,6 @@
public:
static GraphicsEnv& getInstance();
- int getCanLoadSystemLibraries();
-
// Set a search path for loading graphics drivers. The path is a list of
// directories separated by ':'. A directory can be contained in a zip file
// (drivers must be stored uncompressed and page aligned); such elements
@@ -87,13 +85,11 @@
* will be removed soon.
*/
extern "C" {
- android_namespace_t* android_getDriverNamespace();
- android_namespace_t* android_getAngleNamespace();
- const char* android_getAngleAppName();
- const char* android_getAngleAppPref();
- bool android_getAngleDeveloperOptIn();
- const char* android_getLayerPaths();
- const char* android_getDebugLayers();
+android_namespace_t* android_getDriverNamespace();
+android_namespace_t* android_getAngleNamespace();
+const char* android_getAngleAppName();
+const char* android_getAngleAppPref();
+bool android_getAngleDeveloperOptIn();
}
#endif // ANDROID_UI_GRAPHICS_ENV_H
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index 9b84707..bc6aece 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -116,9 +116,10 @@
cid_ = buffer_desc.buffer_cid();
buffer_state_bit_ = buffer_desc.buffer_state_bit();
- // Note that here the buffer state is mapped from shared memory as an atomic
- // object. The std::atomic's constructor will not be called so that the
- // original value stored in the memory region will be preserved.
+ // Note that here the buffer_state, fence_state and active_clients_bit_mask
+ // are mapped from shared memory as an atomic object. The std::atomic's
+ // constructor will not be called so that the original value stored in the
+ // memory region will be preserved.
buffer_state_ = &metadata_header_->buffer_state;
ALOGD_IF(TRACE,
"BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
@@ -127,6 +128,12 @@
ALOGD_IF(TRACE,
"BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", id(),
fence_state_->load());
+ active_clients_bit_mask_ = &metadata_header_->active_clients_bit_mask;
+ ALOGD_IF(
+ TRACE,
+ "BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx64
+ ".",
+ id(), active_clients_bit_mask_->load());
return 0;
}
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 03208f5..282be46 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -134,6 +134,7 @@
void* user_metadata_ptr_{nullptr};
std::atomic<uint64_t>* buffer_state_{nullptr};
std::atomic<uint64_t>* fence_state_{nullptr};
+ std::atomic<uint64_t>* active_clients_bit_mask_{nullptr};
LocalHandle shared_acquire_fence_;
LocalHandle shared_release_fence_;
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index 5a24253..6d28d41 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -75,6 +75,7 @@
// and vendor HAL).
std::atomic<uint64_t> buffer_state;
std::atomic<uint64_t> fence_state;
+ std::atomic<uint64_t> active_clients_bit_mask;
uint64_t queue_index;
// Public data format, which should be updated with caution. See more details
@@ -82,7 +83,7 @@
DvrNativeBufferMetadata metadata;
};
-static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static_assert(sizeof(MetadataHeader) == 136, "Unexpected MetadataHeader size");
static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
} // namespace BufferHubDefs
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 583aec9..2a6dee4 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -140,10 +140,8 @@
"EGL/egl_cache.cpp",
"EGL/egl_display.cpp",
"EGL/egl_object.cpp",
- "EGL/egl_layers.cpp",
"EGL/egl.cpp",
"EGL/eglApi.cpp",
- "EGL/egl_platform_entries.cpp",
"EGL/Loader.cpp",
"EGL/egl_angle_platform.cpp",
],
@@ -151,11 +149,8 @@
"libvndksupport",
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
- "libbase",
"libhidlbase",
"libhidltransport",
- "libnativebridge",
- "libnativeloader",
"libutils",
],
static_libs: [
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index cd227ca..87f0fe1 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -33,7 +33,6 @@
#endif
#include <vndksupport/linker.h>
-#include "egl_platform_entries.h"
#include "egl_trace.h"
#include "egldefs.h"
@@ -238,12 +237,12 @@
setEmulatorGlesValue();
- dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2 | PLATFORM);
+ dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2);
if (dso) {
hnd = new driver_t(dso);
} else {
// Always load EGL first
- dso = load_driver("EGL", cnx, EGL | PLATFORM);
+ dso = load_driver("EGL", cnx, EGL);
if (dso) {
hnd = new driver_t(dso);
hnd->set( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM );
@@ -635,25 +634,6 @@
return nullptr;
}
- if (mask & PLATFORM) {
- // For each entrypoint tracked by the platform
- char const* const* entries = platform_names;
- EGLFuncPointer* curr = reinterpret_cast<EGLFuncPointer*>(&cnx->platform);
-
- while (*entries) {
- const char* name = *entries;
- EGLFuncPointer f = FindPlatformImplAddr(name);
-
- if (f == nullptr) {
- // If no entry found, update the lookup table: sPlatformImplMap
- ALOGE("No entry found in platform lookup table for %s", name);
- }
-
- *curr++ = f;
- entries++;
- }
- }
-
if (mask & EGL) {
getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 9cc73f3..e88d1a2 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -33,8 +33,7 @@
enum {
EGL = 0x01,
GLESv1_CM = 0x02,
- GLESv2 = 0x04,
- PLATFORM = 0x08
+ GLESv2 = 0x04
};
struct driver_t {
explicit driver_t(void* gles);
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 8870d5f..7089860 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -30,10 +30,11 @@
#include "egl_tls.h"
#include "egl_display.h"
#include "egl_object.h"
-#include "egl_layers.h"
#include "CallStack.h"
#include "Loader.h"
+typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer;
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -166,10 +167,6 @@
return (GLint)c->tokenized_gl_extensions.size();
}
-egl_connection_t* egl_get_connection() {
- return &gEGLImpl;
-}
-
// ----------------------------------------------------------------------------
// this mutex protects:
@@ -195,14 +192,6 @@
cnx->dso = loader.open(cnx);
}
- // Check to see if any layers are enabled and route functions through them
- if (cnx->dso) {
- // Layers can be enabled long after the drivers have been loaded.
- // They will only be initialized once.
- LayerLoader& layer_loader(LayerLoader::getInstance());
- layer_loader.InitLayers(cnx);
- }
-
return cnx->dso ? EGL_TRUE : EGL_FALSE;
}
@@ -273,11 +262,6 @@
nullptr
};
-char const * const platform_names[] = {
- #include "platform_entries.in"
- nullptr
-};
-
#undef GL_ENTRY
#undef EGL_ENTRY
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 8202c4e..d2dc514 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1,5 +1,5 @@
/*
- ** Copyright 2018, The Android Open Source Project
+ ** Copyright 2007, 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.
@@ -16,198 +16,1185 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <ctype.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/gralloc1.h>
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <EGL/eglext_angle.h>
+
+#include <android/hardware_buffer.h>
+#include <private/android/AHardwareBufferHelpers.h>
+
+#include <cutils/compiler.h>
+#include <cutils/properties.h>
+#include <log/log.h>
+
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <unordered_map>
+#include <string>
+#include <thread>
#include "../egl_impl.h"
-#include "egl_layers.h"
-#include "egl_platform_entries.h"
+#include "egl_display.h"
+#include "egl_object.h"
#include "egl_tls.h"
#include "egl_trace.h"
using namespace android;
+// ----------------------------------------------------------------------------
+
namespace android {
-extern EGLBoolean egl_init_drivers();
+using nsecs_t = int64_t;
-} // namespace android
+struct extention_map_t {
+ const char* name;
+ __eglMustCastToProperFunctionPointerType address;
+};
-static inline void clearError() {
- egl_tls_t::clearError();
+/*
+ * This is the list of EGL extensions exposed to applications.
+ *
+ * Some of them (gBuiltinExtensionString) are implemented entirely in this EGL
+ * wrapper and are always available.
+ *
+ * The rest (gExtensionString) depend on support in the EGL driver, and are
+ * only available if the driver supports them. However, some of these must be
+ * supported because they are used by the Android system itself; these are
+ * listed as mandatory below and are required by the CDD. The system *assumes*
+ * the mandatory extensions are present and may not function properly if some
+ * are missing.
+ *
+ * NOTE: Both strings MUST have a single space as the last character.
+ */
+
+extern char const * const gBuiltinExtensionString;
+extern char const * const gExtensionString;
+
+// clang-format off
+// Extensions implemented by the EGL wrapper.
+char const * const gBuiltinExtensionString =
+ "EGL_KHR_get_all_proc_addresses "
+ "EGL_ANDROID_presentation_time "
+ "EGL_KHR_swap_buffers_with_damage "
+ "EGL_ANDROID_get_native_client_buffer "
+ "EGL_ANDROID_front_buffer_auto_refresh "
+ "EGL_ANDROID_get_frame_timestamps "
+ "EGL_EXT_surface_SMPTE2086_metadata "
+ "EGL_EXT_surface_CTA861_3_metadata "
+ ;
+
+// Whitelist of extensions exposed to applications if implemented in the vendor driver.
+char const * const gExtensionString =
+ "EGL_KHR_image " // mandatory
+ "EGL_KHR_image_base " // mandatory
+ "EGL_EXT_image_gl_colorspace "
+ "EGL_KHR_image_pixmap "
+ "EGL_KHR_lock_surface "
+ "EGL_KHR_gl_colorspace "
+ "EGL_KHR_gl_texture_2D_image "
+ "EGL_KHR_gl_texture_3D_image "
+ "EGL_KHR_gl_texture_cubemap_image "
+ "EGL_KHR_gl_renderbuffer_image "
+ "EGL_KHR_reusable_sync "
+ "EGL_KHR_fence_sync "
+ "EGL_KHR_create_context "
+ "EGL_KHR_config_attribs "
+ "EGL_KHR_surfaceless_context "
+ "EGL_KHR_stream "
+ "EGL_KHR_stream_fifo "
+ "EGL_KHR_stream_producer_eglsurface "
+ "EGL_KHR_stream_consumer_gltexture "
+ "EGL_KHR_stream_cross_process_fd "
+ "EGL_EXT_create_context_robustness "
+ "EGL_NV_system_time "
+ "EGL_ANDROID_image_native_buffer " // mandatory
+ "EGL_KHR_wait_sync " // strongly recommended
+ "EGL_ANDROID_recordable " // mandatory
+ "EGL_KHR_partial_update " // strongly recommended
+ "EGL_EXT_pixel_format_float "
+ "EGL_EXT_buffer_age " // strongly recommended with partial_update
+ "EGL_KHR_create_context_no_error "
+ "EGL_KHR_mutable_render_buffer "
+ "EGL_EXT_yuv_surface "
+ "EGL_EXT_protected_content "
+ "EGL_IMG_context_priority "
+ "EGL_KHR_no_config_context "
+ ;
+// clang-format on
+
+// extensions not exposed to applications but used by the ANDROID system
+// "EGL_ANDROID_blob_cache " // strongly recommended
+// "EGL_IMG_hibernate_process " // optional
+// "EGL_ANDROID_native_fence_sync " // strongly recommended
+// "EGL_ANDROID_framebuffer_target " // mandatory for HWC 1.1
+
+/*
+ * EGL Extensions entry-points exposed to 3rd party applications
+ * (keep in sync with gExtensionString above)
+ *
+ */
+static const extention_map_t sExtensionMap[] = {
+ // EGL_KHR_lock_surface
+ { "eglLockSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
+ { "eglUnlockSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
+
+ // EGL_KHR_image, EGL_KHR_image_base
+ { "eglCreateImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
+ { "eglDestroyImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
+
+ // EGL_KHR_reusable_sync, EGL_KHR_fence_sync
+ { "eglCreateSyncKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR },
+ { "eglDestroySyncKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR },
+ { "eglClientWaitSyncKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR },
+ { "eglSignalSyncKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglSignalSyncKHR },
+ { "eglGetSyncAttribKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR },
+
+ // EGL_NV_system_time
+ { "eglGetSystemTimeFrequencyNV",
+ (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV },
+ { "eglGetSystemTimeNV",
+ (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV },
+
+ // EGL_KHR_wait_sync
+ { "eglWaitSyncKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglWaitSyncKHR },
+
+ // EGL_ANDROID_presentation_time
+ { "eglPresentationTimeANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglPresentationTimeANDROID },
+
+ // EGL_KHR_swap_buffers_with_damage
+ { "eglSwapBuffersWithDamageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglSwapBuffersWithDamageKHR },
+
+ // EGL_ANDROID_get_native_client_buffer
+ { "eglGetNativeClientBufferANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetNativeClientBufferANDROID },
+
+ // EGL_KHR_partial_update
+ { "eglSetDamageRegionKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglSetDamageRegionKHR },
+
+ { "eglCreateStreamKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateStreamKHR },
+ { "eglDestroyStreamKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroyStreamKHR },
+ { "eglStreamAttribKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglStreamAttribKHR },
+ { "eglQueryStreamKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglQueryStreamKHR },
+ { "eglQueryStreamu64KHR",
+ (__eglMustCastToProperFunctionPointerType)&eglQueryStreamu64KHR },
+ { "eglQueryStreamTimeKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglQueryStreamTimeKHR },
+ { "eglCreateStreamProducerSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateStreamProducerSurfaceKHR },
+ { "eglStreamConsumerGLTextureExternalKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerGLTextureExternalKHR },
+ { "eglStreamConsumerAcquireKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerAcquireKHR },
+ { "eglStreamConsumerReleaseKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerReleaseKHR },
+ { "eglGetStreamFileDescriptorKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglGetStreamFileDescriptorKHR },
+ { "eglCreateStreamFromFileDescriptorKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR },
+
+ // EGL_ANDROID_get_frame_timestamps
+ { "eglGetNextFrameIdANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetNextFrameIdANDROID },
+ { "eglGetCompositorTimingANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingANDROID },
+ { "eglGetCompositorTimingSupportedANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingSupportedANDROID },
+ { "eglGetFrameTimestampsANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampsANDROID },
+ { "eglGetFrameTimestampSupportedANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampSupportedANDROID },
+
+ // EGL_ANDROID_native_fence_sync
+ { "eglDupNativeFenceFDANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglDupNativeFenceFDANDROID },
+};
+
+/*
+ * These extensions entry-points should not be exposed to applications.
+ * They're used internally by the Android EGL layer.
+ */
+#define FILTER_EXTENSIONS(procname) \
+ (!strcmp((procname), "eglSetBlobCacheFuncsANDROID") || \
+ !strcmp((procname), "eglHibernateProcessIMG") || \
+ !strcmp((procname), "eglAwakenProcessIMG"))
+
+// accesses protected by sExtensionMapMutex
+static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
+
+static int sGLExtentionSlot = 0;
+static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void(*findProcAddress(const char* name,
+ const extention_map_t* map, size_t n))() {
+ for (uint32_t i=0 ; i<n ; i++) {
+ if (!strcmp(name, map[i].name)) {
+ return map[i].address;
+ }
+ }
+ return nullptr;
}
-EGLDisplay eglGetDisplay(EGLNativeDisplayType display) {
+// ----------------------------------------------------------------------------
+
+extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
+extern EGLBoolean egl_init_drivers();
+extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
+extern gl_hooks_t gHooksTrace;
+
+} // namespace android;
+
+
+// ----------------------------------------------------------------------------
+
+static inline void clearError() { egl_tls_t::clearError(); }
+static inline EGLContext getContext() { return egl_tls_t::getContext(); }
+
+// ----------------------------------------------------------------------------
+
+EGLDisplay eglGetDisplay(EGLNativeDisplayType display)
+{
ATRACE_CALL();
clearError();
+ uintptr_t index = reinterpret_cast<uintptr_t>(display);
+ if (index >= NUM_DISPLAYS) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
if (egl_init_drivers() == EGL_FALSE) {
return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
}
- // Call down the chain, which usually points directly to the impl
- // but may also be routed through layers
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetDisplay(display);
+ EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
+ return dpy;
}
-EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
+// ----------------------------------------------------------------------------
+// Initialization
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglInitialize(dpy, major, minor);
+ egl_display_ptr dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+
+ EGLBoolean res = dp->initialize(major, minor);
+
+ return res;
}
-EGLBoolean eglTerminate(EGLDisplay dpy) {
+EGLBoolean eglTerminate(EGLDisplay dpy)
+{
+ // NOTE: don't unload the drivers b/c some APIs can be called
+ // after eglTerminate() has been called. eglTerminate() only
+ // terminates an EGLDisplay, not a EGL itself.
+
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglTerminate(dpy);
+ egl_display_ptr dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+
+ EGLBoolean res = dp->terminate();
+
+ return res;
}
-EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size,
- EGLint* num_config) {
+// ----------------------------------------------------------------------------
+// configuration
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglGetConfigs( EGLDisplay dpy,
+ EGLConfig *configs,
+ EGLint config_size, EGLint *num_config)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ if (num_config==nullptr) {
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
+ }
+
+ EGLBoolean res = EGL_FALSE;
+ *num_config = 0;
+
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetConfigs(dpy, configs, config_size, num_config);
+ if (cnx->dso) {
+ res = cnx->egl.eglGetConfigs(
+ dp->disp.dpy, configs, config_size, num_config);
+ }
+
+ return res;
}
-EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs,
- EGLint config_size, EGLint* num_config) {
+EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ if (num_config==nullptr) {
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
+ }
+
+ EGLBoolean res = EGL_FALSE;
+ *num_config = 0;
+
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglChooseConfig(dpy, attrib_list, configs, config_size, num_config);
+ if (cnx->dso) {
+ if (attrib_list) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.force_msaa", value, "false");
+
+ if (!strcmp(value, "true")) {
+ size_t attribCount = 0;
+ EGLint attrib = attrib_list[0];
+
+ // Only enable MSAA if the context is OpenGL ES 2.0 and
+ // if no caveat is requested
+ const EGLint *attribRendererable = nullptr;
+ const EGLint *attribCaveat = nullptr;
+
+ // Count the number of attributes and look for
+ // EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT
+ while (attrib != EGL_NONE) {
+ attrib = attrib_list[attribCount];
+ switch (attrib) {
+ case EGL_RENDERABLE_TYPE:
+ attribRendererable = &attrib_list[attribCount];
+ break;
+ case EGL_CONFIG_CAVEAT:
+ attribCaveat = &attrib_list[attribCount];
+ break;
+ default:
+ break;
+ }
+ attribCount++;
+ }
+
+ if (attribRendererable && attribRendererable[1] == EGL_OPENGL_ES2_BIT &&
+ (!attribCaveat || attribCaveat[1] != EGL_NONE)) {
+
+ // Insert 2 extra attributes to force-enable MSAA 4x
+ EGLint aaAttribs[attribCount + 4];
+ aaAttribs[0] = EGL_SAMPLE_BUFFERS;
+ aaAttribs[1] = 1;
+ aaAttribs[2] = EGL_SAMPLES;
+ aaAttribs[3] = 4;
+
+ memcpy(&aaAttribs[4], attrib_list, attribCount * sizeof(EGLint));
+
+ EGLint numConfigAA;
+ EGLBoolean resAA = cnx->egl.eglChooseConfig(
+ dp->disp.dpy, aaAttribs, configs, config_size, &numConfigAA);
+
+ if (resAA == EGL_TRUE && numConfigAA > 0) {
+ ALOGD("Enabling MSAA 4x");
+ *num_config = numConfigAA;
+ return resAA;
+ }
+ }
+ }
+ }
+
+ res = cnx->egl.eglChooseConfig(
+ dp->disp.dpy, attrib_list, configs, config_size, num_config);
+ }
+ return res;
}
-EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value) {
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetConfigAttrib(dpy, config, attribute, value);
+ egl_connection_t* cnx = nullptr;
+ const egl_display_ptr dp = validate_display_connection(dpy, cnx);
+ if (!dp) return EGL_FALSE;
+
+ return cnx->egl.eglGetConfigAttrib(
+ dp->disp.dpy, config, attribute, value);
}
-EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window,
- const EGLint* attrib_list) {
- clearError();
+// ----------------------------------------------------------------------------
+// surfaces
+// ----------------------------------------------------------------------------
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCreateWindowSurface(dpy, config, window, attrib_list);
+// Translates EGL color spaces to Android data spaces.
+static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) {
+ if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
+ return HAL_DATASPACE_UNKNOWN;
+ } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
+ return HAL_DATASPACE_SRGB;
+ } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) {
+ return HAL_DATASPACE_DISPLAY_P3;
+ } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) {
+ return HAL_DATASPACE_DISPLAY_P3_LINEAR;
+ } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_EXT) {
+ return HAL_DATASPACE_V0_SCRGB;
+ } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
+ return HAL_DATASPACE_V0_SCRGB_LINEAR;
+ } else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) {
+ return HAL_DATASPACE_BT2020_LINEAR;
+ } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) {
+ return HAL_DATASPACE_BT2020_PQ;
+ }
+ return HAL_DATASPACE_UNKNOWN;
}
-EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap,
- const EGLint* attrib_list) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCreatePixmapSurface(dpy, config, pixmap, attrib_list);
+// Get the colorspace value that should be reported from queries. When the colorspace
+// is unknown (no attribute passed), default to reporting LINEAR.
+static EGLint getReportedColorSpace(EGLint colorspace) {
+ return colorspace == EGL_UNKNOWN ? EGL_GL_COLORSPACE_LINEAR_KHR : colorspace;
}
-EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) {
- clearError();
+// Returns a list of color spaces understood by the vendor EGL driver.
+static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp,
+ android_pixel_format format) {
+ std::vector<EGLint> colorSpaces;
+ if (!dp->hasColorSpaceSupport) return colorSpaces;
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCreatePbufferSurface(dpy, config, attrib_list);
+ // OpenGL drivers only support sRGB encoding with 8-bit formats.
+ // RGB_888 is never returned by getNativePixelFormat, but is included for completeness.
+ const bool formatSupportsSRGBEncoding =
+ format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 ||
+ format == HAL_PIXEL_FORMAT_RGB_888;
+ const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16;
+
+ if (formatSupportsSRGBEncoding) {
+ // sRGB and linear are always supported when color space support is present.
+ colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+ colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
+ // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats.
+ if (findExtension(dp->disp.queryString.extensions,
+ "EGL_EXT_gl_colorspace_display_p3")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
+ }
+ }
+
+ // According to the spec, scRGB is only supported for floating point formats.
+ // For non-linear scRGB, the application is responsible for applying the
+ // transfer function.
+ if (formatIsFloatingPoint) {
+ if (findExtension(dp->disp.queryString.extensions,
+ "EGL_EXT_gl_colorspace_scrgb")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
+ }
+ if (findExtension(dp->disp.queryString.extensions,
+ "EGL_EXT_gl_colorspace_scrgb_linear")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
+ }
+ }
+
+ // BT2020 can be used with any pixel format. PQ encoding must be applied by the
+ // application and does not affect the behavior of OpenGL.
+ if (findExtension(dp->disp.queryString.extensions,
+ "EGL_EXT_gl_colorspace_bt2020_linear")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT);
+ }
+ if (findExtension(dp->disp.queryString.extensions,
+ "EGL_EXT_gl_colorspace_bt2020_pq")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
+ }
+
+ // Linear DCI-P3 simply uses different primaries than standard RGB and thus
+ // can be used with any pixel format.
+ if (findExtension(dp->disp.queryString.extensions,
+ "EGL_EXT_gl_colorspace_display_p3_linear")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT);
+ }
+ return colorSpaces;
}
-EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
- clearError();
+// Cleans up color space related parameters that the driver does not understand.
+// If there is no color space attribute in attrib_list, colorSpace is left
+// unmodified.
+static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window,
+ android_pixel_format format, const EGLint* attrib_list,
+ EGLint* colorSpace,
+ std::vector<EGLint>* strippedAttribList) {
+ for (const EGLint* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
+ bool copyAttribute = true;
+ if (attr[0] == EGL_GL_COLORSPACE_KHR) {
+ // Fail immediately if the driver doesn't have color space support at all.
+ if (!dp->hasColorSpaceSupport) return false;
+ *colorSpace = attr[1];
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglDestroySurface(dpy, surface);
+ // Strip the attribute if the driver doesn't understand it.
+ copyAttribute = false;
+ std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format);
+ for (auto driverColorSpace : driverColorSpaces) {
+ if (attr[1] == driverColorSpace) {
+ copyAttribute = true;
+ break;
+ }
+ }
+
+ // If the driver doesn't understand it, we should map sRGB-encoded P3 to
+ // sRGB rather than just dropping the colorspace on the floor.
+ // For this format, the driver is expected to apply the sRGB
+ // transfer function during framebuffer operations.
+ if (!copyAttribute && attr[1] == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) {
+ strippedAttribList->push_back(attr[0]);
+ strippedAttribList->push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+ }
+ }
+ if (copyAttribute) {
+ strippedAttribList->push_back(attr[0]);
+ strippedAttribList->push_back(attr[1]);
+ }
+ }
+ // Terminate the attribute list.
+ strippedAttribList->push_back(EGL_NONE);
+
+ // If the passed color space has wide color gamut, check whether the target native window
+ // supports wide color.
+ const bool colorSpaceIsNarrow =
+ *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
+ *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR ||
+ *colorSpace == EGL_UNKNOWN;
+ if (window && !colorSpaceIsNarrow) {
+ bool windowSupportsWideColor = true;
+ // Ordinarily we'd put a call to native_window_get_wide_color_support
+ // at the beginning of the function so that we'll have the
+ // result when needed elsewhere in the function.
+ // However, because eglCreateWindowSurface is called by SurfaceFlinger and
+ // SurfaceFlinger is required to answer the call below we would
+ // end up in a deadlock situation. By moving the call to only happen
+ // if the application has specifically asked for wide-color we avoid
+ // the deadlock with SurfaceFlinger since it will not ask for a
+ // wide-color surface.
+ int err = native_window_get_wide_color_support(window, &windowSupportsWideColor);
+
+ if (err) {
+ ALOGE("processAttributes: invalid window (win=%p) "
+ "failed (%#x) (already connected to another API?)",
+ window, err);
+ return false;
+ }
+ if (!windowSupportsWideColor) {
+ // Application has asked for a wide-color colorspace but
+ // wide-color support isn't available on the display the window is on.
+ return false;
+ }
+ }
+ return true;
}
-EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value) {
+// Gets the native pixel format corrsponding to the passed EGLConfig.
+void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config,
+ android_pixel_format* format) {
+ // Set the native window's buffers format to match what this config requests.
+ // Whether to use sRGB gamma is not part of the EGLconfig, but is part
+ // of our native format. So if sRGB gamma is requested, we have to
+ // modify the EGLconfig's format before setting the native window's
+ // format.
+
+ EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, &componentType);
+
+ EGLint a = 0;
+ EGLint r, g, b;
+ r = g = b = 0;
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+ EGLint colorDepth = r + g + b;
+
+ // Today, the driver only understands sRGB and linear on 888X
+ // formats. Strip other colorspaces from the attribute list and
+ // only use them to set the dataspace via
+ // native_window_set_buffers_dataspace
+ // if pixel format is RGBX 8888
+ // TBD: Can test for future extensions that indicate that driver
+ // handles requested color space and we can let it through.
+ // allow SRGB and LINEAR. All others need to be stripped.
+ // else if 565, 4444
+ // TBD: Can we assume these are supported if 8888 is?
+ // else if FP16 or 1010102
+ // strip colorspace from attribs.
+ // endif
+ if (a == 0) {
+ if (colorDepth <= 16) {
+ *format = HAL_PIXEL_FORMAT_RGB_565;
+ } else {
+ if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
+ if (colorDepth > 24) {
+ *format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ } else {
+ *format = HAL_PIXEL_FORMAT_RGBX_8888;
+ }
+ } else {
+ *format = HAL_PIXEL_FORMAT_RGBA_FP16;
+ }
+ }
+ } else {
+ if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
+ if (colorDepth > 24) {
+ *format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ } else {
+ *format = HAL_PIXEL_FORMAT_RGBA_8888;
+ }
+ } else {
+ *format = HAL_PIXEL_FORMAT_RGBA_FP16;
+ }
+ }
+}
+
+EGLBoolean sendSurfaceMetadata(egl_surface_t* s) {
+ android_smpte2086_metadata smpteMetadata;
+ if (s->getSmpte2086Metadata(smpteMetadata)) {
+ int err =
+ native_window_set_buffers_smpte2086_metadata(s->getNativeWindow(), &smpteMetadata);
+ s->resetSmpte2086Metadata();
+ if (err != 0) {
+ ALOGE("error setting native window smpte2086 metadata: %s (%d)",
+ strerror(-err), err);
+ return EGL_FALSE;
+ }
+ }
+ android_cta861_3_metadata cta8613Metadata;
+ if (s->getCta8613Metadata(cta8613Metadata)) {
+ int err =
+ native_window_set_buffers_cta861_3_metadata(s->getNativeWindow(), &cta8613Metadata);
+ s->resetCta8613Metadata();
+ if (err != 0) {
+ ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
+ strerror(-err), err);
+ return EGL_FALSE;
+ }
+ }
+ return EGL_TRUE;
+}
+
+EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
+ NativeWindowType window,
+ const EGLint *attrib_list)
+{
+ const EGLint *origAttribList = attrib_list;
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglQuerySurface(dpy, surface, attribute, value);
+ egl_connection_t* cnx = nullptr;
+ egl_display_ptr dp = validate_display_connection(dpy, cnx);
+ if (dp) {
+ if (!window) {
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
+ int value = 0;
+ window->query(window, NATIVE_WINDOW_IS_VALID, &value);
+ if (!value) {
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
+ // NOTE: When using Vulkan backend, the Vulkan runtime makes all the
+ // native_window_* calls, so don't do them here.
+ if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ if (result < 0) {
+ ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
+ "failed (%#x) (already connected to another API?)",
+ window, result);
+ return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+ }
+
+ EGLDisplay iDpy = dp->disp.dpy;
+ android_pixel_format format;
+ getNativePixelFormat(iDpy, cnx, config, &format);
+
+ // now select correct colorspace and dataspace based on user's attribute list
+ EGLint colorSpace = EGL_UNKNOWN;
+ std::vector<EGLint> strippedAttribList;
+ if (!processAttributes(dp, window, format, attrib_list, &colorSpace,
+ &strippedAttribList)) {
+ ALOGE("error invalid colorspace: %d", colorSpace);
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+ attrib_list = strippedAttribList.data();
+
+ if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ int err = native_window_set_buffers_format(window, format);
+ if (err != 0) {
+ ALOGE("error setting native window pixel format: %s (%d)",
+ strerror(-err), err);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
+ android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
+ if (dataSpace != HAL_DATASPACE_UNKNOWN) {
+ err = native_window_set_buffers_data_space(window, dataSpace);
+ if (err != 0) {
+ ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err),
+ err);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+ }
+ }
+
+ // the EGL spec requires that a new EGLSurface default to swap interval
+ // 1, so explicitly set that on the window here.
+ ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
+ anw->setSwapInterval(anw, 1);
+
+ EGLSurface surface = cnx->egl.eglCreateWindowSurface(
+ iDpy, config, window, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s =
+ new egl_surface_t(dp.get(), config, window, surface,
+ getReportedColorSpace(colorSpace), cnx);
+ return s;
+ }
+
+ // EGLSurface creation failed
+ if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ native_window_set_buffers_format(window, 0);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
+ NativePixmapType pixmap,
+ const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_connection_t* cnx = nullptr;
+ egl_display_ptr dp = validate_display_connection(dpy, cnx);
+ if (dp) {
+ EGLDisplay iDpy = dp->disp.dpy;
+ android_pixel_format format;
+ getNativePixelFormat(iDpy, cnx, config, &format);
+
+ // now select a corresponding sRGB format if needed
+ EGLint colorSpace = EGL_UNKNOWN;
+ std::vector<EGLint> strippedAttribList;
+ if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
+ &strippedAttribList)) {
+ ALOGE("error invalid colorspace: %d", colorSpace);
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+ attrib_list = strippedAttribList.data();
+
+ EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
+ dp->disp.dpy, config, pixmap, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s =
+ new egl_surface_t(dp.get(), config, nullptr, surface,
+ getReportedColorSpace(colorSpace), cnx);
+ return s;
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_connection_t* cnx = nullptr;
+ egl_display_ptr dp = validate_display_connection(dpy, cnx);
+ if (dp) {
+ EGLDisplay iDpy = dp->disp.dpy;
+ android_pixel_format format;
+ getNativePixelFormat(iDpy, cnx, config, &format);
+
+ // Select correct colorspace based on user's attribute list
+ EGLint colorSpace = EGL_UNKNOWN;
+ std::vector<EGLint> strippedAttribList;
+ if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
+ &strippedAttribList)) {
+ ALOGE("error invalid colorspace: %d", colorSpace);
+ return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+ attrib_list = strippedAttribList.data();
+
+ EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
+ dp->disp.dpy, config, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s =
+ new egl_surface_t(dp.get(), config, nullptr, surface,
+ getReportedColorSpace(colorSpace), cnx);
+ return s;
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+
+ egl_surface_t * const s = get_surface(surface);
+ EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
+ if (result == EGL_TRUE) {
+ _s.terminate();
+ }
+ return result;
+}
+
+EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint *value)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->getColorSpaceAttribute(attribute, value)) {
+ return EGL_TRUE;
+ } else if (s->getSmpte2086Attribute(attribute, value)) {
+ return EGL_TRUE;
+ } else if (s->getCta8613Attribute(attribute, value)) {
+ return EGL_TRUE;
+ }
+ return s->cnx->egl.eglQuerySurface(dp->disp.dpy, s->surface, attribute, value);
}
void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
ATRACE_CALL();
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- cnx->platform.eglBeginFrame(dpy, surface);
-}
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return;
+ }
-EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list,
- const EGLint* attrib_list) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCreateContext(dpy, config, share_list, attrib_list);
-}
-
-EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglDestroyContext(dpy, ctx);
-}
-
-EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglMakeCurrent(dpy, draw, read, ctx);
-}
-
-EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglQueryContext(dpy, ctx, attribute, value);
-}
-
-EGLContext eglGetCurrentContext(void) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetCurrentContext();
-}
-
-EGLSurface eglGetCurrentSurface(EGLint readdraw) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetCurrentSurface(readdraw);
-}
-
-EGLDisplay eglGetCurrentDisplay(void) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetCurrentDisplay();
-}
-
-EGLBoolean eglWaitGL(void) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglWaitGL();
-}
-
-EGLBoolean eglWaitNative(EGLint engine) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglWaitNative(engine);
-}
-
-EGLint eglGetError(void) {
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->platform.eglGetError) {
- return cnx->platform.eglGetError();
- } else {
- return egl_tls_t::getError();
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
}
}
-__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char* procname) {
+// ----------------------------------------------------------------------------
+// Contexts
+// ----------------------------------------------------------------------------
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_list, const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_connection_t* cnx = nullptr;
+ const egl_display_ptr dp = validate_display_connection(dpy, cnx);
+ if (dp) {
+ if (share_list != EGL_NO_CONTEXT) {
+ if (!ContextRef(dp.get(), share_list).get()) {
+ return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
+ }
+ egl_context_t* const c = get_context(share_list);
+ share_list = c->context;
+ }
+ EGLContext context = cnx->egl.eglCreateContext(
+ dp->disp.dpy, config, share_list, attrib_list);
+ if (context != EGL_NO_CONTEXT) {
+ // figure out if it's a GLESv1 or GLESv2
+ int version = 0;
+ if (attrib_list) {
+ while (*attrib_list != EGL_NONE) {
+ GLint attr = *attrib_list++;
+ GLint value = *attrib_list++;
+ if (attr == EGL_CONTEXT_CLIENT_VERSION) {
+ if (value == 1) {
+ version = egl_connection_t::GLESv1_INDEX;
+ } else if (value == 2 || value == 3) {
+ version = egl_connection_t::GLESv2_INDEX;
+ }
+ }
+ };
+ }
+ egl_context_t* c = new egl_context_t(dpy, context, config, cnx,
+ version);
+ return c;
+ }
+ }
+ return EGL_NO_CONTEXT;
+}
+
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp)
+ return EGL_FALSE;
+
+ ContextRef _c(dp.get(), ctx);
+ if (!_c.get())
+ return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
+
+ egl_context_t * const c = get_context(ctx);
+ EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context);
+ if (result == EGL_TRUE) {
+ _c.terminate();
+ }
+ return result;
+}
+
+EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx)
+{
+ clearError();
+
+ egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+
+ // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
+ // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
+ // a valid but uninitialized display.
+ if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
+ (draw != EGL_NO_SURFACE) ) {
+ if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
+ }
+
+ // get a reference to the object passed in
+ ContextRef _c(dp.get(), ctx);
+ SurfaceRef _d(dp.get(), draw);
+ SurfaceRef _r(dp.get(), read);
+
+ // validate the context (if not EGL_NO_CONTEXT)
+ if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
+ // EGL_NO_CONTEXT is valid
+ return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
+ }
+
+ // these are the underlying implementation's object
+ EGLContext impl_ctx = EGL_NO_CONTEXT;
+ EGLSurface impl_draw = EGL_NO_SURFACE;
+ EGLSurface impl_read = EGL_NO_SURFACE;
+
+ // these are our objects structs passed in
+ egl_context_t * c = nullptr;
+ egl_surface_t const * d = nullptr;
+ egl_surface_t const * r = nullptr;
+
+ // these are the current objects structs
+ egl_context_t * cur_c = get_context(getContext());
+
+ if (ctx != EGL_NO_CONTEXT) {
+ c = get_context(ctx);
+ impl_ctx = c->context;
+ } else {
+ // no context given, use the implementation of the current context
+ if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
+ // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
+ return setError(EGL_BAD_MATCH, (EGLBoolean)EGL_FALSE);
+ }
+ if (cur_c == nullptr) {
+ // no current context
+ // not an error, there is just no current context.
+ return EGL_TRUE;
+ }
+ }
+
+ // retrieve the underlying implementation's draw EGLSurface
+ if (draw != EGL_NO_SURFACE) {
+ if (!_d.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ d = get_surface(draw);
+ impl_draw = d->surface;
+ }
+
+ // retrieve the underlying implementation's read EGLSurface
+ if (read != EGL_NO_SURFACE) {
+ if (!_r.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ r = get_surface(read);
+ impl_read = r->surface;
+ }
+
+
+ EGLBoolean result = dp->makeCurrent(c, cur_c,
+ draw, read, ctx,
+ impl_draw, impl_read, impl_ctx);
+
+ if (result == EGL_TRUE) {
+ if (c) {
+ setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
+ egl_tls_t::setContext(ctx);
+ _c.acquire();
+ _r.acquire();
+ _d.acquire();
+ } else {
+ setGLHooksThreadSpecific(&gHooksNoContext);
+ egl_tls_t::setContext(EGL_NO_CONTEXT);
+ }
+ } else {
+ // this will ALOGE the error
+ egl_connection_t* const cnx = &gEGLImpl;
+ result = setError(cnx->egl.eglGetError(), (EGLBoolean)EGL_FALSE);
+ }
+ return result;
+}
+
+
+EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
+ EGLint attribute, EGLint *value)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ ContextRef _c(dp.get(), ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
+
+ egl_context_t * const c = get_context(ctx);
+ return c->cnx->egl.eglQueryContext(
+ dp->disp.dpy, c->context, attribute, value);
+
+}
+
+EGLContext eglGetCurrentContext(void)
+{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_CONTEXT.
+
+ clearError();
+
+ EGLContext ctx = getContext();
+ return ctx;
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw)
+{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_SURFACE.
+
+ clearError();
+
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
+ switch (readdraw) {
+ case EGL_READ: return c->read;
+ case EGL_DRAW: return c->draw;
+ default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLDisplay eglGetCurrentDisplay(void)
+{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_DISPLAY.
+
+ clearError();
+
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
+ return c->dpy;
+ }
+ return EGL_NO_DISPLAY;
+}
+
+EGLBoolean eglWaitGL(void)
+{
+ clearError();
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
+
+ return cnx->egl.eglWaitGL();
+}
+
+EGLBoolean eglWaitNative(EGLint engine)
+{
+ clearError();
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
+
+ return cnx->egl.eglWaitNative(engine);
+}
+
+EGLint eglGetError(void)
+{
+ EGLint err = EGL_SUCCESS;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso) {
+ err = cnx->egl.eglGetError();
+ }
+ if (err == EGL_SUCCESS) {
+ err = egl_tls_t::getError();
+ }
+ return err;
+}
+
+static __eglMustCastToProperFunctionPointerType findBuiltinWrapper(
+ const char* procname) {
+ const egl_connection_t* cnx = &gEGLImpl;
+ void* proc = nullptr;
+
+ proc = dlsym(cnx->libEgl, procname);
+ if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
+
+ proc = dlsym(cnx->libGles2, procname);
+ if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
+
+ proc = dlsym(cnx->libGles1, procname);
+ if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
+
+ return nullptr;
+}
+
+__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
+{
// eglGetProcAddress() could be the very first function called
// in which case we must make sure we've initialized ourselves, this
// happens the first time egl_get_display() is called.
@@ -216,87 +1203,436 @@
if (egl_init_drivers() == EGL_FALSE) {
setError(EGL_BAD_PARAMETER, NULL);
+ return nullptr;
+ }
+
+ if (FILTER_EXTENSIONS(procname)) {
return nullptr;
}
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetProcAddress(procname);
+ __eglMustCastToProperFunctionPointerType addr;
+ addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap));
+ if (addr) return addr;
+
+ addr = findBuiltinWrapper(procname);
+ if (addr) return addr;
+
+ // this protects accesses to sGLExtentionMap and sGLExtentionSlot
+ pthread_mutex_lock(&sExtensionMapMutex);
+
+ /*
+ * Since eglGetProcAddress() is not associated to anything, it needs
+ * to return a function pointer that "works" regardless of what
+ * the current context is.
+ *
+ * For this reason, we return a "forwarder", a small stub that takes
+ * care of calling the function associated with the context
+ * currently bound.
+ *
+ * We first look for extensions we've already resolved, if we're seeing
+ * this extension for the first time, we go through all our
+ * implementations and call eglGetProcAddress() and record the
+ * result in the appropriate implementation hooks and return the
+ * address of the forwarder corresponding to that hook set.
+ *
+ */
+
+ const std::string name(procname);
+
+ auto& extentionMap = sGLExtentionMap;
+ auto pos = extentionMap.find(name);
+ addr = (pos != extentionMap.end()) ? pos->second : nullptr;
+ const int slot = sGLExtentionSlot;
+
+ ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
+ "no more slots for eglGetProcAddress(\"%s\")",
+ procname);
+
+ if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
+ bool found = false;
+
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglGetProcAddress) {
+ // Extensions are independent of the bound context
+ addr =
+ cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
+ cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
+ cnx->egl.eglGetProcAddress(procname);
+ if (addr) found = true;
+ }
+
+ if (found) {
+ addr = gExtensionForwarders[slot];
+ extentionMap[name] = addr;
+ sGLExtentionSlot++;
+ }
+ }
+
+ pthread_mutex_unlock(&sExtensionMapMutex);
+ return addr;
}
-EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, EGLint* rects,
- EGLint n_rects) {
+class FrameCompletionThread {
+public:
+
+ static void queueSync(EGLSyncKHR sync) {
+ static FrameCompletionThread thread;
+
+ char name[64];
+
+ std::lock_guard<std::mutex> lock(thread.mMutex);
+ snprintf(name, sizeof(name), "kicked off frame %u", (unsigned int)thread.mFramesQueued);
+ ATRACE_NAME(name);
+
+ thread.mQueue.push_back(sync);
+ thread.mCondition.notify_one();
+ thread.mFramesQueued++;
+ ATRACE_INT("GPU Frames Outstanding", int32_t(thread.mQueue.size()));
+ }
+
+private:
+
+ FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {
+ std::thread thread(&FrameCompletionThread::loop, this);
+ thread.detach();
+ }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
+ void loop() {
+ while (true) {
+ threadLoop();
+ }
+ }
+#pragma clang diagnostic pop
+
+ void threadLoop() {
+ EGLSyncKHR sync;
+ uint32_t frameNum;
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (mQueue.empty()) {
+ mCondition.wait(lock);
+ }
+ sync = mQueue[0];
+ frameNum = mFramesCompleted;
+ }
+ EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ {
+ char name[64];
+ snprintf(name, sizeof(name), "waiting for frame %u", (unsigned int)frameNum);
+ ATRACE_NAME(name);
+
+ EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);
+ if (result == EGL_FALSE) {
+ ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError());
+ } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ALOGE("FrameCompletion: timeout waiting for fence");
+ }
+ eglDestroySyncKHR(dpy, sync);
+ }
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mQueue.pop_front();
+ mFramesCompleted++;
+ ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size()));
+ }
+ }
+
+ uint32_t mFramesQueued;
+ uint32_t mFramesCompleted;
+ std::deque<EGLSyncKHR> mQueue;
+ std::condition_variable mCondition;
+ std::mutex mMutex;
+};
+
+EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw,
+ EGLint *rects, EGLint n_rects)
+{
ATRACE_CALL();
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglSwapBuffersWithDamageKHR(dpy, draw, rects, n_rects);
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(dp.get(), draw);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+
+ egl_surface_t* const s = get_surface(draw);
+
+ if (CC_UNLIKELY(dp->traceGpuCompletion)) {
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
+ if (sync != EGL_NO_SYNC_KHR) {
+ FrameCompletionThread::queueSync(sync);
+ }
+ }
+
+ if (CC_UNLIKELY(dp->finishOnSwap)) {
+ uint32_t pixel;
+ egl_context_t * const c = get_context( egl_tls_t::getContext() );
+ if (c) {
+ // glReadPixels() ensures that the frame is complete
+ s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1,
+ GL_RGBA,GL_UNSIGNED_BYTE,&pixel);
+ }
+ }
+
+ if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ if (!sendSurfaceMetadata(s)) {
+ native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL);
+ return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE);
+ }
+ }
+
+ if (n_rects == 0) {
+ return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
+ }
+
+ std::vector<android_native_rect_t> androidRects((size_t)n_rects);
+ for (int r = 0; r < n_rects; ++r) {
+ int offset = r * 4;
+ int x = rects[offset];
+ int y = rects[offset + 1];
+ int width = rects[offset + 2];
+ int height = rects[offset + 3];
+ android_native_rect_t androidRect;
+ androidRect.left = x;
+ androidRect.top = y + height;
+ androidRect.right = x + width;
+ androidRect.bottom = y;
+ androidRects.push_back(androidRect);
+ }
+ if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
+ native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(),
+ androidRects.size());
+ }
+
+ if (s->cnx->egl.eglSwapBuffersWithDamageKHR) {
+ return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface,
+ rects, n_rects);
+ } else {
+ return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
+ }
}
-EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
- ATRACE_CALL();
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
+{
+ return eglSwapBuffersWithDamageKHR(dpy, surface, nullptr, 0);
+}
+
+EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
+ NativePixmapType target)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
+}
+
+const char* eglQueryString(EGLDisplay dpy, EGLint name)
+{
+ clearError();
+
+ // Generate an error quietly when client extensions (as defined by
+ // EGL_EXT_client_extensions) are queried. We do not want to rely on
+ // validate_display to generate the error as validate_display would log
+ // the error, which can be misleading.
+ //
+ // If we want to support EGL_EXT_client_extensions later, we can return
+ // the client extension string here instead.
+ if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
+ return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)nullptr);
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return (const char *) nullptr;
+
+ switch (name) {
+ case EGL_VENDOR:
+ return dp->getVendorString();
+ case EGL_VERSION:
+ return dp->getVersionString();
+ case EGL_EXTENSIONS:
+ return dp->getExtensionString();
+ case EGL_CLIENT_APIS:
+ return dp->getClientApiString();
+ default:
+ break;
+ }
+ return setError(EGL_BAD_PARAMETER, (const char *)nullptr);
+}
+
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return (const char *) nullptr;
+
+ switch (name) {
+ case EGL_VENDOR:
+ return dp->disp.queryString.vendor;
+ case EGL_VERSION:
+ return dp->disp.queryString.version;
+ case EGL_EXTENSIONS:
+ return dp->disp.queryString.extensions;
+ case EGL_CLIENT_APIS:
+ return dp->disp.queryString.clientApi;
+ default:
+ break;
+ }
+ return setError(EGL_BAD_PARAMETER, (const char *)nullptr);
+}
+
+// ----------------------------------------------------------------------------
+// EGL 1.1
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSurfaceAttrib(
+ EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+
+ egl_surface_t * const s = get_surface(surface);
+
+ if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) {
+ if (!s->getNativeWindow()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+ int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0);
+ return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ if (attribute == EGL_TIMESTAMPS_ANDROID) {
+ if (!s->getNativeWindow()) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+ int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0);
+ return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ if (s->setSmpte2086Attribute(attribute, value)) {
+ return EGL_TRUE;
+ } else if (s->setCta8613Attribute(attribute, value)) {
+ return EGL_TRUE;
+ } else if (s->cnx->egl.eglSurfaceAttrib) {
+ return s->cnx->egl.eglSurfaceAttrib(
+ dp->disp.dpy, s->surface, attribute, value);
+ }
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+}
+
+EGLBoolean eglBindTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglBindTexImage) {
+ return s->cnx->egl.eglBindTexImage(
+ dp->disp.dpy, s->surface, buffer);
+ }
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+}
+
+EGLBoolean eglReleaseTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglReleaseTexImage) {
+ return s->cnx->egl.eglReleaseTexImage(
+ dp->disp.dpy, s->surface, buffer);
+ }
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean res = EGL_TRUE;
+ egl_connection_t* const cnx = &gEGLImpl;
+ if (cnx->dso && cnx->egl.eglSwapInterval) {
+ res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
+ }
+
+ return res;
+}
+
+
+// ----------------------------------------------------------------------------
+// EGL 1.2
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglWaitClient(void)
+{
clearError();
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglSwapBuffers(dpy, surface);
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
+
+ EGLBoolean res;
+ if (cnx->egl.eglWaitClient) {
+ res = cnx->egl.eglWaitClient();
+ } else {
+ res = cnx->egl.eglWaitGL();
+ }
+ return res;
}
-EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, NativePixmapType target) {
+EGLBoolean eglBindAPI(EGLenum api)
+{
clearError();
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
+ }
+
+ // bind this API on all EGLs
+ EGLBoolean res = EGL_TRUE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCopyBuffers(dpy, surface, target);
+ if (cnx->dso && cnx->egl.eglBindAPI) {
+ res = cnx->egl.eglBindAPI(api);
+ }
+ return res;
}
-const char* eglQueryString(EGLDisplay dpy, EGLint name) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglQueryString(dpy, name);
-}
-
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglQueryStringImplementationANDROID(dpy, name);
-}
-
-EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglSurfaceAttrib(dpy, surface, attribute, value);
-}
-
-EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglBindTexImage(dpy, surface, buffer);
-}
-
-EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglReleaseTexImage(dpy, surface, buffer);
-}
-
-EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglSwapInterval(dpy, interval);
-}
-
-EGLBoolean eglWaitClient(void) {
- clearError();
-
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglWaitClient();
-}
-
-EGLBoolean eglBindAPI(EGLenum api) {
+EGLenum eglQueryAPI(void)
+{
clearError();
if (egl_init_drivers() == EGL_FALSE) {
@@ -304,282 +1640,806 @@
}
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglBindAPI(api);
-}
-
-EGLenum eglQueryAPI(void) {
- clearError();
-
- if (egl_init_drivers() == EGL_FALSE) {
- return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
+ if (cnx->dso && cnx->egl.eglQueryAPI) {
+ return cnx->egl.eglQueryAPI();
}
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglQueryAPI();
+ // or, it can only be OpenGL ES
+ return EGL_OPENGL_ES_API;
}
-EGLBoolean eglReleaseThread(void) {
+EGLBoolean eglReleaseThread(void)
+{
clearError();
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglReleaseThread();
+ if (cnx->dso && cnx->egl.eglReleaseThread) {
+ cnx->egl.eglReleaseThread();
+ }
+
+ // If there is context bound to the thread, release it
+ egl_display_t::loseCurrent(get_context(getContext()));
+
+ egl_tls_t::clearTLS();
+ return EGL_TRUE;
}
-EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
- EGLConfig config, const EGLint* attrib_list) {
+EGLSurface eglCreatePbufferFromClientBuffer(
+ EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+ EGLConfig config, const EGLint *attrib_list)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCreatePbufferFromClientBuffer(dpy, buftype, buffer, config,
- attrib_list);
+ egl_connection_t* cnx = nullptr;
+ const egl_display_ptr dp = validate_display_connection(dpy, cnx);
+ if (!dp) return EGL_FALSE;
+ if (cnx->egl.eglCreatePbufferFromClientBuffer) {
+ return cnx->egl.eglCreatePbufferFromClientBuffer(
+ dp->disp.dpy, buftype, buffer, config, attrib_list);
+ }
+ return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
}
-EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, const EGLint* attrib_list) {
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 3
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
+ const EGLint *attrib_list)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglLockSurfaceKHR(dpy, surface, attrib_list);
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglLockSurfaceKHR) {
+ return s->cnx->egl.eglLockSurfaceKHR(
+ dp->disp.dpy, s->surface, attrib_list);
+ }
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
-EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) {
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglUnlockSurfaceKHR(dpy, surface);
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglUnlockSurfaceKHR) {
+ return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
+ }
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
}
EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
- EGLClientBuffer buffer, const EGLint* attrib_list) {
+ EGLClientBuffer buffer, const EGLint *attrib_list)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_IMAGE_KHR;
+
+ ContextRef _c(dp.get(), ctx);
+ egl_context_t * const c = _c.get();
+
+ EGLImageKHR result = EGL_NO_IMAGE_KHR;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list);
+ if (cnx->dso && cnx->egl.eglCreateImageKHR) {
+ result = cnx->egl.eglCreateImageKHR(
+ dp->disp.dpy,
+ c ? c->context : EGL_NO_CONTEXT,
+ target, buffer, attrib_list);
+ }
+ return result;
}
-EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) {
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglDestroyImageKHR(dpy, img);
+ if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
+ result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img);
+ }
+ return result;
}
-EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list) {
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 5
+// ----------------------------------------------------------------------------
+
+
+EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_SYNC_KHR;
+
+ EGLSyncKHR result = EGL_NO_SYNC_KHR;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCreateSyncKHR(dpy, type, attrib_list);
+ if (cnx->dso && cnx->egl.eglCreateSyncKHR) {
+ result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list);
+ }
+ return result;
}
-EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) {
+EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglDestroySyncKHR(dpy, sync);
+ if (cnx->dso && cnx->egl.eglDestroySyncKHR) {
+ result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync);
+ }
+ return result;
}
EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglSignalSyncKHR(dpy, sync, mode);
+ if (cnx->dso && cnx->egl.eglSignalSyncKHR) {
+ result = cnx->egl.eglSignalSyncKHR(
+ dp->disp.dpy, sync, mode);
+ }
+ return result;
}
-EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) {
+EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync,
+ EGLint flags, EGLTimeKHR timeout)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLint result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglClientWaitSyncKHR(dpy, sync, flags, timeout);
+ if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
+ result = cnx->egl.eglClientWaitSyncKHR(
+ dp->disp.dpy, sync, flags, timeout);
+ }
+ return result;
}
-EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint* value) {
+EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
+ EGLint attribute, EGLint *value)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetSyncAttribKHR(dpy, sync, attribute, value);
+ if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) {
+ result = cnx->egl.eglGetSyncAttribKHR(
+ dp->disp.dpy, sync, attribute, value);
+ }
+ return result;
}
-EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint* attrib_list) {
+EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_STREAM_KHR;
+
+ EGLStreamKHR result = EGL_NO_STREAM_KHR;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCreateStreamKHR(dpy, attrib_list);
+ if (cnx->dso && cnx->egl.eglCreateStreamKHR) {
+ result = cnx->egl.eglCreateStreamKHR(
+ dp->disp.dpy, attrib_list);
+ }
+ return result;
}
-EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) {
+EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglDestroyStreamKHR(dpy, stream);
+ if (cnx->dso && cnx->egl.eglDestroyStreamKHR) {
+ result = cnx->egl.eglDestroyStreamKHR(
+ dp->disp.dpy, stream);
+ }
+ return result;
}
-EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute,
- EGLint value) {
+EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream,
+ EGLenum attribute, EGLint value)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglStreamAttribKHR(dpy, stream, attribute, value);
+ if (cnx->dso && cnx->egl.eglStreamAttribKHR) {
+ result = cnx->egl.eglStreamAttribKHR(
+ dp->disp.dpy, stream, attribute, value);
+ }
+ return result;
}
-EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute,
- EGLint* value) {
+EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream,
+ EGLenum attribute, EGLint *value)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglQueryStreamKHR(dpy, stream, attribute, value);
+ if (cnx->dso && cnx->egl.eglQueryStreamKHR) {
+ result = cnx->egl.eglQueryStreamKHR(
+ dp->disp.dpy, stream, attribute, value);
+ }
+ return result;
}
-EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute,
- EGLuint64KHR* value) {
+EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream,
+ EGLenum attribute, EGLuint64KHR *value)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglQueryStreamu64KHR(dpy, stream, attribute, value);
+ if (cnx->dso && cnx->egl.eglQueryStreamu64KHR) {
+ result = cnx->egl.eglQueryStreamu64KHR(
+ dp->disp.dpy, stream, attribute, value);
+ }
+ return result;
}
-EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute,
- EGLTimeKHR* value) {
+EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream,
+ EGLenum attribute, EGLTimeKHR *value)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglQueryStreamTimeKHR(dpy, stream, attribute, value);
+ if (cnx->dso && cnx->egl.eglQueryStreamTimeKHR) {
+ result = cnx->egl.eglQueryStreamTimeKHR(
+ dp->disp.dpy, stream, attribute, value);
+ }
+ return result;
}
-EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream,
- const EGLint* attrib_list) {
+EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config,
+ EGLStreamKHR stream, const EGLint *attrib_list)
+{
clearError();
+ egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_SURFACE;
+
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCreateStreamProducerSurfaceKHR(dpy, config, stream, attrib_list);
+ if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) {
+ EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR(
+ dp->disp.dpy, config, stream, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s = new egl_surface_t(dp.get(), config, nullptr, surface,
+ EGL_GL_COLORSPACE_LINEAR_KHR, cnx);
+ return s;
+ }
+ }
+ return EGL_NO_SURFACE;
}
-EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) {
+EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy,
+ EGLStreamKHR stream)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglStreamConsumerGLTextureExternalKHR(dpy, stream);
+ if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) {
+ result = cnx->egl.eglStreamConsumerGLTextureExternalKHR(
+ dp->disp.dpy, stream);
+ }
+ return result;
}
-EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) {
+EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy,
+ EGLStreamKHR stream)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglStreamConsumerAcquireKHR(dpy, stream);
+ if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) {
+ result = cnx->egl.eglStreamConsumerAcquireKHR(
+ dp->disp.dpy, stream);
+ }
+ return result;
}
-EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) {
+EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy,
+ EGLStreamKHR stream)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglStreamConsumerReleaseKHR(dpy, stream);
+ if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) {
+ result = cnx->egl.eglStreamConsumerReleaseKHR(
+ dp->disp.dpy, stream);
+ }
+ return result;
}
-EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR(EGLDisplay dpy, EGLStreamKHR stream) {
+EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR(
+ EGLDisplay dpy, EGLStreamKHR stream)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR;
+
+ EGLNativeFileDescriptorKHR result = EGL_NO_FILE_DESCRIPTOR_KHR;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetStreamFileDescriptorKHR(dpy, stream);
+ if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) {
+ result = cnx->egl.eglGetStreamFileDescriptorKHR(
+ dp->disp.dpy, stream);
+ }
+ return result;
}
-EGLStreamKHR eglCreateStreamFromFileDescriptorKHR(EGLDisplay dpy,
- EGLNativeFileDescriptorKHR file_descriptor) {
+EGLStreamKHR eglCreateStreamFromFileDescriptorKHR(
+ EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_STREAM_KHR;
+
+ EGLStreamKHR result = EGL_NO_STREAM_KHR;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglCreateStreamFromFileDescriptorKHR(dpy, file_descriptor);
+ if (cnx->dso && cnx->egl.eglCreateStreamFromFileDescriptorKHR) {
+ result = cnx->egl.eglCreateStreamFromFileDescriptorKHR(
+ dp->disp.dpy, file_descriptor);
+ }
+ return result;
}
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 15
+// ----------------------------------------------------------------------------
+
EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) {
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+ EGLint result = EGL_FALSE;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglWaitSyncKHR(dpy, sync, flags);
+ if (cnx->dso && cnx->egl.eglWaitSyncKHR) {
+ result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags);
+ }
+ return result;
}
-EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) {
+// ----------------------------------------------------------------------------
+// ANDROID extensions
+// ----------------------------------------------------------------------------
+
+EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync)
+{
clearError();
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
+
+ EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglDupNativeFenceFDANDROID(dpy, sync);
+ if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) {
+ result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync);
+ }
+ return result;
}
-EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time) {
+EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLnsecsANDROID time)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglPresentationTimeANDROID(dpy, surface, time);
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return EGL_FALSE;
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return EGL_FALSE;
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+ native_window_set_buffers_timestamp(s->getNativeWindow(), time);
+
+ return EGL_TRUE;
}
-EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer* buffer) {
+EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) {
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetNativeClientBufferANDROID(buffer);
+ // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus
+ // this function cannot be implemented when this libEGL is built for
+ // vendors.
+#ifndef __ANDROID_VNDK__
+ if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr);
+ return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
+#else
+ return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr);
+#endif
}
-EGLuint64NV eglGetSystemTimeFrequencyNV() {
+// ----------------------------------------------------------------------------
+// NVIDIA extensions
+// ----------------------------------------------------------------------------
+EGLuint64NV eglGetSystemTimeFrequencyNV()
+{
clearError();
if (egl_init_drivers() == EGL_FALSE) {
return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE);
}
+ EGLuint64NV ret = 0;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetSystemTimeFrequencyNV();
+
+ if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
+ return cnx->egl.eglGetSystemTimeFrequencyNV();
+ }
+
+ return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0);
}
-EGLuint64NV eglGetSystemTimeNV() {
+EGLuint64NV eglGetSystemTimeNV()
+{
clearError();
if (egl_init_drivers() == EGL_FALSE) {
return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE);
}
+ EGLuint64NV ret = 0;
egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetSystemTimeNV();
+
+ if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
+ return cnx->egl.eglGetSystemTimeNV();
+ }
+
+ return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0);
}
-EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, EGLint* rects,
- EGLint n_rects) {
+// ----------------------------------------------------------------------------
+// Partial update extension
+// ----------------------------------------------------------------------------
+EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface,
+ EGLint *rects, EGLint n_rects)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglSetDamageRegionKHR(dpy, surface, rects, n_rects);
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ return EGL_FALSE;
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return EGL_FALSE;
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglSetDamageRegionKHR) {
+ return s->cnx->egl.eglSetDamageRegionKHR(dp->disp.dpy, s->surface,
+ rects, n_rects);
+ }
+
+ return EGL_FALSE;
}
-EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR* frameId) {
+EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLuint64KHR *frameId) {
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetNextFrameIdANDROID(dpy, surface, frameId);
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+
+ if (!s->getNativeWindow()) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ uint64_t nextFrameId = 0;
+ int ret = native_window_get_next_frame_id(s->getNativeWindow(), &nextFrameId);
+
+ if (ret != 0) {
+ // This should not happen. Return an error that is not in the spec
+ // so it's obvious something is very wrong.
+ ALOGE("eglGetNextFrameId: Unexpected error.");
+ return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
+ }
+
+ *frameId = nextFrameId;
+ return EGL_TRUE;
}
-EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps,
- const EGLint* names, EGLnsecsANDROID* values) {
+EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetCompositorTimingANDROID(dpy, surface, numTimestamps, names, values);
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+
+ if (!s->getNativeWindow()) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ nsecs_t* compositeDeadline = nullptr;
+ nsecs_t* compositeInterval = nullptr;
+ nsecs_t* compositeToPresentLatency = nullptr;
+
+ for (int i = 0; i < numTimestamps; i++) {
+ switch (names[i]) {
+ case EGL_COMPOSITE_DEADLINE_ANDROID:
+ compositeDeadline = &values[i];
+ break;
+ case EGL_COMPOSITE_INTERVAL_ANDROID:
+ compositeInterval = &values[i];
+ break;
+ case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
+ compositeToPresentLatency = &values[i];
+ break;
+ default:
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
+ }
+ }
+
+ int ret = native_window_get_compositor_timing(s->getNativeWindow(),
+ compositeDeadline, compositeInterval, compositeToPresentLatency);
+
+ switch (ret) {
+ case 0:
+ return EGL_TRUE;
+ case -ENOSYS:
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ default:
+ // This should not happen. Return an error that is not in the spec
+ // so it's obvious something is very wrong.
+ ALOGE("eglGetCompositorTiming: Unexpected error.");
+ return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
+ }
}
-EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint name) {
+EGLBoolean eglGetCompositorTimingSupportedANDROID(
+ EGLDisplay dpy, EGLSurface surface, EGLint name)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetCompositorTimingSupportedANDROID(dpy, surface, name);
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+
+ ANativeWindow* window = s->getNativeWindow();
+ if (!window) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ switch (name) {
+ case EGL_COMPOSITE_DEADLINE_ANDROID:
+ case EGL_COMPOSITE_INTERVAL_ANDROID:
+ case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
+ return EGL_TRUE;
+ default:
+ return EGL_FALSE;
+ }
}
-EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId,
- EGLint numTimestamps, const EGLint* timestamps,
- EGLnsecsANDROID* values) {
+EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
+ EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps,
+ EGLnsecsANDROID *values)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetFrameTimestampsANDROID(dpy, surface, frameId, numTimestamps,
- timestamps, values);
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+
+ if (!s->getNativeWindow()) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ nsecs_t* requestedPresentTime = nullptr;
+ nsecs_t* acquireTime = nullptr;
+ nsecs_t* latchTime = nullptr;
+ nsecs_t* firstRefreshStartTime = nullptr;
+ nsecs_t* gpuCompositionDoneTime = nullptr;
+ nsecs_t* lastRefreshStartTime = nullptr;
+ nsecs_t* displayPresentTime = nullptr;
+ nsecs_t* dequeueReadyTime = nullptr;
+ nsecs_t* releaseTime = nullptr;
+
+ for (int i = 0; i < numTimestamps; i++) {
+ switch (timestamps[i]) {
+ case EGL_REQUESTED_PRESENT_TIME_ANDROID:
+ requestedPresentTime = &values[i];
+ break;
+ case EGL_RENDERING_COMPLETE_TIME_ANDROID:
+ acquireTime = &values[i];
+ break;
+ case EGL_COMPOSITION_LATCH_TIME_ANDROID:
+ latchTime = &values[i];
+ break;
+ case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
+ firstRefreshStartTime = &values[i];
+ break;
+ case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
+ lastRefreshStartTime = &values[i];
+ break;
+ case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID:
+ gpuCompositionDoneTime = &values[i];
+ break;
+ case EGL_DISPLAY_PRESENT_TIME_ANDROID:
+ displayPresentTime = &values[i];
+ break;
+ case EGL_DEQUEUE_READY_TIME_ANDROID:
+ dequeueReadyTime = &values[i];
+ break;
+ case EGL_READS_DONE_TIME_ANDROID:
+ releaseTime = &values[i];
+ break;
+ default:
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
+ }
+ }
+
+ int ret = native_window_get_frame_timestamps(s->getNativeWindow(), frameId,
+ requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
+ lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime,
+ dequeueReadyTime, releaseTime);
+
+ switch (ret) {
+ case 0:
+ return EGL_TRUE;
+ case -ENOENT:
+ return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
+ case -ENOSYS:
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ case -EINVAL:
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
+ default:
+ // This should not happen. Return an error that is not in the spec
+ // so it's obvious something is very wrong.
+ ALOGE("eglGetFrameTimestamps: Unexpected error.");
+ return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
+ }
}
-EGLBoolean eglGetFrameTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface,
- EGLint timestamp) {
+EGLBoolean eglGetFrameTimestampSupportedANDROID(
+ EGLDisplay dpy, EGLSurface surface, EGLint timestamp)
+{
clearError();
- egl_connection_t* const cnx = &gEGLImpl;
- return cnx->platform.eglGetFrameTimestampSupportedANDROID(dpy, surface, timestamp);
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+
+ ANativeWindow* window = s->getNativeWindow();
+ if (!window) {
+ return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ }
+
+ switch (timestamp) {
+ case EGL_COMPOSITE_DEADLINE_ANDROID:
+ case EGL_COMPOSITE_INTERVAL_ANDROID:
+ case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
+ case EGL_REQUESTED_PRESENT_TIME_ANDROID:
+ case EGL_RENDERING_COMPLETE_TIME_ANDROID:
+ case EGL_COMPOSITION_LATCH_TIME_ANDROID:
+ case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
+ case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
+ case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID:
+ case EGL_DEQUEUE_READY_TIME_ANDROID:
+ case EGL_READS_DONE_TIME_ANDROID:
+ return EGL_TRUE;
+ case EGL_DISPLAY_PRESENT_TIME_ANDROID: {
+ int value = 0;
+ window->query(window,
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value);
+ return value == 0 ? EGL_FALSE : EGL_TRUE;
+ }
+ default:
+ return EGL_FALSE;
+ }
}
diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp
deleted file mode 100644
index 6900b8b..0000000
--- a/opengl/libs/EGL/egl_layers.cpp
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- ** Copyright 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 "egl_layers.h"
-
-#include <EGL/egl.h>
-#include <android-base/file.h>
-#include <android-base/strings.h>
-#include <android/dlext.h>
-#include <cutils/properties.h>
-#include <dlfcn.h>
-#include <graphicsenv/GraphicsEnv.h>
-#include <log/log.h>
-#include <nativebridge/native_bridge.h>
-#include <nativeloader/native_loader.h>
-#include <sys/prctl.h>
-
-namespace android {
-
-// GLES Layers
-//
-// - Layer discovery -
-// 1. Check for debug layer list from GraphicsEnv
-// 2. If none enabled, check system properties
-//
-// - Layer initializing -
-// TODO: ADD DETAIL ABOUT NEW INTERFACES
-// - InitializeLayer (provided by layer, called by loader)
-// - GetLayerProcAddress (provided by layer, called by loader)
-// - getNextLayerProcAddress (provided by loader, called by layer)
-//
-// 1. Walk through defs for egl and each gl version
-// 2. Call GetLayerProcAddress passing the name and the target hook entry point
-// - This tells the layer the next point in the chain it should call
-// 3. Replace the hook with the layer's entry point
-// - All entryoints will be present, anything unsupported by the driver will
-// have gl_unimplemented
-//
-// - Extension layering -
-// Not all functions are known to Android, so libEGL handles extensions.
-// They are looked up by applications using eglGetProcAddress
-// Layers can look them up with getNextLayerProcAddress
-
-const int kFuncCount = sizeof(platform_impl_t) / sizeof(char*) + sizeof(egl_t) / sizeof(char*) +
- sizeof(gl_hooks_t) / sizeof(char*);
-
-typedef struct FunctionTable {
- EGLFuncPointer x[kFuncCount];
- EGLFuncPointer& operator[](int i) { return x[i]; }
-} FunctionTable;
-
-// TODO: Move these to class
-std::unordered_map<std::string, int> func_indices;
-// func_indices.reserve(kFuncCount);
-
-std::unordered_map<int, std::string> func_names;
-// func_names.reserve(kFuncCount);
-
-std::vector<FunctionTable> layer_functions;
-
-const void* getNextLayerProcAddress(void* layer_id, const char* name) {
- // Use layer_id to find funcs for layer below current
- // This is the same key provided in InitializeLayer
- auto next_layer_funcs = reinterpret_cast<FunctionTable*>(layer_id);
- EGLFuncPointer val;
-
- if (func_indices.find(name) == func_indices.end()) {
- // No entry for this function - it is an extension
- // call down the GPA chain directly to the impl
- ALOGV("getNextLayerProcAddress servicing %s", name);
-
- // Look up which GPA we should use
- int gpaIndex = func_indices["eglGetProcAddress"];
- EGLFuncPointer gpaNext = (*next_layer_funcs)[gpaIndex];
-
- ALOGV("Calling down the GPA chain (%llu) for %s", (unsigned long long)gpaNext, name);
-
- // Call it for the requested function
- typedef void* (*PFNEGLGETPROCADDRESSPROC)(const char*);
- PFNEGLGETPROCADDRESSPROC next = reinterpret_cast<PFNEGLGETPROCADDRESSPROC>(gpaNext);
-
- val = reinterpret_cast<EGLFuncPointer>(next(name));
- ALOGV("Got back %llu for %s", (unsigned long long)val, name);
-
- // We should store it now, but to do that, we need to move func_idx to the class so we can
- // increment it separately
- // TODO: Move func_idx to class and store the result of GPA
- return reinterpret_cast<void*>(val);
- }
-
- // int index = func_indices[name];
- // val = (*next_layer_funcs)[index];
- // return reinterpret_cast<void*>(val);
- return reinterpret_cast<void*>((*next_layer_funcs)[func_indices[name]]);
-}
-
-void SetupFuncMaps(FunctionTable& functions, char const* const* entries, EGLFuncPointer* curr,
- int& func_idx) {
- while (*entries) {
- const char* name = *entries;
-
- // Some names overlap, only fill with initial entry
- // This does mean that some indices will not be used
- if (func_indices.find(name) == func_indices.end()) {
- func_names[func_idx] = name;
- func_indices[name] = func_idx;
- }
-
- // Populate layer_functions once with initial value
- // These values will arrive in priority order, starting with platform entries
- if (functions[func_idx] == nullptr) {
- functions[func_idx] = *curr;
- }
-
- entries++;
- curr++;
- func_idx++;
- }
-}
-
-LayerLoader& LayerLoader::getInstance() {
- // This function is mutex protected in egl_init_drivers_locked and eglGetProcAddressImpl
- static LayerLoader layer_loader;
-
- if (!layer_loader.layers_loaded_) layer_loader.LoadLayers();
-
- return layer_loader;
-}
-
-const char kSystemLayerLibraryDir[] = "/data/local/debug/gles";
-
-std::string LayerLoader::GetDebugLayers() {
- // Layers can be specified at the Java level in GraphicsEnvironemnt
- // gpu_debug_layers = layer1:layer2:layerN
- std::string debug_layers = android_getDebugLayers();
-
- if (debug_layers.empty()) {
- // Only check system properties if Java settings are empty
- char prop[PROPERTY_VALUE_MAX];
- property_get("debug.gles.layers", prop, "");
- debug_layers = prop;
- }
-
- return debug_layers;
-}
-
-EGLFuncPointer LayerLoader::ApplyLayer(layer_setup_func layer_setup, const char* name,
- EGLFuncPointer next) {
- // Walk through our list of LayerSetup functions (they will already be in reverse order) to
- // build up a call chain from the driver
-
- EGLFuncPointer layer_entry = next;
-
- layer_entry = layer_setup(name, layer_entry);
-
- if (next != layer_entry) {
- ALOGV("We succeeded, replacing hook (%llu) with layer entry (%llu), for %s",
- (unsigned long long)next, (unsigned long long)layer_entry, name);
- }
-
- return layer_entry;
-}
-
-EGLFuncPointer LayerLoader::ApplyLayers(const char* name, EGLFuncPointer next) {
- if (!layers_loaded_ || layer_setup_.empty()) return next;
-
- ALOGV("ApplyLayers called for %s with next (%llu), current_layer_ (%i)", name,
- (unsigned long long)next, current_layer_);
-
- EGLFuncPointer val = next;
-
- // Only ApplyLayers for layers that have been setup, not all layers yet
- for (unsigned i = 0; i < current_layer_; i++) {
- ALOGV("ApplyLayers: Calling ApplyLayer with i = %i for %s with next (%llu)", i, name,
- (unsigned long long)next);
- val = ApplyLayer(layer_setup_[i], name, val);
- }
-
- ALOGV("ApplyLayers returning %llu for %s", (unsigned long long)val, name);
-
- return val;
-}
-
-void LayerLoader::LayerPlatformEntries(layer_setup_func layer_setup, EGLFuncPointer* curr,
- char const* const* entries) {
- while (*entries) {
- char const* name = *entries;
-
- EGLFuncPointer prev = *curr;
-
- // Pass the existing entry point into the layer, replace the call with return value
- *curr = ApplyLayer(layer_setup, name, *curr);
-
- if (prev != *curr) {
- ALOGV("LayerPlatformEntries: Replaced (%llu) with platform entry (%llu), for %s",
- (unsigned long long)prev, (unsigned long long)*curr, name);
- } else {
- ALOGV("LayerPlatformEntries: No change(%llu) for %s, which means layer did not "
- "intercept",
- (unsigned long long)prev, name);
- }
-
- curr++;
- entries++;
- }
-}
-
-void LayerLoader::LayerDriverEntries(layer_setup_func layer_setup, EGLFuncPointer* curr,
- char const* const* entries) {
- while (*entries) {
- char const* name = *entries;
- EGLFuncPointer prev = *curr;
-
- // Only apply layers to driver entries if not handled by the platform
- if (FindPlatformImplAddr(name) == nullptr) {
- // Pass the existing entry point into the layer, replace the call with return value
- *curr = ApplyLayer(layer_setup, name, *prev);
-
- if (prev != *curr) {
- ALOGV("LayerDriverEntries: Replaced (%llu) with platform entry (%llu), for %s",
- (unsigned long long)prev, (unsigned long long)*curr, name);
- }
-
- } else {
- ALOGV("LayerDriverEntries: Skipped (%llu) for %s", (unsigned long long)prev, name);
- }
-
- curr++;
- entries++;
- }
-}
-
-bool LayerLoader::Initialized() {
- return initialized_;
-}
-
-void LayerLoader::InitLayers(egl_connection_t* cnx) {
- if (!layers_loaded_) return;
-
- if (initialized_) return;
-
- if (layer_setup_.empty()) {
- initialized_ = true;
- return;
- }
-
- // Include the driver in layer_functions
- layer_functions.resize(layer_setup_.size() + 1);
-
- // Walk through the initial lists and create layer_functions[0]
- int func_idx = 0;
- char const* const* entries;
- EGLFuncPointer* curr;
-
- entries = platform_names;
- curr = reinterpret_cast<EGLFuncPointer*>(&cnx->platform);
- SetupFuncMaps(layer_functions[0], entries, curr, func_idx);
- ALOGV("InitLayers: func_idx after platform_names: %i", func_idx);
-
- entries = egl_names;
- curr = reinterpret_cast<EGLFuncPointer*>(&cnx->egl);
- SetupFuncMaps(layer_functions[0], entries, curr, func_idx);
- ALOGV("InitLayers: func_idx after egl_names: %i", func_idx);
-
- entries = gl_names;
- curr = reinterpret_cast<EGLFuncPointer*>(&cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl);
- SetupFuncMaps(layer_functions[0], entries, curr, func_idx);
- ALOGV("InitLayers: func_idx after gl_names: %i", func_idx);
-
- // Walk through each layer's entry points per API, starting just above the driver
- for (current_layer_ = 0; current_layer_ < layer_setup_.size(); current_layer_++) {
- // Init the layer with a key that points to layer just below it
- layer_init_[current_layer_](reinterpret_cast<void*>(&layer_functions[current_layer_]),
- reinterpret_cast<PFNEGLGETNEXTLAYERPROCADDRESSPROC>(
- getNextLayerProcAddress));
-
- // Check functions implemented by the platform
- func_idx = 0;
- entries = platform_names;
- curr = reinterpret_cast<EGLFuncPointer*>(&cnx->platform);
- LayerPlatformEntries(layer_setup_[current_layer_], curr, entries);
-
- // Populate next function table after layers have been applied
- SetupFuncMaps(layer_functions[current_layer_ + 1], entries, curr, func_idx);
-
- // EGL
- entries = egl_names;
- curr = reinterpret_cast<EGLFuncPointer*>(&cnx->egl);
- LayerDriverEntries(layer_setup_[current_layer_], curr, entries);
-
- // Populate next function table after layers have been applied
- SetupFuncMaps(layer_functions[current_layer_ + 1], entries, curr, func_idx);
-
- // GLES 2+
- // NOTE: We route calls to GLESv2 hooks, not GLESv1, so layering does not support GLES 1.x
- // If it were added in the future, a different layer initialization model would be needed,
- // that defers loading GLES entrypoints until after eglMakeCurrent, so two phase
- // initialization.
- entries = gl_names;
- curr = reinterpret_cast<EGLFuncPointer*>(&cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl);
- LayerDriverEntries(layer_setup_[current_layer_], curr, entries);
-
- // Populate next function table after layers have been applied
- SetupFuncMaps(layer_functions[current_layer_ + 1], entries, curr, func_idx);
- }
-
- // We only want to apply layers once
- initialized_ = true;
-}
-
-void LayerLoader::LoadLayers() {
- std::string debug_layers = GetDebugLayers();
-
- // If no layers are specified, we're done
- if (debug_layers.empty()) return;
-
- // Only enable the system search path for non-user builds
- std::string system_path;
- if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
- system_path = kSystemLayerLibraryDir;
- }
-
- ALOGI("Debug layer list: %s", debug_layers.c_str());
- std::vector<std::string> layers = android::base::Split(debug_layers, ":");
-
- // Load the layers in reverse order so we start with the driver's entrypoint and work our way up
- for (int32_t i = layers.size() - 1; i >= 0; i--) {
- // Check each layer path for the layer
- std::vector<std::string> paths = android::base::Split(android_getLayerPaths(), ":");
-
- if (!system_path.empty()) {
- // Prepend the system paths so they override other layers
- auto it = paths.begin();
- paths.insert(it, system_path);
- }
-
- bool layer_found = false;
- for (uint32_t j = 0; j < paths.size() && !layer_found; j++) {
- std::string layer;
-
- ALOGI("Searching %s for GLES layers", paths[j].c_str());
-
- // Realpath will return null for non-existent files
- android::base::Realpath(paths[j] + "/" + layers[i], &layer);
-
- if (!layer.empty()) {
- layer_found = true;
- ALOGI("GLES layer found: %s", layer.c_str());
-
- // Load the layer
- //
- // TODO: This code is common with Vulkan loader, refactor
- //
- // Libraries in the system layer library dir can't be loaded into
- // the application namespace. That causes compatibility problems, since
- // any symbol dependencies will be resolved by system libraries. They
- // can't safely use libc++_shared, for example. Which is one reason
- // (among several) we only allow them in non-user builds.
- void* handle = nullptr;
- auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
- if (app_namespace && !android::base::StartsWith(layer, kSystemLayerLibraryDir)) {
- bool native_bridge = false;
- std::string error_message;
- handle = OpenNativeLibrary(app_namespace, layer.c_str(), &native_bridge,
- &error_message);
- if (!handle) {
- ALOGE("Failed to load layer %s with error: %s", layer.c_str(),
- error_message.c_str());
- return;
- }
-
- } else {
- handle = dlopen(layer.c_str(), RTLD_NOW | RTLD_LOCAL);
- }
-
- if (handle) {
- ALOGV("Loaded layer handle (%llu) for layer %s", (unsigned long long)handle,
- layers[i].c_str());
- } else {
- // If the layer is found but can't be loaded, try setenforce 0
- const char* dlsym_error = dlerror();
- ALOGE("Failed to load layer %s with error: %s", layer.c_str(), dlsym_error);
- return;
- }
-
- // Find the layer's Initialize function
- std::string init_func = "InitializeLayer";
- ALOGV("Looking for entrypoint %s", init_func.c_str());
-
- layer_init_func LayerInit =
- reinterpret_cast<layer_init_func>(dlsym(handle, init_func.c_str()));
- if (LayerInit) {
- ALOGV("Found %s for layer %s", init_func.c_str(), layer.c_str());
- layer_init_.push_back(LayerInit);
- } else {
- ALOGE("Failed to dlsym %s for layer %s", init_func.c_str(), layer.c_str());
- return;
- }
-
- // Find the layer's setup function
- std::string setup_func = "GetLayerProcAddress";
- ALOGV("Looking for entrypoint %s", setup_func.c_str());
-
- layer_setup_func LayerSetup =
- reinterpret_cast<layer_setup_func>(dlsym(handle, setup_func.c_str()));
- if (LayerSetup) {
- ALOGV("Found %s for layer %s", setup_func.c_str(), layer.c_str());
- layer_setup_.push_back(LayerSetup);
- } else {
- ALOGE("Failed to dlsym %s for layer %s", setup_func.c_str(), layer.c_str());
- return;
- }
- }
- }
- }
- // Track this so we only attempt to load these once
- layers_loaded_ = true;
-}
-
-} // namespace android
diff --git a/opengl/libs/EGL/egl_layers.h b/opengl/libs/EGL/egl_layers.h
deleted file mode 100644
index e401b44..0000000
--- a/opengl/libs/EGL/egl_layers.h
+++ /dev/null
@@ -1,65 +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.
- */
-
-#ifndef ANDROID_EGL_LAYERS_H
-#define ANDROID_EGL_LAYERS_H
-
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include <EGL/egldefs.h>
-
-#include "egl_platform_entries.h"
-
-typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer;
-
-namespace android {
-
-class LayerLoader {
-public:
- static LayerLoader& getInstance();
- ~LayerLoader(){};
-
- typedef void* (*PFNEGLGETNEXTLAYERPROCADDRESSPROC)(void*, const char*);
- typedef EGLFuncPointer (*layer_init_func)(
- const void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address);
- typedef EGLFuncPointer (*layer_setup_func)(const char* name, EGLFuncPointer next);
-
- void LoadLayers();
- void InitLayers(egl_connection_t*);
- void LayerPlatformEntries(layer_setup_func layer_setup, EGLFuncPointer*, char const* const*);
- void LayerDriverEntries(layer_setup_func layer_setup, EGLFuncPointer*, char const* const*);
- bool Initialized();
- std::string GetDebugLayers();
-
- EGLFuncPointer GetGpaNext(unsigned i);
- EGLFuncPointer ApplyLayer(layer_setup_func layer_setup, const char* name, EGLFuncPointer next);
- EGLFuncPointer ApplyLayers(const char* name, EGLFuncPointer next);
-
- std::vector<layer_init_func> layer_init_;
- std::vector<layer_setup_func> layer_setup_;
-
-private:
- LayerLoader() : layers_loaded_(false), initialized_(false), current_layer_(0){};
- bool layers_loaded_;
- bool initialized_;
- unsigned current_layer_;
-};
-
-}; // namespace android
-
-#endif // ANDROID_EGL_LAYERS_H
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
deleted file mode 100644
index 0d69a65..0000000
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ /dev/null
@@ -1,2475 +0,0 @@
-/*
- ** Copyright 2007, 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.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "egl_platform_entries.h"
-
-#include <ctype.h>
-#include <dlfcn.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <hardware/gralloc1.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <EGL/eglext_angle.h>
-
-#include <android/hardware_buffer.h>
-#include <android-base/strings.h>
-#include <graphicsenv/GraphicsEnv.h>
-#include <private/android/AHardwareBufferHelpers.h>
-
-#include <cutils/compiler.h>
-#include <cutils/properties.h>
-#include <log/log.h>
-
-#include <condition_variable>
-#include <deque>
-#include <mutex>
-#include <unordered_map>
-#include <string>
-#include <thread>
-
-#include "../egl_impl.h"
-
-#include "egl_display.h"
-#include "egl_object.h"
-#include "egl_layers.h"
-#include "egl_tls.h"
-#include "egl_trace.h"
-
-using namespace android;
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-using nsecs_t = int64_t;
-
-struct extention_map_t {
- const char* name;
- __eglMustCastToProperFunctionPointerType address;
-};
-
-/*
- * This is the list of EGL extensions exposed to applications.
- *
- * Some of them (gBuiltinExtensionString) are implemented entirely in this EGL
- * wrapper and are always available.
- *
- * The rest (gExtensionString) depend on support in the EGL driver, and are
- * only available if the driver supports them. However, some of these must be
- * supported because they are used by the Android system itself; these are
- * listed as mandatory below and are required by the CDD. The system *assumes*
- * the mandatory extensions are present and may not function properly if some
- * are missing.
- *
- * NOTE: Both strings MUST have a single space as the last character.
- */
-
-extern char const * const gBuiltinExtensionString;
-extern char const * const gExtensionString;
-
-// clang-format off
-// Extensions implemented by the EGL wrapper.
-char const * const gBuiltinExtensionString =
- "EGL_KHR_get_all_proc_addresses "
- "EGL_ANDROID_presentation_time "
- "EGL_KHR_swap_buffers_with_damage "
- "EGL_ANDROID_get_native_client_buffer "
- "EGL_ANDROID_front_buffer_auto_refresh "
- "EGL_ANDROID_get_frame_timestamps "
- "EGL_EXT_surface_SMPTE2086_metadata "
- "EGL_EXT_surface_CTA861_3_metadata "
- ;
-
-// Whitelist of extensions exposed to applications if implemented in the vendor driver.
-char const * const gExtensionString =
- "EGL_KHR_image " // mandatory
- "EGL_KHR_image_base " // mandatory
- "EGL_EXT_image_gl_colorspace "
- "EGL_KHR_image_pixmap "
- "EGL_KHR_lock_surface "
- "EGL_KHR_gl_colorspace "
- "EGL_KHR_gl_texture_2D_image "
- "EGL_KHR_gl_texture_3D_image "
- "EGL_KHR_gl_texture_cubemap_image "
- "EGL_KHR_gl_renderbuffer_image "
- "EGL_KHR_reusable_sync "
- "EGL_KHR_fence_sync "
- "EGL_KHR_create_context "
- "EGL_KHR_config_attribs "
- "EGL_KHR_surfaceless_context "
- "EGL_KHR_stream "
- "EGL_KHR_stream_fifo "
- "EGL_KHR_stream_producer_eglsurface "
- "EGL_KHR_stream_consumer_gltexture "
- "EGL_KHR_stream_cross_process_fd "
- "EGL_EXT_create_context_robustness "
- "EGL_NV_system_time "
- "EGL_ANDROID_image_native_buffer " // mandatory
- "EGL_KHR_wait_sync " // strongly recommended
- "EGL_ANDROID_recordable " // mandatory
- "EGL_KHR_partial_update " // strongly recommended
- "EGL_EXT_pixel_format_float "
- "EGL_EXT_buffer_age " // strongly recommended with partial_update
- "EGL_KHR_create_context_no_error "
- "EGL_KHR_mutable_render_buffer "
- "EGL_EXT_yuv_surface "
- "EGL_EXT_protected_content "
- "EGL_IMG_context_priority "
- "EGL_KHR_no_config_context "
- ;
-// clang-format on
-
-// extensions not exposed to applications but used by the ANDROID system
-// "EGL_ANDROID_blob_cache " // strongly recommended
-// "EGL_IMG_hibernate_process " // optional
-// "EGL_ANDROID_native_fence_sync " // strongly recommended
-// "EGL_ANDROID_framebuffer_target " // mandatory for HWC 1.1
-
-/*
- * EGL Extensions entry-points exposed to 3rd party applications
- * (keep in sync with gExtensionString above)
- *
- */
-static const extention_map_t sExtensionMap[] = {
- // EGL_KHR_lock_surface
- { "eglLockSurfaceKHR",
- (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
- { "eglUnlockSurfaceKHR",
- (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
-
- // EGL_KHR_image, EGL_KHR_image_base
- { "eglCreateImageKHR",
- (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
- { "eglDestroyImageKHR",
- (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
-
- // EGL_KHR_reusable_sync, EGL_KHR_fence_sync
- { "eglCreateSyncKHR",
- (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR },
- { "eglDestroySyncKHR",
- (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR },
- { "eglClientWaitSyncKHR",
- (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR },
- { "eglSignalSyncKHR",
- (__eglMustCastToProperFunctionPointerType)&eglSignalSyncKHR },
- { "eglGetSyncAttribKHR",
- (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR },
-
- // EGL_NV_system_time
- { "eglGetSystemTimeFrequencyNV",
- (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV },
- { "eglGetSystemTimeNV",
- (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV },
-
- // EGL_KHR_wait_sync
- { "eglWaitSyncKHR",
- (__eglMustCastToProperFunctionPointerType)&eglWaitSyncKHR },
-
- // EGL_ANDROID_presentation_time
- { "eglPresentationTimeANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglPresentationTimeANDROID },
-
- // EGL_KHR_swap_buffers_with_damage
- { "eglSwapBuffersWithDamageKHR",
- (__eglMustCastToProperFunctionPointerType)&eglSwapBuffersWithDamageKHR },
-
- // EGL_ANDROID_get_native_client_buffer
- { "eglGetNativeClientBufferANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglGetNativeClientBufferANDROID },
-
- // EGL_KHR_partial_update
- { "eglSetDamageRegionKHR",
- (__eglMustCastToProperFunctionPointerType)&eglSetDamageRegionKHR },
-
- { "eglCreateStreamKHR",
- (__eglMustCastToProperFunctionPointerType)&eglCreateStreamKHR },
- { "eglDestroyStreamKHR",
- (__eglMustCastToProperFunctionPointerType)&eglDestroyStreamKHR },
- { "eglStreamAttribKHR",
- (__eglMustCastToProperFunctionPointerType)&eglStreamAttribKHR },
- { "eglQueryStreamKHR",
- (__eglMustCastToProperFunctionPointerType)&eglQueryStreamKHR },
- { "eglQueryStreamu64KHR",
- (__eglMustCastToProperFunctionPointerType)&eglQueryStreamu64KHR },
- { "eglQueryStreamTimeKHR",
- (__eglMustCastToProperFunctionPointerType)&eglQueryStreamTimeKHR },
- { "eglCreateStreamProducerSurfaceKHR",
- (__eglMustCastToProperFunctionPointerType)&eglCreateStreamProducerSurfaceKHR },
- { "eglStreamConsumerGLTextureExternalKHR",
- (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerGLTextureExternalKHR },
- { "eglStreamConsumerAcquireKHR",
- (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerAcquireKHR },
- { "eglStreamConsumerReleaseKHR",
- (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerReleaseKHR },
- { "eglGetStreamFileDescriptorKHR",
- (__eglMustCastToProperFunctionPointerType)&eglGetStreamFileDescriptorKHR },
- { "eglCreateStreamFromFileDescriptorKHR",
- (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR },
-
- // EGL_ANDROID_get_frame_timestamps
- { "eglGetNextFrameIdANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglGetNextFrameIdANDROID },
- { "eglGetCompositorTimingANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingANDROID },
- { "eglGetCompositorTimingSupportedANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingSupportedANDROID },
- { "eglGetFrameTimestampsANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampsANDROID },
- { "eglGetFrameTimestampSupportedANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampSupportedANDROID },
-
- // EGL_ANDROID_native_fence_sync
- { "eglDupNativeFenceFDANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglDupNativeFenceFDANDROID },
-};
-
-/*
- * These extensions entry-points should not be exposed to applications.
- * They're used internally by the Android EGL layer.
- */
-#define FILTER_EXTENSIONS(procname) \
- (!strcmp((procname), "eglSetBlobCacheFuncsANDROID") || \
- !strcmp((procname), "eglHibernateProcessIMG") || \
- !strcmp((procname), "eglAwakenProcessIMG"))
-
-// accesses protected by sExtensionMapMutex
-static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
-
-static int sGLExtentionSlot = 0;
-static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void(*findProcAddress(const char* name,
- const extention_map_t* map, size_t n))() {
- for (uint32_t i=0 ; i<n ; i++) {
- if (!strcmp(name, map[i].name)) {
- return map[i].address;
- }
- }
- return nullptr;
-}
-
-// ----------------------------------------------------------------------------
-
-extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
-extern EGLBoolean egl_init_drivers();
-extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
-extern gl_hooks_t gHooksTrace;
-
-// ----------------------------------------------------------------------------
-
-static inline EGLContext getContext() { return egl_tls_t::getContext(); }
-
-// ----------------------------------------------------------------------------
-
-EGLDisplay eglGetDisplayImpl(EGLNativeDisplayType display)
-{
- uintptr_t index = reinterpret_cast<uintptr_t>(display);
- if (index >= NUM_DISPLAYS) {
- return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
- }
-
- EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
- return dpy;
-}
-
-// ----------------------------------------------------------------------------
-// Initialization
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglInitializeImpl(EGLDisplay dpy, EGLint *major, EGLint *minor)
-{
- egl_display_ptr dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
-
- EGLBoolean res = dp->initialize(major, minor);
-
- return res;
-}
-
-EGLBoolean eglTerminateImpl(EGLDisplay dpy)
-{
- // NOTE: don't unload the drivers b/c some APIs can be called
- // after eglTerminate() has been called. eglTerminate() only
- // terminates an EGLDisplay, not a EGL itself.
-
- egl_display_ptr dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
-
- EGLBoolean res = dp->terminate();
-
- return res;
-}
-
-// ----------------------------------------------------------------------------
-// configuration
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglGetConfigsImpl(EGLDisplay dpy,
- EGLConfig *configs,
- EGLint config_size, EGLint *num_config)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- if (num_config==nullptr) {
- return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
- }
-
- EGLBoolean res = EGL_FALSE;
- *num_config = 0;
-
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso) {
- res = cnx->egl.eglGetConfigs(
- dp->disp.dpy, configs, config_size, num_config);
- }
-
- return res;
-}
-
-EGLBoolean eglChooseConfigImpl( EGLDisplay dpy, const EGLint *attrib_list,
- EGLConfig *configs, EGLint config_size,
- EGLint *num_config)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- if (num_config==nullptr) {
- return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
- }
-
- EGLBoolean res = EGL_FALSE;
- *num_config = 0;
-
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso) {
- if (attrib_list) {
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.force_msaa", value, "false");
-
- if (!strcmp(value, "true")) {
- size_t attribCount = 0;
- EGLint attrib = attrib_list[0];
-
- // Only enable MSAA if the context is OpenGL ES 2.0 and
- // if no caveat is requested
- const EGLint *attribRendererable = nullptr;
- const EGLint *attribCaveat = nullptr;
-
- // Count the number of attributes and look for
- // EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT
- while (attrib != EGL_NONE) {
- attrib = attrib_list[attribCount];
- switch (attrib) {
- case EGL_RENDERABLE_TYPE:
- attribRendererable = &attrib_list[attribCount];
- break;
- case EGL_CONFIG_CAVEAT:
- attribCaveat = &attrib_list[attribCount];
- break;
- default:
- break;
- }
- attribCount++;
- }
-
- if (attribRendererable && attribRendererable[1] == EGL_OPENGL_ES2_BIT &&
- (!attribCaveat || attribCaveat[1] != EGL_NONE)) {
-
- // Insert 2 extra attributes to force-enable MSAA 4x
- EGLint aaAttribs[attribCount + 4];
- aaAttribs[0] = EGL_SAMPLE_BUFFERS;
- aaAttribs[1] = 1;
- aaAttribs[2] = EGL_SAMPLES;
- aaAttribs[3] = 4;
-
- memcpy(&aaAttribs[4], attrib_list, attribCount * sizeof(EGLint));
-
- EGLint numConfigAA;
- EGLBoolean resAA = cnx->egl.eglChooseConfig(
- dp->disp.dpy, aaAttribs, configs, config_size, &numConfigAA);
-
- if (resAA == EGL_TRUE && numConfigAA > 0) {
- ALOGD("Enabling MSAA 4x");
- *num_config = numConfigAA;
- return resAA;
- }
- }
- }
- }
-
- res = cnx->egl.eglChooseConfig(
- dp->disp.dpy, attrib_list, configs, config_size, num_config);
- }
- return res;
-}
-
-EGLBoolean eglGetConfigAttribImpl(EGLDisplay dpy, EGLConfig config,
- EGLint attribute, EGLint *value)
-{
- egl_connection_t* cnx = nullptr;
- const egl_display_ptr dp = validate_display_connection(dpy, cnx);
- if (!dp) return EGL_FALSE;
-
- return cnx->egl.eglGetConfigAttrib(
- dp->disp.dpy, config, attribute, value);
-}
-
-// ----------------------------------------------------------------------------
-// surfaces
-// ----------------------------------------------------------------------------
-
-// Translates EGL color spaces to Android data spaces.
-static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) {
- if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
- return HAL_DATASPACE_UNKNOWN;
- } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
- return HAL_DATASPACE_SRGB;
- } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) {
- return HAL_DATASPACE_DISPLAY_P3;
- } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) {
- return HAL_DATASPACE_DISPLAY_P3_LINEAR;
- } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_EXT) {
- return HAL_DATASPACE_V0_SCRGB;
- } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
- return HAL_DATASPACE_V0_SCRGB_LINEAR;
- } else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) {
- return HAL_DATASPACE_BT2020_LINEAR;
- } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) {
- return HAL_DATASPACE_BT2020_PQ;
- }
- return HAL_DATASPACE_UNKNOWN;
-}
-
-// Get the colorspace value that should be reported from queries. When the colorspace
-// is unknown (no attribute passed), default to reporting LINEAR.
-static EGLint getReportedColorSpace(EGLint colorspace) {
- return colorspace == EGL_UNKNOWN ? EGL_GL_COLORSPACE_LINEAR_KHR : colorspace;
-}
-
-// Returns a list of color spaces understood by the vendor EGL driver.
-static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp,
- android_pixel_format format) {
- std::vector<EGLint> colorSpaces;
- if (!dp->hasColorSpaceSupport) return colorSpaces;
-
- // OpenGL drivers only support sRGB encoding with 8-bit formats.
- // RGB_888 is never returned by getNativePixelFormat, but is included for completeness.
- const bool formatSupportsSRGBEncoding =
- format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 ||
- format == HAL_PIXEL_FORMAT_RGB_888;
- const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16;
-
- if (formatSupportsSRGBEncoding) {
- // sRGB and linear are always supported when color space support is present.
- colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
- colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
- // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats.
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_display_p3")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT);
- }
- }
-
- // According to the spec, scRGB is only supported for floating point formats.
- // For non-linear scRGB, the application is responsible for applying the
- // transfer function.
- if (formatIsFloatingPoint) {
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_scrgb")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT);
- }
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_scrgb_linear")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
- }
- }
-
- // BT2020 can be used with any pixel format. PQ encoding must be applied by the
- // application and does not affect the behavior of OpenGL.
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_bt2020_linear")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT);
- }
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_bt2020_pq")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT);
- }
-
- // Linear DCI-P3 simply uses different primaries than standard RGB and thus
- // can be used with any pixel format.
- if (findExtension(dp->disp.queryString.extensions,
- "EGL_EXT_gl_colorspace_display_p3_linear")) {
- colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT);
- }
- return colorSpaces;
-}
-
-// Cleans up color space related parameters that the driver does not understand.
-// If there is no color space attribute in attrib_list, colorSpace is left
-// unmodified.
-static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window,
- android_pixel_format format, const EGLint* attrib_list,
- EGLint* colorSpace,
- std::vector<EGLint>* strippedAttribList) {
- for (const EGLint* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
- bool copyAttribute = true;
- if (attr[0] == EGL_GL_COLORSPACE_KHR) {
- // Fail immediately if the driver doesn't have color space support at all.
- if (!dp->hasColorSpaceSupport) return false;
- *colorSpace = attr[1];
-
- // Strip the attribute if the driver doesn't understand it.
- copyAttribute = false;
- std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format);
- for (auto driverColorSpace : driverColorSpaces) {
- if (attr[1] == driverColorSpace) {
- copyAttribute = true;
- break;
- }
- }
-
- // If the driver doesn't understand it, we should map sRGB-encoded P3 to
- // sRGB rather than just dropping the colorspace on the floor.
- // For this format, the driver is expected to apply the sRGB
- // transfer function during framebuffer operations.
- if (!copyAttribute && attr[1] == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) {
- strippedAttribList->push_back(attr[0]);
- strippedAttribList->push_back(EGL_GL_COLORSPACE_SRGB_KHR);
- }
- }
- if (copyAttribute) {
- strippedAttribList->push_back(attr[0]);
- strippedAttribList->push_back(attr[1]);
- }
- }
- // Terminate the attribute list.
- strippedAttribList->push_back(EGL_NONE);
-
- // If the passed color space has wide color gamut, check whether the target native window
- // supports wide color.
- const bool colorSpaceIsNarrow =
- *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
- *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR ||
- *colorSpace == EGL_UNKNOWN;
- if (window && !colorSpaceIsNarrow) {
- bool windowSupportsWideColor = true;
- // Ordinarily we'd put a call to native_window_get_wide_color_support
- // at the beginning of the function so that we'll have the
- // result when needed elsewhere in the function.
- // However, because eglCreateWindowSurface is called by SurfaceFlinger and
- // SurfaceFlinger is required to answer the call below we would
- // end up in a deadlock situation. By moving the call to only happen
- // if the application has specifically asked for wide-color we avoid
- // the deadlock with SurfaceFlinger since it will not ask for a
- // wide-color surface.
- int err = native_window_get_wide_color_support(window, &windowSupportsWideColor);
-
- if (err) {
- ALOGE("processAttributes: invalid window (win=%p) "
- "failed (%#x) (already connected to another API?)",
- window, err);
- return false;
- }
- if (!windowSupportsWideColor) {
- // Application has asked for a wide-color colorspace but
- // wide-color support isn't available on the display the window is on.
- return false;
- }
- }
- return true;
-}
-
-// Gets the native pixel format corrsponding to the passed EGLConfig.
-void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config,
- android_pixel_format* format) {
- // Set the native window's buffers format to match what this config requests.
- // Whether to use sRGB gamma is not part of the EGLconfig, but is part
- // of our native format. So if sRGB gamma is requested, we have to
- // modify the EGLconfig's format before setting the native window's
- // format.
-
- EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
- cnx->egl.eglGetConfigAttrib(dpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, &componentType);
-
- EGLint a = 0;
- EGLint r, g, b;
- r = g = b = 0;
- cnx->egl.eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
- cnx->egl.eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
- cnx->egl.eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
- cnx->egl.eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
- EGLint colorDepth = r + g + b;
-
- // Today, the driver only understands sRGB and linear on 888X
- // formats. Strip other colorspaces from the attribute list and
- // only use them to set the dataspace via
- // native_window_set_buffers_dataspace
- // if pixel format is RGBX 8888
- // TBD: Can test for future extensions that indicate that driver
- // handles requested color space and we can let it through.
- // allow SRGB and LINEAR. All others need to be stripped.
- // else if 565, 4444
- // TBD: Can we assume these are supported if 8888 is?
- // else if FP16 or 1010102
- // strip colorspace from attribs.
- // endif
- if (a == 0) {
- if (colorDepth <= 16) {
- *format = HAL_PIXEL_FORMAT_RGB_565;
- } else {
- if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
- if (colorDepth > 24) {
- *format = HAL_PIXEL_FORMAT_RGBA_1010102;
- } else {
- *format = HAL_PIXEL_FORMAT_RGBX_8888;
- }
- } else {
- *format = HAL_PIXEL_FORMAT_RGBA_FP16;
- }
- }
- } else {
- if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
- if (colorDepth > 24) {
- *format = HAL_PIXEL_FORMAT_RGBA_1010102;
- } else {
- *format = HAL_PIXEL_FORMAT_RGBA_8888;
- }
- } else {
- *format = HAL_PIXEL_FORMAT_RGBA_FP16;
- }
- }
-}
-
-EGLBoolean sendSurfaceMetadata(egl_surface_t* s) {
- android_smpte2086_metadata smpteMetadata;
- if (s->getSmpte2086Metadata(smpteMetadata)) {
- int err =
- native_window_set_buffers_smpte2086_metadata(s->getNativeWindow(), &smpteMetadata);
- s->resetSmpte2086Metadata();
- if (err != 0) {
- ALOGE("error setting native window smpte2086 metadata: %s (%d)",
- strerror(-err), err);
- return EGL_FALSE;
- }
- }
- android_cta861_3_metadata cta8613Metadata;
- if (s->getCta8613Metadata(cta8613Metadata)) {
- int err =
- native_window_set_buffers_cta861_3_metadata(s->getNativeWindow(), &cta8613Metadata);
- s->resetCta8613Metadata();
- if (err != 0) {
- ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
- strerror(-err), err);
- return EGL_FALSE;
- }
- }
- return EGL_TRUE;
-}
-
-EGLSurface eglCreateWindowSurfaceImpl( EGLDisplay dpy, EGLConfig config,
- NativeWindowType window,
- const EGLint *attrib_list)
-{
- const EGLint *origAttribList = attrib_list;
-
- egl_connection_t* cnx = nullptr;
- egl_display_ptr dp = validate_display_connection(dpy, cnx);
- if (dp) {
- if (!window) {
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
- }
-
- int value = 0;
- window->query(window, NATIVE_WINDOW_IS_VALID, &value);
- if (!value) {
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
- }
-
- // NOTE: When using Vulkan backend, the Vulkan runtime makes all the
- // native_window_* calls, so don't do them here.
- if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
- int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
- if (result < 0) {
- ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
- "failed (%#x) (already connected to another API?)",
- window, result);
- return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- }
- }
-
- EGLDisplay iDpy = dp->disp.dpy;
- android_pixel_format format;
- getNativePixelFormat(iDpy, cnx, config, &format);
-
- // now select correct colorspace and dataspace based on user's attribute list
- EGLint colorSpace = EGL_UNKNOWN;
- std::vector<EGLint> strippedAttribList;
- if (!processAttributes(dp, window, format, attrib_list, &colorSpace,
- &strippedAttribList)) {
- ALOGE("error invalid colorspace: %d", colorSpace);
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
- }
- attrib_list = strippedAttribList.data();
-
- if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
- int err = native_window_set_buffers_format(window, format);
- if (err != 0) {
- ALOGE("error setting native window pixel format: %s (%d)",
- strerror(-err), err);
- native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
- }
-
- android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace);
- if (dataSpace != HAL_DATASPACE_UNKNOWN) {
- err = native_window_set_buffers_data_space(window, dataSpace);
- if (err != 0) {
- ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err),
- err);
- native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
- }
- }
- }
-
- // the EGL spec requires that a new EGLSurface default to swap interval
- // 1, so explicitly set that on the window here.
- ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
- anw->setSwapInterval(anw, 1);
-
- EGLSurface surface = cnx->egl.eglCreateWindowSurface(
- iDpy, config, window, attrib_list);
- if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s =
- new egl_surface_t(dp.get(), config, window, surface,
- getReportedColorSpace(colorSpace), cnx);
- return s;
- }
-
- // EGLSurface creation failed
- if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
- native_window_set_buffers_format(window, 0);
- native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
- }
- }
- return EGL_NO_SURFACE;
-}
-
-EGLSurface eglCreatePixmapSurfaceImpl( EGLDisplay dpy, EGLConfig config,
- NativePixmapType pixmap,
- const EGLint *attrib_list)
-{
- egl_connection_t* cnx = nullptr;
- egl_display_ptr dp = validate_display_connection(dpy, cnx);
- if (dp) {
- EGLDisplay iDpy = dp->disp.dpy;
- android_pixel_format format;
- getNativePixelFormat(iDpy, cnx, config, &format);
-
- // now select a corresponding sRGB format if needed
- EGLint colorSpace = EGL_UNKNOWN;
- std::vector<EGLint> strippedAttribList;
- if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
- &strippedAttribList)) {
- ALOGE("error invalid colorspace: %d", colorSpace);
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
- }
- attrib_list = strippedAttribList.data();
-
- EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
- dp->disp.dpy, config, pixmap, attrib_list);
- if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s =
- new egl_surface_t(dp.get(), config, nullptr, surface,
- getReportedColorSpace(colorSpace), cnx);
- return s;
- }
- }
- return EGL_NO_SURFACE;
-}
-
-EGLSurface eglCreatePbufferSurfaceImpl( EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list)
-{
- egl_connection_t* cnx = nullptr;
- egl_display_ptr dp = validate_display_connection(dpy, cnx);
- if (dp) {
- EGLDisplay iDpy = dp->disp.dpy;
- android_pixel_format format;
- getNativePixelFormat(iDpy, cnx, config, &format);
-
- // Select correct colorspace based on user's attribute list
- EGLint colorSpace = EGL_UNKNOWN;
- std::vector<EGLint> strippedAttribList;
- if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace,
- &strippedAttribList)) {
- ALOGE("error invalid colorspace: %d", colorSpace);
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
- }
- attrib_list = strippedAttribList.data();
-
- EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
- dp->disp.dpy, config, attrib_list);
- if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s =
- new egl_surface_t(dp.get(), config, nullptr, surface,
- getReportedColorSpace(colorSpace), cnx);
- return s;
- }
- }
- return EGL_NO_SURFACE;
-}
-
-EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-
- egl_surface_t * const s = get_surface(surface);
- EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
- if (result == EGL_TRUE) {
- _s.terminate();
- }
- return result;
-}
-
-EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint *value)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-
- egl_surface_t const * const s = get_surface(surface);
- if (s->getColorSpaceAttribute(attribute, value)) {
- return EGL_TRUE;
- } else if (s->getSmpte2086Attribute(attribute, value)) {
- return EGL_TRUE;
- } else if (s->getCta8613Attribute(attribute, value)) {
- return EGL_TRUE;
- }
- return s->cnx->egl.eglQuerySurface(dp->disp.dpy, s->surface, attribute, value);
-}
-
-void EGLAPI eglBeginFrameImpl(EGLDisplay dpy, EGLSurface surface) {
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) {
- return;
- }
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get()) {
- setError(EGL_BAD_SURFACE, EGL_FALSE);
- }
-}
-
-// ----------------------------------------------------------------------------
-// Contexts
-// ----------------------------------------------------------------------------
-
-EGLContext eglCreateContextImpl(EGLDisplay dpy, EGLConfig config,
- EGLContext share_list, const EGLint *attrib_list)
-{
- egl_connection_t* cnx = nullptr;
- const egl_display_ptr dp = validate_display_connection(dpy, cnx);
- if (dp) {
- if (share_list != EGL_NO_CONTEXT) {
- if (!ContextRef(dp.get(), share_list).get()) {
- return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
- }
- egl_context_t* const c = get_context(share_list);
- share_list = c->context;
- }
- EGLContext context = cnx->egl.eglCreateContext(
- dp->disp.dpy, config, share_list, attrib_list);
- if (context != EGL_NO_CONTEXT) {
- // figure out if it's a GLESv1 or GLESv2
- int version = 0;
- if (attrib_list) {
- while (*attrib_list != EGL_NONE) {
- GLint attr = *attrib_list++;
- GLint value = *attrib_list++;
- if (attr == EGL_CONTEXT_CLIENT_VERSION) {
- if (value == 1) {
- version = egl_connection_t::GLESv1_INDEX;
- } else if (value == 2 || value == 3) {
- version = egl_connection_t::GLESv2_INDEX;
- }
- }
- };
- }
- egl_context_t* c = new egl_context_t(dpy, context, config, cnx,
- version);
- return c;
- }
- }
- return EGL_NO_CONTEXT;
-}
-
-EGLBoolean eglDestroyContextImpl(EGLDisplay dpy, EGLContext ctx)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp)
- return EGL_FALSE;
-
- ContextRef _c(dp.get(), ctx);
- if (!_c.get())
- return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
-
- egl_context_t * const c = get_context(ctx);
- EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context);
- if (result == EGL_TRUE) {
- _c.terminate();
- }
- return result;
-}
-
-EGLBoolean eglMakeCurrentImpl( EGLDisplay dpy, EGLSurface draw,
- EGLSurface read, EGLContext ctx)
-{
- egl_display_ptr dp = validate_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
-
- // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
- // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
- // a valid but uninitialized display.
- if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
- (draw != EGL_NO_SURFACE) ) {
- if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
- }
-
- // get a reference to the object passed in
- ContextRef _c(dp.get(), ctx);
- SurfaceRef _d(dp.get(), draw);
- SurfaceRef _r(dp.get(), read);
-
- // validate the context (if not EGL_NO_CONTEXT)
- if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
- // EGL_NO_CONTEXT is valid
- return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
- }
-
- // these are the underlying implementation's object
- EGLContext impl_ctx = EGL_NO_CONTEXT;
- EGLSurface impl_draw = EGL_NO_SURFACE;
- EGLSurface impl_read = EGL_NO_SURFACE;
-
- // these are our objects structs passed in
- egl_context_t * c = nullptr;
- egl_surface_t const * d = nullptr;
- egl_surface_t const * r = nullptr;
-
- // these are the current objects structs
- egl_context_t * cur_c = get_context(getContext());
-
- if (ctx != EGL_NO_CONTEXT) {
- c = get_context(ctx);
- impl_ctx = c->context;
- } else {
- // no context given, use the implementation of the current context
- if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
- // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
- return setError(EGL_BAD_MATCH, (EGLBoolean)EGL_FALSE);
- }
- if (cur_c == nullptr) {
- // no current context
- // not an error, there is just no current context.
- return EGL_TRUE;
- }
- }
-
- // retrieve the underlying implementation's draw EGLSurface
- if (draw != EGL_NO_SURFACE) {
- if (!_d.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- d = get_surface(draw);
- impl_draw = d->surface;
- }
-
- // retrieve the underlying implementation's read EGLSurface
- if (read != EGL_NO_SURFACE) {
- if (!_r.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- r = get_surface(read);
- impl_read = r->surface;
- }
-
-
- EGLBoolean result = dp->makeCurrent(c, cur_c,
- draw, read, ctx,
- impl_draw, impl_read, impl_ctx);
-
- if (result == EGL_TRUE) {
- if (c) {
- setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
- egl_tls_t::setContext(ctx);
- _c.acquire();
- _r.acquire();
- _d.acquire();
- } else {
- setGLHooksThreadSpecific(&gHooksNoContext);
- egl_tls_t::setContext(EGL_NO_CONTEXT);
- }
- } else {
- // this will ALOGE the error
- egl_connection_t* const cnx = &gEGLImpl;
- result = setError(cnx->egl.eglGetError(), (EGLBoolean)EGL_FALSE);
- }
- return result;
-}
-
-EGLBoolean eglQueryContextImpl( EGLDisplay dpy, EGLContext ctx,
- EGLint attribute, EGLint *value)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- ContextRef _c(dp.get(), ctx);
- if (!_c.get()) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
-
- egl_context_t * const c = get_context(ctx);
- return c->cnx->egl.eglQueryContext(
- dp->disp.dpy, c->context, attribute, value);
-
-}
-
-EGLContext eglGetCurrentContextImpl(void)
-{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would correctly return EGL_NO_CONTEXT.
- EGLContext ctx = getContext();
- return ctx;
-}
-
-EGLSurface eglGetCurrentSurfaceImpl(EGLint readdraw)
-{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would correctly return EGL_NO_SURFACE.
-
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
- switch (readdraw) {
- case EGL_READ: return c->read;
- case EGL_DRAW: return c->draw;
- default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
- }
- }
- return EGL_NO_SURFACE;
-}
-
-EGLDisplay eglGetCurrentDisplayImpl(void)
-{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would correctly return EGL_NO_DISPLAY.
-
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
- return c->dpy;
- }
- return EGL_NO_DISPLAY;
-}
-
-EGLBoolean eglWaitGLImpl(void)
-{
- egl_connection_t* const cnx = &gEGLImpl;
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
-
- return cnx->egl.eglWaitGL();
-}
-
-EGLBoolean eglWaitNativeImpl(EGLint engine)
-{
- egl_connection_t* const cnx = &gEGLImpl;
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
-
- return cnx->egl.eglWaitNative(engine);
-}
-
-EGLint eglGetErrorImpl(void)
-{
- EGLint err = EGL_SUCCESS;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso) {
- err = cnx->egl.eglGetError();
- }
- if (err == EGL_SUCCESS) {
- err = egl_tls_t::getError();
- }
- return err;
-}
-
-static __eglMustCastToProperFunctionPointerType findBuiltinWrapper(
- const char* procname) {
- const egl_connection_t* cnx = &gEGLImpl;
- void* proc = nullptr;
-
- proc = dlsym(cnx->libEgl, procname);
- if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
-
- proc = dlsym(cnx->libGles2, procname);
- if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
-
- proc = dlsym(cnx->libGles1, procname);
- if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
-
- return nullptr;
-}
-
-__eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procname)
-{
- if (FILTER_EXTENSIONS(procname)) {
- return nullptr;
- }
-
- __eglMustCastToProperFunctionPointerType addr;
- addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap));
- if (addr) return addr;
-
- addr = findBuiltinWrapper(procname);
- if (addr) return addr;
-
- // this protects accesses to sGLExtentionMap and sGLExtentionSlot
- pthread_mutex_lock(&sExtensionMapMutex);
-
- /*
- * Since eglGetProcAddress() is not associated to anything, it needs
- * to return a function pointer that "works" regardless of what
- * the current context is.
- *
- * For this reason, we return a "forwarder", a small stub that takes
- * care of calling the function associated with the context
- * currently bound.
- *
- * We first look for extensions we've already resolved, if we're seeing
- * this extension for the first time, we go through all our
- * implementations and call eglGetProcAddress() and record the
- * result in the appropriate implementation hooks and return the
- * address of the forwarder corresponding to that hook set.
- *
- */
-
- const std::string name(procname);
-
- auto& extentionMap = sGLExtentionMap;
- auto pos = extentionMap.find(name);
- addr = (pos != extentionMap.end()) ? pos->second : nullptr;
- const int slot = sGLExtentionSlot;
-
- ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
- "no more slots for eglGetProcAddress(\"%s\")",
- procname);
-
- egl_connection_t* const cnx = &gEGLImpl;
- LayerLoader& layer_loader(LayerLoader::getInstance());
-
- if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
-
- if (cnx->dso && cnx->egl.eglGetProcAddress) {
-
- // Extensions are independent of the bound context
- addr = cnx->egl.eglGetProcAddress(procname);
- if (addr) {
-
- // purposefully track the bottom of the stack in extensionMap
- extentionMap[name] = addr;
-
- // Apply layers
- addr = layer_loader.ApplyLayers(procname, addr);
-
- // Track the top most entry point
- cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
- cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = addr;
- addr = gExtensionForwarders[slot];
- sGLExtentionSlot++;
- }
- }
-
- } else if (slot < MAX_NUMBER_OF_GL_EXTENSIONS) {
-
- // We've seen this func before, but we tracked the bottom, so re-apply layers
- // More layers might have been enabled
- addr = layer_loader.ApplyLayers(procname, addr);
-
- // Track the top most entry point
- cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
- cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = addr;
- addr = gExtensionForwarders[slot];
- }
-
- pthread_mutex_unlock(&sExtensionMapMutex);
- return addr;
-}
-
-class FrameCompletionThread {
-public:
-
- static void queueSync(EGLSyncKHR sync) {
- static FrameCompletionThread thread;
-
- char name[64];
-
- std::lock_guard<std::mutex> lock(thread.mMutex);
- snprintf(name, sizeof(name), "kicked off frame %u", (unsigned int)thread.mFramesQueued);
- ATRACE_NAME(name);
-
- thread.mQueue.push_back(sync);
- thread.mCondition.notify_one();
- thread.mFramesQueued++;
- ATRACE_INT("GPU Frames Outstanding", int32_t(thread.mQueue.size()));
- }
-
-private:
-
- FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {
- std::thread thread(&FrameCompletionThread::loop, this);
- thread.detach();
- }
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmissing-noreturn"
- void loop() {
- while (true) {
- threadLoop();
- }
- }
-#pragma clang diagnostic pop
-
- void threadLoop() {
- EGLSyncKHR sync;
- uint32_t frameNum;
- {
- std::unique_lock<std::mutex> lock(mMutex);
- while (mQueue.empty()) {
- mCondition.wait(lock);
- }
- sync = mQueue[0];
- frameNum = mFramesCompleted;
- }
- EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- {
- char name[64];
- snprintf(name, sizeof(name), "waiting for frame %u", (unsigned int)frameNum);
- ATRACE_NAME(name);
-
- EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);
- if (result == EGL_FALSE) {
- ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError());
- } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ALOGE("FrameCompletion: timeout waiting for fence");
- }
- eglDestroySyncKHR(dpy, sync);
- }
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mQueue.pop_front();
- mFramesCompleted++;
- ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size()));
- }
- }
-
- uint32_t mFramesQueued;
- uint32_t mFramesCompleted;
- std::deque<EGLSyncKHR> mQueue;
- std::condition_variable mCondition;
- std::mutex mMutex;
-};
-
-EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw,
- EGLint *rects, EGLint n_rects)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(dp.get(), draw);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-
- egl_surface_t* const s = get_surface(draw);
-
- if (CC_UNLIKELY(dp->traceGpuCompletion)) {
- EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
- if (sync != EGL_NO_SYNC_KHR) {
- FrameCompletionThread::queueSync(sync);
- }
- }
-
- if (CC_UNLIKELY(dp->finishOnSwap)) {
- uint32_t pixel;
- egl_context_t * const c = get_context( egl_tls_t::getContext() );
- if (c) {
- // glReadPixels() ensures that the frame is complete
- s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1,
- GL_RGBA,GL_UNSIGNED_BYTE,&pixel);
- }
- }
-
- if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
- if (!sendSurfaceMetadata(s)) {
- native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL);
- return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE);
- }
- }
-
- if (n_rects == 0) {
- return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
- }
-
- std::vector<android_native_rect_t> androidRects((size_t)n_rects);
- for (int r = 0; r < n_rects; ++r) {
- int offset = r * 4;
- int x = rects[offset];
- int y = rects[offset + 1];
- int width = rects[offset + 2];
- int height = rects[offset + 3];
- android_native_rect_t androidRect;
- androidRect.left = x;
- androidRect.top = y + height;
- androidRect.right = x + width;
- androidRect.bottom = y;
- androidRects.push_back(androidRect);
- }
- if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) {
- native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(),
- androidRects.size());
- }
-
- if (s->cnx->egl.eglSwapBuffersWithDamageKHR) {
- return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface,
- rects, n_rects);
- } else {
- return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
- }
-}
-
-EGLBoolean eglSwapBuffersImpl(EGLDisplay dpy, EGLSurface surface)
-{
- return eglSwapBuffersWithDamageKHRImpl(dpy, surface, nullptr, 0);
-}
-
-EGLBoolean eglCopyBuffersImpl( EGLDisplay dpy, EGLSurface surface,
- NativePixmapType target)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-
- egl_surface_t const * const s = get_surface(surface);
- return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
-}
-
-const char* eglQueryStringImpl(EGLDisplay dpy, EGLint name)
-{
- // Generate an error quietly when client extensions (as defined by
- // EGL_EXT_client_extensions) are queried. We do not want to rely on
- // validate_display to generate the error as validate_display would log
- // the error, which can be misleading.
- //
- // If we want to support EGL_EXT_client_extensions later, we can return
- // the client extension string here instead.
- if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
- return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)nullptr);
-
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return (const char *) nullptr;
-
- switch (name) {
- case EGL_VENDOR:
- return dp->getVendorString();
- case EGL_VERSION:
- return dp->getVersionString();
- case EGL_EXTENSIONS:
- return dp->getExtensionString();
- case EGL_CLIENT_APIS:
- return dp->getClientApiString();
- default:
- break;
- }
- return setError(EGL_BAD_PARAMETER, (const char *)nullptr);
-}
-
-EGLAPI const char* eglQueryStringImplementationANDROIDImpl(EGLDisplay dpy, EGLint name)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return (const char *) nullptr;
-
- switch (name) {
- case EGL_VENDOR:
- return dp->disp.queryString.vendor;
- case EGL_VERSION:
- return dp->disp.queryString.version;
- case EGL_EXTENSIONS:
- return dp->disp.queryString.extensions;
- case EGL_CLIENT_APIS:
- return dp->disp.queryString.clientApi;
- default:
- break;
- }
- return setError(EGL_BAD_PARAMETER, (const char *)nullptr);
-}
-
-// ----------------------------------------------------------------------------
-// EGL 1.1
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglSurfaceAttribImpl(
- EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-
- egl_surface_t * const s = get_surface(surface);
-
- if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) {
- if (!s->getNativeWindow()) {
- setError(EGL_BAD_SURFACE, EGL_FALSE);
- }
- int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0);
- return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- if (attribute == EGL_TIMESTAMPS_ANDROID) {
- if (!s->getNativeWindow()) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
- int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0);
- return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- if (s->setSmpte2086Attribute(attribute, value)) {
- return EGL_TRUE;
- } else if (s->setCta8613Attribute(attribute, value)) {
- return EGL_TRUE;
- } else if (s->cnx->egl.eglSurfaceAttrib) {
- return s->cnx->egl.eglSurfaceAttrib(
- dp->disp.dpy, s->surface, attribute, value);
- }
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-}
-
-EGLBoolean eglBindTexImageImpl(
- EGLDisplay dpy, EGLSurface surface, EGLint buffer)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-
- egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->egl.eglBindTexImage) {
- return s->cnx->egl.eglBindTexImage(
- dp->disp.dpy, s->surface, buffer);
- }
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-}
-
-EGLBoolean eglReleaseTexImageImpl(
- EGLDisplay dpy, EGLSurface surface, EGLint buffer)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-
- egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->egl.eglReleaseTexImage) {
- return s->cnx->egl.eglReleaseTexImage(
- dp->disp.dpy, s->surface, buffer);
- }
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-}
-
-EGLBoolean eglSwapIntervalImpl(EGLDisplay dpy, EGLint interval)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean res = EGL_TRUE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglSwapInterval) {
- res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
- }
-
- return res;
-}
-
-
-// ----------------------------------------------------------------------------
-// EGL 1.2
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglWaitClientImpl(void)
-{
- egl_connection_t* const cnx = &gEGLImpl;
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE);
-
- EGLBoolean res;
- if (cnx->egl.eglWaitClient) {
- res = cnx->egl.eglWaitClient();
- } else {
- res = cnx->egl.eglWaitGL();
- }
- return res;
-}
-
-EGLBoolean eglBindAPIImpl(EGLenum api)
-{
- // bind this API on all EGLs
- EGLBoolean res = EGL_TRUE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglBindAPI) {
- res = cnx->egl.eglBindAPI(api);
- }
- return res;
-}
-
-EGLenum eglQueryAPIImpl(void)
-{
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglQueryAPI) {
- return cnx->egl.eglQueryAPI();
- }
-
- // or, it can only be OpenGL ES
- return EGL_OPENGL_ES_API;
-}
-
-EGLBoolean eglReleaseThreadImpl(void)
-{
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglReleaseThread) {
- cnx->egl.eglReleaseThread();
- }
-
- // If there is context bound to the thread, release it
- egl_display_t::loseCurrent(get_context(getContext()));
-
- egl_tls_t::clearTLS();
- return EGL_TRUE;
-}
-
-EGLSurface eglCreatePbufferFromClientBufferImpl(
- EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
- EGLConfig config, const EGLint *attrib_list)
-{
- egl_connection_t* cnx = nullptr;
- const egl_display_ptr dp = validate_display_connection(dpy, cnx);
- if (!dp) return EGL_FALSE;
- if (cnx->egl.eglCreatePbufferFromClientBuffer) {
- return cnx->egl.eglCreatePbufferFromClientBuffer(
- dp->disp.dpy, buftype, buffer, config, attrib_list);
- }
- return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
-}
-
-// ----------------------------------------------------------------------------
-// EGL_EGLEXT_VERSION 3
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglLockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface,
- const EGLint *attrib_list)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-
- egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->egl.eglLockSurfaceKHR) {
- return s->cnx->egl.eglLockSurfaceKHR(
- dp->disp.dpy, s->surface, attrib_list);
- }
- return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
-}
-
-EGLBoolean eglUnlockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get())
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-
- egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->egl.eglUnlockSurfaceKHR) {
- return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
- }
- return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
-}
-
-EGLImageKHR eglCreateImageKHRImpl(EGLDisplay dpy, EGLContext ctx, EGLenum target,
- EGLClientBuffer buffer, const EGLint *attrib_list)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_NO_IMAGE_KHR;
-
- ContextRef _c(dp.get(), ctx);
- egl_context_t * const c = _c.get();
-
- EGLImageKHR result = EGL_NO_IMAGE_KHR;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglCreateImageKHR) {
- result = cnx->egl.eglCreateImageKHR(
- dp->disp.dpy,
- c ? c->context : EGL_NO_CONTEXT,
- target, buffer, attrib_list);
- }
- return result;
-}
-
-EGLBoolean eglDestroyImageKHRImpl(EGLDisplay dpy, EGLImageKHR img)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
- result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img);
- }
- return result;
-}
-
-// ----------------------------------------------------------------------------
-// EGL_EGLEXT_VERSION 5
-// ----------------------------------------------------------------------------
-
-
-EGLSyncKHR eglCreateSyncKHRImpl(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_NO_SYNC_KHR;
-
- EGLSyncKHR result = EGL_NO_SYNC_KHR;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglCreateSyncKHR) {
- result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list);
- }
- return result;
-}
-
-EGLBoolean eglDestroySyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglDestroySyncKHR) {
- result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync);
- }
- return result;
-}
-
-EGLBoolean eglSignalSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglSignalSyncKHR) {
- result = cnx->egl.eglSignalSyncKHR(
- dp->disp.dpy, sync, mode);
- }
- return result;
-}
-
-EGLint eglClientWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync,
- EGLint flags, EGLTimeKHR timeout)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLint result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
- result = cnx->egl.eglClientWaitSyncKHR(
- dp->disp.dpy, sync, flags, timeout);
- }
- return result;
-}
-
-EGLBoolean eglGetSyncAttribKHRImpl(EGLDisplay dpy, EGLSyncKHR sync,
- EGLint attribute, EGLint *value)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) {
- result = cnx->egl.eglGetSyncAttribKHR(
- dp->disp.dpy, sync, attribute, value);
- }
- return result;
-}
-
-EGLStreamKHR eglCreateStreamKHRImpl(EGLDisplay dpy, const EGLint *attrib_list)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_NO_STREAM_KHR;
-
- EGLStreamKHR result = EGL_NO_STREAM_KHR;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglCreateStreamKHR) {
- result = cnx->egl.eglCreateStreamKHR(
- dp->disp.dpy, attrib_list);
- }
- return result;
-}
-
-EGLBoolean eglDestroyStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglDestroyStreamKHR) {
- result = cnx->egl.eglDestroyStreamKHR(
- dp->disp.dpy, stream);
- }
- return result;
-}
-
-EGLBoolean eglStreamAttribKHRImpl(EGLDisplay dpy, EGLStreamKHR stream,
- EGLenum attribute, EGLint value)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglStreamAttribKHR) {
- result = cnx->egl.eglStreamAttribKHR(
- dp->disp.dpy, stream, attribute, value);
- }
- return result;
-}
-
-EGLBoolean eglQueryStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream,
- EGLenum attribute, EGLint *value)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglQueryStreamKHR) {
- result = cnx->egl.eglQueryStreamKHR(
- dp->disp.dpy, stream, attribute, value);
- }
- return result;
-}
-
-EGLBoolean eglQueryStreamu64KHRImpl(EGLDisplay dpy, EGLStreamKHR stream,
- EGLenum attribute, EGLuint64KHR *value)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglQueryStreamu64KHR) {
- result = cnx->egl.eglQueryStreamu64KHR(
- dp->disp.dpy, stream, attribute, value);
- }
- return result;
-}
-
-EGLBoolean eglQueryStreamTimeKHRImpl(EGLDisplay dpy, EGLStreamKHR stream,
- EGLenum attribute, EGLTimeKHR *value)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglQueryStreamTimeKHR) {
- result = cnx->egl.eglQueryStreamTimeKHR(
- dp->disp.dpy, stream, attribute, value);
- }
- return result;
-}
-
-EGLSurface eglCreateStreamProducerSurfaceKHRImpl(EGLDisplay dpy, EGLConfig config,
- EGLStreamKHR stream, const EGLint *attrib_list)
-{
- egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_NO_SURFACE;
-
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) {
- EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR(
- dp->disp.dpy, config, stream, attrib_list);
- if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dp.get(), config, nullptr, surface,
- EGL_GL_COLORSPACE_LINEAR_KHR, cnx);
- return s;
- }
- }
- return EGL_NO_SURFACE;
-}
-
-EGLBoolean eglStreamConsumerGLTextureExternalKHRImpl(EGLDisplay dpy,
- EGLStreamKHR stream)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) {
- result = cnx->egl.eglStreamConsumerGLTextureExternalKHR(
- dp->disp.dpy, stream);
- }
- return result;
-}
-
-EGLBoolean eglStreamConsumerAcquireKHRImpl(EGLDisplay dpy,
- EGLStreamKHR stream)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) {
- result = cnx->egl.eglStreamConsumerAcquireKHR(
- dp->disp.dpy, stream);
- }
- return result;
-}
-
-EGLBoolean eglStreamConsumerReleaseKHRImpl(EGLDisplay dpy,
- EGLStreamKHR stream)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) {
- result = cnx->egl.eglStreamConsumerReleaseKHR(
- dp->disp.dpy, stream);
- }
- return result;
-}
-
-EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHRImpl(
- EGLDisplay dpy, EGLStreamKHR stream)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR;
-
- EGLNativeFileDescriptorKHR result = EGL_NO_FILE_DESCRIPTOR_KHR;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) {
- result = cnx->egl.eglGetStreamFileDescriptorKHR(
- dp->disp.dpy, stream);
- }
- return result;
-}
-
-EGLStreamKHR eglCreateStreamFromFileDescriptorKHRImpl(
- EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_NO_STREAM_KHR;
-
- EGLStreamKHR result = EGL_NO_STREAM_KHR;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglCreateStreamFromFileDescriptorKHR) {
- result = cnx->egl.eglCreateStreamFromFileDescriptorKHR(
- dp->disp.dpy, file_descriptor);
- }
- return result;
-}
-
-// ----------------------------------------------------------------------------
-// EGL_EGLEXT_VERSION 15
-// ----------------------------------------------------------------------------
-
-EGLint eglWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) {
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
- EGLint result = EGL_FALSE;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglWaitSyncKHR) {
- result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags);
- }
- return result;
-}
-
-// ----------------------------------------------------------------------------
-// ANDROID extensions
-// ----------------------------------------------------------------------------
-
-EGLint eglDupNativeFenceFDANDROIDImpl(EGLDisplay dpy, EGLSyncKHR sync)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
-
- EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID;
- egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) {
- result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync);
- }
- return result;
-}
-
-EGLBoolean eglPresentationTimeANDROIDImpl(EGLDisplay dpy, EGLSurface surface,
- EGLnsecsANDROID time)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) {
- return EGL_FALSE;
- }
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get()) {
- setError(EGL_BAD_SURFACE, EGL_FALSE);
- return EGL_FALSE;
- }
-
- egl_surface_t const * const s = get_surface(surface);
- native_window_set_buffers_timestamp(s->getNativeWindow(), time);
-
- return EGL_TRUE;
-}
-
-EGLClientBuffer eglGetNativeClientBufferANDROIDImpl(const AHardwareBuffer *buffer) {
- // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus
- // this function cannot be implemented when this libEGL is built for
- // vendors.
-#ifndef __ANDROID_VNDK__
- if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr);
- return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
-#else
- return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr);
-#endif
-}
-
-// ----------------------------------------------------------------------------
-// NVIDIA extensions
-// ----------------------------------------------------------------------------
-EGLuint64NV eglGetSystemTimeFrequencyNVImpl()
-{
- EGLuint64NV ret = 0;
- egl_connection_t* const cnx = &gEGLImpl;
-
- if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
- return cnx->egl.eglGetSystemTimeFrequencyNV();
- }
-
- return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0);
-}
-
-EGLuint64NV eglGetSystemTimeNVImpl()
-{
- EGLuint64NV ret = 0;
- egl_connection_t* const cnx = &gEGLImpl;
-
- if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
- return cnx->egl.eglGetSystemTimeNV();
- }
-
- return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0);
-}
-
-// ----------------------------------------------------------------------------
-// Partial update extension
-// ----------------------------------------------------------------------------
-EGLBoolean eglSetDamageRegionKHRImpl(EGLDisplay dpy, EGLSurface surface,
- EGLint *rects, EGLint n_rects)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) {
- setError(EGL_BAD_DISPLAY, EGL_FALSE);
- return EGL_FALSE;
- }
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get()) {
- setError(EGL_BAD_SURFACE, EGL_FALSE);
- return EGL_FALSE;
- }
-
- egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->egl.eglSetDamageRegionKHR) {
- return s->cnx->egl.eglSetDamageRegionKHR(dp->disp.dpy, s->surface,
- rects, n_rects);
- }
-
- return EGL_FALSE;
-}
-
-EGLBoolean eglGetNextFrameIdANDROIDImpl(EGLDisplay dpy, EGLSurface surface,
- EGLuint64KHR *frameId) {
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) {
- return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
- }
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get()) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- egl_surface_t const * const s = get_surface(surface);
-
- if (!s->getNativeWindow()) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- uint64_t nextFrameId = 0;
- int ret = native_window_get_next_frame_id(s->getNativeWindow(), &nextFrameId);
-
- if (ret != 0) {
- // This should not happen. Return an error that is not in the spec
- // so it's obvious something is very wrong.
- ALOGE("eglGetNextFrameId: Unexpected error.");
- return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
- }
-
- *frameId = nextFrameId;
- return EGL_TRUE;
-}
-
-EGLBoolean eglGetCompositorTimingANDROIDImpl(EGLDisplay dpy, EGLSurface surface,
- EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) {
- return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
- }
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get()) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- egl_surface_t const * const s = get_surface(surface);
-
- if (!s->getNativeWindow()) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- nsecs_t* compositeDeadline = nullptr;
- nsecs_t* compositeInterval = nullptr;
- nsecs_t* compositeToPresentLatency = nullptr;
-
- for (int i = 0; i < numTimestamps; i++) {
- switch (names[i]) {
- case EGL_COMPOSITE_DEADLINE_ANDROID:
- compositeDeadline = &values[i];
- break;
- case EGL_COMPOSITE_INTERVAL_ANDROID:
- compositeInterval = &values[i];
- break;
- case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
- compositeToPresentLatency = &values[i];
- break;
- default:
- return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
- }
- }
-
- int ret = native_window_get_compositor_timing(s->getNativeWindow(),
- compositeDeadline, compositeInterval, compositeToPresentLatency);
-
- switch (ret) {
- case 0:
- return EGL_TRUE;
- case -ENOSYS:
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- default:
- // This should not happen. Return an error that is not in the spec
- // so it's obvious something is very wrong.
- ALOGE("eglGetCompositorTiming: Unexpected error.");
- return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
- }
-}
-
-EGLBoolean eglGetCompositorTimingSupportedANDROIDImpl(
- EGLDisplay dpy, EGLSurface surface, EGLint name)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) {
- return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
- }
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get()) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- egl_surface_t const * const s = get_surface(surface);
-
- ANativeWindow* window = s->getNativeWindow();
- if (!window) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- switch (name) {
- case EGL_COMPOSITE_DEADLINE_ANDROID:
- case EGL_COMPOSITE_INTERVAL_ANDROID:
- case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
- return EGL_TRUE;
- default:
- return EGL_FALSE;
- }
-}
-
-EGLBoolean eglGetFrameTimestampsANDROIDImpl(EGLDisplay dpy, EGLSurface surface,
- EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps,
- EGLnsecsANDROID *values)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) {
- return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
- }
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get()) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- egl_surface_t const * const s = get_surface(surface);
-
- if (!s->getNativeWindow()) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- nsecs_t* requestedPresentTime = nullptr;
- nsecs_t* acquireTime = nullptr;
- nsecs_t* latchTime = nullptr;
- nsecs_t* firstRefreshStartTime = nullptr;
- nsecs_t* gpuCompositionDoneTime = nullptr;
- nsecs_t* lastRefreshStartTime = nullptr;
- nsecs_t* displayPresentTime = nullptr;
- nsecs_t* dequeueReadyTime = nullptr;
- nsecs_t* releaseTime = nullptr;
-
- for (int i = 0; i < numTimestamps; i++) {
- switch (timestamps[i]) {
- case EGL_REQUESTED_PRESENT_TIME_ANDROID:
- requestedPresentTime = &values[i];
- break;
- case EGL_RENDERING_COMPLETE_TIME_ANDROID:
- acquireTime = &values[i];
- break;
- case EGL_COMPOSITION_LATCH_TIME_ANDROID:
- latchTime = &values[i];
- break;
- case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
- firstRefreshStartTime = &values[i];
- break;
- case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
- lastRefreshStartTime = &values[i];
- break;
- case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID:
- gpuCompositionDoneTime = &values[i];
- break;
- case EGL_DISPLAY_PRESENT_TIME_ANDROID:
- displayPresentTime = &values[i];
- break;
- case EGL_DEQUEUE_READY_TIME_ANDROID:
- dequeueReadyTime = &values[i];
- break;
- case EGL_READS_DONE_TIME_ANDROID:
- releaseTime = &values[i];
- break;
- default:
- return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
- }
- }
-
- int ret = native_window_get_frame_timestamps(s->getNativeWindow(), frameId,
- requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
- lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime,
- dequeueReadyTime, releaseTime);
-
- switch (ret) {
- case 0:
- return EGL_TRUE;
- case -ENOENT:
- return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
- case -ENOSYS:
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- case -EINVAL:
- return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
- default:
- // This should not happen. Return an error that is not in the spec
- // so it's obvious something is very wrong.
- ALOGE("eglGetFrameTimestamps: Unexpected error.");
- return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE);
- }
-}
-
-EGLBoolean eglGetFrameTimestampSupportedANDROIDImpl(
- EGLDisplay dpy, EGLSurface surface, EGLint timestamp)
-{
- const egl_display_ptr dp = validate_display(dpy);
- if (!dp) {
- return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE);
- }
-
- SurfaceRef _s(dp.get(), surface);
- if (!_s.get()) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- egl_surface_t const * const s = get_surface(surface);
-
- ANativeWindow* window = s->getNativeWindow();
- if (!window) {
- return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- }
-
- switch (timestamp) {
- case EGL_COMPOSITE_DEADLINE_ANDROID:
- case EGL_COMPOSITE_INTERVAL_ANDROID:
- case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID:
- case EGL_REQUESTED_PRESENT_TIME_ANDROID:
- case EGL_RENDERING_COMPLETE_TIME_ANDROID:
- case EGL_COMPOSITION_LATCH_TIME_ANDROID:
- case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
- case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
- case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID:
- case EGL_DEQUEUE_READY_TIME_ANDROID:
- case EGL_READS_DONE_TIME_ANDROID:
- return EGL_TRUE;
- case EGL_DISPLAY_PRESENT_TIME_ANDROID: {
- int value = 0;
- window->query(window,
- NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value);
- return value == 0 ? EGL_FALSE : EGL_TRUE;
- }
- default:
- return EGL_FALSE;
- }
-}
-
-const GLubyte * glGetStringImpl(GLenum name) {
- const GLubyte * ret = egl_get_string_for_current_context(name);
- if (ret == NULL) {
- gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
- if(_c) ret = _c->glGetString(name);
- }
- return ret;
-}
-
-const GLubyte * glGetStringiImpl(GLenum name, GLuint index) {
- const GLubyte * ret = egl_get_string_for_current_context(name, index);
- if (ret == NULL) {
- gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
- if(_c) ret = _c->glGetStringi(name, index);
- }
- return ret;
-}
-
-void glGetBooleanvImpl(GLenum pname, GLboolean * data) {
- if (pname == GL_NUM_EXTENSIONS) {
- int num_exts = egl_get_num_extensions_for_current_context();
- if (num_exts >= 0) {
- *data = num_exts > 0 ? GL_TRUE : GL_FALSE;
- return;
- }
- }
-
- gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
- if (_c) _c->glGetBooleanv(pname, data);
-}
-
-void glGetFloatvImpl(GLenum pname, GLfloat * data) {
- if (pname == GL_NUM_EXTENSIONS) {
- int num_exts = egl_get_num_extensions_for_current_context();
- if (num_exts >= 0) {
- *data = (GLfloat)num_exts;
- return;
- }
- }
-
- gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
- if (_c) _c->glGetFloatv(pname, data);
-}
-
-void glGetIntegervImpl(GLenum pname, GLint * data) {
- if (pname == GL_NUM_EXTENSIONS) {
- int num_exts = egl_get_num_extensions_for_current_context();
- if (num_exts >= 0) {
- *data = (GLint)num_exts;
- return;
- }
- }
-
- gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
- if (_c) _c->glGetIntegerv(pname, data);
-}
-
-void glGetInteger64vImpl(GLenum pname, GLint64 * data) {
- if (pname == GL_NUM_EXTENSIONS) {
- int num_exts = egl_get_num_extensions_for_current_context();
- if (num_exts >= 0) {
- *data = (GLint64)num_exts;
- return;
- }
- }
-
- gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
- if (_c) _c->glGetInteger64v(pname, data);
-}
-
-struct implementation_map_t {
- const char* name;
- EGLFuncPointer address;
-};
-
-static const implementation_map_t sPlatformImplMap[] = {
- { "eglGetDisplay", (EGLFuncPointer)&eglGetDisplayImpl },
- { "eglInitialize", (EGLFuncPointer)&eglInitializeImpl },
- { "eglTerminate", (EGLFuncPointer)&eglTerminateImpl },
- { "eglGetConfigs", (EGLFuncPointer)&eglGetConfigsImpl },
- { "eglChooseConfig", (EGLFuncPointer)&eglChooseConfigImpl },
- { "eglGetConfigAttrib", (EGLFuncPointer)&eglGetConfigAttribImpl },
- { "eglCreateWindowSurface", (EGLFuncPointer)&eglCreateWindowSurfaceImpl },
- { "eglCreatePixmapSurface", (EGLFuncPointer)&eglCreatePixmapSurfaceImpl },
- { "eglCreatePbufferSurface", (EGLFuncPointer)&eglCreatePbufferSurfaceImpl },
- { "eglDestroySurface", (EGLFuncPointer)&eglDestroySurfaceImpl },
- { "eglQuerySurface", (EGLFuncPointer)&eglQuerySurfaceImpl },
- { "eglBeginFrame", (EGLFuncPointer)&eglBeginFrameImpl },
- { "eglCreateContext", (EGLFuncPointer)&eglCreateContextImpl },
- { "eglDestroyContext", (EGLFuncPointer)&eglDestroyContextImpl },
- { "eglMakeCurrent", (EGLFuncPointer)&eglMakeCurrentImpl },
- { "eglQueryContext", (EGLFuncPointer)&eglQueryContextImpl },
- { "eglGetCurrentContext", (EGLFuncPointer)&eglGetCurrentContextImpl },
- { "eglGetCurrentSurface", (EGLFuncPointer)&eglGetCurrentSurfaceImpl },
- { "eglGetCurrentDisplay", (EGLFuncPointer)&eglGetCurrentDisplayImpl },
- { "eglWaitGL", (EGLFuncPointer)&eglWaitGLImpl },
- { "eglWaitNative", (EGLFuncPointer)&eglWaitNativeImpl },
- { "eglGetError", (EGLFuncPointer)&eglGetErrorImpl },
- { "eglSwapBuffersWithDamageKHR", (EGLFuncPointer)&eglSwapBuffersWithDamageKHRImpl },
- { "eglGetProcAddress", (EGLFuncPointer)&eglGetProcAddressImpl },
- { "eglSwapBuffers", (EGLFuncPointer)&eglSwapBuffersImpl },
- { "eglCopyBuffers", (EGLFuncPointer)&eglCopyBuffersImpl },
- { "eglQueryString", (EGLFuncPointer)&eglQueryStringImpl },
- { "eglQueryStringImplementationANDROID", (EGLFuncPointer)&eglQueryStringImplementationANDROIDImpl },
- { "eglSurfaceAttrib", (EGLFuncPointer)&eglSurfaceAttribImpl },
- { "eglBindTexImage", (EGLFuncPointer)&eglBindTexImageImpl },
- { "eglReleaseTexImage", (EGLFuncPointer)&eglReleaseTexImageImpl },
- { "eglSwapInterval", (EGLFuncPointer)&eglSwapIntervalImpl },
- { "eglWaitClient", (EGLFuncPointer)&eglWaitClientImpl },
- { "eglBindAPI", (EGLFuncPointer)&eglBindAPIImpl },
- { "eglQueryAPI", (EGLFuncPointer)&eglQueryAPIImpl },
- { "eglReleaseThread", (EGLFuncPointer)&eglReleaseThreadImpl },
- { "eglCreatePbufferFromClientBuffer", (EGLFuncPointer)&eglCreatePbufferFromClientBufferImpl },
- { "eglLockSurfaceKHR", (EGLFuncPointer)&eglLockSurfaceKHRImpl },
- { "eglUnlockSurfaceKHR", (EGLFuncPointer)&eglUnlockSurfaceKHRImpl },
- { "eglCreateImageKHR", (EGLFuncPointer)&eglCreateImageKHRImpl },
- { "eglDestroyImageKHR", (EGLFuncPointer)&eglDestroyImageKHRImpl },
- { "eglCreateSyncKHR", (EGLFuncPointer)&eglCreateSyncKHRImpl },
- { "eglDestroySyncKHR", (EGLFuncPointer)&eglDestroySyncKHRImpl },
- { "eglSignalSyncKHR", (EGLFuncPointer)&eglSignalSyncKHRImpl },
- { "eglClientWaitSyncKHR", (EGLFuncPointer)&eglClientWaitSyncKHRImpl },
- { "eglGetSyncAttribKHR", (EGLFuncPointer)&eglGetSyncAttribKHRImpl },
- { "eglCreateStreamKHR", (EGLFuncPointer)&eglCreateStreamKHRImpl },
- { "eglDestroyStreamKHR", (EGLFuncPointer)&eglDestroyStreamKHRImpl },
- { "eglStreamAttribKHR", (EGLFuncPointer)&eglStreamAttribKHRImpl },
- { "eglQueryStreamKHR", (EGLFuncPointer)&eglQueryStreamKHRImpl },
- { "eglQueryStreamu64KHR", (EGLFuncPointer)&eglQueryStreamu64KHRImpl },
- { "eglQueryStreamTimeKHR", (EGLFuncPointer)&eglQueryStreamTimeKHRImpl },
- { "eglCreateStreamProducerSurfaceKHR", (EGLFuncPointer)&eglCreateStreamProducerSurfaceKHRImpl },
- { "eglStreamConsumerGLTextureExternalKHR", (EGLFuncPointer)&eglStreamConsumerGLTextureExternalKHRImpl },
- { "eglStreamConsumerAcquireKHR", (EGLFuncPointer)&eglStreamConsumerAcquireKHRImpl },
- { "eglStreamConsumerReleaseKHR", (EGLFuncPointer)&eglStreamConsumerReleaseKHRImpl },
- { "eglGetStreamFileDescriptorKHR", (EGLFuncPointer)&eglGetStreamFileDescriptorKHRImpl },
- { "eglCreateStreamFromFileDescriptorKHR", (EGLFuncPointer)&eglCreateStreamFromFileDescriptorKHRImpl },
- { "eglWaitSyncKHR", (EGLFuncPointer)&eglWaitSyncKHRImpl },
- { "eglDupNativeFenceFDANDROID", (EGLFuncPointer)&eglDupNativeFenceFDANDROIDImpl },
- { "eglPresentationTimeANDROID", (EGLFuncPointer)&eglPresentationTimeANDROIDImpl },
- { "eglGetNativeClientBufferANDROID", (EGLFuncPointer)&eglGetNativeClientBufferANDROIDImpl },
- { "eglGetSystemTimeFrequencyNV", (EGLFuncPointer)&eglGetSystemTimeFrequencyNVImpl },
- { "eglGetSystemTimeNV", (EGLFuncPointer)&eglGetSystemTimeNVImpl },
- { "eglSetDamageRegionKHR", (EGLFuncPointer)&eglSetDamageRegionKHRImpl },
- { "eglGetNextFrameIdANDROID", (EGLFuncPointer)&eglGetNextFrameIdANDROIDImpl },
- { "eglGetCompositorTimingANDROID", (EGLFuncPointer)&eglGetCompositorTimingANDROIDImpl },
- { "eglGetCompositorTimingSupportedANDROID", (EGLFuncPointer)&eglGetCompositorTimingSupportedANDROIDImpl },
- { "eglGetFrameTimestampsANDROID", (EGLFuncPointer)&eglGetFrameTimestampsANDROIDImpl },
- { "eglGetFrameTimestampSupportedANDROID", (EGLFuncPointer)&eglGetFrameTimestampSupportedANDROIDImpl },
- { "glGetString", (EGLFuncPointer)&glGetStringImpl },
- { "glGetStringi", (EGLFuncPointer)&glGetStringiImpl },
- { "glGetBooleanv", (EGLFuncPointer)&glGetBooleanvImpl },
- { "glGetFloatv", (EGLFuncPointer)&glGetFloatvImpl },
- { "glGetIntegerv", (EGLFuncPointer)&glGetIntegervImpl },
- { "glGetInteger64v", (EGLFuncPointer)&glGetInteger64vImpl },
-};
-
-EGLFuncPointer FindPlatformImplAddr(const char* name)
-{
- static const bool DEBUG = false;
-
- if (name == nullptr) {
- ALOGV("FindPlatformImplAddr called with null name");
- return nullptr;
- }
-
- for (int i = 0; i < NELEM(sPlatformImplMap); i++) {
- if (sPlatformImplMap[i].name == nullptr) {
- ALOGV("FindPlatformImplAddr found nullptr for sPlatformImplMap[%i].name (%s)", i, name);
- return nullptr;
- }
- if (!strcmp(name, sPlatformImplMap[i].name)) {
- ALOGV("FindPlatformImplAddr found %llu for sPlatformImplMap[%i].address (%s)", (unsigned long long)sPlatformImplMap[i].address, i, name);
- return sPlatformImplMap[i].address;
- }
- }
-
- ALOGV("FindPlatformImplAddr did not find an entry for %s", name);
- return nullptr;
-}
-} // namespace android
diff --git a/opengl/libs/EGL/egl_platform_entries.h b/opengl/libs/EGL/egl_platform_entries.h
deleted file mode 100644
index 7cd80d6..0000000
--- a/opengl/libs/EGL/egl_platform_entries.h
+++ /dev/null
@@ -1,31 +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.
- */
-
-#ifndef ANDROID_EGLAPI_H
-#define ANDROID_EGLAPI_H
-
-#include <EGL/egl.h>
-
-typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer;
-
-namespace android {
-
-EGLFuncPointer FindPlatformImplAddr(const char* name);
-
-}; // namespace android
-
-#endif // ANDROID_EGLAPI_H
-
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index d8606d3..449ffc7 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -38,16 +38,12 @@
};
inline egl_connection_t() : dso(nullptr) { }
-
void * dso;
gl_hooks_t * hooks[2];
EGLint major;
EGLint minor;
egl_t egl;
- // Functions implemented or redirected by platform libraries
- platform_impl_t platform;
-
void* libEgl;
void* libGles1;
void* libGles2;
@@ -68,7 +64,6 @@
extern char const * const gl_names[];
extern char const * const gl_names_1[];
extern char const * const egl_names[];
-extern char const * const platform_names[];
extern egl_connection_t gEGLImpl;
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index 65f50f5..f7fde96 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -301,31 +301,71 @@
}
const GLubyte * glGetString(GLenum name) {
- egl_connection_t* const cnx = egl_get_connection();
- return cnx->platform.glGetString(name);
+ const GLubyte * ret = egl_get_string_for_current_context(name);
+ if (ret == NULL) {
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+ if(_c) ret = _c->glGetString(name);
+ }
+ return ret;
}
const GLubyte * glGetStringi(GLenum name, GLuint index) {
- egl_connection_t* const cnx = egl_get_connection();
- return cnx->platform.glGetStringi(name, index);
+ const GLubyte * ret = egl_get_string_for_current_context(name, index);
+ if (ret == NULL) {
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+ if(_c) ret = _c->glGetStringi(name, index);
+ }
+ return ret;
}
void glGetBooleanv(GLenum pname, GLboolean * data) {
- egl_connection_t* const cnx = egl_get_connection();
- return cnx->platform.glGetBooleanv(pname, data);
+ if (pname == GL_NUM_EXTENSIONS) {
+ int num_exts = egl_get_num_extensions_for_current_context();
+ if (num_exts >= 0) {
+ *data = num_exts > 0 ? GL_TRUE : GL_FALSE;
+ return;
+ }
+ }
+
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+ if (_c) _c->glGetBooleanv(pname, data);
}
void glGetFloatv(GLenum pname, GLfloat * data) {
- egl_connection_t* const cnx = egl_get_connection();
- return cnx->platform.glGetFloatv(pname, data);
+ if (pname == GL_NUM_EXTENSIONS) {
+ int num_exts = egl_get_num_extensions_for_current_context();
+ if (num_exts >= 0) {
+ *data = (GLfloat)num_exts;
+ return;
+ }
+ }
+
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+ if (_c) _c->glGetFloatv(pname, data);
}
void glGetIntegerv(GLenum pname, GLint * data) {
- egl_connection_t* const cnx = egl_get_connection();
- return cnx->platform.glGetIntegerv(pname, data);
+ if (pname == GL_NUM_EXTENSIONS) {
+ int num_exts = egl_get_num_extensions_for_current_context();
+ if (num_exts >= 0) {
+ *data = (GLint)num_exts;
+ return;
+ }
+ }
+
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+ if (_c) _c->glGetIntegerv(pname, data);
}
void glGetInteger64v(GLenum pname, GLint64 * data) {
- egl_connection_t* const cnx = egl_get_connection();
- return cnx->platform.glGetInteger64v(pname, data);
+ if (pname == GL_NUM_EXTENSIONS) {
+ int num_exts = egl_get_num_extensions_for_current_context();
+ if (num_exts >= 0) {
+ *data = (GLint64)num_exts;
+ return;
+ }
+ }
+
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+ if (_c) _c->glGetInteger64v(pname, data);
}
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index 0af0501..a8855ef 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -21,18 +21,15 @@
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
-#include "EGL/egldefs.h"
#include "hooks.h"
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
-
EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name);
EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index);
EGLAPI GLint egl_get_num_extensions_for_current_context();
-EGLAPI egl_connection_t* egl_get_connection();
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index 63a0e14..81dbe0e 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -59,10 +59,6 @@
#define GL_ENTRY(_r, _api, ...) _r (*(_api))(__VA_ARGS__);
#define EGL_ENTRY(_r, _api, ...) _r (*(_api))(__VA_ARGS__);
-struct platform_impl_t {
- #include "platform_entries.in"
-};
-
struct egl_t {
#include "EGL/egl_entries.in"
};
diff --git a/opengl/libs/platform_entries.in b/opengl/libs/platform_entries.in
deleted file mode 100644
index b28f6cc..0000000
--- a/opengl/libs/platform_entries.in
+++ /dev/null
@@ -1,76 +0,0 @@
-EGL_ENTRY(EGLDisplay, eglGetDisplay, EGLNativeDisplayType)
-EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
-EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
-EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)
-EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint*, EGLConfig*, EGLint, EGLint*)
-EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint*)
-EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint*)
-EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint*)
-EGL_ENTRY(EGLSurface, eglCreatePbufferSurface, EGLDisplay, EGLConfig, const EGLint*)
-EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface)
-EGL_ENTRY(EGLBoolean, eglQuerySurface, EGLDisplay, EGLSurface, EGLint, EGLint*)
-EGL_ENTRY(void, eglBeginFrame, EGLDisplay, EGLSurface)
-EGL_ENTRY(EGLContext, eglCreateContext, EGLDisplay, EGLConfig, EGLContext, const EGLint*)
-EGL_ENTRY(EGLBoolean, eglDestroyContext, EGLDisplay, EGLContext)
-EGL_ENTRY(EGLBoolean, eglMakeCurrent, EGLDisplay, EGLSurface, EGLSurface, EGLContext)
-EGL_ENTRY(EGLBoolean, eglQueryContext, EGLDisplay, EGLContext, EGLint, EGLint*)
-EGL_ENTRY(EGLContext, eglGetCurrentContext, void)
-EGL_ENTRY(EGLSurface, eglGetCurrentSurface, EGLint)
-EGL_ENTRY(EGLDisplay, eglGetCurrentDisplay, void)
-EGL_ENTRY(EGLBoolean, eglWaitGL, void)
-EGL_ENTRY(EGLBoolean, eglWaitNative, EGLint)
-EGL_ENTRY(EGLint, eglGetError, void)
-EGL_ENTRY(__eglMustCastToProperFunctionPointerType, eglGetProcAddress, const char*)
-EGL_ENTRY(EGLBoolean, eglSwapBuffersWithDamageKHR, EGLDisplay, EGLSurface, EGLint*, EGLint)
-EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface)
-EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType)
-EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint)
-EGL_ENTRY(const char*, eglQueryStringImplementationANDROID, EGLDisplay, EGLint)
-EGL_ENTRY(EGLBoolean, eglSurfaceAttrib, EGLDisplay, EGLSurface, EGLint, EGLint)
-EGL_ENTRY(EGLBoolean, eglBindTexImage, EGLDisplay, EGLSurface, EGLint)
-EGL_ENTRY(EGLBoolean, eglReleaseTexImage, EGLDisplay, EGLSurface, EGLint)
-EGL_ENTRY(EGLBoolean, eglSwapInterval, EGLDisplay, EGLint)
-EGL_ENTRY(EGLBoolean, eglWaitClient, void)
-EGL_ENTRY(EGLBoolean, eglBindAPI, EGLenum)
-EGL_ENTRY(EGLenum, eglQueryAPI, void)
-EGL_ENTRY(EGLBoolean, eglReleaseThread, void)
-EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint*)
-EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint*)
-EGL_ENTRY(EGLBoolean, eglUnlockSurfaceKHR, EGLDisplay, EGLSurface)
-EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint*)
-EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR)
-EGL_ENTRY(EGLSyncKHR, eglCreateSyncKHR, EGLDisplay, EGLenum, const EGLint*)
-EGL_ENTRY(EGLBoolean, eglDestroySyncKHR, EGLDisplay, EGLSyncKHR)
-EGL_ENTRY(EGLBoolean, eglSignalSyncKHR, EGLDisplay, EGLSyncKHR, EGLenum)
-EGL_ENTRY(EGLint, eglClientWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR)
-EGL_ENTRY(EGLBoolean, eglGetSyncAttribKHR, EGLDisplay, EGLSyncKHR, EGLint, EGLint*)
-EGL_ENTRY(EGLStreamKHR, eglCreateStreamKHR, EGLDisplay, const EGLint*)
-EGL_ENTRY(EGLBoolean, eglDestroyStreamKHR, EGLDisplay, EGLStreamKHR)
-EGL_ENTRY(EGLBoolean, eglStreamAttribKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint)
-EGL_ENTRY(EGLBoolean, eglQueryStreamKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint*)
-EGL_ENTRY(EGLBoolean, eglQueryStreamu64KHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLuint64KHR*)
-EGL_ENTRY(EGLBoolean, eglQueryStreamTimeKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLTimeKHR*)
-EGL_ENTRY(EGLSurface, eglCreateStreamProducerSurfaceKHR, EGLDisplay, EGLConfig, EGLStreamKHR, const EGLint*)
-EGL_ENTRY(EGLBoolean, eglStreamConsumerGLTextureExternalKHR, EGLDisplay, EGLStreamKHR)
-EGL_ENTRY(EGLBoolean, eglStreamConsumerAcquireKHR, EGLDisplay, EGLStreamKHR)
-EGL_ENTRY(EGLBoolean, eglStreamConsumerReleaseKHR, EGLDisplay, EGLStreamKHR)
-EGL_ENTRY(EGLNativeFileDescriptorKHR, eglGetStreamFileDescriptorKHR, EGLDisplay, EGLStreamKHR)
-EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR, EGLDisplay, EGLNativeFileDescriptorKHR)
-EGL_ENTRY(EGLint, eglWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint)
-EGL_ENTRY(EGLint, eglDupNativeFenceFDANDROID, EGLDisplay, EGLSyncKHR)
-EGL_ENTRY(EGLBoolean, eglPresentationTimeANDROID, EGLDisplay, EGLSurface, EGLnsecsANDROID)
-EGL_ENTRY(EGLClientBuffer, eglGetNativeClientBufferANDROID, const AHardwareBuffer*)
-EGL_ENTRY(EGLuint64NV, eglGetSystemTimeFrequencyNV, void)
-EGL_ENTRY(EGLuint64NV, eglGetSystemTimeNV, void)
-EGL_ENTRY(EGLBoolean, eglSetDamageRegionKHR, EGLDisplay, EGLSurface, EGLint*, EGLint)
-EGL_ENTRY(EGLBoolean, eglGetNextFrameIdANDROID, EGLDisplay, EGLSurface, EGLuint64KHR*)
-EGL_ENTRY(EGLBoolean, eglGetCompositorTimingANDROID, EGLDisplay, EGLSurface, EGLint, const EGLint*, EGLnsecsANDROID*)
-EGL_ENTRY(EGLBoolean, eglGetCompositorTimingSupportedANDROID, EGLDisplay, EGLSurface, EGLint)
-EGL_ENTRY(EGLBoolean, eglGetFrameTimestampsANDROID, EGLDisplay, EGLSurface, EGLuint64KHR, EGLint, const EGLint*, EGLnsecsANDROID*)
-EGL_ENTRY(EGLBoolean, eglGetFrameTimestampSupportedANDROID, EGLDisplay, EGLSurface, EGLint)
-GL_ENTRY(const GLubyte*, glGetString, GLenum)
-GL_ENTRY(const GLubyte*, glGetStringi, GLenum, GLuint)
-GL_ENTRY(void, glGetBooleanv, GLenum, GLboolean*)
-GL_ENTRY(void, glGetFloatv, GLenum, GLfloat*)
-GL_ENTRY(void, glGetIntegerv, GLenum, GLint*)
-GL_ENTRY(void, glGetInteger64v, GLenum, GLint64*)
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 57fc17f..0b73be0 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -256,18 +256,17 @@
// --- InputReaderConfiguration ---
-bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
- const std::string& uniqueDisplayId, DisplayViewport* outViewport) const {
+std::optional<DisplayViewport> InputReaderConfiguration::getDisplayViewport(
+ ViewportType viewportType, const std::string& uniqueDisplayId) const {
for (const DisplayViewport& currentViewport : mDisplays) {
if (currentViewport.type == viewportType) {
if (uniqueDisplayId.empty() ||
(!uniqueDisplayId.empty() && uniqueDisplayId == currentViewport.uniqueId)) {
- *outViewport = currentViewport;
- return true;
+ return std::make_optional(currentViewport);
}
}
}
- return false;
+ return std::nullopt;
}
void InputReaderConfiguration::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
@@ -2249,7 +2248,6 @@
dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
}
-
void KeyboardInputMapper::configure(nsecs_t when,
const InputReaderConfiguration* config, uint32_t changes) {
InputMapper::configure(when, config, changes);
@@ -2261,9 +2259,7 @@
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
if (mParameters.orientationAware) {
- DisplayViewport dvp;
- config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &dvp);
- mViewport = dvp;
+ mViewport = config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
}
}
}
@@ -2672,9 +2668,10 @@
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
mOrientation = DISPLAY_ORIENTATION_0;
if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
- DisplayViewport v;
- if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &v)) {
- mOrientation = v.orientation;
+ std::optional<DisplayViewport> internalViewport =
+ config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
+ if (internalViewport) {
+ mOrientation = internalViewport->orientation;
}
}
bumpGeneration();
@@ -2987,9 +2984,10 @@
mRotaryEncoderScrollAccumulator.configure(getDevice());
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
- DisplayViewport v;
- if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "", &v)) {
- mOrientation = v.orientation;
+ std::optional<DisplayViewport> internalViewport =
+ config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
+ if (internalViewport) {
+ mOrientation = internalViewport->orientation;
} else {
mOrientation = DISPLAY_ORIENTATION_0;
}
@@ -3502,7 +3500,9 @@
viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
}
- if (!mConfig.getDisplayViewport(viewportTypeToUse, uniqueDisplayId, &newViewport)) {
+ std::optional<DisplayViewport> viewportToUse =
+ mConfig.getDisplayViewport(viewportTypeToUse, uniqueDisplayId);
+ if (!viewportToUse) {
ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
"display. The device will be inoperable until the display size "
"becomes available.",
@@ -3510,6 +3510,7 @@
mDeviceMode = DEVICE_MODE_DISABLED;
return;
}
+ newViewport = *viewportToUse;
} else {
newViewport.setNonDisplayViewport(rawWidth, rawHeight);
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 74668b7..3410bc9 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -202,8 +202,8 @@
pointerGestureZoomSpeedRatio(0.3f),
showTouches(false) { }
- bool getDisplayViewport(ViewportType viewportType, const std::string& uniqueDisplayId,
- DisplayViewport* outViewport) const;
+ std::optional<DisplayViewport> getDisplayViewport(ViewportType viewportType,
+ const std::string& uniqueDisplayId) const;
void setDisplayViewports(const std::vector<DisplayViewport>& viewports);
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 517e639..a1cd71c 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -10,6 +10,7 @@
cflags: [
"-Wall",
"-Werror",
+ "-Wextra",
"-Wno-unused-parameter",
],
shared_libs: [
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index b70ee09..707f3c5 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -33,7 +33,7 @@
static const int32_t VIRTUAL_DISPLAY_ID = 1;
static const int32_t VIRTUAL_DISPLAY_WIDTH = 400;
static const int32_t VIRTUAL_DISPLAY_HEIGHT = 500;
-static const char* VIRTUAL_DISPLAY_UNIQUE_ID = "Vr-display-unique-ID";
+static const char* VIRTUAL_DISPLAY_UNIQUE_ID = "virtual:1";
// Error tolerance for floating point assertions.
static const float EPSILON = 0.001f;
@@ -142,21 +142,21 @@
FakeInputReaderPolicy() {
}
- void setDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
- const std::string& uniqueId) {
+ virtual void clearViewports() {
mViewports.clear();
- // Set the size of both the internal and external display at the same time.
- mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
- ViewportType::VIEWPORT_INTERNAL));
- mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
- ViewportType::VIEWPORT_EXTERNAL));
mConfig.setDisplayViewports(mViewports);
}
- void setVirtualDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
+ std::optional<DisplayViewport> getDisplayViewport(ViewportType viewportType,
const std::string& uniqueId) {
- mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
- ViewportType::VIEWPORT_VIRTUAL));
+ return mConfig.getDisplayViewport(viewportType, uniqueId);
+ }
+
+ void addDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
+ const std::string& uniqueId, ViewportType viewportType) {
+ const DisplayViewport viewport = createDisplayViewport(displayId, width, height,
+ orientation, uniqueId, viewportType);
+ mViewports.push_back(viewport);
mConfig.setDisplayViewports(mViewports);
}
@@ -1080,6 +1080,146 @@
friend class InputReaderTest;
};
+// --- InputReaderPolicyTest ---
+class InputReaderPolicyTest : public testing::Test {
+ protected:
+ sp<FakeInputReaderPolicy> mFakePolicy;
+
+ virtual void SetUp() {
+ mFakePolicy = new FakeInputReaderPolicy();
+ }
+ virtual void TearDown() {
+ mFakePolicy.clear();
+ }
+};
+
+/**
+ * Check that empty set of viewports is an acceptable configuration.
+ * Also try to get internal viewport two different ways - by type and by uniqueId.
+ *
+ * There will be confusion if two viewports with empty uniqueId and identical type are present.
+ * Such configuration is not currently allowed.
+ */
+TEST_F(InputReaderPolicyTest, Viewports_GetCleared) {
+ const std::string uniqueId = "local:0";
+
+ // We didn't add any viewports yet, so there shouldn't be any.
+ std::optional<DisplayViewport> internalViewport =
+ mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, uniqueId);
+ ASSERT_FALSE(internalViewport);
+
+ // Add an internal viewport, then clear it
+ mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, uniqueId, ViewportType::VIEWPORT_INTERNAL);
+
+ // Check matching by uniqueId
+ internalViewport = mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, uniqueId);
+ ASSERT_TRUE(internalViewport);
+
+ // Check matching by viewport type
+ internalViewport = mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
+ ASSERT_TRUE(internalViewport);
+
+ mFakePolicy->clearViewports();
+ // Make sure nothing is found after clear
+ internalViewport = mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, uniqueId);
+ ASSERT_FALSE(internalViewport);
+ internalViewport = mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
+ ASSERT_FALSE(internalViewport);
+}
+
+TEST_F(InputReaderPolicyTest, Viewports_GetByType) {
+ const std::string internalUniqueId = "local:0";
+ const std::string externalUniqueId = "local:1";
+ const std::string virtualUniqueId1 = "virtual:2";
+ const std::string virtualUniqueId2 = "virtual:3";
+ constexpr int32_t virtualDisplayId1 = 2;
+ constexpr int32_t virtualDisplayId2 = 3;
+
+ // Add an internal viewport
+ mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, internalUniqueId, ViewportType::VIEWPORT_INTERNAL);
+ // Add an external viewport
+ mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, externalUniqueId, ViewportType::VIEWPORT_EXTERNAL);
+ // Add an virtual viewport
+ mFakePolicy->addDisplayViewport(virtualDisplayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, virtualUniqueId1, ViewportType::VIEWPORT_VIRTUAL);
+ // Add another virtual viewport
+ mFakePolicy->addDisplayViewport(virtualDisplayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, virtualUniqueId2, ViewportType::VIEWPORT_VIRTUAL);
+
+ // Check matching by type for internal
+ std::optional<DisplayViewport> internalViewport =
+ mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, "");
+ ASSERT_TRUE(internalViewport);
+ ASSERT_EQ(internalUniqueId, internalViewport->uniqueId);
+
+ // Check matching by type for external
+ std::optional<DisplayViewport> externalViewport =
+ mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_EXTERNAL, "");
+ ASSERT_TRUE(externalViewport);
+ ASSERT_EQ(externalUniqueId, externalViewport->uniqueId);
+
+ // Check matching by uniqueId for virtual viewport #1
+ std::optional<DisplayViewport> virtualViewport1 =
+ mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_VIRTUAL, virtualUniqueId1);
+ ASSERT_TRUE(virtualViewport1);
+ ASSERT_EQ(virtualUniqueId1, virtualViewport1->uniqueId);
+ ASSERT_EQ(virtualDisplayId1, virtualViewport1->displayId);
+
+ // Check matching by uniqueId for virtual viewport #2
+ std::optional<DisplayViewport> virtualViewport2 =
+ mFakePolicy->getDisplayViewport(ViewportType::VIEWPORT_VIRTUAL, virtualUniqueId2);
+ ASSERT_TRUE(virtualViewport2);
+ ASSERT_EQ(virtualUniqueId2, virtualViewport2->uniqueId);
+ ASSERT_EQ(virtualDisplayId2, virtualViewport2->displayId);
+}
+
+
+/**
+ * We can have 2 viewports of the same kind. We can distinguish them by uniqueId, and confirm
+ * that lookup works by checking display id.
+ * Check that 2 viewports of each kind is possible, for all existing viewport types.
+ */
+TEST_F(InputReaderPolicyTest, Viewports_TwoOfSameType) {
+ const std::string uniqueId1 = "uniqueId1";
+ const std::string uniqueId2 = "uniqueId2";
+ constexpr int32_t displayId1 = 2;
+ constexpr int32_t displayId2 = 3;
+
+ std::vector<ViewportType> types = {ViewportType::VIEWPORT_INTERNAL,
+ ViewportType::VIEWPORT_EXTERNAL, ViewportType::VIEWPORT_VIRTUAL};
+ for (const ViewportType& type : types) {
+ mFakePolicy->clearViewports();
+ // Add a viewport
+ mFakePolicy->addDisplayViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, uniqueId1, type);
+ // Add another viewport
+ mFakePolicy->addDisplayViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, uniqueId2, type);
+
+ // Check that correct display viewport was returned by comparing the display IDs.
+ std::optional<DisplayViewport> viewport1 = mFakePolicy->getDisplayViewport(type, uniqueId1);
+ ASSERT_TRUE(viewport1);
+ ASSERT_EQ(displayId1, viewport1->displayId);
+ ASSERT_EQ(type, viewport1->type);
+
+ std::optional<DisplayViewport> viewport2 = mFakePolicy->getDisplayViewport(type, uniqueId2);
+ ASSERT_TRUE(viewport2);
+ ASSERT_EQ(displayId2, viewport2->displayId);
+ ASSERT_EQ(type, viewport2->type);
+
+ // When there are multiple viewports of the same kind, and uniqueId is not specified
+ // in the call to getDisplayViewport, then that situation is not supported.
+ // The viewports can be stored in any order, so we cannot rely on the order, since that
+ // is just implementation detail.
+ // However, we can check that it still returns *a* viewport, we just cannot assert
+ // which one specifically is returned.
+ std::optional<DisplayViewport> someViewport = mFakePolicy->getDisplayViewport(type, "");
+ ASSERT_TRUE(someViewport);
+ }
+}
// --- InputReaderTest ---
@@ -1603,15 +1743,14 @@
}
void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
- int32_t orientation) {
- mFakePolicy->setDisplayViewport(displayId, width, height, orientation, "");
+ int32_t orientation, const std::string& uniqueId, ViewportType viewportType) {
+ mFakePolicy->addDisplayViewport(
+ displayId, width, height, orientation, uniqueId, viewportType);
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
}
- void setVirtualDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
- int32_t orientation, const std::string& uniqueId) {
- mFakePolicy->setVirtualDisplayViewport(displayId, width, height, orientation, uniqueId);
- configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ void clearViewports() {
+ mFakePolicy->clearViewports();
}
static void process(InputMapper* mapper, nsecs_t when, int32_t deviceId, int32_t type,
@@ -1715,12 +1854,24 @@
class KeyboardInputMapperTest : public InputMapperTest {
protected:
+ const std::string UNIQUE_ID = "local:0";
+
+ void prepareDisplay(int32_t orientation);
+
void testDPadKeyRotation(KeyboardInputMapper* mapper,
int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode);
};
+/* Similar to setDisplayInfoAndReconfigure, but pre-populates all parameters except for the
+ * orientation.
+ */
+void KeyboardInputMapperTest::prepareDisplay(int32_t orientation) {
+ setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ orientation, UNIQUE_ID, ViewportType::VIEWPORT_INTERNAL);
+}
+
void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper,
- int32_t originalScanCode, int32_t, int32_t rotatedKeyCode) {
+ int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode) {
NotifyKeyArgs args;
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 1);
@@ -1908,9 +2059,7 @@
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
- setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_90);
+ prepareDisplay(DISPLAY_ORIENTATION_90);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1932,9 +2081,7 @@
addConfigurationProperty("keyboard.orientationAware", "1");
addMapperAndConfigure(mapper);
- setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1944,9 +2091,8 @@
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
- setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_90);
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_90);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1956,9 +2102,8 @@
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN));
- setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_180);
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_180);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1968,9 +2113,8 @@
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT));
- setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_270);
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_270);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1983,19 +2127,16 @@
// Special case: if orientation changes while key is down, we still emit the same keycode
// in the key up as we did in the key down.
NotifyKeyArgs args;
-
- setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_270);
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_270);
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
ASSERT_EQ(KEY_UP, args.scanCode);
ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
- setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_180);
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_180);
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
@@ -2020,8 +2161,7 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(ADISPLAY_ID_NONE, args.displayId);
- setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
@@ -2043,8 +2183,8 @@
// Display id should be ADISPLAY_ID_NONE without any display configuration.
// ^--- already checked by the previous test
- setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+ setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
+ UNIQUE_ID, ViewportType::VIEWPORT_INTERNAL);
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
@@ -2052,8 +2192,9 @@
ASSERT_EQ(DISPLAY_ID, args.displayId);
constexpr int32_t newDisplayId = 2;
- setDisplayInfoAndReconfigure(newDisplayId,
- DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+ clearViewports();
+ setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
+ UNIQUE_ID, ViewportType::VIEWPORT_INTERNAL);
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
@@ -2484,9 +2625,12 @@
addConfigurationProperty("cursor.mode", "navigation");
addMapperAndConfigure(mapper);
+ const std::string uniqueId = "local:0";
+ const ViewportType viewportType = ViewportType::VIEWPORT_INTERNAL;
+
setDisplayInfoAndReconfigure(DISPLAY_ID,
DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_90);
+ DISPLAY_ORIENTATION_90, uniqueId, viewportType);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0));
@@ -2503,8 +2647,11 @@
addConfigurationProperty("cursor.orientationAware", "1");
addMapperAndConfigure(mapper);
+ const std::string uniqueId = "local:0";
+ const ViewportType viewportType = ViewportType::VIEWPORT_INTERNAL;
+
setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, uniqueId, viewportType);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0));
@@ -2515,7 +2662,7 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1));
setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90);
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90, uniqueId, viewportType);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1));
@@ -2526,7 +2673,7 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1));
setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180);
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180, uniqueId, viewportType);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, -1, 0));
@@ -2537,7 +2684,7 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1));
setDisplayInfoAndReconfigure(DISPLAY_ID,
- DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270);
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270, uniqueId, viewportType);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1));
@@ -2982,6 +3129,8 @@
static const VirtualKeyDefinition VIRTUAL_KEYS[2];
+ const std::string UNIQUE_ID = "local:0";
+
enum Axes {
POSITION = 1 << 0,
TOUCH = 1 << 1,
@@ -3050,12 +3199,14 @@
};
void TouchInputMapperTest::prepareDisplay(int32_t orientation) {
- setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation);
+ setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation,
+ UNIQUE_ID, ViewportType::VIEWPORT_INTERNAL);
}
void TouchInputMapperTest::prepareVirtualDisplay(int32_t orientation) {
- setVirtualDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
- VIRTUAL_DISPLAY_HEIGHT, orientation, VIRTUAL_DISPLAY_UNIQUE_ID);
+ setDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
+ VIRTUAL_DISPLAY_HEIGHT, orientation,
+ VIRTUAL_DISPLAY_UNIQUE_ID, ViewportType::VIEWPORT_VIRTUAL);
}
void TouchInputMapperTest::prepareVirtualKeys() {
@@ -3784,6 +3935,7 @@
NotifyMotionArgs args;
// Rotation 0.
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_0);
processDown(mapper, toRawX(50), toRawY(75));
processSync(mapper);
@@ -3797,6 +3949,7 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
// Rotation 90.
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_90);
processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50));
processSync(mapper);
@@ -3810,6 +3963,7 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
// Rotation 180.
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_180);
processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN);
processSync(mapper);
@@ -3823,6 +3977,7 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
// Rotation 270.
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_270);
processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN);
processSync(mapper);
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index a294793..d000d85 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -138,7 +138,7 @@
virtual void setFilteringEnabled(bool enabled) = 0;
- virtual status_t bindTextureImage() const = 0;
+ virtual status_t bindTextureImage() = 0;
virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
const sp<Fence>& flushFence) = 0;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 8c8915c..6826050 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -111,12 +111,6 @@
return NO_INIT;
}
- // Make sure RenderEngine is current
- if (!mRE.isCurrent()) {
- BLC_LOGE("updateTexImage: RenderEngine is not current");
- return INVALID_OPERATION;
- }
-
BufferItem item;
// Acquire the next buffer.
@@ -185,8 +179,7 @@
return;
}
- auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer
- : mCurrentTextureImage->graphicBuffer();
+ auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer : mCurrentTextureBuffer;
auto err = addReleaseFence(slot, buffer, fence);
if (err != OK) {
BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
@@ -222,10 +215,9 @@
}
// If item->mGraphicBuffer is not null, this buffer has not been acquired
- // before, so any prior EglImage created is using a stale buffer. This
- // replaces any old EglImage with a new one (using the new buffer).
+ // before.
if (item->mGraphicBuffer != nullptr) {
- mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE);
+ mImages[item->mSlot] = nullptr;
}
return NO_ERROR;
@@ -252,19 +244,18 @@
}
BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
- mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : 0,
- slot, mSlots[slot].mGraphicBuffer->handle);
+ mCurrentTextureBuffer != nullptr ? mCurrentTextureBuffer->handle : 0, slot,
+ mSlots[slot].mGraphicBuffer->handle);
// Hang onto the pointer so that it isn't freed in the call to
// releaseBufferLocked() if we're in shared buffer mode and both buffers are
// the same.
- sp<Image> nextTextureImage = mImages[slot];
+ sp<GraphicBuffer> nextTextureBuffer = mSlots[slot].mGraphicBuffer;
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
if (pendingRelease == nullptr) {
- status_t status =
- releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer());
+ status_t status = releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer);
if (status < NO_ERROR) {
BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
status);
@@ -273,14 +264,15 @@
}
} else {
pendingRelease->currentTexture = mCurrentTexture;
- pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
+ pendingRelease->graphicBuffer = mCurrentTextureBuffer;
pendingRelease->isPending = true;
}
}
// Update the BufferLayerConsumer state.
mCurrentTexture = slot;
- mCurrentTextureImage = nextTextureImage;
+ mCurrentTextureBuffer = nextTextureBuffer;
+ mCurrentTextureImageFreed = nullptr;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
@@ -301,22 +293,46 @@
status_t BufferLayerConsumer::bindTextureImageLocked() {
ATRACE_CALL();
+
mRE.checkErrors();
- if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
+ // It is possible for the current slot's buffer to be freed before a new one
+ // is bound. In that scenario we still want to bind the image.
+ if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureBuffer == nullptr) {
BLC_LOGE("bindTextureImage: no currently-bound texture");
mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
return NO_INIT;
}
- status_t err = mCurrentTextureImage->createIfNeeded();
- if (err != NO_ERROR) {
- BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
- mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
- return UNKNOWN_ERROR;
+ renderengine::Image* imageToRender;
+
+ // mCurrentTextureImageFreed is non-null iff mCurrentTexture ==
+ // BufferQueue::INVALID_BUFFER_SLOT, so we can omit that check.
+ if (mCurrentTextureImageFreed) {
+ imageToRender = mCurrentTextureImageFreed.get();
+ } else if (mImages[mCurrentTexture]) {
+ imageToRender = mImages[mCurrentTexture].get();
+ } else {
+ std::unique_ptr<renderengine::Image> image = mRE.createImage();
+ bool success = image->setNativeWindowBuffer(mCurrentTextureBuffer->getNativeBuffer(),
+ mCurrentTextureBuffer->getUsage() &
+ GRALLOC_USAGE_PROTECTED);
+ if (!success) {
+ BLC_LOGE("bindTextureImage: Failed to create image. size=%ux%u st=%u usage=%#" PRIx64
+ " fmt=%d",
+ mCurrentTextureBuffer->getWidth(), mCurrentTextureBuffer->getHeight(),
+ mCurrentTextureBuffer->getStride(), mCurrentTextureBuffer->getUsage(),
+ mCurrentTextureBuffer->getPixelFormat());
+ BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
+ mRE.bindExternalTextureImage(mTexName, *image);
+ return UNKNOWN_ERROR;
+ }
+ imageToRender = image.get();
+ // Cache the image here so that we can reuse it.
+ mImages[mCurrentTexture] = std::move(image);
}
- mRE.bindExternalTextureImage(mTexName, mCurrentTextureImage->image());
+ mRE.bindExternalTextureImage(mTexName, *imageToRender);
// Wait for the new buffer to be ready.
return doFenceWaitLocked();
@@ -333,8 +349,7 @@
return UNKNOWN_ERROR;
}
status_t err =
- addReleaseFenceLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
- releaseFence);
+ addReleaseFenceLocked(mCurrentTexture, mCurrentTextureBuffer, releaseFence);
if (err != OK) {
BLC_LOGE("syncForReleaseLocked: error adding release fence: "
"%s (%d)",
@@ -361,24 +376,22 @@
bool needsRecompute = mFilteringEnabled != enabled;
mFilteringEnabled = enabled;
- if (needsRecompute && mCurrentTextureImage == nullptr) {
- BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == nullptr");
+ if (needsRecompute && mCurrentTextureBuffer == nullptr) {
+ BLC_LOGD("setFilteringEnabled called with mCurrentTextureBuffer == nullptr");
}
- if (needsRecompute && mCurrentTextureImage != nullptr) {
+ if (needsRecompute && mCurrentTextureBuffer != nullptr) {
computeCurrentTransformMatrixLocked();
}
}
void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
BLC_LOGV("computeCurrentTransformMatrixLocked");
- sp<GraphicBuffer> buf =
- (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
- if (buf == nullptr) {
+ if (mCurrentTextureBuffer == nullptr) {
BLC_LOGD("computeCurrentTransformMatrixLocked: "
- "mCurrentTextureImage is nullptr");
+ "mCurrentTextureBuffer is nullptr");
}
- GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop,
+ GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, mCurrentTextureBuffer, mCurrentCrop,
mCurrentTransform, mFilteringEnabled);
}
@@ -427,7 +440,7 @@
*outSlot = mCurrentTexture;
}
- return (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
+ return mCurrentTextureBuffer;
}
Rect BufferLayerConsumer::getCurrentCrop() const {
@@ -458,11 +471,6 @@
}
status_t BufferLayerConsumer::doFenceWaitLocked() const {
- if (!mRE.isCurrent()) {
- BLC_LOGE("doFenceWait: RenderEngine is not current");
- return INVALID_OPERATION;
- }
-
if (mCurrentFence->isValid()) {
if (mRE.useWaitSync()) {
base::unique_fd fenceFd(mCurrentFence->dup());
@@ -490,8 +498,10 @@
BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
if (slotIndex == mCurrentTexture) {
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
+ mCurrentTextureImageFreed = std::move(mImages[slotIndex]);
+ } else {
+ mImages[slotIndex] = nullptr;
}
- mImages[slotIndex].clear();
ConsumerBase::freeBufferLocked(slotIndex);
}
@@ -530,7 +540,7 @@
void BufferLayerConsumer::abandonLocked() {
BLC_LOGV("abandonLocked");
- mCurrentTextureImage.clear();
+ mCurrentTextureBuffer.clear();
ConsumerBase::abandonLocked();
}
@@ -548,29 +558,4 @@
ConsumerBase::dumpLocked(result, prefix);
}
-BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer,
- renderengine::RenderEngine& engine)
- : mGraphicBuffer(graphicBuffer),
- mImage{engine.createImage()},
- mCreated(false),
- mCropWidth(0),
- mCropHeight(0) {}
-
-BufferLayerConsumer::Image::~Image() = default;
-
-status_t BufferLayerConsumer::Image::createIfNeeded() {
- if (mCreated) return OK;
-
- mCreated = mImage->setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(),
- mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
- if (!mCreated) {
- const sp<GraphicBuffer>& buffer = mGraphicBuffer;
- ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
- buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
- buffer->getPixelFormat());
- }
-
- return mCreated ? OK : UNKNOWN_ERROR;
-}
-
}; // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index e174680..ea46245 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -185,8 +185,7 @@
// specific info in addition to the ConsumerBase behavior.
virtual void dumpLocked(String8& result, const char* prefix) const;
- // acquireBufferLocked overrides the ConsumerBase method to update the
- // mImages array in addition to the ConsumerBase behavior.
+ // See ConsumerBase::acquireBufferLocked
virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
uint64_t maxFrameNumber = 0) override;
@@ -210,53 +209,14 @@
PendingRelease* pendingRelease = nullptr,
const sp<Fence>& releaseFence = Fence::NO_FENCE);
- // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target. Uses
- // mCurrentTexture if it's set, mCurrentTextureImage if not. If the
- // bind succeeds, this calls doFenceWait.
+ // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.
+ // If the bind succeeds, this calls doFenceWait.
status_t bindTextureImageLocked();
private:
- // Image is a utility class for tracking and creating renderengine::Images. There
- // is primarily just one image per slot, but there is also special cases:
- // - After freeBuffer, we must still keep the current image/buffer
- // Reference counting renderengine::Images lets us handle all these cases easily while
- // also only creating new renderengine::Images from buffers when required.
- class Image : public LightRefBase<Image> {
- public:
- Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine);
-
- Image(const Image& rhs) = delete;
- Image& operator=(const Image& rhs) = delete;
-
- // createIfNeeded creates an renderengine::Image if we haven't created one yet.
- status_t createIfNeeded();
-
- const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
- const native_handle* graphicBufferHandle() {
- return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
- }
-
- const renderengine::Image& image() const { return *mImage; }
-
- private:
- // Only allow instantiation using ref counting.
- friend class LightRefBase<Image>;
- virtual ~Image();
-
- // mGraphicBuffer is the buffer that was used to create this image.
- sp<GraphicBuffer> mGraphicBuffer;
-
- // mImage is the image created from mGraphicBuffer.
- std::unique_ptr<renderengine::Image> mImage;
- bool mCreated;
- int32_t mCropWidth;
- int32_t mCropHeight;
- };
-
// freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in
- // that slot and destroy the renderengine::Image in that slot. Otherwise it has no
- // effect.
+ // that slot. Otherwise it has no effect.
//
// This method must be called with mMutex locked.
virtual void freeBufferLocked(int slotIndex);
@@ -290,10 +250,10 @@
// consume buffers as hardware textures.
static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
- // mCurrentTextureImage is the Image/buffer of the current texture. It's
+ // mCurrentTextureImage is the buffer containing the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
// must track it separately in order to support the getCurrentBuffer method.
- sp<Image> mCurrentTextureImage;
+ sp<GraphicBuffer> mCurrentTextureBuffer;
// mCurrentCrop is the crop rectangle that applies to the current texture.
// It gets set each time updateTexImage is called.
@@ -363,15 +323,6 @@
wp<ContentsChangedListener> mContentsChangedListener;
- // mImages stores the buffers that have been allocated by the BufferQueue
- // for each buffer slot. It is initialized to null pointers, and gets
- // filled in with the result of BufferQueue::acquire when the
- // client dequeues a buffer from a
- // slot that has not yet been used. The buffer allocated to a slot will also
- // be replaced if the requested buffer usage or geometry differs from that
- // of the buffer allocated to a slot.
- sp<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
-
// mCurrentTexture is the buffer slot index of the buffer that is currently
// bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT,
// indicating that no buffer slot is currently bound to the texture. Note,
@@ -380,6 +331,17 @@
// reset mCurrentTexture to INVALID_BUFFER_SLOT.
int mCurrentTexture;
+ // Cached image used for rendering the current texture through GPU
+ // composition, which contains the cached image after freeBufferLocked is
+ // called on the current buffer. Whenever latchBuffer is called, this is
+ // expected to be cleared. Then, if bindTexImage is called before the next
+ // buffer is acquired, then this image is bound.
+ std::unique_ptr<renderengine::Image> mCurrentTextureImageFreed;
+
+ // Cached images used for rendering the current texture through GPU
+ // composition.
+ std::unique_ptr<renderengine::Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
+
// A release that is pending on the receipt of a new release fence from
// presentDisplay
PendingRelease mPendingRelease;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index ab9a2f8..e75fbdf 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -216,7 +216,7 @@
return mConsumer->setFilteringEnabled(enabled);
}
-status_t BufferQueueLayer::bindTextureImage() const {
+status_t BufferQueueLayer::bindTextureImage() {
return mConsumer->bindTextureImage();
}
@@ -230,10 +230,13 @@
LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
+
+ const nsecs_t expectedPresentTime = mFlinger->mUseScheduler
+ ? mFlinger->mScheduler->mPrimaryDispSync->expectedPresentTime()
+ : mFlinger->mPrimaryDispSync->expectedPresentTime();
status_t updateResult =
- mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync->expectedPresentTime(),
- &mAutoRefresh, &queuedBuffer, mLastFrameNumberReceived,
- releaseFence);
+ mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh, &queuedBuffer,
+ mLastFrameNumberReceived, releaseFence);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index c239a00..abe0bc7 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -89,7 +89,7 @@
void setFilteringEnabled(bool enabled) override;
- status_t bindTextureImage() const override;
+ status_t bindTextureImage() override;
status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
const sp<Fence>& releaseFence) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c817fb0..e52b35a 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -323,22 +323,14 @@
mCurrentTransform, enabled);
}
-status_t BufferStateLayer::bindTextureImage() const {
+status_t BufferStateLayer::bindTextureImage() {
const State& s(getDrawingState());
auto& engine(mFlinger->getRenderEngine());
- if (!engine.isCurrent()) {
- ALOGE("RenderEngine is not current");
- return INVALID_OPERATION;
- }
-
engine.checkErrors();
- if (!mTextureImage) {
- ALOGE("no currently-bound texture");
- engine.bindExternalTextureImage(mTextureName, *engine.createImage());
- return NO_INIT;
- }
+ // TODO(marissaw): once buffers are cached, don't create a new image everytime
+ mTextureImage = engine.createImage();
bool created =
mTextureImage->setNativeWindowBuffer(s.buffer->getNativeBuffer(),
@@ -385,16 +377,6 @@
return NO_ERROR;
}
- auto& engine(mFlinger->getRenderEngine());
- if (!engine.isCurrent()) {
- ALOGE("RenderEngine is not current");
- return INVALID_OPERATION;
- }
- engine.checkErrors();
-
- // TODO(marissaw): once buffers are cached, don't create a new image everytime
- mTextureImage = engine.createImage();
-
// Reject if the layer is invalid
uint32_t bufferWidth = s.buffer->width;
uint32_t bufferHeight = s.buffer->height;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index b134fc5..0c6eaf5 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -114,7 +114,7 @@
void setFilteringEnabled(bool enabled) override;
- status_t bindTextureImage() const override;
+ status_t bindTextureImage() override;
status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
const sp<Fence>& releaseFence) override;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 54e19c7..18a8bb1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -20,15 +20,25 @@
#include <cstdint>
#include <memory>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
#include <gui/ISurfaceComposer.h>
+#include <ui/DisplayStatInfo.h>
#include "DispSync.h"
#include "DispSyncSource.h"
+#include "EventControlThread.h"
#include "EventThread.h"
#include "InjectVSyncSource.h"
namespace android {
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
#define RETURN_VALUE_IF_INVALID(value) \
if (handle == nullptr || mConnections.count(handle->id) == 0) return value
#define RETURN_IF_INVALID() \
@@ -36,17 +46,34 @@
std::atomic<int64_t> Scheduler::sNextId = 0;
+Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function)
+ : mHasSyncFramework(
+ getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasSyncFramework>(true)),
+ mDispSyncPresentTimeOffset(
+ getInt64<ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0)),
+ mPrimaryHWVsyncEnabled(false),
+ mHWVsyncAvailable(false) {
+ // Note: We create a local temporary with the real DispSync implementation
+ // type temporarily so we can initialize it with the configured values,
+ // before storing it for more generic use using the interface type.
+ auto primaryDispSync = std::make_unique<impl::DispSync>("SchedulerDispSync");
+ primaryDispSync->init(mHasSyncFramework, mDispSyncPresentTimeOffset);
+ mPrimaryDispSync = std::move(primaryDispSync);
+ mEventControlThread = std::make_unique<impl::EventControlThread>(function);
+}
+
Scheduler::~Scheduler() = default;
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
- const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const std::string& connectionName, int64_t phaseOffsetNs,
impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
std::unique_ptr<EventThread> eventThread =
- makeEventThread(connectionName, dispSync, phaseOffsetNs, resyncCallback,
+ makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, resyncCallback,
interceptCallback);
auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
eventThread->createEventConnection(),
@@ -108,4 +135,65 @@
RETURN_IF_INVALID();
mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
}
+
+void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
+ stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+ stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
+}
+
+void Scheduler::enableHardwareVsync() {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
+ mPrimaryDispSync->beginResync();
+ mEventControlThread->setVsyncEnabled(true);
+ mPrimaryHWVsyncEnabled = true;
+ }
+}
+
+void Scheduler::disableHardwareVsync(bool makeUnavailable) {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ if (mPrimaryHWVsyncEnabled) {
+ mEventControlThread->setVsyncEnabled(false);
+ mPrimaryDispSync->endResync();
+ mPrimaryHWVsyncEnabled = false;
+ }
+ if (makeUnavailable) {
+ mHWVsyncAvailable = false;
+ }
+}
+
+void Scheduler::setVsyncPeriod(const nsecs_t period) {
+ mPrimaryDispSync->reset();
+ mPrimaryDispSync->setPeriod(period);
+ enableHardwareVsync();
+}
+
+void Scheduler::addResyncSample(const nsecs_t timestamp) {
+ bool needsHwVsync = false;
+ { // Scope for the lock
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ if (mPrimaryHWVsyncEnabled) {
+ needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
+ }
+ }
+
+ if (needsHwVsync) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(false);
+ }
+}
+
+void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
+ if (mPrimaryDispSync->addPresentFence(fenceTime)) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(false);
+ }
+}
+
+void Scheduler::setIgnorePresentFences(bool ignore) {
+ mPrimaryDispSync->setIgnorePresentFences(ignore);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index fcb46e6..fdafe58 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -20,22 +20,31 @@
#include <memory>
#include <gui/ISurfaceComposer.h>
+#include <ui/DisplayStatInfo.h>
#include "DispSync.h"
+#include "EventControlThread.h"
#include "EventThread.h"
#include "InjectVSyncSource.h"
namespace android {
+class EventControlThread;
+
class Scheduler {
public:
+ // Enum to indicate whether to start the transaction early, or at vsync time.
+ enum class TransactionStart { EARLY, NORMAL };
+
/* The scheduler handle is a BBinder object passed to the client from which we can extract
* an ID for subsequent operations.
*/
class ConnectionHandle : public BBinder {
public:
ConnectionHandle(int64_t id) : id(id) {}
+
~ConnectionHandle() = default;
+
const int64_t id;
};
@@ -44,6 +53,7 @@
Connection(sp<ConnectionHandle> handle, sp<BnDisplayEventConnection> eventConnection,
std::unique_ptr<EventThread> eventThread)
: handle(handle), eventConnection(eventConnection), thread(std::move(eventThread)) {}
+
~Connection() = default;
sp<ConnectionHandle> handle;
@@ -51,32 +61,48 @@
const std::unique_ptr<EventThread> thread;
};
- Scheduler() = default;
+ explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function);
+
virtual ~Scheduler();
/** Creates an EventThread connection. */
sp<ConnectionHandle> createConnection(
- const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const std::string& connectionName, int64_t phaseOffsetNs,
impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
+
sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle);
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
+
sp<BnDisplayEventConnection> getEventConnection(const sp<ConnectionHandle>& handle);
// Should be called when receiving a hotplug event.
void hotplugReceived(const sp<ConnectionHandle>& handle, EventThread::DisplayType displayType,
bool connected);
+
// Should be called after the screen is turned on.
void onScreenAcquired(const sp<ConnectionHandle>& handle);
+
// Should be called before the screen is turned off.
void onScreenReleased(const sp<ConnectionHandle>& handle);
+
// Should be called when dumpsys command is received.
void dump(const sp<ConnectionHandle>& handle, String8& result) const;
+
// Offers ability to modify phase offset in the event thread.
void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
+ void getDisplayStatInfo(DisplayStatInfo* stats);
+
+ void enableHardwareVsync();
+ void disableHardwareVsync(bool makeUnavailable);
+ void setVsyncPeriod(const nsecs_t period);
+ void addResyncSample(const nsecs_t timestamp);
+ void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
+ void setIgnorePresentFences(bool ignore);
+
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
@@ -84,8 +110,29 @@
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
+ // TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
+ // should make request to Scheduler to compute next refresh.
+ friend class BufferQueueLayer;
+
+ // If fences from sync Framework are supported.
+ const bool mHasSyncFramework;
+
+ // The offset in nanoseconds to use, when DispSync timestamps present fence
+ // signaling time.
+ const nsecs_t mDispSyncPresentTimeOffset;
+
+ // Each connection has it's own ID. This variable keeps track of the count.
static std::atomic<int64_t> sNextId;
+
+ // Connections are stored in a map <connection ID, connection> for easy retrieval.
std::unordered_map<int64_t, std::unique_ptr<Connection>> mConnections;
+
+ std::mutex mHWVsyncLock;
+ bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock);
+ bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock);
+
+ std::unique_ptr<DispSync> mPrimaryDispSync;
+ std::unique_ptr<EventControlThread> mEventControlThread;
};
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index ea8ca4c..dde0c57 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -39,8 +39,6 @@
nsecs_t app;
};
- enum TransactionStart { EARLY, NORMAL };
-
// Sets the phase offsets
//
// sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
@@ -75,13 +73,14 @@
mSfConnectionHandle = sfConnectionHandle;
}
- void setTransactionStart(TransactionStart transactionStart) {
- if (transactionStart == TransactionStart::EARLY) {
+ void setTransactionStart(Scheduler::TransactionStart transactionStart) {
+ if (transactionStart == Scheduler::TransactionStart::EARLY) {
mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT;
}
// An early transaction stays an early transaction.
- if (transactionStart == mTransactionStart || mTransactionStart == TransactionStart::EARLY) {
+ if (transactionStart == mTransactionStart ||
+ mTransactionStart == Scheduler::TransactionStart::EARLY) {
return;
}
mTransactionStart = transactionStart;
@@ -89,8 +88,8 @@
}
void onTransactionHandled() {
- if (mTransactionStart == TransactionStart::NORMAL) return;
- mTransactionStart = TransactionStart::NORMAL;
+ if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
+ mTransactionStart = Scheduler::TransactionStart::NORMAL;
updateOffsets();
}
@@ -138,7 +137,8 @@
}
Offsets getOffsets() {
- if (mTransactionStart == TransactionStart::EARLY || mRemainingEarlyFrameCount > 0) {
+ if (mTransactionStart == Scheduler::TransactionStart::EARLY ||
+ mRemainingEarlyFrameCount > 0) {
return mEarlyOffsets;
} else if (mLastFrameUsedRenderEngine) {
return mEarlyGlOffsets;
@@ -160,7 +160,8 @@
std::atomic<Offsets> mOffsets;
- std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL;
+ std::atomic<Scheduler::TransactionStart> mTransactionStart =
+ Scheduler::TransactionStart::NORMAL;
std::atomic<bool> mLastFrameUsedRenderEngine = false;
std::atomic<int> mRemainingEarlyFrameCount = 0;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5744266..f0723e8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -584,15 +584,14 @@
// start the EventThread
if (mUseScheduler) {
- mScheduler = std::make_unique<Scheduler>();
+ mScheduler = std::make_unique<Scheduler>(
+ [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
mAppConnectionHandle =
- mScheduler->createConnection("appConnection", mPrimaryDispSync.get(),
- SurfaceFlinger::vsyncPhaseOffsetNs,
+ mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
[this] { resyncWithRateLimit(); },
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sfConnection", mPrimaryDispSync.get(),
- SurfaceFlinger::sfVsyncPhaseOffsetNs,
+ mScheduler->createConnection("sfConnection", SurfaceFlinger::sfVsyncPhaseOffsetNs,
[this] { resyncWithRateLimit(); },
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
@@ -912,10 +911,13 @@
return BAD_VALUE;
}
- // FIXME for now we always return stats for the primary display
- memset(stats, 0, sizeof(*stats));
- stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
- stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
+ // FIXME for now we always return stats for the primary display.
+ if (mUseScheduler) {
+ mScheduler->getDisplayStatInfo(stats);
+ } else {
+ stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+ stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
+ }
return NO_ERROR;
}
@@ -1246,13 +1248,17 @@
const auto activeConfig = getHwComposer().getActiveConfig(displayId);
const nsecs_t period = activeConfig->getVsyncPeriod();
- mPrimaryDispSync->reset();
- mPrimaryDispSync->setPeriod(period);
+ if (mUseScheduler) {
+ mScheduler->setVsyncPeriod(period);
+ } else {
+ mPrimaryDispSync->reset();
+ mPrimaryDispSync->setPeriod(period);
- if (!mPrimaryHWVsyncEnabled) {
- mPrimaryDispSync->beginResync();
- mEventControlThread->setVsyncEnabled(true);
- mPrimaryHWVsyncEnabled = true;
+ if (!mPrimaryHWVsyncEnabled) {
+ mPrimaryDispSync->beginResync();
+ mEventControlThread->setVsyncEnabled(true);
+ mPrimaryHWVsyncEnabled = true;
+ }
}
}
@@ -1300,19 +1306,22 @@
return;
}
- bool needsHwVsync = false;
-
- { // Scope for the lock
- Mutex::Autolock _l(mHWVsyncLock);
- if (mPrimaryHWVsyncEnabled) {
- needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
- }
- }
-
- if (needsHwVsync) {
- enableHardwareVsync();
+ if (mUseScheduler) {
+ mScheduler->addResyncSample(timestamp);
} else {
- disableHardwareVsync(false);
+ bool needsHwVsync = false;
+ { // Scope for the lock
+ Mutex::Autolock _l(mHWVsyncLock);
+ if (mPrimaryHWVsyncEnabled) {
+ needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
+ }
+ }
+
+ if (needsHwVsync) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(false);
+ }
}
}
@@ -1364,7 +1373,11 @@
// Note: it is assumed the caller holds |mStateLock| when this is called
void SurfaceFlinger::resetDisplayState() {
- disableHardwareVsync(true);
+ if (mUseScheduler) {
+ mScheduler->disableHardwareVsync(true);
+ } else {
+ disableHardwareVsync(true);
+ }
// Clear the drawing state so that the logic inside of
// handleTransactionLocked will fire. It will determine the delta between
// mCurrentState and mDrawingState and re-apply all changes when we make the
@@ -1432,12 +1445,17 @@
// The present fences returned from vr_hwc are not an accurate
// representation of vsync times.
- mPrimaryDispSync->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() ||
- !hasSyncFramework);
+ if (mUseScheduler) {
+ mScheduler->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() || !hasSyncFramework);
+ } else {
+ mPrimaryDispSync->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() ||
+ !hasSyncFramework);
+ }
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
- setCompositorTimingSnapped(0, period, 0);
+ DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+ setCompositorTimingSnapped(stats, 0);
resyncToHardwareVsync(false);
@@ -1736,9 +1754,8 @@
}
}
-void SurfaceFlinger::updateCompositorTiming(
- nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
- std::shared_ptr<FenceTime>& presentFenceTime) {
+void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
+ std::shared_ptr<FenceTime>& presentFenceTime) {
// Update queue of past composite+present times and determine the
// most recently known composite to present latency.
getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime});
@@ -1760,21 +1777,20 @@
getBE().mCompositePresentTimes.pop();
}
- setCompositorTimingSnapped(
- vsyncPhase, vsyncInterval, compositeToPresentLatency);
+ setCompositorTimingSnapped(stats, compositeToPresentLatency);
}
-void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncPhase,
- nsecs_t vsyncInterval, nsecs_t compositeToPresentLatency) {
+void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats,
+ nsecs_t compositeToPresentLatency) {
// Integer division and modulo round toward 0 not -inf, so we need to
// treat negative and positive offsets differently.
- nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0) ?
- (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
- ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
+ nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0)
+ ? (stats.vsyncPeriod - (sfVsyncPhaseOffsetNs % stats.vsyncPeriod))
+ : ((-sfVsyncPhaseOffsetNs) % stats.vsyncPeriod);
// Just in case sfVsyncPhaseOffsetNs == -vsyncInterval.
if (idealLatency <= 0) {
- idealLatency = vsyncInterval;
+ idealLatency = stats.vsyncPeriod;
}
// Snap the latency to a value that removes scheduling jitter from the
@@ -1783,15 +1799,14 @@
// something (such as user input) to an accurate diasplay time.
// Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
// with (presentLatency % interval).
- nsecs_t bias = vsyncInterval / 2;
- int64_t extraVsyncs =
- (compositeToPresentLatency - idealLatency + bias) / vsyncInterval;
- nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ?
- idealLatency + (extraVsyncs * vsyncInterval) : idealLatency;
+ nsecs_t bias = stats.vsyncPeriod / 2;
+ int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
+ nsecs_t snappedCompositeToPresentLatency =
+ (extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency;
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
- getBE().mCompositorTiming.deadline = vsyncPhase - idealLatency;
- getBE().mCompositorTiming.interval = vsyncInterval;
+ getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency;
+ getBE().mCompositorTiming.interval = stats.vsyncPeriod;
getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
}
@@ -1825,14 +1840,18 @@
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
getBE().mDisplayTimeline.push(presentFenceTime);
- nsecs_t vsyncPhase = mPrimaryDispSync->computeNextRefresh(0);
- nsecs_t vsyncInterval = mPrimaryDispSync->getPeriod();
+ DisplayStatInfo stats;
+ if (mUseScheduler) {
+ mScheduler->getDisplayStatInfo(&stats);
+ } else {
+ stats.vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+ stats.vsyncPeriod = mPrimaryDispSync->getPeriod();
+ }
// We use the mRefreshStartTime which might be sampled a little later than
// when we started doing work for this frame, but that should be okay
// since updateCompositorTiming has snapping logic.
- updateCompositorTiming(
- vsyncPhase, vsyncInterval, mRefreshStartTime, presentFenceTime);
+ updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
CompositorTiming compositorTiming;
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -1849,16 +1868,24 @@
});
if (presentFenceTime->isValid()) {
- if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
- enableHardwareVsync();
+ if (mUseScheduler) {
+ mScheduler->addPresentFence(presentFenceTime);
} else {
- disableHardwareVsync(false);
+ if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(false);
+ }
}
}
if (!hasSyncFramework) {
if (display && getHwComposer().isConnected(display->getId()) && display->isPoweredOn()) {
- enableHardwareVsync();
+ if (mUseScheduler) {
+ mScheduler->enableHardwareVsync();
+ } else {
+ enableHardwareVsync();
+ }
}
}
@@ -1892,7 +1919,7 @@
mHasPoweredOff = false;
} else {
nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
- size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncInterval);
+ size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod);
if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
getBE().mFrameBuckets[numPeriods] += elapsedTime;
} else {
@@ -3372,11 +3399,11 @@
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
- return setTransactionFlags(flags, VSyncModulator::TransactionStart::NORMAL);
+ return setTransactionFlags(flags, Scheduler::TransactionStart::NORMAL);
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
- VSyncModulator::TransactionStart transactionStart) {
+ Scheduler::TransactionStart transactionStart) {
uint32_t old = mTransactionFlags.fetch_or(flags);
mVsyncModulator.setTransactionStart(transactionStart);
if ((old & flags)==0) { // wake the server up
@@ -3467,9 +3494,8 @@
}
// this triggers the transaction
- const auto start = (flags & eEarlyWakeup)
- ? VSyncModulator::TransactionStart::EARLY
- : VSyncModulator::TransactionStart::NORMAL;
+ const auto start = (flags & eEarlyWakeup) ? Scheduler::TransactionStart::EARLY
+ : Scheduler::TransactionStart::NORMAL;
setTransactionFlags(transactionFlags, start);
// if this is a synchronous transaction, wait for it to take effect
@@ -3992,7 +4018,8 @@
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
- setCompositorTimingSnapped(0, period, 0);
+ DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+ setCompositorTimingSnapped(stats, 0);
}
void SurfaceFlinger::initializeDisplays() {
@@ -4058,8 +4085,11 @@
}
if (display->isPrimary() && currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
- disableHardwareVsync(true); // also cancels any in-progress resync
-
+ if (mUseScheduler) {
+ mScheduler->disableHardwareVsync(true);
+ } else {
+ disableHardwareVsync(true); // also cancels any in-progress resync
+ }
// FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenReleased(mAppConnectionHandle);
@@ -4087,7 +4117,11 @@
} else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
// Leave display going to doze
if (display->isPrimary()) {
- disableHardwareVsync(true); // also cancels any in-progress resync
+ if (mUseScheduler) {
+ mScheduler->disableHardwareVsync(true);
+ } else {
+ disableHardwareVsync(true); // also cancels any in-progress resync
+ }
// FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenReleased(mAppConnectionHandle);
@@ -5034,6 +5068,7 @@
// Needs to be shifted to proper binder interface when we productize
case 1016: {
n = data.readInt32();
+ // TODO(b/113612090): Evaluate if this can be removed.
mPrimaryDispSync->setRefreshSkipCount(n);
return NO_ERROR;
}
@@ -5162,9 +5197,17 @@
}
if ((frequencyScaler.multiplier == 1) && (frequencyScaler.divisor == 1)) {
- enableHardwareVsync();
+ if (mUseScheduler) {
+ mScheduler->enableHardwareVsync();
+ } else {
+ enableHardwareVsync();
+ }
} else {
- disableHardwareVsync(true);
+ if (mUseScheduler) {
+ mScheduler->disableHardwareVsync(true);
+ } else {
+ disableHardwareVsync(true);
+ }
}
mPrimaryDispSync->scalePeriod(frequencyScaler);
getBE().mHwc->setDisplayFrequencyScaleParameters(frequencyScaler);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a0f7c75..f535c4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -523,7 +523,7 @@
uint32_t peekTransactionFlags();
// Can only be called from the main thread or with mStateLock held
uint32_t setTransactionFlags(uint32_t flags);
- uint32_t setTransactionFlags(uint32_t flags, VSyncModulator::TransactionStart transactionStart);
+ uint32_t setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart);
void commitTransaction();
bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
uint32_t setClientStateLocked(const ComposerState& composerState);
@@ -662,12 +662,10 @@
void preComposition();
void postComposition();
- void updateCompositorTiming(
- nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
- std::shared_ptr<FenceTime>& presentFenceTime);
- void setCompositorTimingSnapped(
- nsecs_t vsyncPhase, nsecs_t vsyncInterval,
- nsecs_t compositeToPresentLatency);
+ void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
+ std::shared_ptr<FenceTime>& presentFenceTime);
+ void setCompositorTimingSnapped(const DisplayStatInfo& stats,
+ nsecs_t compositeToPresentLatency);
void rebuildLayerStacks();
ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& display,
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 7b79fbd..4e403b7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -474,10 +474,7 @@
enqueueBuffer(test, layer);
Mock::VerifyAndClear(test->mMessageQueue);
- EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
- EXPECT_CALL(*test->mRenderEngine, createImage())
- .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
bool ignoredRecomputeVisibleRegions;
layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, Fence::NO_FENCE);
Mock::VerifyAndClear(test->mRenderEngine);
@@ -574,6 +571,9 @@
LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
.Times(1);
+ EXPECT_CALL(*test->mRenderEngine, createImage())
+ .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
+ EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, _)).WillOnce(Return(true));
EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
EXPECT_CALL(*test->mRenderEngine, setupLayerTexturing(_)).Times(1);
EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
@@ -669,6 +669,9 @@
static constexpr uint32_t LAYER_FLAGS = ISurfaceComposerClient::eSecure;
static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, createImage())
+ .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
+ EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, _)).WillOnce(Return(true));
EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
EXPECT_CALL(*test->mRenderEngine, setupLayerBlackedOut()).Times(1);
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index df0d982..be91a9c 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -6,8 +6,11 @@
#include <log/log.h>
+#include <mutex>
+
#include "AsyncCallRecorder.h"
#include "Scheduler/DispSync.h"
+#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/Scheduler.h"
#include "mock/MockDispSync.h"
@@ -37,7 +40,7 @@
class MockScheduler : public android::Scheduler {
public:
MockScheduler(std::unique_ptr<EventThread> eventThread)
- : mEventThread(std::move(eventThread)) {}
+ : Scheduler([](bool) {}), mEventThread(std::move(eventThread)) {}
std::unique_ptr<EventThread> makeEventThread(
const std::string& /* connectionName */, DispSync* /* dispSync */,
@@ -81,9 +84,9 @@
EXPECT_CALL(*mEventThread, createEventConnection())
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle = mScheduler->createConnection("appConnection", mPrimaryDispSync, 16,
- mResyncCallRecorder.getInvocable(),
- mInterceptVSyncCallRecorder.getInvocable());
+ mConnectionHandle =
+ mScheduler->createConnection("appConnection", 16, mResyncCallRecorder.getInvocable(),
+ mInterceptVSyncCallRecorder.getInvocable());
}
SchedulerTest::~SchedulerTest() {
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index b4ea115..18bb7bf 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -8,8 +8,8 @@
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/buffer_wrapper.h>
-#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/buffer_hub.h>
+#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/ion_buffer.h>
namespace android {
@@ -81,10 +81,8 @@
BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
std::atomic<uint64_t>* buffer_state_ = nullptr;
std::atomic<uint64_t>* fence_state_ = nullptr;
+ std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
- // All active consumer bits. Valid bits are the lower 63 bits, while the
- // highest bit is reserved for the producer and should not be set.
- uint64_t active_consumer_bit_mask_{0ULL};
// All orphaned consumer bits. Valid bits are the lower 63 bits, while the
// highest bit is reserved for the producer and should not be set.
uint64_t orphaned_consumer_bit_mask_{0ULL};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index e7622ba..581390f 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -97,6 +97,8 @@
buffer_state_ =
new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
fence_state_ = new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
+ active_clients_bit_mask_ =
+ new (&metadata_header_->active_clients_bit_mask) std::atomic<uint64_t>(0);
acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
@@ -260,8 +262,12 @@
// Try find the next consumer state bit which has not been claimed by any
// consumer yet.
+ // memory_order_acquire is chosen here because all writes in other threads
+ // that release active_clients_bit_mask_ need to be visible here.
+ uint64_t current_active_clients_bit_mask =
+ active_clients_bit_mask_->load(std::memory_order_acquire);
uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
- active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
+ current_active_clients_bit_mask | orphaned_consumer_bit_mask_ |
BufferHubDefs::kProducerStateBit);
if (consumer_state_bit == 0ULL) {
ALOGE(
@@ -270,6 +276,23 @@
return ErrorStatus(E2BIG);
}
+ uint64_t updated_active_clients_bit_mask =
+ current_active_clients_bit_mask | consumer_state_bit;
+ // Set the updated value only if the current value stays the same as what was
+ // read before. If the comparison succeeds, update the value without
+ // reordering anything before or after this read-modify-write in the current
+ // thread, and the modification will be visible in other threads that acquire
+ // active_clients_bit_mask_. If the comparison fails, load the result of
+ // all writes from all threads to updated_active_clients_bit_mask.
+ if (!active_clients_bit_mask_->compare_exchange_weak(
+ current_active_clients_bit_mask, updated_active_clients_bit_mask,
+ std::memory_order_acq_rel, std::memory_order_acquire)) {
+ ALOGE("Current active clients bit mask is changed to %" PRIu64
+ ", which was expected to be %" PRIu64 ".",
+ updated_active_clients_bit_mask, current_active_clients_bit_mask);
+ return ErrorStatus(EBUSY);
+ }
+
auto consumer =
std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
consumer_state_bit, shared_from_this());
@@ -279,6 +302,10 @@
"ProducerChannel::CreateConsumer: failed to set new consumer channel: "
"%s",
channel_status.GetErrorMessage().c_str());
+ // Restore the consumer state bit and make it visible in other threads that
+ // acquire the active_clients_bit_mask_.
+ active_clients_bit_mask_->fetch_and(~consumer_state_bit,
+ std::memory_order_release);
return ErrorStatus(ENOMEM);
}
@@ -289,7 +316,6 @@
pending_consumers_++;
}
- active_consumer_bit_mask_ |= consumer_state_bit;
return {status.take()};
}
@@ -551,7 +577,10 @@
void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
consumer_channels_.erase(
std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
- active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
+ // Restore the consumer state bit and make it visible in other threads that
+ // acquire the active_clients_bit_mask_.
+ active_clients_bit_mask_->fetch_and(~channel->consumer_state_bit(),
+ std::memory_order_release);
const uint64_t buffer_state = buffer_state_->load();
if (BufferHubDefs::IsBufferPosted(buffer_state) ||