From 96a184d0ffa67bc9511ba089fd156370717aa88b Mon Sep 17 00:00:00 2001 From: Tobin Ehlis Date: Wed, 18 Jul 2018 16:14:07 -0600 Subject: Adding ANGLE systrace support Plumb ANGLE systrace support into Android by setting ANGLE PlatformMethods struct to required function pointers used by built-in ANGLE tracing macros. This includes "#define ATRACE_TAG ATRACE_TAG_GRAPHICS" so that these markers will fall under the "gfx" class of systrace. This requires mirroring new header, Platform.h, from ANGLE. Added AnglePlatformImpl class with static functions that are assigned into PlatformMethods struct that's passed to ANGLE. This lives in new egl_angle_platform.h/cpp files. Since we're moving to ANGLE as default long-term I think it makes sense to have this file live in EGL dir where I put it. Currently only defining the functions that we needs to support systrace through existing ANGLE PlatformMethods. Could potentially expand this to define more. Test: build and flash device, run app w/ ANGLE enabled, systrace Change-Id: I3f0812e8a7554768bbecc3e94feac6559ce17bb2 (cherry picked from commit b032494f6ce813323e79a55a0caa216997fe6a5d) --- opengl/libs/Android.bp | 1 + 1 file changed, 1 insertion(+) (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index d43c1648be..2a6dee4f4f 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -143,6 +143,7 @@ cc_library_shared { "EGL/egl.cpp", "EGL/eglApi.cpp", "EGL/Loader.cpp", + "EGL/egl_angle_platform.cpp", ], shared_libs: [ "libvndksupport", -- cgit v1.2.3-59-g8ed1b From 489e5df936aed8bc96ea33bbf2fb668d129eb702 Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Thu, 4 Oct 2018 14:29:10 -0600 Subject: Rename eglApi.cpp to egl_platform_entries.cpp Leading change for GLES layers. Test: Built, flashed, ran some GLES apps Bug: 110883880 Change-Id: I20f1890c1108e00cb85725712fc720e3d756d72e --- opengl/libs/Android.bp | 2 +- opengl/libs/EGL/eglApi.cpp | 2445 ------------------------------ opengl/libs/EGL/egl_platform_entries.cpp | 2445 ++++++++++++++++++++++++++++++ 3 files changed, 2446 insertions(+), 2446 deletions(-) delete mode 100644 opengl/libs/EGL/eglApi.cpp create mode 100644 opengl/libs/EGL/egl_platform_entries.cpp (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 2a6dee4f4f..78309d419f 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -141,7 +141,7 @@ cc_library_shared { "EGL/egl_display.cpp", "EGL/egl_object.cpp", "EGL/egl.cpp", - "EGL/eglApi.cpp", + "EGL/egl_platform_entries.cpp", "EGL/Loader.cpp", "EGL/egl_angle_platform.cpp", ], diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp deleted file mode 100644 index d2dc514ff2..0000000000 --- a/opengl/libs/EGL/eglApi.cpp +++ /dev/null @@ -1,2445 +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 -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "../egl_impl.h" - -#include "egl_display.h" -#include "egl_object.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 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(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); - } - - EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); - return dpy; -} - -// ---------------------------------------------------------------------------- -// Initialization -// ---------------------------------------------------------------------------- - -EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) -{ - clearError(); - - 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) -{ - // 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_display_ptr dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - - EGLBoolean res = dp->terminate(); - - return res; -} - -// ---------------------------------------------------------------------------- -// 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; - 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) -{ - 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; - 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) -{ - clearError(); - - 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 getDriverColorSpaces(egl_display_ptr dp, - android_pixel_format format) { - std::vector 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* 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 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 eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, - NativeWindowType window, - const EGLint *attrib_list) -{ - const EGLint *origAttribList = attrib_list; - clearError(); - - 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 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(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 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 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(); - - 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 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. - - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - setError(EGL_BAD_PARAMETER, NULL); - return nullptr; - } - - 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); - - 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; -} - -class FrameCompletionThread { -public: - - static void queueSync(EGLSyncKHR sync) { - static FrameCompletionThread thread; - - char name[64]; - - std::lock_guard 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 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 lock(mMutex); - mQueue.pop_front(); - mFramesCompleted++; - ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size())); - } - } - - uint32_t mFramesQueued; - uint32_t mFramesCompleted; - std::deque mQueue; - std::condition_variable mCondition; - std::mutex mMutex; -}; - -EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, - EGLint *rects, EGLint n_rects) -{ - ATRACE_CALL(); - clearError(); - - 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 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) -{ - 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; - 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 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; - if (cnx->dso && cnx->egl.eglBindAPI) { - res = cnx->egl.eglBindAPI(api); - } - return res; -} - -EGLenum eglQueryAPI(void) -{ - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - - 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 eglReleaseThread(void) -{ - clearError(); - - 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 eglCreatePbufferFromClientBuffer( - EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, - EGLConfig config, const EGLint *attrib_list) -{ - clearError(); - - 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 eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, - const EGLint *attrib_list) -{ - 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.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) -{ - 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.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) -{ - 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; - 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) -{ - clearError(); - - 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 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; - if (cnx->dso && cnx->egl.eglCreateSyncKHR) { - result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); - } - return result; -} - -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; - 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; - 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) -{ - clearError(); - - 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 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; - 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) -{ - 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; - if (cnx->dso && cnx->egl.eglCreateStreamKHR) { - result = cnx->egl.eglCreateStreamKHR( - dp->disp.dpy, attrib_list); - } - return result; -} - -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; - 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) -{ - clearError(); - - 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 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; - 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) -{ - clearError(); - - 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 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; - 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) -{ - clearError(); - - 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 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; - if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) { - result = cnx->egl.eglStreamConsumerGLTextureExternalKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) { - result = cnx->egl.eglStreamConsumerAcquireKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) { - result = cnx->egl.eglStreamConsumerReleaseKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) { - result = cnx->egl.eglGetStreamFileDescriptorKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - 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; - if (cnx->dso && cnx->egl.eglWaitSyncKHR) { - result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); - } - return result; -} - -// ---------------------------------------------------------------------------- -// 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; - if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { - result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); - } - return result; -} - -EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, - EGLnsecsANDROID time) -{ - clearError(); - - 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) { - clearError(); - // 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(AHardwareBuffer_to_ANativeWindowBuffer(buffer)); -#else - return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr); -#endif -} - -// ---------------------------------------------------------------------------- -// 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; - - if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { - return cnx->egl.eglGetSystemTimeFrequencyNV(); - } - - return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); -} - -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; - - if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { - return cnx->egl.eglGetSystemTimeNV(); - } - - return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); -} - -// ---------------------------------------------------------------------------- -// Partial update extension -// ---------------------------------------------------------------------------- -EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, - EGLint *rects, EGLint n_rects) -{ - clearError(); - - 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) { - clearError(); - - 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) -{ - clearError(); - - 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) -{ - clearError(); - - 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) -{ - clearError(); - - 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) -{ - clearError(); - - 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_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp new file mode 100644 index 0000000000..d2dc514ff2 --- /dev/null +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -0,0 +1,2445 @@ +/* + ** 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 +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../egl_impl.h" + +#include "egl_display.h" +#include "egl_object.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 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(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); + } + + EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); + return dpy; +} + +// ---------------------------------------------------------------------------- +// Initialization +// ---------------------------------------------------------------------------- + +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + clearError(); + + 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) +{ + // 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_display_ptr dp = get_display(dpy); + if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + + EGLBoolean res = dp->terminate(); + + return res; +} + +// ---------------------------------------------------------------------------- +// 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; + 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) +{ + 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; + 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) +{ + clearError(); + + 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 getDriverColorSpaces(egl_display_ptr dp, + android_pixel_format format) { + std::vector 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* 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 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 eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, + NativeWindowType window, + const EGLint *attrib_list) +{ + const EGLint *origAttribList = attrib_list; + clearError(); + + 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 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(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 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 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(); + + 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 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. + + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + setError(EGL_BAD_PARAMETER, NULL); + return nullptr; + } + + 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); + + 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; +} + +class FrameCompletionThread { +public: + + static void queueSync(EGLSyncKHR sync) { + static FrameCompletionThread thread; + + char name[64]; + + std::lock_guard 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 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 lock(mMutex); + mQueue.pop_front(); + mFramesCompleted++; + ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size())); + } + } + + uint32_t mFramesQueued; + uint32_t mFramesCompleted; + std::deque mQueue; + std::condition_variable mCondition; + std::mutex mMutex; +}; + +EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, + EGLint *rects, EGLint n_rects) +{ + ATRACE_CALL(); + clearError(); + + 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 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) +{ + 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; + 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 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; + if (cnx->dso && cnx->egl.eglBindAPI) { + res = cnx->egl.eglBindAPI(api); + } + return res; +} + +EGLenum eglQueryAPI(void) +{ + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + + 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 eglReleaseThread(void) +{ + clearError(); + + 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 eglCreatePbufferFromClientBuffer( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list) +{ + clearError(); + + 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 eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, + const EGLint *attrib_list) +{ + 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.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) +{ + 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.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) +{ + 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; + 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) +{ + clearError(); + + 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 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; + if (cnx->dso && cnx->egl.eglCreateSyncKHR) { + result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); + } + return result; +} + +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; + 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; + 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) +{ + clearError(); + + 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 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; + 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) +{ + 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; + if (cnx->dso && cnx->egl.eglCreateStreamKHR) { + result = cnx->egl.eglCreateStreamKHR( + dp->disp.dpy, attrib_list); + } + return result; +} + +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; + 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) +{ + clearError(); + + 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 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; + 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) +{ + clearError(); + + 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 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; + 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) +{ + clearError(); + + 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 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; + if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) { + result = cnx->egl.eglStreamConsumerGLTextureExternalKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) { + result = cnx->egl.eglStreamConsumerAcquireKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) { + result = cnx->egl.eglStreamConsumerReleaseKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) { + result = cnx->egl.eglGetStreamFileDescriptorKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + 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; + if (cnx->dso && cnx->egl.eglWaitSyncKHR) { + result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); + } + return result; +} + +// ---------------------------------------------------------------------------- +// 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; + if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { + result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); + } + return result; +} + +EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, + EGLnsecsANDROID time) +{ + clearError(); + + 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) { + clearError(); + // 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(AHardwareBuffer_to_ANativeWindowBuffer(buffer)); +#else + return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr); +#endif +} + +// ---------------------------------------------------------------------------- +// 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; + + if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { + return cnx->egl.eglGetSystemTimeFrequencyNV(); + } + + return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); +} + +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; + + if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { + return cnx->egl.eglGetSystemTimeNV(); + } + + return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); +} + +// ---------------------------------------------------------------------------- +// Partial update extension +// ---------------------------------------------------------------------------- +EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, + EGLint *rects, EGLint n_rects) +{ + clearError(); + + 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) { + clearError(); + + 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) +{ + clearError(); + + 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) +{ + clearError(); + + 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) +{ + clearError(); + + 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) +{ + clearError(); + + 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; + } +} -- cgit v1.2.3-59-g8ed1b From 87a562ced75efb1383a553bf8837ec3b9b848920 Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Thu, 4 Oct 2018 14:44:11 -0600 Subject: Split platform functions from entrypoints Test: Built, flashed, ran some GLES apps Bug: 110883880 Change-Id: I8697002582c9ca4deea926c298c5e9ab7ac39580 --- opengl/libs/Android.bp | 1 + opengl/libs/EGL/Loader.cpp | 24 +- opengl/libs/EGL/Loader.h | 3 +- opengl/libs/EGL/egl.cpp | 9 + opengl/libs/EGL/eglApi.cpp | 585 +++++++++++++++++++++++++++++++ opengl/libs/EGL/egl_platform_entries.cpp | 522 +++++++++++++-------------- opengl/libs/EGL/egl_platform_entries.h | 31 ++ opengl/libs/EGL/egldefs.h | 5 + opengl/libs/GLES2/gl2.cpp | 64 +--- opengl/libs/egl_impl.h | 3 + opengl/libs/hooks.h | 4 + opengl/libs/platform_entries.in | 76 ++++ 12 files changed, 1016 insertions(+), 311 deletions(-) create mode 100644 opengl/libs/EGL/eglApi.cpp create mode 100644 opengl/libs/EGL/egl_platform_entries.h create mode 100644 opengl/libs/platform_entries.in (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 78309d419f..fb6a221973 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -141,6 +141,7 @@ cc_library_shared { "EGL/egl_display.cpp", "EGL/egl_object.cpp", "EGL/egl.cpp", + "EGL/eglApi.cpp", "EGL/egl_platform_entries.cpp", "EGL/Loader.cpp", "EGL/egl_angle_platform.cpp", diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 018d97977a..5aa03a7647 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -33,6 +33,7 @@ #endif #include +#include "egl_platform_entries.h" #include "egl_trace.h" #include "egldefs.h" @@ -237,12 +238,12 @@ void* Loader::open(egl_connection_t* cnx) setEmulatorGlesValue(); - dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2); + dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2 | PLATFORM); if (dso) { hnd = new driver_t(dso); } else { // Always load EGL first - dso = load_driver("EGL", cnx, EGL); + dso = load_driver("EGL", cnx, EGL | PLATFORM); if (dso) { hnd = new driver_t(dso); hnd->set( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM ); @@ -623,6 +624,25 @@ void *Loader::load_driver(const char* kind, return nullptr; } + if (mask & PLATFORM) { + // For each entrypoint tracked by the platform + char const* const* entries = platform_names; + EGLFuncPointer* curr = reinterpret_cast(&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 6a32bb3066..93c33a824b 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -33,7 +33,8 @@ class Loader { enum { EGL = 0x01, GLESv1_CM = 0x02, - GLESv2 = 0x04 + GLESv2 = 0x04, + PLATFORM = 0x08 }; struct driver_t { explicit driver_t(void* gles); diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index e292b80ac5..d0cfadaff1 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -167,6 +167,10 @@ GLint egl_get_num_extensions_for_current_context() { return (GLint)c->tokenized_gl_extensions.size(); } +egl_connection_t* egl_get_connection() { + return &gEGLImpl; +} + // ---------------------------------------------------------------------------- // this mutex protects: @@ -257,6 +261,11 @@ char const * const egl_names[] = { 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 new file mode 100644 index 0000000000..8202c4eaae --- /dev/null +++ b/opengl/libs/EGL/eglApi.cpp @@ -0,0 +1,585 @@ +/* + ** 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. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include +#include + +#include "../egl_impl.h" + +#include "egl_layers.h" +#include "egl_platform_entries.h" +#include "egl_tls.h" +#include "egl_trace.h" + +using namespace android; + +namespace android { + +extern EGLBoolean egl_init_drivers(); + +} // namespace android + +static inline void clearError() { + egl_tls_t::clearError(); +} + +EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { + ATRACE_CALL(); + clearError(); + + 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); +} + +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglInitialize(dpy, major, minor); +} + +EGLBoolean eglTerminate(EGLDisplay dpy) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglTerminate(dpy); +} + +EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, + EGLint* num_config) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetConfigs(dpy, configs, config_size, num_config); +} + +EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, + EGLint config_size, EGLint* num_config) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglChooseConfig(dpy, attrib_list, configs, config_size, num_config); +} + +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); +} + +EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, + const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateWindowSurface(dpy, config, window, attrib_list); +} + +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); +} + +EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreatePbufferSurface(dpy, config, attrib_list); +} + +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglDestroySurface(dpy, surface); +} + +EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglQuerySurface(dpy, surface, attribute, value); +} + +void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { + ATRACE_CALL(); + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + cnx->platform.eglBeginFrame(dpy, surface); +} + +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(); + } +} + +__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. + + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + setError(EGL_BAD_PARAMETER, NULL); + return nullptr; + } + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetProcAddress(procname); +} + +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); +} + +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { + ATRACE_CALL(); + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglSwapBuffers(dpy, surface); +} + +EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, NativePixmapType target) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCopyBuffers(dpy, surface, target); +} + +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) { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + + 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); + } + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglQueryAPI(); +} + +EGLBoolean eglReleaseThread(void) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglReleaseThread(); +} + +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); +} + +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); +} + +EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglUnlockSurfaceKHR(dpy, surface); +} + +EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list); +} + +EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglDestroyImageKHR(dpy, img); +} + +EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateSyncKHR(dpy, type, attrib_list); +} + +EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglDestroySyncKHR(dpy, sync); +} + +EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglSignalSyncKHR(dpy, sync, mode); +} + +EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglClientWaitSyncKHR(dpy, sync, flags, timeout); +} + +EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint* value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetSyncAttribKHR(dpy, sync, attribute, value); +} + +EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateStreamKHR(dpy, attrib_list); +} + +EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglDestroyStreamKHR(dpy, stream); +} + +EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, + EGLint value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglStreamAttribKHR(dpy, stream, attribute, value); +} + +EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, + EGLint* value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglQueryStreamKHR(dpy, stream, attribute, value); +} + +EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, + EGLuint64KHR* value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglQueryStreamu64KHR(dpy, stream, attribute, value); +} + +EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, + EGLTimeKHR* value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglQueryStreamTimeKHR(dpy, stream, attribute, value); +} + +EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, + const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateStreamProducerSurfaceKHR(dpy, config, stream, attrib_list); +} + +EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglStreamConsumerGLTextureExternalKHR(dpy, stream); +} + +EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglStreamConsumerAcquireKHR(dpy, stream); +} + +EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglStreamConsumerReleaseKHR(dpy, stream); +} + +EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetStreamFileDescriptorKHR(dpy, stream); +} + +EGLStreamKHR eglCreateStreamFromFileDescriptorKHR(EGLDisplay dpy, + EGLNativeFileDescriptorKHR file_descriptor) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateStreamFromFileDescriptorKHR(dpy, file_descriptor); +} + +EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglWaitSyncKHR(dpy, sync, flags); +} + +EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglDupNativeFenceFDANDROID(dpy, sync); +} + +EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglPresentationTimeANDROID(dpy, surface, time); +} + +EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer* buffer) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetNativeClientBufferANDROID(buffer); +} + +EGLuint64NV eglGetSystemTimeFrequencyNV() { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); + } + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetSystemTimeFrequencyNV(); +} + +EGLuint64NV eglGetSystemTimeNV() { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); + } + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetSystemTimeNV(); +} + +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); +} + +EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR* frameId) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetNextFrameIdANDROID(dpy, surface, frameId); +} + +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); +} + +EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint name) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetCompositorTimingSupportedANDROID(dpy, surface, name); +} + +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); +} + +EGLBoolean eglGetFrameTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, + EGLint timestamp) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetFrameTimestampSupportedANDROID(dpy, surface, timestamp); +} diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index d2dc514ff2..296ee44ce5 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -16,6 +16,8 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include "egl_platform_entries.h" + #include #include #include @@ -268,30 +270,19 @@ 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) +EGLDisplay eglGetDisplayImpl(EGLNativeDisplayType display) { - ATRACE_CALL(); - clearError(); - uintptr_t index = reinterpret_cast(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); - } - EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); return dpy; } @@ -300,10 +291,8 @@ EGLDisplay eglGetDisplay(EGLNativeDisplayType display) // Initialization // ---------------------------------------------------------------------------- -EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +EGLBoolean eglInitializeImpl(EGLDisplay dpy, EGLint *major, EGLint *minor) { - clearError(); - egl_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -312,14 +301,12 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) return res; } -EGLBoolean eglTerminate(EGLDisplay dpy) +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. - clearError(); - egl_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -332,12 +319,10 @@ EGLBoolean eglTerminate(EGLDisplay dpy) // configuration // ---------------------------------------------------------------------------- -EGLBoolean eglGetConfigs( EGLDisplay dpy, - EGLConfig *configs, - EGLint config_size, EGLint *num_config) +EGLBoolean eglGetConfigsImpl(EGLDisplay dpy, + EGLConfig *configs, + EGLint config_size, EGLint *num_config) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -357,12 +342,10 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy, return res; } -EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, - EGLConfig *configs, EGLint config_size, - EGLint *num_config) +EGLBoolean eglChooseConfigImpl( 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; @@ -436,11 +419,9 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, return res; } -EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, +EGLBoolean eglGetConfigAttribImpl(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { - clearError(); - egl_connection_t* cnx = nullptr; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (!dp) return EGL_FALSE; @@ -701,12 +682,11 @@ EGLBoolean sendSurfaceMetadata(egl_surface_t* s) { return EGL_TRUE; } -EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, - NativeWindowType window, - const EGLint *attrib_list) +EGLSurface eglCreateWindowSurfaceImpl( EGLDisplay dpy, EGLConfig config, + NativeWindowType window, + const EGLint *attrib_list) { const EGLint *origAttribList = attrib_list; - clearError(); egl_connection_t* cnx = nullptr; egl_display_ptr dp = validate_display_connection(dpy, cnx); @@ -791,12 +771,10 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, - NativePixmapType pixmap, - const EGLint *attrib_list) +EGLSurface eglCreatePixmapSurfaceImpl( 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) { @@ -826,11 +804,9 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, - const EGLint *attrib_list) +EGLSurface eglCreatePbufferSurfaceImpl( 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) { @@ -860,10 +836,8 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -879,11 +853,9 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) return result; } -EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, - EGLint attribute, EGLint *value) +EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -902,10 +874,7 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, return s->cnx->egl.eglQuerySurface(dp->disp.dpy, s->surface, attribute, value); } -void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { - ATRACE_CALL(); - clearError(); - +void EGLAPI eglBeginFrameImpl(EGLDisplay dpy, EGLSurface surface) { const egl_display_ptr dp = validate_display(dpy); if (!dp) { return; @@ -921,11 +890,9 @@ void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { // Contexts // ---------------------------------------------------------------------------- -EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, - EGLContext share_list, const EGLint *attrib_list) +EGLContext eglCreateContextImpl(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) { @@ -962,10 +929,8 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, return EGL_NO_CONTEXT; } -EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +EGLBoolean eglDestroyContextImpl(EGLDisplay dpy, EGLContext ctx) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -982,11 +947,9 @@ EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) return result; } -EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, - EGLSurface read, EGLContext ctx) +EGLBoolean eglMakeCurrentImpl( 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); @@ -1076,12 +1039,9 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, return result; } - -EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, - EGLint attribute, EGLint *value) +EGLBoolean eglQueryContextImpl( EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1094,24 +1054,19 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, } -EGLContext eglGetCurrentContext(void) +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. - - clearError(); - EGLContext ctx = getContext(); return ctx; } -EGLSurface eglGetCurrentSurface(EGLint readdraw) +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. - clearError(); - EGLContext ctx = getContext(); if (ctx) { egl_context_t const * const c = get_context(ctx); @@ -1125,13 +1080,11 @@ EGLSurface eglGetCurrentSurface(EGLint readdraw) return EGL_NO_SURFACE; } -EGLDisplay eglGetCurrentDisplay(void) +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. - clearError(); - EGLContext ctx = getContext(); if (ctx) { egl_context_t const * const c = get_context(ctx); @@ -1141,10 +1094,8 @@ EGLDisplay eglGetCurrentDisplay(void) return EGL_NO_DISPLAY; } -EGLBoolean eglWaitGL(void) +EGLBoolean eglWaitGLImpl(void) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1152,10 +1103,8 @@ EGLBoolean eglWaitGL(void) return cnx->egl.eglWaitGL(); } -EGLBoolean eglWaitNative(EGLint engine) +EGLBoolean eglWaitNativeImpl(EGLint engine) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1163,7 +1112,7 @@ EGLBoolean eglWaitNative(EGLint engine) return cnx->egl.eglWaitNative(engine); } -EGLint eglGetError(void) +EGLint eglGetErrorImpl(void) { EGLint err = EGL_SUCCESS; egl_connection_t* const cnx = &gEGLImpl; @@ -1193,19 +1142,8 @@ static __eglMustCastToProperFunctionPointerType findBuiltinWrapper( return nullptr; } -__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) +__eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(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. - - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - setError(EGL_BAD_PARAMETER, NULL); - return nullptr; - } - if (FILTER_EXTENSIONS(procname)) { return nullptr; } @@ -1346,12 +1284,9 @@ private: std::mutex mMutex; }; -EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, +EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, EGLint *rects, EGLint n_rects) { - ATRACE_CALL(); - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1416,16 +1351,14 @@ EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, } } -EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglSwapBuffersImpl(EGLDisplay dpy, EGLSurface surface) { - return eglSwapBuffersWithDamageKHR(dpy, surface, nullptr, 0); + return eglSwapBuffersWithDamageKHRImpl(dpy, surface, nullptr, 0); } -EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, - NativePixmapType target) +EGLBoolean eglCopyBuffersImpl( EGLDisplay dpy, EGLSurface surface, + NativePixmapType target) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1437,10 +1370,8 @@ EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); } -const char* eglQueryString(EGLDisplay dpy, EGLint name) +const char* eglQueryStringImpl(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 @@ -1469,10 +1400,8 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) return setError(EGL_BAD_PARAMETER, (const char *)nullptr); } -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) +EGLAPI const char* eglQueryStringImplementationANDROIDImpl(EGLDisplay dpy, EGLint name) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return (const char *) nullptr; @@ -1495,11 +1424,9 @@ extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy // EGL 1.1 // ---------------------------------------------------------------------------- -EGLBoolean eglSurfaceAttrib( +EGLBoolean eglSurfaceAttribImpl( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1536,11 +1463,9 @@ EGLBoolean eglSurfaceAttrib( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglBindTexImage( +EGLBoolean eglBindTexImageImpl( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1556,11 +1481,9 @@ EGLBoolean eglBindTexImage( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglReleaseTexImage( +EGLBoolean eglReleaseTexImageImpl( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1576,10 +1499,8 @@ EGLBoolean eglReleaseTexImage( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) +EGLBoolean eglSwapIntervalImpl(EGLDisplay dpy, EGLint interval) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1597,10 +1518,8 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) // EGL 1.2 // ---------------------------------------------------------------------------- -EGLBoolean eglWaitClient(void) +EGLBoolean eglWaitClientImpl(void) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1614,14 +1533,8 @@ EGLBoolean eglWaitClient(void) return res; } -EGLBoolean eglBindAPI(EGLenum api) +EGLBoolean eglBindAPIImpl(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; @@ -1631,14 +1544,8 @@ EGLBoolean eglBindAPI(EGLenum api) return res; } -EGLenum eglQueryAPI(void) +EGLenum eglQueryAPIImpl(void) { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglQueryAPI) { return cnx->egl.eglQueryAPI(); @@ -1648,10 +1555,8 @@ EGLenum eglQueryAPI(void) return EGL_OPENGL_ES_API; } -EGLBoolean eglReleaseThread(void) +EGLBoolean eglReleaseThreadImpl(void) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglReleaseThread) { cnx->egl.eglReleaseThread(); @@ -1664,12 +1569,10 @@ EGLBoolean eglReleaseThread(void) return EGL_TRUE; } -EGLSurface eglCreatePbufferFromClientBuffer( +EGLSurface eglCreatePbufferFromClientBufferImpl( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) { - clearError(); - egl_connection_t* cnx = nullptr; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (!dp) return EGL_FALSE; @@ -1684,11 +1587,9 @@ EGLSurface eglCreatePbufferFromClientBuffer( // EGL_EGLEXT_VERSION 3 // ---------------------------------------------------------------------------- -EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglLockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1704,10 +1605,8 @@ EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglUnlockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1722,11 +1621,9 @@ EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } -EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, +EGLImageKHR eglCreateImageKHRImpl(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_IMAGE_KHR; @@ -1744,10 +1641,8 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, return result; } -EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) +EGLBoolean eglDestroyImageKHRImpl(EGLDisplay dpy, EGLImageKHR img) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1764,10 +1659,8 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) // ---------------------------------------------------------------------------- -EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) +EGLSyncKHR eglCreateSyncKHRImpl(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_SYNC_KHR; @@ -1779,10 +1672,8 @@ EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_l return result; } -EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) +EGLBoolean eglDestroySyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1794,9 +1685,7 @@ EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) return result; } -EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { - clearError(); - +EGLBoolean eglSignalSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1809,11 +1698,9 @@ EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { return result; } -EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, +EGLint eglClientWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1826,11 +1713,9 @@ EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, return result; } -EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, +EGLBoolean eglGetSyncAttribKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1843,10 +1728,8 @@ EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, return result; } -EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) +EGLStreamKHR eglCreateStreamKHRImpl(EGLDisplay dpy, const EGLint *attrib_list) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_STREAM_KHR; @@ -1859,10 +1742,8 @@ EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) return result; } -EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) +EGLBoolean eglDestroyStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1875,11 +1756,9 @@ EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) return result; } -EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglStreamAttribKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1892,11 +1771,9 @@ EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1909,11 +1786,9 @@ EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamu64KHRImpl(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1926,11 +1801,9 @@ EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamTimeKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1943,11 +1816,9 @@ EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, +EGLSurface eglCreateStreamProducerSurfaceKHRImpl(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list) { - clearError(); - egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_SURFACE; @@ -1964,11 +1835,9 @@ EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, +EGLBoolean eglStreamConsumerGLTextureExternalKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1981,11 +1850,9 @@ EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, return result; } -EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, +EGLBoolean eglStreamConsumerAcquireKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1998,11 +1865,9 @@ EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, return result; } -EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, +EGLBoolean eglStreamConsumerReleaseKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -2015,11 +1880,9 @@ EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, return result; } -EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR( +EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHRImpl( EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR; @@ -2032,11 +1895,9 @@ EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR( return result; } -EGLStreamKHR eglCreateStreamFromFileDescriptorKHR( +EGLStreamKHR eglCreateStreamFromFileDescriptorKHRImpl( EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_STREAM_KHR; @@ -2053,8 +1914,7 @@ EGLStreamKHR eglCreateStreamFromFileDescriptorKHR( // EGL_EGLEXT_VERSION 15 // ---------------------------------------------------------------------------- -EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { - clearError(); +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; @@ -2069,10 +1929,8 @@ EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { // ANDROID extensions // ---------------------------------------------------------------------------- -EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) +EGLint eglDupNativeFenceFDANDROIDImpl(EGLDisplay dpy, EGLSyncKHR sync) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID; @@ -2084,11 +1942,9 @@ EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) return result; } -EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglPresentationTimeANDROIDImpl(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return EGL_FALSE; @@ -2106,8 +1962,7 @@ EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, return EGL_TRUE; } -EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) { - clearError(); +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. @@ -2122,14 +1977,8 @@ EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) { // ---------------------------------------------------------------------------- // NVIDIA extensions // ---------------------------------------------------------------------------- -EGLuint64NV eglGetSystemTimeFrequencyNV() +EGLuint64NV eglGetSystemTimeFrequencyNVImpl() { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); - } - EGLuint64NV ret = 0; egl_connection_t* const cnx = &gEGLImpl; @@ -2140,14 +1989,8 @@ EGLuint64NV eglGetSystemTimeFrequencyNV() return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); } -EGLuint64NV eglGetSystemTimeNV() +EGLuint64NV eglGetSystemTimeNVImpl() { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); - } - EGLuint64NV ret = 0; egl_connection_t* const cnx = &gEGLImpl; @@ -2161,11 +2004,9 @@ EGLuint64NV eglGetSystemTimeNV() // ---------------------------------------------------------------------------- // Partial update extension // ---------------------------------------------------------------------------- -EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglSetDamageRegionKHRImpl(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { setError(EGL_BAD_DISPLAY, EGL_FALSE); @@ -2187,10 +2028,8 @@ EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, return EGL_FALSE; } -EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetNextFrameIdANDROIDImpl(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2221,11 +2060,9 @@ EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, return EGL_TRUE; } -EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetCompositorTimingANDROIDImpl(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2278,11 +2115,9 @@ EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, } } -EGLBoolean eglGetCompositorTimingSupportedANDROID( +EGLBoolean eglGetCompositorTimingSupportedANDROIDImpl( EGLDisplay dpy, EGLSurface surface, EGLint name) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2310,12 +2145,10 @@ EGLBoolean eglGetCompositorTimingSupportedANDROID( } } -EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetFrameTimestampsANDROIDImpl(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2398,11 +2231,9 @@ EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, } } -EGLBoolean eglGetFrameTimestampSupportedANDROID( +EGLBoolean eglGetFrameTimestampSupportedANDROIDImpl( EGLDisplay dpy, EGLSurface surface, EGLint timestamp) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2443,3 +2274,182 @@ EGLBoolean eglGetFrameTimestampSupportedANDROID( 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 new file mode 100644 index 0000000000..7cd80d6dc2 --- /dev/null +++ b/opengl/libs/EGL/egl_platform_entries.h @@ -0,0 +1,31 @@ +/* + * 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 + +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 4990af6edd..1a88678964 100644 --- a/opengl/libs/EGL/egldefs.h +++ b/opengl/libs/EGL/egldefs.h @@ -38,12 +38,16 @@ struct egl_connection_t { }; 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; @@ -63,6 +67,7 @@ extern "C" void gl_noop(); extern char const * const gl_names[]; 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 f7fde9625f..65f50f54fb 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -301,71 +301,31 @@ extern "C" { } const GLubyte * glGetString(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; + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetString(name); } const GLubyte * glGetStringi(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; + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetStringi(name, index); } void glGetBooleanv(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); + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetBooleanv(pname, data); } void glGetFloatv(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); + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetFloatv(pname, data); } void glGetIntegerv(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); + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetIntegerv(pname, data); } void glGetInteger64v(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); + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetInteger64v(pname, data); } diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h index a8855efa57..0af050175b 100644 --- a/opengl/libs/egl_impl.h +++ b/opengl/libs/egl_impl.h @@ -21,15 +21,18 @@ #include #include +#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 81dbe0e34b..63a0e140cc 100644 --- a/opengl/libs/hooks.h +++ b/opengl/libs/hooks.h @@ -59,6 +59,10 @@ namespace android { #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 new file mode 100644 index 0000000000..b28f6ccac8 --- /dev/null +++ b/opengl/libs/platform_entries.in @@ -0,0 +1,76 @@ +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*) -- cgit v1.2.3-59-g8ed1b From d9f0ec416aa89d8213effa8b983de974b2c667bd Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Thu, 4 Oct 2018 14:48:07 -0600 Subject: Rootless Debug for GLES Add the ability to enable debug layers for OpenGL ES. This update concides with changes to framework/base to control the enabling logic in GraphicsEnvironment. Refer to go/rootless-gpu-debug-gles for design overview. To learn more about creating GLES layers, refer to https://developer.android.com/ndk/guides/ Test: cts-tradefed run singleCommand cts -m CtsGpuToolsHostTestCases Bug: 110883880 Bug: 117515773 Change-Id: I0334cd9cd386f20bf40adac117e3144b0f76b7d3 --- libs/graphicsenv/Android.bp | 1 + libs/graphicsenv/GraphicsEnv.cpp | 17 + libs/graphicsenv/include/graphicsenv/GraphicsEnv.h | 14 +- opengl/libs/Android.bp | 4 + opengl/libs/EGL/egl.cpp | 11 +- opengl/libs/EGL/egl_layers.cpp | 433 +++++++++++++++++++++ opengl/libs/EGL/egl_layers.h | 65 ++++ opengl/libs/EGL/egl_platform_entries.cpp | 92 +++-- 8 files changed, 594 insertions(+), 43 deletions(-) create mode 100644 opengl/libs/EGL/egl_layers.cpp create mode 100644 opengl/libs/EGL/egl_layers.h (limited to 'opengl/libs/Android.bp') diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index 4da30e9980..bab87acb05 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -23,6 +23,7 @@ cc_library_shared { shared_libs: [ "liblog", + "libcutils", ], export_include_dirs: ["include"], diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 2a7d76e856..3328ad7291 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -18,9 +18,12 @@ #define LOG_TAG "GraphicsEnv" #include +#include + #include #include +#include #include // TODO(b/37049319) Get this from a header once one exists @@ -46,6 +49,14 @@ namespace android { 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'", @@ -181,4 +192,10 @@ bool android_getAngleDeveloperOptIn() { 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 00e8fc01f7..1783429b9d 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -29,6 +29,8 @@ class GraphicsEnv { 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 @@ -85,11 +87,13 @@ private: * 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(); + 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(); } #endif // ANDROID_UI_GRAPHICS_ENV_H diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index fb6a221973..583aec9db5 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -140,6 +140,7 @@ cc_library_shared { "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", @@ -150,8 +151,11 @@ cc_library_shared { "libvndksupport", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", + "libbase", "libhidlbase", "libhidltransport", + "libnativebridge", + "libnativeloader", "libutils", ], static_libs: [ diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index d0cfadaff1..01795e0af3 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -30,11 +30,10 @@ #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 { // ---------------------------------------------------------------------------- @@ -196,6 +195,14 @@ static EGLBoolean egl_init_drivers_locked() { 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; } diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp new file mode 100644 index 0000000000..6900b8b464 --- /dev/null +++ b/opengl/libs/EGL/egl_layers.cpp @@ -0,0 +1,433 @@ +/* + ** 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 func_indices; +// func_indices.reserve(kFuncCount); + +std::unordered_map func_names; +// func_names.reserve(kFuncCount); + +std::vector 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(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(gpaNext); + + val = reinterpret_cast(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(val); + } + + // int index = func_indices[name]; + // val = (*next_layer_funcs)[index]; + // return reinterpret_cast(val); + return reinterpret_cast((*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(&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(&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(&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(&layer_functions[current_layer_]), + reinterpret_cast( + getNextLayerProcAddress)); + + // Check functions implemented by the platform + func_idx = 0; + entries = platform_names; + curr = reinterpret_cast(&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(&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(&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 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 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(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(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 new file mode 100644 index 0000000000..e401b448cf --- /dev/null +++ b/opengl/libs/EGL/egl_layers.h @@ -0,0 +1,65 @@ +/* + * 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 +#include +#include + +#include + +#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_; + std::vector 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 index 296ee44ce5..0d69a658e3 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -30,6 +30,8 @@ #include #include +#include +#include #include #include @@ -47,6 +49,7 @@ #include "egl_display.h" #include "egl_object.h" +#include "egl_layers.h" #include "egl_tls.h" #include "egl_trace.h" @@ -1158,54 +1161,71 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procn // 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); + /* + * 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; + 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); + 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; + LayerLoader& layer_loader(LayerLoader::getInstance()); - 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 (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { - if (found) { - addr = gExtensionForwarders[slot]; + 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; } -- cgit v1.2.3-59-g8ed1b From 9f20d92fb3b7ed2a88d2e497ec36d21e9005f497 Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Fri, 12 Oct 2018 14:34:26 -0600 Subject: Revert "Rootless Debug for GLES" This reverts commit d9f0ec416aa89d8213effa8b983de974b2c667bd. Bug: 110883880 Test: Chrome no longer crashes Change-Id: I57d08a33a392394bd0a2cf4d7af97a3cce7ed8f5 --- libs/graphicsenv/Android.bp | 1 - libs/graphicsenv/GraphicsEnv.cpp | 17 - libs/graphicsenv/include/graphicsenv/GraphicsEnv.h | 14 +- opengl/libs/Android.bp | 4 - opengl/libs/EGL/egl.cpp | 11 +- opengl/libs/EGL/egl_layers.cpp | 433 --------------------- opengl/libs/EGL/egl_layers.h | 65 ---- opengl/libs/EGL/egl_platform_entries.cpp | 92 ++--- 8 files changed, 43 insertions(+), 594 deletions(-) delete mode 100644 opengl/libs/EGL/egl_layers.cpp delete mode 100644 opengl/libs/EGL/egl_layers.h (limited to 'opengl/libs/Android.bp') diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index bab87acb05..4da30e9980 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -23,7 +23,6 @@ cc_library_shared { shared_libs: [ "liblog", - "libcutils", ], export_include_dirs: ["include"], diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 3328ad7291..2a7d76e856 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -18,12 +18,9 @@ #define LOG_TAG "GraphicsEnv" #include -#include - #include #include -#include #include // TODO(b/37049319) Get this from a header once one exists @@ -49,14 +46,6 @@ namespace android { 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 @@ bool android_getAngleDeveloperOptIn() { 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 1783429b9d..00e8fc01f7 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -29,8 +29,6 @@ class GraphicsEnv { 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 @@ private: * 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/opengl/libs/Android.bp b/opengl/libs/Android.bp index 583aec9db5..fb6a221973 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -140,7 +140,6 @@ cc_library_shared { "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", @@ -151,11 +150,8 @@ cc_library_shared { "libvndksupport", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", - "libbase", "libhidlbase", "libhidltransport", - "libnativebridge", - "libnativeloader", "libutils", ], static_libs: [ diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 8870d5f571..1229bc288d 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 { // ---------------------------------------------------------------------------- @@ -195,14 +196,6 @@ static EGLBoolean egl_init_drivers_locked() { 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; } diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp deleted file mode 100644 index 6900b8b464..0000000000 --- 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 func_indices; -// func_indices.reserve(kFuncCount); - -std::unordered_map func_names; -// func_names.reserve(kFuncCount); - -std::vector 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(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(gpaNext); - - val = reinterpret_cast(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(val); - } - - // int index = func_indices[name]; - // val = (*next_layer_funcs)[index]; - // return reinterpret_cast(val); - return reinterpret_cast((*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(&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(&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(&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(&layer_functions[current_layer_]), - reinterpret_cast( - getNextLayerProcAddress)); - - // Check functions implemented by the platform - func_idx = 0; - entries = platform_names; - curr = reinterpret_cast(&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(&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(&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 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 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(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(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 e401b448cf..0000000000 --- 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 -#include -#include - -#include - -#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_; - std::vector 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 index 0d69a658e3..296ee44ce5 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -30,8 +30,6 @@ #include #include -#include -#include #include #include @@ -49,7 +47,6 @@ #include "egl_display.h" #include "egl_object.h" -#include "egl_layers.h" #include "egl_tls.h" #include "egl_trace.h" @@ -1161,71 +1158,54 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procn // 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); + /* + * 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; + 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); + 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); + if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { + bool found = false; - // Track the top most entry point + 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] = addr; + 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++; } } - } 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; } -- cgit v1.2.3-59-g8ed1b From d18d55344f9c1133c6b4f41aa6defcde1c32c7f3 Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Fri, 12 Oct 2018 14:34:42 -0600 Subject: Revert "Split platform functions from entrypoints" This reverts commit 87a562ced75efb1383a553bf8837ec3b9b848920. Bug: 110883880 Test: Chrome no longer crashes Change-Id: I81d97298cbfd7f947920b6e9e8ad3abcd1a0d75a --- opengl/libs/Android.bp | 1 - opengl/libs/EGL/Loader.cpp | 24 +- opengl/libs/EGL/Loader.h | 3 +- opengl/libs/EGL/egl.cpp | 9 - opengl/libs/EGL/eglApi.cpp | 585 ------------------------------- opengl/libs/EGL/egl_platform_entries.cpp | 522 ++++++++++++++------------- opengl/libs/EGL/egl_platform_entries.h | 31 -- opengl/libs/EGL/egldefs.h | 5 - opengl/libs/GLES2/gl2.cpp | 64 +++- opengl/libs/egl_impl.h | 3 - opengl/libs/hooks.h | 4 - opengl/libs/platform_entries.in | 76 ---- 12 files changed, 311 insertions(+), 1016 deletions(-) delete mode 100644 opengl/libs/EGL/eglApi.cpp delete mode 100644 opengl/libs/EGL/egl_platform_entries.h delete mode 100644 opengl/libs/platform_entries.in (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index fb6a221973..78309d419f 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -141,7 +141,6 @@ cc_library_shared { "EGL/egl_display.cpp", "EGL/egl_object.cpp", "EGL/egl.cpp", - "EGL/eglApi.cpp", "EGL/egl_platform_entries.cpp", "EGL/Loader.cpp", "EGL/egl_angle_platform.cpp", diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index cd227caad6..87f0fe1f5c 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -33,7 +33,6 @@ #endif #include -#include "egl_platform_entries.h" #include "egl_trace.h" #include "egldefs.h" @@ -238,12 +237,12 @@ void* Loader::open(egl_connection_t* cnx) 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 @@ void *Loader::load_driver(const char* kind, return nullptr; } - if (mask & PLATFORM) { - // For each entrypoint tracked by the platform - char const* const* entries = platform_names; - EGLFuncPointer* curr = reinterpret_cast(&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 9cc73f376a..e88d1a285e 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -33,8 +33,7 @@ class Loader { 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 1229bc288d..708986016c 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -167,10 +167,6 @@ GLint egl_get_num_extensions_for_current_context() { return (GLint)c->tokenized_gl_extensions.size(); } -egl_connection_t* egl_get_connection() { - return &gEGLImpl; -} - // ---------------------------------------------------------------------------- // this mutex protects: @@ -266,11 +262,6 @@ char const * const egl_names[] = { 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 deleted file mode 100644 index 8202c4eaae..0000000000 --- a/opengl/libs/EGL/eglApi.cpp +++ /dev/null @@ -1,585 +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. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include -#include - -#include "../egl_impl.h" - -#include "egl_layers.h" -#include "egl_platform_entries.h" -#include "egl_tls.h" -#include "egl_trace.h" - -using namespace android; - -namespace android { - -extern EGLBoolean egl_init_drivers(); - -} // namespace android - -static inline void clearError() { - egl_tls_t::clearError(); -} - -EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { - ATRACE_CALL(); - clearError(); - - 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); -} - -EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglInitialize(dpy, major, minor); -} - -EGLBoolean eglTerminate(EGLDisplay dpy) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglTerminate(dpy); -} - -EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, - EGLint* num_config) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetConfigs(dpy, configs, config_size, num_config); -} - -EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, - EGLint config_size, EGLint* num_config) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglChooseConfig(dpy, attrib_list, configs, config_size, num_config); -} - -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); -} - -EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, - const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateWindowSurface(dpy, config, window, attrib_list); -} - -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); -} - -EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreatePbufferSurface(dpy, config, attrib_list); -} - -EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDestroySurface(dpy, surface); -} - -EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQuerySurface(dpy, surface, attribute, value); -} - -void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { - ATRACE_CALL(); - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - cnx->platform.eglBeginFrame(dpy, surface); -} - -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(); - } -} - -__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. - - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - setError(EGL_BAD_PARAMETER, NULL); - return nullptr; - } - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetProcAddress(procname); -} - -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); -} - -EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { - ATRACE_CALL(); - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglSwapBuffers(dpy, surface); -} - -EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, NativePixmapType target) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCopyBuffers(dpy, surface, target); -} - -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) { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - - 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); - } - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryAPI(); -} - -EGLBoolean eglReleaseThread(void) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglReleaseThread(); -} - -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); -} - -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); -} - -EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglUnlockSurfaceKHR(dpy, surface); -} - -EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, - EGLClientBuffer buffer, const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list); -} - -EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDestroyImageKHR(dpy, img); -} - -EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateSyncKHR(dpy, type, attrib_list); -} - -EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDestroySyncKHR(dpy, sync); -} - -EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglSignalSyncKHR(dpy, sync, mode); -} - -EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglClientWaitSyncKHR(dpy, sync, flags, timeout); -} - -EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetSyncAttribKHR(dpy, sync, attribute, value); -} - -EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateStreamKHR(dpy, attrib_list); -} - -EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDestroyStreamKHR(dpy, stream); -} - -EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, - EGLint value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglStreamAttribKHR(dpy, stream, attribute, value); -} - -EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, - EGLint* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryStreamKHR(dpy, stream, attribute, value); -} - -EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, - EGLuint64KHR* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryStreamu64KHR(dpy, stream, attribute, value); -} - -EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, - EGLTimeKHR* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryStreamTimeKHR(dpy, stream, attribute, value); -} - -EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, - const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateStreamProducerSurfaceKHR(dpy, config, stream, attrib_list); -} - -EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglStreamConsumerGLTextureExternalKHR(dpy, stream); -} - -EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglStreamConsumerAcquireKHR(dpy, stream); -} - -EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglStreamConsumerReleaseKHR(dpy, stream); -} - -EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetStreamFileDescriptorKHR(dpy, stream); -} - -EGLStreamKHR eglCreateStreamFromFileDescriptorKHR(EGLDisplay dpy, - EGLNativeFileDescriptorKHR file_descriptor) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateStreamFromFileDescriptorKHR(dpy, file_descriptor); -} - -EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglWaitSyncKHR(dpy, sync, flags); -} - -EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDupNativeFenceFDANDROID(dpy, sync); -} - -EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglPresentationTimeANDROID(dpy, surface, time); -} - -EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer* buffer) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetNativeClientBufferANDROID(buffer); -} - -EGLuint64NV eglGetSystemTimeFrequencyNV() { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); - } - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetSystemTimeFrequencyNV(); -} - -EGLuint64NV eglGetSystemTimeNV() { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); - } - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetSystemTimeNV(); -} - -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); -} - -EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR* frameId) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetNextFrameIdANDROID(dpy, surface, frameId); -} - -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); -} - -EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint name) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetCompositorTimingSupportedANDROID(dpy, surface, name); -} - -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); -} - -EGLBoolean eglGetFrameTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, - EGLint timestamp) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetFrameTimestampSupportedANDROID(dpy, surface, timestamp); -} diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index 296ee44ce5..d2dc514ff2 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -16,8 +16,6 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "egl_platform_entries.h" - #include #include #include @@ -270,19 +268,30 @@ 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 eglGetDisplayImpl(EGLNativeDisplayType display) +EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { + ATRACE_CALL(); + clearError(); + uintptr_t index = reinterpret_cast(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); + } + EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); return dpy; } @@ -291,8 +300,10 @@ EGLDisplay eglGetDisplayImpl(EGLNativeDisplayType display) // Initialization // ---------------------------------------------------------------------------- -EGLBoolean eglInitializeImpl(EGLDisplay dpy, EGLint *major, EGLint *minor) +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { + clearError(); + egl_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -301,12 +312,14 @@ EGLBoolean eglInitializeImpl(EGLDisplay dpy, EGLint *major, EGLint *minor) return res; } -EGLBoolean eglTerminateImpl(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_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -319,10 +332,12 @@ EGLBoolean eglTerminateImpl(EGLDisplay dpy) // configuration // ---------------------------------------------------------------------------- -EGLBoolean eglGetConfigsImpl(EGLDisplay dpy, - EGLConfig *configs, - EGLint config_size, EGLint *num_config) +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; @@ -342,10 +357,12 @@ EGLBoolean eglGetConfigsImpl(EGLDisplay dpy, return res; } -EGLBoolean eglChooseConfigImpl( 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; @@ -419,9 +436,11 @@ EGLBoolean eglChooseConfigImpl( EGLDisplay dpy, const EGLint *attrib_list, return res; } -EGLBoolean eglGetConfigAttribImpl(EGLDisplay dpy, EGLConfig config, +EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { + clearError(); + egl_connection_t* cnx = nullptr; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (!dp) return EGL_FALSE; @@ -682,11 +701,12 @@ EGLBoolean sendSurfaceMetadata(egl_surface_t* s) { return EGL_TRUE; } -EGLSurface eglCreateWindowSurfaceImpl( EGLDisplay dpy, EGLConfig config, - NativeWindowType window, - const EGLint *attrib_list) +EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, + NativeWindowType window, + const EGLint *attrib_list) { const EGLint *origAttribList = attrib_list; + clearError(); egl_connection_t* cnx = nullptr; egl_display_ptr dp = validate_display_connection(dpy, cnx); @@ -771,10 +791,12 @@ EGLSurface eglCreateWindowSurfaceImpl( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLSurface eglCreatePixmapSurfaceImpl( EGLDisplay dpy, EGLConfig config, - NativePixmapType pixmap, - const EGLint *attrib_list) +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) { @@ -804,9 +826,11 @@ EGLSurface eglCreatePixmapSurfaceImpl( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLSurface eglCreatePbufferSurfaceImpl( EGLDisplay dpy, EGLConfig config, - const EGLint *attrib_list) +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) { @@ -836,8 +860,10 @@ EGLSurface eglCreatePbufferSurfaceImpl( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -853,9 +879,11 @@ EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface) return result; } -EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface, - EGLint attribute, EGLint *value) +EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -874,7 +902,10 @@ EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface, return s->cnx->egl.eglQuerySurface(dp->disp.dpy, s->surface, attribute, value); } -void EGLAPI eglBeginFrameImpl(EGLDisplay dpy, EGLSurface surface) { +void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { + ATRACE_CALL(); + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return; @@ -890,9 +921,11 @@ void EGLAPI eglBeginFrameImpl(EGLDisplay dpy, EGLSurface surface) { // Contexts // ---------------------------------------------------------------------------- -EGLContext eglCreateContextImpl(EGLDisplay dpy, EGLConfig config, - EGLContext share_list, const EGLint *attrib_list) +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) { @@ -929,8 +962,10 @@ EGLContext eglCreateContextImpl(EGLDisplay dpy, EGLConfig config, return EGL_NO_CONTEXT; } -EGLBoolean eglDestroyContextImpl(EGLDisplay dpy, EGLContext ctx) +EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -947,9 +982,11 @@ EGLBoolean eglDestroyContextImpl(EGLDisplay dpy, EGLContext ctx) return result; } -EGLBoolean eglMakeCurrentImpl( EGLDisplay dpy, EGLSurface draw, - EGLSurface read, EGLContext ctx) +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); @@ -1039,9 +1076,12 @@ EGLBoolean eglMakeCurrentImpl( EGLDisplay dpy, EGLSurface draw, return result; } -EGLBoolean eglQueryContextImpl( EGLDisplay dpy, EGLContext ctx, - EGLint attribute, EGLint *value) + +EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1054,19 +1094,24 @@ EGLBoolean eglQueryContextImpl( EGLDisplay dpy, EGLContext ctx, } -EGLContext eglGetCurrentContextImpl(void) +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 eglGetCurrentSurfaceImpl(EGLint readdraw) +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); @@ -1080,11 +1125,13 @@ EGLSurface eglGetCurrentSurfaceImpl(EGLint readdraw) return EGL_NO_SURFACE; } -EGLDisplay eglGetCurrentDisplayImpl(void) +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); @@ -1094,8 +1141,10 @@ EGLDisplay eglGetCurrentDisplayImpl(void) return EGL_NO_DISPLAY; } -EGLBoolean eglWaitGLImpl(void) +EGLBoolean eglWaitGL(void) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1103,8 +1152,10 @@ EGLBoolean eglWaitGLImpl(void) return cnx->egl.eglWaitGL(); } -EGLBoolean eglWaitNativeImpl(EGLint engine) +EGLBoolean eglWaitNative(EGLint engine) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1112,7 +1163,7 @@ EGLBoolean eglWaitNativeImpl(EGLint engine) return cnx->egl.eglWaitNative(engine); } -EGLint eglGetErrorImpl(void) +EGLint eglGetError(void) { EGLint err = EGL_SUCCESS; egl_connection_t* const cnx = &gEGLImpl; @@ -1142,8 +1193,19 @@ static __eglMustCastToProperFunctionPointerType findBuiltinWrapper( return nullptr; } -__eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procname) +__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. + + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + setError(EGL_BAD_PARAMETER, NULL); + return nullptr; + } + if (FILTER_EXTENSIONS(procname)) { return nullptr; } @@ -1284,9 +1346,12 @@ private: std::mutex mMutex; }; -EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, +EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, EGLint *rects, EGLint n_rects) { + ATRACE_CALL(); + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1351,14 +1416,16 @@ EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, } } -EGLBoolean eglSwapBuffersImpl(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { - return eglSwapBuffersWithDamageKHRImpl(dpy, surface, nullptr, 0); + return eglSwapBuffersWithDamageKHR(dpy, surface, nullptr, 0); } -EGLBoolean eglCopyBuffersImpl( EGLDisplay dpy, EGLSurface surface, - NativePixmapType target) +EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, + NativePixmapType target) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1370,8 +1437,10 @@ EGLBoolean eglCopyBuffersImpl( EGLDisplay dpy, EGLSurface surface, return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); } -const char* eglQueryStringImpl(EGLDisplay dpy, EGLint name) +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 @@ -1400,8 +1469,10 @@ const char* eglQueryStringImpl(EGLDisplay dpy, EGLint name) return setError(EGL_BAD_PARAMETER, (const char *)nullptr); } -EGLAPI const char* eglQueryStringImplementationANDROIDImpl(EGLDisplay dpy, EGLint name) +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; @@ -1424,9 +1495,11 @@ EGLAPI const char* eglQueryStringImplementationANDROIDImpl(EGLDisplay dpy, EGLin // EGL 1.1 // ---------------------------------------------------------------------------- -EGLBoolean eglSurfaceAttribImpl( +EGLBoolean eglSurfaceAttrib( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1463,9 +1536,11 @@ EGLBoolean eglSurfaceAttribImpl( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglBindTexImageImpl( +EGLBoolean eglBindTexImage( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1481,9 +1556,11 @@ EGLBoolean eglBindTexImageImpl( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglReleaseTexImageImpl( +EGLBoolean eglReleaseTexImage( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1499,8 +1576,10 @@ EGLBoolean eglReleaseTexImageImpl( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglSwapIntervalImpl(EGLDisplay dpy, EGLint interval) +EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1518,8 +1597,10 @@ EGLBoolean eglSwapIntervalImpl(EGLDisplay dpy, EGLint interval) // EGL 1.2 // ---------------------------------------------------------------------------- -EGLBoolean eglWaitClientImpl(void) +EGLBoolean eglWaitClient(void) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1533,8 +1614,14 @@ EGLBoolean eglWaitClientImpl(void) return res; } -EGLBoolean eglBindAPIImpl(EGLenum api) +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; @@ -1544,8 +1631,14 @@ EGLBoolean eglBindAPIImpl(EGLenum api) return res; } -EGLenum eglQueryAPIImpl(void) +EGLenum eglQueryAPI(void) { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglQueryAPI) { return cnx->egl.eglQueryAPI(); @@ -1555,8 +1648,10 @@ EGLenum eglQueryAPIImpl(void) return EGL_OPENGL_ES_API; } -EGLBoolean eglReleaseThreadImpl(void) +EGLBoolean eglReleaseThread(void) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglReleaseThread) { cnx->egl.eglReleaseThread(); @@ -1569,10 +1664,12 @@ EGLBoolean eglReleaseThreadImpl(void) return EGL_TRUE; } -EGLSurface eglCreatePbufferFromClientBufferImpl( +EGLSurface eglCreatePbufferFromClientBuffer( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) { + clearError(); + egl_connection_t* cnx = nullptr; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (!dp) return EGL_FALSE; @@ -1587,9 +1684,11 @@ EGLSurface eglCreatePbufferFromClientBufferImpl( // EGL_EGLEXT_VERSION 3 // ---------------------------------------------------------------------------- -EGLBoolean eglLockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1605,8 +1704,10 @@ EGLBoolean eglLockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface, return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglUnlockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1621,9 +1722,11 @@ EGLBoolean eglUnlockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } -EGLImageKHR eglCreateImageKHRImpl(EGLDisplay dpy, EGLContext ctx, EGLenum target, +EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_IMAGE_KHR; @@ -1641,8 +1744,10 @@ EGLImageKHR eglCreateImageKHRImpl(EGLDisplay dpy, EGLContext ctx, EGLenum target return result; } -EGLBoolean eglDestroyImageKHRImpl(EGLDisplay dpy, EGLImageKHR img) +EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1659,8 +1764,10 @@ EGLBoolean eglDestroyImageKHRImpl(EGLDisplay dpy, EGLImageKHR img) // ---------------------------------------------------------------------------- -EGLSyncKHR eglCreateSyncKHRImpl(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) +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; @@ -1672,8 +1779,10 @@ EGLSyncKHR eglCreateSyncKHRImpl(EGLDisplay dpy, EGLenum type, const EGLint *attr return result; } -EGLBoolean eglDestroySyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync) +EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1685,7 +1794,9 @@ EGLBoolean eglDestroySyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync) return result; } -EGLBoolean eglSignalSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { +EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1698,9 +1809,11 @@ EGLBoolean eglSignalSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { return result; } -EGLint eglClientWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, +EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1713,9 +1826,11 @@ EGLint eglClientWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, return result; } -EGLBoolean eglGetSyncAttribKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, +EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1728,8 +1843,10 @@ EGLBoolean eglGetSyncAttribKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, return result; } -EGLStreamKHR eglCreateStreamKHRImpl(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; @@ -1742,8 +1859,10 @@ EGLStreamKHR eglCreateStreamKHRImpl(EGLDisplay dpy, const EGLint *attrib_list) return result; } -EGLBoolean eglDestroyStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) +EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1756,9 +1875,11 @@ EGLBoolean eglDestroyStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) return result; } -EGLBoolean eglStreamAttribKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1771,9 +1892,11 @@ EGLBoolean eglStreamAttribKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1786,9 +1909,11 @@ EGLBoolean eglQueryStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamu64KHRImpl(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1801,9 +1926,11 @@ EGLBoolean eglQueryStreamu64KHRImpl(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamTimeKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1816,9 +1943,11 @@ EGLBoolean eglQueryStreamTimeKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLSurface eglCreateStreamProducerSurfaceKHRImpl(EGLDisplay dpy, EGLConfig config, +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; @@ -1835,9 +1964,11 @@ EGLSurface eglCreateStreamProducerSurfaceKHRImpl(EGLDisplay dpy, EGLConfig confi return EGL_NO_SURFACE; } -EGLBoolean eglStreamConsumerGLTextureExternalKHRImpl(EGLDisplay dpy, +EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1850,9 +1981,11 @@ EGLBoolean eglStreamConsumerGLTextureExternalKHRImpl(EGLDisplay dpy, return result; } -EGLBoolean eglStreamConsumerAcquireKHRImpl(EGLDisplay dpy, +EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1865,9 +1998,11 @@ EGLBoolean eglStreamConsumerAcquireKHRImpl(EGLDisplay dpy, return result; } -EGLBoolean eglStreamConsumerReleaseKHRImpl(EGLDisplay dpy, +EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1880,9 +2015,11 @@ EGLBoolean eglStreamConsumerReleaseKHRImpl(EGLDisplay dpy, return result; } -EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHRImpl( +EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR( EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR; @@ -1895,9 +2032,11 @@ EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHRImpl( return result; } -EGLStreamKHR eglCreateStreamFromFileDescriptorKHRImpl( +EGLStreamKHR eglCreateStreamFromFileDescriptorKHR( EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_STREAM_KHR; @@ -1914,7 +2053,8 @@ EGLStreamKHR eglCreateStreamFromFileDescriptorKHRImpl( // EGL_EGLEXT_VERSION 15 // ---------------------------------------------------------------------------- -EGLint eglWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { +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; @@ -1929,8 +2069,10 @@ EGLint eglWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { // ANDROID extensions // ---------------------------------------------------------------------------- -EGLint eglDupNativeFenceFDANDROIDImpl(EGLDisplay dpy, EGLSyncKHR sync) +EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID; @@ -1942,9 +2084,11 @@ EGLint eglDupNativeFenceFDANDROIDImpl(EGLDisplay dpy, EGLSyncKHR sync) return result; } -EGLBoolean eglPresentationTimeANDROIDImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return EGL_FALSE; @@ -1962,7 +2106,8 @@ EGLBoolean eglPresentationTimeANDROIDImpl(EGLDisplay dpy, EGLSurface surface, return EGL_TRUE; } -EGLClientBuffer eglGetNativeClientBufferANDROIDImpl(const AHardwareBuffer *buffer) { +EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) { + clearError(); // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus // this function cannot be implemented when this libEGL is built for // vendors. @@ -1977,8 +2122,14 @@ EGLClientBuffer eglGetNativeClientBufferANDROIDImpl(const AHardwareBuffer *buffe // ---------------------------------------------------------------------------- // NVIDIA extensions // ---------------------------------------------------------------------------- -EGLuint64NV eglGetSystemTimeFrequencyNVImpl() +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; @@ -1989,8 +2140,14 @@ EGLuint64NV eglGetSystemTimeFrequencyNVImpl() return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); } -EGLuint64NV eglGetSystemTimeNVImpl() +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; @@ -2004,9 +2161,11 @@ EGLuint64NV eglGetSystemTimeNVImpl() // ---------------------------------------------------------------------------- // Partial update extension // ---------------------------------------------------------------------------- -EGLBoolean eglSetDamageRegionKHRImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { setError(EGL_BAD_DISPLAY, EGL_FALSE); @@ -2028,8 +2187,10 @@ EGLBoolean eglSetDamageRegionKHRImpl(EGLDisplay dpy, EGLSurface surface, return EGL_FALSE; } -EGLBoolean eglGetNextFrameIdANDROIDImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2060,9 +2221,11 @@ EGLBoolean eglGetNextFrameIdANDROIDImpl(EGLDisplay dpy, EGLSurface surface, return EGL_TRUE; } -EGLBoolean eglGetCompositorTimingANDROIDImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2115,9 +2278,11 @@ EGLBoolean eglGetCompositorTimingANDROIDImpl(EGLDisplay dpy, EGLSurface surface, } } -EGLBoolean eglGetCompositorTimingSupportedANDROIDImpl( +EGLBoolean eglGetCompositorTimingSupportedANDROID( EGLDisplay dpy, EGLSurface surface, EGLint name) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2145,10 +2310,12 @@ EGLBoolean eglGetCompositorTimingSupportedANDROIDImpl( } } -EGLBoolean eglGetFrameTimestampsANDROIDImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2231,9 +2398,11 @@ EGLBoolean eglGetFrameTimestampsANDROIDImpl(EGLDisplay dpy, EGLSurface surface, } } -EGLBoolean eglGetFrameTimestampSupportedANDROIDImpl( +EGLBoolean eglGetFrameTimestampSupportedANDROID( EGLDisplay dpy, EGLSurface surface, EGLint timestamp) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2274,182 +2443,3 @@ EGLBoolean eglGetFrameTimestampSupportedANDROIDImpl( 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 7cd80d6dc2..0000000000 --- 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 - -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 d8606d3e87..449ffc73c0 100644 --- a/opengl/libs/EGL/egldefs.h +++ b/opengl/libs/EGL/egldefs.h @@ -38,16 +38,12 @@ struct egl_connection_t { }; 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 "C" void gl_noop(); 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 65f50f54fb..f7fde9625f 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -301,31 +301,71 @@ extern "C" { } 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 0af050175b..a8855efa57 100644 --- a/opengl/libs/egl_impl.h +++ b/opengl/libs/egl_impl.h @@ -21,18 +21,15 @@ #include #include -#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 63a0e140cc..81dbe0e34b 100644 --- a/opengl/libs/hooks.h +++ b/opengl/libs/hooks.h @@ -59,10 +59,6 @@ namespace android { #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 b28f6ccac8..0000000000 --- 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*) -- cgit v1.2.3-59-g8ed1b From 8dec3913042c8f199c79168980da8bfc78da97a1 Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Fri, 12 Oct 2018 14:34:50 -0600 Subject: Revert "Rename eglApi.cpp to egl_platform_entries.cpp" This reverts commit 489e5df936aed8bc96ea33bbf2fb668d129eb702. Bug: 110883880 Test: Chrome no longer crashes Change-Id: I1022ad2ccc647f35fc074422c538e39613be43c2 --- opengl/libs/Android.bp | 2 +- opengl/libs/EGL/eglApi.cpp | 2445 ++++++++++++++++++++++++++++++ opengl/libs/EGL/egl_platform_entries.cpp | 2445 ------------------------------ 3 files changed, 2446 insertions(+), 2446 deletions(-) create mode 100644 opengl/libs/EGL/eglApi.cpp delete mode 100644 opengl/libs/EGL/egl_platform_entries.cpp (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 78309d419f..2a6dee4f4f 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -141,7 +141,7 @@ cc_library_shared { "EGL/egl_display.cpp", "EGL/egl_object.cpp", "EGL/egl.cpp", - "EGL/egl_platform_entries.cpp", + "EGL/eglApi.cpp", "EGL/Loader.cpp", "EGL/egl_angle_platform.cpp", ], diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp new file mode 100644 index 0000000000..d2dc514ff2 --- /dev/null +++ b/opengl/libs/EGL/eglApi.cpp @@ -0,0 +1,2445 @@ +/* + ** 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 +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../egl_impl.h" + +#include "egl_display.h" +#include "egl_object.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 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(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); + } + + EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); + return dpy; +} + +// ---------------------------------------------------------------------------- +// Initialization +// ---------------------------------------------------------------------------- + +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + clearError(); + + 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) +{ + // 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_display_ptr dp = get_display(dpy); + if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + + EGLBoolean res = dp->terminate(); + + return res; +} + +// ---------------------------------------------------------------------------- +// 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; + 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) +{ + 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; + 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) +{ + clearError(); + + 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 getDriverColorSpaces(egl_display_ptr dp, + android_pixel_format format) { + std::vector 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* 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 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 eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, + NativeWindowType window, + const EGLint *attrib_list) +{ + const EGLint *origAttribList = attrib_list; + clearError(); + + 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 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(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 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 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(); + + 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 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. + + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + setError(EGL_BAD_PARAMETER, NULL); + return nullptr; + } + + 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); + + 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; +} + +class FrameCompletionThread { +public: + + static void queueSync(EGLSyncKHR sync) { + static FrameCompletionThread thread; + + char name[64]; + + std::lock_guard 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 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 lock(mMutex); + mQueue.pop_front(); + mFramesCompleted++; + ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size())); + } + } + + uint32_t mFramesQueued; + uint32_t mFramesCompleted; + std::deque mQueue; + std::condition_variable mCondition; + std::mutex mMutex; +}; + +EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, + EGLint *rects, EGLint n_rects) +{ + ATRACE_CALL(); + clearError(); + + 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 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) +{ + 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; + 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 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; + if (cnx->dso && cnx->egl.eglBindAPI) { + res = cnx->egl.eglBindAPI(api); + } + return res; +} + +EGLenum eglQueryAPI(void) +{ + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + + 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 eglReleaseThread(void) +{ + clearError(); + + 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 eglCreatePbufferFromClientBuffer( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list) +{ + clearError(); + + 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 eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, + const EGLint *attrib_list) +{ + 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.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) +{ + 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.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) +{ + 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; + 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) +{ + clearError(); + + 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 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; + if (cnx->dso && cnx->egl.eglCreateSyncKHR) { + result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); + } + return result; +} + +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; + 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; + 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) +{ + clearError(); + + 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 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; + 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) +{ + 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; + if (cnx->dso && cnx->egl.eglCreateStreamKHR) { + result = cnx->egl.eglCreateStreamKHR( + dp->disp.dpy, attrib_list); + } + return result; +} + +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; + 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) +{ + clearError(); + + 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 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; + 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) +{ + clearError(); + + 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 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; + 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) +{ + clearError(); + + 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 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; + if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) { + result = cnx->egl.eglStreamConsumerGLTextureExternalKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) { + result = cnx->egl.eglStreamConsumerAcquireKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) { + result = cnx->egl.eglStreamConsumerReleaseKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) { + result = cnx->egl.eglGetStreamFileDescriptorKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + 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; + if (cnx->dso && cnx->egl.eglWaitSyncKHR) { + result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); + } + return result; +} + +// ---------------------------------------------------------------------------- +// 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; + if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { + result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); + } + return result; +} + +EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, + EGLnsecsANDROID time) +{ + clearError(); + + 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) { + clearError(); + // 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(AHardwareBuffer_to_ANativeWindowBuffer(buffer)); +#else + return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr); +#endif +} + +// ---------------------------------------------------------------------------- +// 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; + + if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { + return cnx->egl.eglGetSystemTimeFrequencyNV(); + } + + return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); +} + +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; + + if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { + return cnx->egl.eglGetSystemTimeNV(); + } + + return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); +} + +// ---------------------------------------------------------------------------- +// Partial update extension +// ---------------------------------------------------------------------------- +EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, + EGLint *rects, EGLint n_rects) +{ + clearError(); + + 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) { + clearError(); + + 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) +{ + clearError(); + + 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) +{ + clearError(); + + 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) +{ + clearError(); + + 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) +{ + clearError(); + + 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_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp deleted file mode 100644 index d2dc514ff2..0000000000 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ /dev/null @@ -1,2445 +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 -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "../egl_impl.h" - -#include "egl_display.h" -#include "egl_object.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 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(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); - } - - EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); - return dpy; -} - -// ---------------------------------------------------------------------------- -// Initialization -// ---------------------------------------------------------------------------- - -EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) -{ - clearError(); - - 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) -{ - // 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_display_ptr dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - - EGLBoolean res = dp->terminate(); - - return res; -} - -// ---------------------------------------------------------------------------- -// 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; - 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) -{ - 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; - 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) -{ - clearError(); - - 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 getDriverColorSpaces(egl_display_ptr dp, - android_pixel_format format) { - std::vector 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* 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 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 eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, - NativeWindowType window, - const EGLint *attrib_list) -{ - const EGLint *origAttribList = attrib_list; - clearError(); - - 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 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(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 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 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(); - - 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 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. - - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - setError(EGL_BAD_PARAMETER, NULL); - return nullptr; - } - - 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); - - 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; -} - -class FrameCompletionThread { -public: - - static void queueSync(EGLSyncKHR sync) { - static FrameCompletionThread thread; - - char name[64]; - - std::lock_guard 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 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 lock(mMutex); - mQueue.pop_front(); - mFramesCompleted++; - ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size())); - } - } - - uint32_t mFramesQueued; - uint32_t mFramesCompleted; - std::deque mQueue; - std::condition_variable mCondition; - std::mutex mMutex; -}; - -EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, - EGLint *rects, EGLint n_rects) -{ - ATRACE_CALL(); - clearError(); - - 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 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) -{ - 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; - 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 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; - if (cnx->dso && cnx->egl.eglBindAPI) { - res = cnx->egl.eglBindAPI(api); - } - return res; -} - -EGLenum eglQueryAPI(void) -{ - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - - 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 eglReleaseThread(void) -{ - clearError(); - - 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 eglCreatePbufferFromClientBuffer( - EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, - EGLConfig config, const EGLint *attrib_list) -{ - clearError(); - - 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 eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, - const EGLint *attrib_list) -{ - 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.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) -{ - 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.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) -{ - 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; - 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) -{ - clearError(); - - 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 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; - if (cnx->dso && cnx->egl.eglCreateSyncKHR) { - result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); - } - return result; -} - -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; - 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; - 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) -{ - clearError(); - - 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 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; - 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) -{ - 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; - if (cnx->dso && cnx->egl.eglCreateStreamKHR) { - result = cnx->egl.eglCreateStreamKHR( - dp->disp.dpy, attrib_list); - } - return result; -} - -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; - 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) -{ - clearError(); - - 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 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; - 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) -{ - clearError(); - - 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 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; - 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) -{ - clearError(); - - 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 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; - if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) { - result = cnx->egl.eglStreamConsumerGLTextureExternalKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) { - result = cnx->egl.eglStreamConsumerAcquireKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) { - result = cnx->egl.eglStreamConsumerReleaseKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) { - result = cnx->egl.eglGetStreamFileDescriptorKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - 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; - if (cnx->dso && cnx->egl.eglWaitSyncKHR) { - result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); - } - return result; -} - -// ---------------------------------------------------------------------------- -// 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; - if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { - result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); - } - return result; -} - -EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, - EGLnsecsANDROID time) -{ - clearError(); - - 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) { - clearError(); - // 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(AHardwareBuffer_to_ANativeWindowBuffer(buffer)); -#else - return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr); -#endif -} - -// ---------------------------------------------------------------------------- -// 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; - - if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { - return cnx->egl.eglGetSystemTimeFrequencyNV(); - } - - return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); -} - -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; - - if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { - return cnx->egl.eglGetSystemTimeNV(); - } - - return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); -} - -// ---------------------------------------------------------------------------- -// Partial update extension -// ---------------------------------------------------------------------------- -EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, - EGLint *rects, EGLint n_rects) -{ - clearError(); - - 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) { - clearError(); - - 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) -{ - clearError(); - - 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) -{ - clearError(); - - 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) -{ - clearError(); - - 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) -{ - clearError(); - - 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; - } -} -- cgit v1.2.3-59-g8ed1b From 0ec5d380a9468f194737ac395dd9ca1453e608fe Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Mon, 15 Oct 2018 07:22:07 -0600 Subject: Revert "Revert "Rename eglApi.cpp to egl_platform_entries.cpp"" This reverts commit 8dec3913042c8f199c79168980da8bfc78da97a1. Test: cts-tradefed run singleCommand cts -m CtsGpuToolsHostTestCases Test: Chromium starts up Test: deqp - EGL, GLES2, GLES3 Bug: 110883880 Change-Id: I2e2e142c54ac406c978a41a016c4c0df3db7cdfa --- opengl/libs/Android.bp | 2 +- opengl/libs/EGL/eglApi.cpp | 2445 ------------------------------ opengl/libs/EGL/egl_platform_entries.cpp | 2445 ++++++++++++++++++++++++++++++ 3 files changed, 2446 insertions(+), 2446 deletions(-) delete mode 100644 opengl/libs/EGL/eglApi.cpp create mode 100644 opengl/libs/EGL/egl_platform_entries.cpp (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 2a6dee4f4f..78309d419f 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -141,7 +141,7 @@ cc_library_shared { "EGL/egl_display.cpp", "EGL/egl_object.cpp", "EGL/egl.cpp", - "EGL/eglApi.cpp", + "EGL/egl_platform_entries.cpp", "EGL/Loader.cpp", "EGL/egl_angle_platform.cpp", ], diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp deleted file mode 100644 index d2dc514ff2..0000000000 --- a/opengl/libs/EGL/eglApi.cpp +++ /dev/null @@ -1,2445 +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 -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "../egl_impl.h" - -#include "egl_display.h" -#include "egl_object.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 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(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); - } - - EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); - return dpy; -} - -// ---------------------------------------------------------------------------- -// Initialization -// ---------------------------------------------------------------------------- - -EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) -{ - clearError(); - - 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) -{ - // 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_display_ptr dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - - EGLBoolean res = dp->terminate(); - - return res; -} - -// ---------------------------------------------------------------------------- -// 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; - 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) -{ - 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; - 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) -{ - clearError(); - - 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 getDriverColorSpaces(egl_display_ptr dp, - android_pixel_format format) { - std::vector 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* 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 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 eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, - NativeWindowType window, - const EGLint *attrib_list) -{ - const EGLint *origAttribList = attrib_list; - clearError(); - - 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 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(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 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 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(); - - 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 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. - - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - setError(EGL_BAD_PARAMETER, NULL); - return nullptr; - } - - 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); - - 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; -} - -class FrameCompletionThread { -public: - - static void queueSync(EGLSyncKHR sync) { - static FrameCompletionThread thread; - - char name[64]; - - std::lock_guard 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 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 lock(mMutex); - mQueue.pop_front(); - mFramesCompleted++; - ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size())); - } - } - - uint32_t mFramesQueued; - uint32_t mFramesCompleted; - std::deque mQueue; - std::condition_variable mCondition; - std::mutex mMutex; -}; - -EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, - EGLint *rects, EGLint n_rects) -{ - ATRACE_CALL(); - clearError(); - - 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 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) -{ - 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; - 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 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; - if (cnx->dso && cnx->egl.eglBindAPI) { - res = cnx->egl.eglBindAPI(api); - } - return res; -} - -EGLenum eglQueryAPI(void) -{ - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - - 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 eglReleaseThread(void) -{ - clearError(); - - 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 eglCreatePbufferFromClientBuffer( - EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, - EGLConfig config, const EGLint *attrib_list) -{ - clearError(); - - 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 eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, - const EGLint *attrib_list) -{ - 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.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) -{ - 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.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) -{ - 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; - 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) -{ - clearError(); - - 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 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; - if (cnx->dso && cnx->egl.eglCreateSyncKHR) { - result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); - } - return result; -} - -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; - 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; - 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) -{ - clearError(); - - 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 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; - 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) -{ - 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; - if (cnx->dso && cnx->egl.eglCreateStreamKHR) { - result = cnx->egl.eglCreateStreamKHR( - dp->disp.dpy, attrib_list); - } - return result; -} - -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; - 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) -{ - clearError(); - - 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 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; - 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) -{ - clearError(); - - 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 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; - 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) -{ - clearError(); - - 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 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; - if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) { - result = cnx->egl.eglStreamConsumerGLTextureExternalKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) { - result = cnx->egl.eglStreamConsumerAcquireKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) { - result = cnx->egl.eglStreamConsumerReleaseKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) { - result = cnx->egl.eglGetStreamFileDescriptorKHR( - dp->disp.dpy, stream); - } - return result; -} - -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; - 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; - if (cnx->dso && cnx->egl.eglWaitSyncKHR) { - result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); - } - return result; -} - -// ---------------------------------------------------------------------------- -// 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; - if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { - result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); - } - return result; -} - -EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, - EGLnsecsANDROID time) -{ - clearError(); - - 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) { - clearError(); - // 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(AHardwareBuffer_to_ANativeWindowBuffer(buffer)); -#else - return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr); -#endif -} - -// ---------------------------------------------------------------------------- -// 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; - - if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { - return cnx->egl.eglGetSystemTimeFrequencyNV(); - } - - return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); -} - -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; - - if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { - return cnx->egl.eglGetSystemTimeNV(); - } - - return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); -} - -// ---------------------------------------------------------------------------- -// Partial update extension -// ---------------------------------------------------------------------------- -EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, - EGLint *rects, EGLint n_rects) -{ - clearError(); - - 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) { - clearError(); - - 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) -{ - clearError(); - - 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) -{ - clearError(); - - 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) -{ - clearError(); - - 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) -{ - clearError(); - - 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_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp new file mode 100644 index 0000000000..d2dc514ff2 --- /dev/null +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -0,0 +1,2445 @@ +/* + ** 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 +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../egl_impl.h" + +#include "egl_display.h" +#include "egl_object.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 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(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); + } + + EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); + return dpy; +} + +// ---------------------------------------------------------------------------- +// Initialization +// ---------------------------------------------------------------------------- + +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + clearError(); + + 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) +{ + // 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_display_ptr dp = get_display(dpy); + if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + + EGLBoolean res = dp->terminate(); + + return res; +} + +// ---------------------------------------------------------------------------- +// 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; + 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) +{ + 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; + 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) +{ + clearError(); + + 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 getDriverColorSpaces(egl_display_ptr dp, + android_pixel_format format) { + std::vector 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* 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 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 eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, + NativeWindowType window, + const EGLint *attrib_list) +{ + const EGLint *origAttribList = attrib_list; + clearError(); + + 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 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(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 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 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(); + + 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 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. + + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + setError(EGL_BAD_PARAMETER, NULL); + return nullptr; + } + + 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); + + 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; +} + +class FrameCompletionThread { +public: + + static void queueSync(EGLSyncKHR sync) { + static FrameCompletionThread thread; + + char name[64]; + + std::lock_guard 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 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 lock(mMutex); + mQueue.pop_front(); + mFramesCompleted++; + ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size())); + } + } + + uint32_t mFramesQueued; + uint32_t mFramesCompleted; + std::deque mQueue; + std::condition_variable mCondition; + std::mutex mMutex; +}; + +EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, + EGLint *rects, EGLint n_rects) +{ + ATRACE_CALL(); + clearError(); + + 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 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) +{ + 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; + 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 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; + if (cnx->dso && cnx->egl.eglBindAPI) { + res = cnx->egl.eglBindAPI(api); + } + return res; +} + +EGLenum eglQueryAPI(void) +{ + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + + 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 eglReleaseThread(void) +{ + clearError(); + + 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 eglCreatePbufferFromClientBuffer( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list) +{ + clearError(); + + 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 eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, + const EGLint *attrib_list) +{ + 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.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) +{ + 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.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) +{ + 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; + 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) +{ + clearError(); + + 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 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; + if (cnx->dso && cnx->egl.eglCreateSyncKHR) { + result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); + } + return result; +} + +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; + 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; + 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) +{ + clearError(); + + 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 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; + 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) +{ + 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; + if (cnx->dso && cnx->egl.eglCreateStreamKHR) { + result = cnx->egl.eglCreateStreamKHR( + dp->disp.dpy, attrib_list); + } + return result; +} + +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; + 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) +{ + clearError(); + + 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 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; + 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) +{ + clearError(); + + 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 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; + 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) +{ + clearError(); + + 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 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; + if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) { + result = cnx->egl.eglStreamConsumerGLTextureExternalKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) { + result = cnx->egl.eglStreamConsumerAcquireKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) { + result = cnx->egl.eglStreamConsumerReleaseKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) { + result = cnx->egl.eglGetStreamFileDescriptorKHR( + dp->disp.dpy, stream); + } + return result; +} + +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; + 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; + if (cnx->dso && cnx->egl.eglWaitSyncKHR) { + result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); + } + return result; +} + +// ---------------------------------------------------------------------------- +// 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; + if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { + result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); + } + return result; +} + +EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, + EGLnsecsANDROID time) +{ + clearError(); + + 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) { + clearError(); + // 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(AHardwareBuffer_to_ANativeWindowBuffer(buffer)); +#else + return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr); +#endif +} + +// ---------------------------------------------------------------------------- +// 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; + + if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { + return cnx->egl.eglGetSystemTimeFrequencyNV(); + } + + return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); +} + +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; + + if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { + return cnx->egl.eglGetSystemTimeNV(); + } + + return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); +} + +// ---------------------------------------------------------------------------- +// Partial update extension +// ---------------------------------------------------------------------------- +EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, + EGLint *rects, EGLint n_rects) +{ + clearError(); + + 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) { + clearError(); + + 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) +{ + clearError(); + + 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) +{ + clearError(); + + 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) +{ + clearError(); + + 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) +{ + clearError(); + + 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; + } +} -- cgit v1.2.3-59-g8ed1b From 68d1035a29036c4efe8ff741b9d943f6dbf2c23d Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Mon, 15 Oct 2018 07:22:09 -0600 Subject: Revert "Revert "Split platform functions from entrypoints"" This reverts commit d18d55344f9c1133c6b4f41aa6defcde1c32c7f3. Test: cts-tradefed run singleCommand cts -m CtsGpuToolsHostTestCases Test: Chromium starts up Test: deqp - EGL, GLES2, GLES3 Bug: 110883880 Change-Id: Id551cc0cdc9404c7c6a42c64693dedd217b18c7b --- opengl/libs/Android.bp | 1 + opengl/libs/EGL/Loader.cpp | 24 +- opengl/libs/EGL/Loader.h | 3 +- opengl/libs/EGL/egl.cpp | 9 + opengl/libs/EGL/eglApi.cpp | 585 +++++++++++++++++++++++++++++++ opengl/libs/EGL/egl_platform_entries.cpp | 522 +++++++++++++-------------- opengl/libs/EGL/egl_platform_entries.h | 31 ++ opengl/libs/EGL/egldefs.h | 5 + opengl/libs/GLES2/gl2.cpp | 64 +--- opengl/libs/egl_impl.h | 3 + opengl/libs/hooks.h | 4 + opengl/libs/platform_entries.in | 76 ++++ 12 files changed, 1016 insertions(+), 311 deletions(-) create mode 100644 opengl/libs/EGL/eglApi.cpp create mode 100644 opengl/libs/EGL/egl_platform_entries.h create mode 100644 opengl/libs/platform_entries.in (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 78309d419f..fb6a221973 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -141,6 +141,7 @@ cc_library_shared { "EGL/egl_display.cpp", "EGL/egl_object.cpp", "EGL/egl.cpp", + "EGL/eglApi.cpp", "EGL/egl_platform_entries.cpp", "EGL/Loader.cpp", "EGL/egl_angle_platform.cpp", diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 87f0fe1f5c..cd227caad6 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -33,6 +33,7 @@ #endif #include +#include "egl_platform_entries.h" #include "egl_trace.h" #include "egldefs.h" @@ -237,12 +238,12 @@ void* Loader::open(egl_connection_t* cnx) setEmulatorGlesValue(); - dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2); + dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2 | PLATFORM); if (dso) { hnd = new driver_t(dso); } else { // Always load EGL first - dso = load_driver("EGL", cnx, EGL); + dso = load_driver("EGL", cnx, EGL | PLATFORM); if (dso) { hnd = new driver_t(dso); hnd->set( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM ); @@ -634,6 +635,25 @@ void *Loader::load_driver(const char* kind, return nullptr; } + if (mask & PLATFORM) { + // For each entrypoint tracked by the platform + char const* const* entries = platform_names; + EGLFuncPointer* curr = reinterpret_cast(&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 e88d1a285e..9cc73f376a 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -33,7 +33,8 @@ class Loader { enum { EGL = 0x01, GLESv1_CM = 0x02, - GLESv2 = 0x04 + GLESv2 = 0x04, + PLATFORM = 0x08 }; struct driver_t { explicit driver_t(void* gles); diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 708986016c..1229bc288d 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -167,6 +167,10 @@ GLint egl_get_num_extensions_for_current_context() { return (GLint)c->tokenized_gl_extensions.size(); } +egl_connection_t* egl_get_connection() { + return &gEGLImpl; +} + // ---------------------------------------------------------------------------- // this mutex protects: @@ -262,6 +266,11 @@ char const * const egl_names[] = { 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 new file mode 100644 index 0000000000..8202c4eaae --- /dev/null +++ b/opengl/libs/EGL/eglApi.cpp @@ -0,0 +1,585 @@ +/* + ** 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. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include +#include + +#include "../egl_impl.h" + +#include "egl_layers.h" +#include "egl_platform_entries.h" +#include "egl_tls.h" +#include "egl_trace.h" + +using namespace android; + +namespace android { + +extern EGLBoolean egl_init_drivers(); + +} // namespace android + +static inline void clearError() { + egl_tls_t::clearError(); +} + +EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { + ATRACE_CALL(); + clearError(); + + 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); +} + +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglInitialize(dpy, major, minor); +} + +EGLBoolean eglTerminate(EGLDisplay dpy) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglTerminate(dpy); +} + +EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, + EGLint* num_config) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetConfigs(dpy, configs, config_size, num_config); +} + +EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, + EGLint config_size, EGLint* num_config) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglChooseConfig(dpy, attrib_list, configs, config_size, num_config); +} + +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); +} + +EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, + const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateWindowSurface(dpy, config, window, attrib_list); +} + +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); +} + +EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreatePbufferSurface(dpy, config, attrib_list); +} + +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglDestroySurface(dpy, surface); +} + +EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglQuerySurface(dpy, surface, attribute, value); +} + +void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { + ATRACE_CALL(); + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + cnx->platform.eglBeginFrame(dpy, surface); +} + +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(); + } +} + +__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. + + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + setError(EGL_BAD_PARAMETER, NULL); + return nullptr; + } + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetProcAddress(procname); +} + +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); +} + +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { + ATRACE_CALL(); + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglSwapBuffers(dpy, surface); +} + +EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, NativePixmapType target) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCopyBuffers(dpy, surface, target); +} + +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) { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + + 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); + } + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglQueryAPI(); +} + +EGLBoolean eglReleaseThread(void) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglReleaseThread(); +} + +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); +} + +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); +} + +EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglUnlockSurfaceKHR(dpy, surface); +} + +EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list); +} + +EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglDestroyImageKHR(dpy, img); +} + +EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateSyncKHR(dpy, type, attrib_list); +} + +EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglDestroySyncKHR(dpy, sync); +} + +EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglSignalSyncKHR(dpy, sync, mode); +} + +EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglClientWaitSyncKHR(dpy, sync, flags, timeout); +} + +EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint* value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetSyncAttribKHR(dpy, sync, attribute, value); +} + +EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateStreamKHR(dpy, attrib_list); +} + +EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglDestroyStreamKHR(dpy, stream); +} + +EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, + EGLint value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglStreamAttribKHR(dpy, stream, attribute, value); +} + +EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, + EGLint* value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglQueryStreamKHR(dpy, stream, attribute, value); +} + +EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, + EGLuint64KHR* value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglQueryStreamu64KHR(dpy, stream, attribute, value); +} + +EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, + EGLTimeKHR* value) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglQueryStreamTimeKHR(dpy, stream, attribute, value); +} + +EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, + const EGLint* attrib_list) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateStreamProducerSurfaceKHR(dpy, config, stream, attrib_list); +} + +EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglStreamConsumerGLTextureExternalKHR(dpy, stream); +} + +EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglStreamConsumerAcquireKHR(dpy, stream); +} + +EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglStreamConsumerReleaseKHR(dpy, stream); +} + +EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetStreamFileDescriptorKHR(dpy, stream); +} + +EGLStreamKHR eglCreateStreamFromFileDescriptorKHR(EGLDisplay dpy, + EGLNativeFileDescriptorKHR file_descriptor) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglCreateStreamFromFileDescriptorKHR(dpy, file_descriptor); +} + +EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglWaitSyncKHR(dpy, sync, flags); +} + +EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglDupNativeFenceFDANDROID(dpy, sync); +} + +EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglPresentationTimeANDROID(dpy, surface, time); +} + +EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer* buffer) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetNativeClientBufferANDROID(buffer); +} + +EGLuint64NV eglGetSystemTimeFrequencyNV() { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); + } + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetSystemTimeFrequencyNV(); +} + +EGLuint64NV eglGetSystemTimeNV() { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); + } + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetSystemTimeNV(); +} + +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); +} + +EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR* frameId) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetNextFrameIdANDROID(dpy, surface, frameId); +} + +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); +} + +EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint name) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetCompositorTimingSupportedANDROID(dpy, surface, name); +} + +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); +} + +EGLBoolean eglGetFrameTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, + EGLint timestamp) { + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + return cnx->platform.eglGetFrameTimestampSupportedANDROID(dpy, surface, timestamp); +} diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index d2dc514ff2..296ee44ce5 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -16,6 +16,8 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include "egl_platform_entries.h" + #include #include #include @@ -268,30 +270,19 @@ 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) +EGLDisplay eglGetDisplayImpl(EGLNativeDisplayType display) { - ATRACE_CALL(); - clearError(); - uintptr_t index = reinterpret_cast(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); - } - EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); return dpy; } @@ -300,10 +291,8 @@ EGLDisplay eglGetDisplay(EGLNativeDisplayType display) // Initialization // ---------------------------------------------------------------------------- -EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +EGLBoolean eglInitializeImpl(EGLDisplay dpy, EGLint *major, EGLint *minor) { - clearError(); - egl_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -312,14 +301,12 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) return res; } -EGLBoolean eglTerminate(EGLDisplay dpy) +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. - clearError(); - egl_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -332,12 +319,10 @@ EGLBoolean eglTerminate(EGLDisplay dpy) // configuration // ---------------------------------------------------------------------------- -EGLBoolean eglGetConfigs( EGLDisplay dpy, - EGLConfig *configs, - EGLint config_size, EGLint *num_config) +EGLBoolean eglGetConfigsImpl(EGLDisplay dpy, + EGLConfig *configs, + EGLint config_size, EGLint *num_config) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -357,12 +342,10 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy, return res; } -EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, - EGLConfig *configs, EGLint config_size, - EGLint *num_config) +EGLBoolean eglChooseConfigImpl( 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; @@ -436,11 +419,9 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, return res; } -EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, +EGLBoolean eglGetConfigAttribImpl(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { - clearError(); - egl_connection_t* cnx = nullptr; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (!dp) return EGL_FALSE; @@ -701,12 +682,11 @@ EGLBoolean sendSurfaceMetadata(egl_surface_t* s) { return EGL_TRUE; } -EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, - NativeWindowType window, - const EGLint *attrib_list) +EGLSurface eglCreateWindowSurfaceImpl( EGLDisplay dpy, EGLConfig config, + NativeWindowType window, + const EGLint *attrib_list) { const EGLint *origAttribList = attrib_list; - clearError(); egl_connection_t* cnx = nullptr; egl_display_ptr dp = validate_display_connection(dpy, cnx); @@ -791,12 +771,10 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, - NativePixmapType pixmap, - const EGLint *attrib_list) +EGLSurface eglCreatePixmapSurfaceImpl( 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) { @@ -826,11 +804,9 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, - const EGLint *attrib_list) +EGLSurface eglCreatePbufferSurfaceImpl( 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) { @@ -860,10 +836,8 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -879,11 +853,9 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) return result; } -EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, - EGLint attribute, EGLint *value) +EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -902,10 +874,7 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, return s->cnx->egl.eglQuerySurface(dp->disp.dpy, s->surface, attribute, value); } -void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { - ATRACE_CALL(); - clearError(); - +void EGLAPI eglBeginFrameImpl(EGLDisplay dpy, EGLSurface surface) { const egl_display_ptr dp = validate_display(dpy); if (!dp) { return; @@ -921,11 +890,9 @@ void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { // Contexts // ---------------------------------------------------------------------------- -EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, - EGLContext share_list, const EGLint *attrib_list) +EGLContext eglCreateContextImpl(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) { @@ -962,10 +929,8 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, return EGL_NO_CONTEXT; } -EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +EGLBoolean eglDestroyContextImpl(EGLDisplay dpy, EGLContext ctx) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -982,11 +947,9 @@ EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) return result; } -EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, - EGLSurface read, EGLContext ctx) +EGLBoolean eglMakeCurrentImpl( 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); @@ -1076,12 +1039,9 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, return result; } - -EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, - EGLint attribute, EGLint *value) +EGLBoolean eglQueryContextImpl( EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1094,24 +1054,19 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, } -EGLContext eglGetCurrentContext(void) +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. - - clearError(); - EGLContext ctx = getContext(); return ctx; } -EGLSurface eglGetCurrentSurface(EGLint readdraw) +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. - clearError(); - EGLContext ctx = getContext(); if (ctx) { egl_context_t const * const c = get_context(ctx); @@ -1125,13 +1080,11 @@ EGLSurface eglGetCurrentSurface(EGLint readdraw) return EGL_NO_SURFACE; } -EGLDisplay eglGetCurrentDisplay(void) +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. - clearError(); - EGLContext ctx = getContext(); if (ctx) { egl_context_t const * const c = get_context(ctx); @@ -1141,10 +1094,8 @@ EGLDisplay eglGetCurrentDisplay(void) return EGL_NO_DISPLAY; } -EGLBoolean eglWaitGL(void) +EGLBoolean eglWaitGLImpl(void) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1152,10 +1103,8 @@ EGLBoolean eglWaitGL(void) return cnx->egl.eglWaitGL(); } -EGLBoolean eglWaitNative(EGLint engine) +EGLBoolean eglWaitNativeImpl(EGLint engine) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1163,7 +1112,7 @@ EGLBoolean eglWaitNative(EGLint engine) return cnx->egl.eglWaitNative(engine); } -EGLint eglGetError(void) +EGLint eglGetErrorImpl(void) { EGLint err = EGL_SUCCESS; egl_connection_t* const cnx = &gEGLImpl; @@ -1193,19 +1142,8 @@ static __eglMustCastToProperFunctionPointerType findBuiltinWrapper( return nullptr; } -__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) +__eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(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. - - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - setError(EGL_BAD_PARAMETER, NULL); - return nullptr; - } - if (FILTER_EXTENSIONS(procname)) { return nullptr; } @@ -1346,12 +1284,9 @@ private: std::mutex mMutex; }; -EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, +EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, EGLint *rects, EGLint n_rects) { - ATRACE_CALL(); - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1416,16 +1351,14 @@ EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, } } -EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglSwapBuffersImpl(EGLDisplay dpy, EGLSurface surface) { - return eglSwapBuffersWithDamageKHR(dpy, surface, nullptr, 0); + return eglSwapBuffersWithDamageKHRImpl(dpy, surface, nullptr, 0); } -EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, - NativePixmapType target) +EGLBoolean eglCopyBuffersImpl( EGLDisplay dpy, EGLSurface surface, + NativePixmapType target) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1437,10 +1370,8 @@ EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); } -const char* eglQueryString(EGLDisplay dpy, EGLint name) +const char* eglQueryStringImpl(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 @@ -1469,10 +1400,8 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) return setError(EGL_BAD_PARAMETER, (const char *)nullptr); } -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) +EGLAPI const char* eglQueryStringImplementationANDROIDImpl(EGLDisplay dpy, EGLint name) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return (const char *) nullptr; @@ -1495,11 +1424,9 @@ extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy // EGL 1.1 // ---------------------------------------------------------------------------- -EGLBoolean eglSurfaceAttrib( +EGLBoolean eglSurfaceAttribImpl( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1536,11 +1463,9 @@ EGLBoolean eglSurfaceAttrib( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglBindTexImage( +EGLBoolean eglBindTexImageImpl( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1556,11 +1481,9 @@ EGLBoolean eglBindTexImage( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglReleaseTexImage( +EGLBoolean eglReleaseTexImageImpl( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1576,10 +1499,8 @@ EGLBoolean eglReleaseTexImage( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) +EGLBoolean eglSwapIntervalImpl(EGLDisplay dpy, EGLint interval) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1597,10 +1518,8 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) // EGL 1.2 // ---------------------------------------------------------------------------- -EGLBoolean eglWaitClient(void) +EGLBoolean eglWaitClientImpl(void) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1614,14 +1533,8 @@ EGLBoolean eglWaitClient(void) return res; } -EGLBoolean eglBindAPI(EGLenum api) +EGLBoolean eglBindAPIImpl(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; @@ -1631,14 +1544,8 @@ EGLBoolean eglBindAPI(EGLenum api) return res; } -EGLenum eglQueryAPI(void) +EGLenum eglQueryAPIImpl(void) { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglQueryAPI) { return cnx->egl.eglQueryAPI(); @@ -1648,10 +1555,8 @@ EGLenum eglQueryAPI(void) return EGL_OPENGL_ES_API; } -EGLBoolean eglReleaseThread(void) +EGLBoolean eglReleaseThreadImpl(void) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglReleaseThread) { cnx->egl.eglReleaseThread(); @@ -1664,12 +1569,10 @@ EGLBoolean eglReleaseThread(void) return EGL_TRUE; } -EGLSurface eglCreatePbufferFromClientBuffer( +EGLSurface eglCreatePbufferFromClientBufferImpl( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) { - clearError(); - egl_connection_t* cnx = nullptr; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (!dp) return EGL_FALSE; @@ -1684,11 +1587,9 @@ EGLSurface eglCreatePbufferFromClientBuffer( // EGL_EGLEXT_VERSION 3 // ---------------------------------------------------------------------------- -EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglLockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1704,10 +1605,8 @@ EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglUnlockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1722,11 +1621,9 @@ EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } -EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, +EGLImageKHR eglCreateImageKHRImpl(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_IMAGE_KHR; @@ -1744,10 +1641,8 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, return result; } -EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) +EGLBoolean eglDestroyImageKHRImpl(EGLDisplay dpy, EGLImageKHR img) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1764,10 +1659,8 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) // ---------------------------------------------------------------------------- -EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) +EGLSyncKHR eglCreateSyncKHRImpl(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_SYNC_KHR; @@ -1779,10 +1672,8 @@ EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_l return result; } -EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) +EGLBoolean eglDestroySyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1794,9 +1685,7 @@ EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) return result; } -EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { - clearError(); - +EGLBoolean eglSignalSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1809,11 +1698,9 @@ EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { return result; } -EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, +EGLint eglClientWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1826,11 +1713,9 @@ EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, return result; } -EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, +EGLBoolean eglGetSyncAttribKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1843,10 +1728,8 @@ EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, return result; } -EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) +EGLStreamKHR eglCreateStreamKHRImpl(EGLDisplay dpy, const EGLint *attrib_list) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_STREAM_KHR; @@ -1859,10 +1742,8 @@ EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) return result; } -EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) +EGLBoolean eglDestroyStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1875,11 +1756,9 @@ EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) return result; } -EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglStreamAttribKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1892,11 +1771,9 @@ EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1909,11 +1786,9 @@ EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamu64KHRImpl(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1926,11 +1801,9 @@ EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamTimeKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1943,11 +1816,9 @@ EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, +EGLSurface eglCreateStreamProducerSurfaceKHRImpl(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list) { - clearError(); - egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_SURFACE; @@ -1964,11 +1835,9 @@ EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, +EGLBoolean eglStreamConsumerGLTextureExternalKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1981,11 +1850,9 @@ EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, return result; } -EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, +EGLBoolean eglStreamConsumerAcquireKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1998,11 +1865,9 @@ EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, return result; } -EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, +EGLBoolean eglStreamConsumerReleaseKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -2015,11 +1880,9 @@ EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, return result; } -EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR( +EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHRImpl( EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR; @@ -2032,11 +1895,9 @@ EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR( return result; } -EGLStreamKHR eglCreateStreamFromFileDescriptorKHR( +EGLStreamKHR eglCreateStreamFromFileDescriptorKHRImpl( EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_STREAM_KHR; @@ -2053,8 +1914,7 @@ EGLStreamKHR eglCreateStreamFromFileDescriptorKHR( // EGL_EGLEXT_VERSION 15 // ---------------------------------------------------------------------------- -EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { - clearError(); +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; @@ -2069,10 +1929,8 @@ EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { // ANDROID extensions // ---------------------------------------------------------------------------- -EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) +EGLint eglDupNativeFenceFDANDROIDImpl(EGLDisplay dpy, EGLSyncKHR sync) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID; @@ -2084,11 +1942,9 @@ EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) return result; } -EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglPresentationTimeANDROIDImpl(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return EGL_FALSE; @@ -2106,8 +1962,7 @@ EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, return EGL_TRUE; } -EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) { - clearError(); +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. @@ -2122,14 +1977,8 @@ EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) { // ---------------------------------------------------------------------------- // NVIDIA extensions // ---------------------------------------------------------------------------- -EGLuint64NV eglGetSystemTimeFrequencyNV() +EGLuint64NV eglGetSystemTimeFrequencyNVImpl() { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); - } - EGLuint64NV ret = 0; egl_connection_t* const cnx = &gEGLImpl; @@ -2140,14 +1989,8 @@ EGLuint64NV eglGetSystemTimeFrequencyNV() return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); } -EGLuint64NV eglGetSystemTimeNV() +EGLuint64NV eglGetSystemTimeNVImpl() { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); - } - EGLuint64NV ret = 0; egl_connection_t* const cnx = &gEGLImpl; @@ -2161,11 +2004,9 @@ EGLuint64NV eglGetSystemTimeNV() // ---------------------------------------------------------------------------- // Partial update extension // ---------------------------------------------------------------------------- -EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglSetDamageRegionKHRImpl(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { setError(EGL_BAD_DISPLAY, EGL_FALSE); @@ -2187,10 +2028,8 @@ EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, return EGL_FALSE; } -EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetNextFrameIdANDROIDImpl(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2221,11 +2060,9 @@ EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, return EGL_TRUE; } -EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetCompositorTimingANDROIDImpl(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2278,11 +2115,9 @@ EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, } } -EGLBoolean eglGetCompositorTimingSupportedANDROID( +EGLBoolean eglGetCompositorTimingSupportedANDROIDImpl( EGLDisplay dpy, EGLSurface surface, EGLint name) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2310,12 +2145,10 @@ EGLBoolean eglGetCompositorTimingSupportedANDROID( } } -EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetFrameTimestampsANDROIDImpl(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2398,11 +2231,9 @@ EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, } } -EGLBoolean eglGetFrameTimestampSupportedANDROID( +EGLBoolean eglGetFrameTimestampSupportedANDROIDImpl( EGLDisplay dpy, EGLSurface surface, EGLint timestamp) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2443,3 +2274,182 @@ EGLBoolean eglGetFrameTimestampSupportedANDROID( 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 new file mode 100644 index 0000000000..7cd80d6dc2 --- /dev/null +++ b/opengl/libs/EGL/egl_platform_entries.h @@ -0,0 +1,31 @@ +/* + * 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 + +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 449ffc73c0..d8606d3e87 100644 --- a/opengl/libs/EGL/egldefs.h +++ b/opengl/libs/EGL/egldefs.h @@ -38,12 +38,16 @@ struct egl_connection_t { }; 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; @@ -64,6 +68,7 @@ extern "C" void gl_noop(); 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 f7fde9625f..65f50f54fb 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -301,71 +301,31 @@ extern "C" { } const GLubyte * glGetString(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; + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetString(name); } const GLubyte * glGetStringi(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; + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetStringi(name, index); } void glGetBooleanv(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); + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetBooleanv(pname, data); } void glGetFloatv(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); + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetFloatv(pname, data); } void glGetIntegerv(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); + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetIntegerv(pname, data); } void glGetInteger64v(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); + egl_connection_t* const cnx = egl_get_connection(); + return cnx->platform.glGetInteger64v(pname, data); } diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h index a8855efa57..0af050175b 100644 --- a/opengl/libs/egl_impl.h +++ b/opengl/libs/egl_impl.h @@ -21,15 +21,18 @@ #include #include +#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 81dbe0e34b..63a0e140cc 100644 --- a/opengl/libs/hooks.h +++ b/opengl/libs/hooks.h @@ -59,6 +59,10 @@ namespace android { #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 new file mode 100644 index 0000000000..b28f6ccac8 --- /dev/null +++ b/opengl/libs/platform_entries.in @@ -0,0 +1,76 @@ +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*) -- cgit v1.2.3-59-g8ed1b From 629ce4e13c46de2c9c76c458afd5ae54d4e5eb85 Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Mon, 15 Oct 2018 07:22:09 -0600 Subject: Revert "Revert "Rootless Debug for GLES"" This reverts commit 9f20d92fb3b7ed2a88d2e497ec36d21e9005f497. Test: cts-tradefed run singleCommand cts -m CtsGpuToolsHostTestCases Test: Chromium starts up Test: deqp - EGL, GLES2, GLES3 Bug: 110883880 Change-Id: I728ce502f8df43d5bfb370e6f9d4bd382f8c909d --- libs/graphicsenv/Android.bp | 1 + libs/graphicsenv/GraphicsEnv.cpp | 17 + libs/graphicsenv/include/graphicsenv/GraphicsEnv.h | 14 +- opengl/libs/Android.bp | 4 + opengl/libs/EGL/egl.cpp | 11 +- opengl/libs/EGL/egl_layers.cpp | 433 +++++++++++++++++++++ opengl/libs/EGL/egl_layers.h | 65 ++++ opengl/libs/EGL/egl_platform_entries.cpp | 92 +++-- 8 files changed, 594 insertions(+), 43 deletions(-) create mode 100644 opengl/libs/EGL/egl_layers.cpp create mode 100644 opengl/libs/EGL/egl_layers.h (limited to 'opengl/libs/Android.bp') diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index 4da30e9980..bab87acb05 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -23,6 +23,7 @@ cc_library_shared { shared_libs: [ "liblog", + "libcutils", ], export_include_dirs: ["include"], diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 2a7d76e856..3328ad7291 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -18,9 +18,12 @@ #define LOG_TAG "GraphicsEnv" #include +#include + #include #include +#include #include // TODO(b/37049319) Get this from a header once one exists @@ -46,6 +49,14 @@ namespace android { 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'", @@ -181,4 +192,10 @@ bool android_getAngleDeveloperOptIn() { 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 00e8fc01f7..1783429b9d 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -29,6 +29,8 @@ class GraphicsEnv { 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 @@ -85,11 +87,13 @@ private: * 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(); + 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(); } #endif // ANDROID_UI_GRAPHICS_ENV_H diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index fb6a221973..583aec9db5 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -140,6 +140,7 @@ cc_library_shared { "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", @@ -150,8 +151,11 @@ cc_library_shared { "libvndksupport", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", + "libbase", "libhidlbase", "libhidltransport", + "libnativebridge", + "libnativeloader", "libutils", ], static_libs: [ diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 1229bc288d..8870d5f571 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -30,11 +30,10 @@ #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 { // ---------------------------------------------------------------------------- @@ -196,6 +195,14 @@ static EGLBoolean egl_init_drivers_locked() { 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; } diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp new file mode 100644 index 0000000000..6900b8b464 --- /dev/null +++ b/opengl/libs/EGL/egl_layers.cpp @@ -0,0 +1,433 @@ +/* + ** 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 func_indices; +// func_indices.reserve(kFuncCount); + +std::unordered_map func_names; +// func_names.reserve(kFuncCount); + +std::vector 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(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(gpaNext); + + val = reinterpret_cast(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(val); + } + + // int index = func_indices[name]; + // val = (*next_layer_funcs)[index]; + // return reinterpret_cast(val); + return reinterpret_cast((*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(&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(&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(&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(&layer_functions[current_layer_]), + reinterpret_cast( + getNextLayerProcAddress)); + + // Check functions implemented by the platform + func_idx = 0; + entries = platform_names; + curr = reinterpret_cast(&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(&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(&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 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 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(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(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 new file mode 100644 index 0000000000..e401b448cf --- /dev/null +++ b/opengl/libs/EGL/egl_layers.h @@ -0,0 +1,65 @@ +/* + * 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 +#include +#include + +#include + +#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_; + std::vector 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 index 296ee44ce5..0d69a658e3 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -30,6 +30,8 @@ #include #include +#include +#include #include #include @@ -47,6 +49,7 @@ #include "egl_display.h" #include "egl_object.h" +#include "egl_layers.h" #include "egl_tls.h" #include "egl_trace.h" @@ -1158,54 +1161,71 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procn // 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); + /* + * 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; + 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); + 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; + LayerLoader& layer_loader(LayerLoader::getInstance()); - 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 (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { - if (found) { - addr = gExtensionForwarders[slot]; + 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; } -- cgit v1.2.3-59-g8ed1b From 0b586e87d4753c8ae9ef8a292d43fb660b70f5bc Mon Sep 17 00:00:00 2001 From: dimitry Date: Tue, 11 Dec 2018 14:33:30 +0100 Subject: Apply version-script to libGLESv1_CM library Hide unintentionally exported symbols, validate that symbols mentioned in the map file are actually exported by the library. Bug: http://b/69603741 Test: make Change-Id: Iffec2dce9cfbfcbefb6f9f3235e6bf79c0a58969 --- opengl/libs/Android.bp | 1 + 1 file changed, 1 insertion(+) (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 583aec9db5..c80b79a319 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -197,6 +197,7 @@ cc_library_shared { defaults: ["gles_libs_defaults"], srcs: ["GLES_CM/gl.cpp"], cflags: ["-DLOG_TAG=\"libGLESv1\""], + version_script: "libGLESv1_CM.map.txt", } //############################################################################## -- cgit v1.2.3-59-g8ed1b From 9249cbbea5409439b4f5b73c54c60ddc45d21f0b Mon Sep 17 00:00:00 2001 From: dimitry Date: Wed, 12 Dec 2018 13:16:57 +0100 Subject: Apply version-script to libGLESv2 library Hide unintentionally exported symbols, validate that symbols mentioned in the map file are actually exported by the library. Also add missing gl*Query*EXT symbols to the list. Part of them are used by hwui unit tests. They were exported implicitly before, this change make it explicit. Bug: http://b/69603741 Test: make Change-Id: Iac3b821477a4e88bd507596324a45c7afaf18ba6 --- opengl/libs/Android.bp | 1 + opengl/libs/libGLESv1_CM.map.txt | 1 + opengl/libs/libGLESv2.map.txt | 128 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index c80b79a319..5c05bbe3ed 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -208,6 +208,7 @@ cc_library_shared { defaults: ["gles_libs_defaults"], srcs: ["GLES2/gl2.cpp"], cflags: ["-DLOG_TAG=\"libGLESv2\""], + version_script: "libGLESv2.map.txt", } //############################################################################## diff --git a/opengl/libs/libGLESv1_CM.map.txt b/opengl/libs/libGLESv1_CM.map.txt index 8ba91e6e65..41bf4ca192 100644 --- a/opengl/libs/libGLESv1_CM.map.txt +++ b/opengl/libs/libGLESv1_CM.map.txt @@ -179,6 +179,7 @@ LIBGLESV1_CM { glLoadPaletteFromModelViewMatrixOES; glLogicOp; glMapBufferOES; + glMapBufferRangeEXT; glMaterialf; glMaterialfv; glMaterialx; diff --git a/opengl/libs/libGLESv2.map.txt b/opengl/libs/libGLESv2.map.txt index 787c8355a8..844d1e2b72 100644 --- a/opengl/libs/libGLESv2.map.txt +++ b/opengl/libs/libGLESv2.map.txt @@ -1,19 +1,28 @@ LIBGLESV2 { global: + glActiveShaderProgramEXT; glActiveTexture; glAttachShader; + glBeginQueryEXT; glBeginPerfMonitorAMD; glBindAttribLocation; glBindBuffer; + glBindFragDataLocationEXT; # introduced=24 + glBindFragDataLocationIndexedEXT; # introduced=24 glBindFramebuffer; + glBindProgramPipelineEXT; glBindRenderbuffer; glBindTexture; glBindVertexArrayOES; # introduced-mips=9 introduced-x86=9 glBlendColor; glBlendEquation; + glBlendEquationiOES; # introduced=24 glBlendEquationSeparate; + glBlendEquationSeparateiOES; # introduced=24 glBlendFunc; + glBlendFunciOES; # introduced=24 glBlendFuncSeparate; + glBlendFuncSeparateiOES; # introduced=24 glBufferData; glBufferSubData; glCheckFramebufferStatus; @@ -22,6 +31,7 @@ LIBGLESV2 { glClearDepthf; glClearStencil; glColorMask; + glColorMaskiOES; # introduced=24 glCompileShader; glCompressedTexImage2D; glCompressedTexImage3DOES; @@ -34,12 +44,16 @@ LIBGLESV2 { glCoverageOperationNV; # introduced-mips=9 introduced-x86=9 glCreateProgram; glCreateShader; + glCreateShaderProgramvEXT; glCullFace; + glDebugMessageCallbackKHR; # introduced=21 glDeleteBuffers; glDeleteFencesNV; glDeleteFramebuffers; glDeletePerfMonitorsAMD; glDeleteProgram; + glDeleteProgramPipelinesEXT; + glDeleteQueriesEXT; glDeleteRenderbuffers; glDeleteShader; glDeleteTextures; @@ -49,17 +63,32 @@ LIBGLESV2 { glDepthRangef; glDetachShader; glDisable; + glDisableiOES; # introduced=24 glDisableDriverControlQCOM; glDisableVertexAttribArray; glDiscardFramebufferEXT; # introduced-mips=9 introduced-x86=9 glDrawArrays; + glDrawArraysInstancedBaseInstanceEXT; # introduced=24 + glDrawArraysInstancedEXT; # introduced=21 + glDrawBuffersEXT; # introduced=21 + glDrawBuffersIndexedEXT; # introduced=21 glDrawElements; + glDrawElementsBaseVertexEXT; # introduced=24 + glDrawElementsBaseVertexOES; # introduced=24 + glDrawElementsInstancedBaseInstanceEXT; # introduced=24 + glDrawElementsInstancedBaseVertexEXT; # introduced=24 + glDrawElementsInstancedBaseVertexOES; # introduced=24 + glDrawElementsInstancedBaseVertexBaseInstanceEXT; # introduced=24 + glDrawRangeElementsBaseVertexEXT; # introduced=24 + glDrawRangeElementsBaseVertexOES; # introduced=24 glEGLImageTargetRenderbufferStorageOES; glEGLImageTargetTexture2DOES; glEnable; + glEnableiOES; # introduced=24 glEnableDriverControlQCOM; glEnableVertexAttribArray; glEndPerfMonitorAMD; + glEndQueryEXT; glEndTilingQCOM; # introduced-mips=9 introduced-x86=9 glExtGetBufferPointervQCOM; # introduced-mips=9 introduced-x86=9 glExtGetBuffersQCOM; # introduced-mips=9 introduced-x86=9 @@ -76,17 +105,20 @@ LIBGLESV2 { glFinish; glFinishFenceNV; glFlush; + glFlushMappedBufferRangeEXT; # introduced=21 glFramebufferRenderbuffer; glFramebufferTexture2D; glFramebufferTexture2DMultisampleIMG; # introduced-mips=9 introduced-x86=9 glFramebufferTexture2DMultisampleEXT; # introduced=28 glFramebufferTexture3DOES; + glFramebufferTextureOES; # introduced=24 glFrontFace; glGenBuffers; glGenFencesNV; glGenFramebuffers; glGenPerfMonitorsAMD; glGenRenderbuffers; + glGenQueriesEXT; glGenTextures; glGenVertexArraysOES; # introduced-mips=9 introduced-x86=9 glGenerateMipmap; @@ -102,24 +134,49 @@ LIBGLESV2 { glGetError; glGetFenceivNV; glGetFloatv; + glGetFragDataIndexEXT; # introduced=24 glGetFramebufferAttachmentParameteriv; + glGetGraphicsResetStatusEXT; + glGetGraphicsResetStatusKHR; # introduced=24 + glGetIntegeri_vEXT; # introduced=21 glGetIntegerv; + glGetnUniformfvEXT; + glGetnUniformfvKHR; # introduced=24 + glGetnUniformivEXT; + glGetnUniformivKHR; # introduced=24 + glGetnUniformuivKHR; # introduced=24 + glGetObjectLabelEXT; + glCopyImageSubDataOES; # introduced=24 glGetPerfMonitorCounterDataAMD; glGetPerfMonitorCounterInfoAMD; glGetPerfMonitorCounterStringAMD; glGetPerfMonitorCountersAMD; glGetPerfMonitorGroupStringAMD; glGetPerfMonitorGroupsAMD; + glGetPointervKHR; # introduced=21 glGetProgramBinaryOES; glGetProgramInfoLog; glGetProgramiv; + glGenProgramPipelinesEXT; + glGetProgramPipelineInfoLogEXT; + glGetProgramPipelineivEXT; + glGetProgramResourceLocationIndexEXT; # introduced=24 + glGetQueryivEXT; + glGetQueryObjectivEXT; # introduced=21 + glGetQueryObjectuivEXT; + glGetQueryObjecti64vEXT; # introduced=21 + glGetQueryObjectui64vEXT; # introduced=21 glGetRenderbufferParameteriv; + glGetSamplerParameterIivOES; # introduced=24 + glGetSamplerParameterIuivOES; # introduced=24 glGetShaderInfoLog; glGetShaderPrecisionFormat; glGetShaderSource; glGetShaderiv; glGetString; glGetTexParameterfv; + glGetTexParameterIivOES; # introduced=24 + glGetTexParameterIuivOES; # introduced=24 glGetTexParameteriv; glGetUniformLocation; glGetUniformfv; @@ -128,29 +185,83 @@ LIBGLESV2 { glGetVertexAttribfv; glGetVertexAttribiv; glHint; + glInsertEventMarkerEXT; glIsBuffer; glIsEnabled; + glIsEnablediOES; # introduced=24 glIsFenceNV; glIsFramebuffer; glIsProgram; + glIsProgramPipelineEXT; + glIsQueryEXT; glIsRenderbuffer; glIsShader; glIsTexture; glIsVertexArrayOES; # introduced-mips=9 introduced-x86=9 + glLabelObjectEXT; glLineWidth; glLinkProgram; glMapBufferOES; glMultiDrawArraysEXT; # introduced-mips=9 introduced-x86=9 + glMultiDrawArraysIndirectEXT; # introduced=24 + glMultiDrawElementsIndirectEXT; # introduced=24 + glMultiDrawElementsBaseVertexEXT; # introduced=24 + glDrawElementsInstancedEXT; # introduced=21 glMultiDrawElementsEXT; # introduced-mips=9 introduced-x86=9 + glPatchParameteriOES; # introduced=24 glPixelStorei; glPolygonOffset; + glPopGroupMarkerEXT; # introduced=21 + glPrimitiveBoundingBoxOES; # introduced=24 glProgramBinaryOES; + glProgramParameteriEXT; + glProgramUniform1fEXT; + glProgramUniform1fvEXT; + glProgramUniform1iEXT; + glProgramUniform1ivEXT; + glProgramUniform1uiEXT; # introduced=21 + glProgramUniform1uivEXT; # introduced=21 + glProgramUniform2fEXT; + glProgramUniform2fvEXT; + glProgramUniform2iEXT; + glProgramUniform2ivEXT; + glProgramUniform2uiEXT; # introduced=21 + glProgramUniform2uivEXT; # introduced=21 + glProgramUniform3fEXT; + glProgramUniform3fvEXT; + glProgramUniform3iEXT; + glProgramUniform3ivEXT; + glProgramUniform3uiEXT; # introduced=21 + glProgramUniform3uivEXT; # introduced=21 + glProgramUniform4fEXT; + glProgramUniform4fvEXT; + glProgramUniform4iEXT; + glProgramUniform4ivEXT; + glProgramUniform4uiEXT; # introduced=21 + glProgramUniform4uivEXT; # introduced=21 + glProgramUniformMatrix2fvEXT; + glProgramUniformMatrix2x3fvEXT; # introduced=21 + glProgramUniformMatrix2x4fvEXT; # introduced=21 + glProgramUniformMatrix3fvEXT; + glProgramUniformMatrix3x2fvEXT; # introduced=21 + glProgramUniformMatrix3x4fvEXT; # introduced=21 + glProgramUniformMatrix4fvEXT; + glProgramUniformMatrix4x2fvEXT; # introduced=21 + glProgramUniformMatrix4x3fvEXT; # introduced=21 + glPushGroupMarkerEXT; + glQueryCounterEXT; # introduced=21 + glRasterSamplesEXT; # introduced=24 + glReadBufferIndexedEXT; # introduced=21 + glReadnPixelsEXT; + glReadnPixelsKHR; # introduced=24 glReadPixels; glReleaseShaderCompiler; glRenderbufferStorage; glRenderbufferStorageMultisampleEXT; # introduced=28 glRenderbufferStorageMultisampleIMG; # introduced-mips=9 introduced-x86=9 glSampleCoverage; + glSamplerParameterIivOES; # introduced=24 + glSamplerParameterIuivOES; # introduced=24 glScissor; glSelectPerfMonitorCountersAMD; glSetFenceNV; @@ -164,14 +275,27 @@ LIBGLESV2 { glStencilOp; glStencilOpSeparate; glTestFenceNV; + glTexBufferOES; # introduced=24 + glTexBufferRangeOES; # introduced=24 glTexImage2D; glTexImage3DOES; + glTexPageCommitmentEXT; # introduced=24 glTexParameterf; glTexParameterfv; glTexParameteri; + glTexParameterIivOES; # introduced=24 + glTexParameterIuivOES; # introduced=24 glTexParameteriv; + glTexStorage1DEXT; + glTexStorage2DEXT; + glTexStorage3DEXT; glTexSubImage2D; glTexSubImage3DOES; + glTextureStorage1DEXT; + glTextureStorage2DEXT; + glTextureStorage3DEXT; + glTextureViewEXT; # introduced=21 + glTextureViewOES; # introduced=24 glUniform1f; glUniform1fv; glUniform1i; @@ -193,7 +317,11 @@ LIBGLESV2 { glUniformMatrix4fv; glUnmapBufferOES; glUseProgram; + glUseProgramStagesEXT; glValidateProgram; + glValidateProgramPipelineEXT; + glVertexAttribDivisorANGLE; # introduced=21 + glVertexAttribDivisorEXT; # introduced=21 glVertexAttrib1f; glVertexAttrib1fv; glVertexAttrib2f; -- cgit v1.2.3-59-g8ed1b From 1405ded7d1bf5a032c77f637b0c298eca00983f2 Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Tue, 8 Jan 2019 22:34:42 +0000 Subject: Revert "Apply version-script to libGLESv2 library" This reverts commit 9249cbbea5409439b4f5b73c54c60ddc45d21f0b. Reason for revert: b/122494057 Bug: 122494057 Change-Id: I6cb879ef169cdd160176d2b703bd6a680161a4b4 --- opengl/libs/Android.bp | 1 - opengl/libs/libGLESv1_CM.map.txt | 1 - opengl/libs/libGLESv2.map.txt | 128 --------------------------------------- 3 files changed, 130 deletions(-) (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 5c05bbe3ed..c80b79a319 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -208,7 +208,6 @@ cc_library_shared { defaults: ["gles_libs_defaults"], srcs: ["GLES2/gl2.cpp"], cflags: ["-DLOG_TAG=\"libGLESv2\""], - version_script: "libGLESv2.map.txt", } //############################################################################## diff --git a/opengl/libs/libGLESv1_CM.map.txt b/opengl/libs/libGLESv1_CM.map.txt index 41bf4ca192..8ba91e6e65 100644 --- a/opengl/libs/libGLESv1_CM.map.txt +++ b/opengl/libs/libGLESv1_CM.map.txt @@ -179,7 +179,6 @@ LIBGLESV1_CM { glLoadPaletteFromModelViewMatrixOES; glLogicOp; glMapBufferOES; - glMapBufferRangeEXT; glMaterialf; glMaterialfv; glMaterialx; diff --git a/opengl/libs/libGLESv2.map.txt b/opengl/libs/libGLESv2.map.txt index 844d1e2b72..787c8355a8 100644 --- a/opengl/libs/libGLESv2.map.txt +++ b/opengl/libs/libGLESv2.map.txt @@ -1,28 +1,19 @@ LIBGLESV2 { global: - glActiveShaderProgramEXT; glActiveTexture; glAttachShader; - glBeginQueryEXT; glBeginPerfMonitorAMD; glBindAttribLocation; glBindBuffer; - glBindFragDataLocationEXT; # introduced=24 - glBindFragDataLocationIndexedEXT; # introduced=24 glBindFramebuffer; - glBindProgramPipelineEXT; glBindRenderbuffer; glBindTexture; glBindVertexArrayOES; # introduced-mips=9 introduced-x86=9 glBlendColor; glBlendEquation; - glBlendEquationiOES; # introduced=24 glBlendEquationSeparate; - glBlendEquationSeparateiOES; # introduced=24 glBlendFunc; - glBlendFunciOES; # introduced=24 glBlendFuncSeparate; - glBlendFuncSeparateiOES; # introduced=24 glBufferData; glBufferSubData; glCheckFramebufferStatus; @@ -31,7 +22,6 @@ LIBGLESV2 { glClearDepthf; glClearStencil; glColorMask; - glColorMaskiOES; # introduced=24 glCompileShader; glCompressedTexImage2D; glCompressedTexImage3DOES; @@ -44,16 +34,12 @@ LIBGLESV2 { glCoverageOperationNV; # introduced-mips=9 introduced-x86=9 glCreateProgram; glCreateShader; - glCreateShaderProgramvEXT; glCullFace; - glDebugMessageCallbackKHR; # introduced=21 glDeleteBuffers; glDeleteFencesNV; glDeleteFramebuffers; glDeletePerfMonitorsAMD; glDeleteProgram; - glDeleteProgramPipelinesEXT; - glDeleteQueriesEXT; glDeleteRenderbuffers; glDeleteShader; glDeleteTextures; @@ -63,32 +49,17 @@ LIBGLESV2 { glDepthRangef; glDetachShader; glDisable; - glDisableiOES; # introduced=24 glDisableDriverControlQCOM; glDisableVertexAttribArray; glDiscardFramebufferEXT; # introduced-mips=9 introduced-x86=9 glDrawArrays; - glDrawArraysInstancedBaseInstanceEXT; # introduced=24 - glDrawArraysInstancedEXT; # introduced=21 - glDrawBuffersEXT; # introduced=21 - glDrawBuffersIndexedEXT; # introduced=21 glDrawElements; - glDrawElementsBaseVertexEXT; # introduced=24 - glDrawElementsBaseVertexOES; # introduced=24 - glDrawElementsInstancedBaseInstanceEXT; # introduced=24 - glDrawElementsInstancedBaseVertexEXT; # introduced=24 - glDrawElementsInstancedBaseVertexOES; # introduced=24 - glDrawElementsInstancedBaseVertexBaseInstanceEXT; # introduced=24 - glDrawRangeElementsBaseVertexEXT; # introduced=24 - glDrawRangeElementsBaseVertexOES; # introduced=24 glEGLImageTargetRenderbufferStorageOES; glEGLImageTargetTexture2DOES; glEnable; - glEnableiOES; # introduced=24 glEnableDriverControlQCOM; glEnableVertexAttribArray; glEndPerfMonitorAMD; - glEndQueryEXT; glEndTilingQCOM; # introduced-mips=9 introduced-x86=9 glExtGetBufferPointervQCOM; # introduced-mips=9 introduced-x86=9 glExtGetBuffersQCOM; # introduced-mips=9 introduced-x86=9 @@ -105,20 +76,17 @@ LIBGLESV2 { glFinish; glFinishFenceNV; glFlush; - glFlushMappedBufferRangeEXT; # introduced=21 glFramebufferRenderbuffer; glFramebufferTexture2D; glFramebufferTexture2DMultisampleIMG; # introduced-mips=9 introduced-x86=9 glFramebufferTexture2DMultisampleEXT; # introduced=28 glFramebufferTexture3DOES; - glFramebufferTextureOES; # introduced=24 glFrontFace; glGenBuffers; glGenFencesNV; glGenFramebuffers; glGenPerfMonitorsAMD; glGenRenderbuffers; - glGenQueriesEXT; glGenTextures; glGenVertexArraysOES; # introduced-mips=9 introduced-x86=9 glGenerateMipmap; @@ -134,49 +102,24 @@ LIBGLESV2 { glGetError; glGetFenceivNV; glGetFloatv; - glGetFragDataIndexEXT; # introduced=24 glGetFramebufferAttachmentParameteriv; - glGetGraphicsResetStatusEXT; - glGetGraphicsResetStatusKHR; # introduced=24 - glGetIntegeri_vEXT; # introduced=21 glGetIntegerv; - glGetnUniformfvEXT; - glGetnUniformfvKHR; # introduced=24 - glGetnUniformivEXT; - glGetnUniformivKHR; # introduced=24 - glGetnUniformuivKHR; # introduced=24 - glGetObjectLabelEXT; - glCopyImageSubDataOES; # introduced=24 glGetPerfMonitorCounterDataAMD; glGetPerfMonitorCounterInfoAMD; glGetPerfMonitorCounterStringAMD; glGetPerfMonitorCountersAMD; glGetPerfMonitorGroupStringAMD; glGetPerfMonitorGroupsAMD; - glGetPointervKHR; # introduced=21 glGetProgramBinaryOES; glGetProgramInfoLog; glGetProgramiv; - glGenProgramPipelinesEXT; - glGetProgramPipelineInfoLogEXT; - glGetProgramPipelineivEXT; - glGetProgramResourceLocationIndexEXT; # introduced=24 - glGetQueryivEXT; - glGetQueryObjectivEXT; # introduced=21 - glGetQueryObjectuivEXT; - glGetQueryObjecti64vEXT; # introduced=21 - glGetQueryObjectui64vEXT; # introduced=21 glGetRenderbufferParameteriv; - glGetSamplerParameterIivOES; # introduced=24 - glGetSamplerParameterIuivOES; # introduced=24 glGetShaderInfoLog; glGetShaderPrecisionFormat; glGetShaderSource; glGetShaderiv; glGetString; glGetTexParameterfv; - glGetTexParameterIivOES; # introduced=24 - glGetTexParameterIuivOES; # introduced=24 glGetTexParameteriv; glGetUniformLocation; glGetUniformfv; @@ -185,83 +128,29 @@ LIBGLESV2 { glGetVertexAttribfv; glGetVertexAttribiv; glHint; - glInsertEventMarkerEXT; glIsBuffer; glIsEnabled; - glIsEnablediOES; # introduced=24 glIsFenceNV; glIsFramebuffer; glIsProgram; - glIsProgramPipelineEXT; - glIsQueryEXT; glIsRenderbuffer; glIsShader; glIsTexture; glIsVertexArrayOES; # introduced-mips=9 introduced-x86=9 - glLabelObjectEXT; glLineWidth; glLinkProgram; glMapBufferOES; glMultiDrawArraysEXT; # introduced-mips=9 introduced-x86=9 - glMultiDrawArraysIndirectEXT; # introduced=24 - glMultiDrawElementsIndirectEXT; # introduced=24 - glMultiDrawElementsBaseVertexEXT; # introduced=24 - glDrawElementsInstancedEXT; # introduced=21 glMultiDrawElementsEXT; # introduced-mips=9 introduced-x86=9 - glPatchParameteriOES; # introduced=24 glPixelStorei; glPolygonOffset; - glPopGroupMarkerEXT; # introduced=21 - glPrimitiveBoundingBoxOES; # introduced=24 glProgramBinaryOES; - glProgramParameteriEXT; - glProgramUniform1fEXT; - glProgramUniform1fvEXT; - glProgramUniform1iEXT; - glProgramUniform1ivEXT; - glProgramUniform1uiEXT; # introduced=21 - glProgramUniform1uivEXT; # introduced=21 - glProgramUniform2fEXT; - glProgramUniform2fvEXT; - glProgramUniform2iEXT; - glProgramUniform2ivEXT; - glProgramUniform2uiEXT; # introduced=21 - glProgramUniform2uivEXT; # introduced=21 - glProgramUniform3fEXT; - glProgramUniform3fvEXT; - glProgramUniform3iEXT; - glProgramUniform3ivEXT; - glProgramUniform3uiEXT; # introduced=21 - glProgramUniform3uivEXT; # introduced=21 - glProgramUniform4fEXT; - glProgramUniform4fvEXT; - glProgramUniform4iEXT; - glProgramUniform4ivEXT; - glProgramUniform4uiEXT; # introduced=21 - glProgramUniform4uivEXT; # introduced=21 - glProgramUniformMatrix2fvEXT; - glProgramUniformMatrix2x3fvEXT; # introduced=21 - glProgramUniformMatrix2x4fvEXT; # introduced=21 - glProgramUniformMatrix3fvEXT; - glProgramUniformMatrix3x2fvEXT; # introduced=21 - glProgramUniformMatrix3x4fvEXT; # introduced=21 - glProgramUniformMatrix4fvEXT; - glProgramUniformMatrix4x2fvEXT; # introduced=21 - glProgramUniformMatrix4x3fvEXT; # introduced=21 - glPushGroupMarkerEXT; - glQueryCounterEXT; # introduced=21 - glRasterSamplesEXT; # introduced=24 - glReadBufferIndexedEXT; # introduced=21 - glReadnPixelsEXT; - glReadnPixelsKHR; # introduced=24 glReadPixels; glReleaseShaderCompiler; glRenderbufferStorage; glRenderbufferStorageMultisampleEXT; # introduced=28 glRenderbufferStorageMultisampleIMG; # introduced-mips=9 introduced-x86=9 glSampleCoverage; - glSamplerParameterIivOES; # introduced=24 - glSamplerParameterIuivOES; # introduced=24 glScissor; glSelectPerfMonitorCountersAMD; glSetFenceNV; @@ -275,27 +164,14 @@ LIBGLESV2 { glStencilOp; glStencilOpSeparate; glTestFenceNV; - glTexBufferOES; # introduced=24 - glTexBufferRangeOES; # introduced=24 glTexImage2D; glTexImage3DOES; - glTexPageCommitmentEXT; # introduced=24 glTexParameterf; glTexParameterfv; glTexParameteri; - glTexParameterIivOES; # introduced=24 - glTexParameterIuivOES; # introduced=24 glTexParameteriv; - glTexStorage1DEXT; - glTexStorage2DEXT; - glTexStorage3DEXT; glTexSubImage2D; glTexSubImage3DOES; - glTextureStorage1DEXT; - glTextureStorage2DEXT; - glTextureStorage3DEXT; - glTextureViewEXT; # introduced=21 - glTextureViewOES; # introduced=24 glUniform1f; glUniform1fv; glUniform1i; @@ -317,11 +193,7 @@ LIBGLESV2 { glUniformMatrix4fv; glUnmapBufferOES; glUseProgram; - glUseProgramStagesEXT; glValidateProgram; - glValidateProgramPipelineEXT; - glVertexAttribDivisorANGLE; # introduced=21 - glVertexAttribDivisorEXT; # introduced=21 glVertexAttrib1f; glVertexAttrib1fv; glVertexAttrib2f; -- cgit v1.2.3-59-g8ed1b From bd1ddb28a75842b236980fbdd31a4c8401ffaa22 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 18 Feb 2019 21:22:28 +0900 Subject: Cut the static deps from libEGL to libnativeloader and libnativebridge The dependencies are replaced with *_lazy libraries which dynamically load and links to the real libraries at runtime using dlopen and dlsym. This allows libEGL to be used by early processes that are executed before the activation of the runtime APEX where libnativeloader and libnativebridge are provided. Bug: 123403798 Test: m Test: device boots to the UI Change-Id: Ia54443163e1edcdcd142fcf392d830f1ae4c32bb --- opengl/libs/Android.bp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'opengl/libs/Android.bp') diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index c80b79a319..c0bace8486 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -154,8 +154,8 @@ cc_library_shared { "libbase", "libhidlbase", "libhidltransport", - "libnativebridge", - "libnativeloader", + "libnativebridge_lazy", + "libnativeloader_lazy", "libutils", ], static_libs: [ -- cgit v1.2.3-59-g8ed1b