diff options
Diffstat (limited to 'opengl')
70 files changed, 4208 insertions, 1496 deletions
diff --git a/opengl/Android.bp b/opengl/Android.bp new file mode 100644 index 0000000000..c520bda140 --- /dev/null +++ b/opengl/Android.bp @@ -0,0 +1,57 @@ +// Copyright (C) 2016 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. + +ndk_headers { + name: "libEGL_headers", + from: "include", + to: "", + srcs: ["include/EGL/**/*.h"], + license: "include/EGL/NOTICE", +} + +ndk_headers { + name: "libGLESv1_CM_headers", + from: "include", + to: "", + srcs: ["include/GLES/**/*.h"], + license: "include/GLES/NOTICE", +} + +ndk_headers { + name: "libGLESv2_headers", + from: "include", + to: "", + srcs: ["include/GLES2/**/*.h"], + license: "include/GLES2/NOTICE", +} + +ndk_headers { + name: "libGLESv3_headers", + from: "include", + to: "", + srcs: ["include/GLES3/**/*.h"], + license: "include/GLES3/NOTICE", +} + +ndk_headers { + name: "khr_headers", + from: "include", + to: "", + srcs: ["include/KHR/**/*.h"], + license: "include/KHR/NOTICE", +} + +subdirs = [ + "*", +] diff --git a/opengl/include/EGL/NOTICE b/opengl/include/EGL/NOTICE new file mode 100644 index 0000000000..55f5efaed4 --- /dev/null +++ b/opengl/include/EGL/NOTICE @@ -0,0 +1,20 @@ +Copyright (c) 2007-2009 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Materials. + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. diff --git a/opengl/include/EGL/egl.h b/opengl/include/EGL/egl.h index 99ea342a47..ccb54eaf2c 100644 --- a/opengl/include/EGL/egl.h +++ b/opengl/include/EGL/egl.h @@ -65,13 +65,13 @@ typedef void *EGLClientBuffer; #define EGL_TRUE 1 /* Out-of-band handle values */ -#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) -#define EGL_NO_CONTEXT ((EGLContext)0) -#define EGL_NO_DISPLAY ((EGLDisplay)0) -#define EGL_NO_SURFACE ((EGLSurface)0) +#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType, 0) +#define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0) +#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0) +#define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0) /* Out-of-band attribute value */ -#define EGL_DONT_CARE ((EGLint)-1) +#define EGL_DONT_CARE EGL_CAST(EGLint, -1) /* Errors / GetError return values */ #define EGL_SUCCESS 0x3000 @@ -198,7 +198,7 @@ typedef void *EGLClientBuffer; #define EGL_DISPLAY_SCALING 10000 /* Unknown display resolution/aspect ratio */ -#define EGL_UNKNOWN ((EGLint)-1) +#define EGL_UNKNOWN EGL_CAST(EGLint, -1) /* Back buffer swap behaviors */ #define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */ diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h index 2e186985e6..d0996f03f6 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -79,7 +79,7 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display #define EGL_KHR_image 1 #define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */ typedef void *EGLImageKHR; -#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0) +#define EGL_NO_IMAGE_KHR EGL_CAST(EGLImageKHR, 0) #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image); @@ -115,6 +115,13 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGL #define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */ #endif +#ifndef EGL_KHR_gl_colorspace +#define EGL_KHR_gl_colorspace 1 +#define EGL_GL_COLORSPACE_KHR 0x309D +#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 +#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A +#endif + #ifndef EGL_KHR_gl_renderbuffer_image #define EGL_KHR_gl_renderbuffer_image 1 #define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */ @@ -136,7 +143,7 @@ typedef khronos_utime_nanoseconds_t EGLTimeKHR; #define EGL_SYNC_REUSABLE_KHR 0x30FA #define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 /* eglClientWaitSyncKHR <flags> bitfield */ #define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull -#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0) +#define EGL_NO_SYNC_KHR EGL_CAST(EGLSyncKHR, 0) #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync); @@ -213,7 +220,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglSetDamageRegionKHR (EGLDisplay dpy, EGLSurface #define EGL_SYNC_TYPE_NV 0x30ED #define EGL_SYNC_CONDITION_NV 0x30EE #define EGL_SYNC_FENCE_NV 0x30EF -#define EGL_NO_SYNC_NV ((EGLSyncNV)0) +#define EGL_NO_SYNC_NV EGL_CAST(EGLSyncNV, 0) typedef void* EGLSyncNV; typedef khronos_utime_nanoseconds_t EGLTimeNV; #ifdef EGL_EGLEXT_PROTOTYPES @@ -339,7 +346,7 @@ typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void); #define EGL_KHR_stream 1 typedef void* EGLStreamKHR; typedef khronos_uint64_t EGLuint64KHR; -#define EGL_NO_STREAM_KHR ((EGLStreamKHR)0) +#define EGL_NO_STREAM_KHR EGL_CAST(EGLStreamKHR, 0) #define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210 #define EGL_PRODUCER_FRAME_KHR 0x3212 #define EGL_CONSUMER_FRAME_KHR 0x3213 @@ -466,7 +473,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageKHR (EGLDisplay dpy, EGLSu #ifndef EGL_KHR_stream_cross_process_fd #define EGL_KHR_stream_cross_process_fd 1 typedef int EGLNativeFileDescriptorKHR; -#define EGL_NO_FILE_DESCRIPTOR_KHR ((EGLNativeFileDescriptorKHR)(-1)) +#define EGL_NO_FILE_DESCRIPTOR_KHR EGL_CAST(EGLNativeFileDescriptorKHR, -1) #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR(EGLDisplay dpy, EGLStreamKHR stream); EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR(EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor); @@ -545,7 +552,7 @@ typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC)(EGLDisplay dpy, E #define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144 #define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145 #define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146 -#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1 +#define EGL_NO_NATIVE_FENCE_FD_ANDROID (-1) #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID( EGLDisplay dpy, EGLSyncKHR); #endif /* EGL_EGLEXT_PROTOTYPES */ @@ -598,16 +605,13 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLPRESENTATIONTIMEANDROID) (EGLDisplay dpy, #endif #endif -#ifndef EGL_ANDROID_create_native_client_buffer -#define EGL_ANDROID_create_native_client_buffer 1 -#define EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143 -#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001 -#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002 -#define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004 +#ifndef EGL_ANDROID_get_native_client_buffer +#define EGL_ANDROID_get_native_client_buffer 1 +struct AHardwareBuffer; #ifdef EGL_EGLEXT_PROTOTYPES -EGLAPI EGLClientBuffer eglCreateNativeClientBufferANDROID (const EGLint *attrib_list); +EGLAPI EGLClientBuffer eglGetNativeClientBufferANDROID (const struct AHardwareBuffer *buffer); #else -typedef EGLAPI EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROID) (const EGLint *attrib_list); +typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const struct AHardwareBuffer *buffer); #endif #endif @@ -623,21 +627,72 @@ typedef EGLAPI EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDRO #ifndef EGL_ANDROID_get_frame_timestamps #define EGL_ANDROID_get_frame_timestamps 1 -#define EGL_TIMESTAMPS_ANDROID 0x314D -#define EGL_QUEUE_TIME_ANDROID 0x314E -#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F -#define EGL_COMPOSITION_START_TIME_ANDROID 0x3430 -#define EGL_COMPOSITION_FINISHED_TIME_ANDROID 0x3431 -#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3432 -#define EGL_READS_DONE_TIME_ANDROID 0x3433 +#define EGL_TIMESTAMPS_ANDROID 0x3430 +#define EGL_COMPOSITE_DEADLINE_ANDROID 0x3431 +#define EGL_COMPOSITE_INTERVAL_ANDROID 0x3432 +#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433 +#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434 +#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435 +#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436 +#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437 +#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438 +#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439 +#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x343A +#define EGL_DEQUEUE_READY_TIME_ANDROID 0x343B +#define EGL_READS_DONE_TIME_ANDROID 0x343C +#define EGL_TIMESTAMP_PENDING_ANDROID EGL_CAST(EGLnsecsANDROID, -2) +#define EGL_TIMESTAMP_INVALID_ANDROID EGL_CAST(EGLnsecsANDROID, -1) #ifdef EGL_EGLEXT_PROTOTYPES -EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values); -EGLAPI EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint timestamp); +EGLAPI EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId); +EGLAPI EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values); +EGLAPI EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint name); +EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values); +EGLAPI EGLBoolean eglGetFrameTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint timestamp); #else -typedef EGLAPI EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values); -typedef EGLAPI EGLBoolean (EGLAPIENTRYP PFNEGLQUERYTIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp); -#endif -#endif +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETNEXTFRAMEIDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint name); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROID) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp); +#endif +#endif + +#ifndef EGL_EXT_gl_colorspace_bt2020_linear +#define EGL_EXT_gl_colorspace_bt2020_linear 1 +#define EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F +#endif /* EGL_EXT_gl_colorspace_bt2020_linear */ + +#ifndef EGL_EXT_gl_colorspace_bt2020_pq +#define EGL_EXT_gl_colorspace_bt2020_pq 1 +#define EGL_GL_COLORSPACE_BT2020_PQ_EXT 0x3340 +#endif /* EGL_EXT_gl_colorspace_bt2020_pq */ + +#ifndef EGL_EXT_gl_colorspace_scrgb_linear +#define EGL_EXT_gl_colorspace_scrgb_linear 1 +#define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350 +#endif /* EGL_EXT_gl_colorspace_scrgb_linear */ + +#ifndef EGL_EXT_pixel_format_float +#define EGL_EXT_pixel_format_float 1 +#define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339 +#define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A +#define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B +#endif /* EGL_EXT_pixel_format_float */ + +#ifndef EGL_EXT_surface_SMPTE2086_metadata +#define EGL_EXT_surface_SMPTE2086_metadata 1 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT 0x3341 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT 0x3342 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT 0x3343 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT 0x3344 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT 0x3345 +#define EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT 0x3346 +#define EGL_SMPTE2086_WHITE_POINT_X_EXT 0x3347 +#define EGL_SMPTE2086_WHITE_POINT_Y_EXT 0x3348 +#define EGL_SMPTE2086_MAX_LUMINANCE_EXT 0x3349 +#define EGL_SMPTE2086_MIN_LUMINANCE_EXT 0x334A +#define EGL_METADATA_SCALING_EXT 50000 +#endif /* EGL_EXT_surface_SMPTE2086_metadata */ #ifdef __cplusplus } diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h index 354ac22b1e..54011c87d0 100644 --- a/opengl/include/EGL/eglplatform.h +++ b/opengl/include/EGL/eglplatform.h @@ -121,4 +121,10 @@ typedef EGLNativeWindowType NativeWindowType; */ typedef khronos_int32_t EGLint; +#if defined(__cplusplus) +#define EGL_CAST(type, value) (static_cast<type>(value)) +#else +#define EGL_CAST(type, value) ((type) (value)) +#endif + #endif /* __eglplatform_h */ diff --git a/opengl/include/GLES/NOTICE b/opengl/include/GLES/NOTICE new file mode 100644 index 0000000000..4dc66144a0 --- /dev/null +++ b/opengl/include/GLES/NOTICE @@ -0,0 +1,2 @@ +This document is licensed under the SGI Free Software B License Version 2.0. +For details, see http://oss.sgi.com/projects/FreeB/ . diff --git a/opengl/include/GLES2/NOTICE b/opengl/include/GLES2/NOTICE new file mode 100644 index 0000000000..7a943739a4 --- /dev/null +++ b/opengl/include/GLES2/NOTICE @@ -0,0 +1,20 @@ +Copyright (c) 2013-2015 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Materials. + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. diff --git a/opengl/include/GLES3/NOTICE b/opengl/include/GLES3/NOTICE new file mode 100644 index 0000000000..7a943739a4 --- /dev/null +++ b/opengl/include/GLES3/NOTICE @@ -0,0 +1,20 @@ +Copyright (c) 2013-2015 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Materials. + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. diff --git a/opengl/include/KHR/NOTICE b/opengl/include/KHR/NOTICE new file mode 100644 index 0000000000..36796e89d1 --- /dev/null +++ b/opengl/include/KHR/NOTICE @@ -0,0 +1,20 @@ +Copyright (c) 2008-2009 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Materials. + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. diff --git a/opengl/libagl/arch-mips/fixed_asm.S b/opengl/libagl/arch-mips/fixed_asm.S index e1a53bc745..a30ffc5473 100644 --- a/opengl/libagl/arch-mips/fixed_asm.S +++ b/opengl/libagl/arch-mips/fixed_asm.S @@ -17,7 +17,7 @@ .text - .align + .align 4 /* * this version rounds-to-nearest and saturates numbers diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index c1efd1cae6..04f6d6d1a3 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -18,21 +18,22 @@ #include <assert.h> #include <atomic> #include <errno.h> -#include <stdlib.h> +#include <fcntl.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <unistd.h> -#include <fcntl.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/mman.h> +#include <unistd.h> -#include <cutils/log.h> +#include <log/log.h> #include <utils/threads.h> #include <ui/ANativeObjectBase.h> #include <ui/Fence.h> #include <ui/GraphicBufferMapper.h> +#include <ui/Rect.h> #include <EGL/egl.h> #include <EGL/eglext.h> @@ -740,6 +741,7 @@ egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break; case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break; case GGL_PIXEL_FORMAT_RGBX_8888: size *= 4; break; + case GGL_PIXEL_FORMAT_BGRA_8888: size *= 4; break; default: ALOGE("incompatible pixel format for pbuffer (format=%d)", f); pbuffer.data = 0; @@ -1027,6 +1029,19 @@ static config_pair_t const config_7_attribute_list[] = { { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, }; +// BGRA 8888 config +static config_pair_t const config_8_attribute_list[] = { + { EGL_BUFFER_SIZE, 32 }, + { EGL_ALPHA_SIZE, 8 }, + { EGL_BLUE_SIZE, 8 }, + { EGL_GREEN_SIZE, 8 }, + { EGL_RED_SIZE, 8 }, + { EGL_DEPTH_SIZE, 0 }, + { EGL_CONFIG_ID, 8 }, + { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_BGRA_8888 }, + { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT }, +}; + static configs_t const gConfigs[] = { { config_0_attribute_list, NELEM(config_0_attribute_list) }, { config_1_attribute_list, NELEM(config_1_attribute_list) }, @@ -1036,6 +1051,7 @@ static configs_t const gConfigs[] = { { config_5_attribute_list, NELEM(config_5_attribute_list) }, { config_6_attribute_list, NELEM(config_6_attribute_list) }, { config_7_attribute_list, NELEM(config_7_attribute_list) }, + { config_8_attribute_list, NELEM(config_8_attribute_list) }, }; static config_management_t const gConfigManagement[] = { @@ -1118,6 +1134,10 @@ static status_t getConfigFormatInfo(EGLint configID, pixelFormat = GGL_PIXEL_FORMAT_A_8; depthFormat = GGL_PIXEL_FORMAT_Z_16; break; + case 8: + pixelFormat = GGL_PIXEL_FORMAT_BGRA_8888; + depthFormat = 0; + break; default: return NAME_NOT_FOUND; } @@ -1459,6 +1479,9 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy, if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + if (ggl_unlikely(num_config==NULL)) + return setError(EGL_BAD_PARAMETER, EGL_FALSE); + GLint numConfigs = NELEM(gConfigs); if (!configs) { *num_config = numConfigs; @@ -1478,8 +1501,8 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, { if (egl_display_t::is_valid(dpy) == EGL_FALSE) return setError(EGL_BAD_DISPLAY, EGL_FALSE); - - if (ggl_unlikely(num_config==0)) { + + if (ggl_unlikely(num_config==NULL)) { return setError(EGL_BAD_PARAMETER, EGL_FALSE); } diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp new file mode 100644 index 0000000000..d6bdc81020 --- /dev/null +++ b/opengl/libs/Android.bp @@ -0,0 +1,171 @@ +// Build the ETC1 library +cc_library { + name: "libETC1", + srcs: ["ETC1/etc1.cpp"], + host_supported: true, + + target: { + android: { + static: { + enabled: false, + }, + }, + host: { + shared: { + enabled: false, + }, + }, + windows: { + enabled: true, + }, + }, +} + +// The headers modules are in frameworks/native/opengl/Android.bp. +ndk_library { + name: "libEGL", + symbol_file: "libEGL.map.txt", + first_version: "9", + unversioned_until: "current", +} + +ndk_library { + name: "libGLESv1_CM", + symbol_file: "libGLESv1_CM.map.txt", + first_version: "9", + unversioned_until: "current", +} + +ndk_library { + name: "libGLESv2", + symbol_file: "libGLESv2.map.txt", + first_version: "9", + unversioned_until: "current", +} + +ndk_library { + name: "libGLESv3", + symbol_file: "libGLESv3.map.txt", + first_version: "18", + unversioned_until: "current", +} + +cc_defaults { + name: "gl_libs_defaults", + cflags: [ + "-DGL_GLEXT_PROTOTYPES", + "-DEGL_EGLEXT_PROTOTYPES", + "-fvisibility=hidden", + ], + shared_libs: [ + // ***** DO NOT ADD NEW DEPENDENCIES HERE ***** + // In particular, DO NOT add libutils or anything "above" libcutils + "libcutils", + "liblog", + "libdl", + ], + + // we need to access the private Bionic header <bionic_tls.h> + include_dirs: ["bionic/libc/private"], +} + +//############################################################################## +// Build META EGL library +// +cc_defaults { + name: "egl_libs_defaults", + defaults: ["gl_libs_defaults"], + cflags: [ + "-DLOG_TAG=\"libEGL\"", + ], + shared_libs: [ + // ***** DO NOT ADD NEW DEPENDENCIES HERE ***** + // In particular, DO NOT add libutils nor anything "above" libui + "libui", + "libnativewindow", + "libbacktrace", + ], +} + +cc_library_static { + name: "libEGL_getProcAddress", + defaults: ["egl_libs_defaults"], + srcs: ["EGL/getProcAddress.cpp"], + arch: { + arm: { + instruction_set: "arm", + }, + }, +} + +cc_library_shared { + name: "libEGL", + defaults: ["egl_libs_defaults"], + srcs: [ + "EGL/egl_tls.cpp", + "EGL/egl_cache.cpp", + "EGL/egl_display.cpp", + "EGL/egl_object.cpp", + "EGL/egl.cpp", + "EGL/eglApi.cpp", + "EGL/Loader.cpp", + "EGL/BlobCache.cpp", + ], + shared_libs: ["libvndksupport"], + static_libs: ["libEGL_getProcAddress"], + ldflags: ["-Wl,--exclude-libs=ALL"], + export_include_dirs: ["EGL/include"], +} + +cc_test { + name: "libEGL_test", + defaults: ["egl_libs_defaults"], + srcs: [ + "EGL/BlobCache.cpp", + "EGL/BlobCache_test.cpp", + ], +} + +cc_defaults { + name: "gles_libs_defaults", + defaults: ["gl_libs_defaults"], + arch: { + arm: { + instruction_set: "arm", + + // TODO: This is to work around b/20093774. Remove after root cause is fixed + ldflags: ["-Wl,--hash-style,both"], + }, + }, + shared_libs: ["libEGL"], +} + +//############################################################################## +// Build the wrapper OpenGL ES 1.x library +// +cc_library_shared { + name: "libGLESv1_CM", + defaults: ["gles_libs_defaults"], + srcs: ["GLES_CM/gl.cpp"], + cflags: ["-DLOG_TAG=\"libGLESv1\""], +} + +//############################################################################## +// Build the wrapper OpenGL ES 2.x library +// +cc_library_shared { + name: "libGLESv2", + defaults: ["gles_libs_defaults"], + srcs: ["GLES2/gl2.cpp"], + cflags: ["-DLOG_TAG=\"libGLESv2\""], +} + +//############################################################################## +// Build the wrapper OpenGL ES 3.x library (this is just different name for v2) +// +cc_library_shared { + name: "libGLESv3", + defaults: ["gles_libs_defaults"], + srcs: ["GLES2/gl2.cpp"], + cflags: ["-DLOG_TAG=\"libGLESv3\""], +} diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk index 24e4c19a58..2f42ab63d1 100644 --- a/opengl/libs/Android.mk +++ b/opengl/libs/Android.mk @@ -1,182 +1 @@ LOCAL_PATH:= $(call my-dir) - -############################################################################### -# Build META EGL library -# - -egl.cfg_config_module := -# OpenGL drivers config file -ifneq ($(BOARD_EGL_CFG),) - -include $(CLEAR_VARS) -LOCAL_MODULE := egl.cfg -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/egl -LOCAL_SRC_FILES := ../../../../$(BOARD_EGL_CFG) -include $(BUILD_PREBUILT) -egl.cfg_config_module := $(LOCAL_MODULE) -endif - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - EGL/egl_tls.cpp \ - EGL/egl_cache.cpp \ - EGL/egl_display.cpp \ - EGL/egl_object.cpp \ - EGL/egl.cpp \ - EGL/eglApi.cpp \ - EGL/getProcAddress.cpp.arm \ - EGL/Loader.cpp \ -# - -LOCAL_SHARED_LIBRARIES += libbinder libcutils libutils liblog libui -LOCAL_MODULE:= libEGL -LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL -LOCAL_SHARED_LIBRARIES += libdl -# we need to access the private Bionic header <bionic_tls.h> -LOCAL_C_INCLUDES += bionic/libc/private - -LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\" -LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -LOCAL_CFLAGS += -fvisibility=hidden - -ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true) - LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION -endif -ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),) - LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE) -endif - -ifneq ($(MAX_EGL_CACHE_KEY_SIZE),) - LOCAL_CFLAGS += -DMAX_EGL_CACHE_KEY_SIZE=$(MAX_EGL_CACHE_KEY_SIZE) -endif - -ifneq ($(MAX_EGL_CACHE_SIZE),) - LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE) -endif - -ifneq ($(filter address,$(SANITIZE_TARGET)),) - LOCAL_CFLAGS_32 += -DEGL_WRAPPER_DIR=\"/$(TARGET_COPY_OUT_DATA)/lib\" - LOCAL_CFLAGS_64 += -DEGL_WRAPPER_DIR=\"/$(TARGET_COPY_OUT_DATA)/lib64\" -endif - -LOCAL_REQUIRED_MODULES := $(egl.cfg_config_module) -egl.cfg_config_module := - -include $(BUILD_SHARED_LIBRARY) - -############################################################################### -# Build the wrapper OpenGL ES 1.x library -# - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - GLES_CM/gl.cpp.arm \ -# - -LOCAL_CLANG := false -LOCAL_SHARED_LIBRARIES += libcutils liblog libEGL -LOCAL_MODULE:= libGLESv1_CM - -LOCAL_SHARED_LIBRARIES += libdl -# we need to access the private Bionic header <bionic_tls.h> -LOCAL_C_INCLUDES += bionic/libc/private - -LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv1\" -LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -LOCAL_CFLAGS += -fvisibility=hidden - -# TODO: This is to work around b/20093774. Remove after root cause is fixed -LOCAL_LDFLAGS_arm += -Wl,--hash-style,both - -include $(BUILD_SHARED_LIBRARY) - - -############################################################################### -# Build the wrapper OpenGL ES 2.x library -# - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - GLES2/gl2.cpp \ -# - -LOCAL_CLANG := false -LOCAL_ARM_MODE := arm -LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL -LOCAL_MODULE:= libGLESv2 - -LOCAL_SHARED_LIBRARIES += libdl -# we need to access the private Bionic header <bionic_tls.h> -LOCAL_C_INCLUDES += bionic/libc/private - -LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv2\" -LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -LOCAL_CFLAGS += -fvisibility=hidden - -# TODO: This is to work around b/20093774. Remove after root cause is fixed -LOCAL_LDFLAGS_arm += -Wl,--hash-style,both - -include $(BUILD_SHARED_LIBRARY) - -############################################################################### -# Build the wrapper OpenGL ES 3.x library (this is just different name for v2) -# - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - GLES2/gl2.cpp \ -# - -LOCAL_CLANG := false -LOCAL_ARM_MODE := arm -LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL -LOCAL_MODULE:= libGLESv3 -LOCAL_SHARED_LIBRARIES += libdl -# we need to access the private Bionic header <bionic_tls.h> -LOCAL_C_INCLUDES += bionic/libc/private - -LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv3\" -LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -LOCAL_CFLAGS += -fvisibility=hidden - -# TODO: This is to work around b/20093774. Remove after root cause is fixed -LOCAL_LDFLAGS_arm += -Wl,--hash-style,both - -include $(BUILD_SHARED_LIBRARY) - -############################################################################### -# Build the ETC1 host static library -# - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - ETC1/etc1.cpp \ -# - -LOCAL_MODULE:= libETC1 -LOCAL_MODULE_HOST_OS := darwin linux windows - -include $(BUILD_HOST_STATIC_LIBRARY) - -############################################################################### -# Build the ETC1 device library -# - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - ETC1/etc1.cpp \ -# - -LOCAL_MODULE:= libETC1 - -include $(BUILD_SHARED_LIBRARY) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp new file mode 100644 index 0000000000..f1b30c7957 --- /dev/null +++ b/opengl/libs/EGL/BlobCache.cpp @@ -0,0 +1,373 @@ +/* + ** Copyright 2011, 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 LOG_NDEBUG 0 + +#include "BlobCache.h" + +#include <inttypes.h> + +#include <cutils/properties.h> +#include <log/log.h> +#include <chrono> + +namespace android { + +// BlobCache::Header::mMagicNumber value +static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$'; + +// BlobCache::Header::mBlobCacheVersion value +static const uint32_t blobCacheVersion = 3; + +// BlobCache::Header::mDeviceVersion value +static const uint32_t blobCacheDeviceVersion = 1; + +BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize): + mMaxKeySize(maxKeySize), + mMaxValueSize(maxValueSize), + mMaxTotalSize(maxTotalSize), + mTotalSize(0) { + int64_t now = std::chrono::steady_clock::now().time_since_epoch().count(); +#ifdef _WIN32 + srand(now); +#else + mRandState[0] = (now >> 0) & 0xFFFF; + mRandState[1] = (now >> 16) & 0xFFFF; + mRandState[2] = (now >> 32) & 0xFFFF; +#endif + ALOGV("initializing random seed using %lld", (unsigned long long)now); +} + +void BlobCache::set(const void* key, size_t keySize, const void* value, + size_t valueSize) { + if (mMaxKeySize < keySize) { + ALOGV("set: not caching because the key is too large: %zu (limit: %zu)", + keySize, mMaxKeySize); + return; + } + if (mMaxValueSize < valueSize) { + ALOGV("set: not caching because the value is too large: %zu (limit: %zu)", + valueSize, mMaxValueSize); + return; + } + if (mMaxTotalSize < keySize + valueSize) { + ALOGV("set: not caching because the combined key/value size is too " + "large: %zu (limit: %zu)", keySize + valueSize, mMaxTotalSize); + return; + } + if (keySize == 0) { + ALOGW("set: not caching because keySize is 0"); + return; + } + if (valueSize <= 0) { + ALOGW("set: not caching because valueSize is 0"); + return; + } + + std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false)); + CacheEntry dummyEntry(dummyKey, NULL); + + while (true) { + auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry); + if (index == mCacheEntries.end() || dummyEntry < *index) { + // Create a new cache entry. + std::shared_ptr<Blob> keyBlob(new Blob(key, keySize, true)); + std::shared_ptr<Blob> valueBlob(new Blob(value, valueSize, true)); + size_t newTotalSize = mTotalSize + keySize + valueSize; + if (mMaxTotalSize < newTotalSize) { + if (isCleanable()) { + // Clean the cache and try again. + clean(); + continue; + } else { + ALOGV("set: not caching new key/value pair because the " + "total cache size limit would be exceeded: %zu " + "(limit: %zu)", + keySize + valueSize, mMaxTotalSize); + break; + } + } + mCacheEntries.insert(index, CacheEntry(keyBlob, valueBlob)); + mTotalSize = newTotalSize; + ALOGV("set: created new cache entry with %zu byte key and %zu byte value", + keySize, valueSize); + } else { + // Update the existing cache entry. + std::shared_ptr<Blob> valueBlob(new Blob(value, valueSize, true)); + std::shared_ptr<Blob> oldValueBlob(index->getValue()); + size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize(); + if (mMaxTotalSize < newTotalSize) { + if (isCleanable()) { + // Clean the cache and try again. + clean(); + continue; + } else { + ALOGV("set: not caching new value because the total cache " + "size limit would be exceeded: %zu (limit: %zu)", + keySize + valueSize, mMaxTotalSize); + break; + } + } + index->setValue(valueBlob); + mTotalSize = newTotalSize; + ALOGV("set: updated existing cache entry with %zu byte key and %zu byte " + "value", keySize, valueSize); + } + break; + } +} + +size_t BlobCache::get(const void* key, size_t keySize, void* value, + size_t valueSize) { + if (mMaxKeySize < keySize) { + ALOGV("get: not searching because the key is too large: %zu (limit %zu)", + keySize, mMaxKeySize); + return 0; + } + std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false)); + CacheEntry dummyEntry(dummyKey, NULL); + auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry); + if (index == mCacheEntries.end() || dummyEntry < *index) { + ALOGV("get: no cache entry found for key of size %zu", keySize); + return 0; + } + + // The key was found. Return the value if the caller's buffer is large + // enough. + std::shared_ptr<Blob> valueBlob(index->getValue()); + size_t valueBlobSize = valueBlob->getSize(); + if (valueBlobSize <= valueSize) { + ALOGV("get: copying %zu bytes to caller's buffer", valueBlobSize); + memcpy(value, valueBlob->getData(), valueBlobSize); + } else { + ALOGV("get: caller's buffer is too small for value: %zu (needs %zu)", + valueSize, valueBlobSize); + } + return valueBlobSize; +} + +static inline size_t align4(size_t size) { + return (size + 3) & ~3; +} + +size_t BlobCache::getFlattenedSize() const { + size_t size = align4(sizeof(Header) + PROPERTY_VALUE_MAX); + for (const CacheEntry& e : mCacheEntries) { + std::shared_ptr<Blob> const& keyBlob = e.getKey(); + std::shared_ptr<Blob> const& valueBlob = e.getValue(); + size += align4(sizeof(EntryHeader) + keyBlob->getSize() + valueBlob->getSize()); + } + return size; +} + +int BlobCache::flatten(void* buffer, size_t size) const { + // Write the cache header + if (size < sizeof(Header)) { + ALOGE("flatten: not enough room for cache header"); + return 0; + } + Header* header = reinterpret_cast<Header*>(buffer); + header->mMagicNumber = blobCacheMagic; + header->mBlobCacheVersion = blobCacheVersion; + header->mDeviceVersion = blobCacheDeviceVersion; + header->mNumEntries = mCacheEntries.size(); + char buildId[PROPERTY_VALUE_MAX]; + header->mBuildIdLength = property_get("ro.build.id", buildId, ""); + memcpy(header->mBuildId, buildId, header->mBuildIdLength); + + // Write cache entries + uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer); + off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength); + for (const CacheEntry& e : mCacheEntries) { + std::shared_ptr<Blob> const& keyBlob = e.getKey(); + std::shared_ptr<Blob> const& valueBlob = e.getValue(); + size_t keySize = keyBlob->getSize(); + size_t valueSize = valueBlob->getSize(); + + size_t entrySize = sizeof(EntryHeader) + keySize + valueSize; + size_t totalSize = align4(entrySize); + if (byteOffset + totalSize > size) { + ALOGE("flatten: not enough room for cache entries"); + return -EINVAL; + } + + EntryHeader* eheader = reinterpret_cast<EntryHeader*>(&byteBuffer[byteOffset]); + eheader->mKeySize = keySize; + eheader->mValueSize = valueSize; + + memcpy(eheader->mData, keyBlob->getData(), keySize); + memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize); + + if (totalSize > entrySize) { + // We have padding bytes. Those will get written to storage, and contribute to the CRC, + // so make sure we zero-them to have reproducible results. + memset(eheader->mData + keySize + valueSize, 0, totalSize - entrySize); + } + + byteOffset += totalSize; + } + + return 0; +} + +int BlobCache::unflatten(void const* buffer, size_t size) { + // All errors should result in the BlobCache being in an empty state. + mCacheEntries.clear(); + + // Read the cache header + if (size < sizeof(Header)) { + ALOGE("unflatten: not enough room for cache header"); + return -EINVAL; + } + const Header* header = reinterpret_cast<const Header*>(buffer); + if (header->mMagicNumber != blobCacheMagic) { + ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber); + return -EINVAL; + } + char buildId[PROPERTY_VALUE_MAX]; + int len = property_get("ro.build.id", buildId, ""); + if (header->mBlobCacheVersion != blobCacheVersion || + header->mDeviceVersion != blobCacheDeviceVersion || + len != header->mBuildIdLength || + strncmp(buildId, header->mBuildId, len)) { + // We treat version mismatches as an empty cache. + return 0; + } + + // Read cache entries + const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer); + off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength); + size_t numEntries = header->mNumEntries; + for (size_t i = 0; i < numEntries; i++) { + if (byteOffset + sizeof(EntryHeader) > size) { + mCacheEntries.clear(); + ALOGE("unflatten: not enough room for cache entry headers"); + return -EINVAL; + } + + const EntryHeader* eheader = reinterpret_cast<const EntryHeader*>( + &byteBuffer[byteOffset]); + size_t keySize = eheader->mKeySize; + size_t valueSize = eheader->mValueSize; + size_t entrySize = sizeof(EntryHeader) + keySize + valueSize; + + size_t totalSize = align4(entrySize); + if (byteOffset + totalSize > size) { + mCacheEntries.clear(); + ALOGE("unflatten: not enough room for cache entry headers"); + return -EINVAL; + } + + const uint8_t* data = eheader->mData; + set(data, keySize, data + keySize, valueSize); + + byteOffset += totalSize; + } + + return 0; +} + +long int BlobCache::blob_random() { +#ifdef _WIN32 + return rand(); +#else + return nrand48(mRandState); +#endif +} + +void BlobCache::clean() { + // Remove a random cache entry until the total cache size gets below half + // the maximum total cache size. + while (mTotalSize > mMaxTotalSize / 2) { + size_t i = size_t(blob_random() % (mCacheEntries.size())); + const CacheEntry& entry(mCacheEntries[i]); + mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize(); + mCacheEntries.erase(mCacheEntries.begin() + i); + } +} + +bool BlobCache::isCleanable() const { + return mTotalSize > mMaxTotalSize / 2; +} + +BlobCache::Blob::Blob(const void* data, size_t size, bool copyData) : + mData(copyData ? malloc(size) : data), + mSize(size), + mOwnsData(copyData) { + if (data != NULL && copyData) { + memcpy(const_cast<void*>(mData), data, size); + } +} + +BlobCache::Blob::~Blob() { + if (mOwnsData) { + free(const_cast<void*>(mData)); + } +} + +bool BlobCache::Blob::operator<(const Blob& rhs) const { + if (mSize == rhs.mSize) { + return memcmp(mData, rhs.mData, mSize) < 0; + } else { + return mSize < rhs.mSize; + } +} + +const void* BlobCache::Blob::getData() const { + return mData; +} + +size_t BlobCache::Blob::getSize() const { + return mSize; +} + +BlobCache::CacheEntry::CacheEntry() { +} + +BlobCache::CacheEntry::CacheEntry( + const std::shared_ptr<Blob>& key, const std::shared_ptr<Blob>& value): + mKey(key), + mValue(value) { +} + +BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce): + mKey(ce.mKey), + mValue(ce.mValue) { +} + +bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const { + return *mKey < *rhs.mKey; +} + +const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) { + mKey = rhs.mKey; + mValue = rhs.mValue; + return *this; +} + +std::shared_ptr<BlobCache::Blob> BlobCache::CacheEntry::getKey() const { + return mKey; +} + +std::shared_ptr<BlobCache::Blob> BlobCache::CacheEntry::getValue() const { + return mValue; +} + +void BlobCache::CacheEntry::setValue(const std::shared_ptr<Blob>& value) { + mValue = value; +} + +} // namespace android diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h new file mode 100644 index 0000000000..a0a270a5fe --- /dev/null +++ b/opengl/libs/EGL/BlobCache.h @@ -0,0 +1,245 @@ +/* + ** Copyright 2011, 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_BLOB_CACHE_H +#define ANDROID_BLOB_CACHE_H + +#include <stddef.h> + +#include <memory> +#include <vector> + +namespace android { + +// A BlobCache is an in-memory cache for binary key/value pairs. A BlobCache +// does NOT provide any thread-safety guarantees. +// +// The cache contents can be serialized to an in-memory buffer or mmap'd file +// and then reloaded in a subsequent execution of the program. This +// serialization is non-portable and the data should only be used by the device +// that generated it. +class BlobCache { +public: + // Create an empty blob cache. The blob cache will cache key/value pairs + // with key and value sizes less than or equal to maxKeySize and + // maxValueSize, respectively. The total combined size of ALL cache entries + // (key sizes plus value sizes) will not exceed maxTotalSize. + BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize); + + // set inserts a new binary value into the cache and associates it with the + // given binary key. If the key or value are too large for the cache then + // the cache remains unchanged. This includes the case where a different + // value was previously associated with the given key - the old value will + // remain in the cache. If the given key and value are small enough to be + // put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize + // values specified to the BlobCache constructor), then the key/value pair + // will be in the cache after set returns. Note, however, that a subsequent + // call to set may evict old key/value pairs from the cache. + // + // Preconditions: + // key != NULL + // 0 < keySize + // value != NULL + // 0 < valueSize + void set(const void* key, size_t keySize, const void* value, + size_t valueSize); + + // get retrieves from the cache the binary value associated with a given + // binary key. If the key is present in the cache then the length of the + // binary value associated with that key is returned. If the value argument + // is non-NULL and the size of the cached value is less than valueSize bytes + // then the cached value is copied into the buffer pointed to by the value + // argument. If the key is not present in the cache then 0 is returned and + // the buffer pointed to by the value argument is not modified. + // + // Note that when calling get multiple times with the same key, the later + // calls may fail, returning 0, even if earlier calls succeeded. The return + // value must be checked for each call. + // + // Preconditions: + // key != NULL + // 0 < keySize + // 0 <= valueSize + size_t get(const void* key, size_t keySize, void* value, size_t valueSize); + + + // getFlattenedSize returns the number of bytes needed to store the entire + // serialized cache. + size_t getFlattenedSize() const; + + // flatten serializes the current contents of the cache into the memory + // pointed to by 'buffer'. The serialized cache contents can later be + // loaded into a BlobCache object using the unflatten method. The contents + // of the BlobCache object will not be modified. + // + // Preconditions: + // size >= this.getFlattenedSize() + int flatten(void* buffer, size_t size) const; + + // unflatten replaces the contents of the cache with the serialized cache + // contents in the memory pointed to by 'buffer'. The previous contents of + // the BlobCache will be evicted from the cache. If an error occurs while + // unflattening the serialized cache contents then the BlobCache will be + // left in an empty state. + // + int unflatten(void const* buffer, size_t size); + +private: + // Copying is disallowed. + BlobCache(const BlobCache&); + void operator=(const BlobCache&); + + // A random function helper to get around MinGW not having nrand48() + long int blob_random(); + + // clean evicts a randomly chosen set of entries from the cache such that + // the total size of all remaining entries is less than mMaxTotalSize/2. + void clean(); + + // isCleanable returns true if the cache is full enough for the clean method + // to have some effect, and false otherwise. + bool isCleanable() const; + + // A Blob is an immutable sized unstructured data blob. + class Blob { + public: + Blob(const void* data, size_t size, bool copyData); + ~Blob(); + + bool operator<(const Blob& rhs) const; + + const void* getData() const; + size_t getSize() const; + + private: + // Copying is not allowed. + Blob(const Blob&); + void operator=(const Blob&); + + // mData points to the buffer containing the blob data. + const void* mData; + + // mSize is the size of the blob data in bytes. + size_t mSize; + + // mOwnsData indicates whether or not this Blob object should free the + // memory pointed to by mData when the Blob gets destructed. + bool mOwnsData; + }; + + // A CacheEntry is a single key/value pair in the cache. + class CacheEntry { + public: + CacheEntry(); + CacheEntry(const std::shared_ptr<Blob>& key, const std::shared_ptr<Blob>& value); + CacheEntry(const CacheEntry& ce); + + bool operator<(const CacheEntry& rhs) const; + const CacheEntry& operator=(const CacheEntry&); + + std::shared_ptr<Blob> getKey() const; + std::shared_ptr<Blob> getValue() const; + + void setValue(const std::shared_ptr<Blob>& value); + + private: + + // mKey is the key that identifies the cache entry. + std::shared_ptr<Blob> mKey; + + // mValue is the cached data associated with the key. + std::shared_ptr<Blob> mValue; + }; + + // A Header is the header for the entire BlobCache serialization format. No + // need to make this portable, so we simply write the struct out. + struct Header { + // mMagicNumber is the magic number that identifies the data as + // serialized BlobCache contents. It must always contain 'Blb$'. + uint32_t mMagicNumber; + + // mBlobCacheVersion is the serialization format version. + uint32_t mBlobCacheVersion; + + // mDeviceVersion is the device-specific version of the cache. This can + // be used to invalidate the cache. + uint32_t mDeviceVersion; + + // mNumEntries is number of cache entries following the header in the + // data. + size_t mNumEntries; + + // mBuildId is the build id of the device when the cache was created. + // When an update to the build happens (via an OTA or other update) this + // is used to invalidate the cache. + int mBuildIdLength; + char mBuildId[]; + }; + + // An EntryHeader is the header for a serialized cache entry. No need to + // make this portable, so we simply write the struct out. Each EntryHeader + // is followed imediately by the key data and then the value data. + // + // The beginning of each serialized EntryHeader is 4-byte aligned, so the + // number of bytes that a serialized cache entry will occupy is: + // + // ((sizeof(EntryHeader) + keySize + valueSize) + 3) & ~3 + // + struct EntryHeader { + // mKeySize is the size of the entry key in bytes. + size_t mKeySize; + + // mValueSize is the size of the entry value in bytes. + size_t mValueSize; + + // mData contains both the key and value data for the cache entry. The + // key comes first followed immediately by the value. + uint8_t mData[]; + }; + + // mMaxKeySize is the maximum key size that will be cached. Calls to + // BlobCache::set with a keySize parameter larger than mMaxKeySize will + // simply not add the key/value pair to the cache. + const size_t mMaxKeySize; + + // mMaxValueSize is the maximum value size that will be cached. Calls to + // BlobCache::set with a valueSize parameter larger than mMaxValueSize will + // simply not add the key/value pair to the cache. + const size_t mMaxValueSize; + + // mMaxTotalSize is the maximum size that all cache entries can occupy. This + // includes space for both keys and values. When a call to BlobCache::set + // would otherwise cause this limit to be exceeded, either the key/value + // pair passed to BlobCache::set will not be cached or other cache entries + // will be evicted from the cache to make room for the new entry. + const size_t mMaxTotalSize; + + // mTotalSize is the total combined size of all keys and values currently in + // the cache. + size_t mTotalSize; + + // mRandState is the pseudo-random number generator state. It is passed to + // nrand48 to generate random numbers when needed. + unsigned short mRandState[3]; + + // mCacheEntries stores all the cache entries that are resident in memory. + // Cache entries are added to it by the 'set' method. + std::vector<CacheEntry> mCacheEntries; +}; + +} + +#endif // ANDROID_BLOB_CACHE_H diff --git a/opengl/libs/EGL/BlobCache_test.cpp b/opengl/libs/EGL/BlobCache_test.cpp new file mode 100644 index 0000000000..edbaaf090d --- /dev/null +++ b/opengl/libs/EGL/BlobCache_test.cpp @@ -0,0 +1,434 @@ +/* + ** Copyright 2011, 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 <fcntl.h> +#include <stdio.h> + +#include <memory> + +#include <gtest/gtest.h> + +#include "BlobCache.h" + +namespace android { + +template<typename T> using sp = std::shared_ptr<T>; + +class BlobCacheTest : public ::testing::Test { +protected: + + enum { + OK = 0, + BAD_VALUE = -EINVAL + }; + + enum { + MAX_KEY_SIZE = 6, + MAX_VALUE_SIZE = 8, + MAX_TOTAL_SIZE = 13, + }; + + virtual void SetUp() { + mBC.reset(new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE)); + } + + virtual void TearDown() { + mBC.reset(); + } + + std::unique_ptr<BlobCache> mBC; +}; + +TEST_F(BlobCacheTest, CacheSingleValueSucceeds) { + unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + mBC->set("abcd", 4, "efgh", 4); + ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); + ASSERT_EQ('e', buf[0]); + ASSERT_EQ('f', buf[1]); + ASSERT_EQ('g', buf[2]); + ASSERT_EQ('h', buf[3]); +} + +TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) { + unsigned char buf[2] = { 0xee, 0xee }; + mBC->set("ab", 2, "cd", 2); + mBC->set("ef", 2, "gh", 2); + ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2)); + ASSERT_EQ('c', buf[0]); + ASSERT_EQ('d', buf[1]); + ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2)); + ASSERT_EQ('g', buf[0]); + ASSERT_EQ('h', buf[1]); +} + +TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) { + unsigned char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee }; + mBC->set("abcd", 4, "efgh", 4); + ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4)); + ASSERT_EQ(0xee, buf[0]); + ASSERT_EQ('e', buf[1]); + ASSERT_EQ('f', buf[2]); + ASSERT_EQ('g', buf[3]); + ASSERT_EQ('h', buf[4]); + ASSERT_EQ(0xee, buf[5]); +} + +TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) { + unsigned char buf[3] = { 0xee, 0xee, 0xee }; + mBC->set("abcd", 4, "efgh", 4); + ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3)); + ASSERT_EQ(0xee, buf[0]); + ASSERT_EQ(0xee, buf[1]); + ASSERT_EQ(0xee, buf[2]); +} + +TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) { + mBC->set("abcd", 4, "efgh", 4); + ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0)); +} + +TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) { + unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + mBC->set("abcd", 4, "efgh", 4); + mBC->set("abcd", 4, "ijkl", 4); + ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); + ASSERT_EQ('i', buf[0]); + ASSERT_EQ('j', buf[1]); + ASSERT_EQ('k', buf[2]); + ASSERT_EQ('l', buf[3]); +} + +TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) { + unsigned char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee }; + mBC->set("abcd", 4, "efgh", 4); + mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1); + ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4)); + ASSERT_EQ('e', buf[0]); + ASSERT_EQ('f', buf[1]); + ASSERT_EQ('g', buf[2]); + ASSERT_EQ('h', buf[3]); +} + +TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) { + char key[MAX_KEY_SIZE+1]; + unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + for (int i = 0; i < MAX_KEY_SIZE+1; i++) { + key[i] = 'a'; + } + mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4); + ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4)); + ASSERT_EQ(0xee, buf[0]); + ASSERT_EQ(0xee, buf[1]); + ASSERT_EQ(0xee, buf[2]); + ASSERT_EQ(0xee, buf[3]); +} + +TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) { + char buf[MAX_VALUE_SIZE+1]; + for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { + buf[i] = 'b'; + } + mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1); + for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { + buf[i] = 0xee; + } + ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1)); + for (int i = 0; i < MAX_VALUE_SIZE+1; i++) { + SCOPED_TRACE(i); + ASSERT_EQ(0xee, buf[i]); + } +} + +TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) { + // Check a testing assumptions + ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE); + ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE); + + enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 }; + + char key[MAX_KEY_SIZE]; + char buf[bufSize]; + for (int i = 0; i < MAX_KEY_SIZE; i++) { + key[i] = 'a'; + } + for (int i = 0; i < bufSize; i++) { + buf[i] = 'b'; + } + + mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE); + ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0)); +} + +TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) { + char key[MAX_KEY_SIZE]; + unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + for (int i = 0; i < MAX_KEY_SIZE; i++) { + key[i] = 'a'; + } + mBC->set(key, MAX_KEY_SIZE, "wxyz", 4); + ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4)); + ASSERT_EQ('w', buf[0]); + ASSERT_EQ('x', buf[1]); + ASSERT_EQ('y', buf[2]); + ASSERT_EQ('z', buf[3]); +} + +TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) { + char buf[MAX_VALUE_SIZE]; + for (int i = 0; i < MAX_VALUE_SIZE; i++) { + buf[i] = 'b'; + } + mBC->set("abcd", 4, buf, MAX_VALUE_SIZE); + for (int i = 0; i < MAX_VALUE_SIZE; i++) { + buf[i] = 0xee; + } + ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf, + MAX_VALUE_SIZE)); + for (int i = 0; i < MAX_VALUE_SIZE; i++) { + SCOPED_TRACE(i); + ASSERT_EQ('b', buf[i]); + } +} + +TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) { + // Check a testing assumption + ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE); + + enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE }; + + char key[MAX_KEY_SIZE]; + char buf[bufSize]; + for (int i = 0; i < MAX_KEY_SIZE; i++) { + key[i] = 'a'; + } + for (int i = 0; i < bufSize; i++) { + buf[i] = 'b'; + } + + mBC->set(key, MAX_KEY_SIZE, buf, bufSize); + ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0)); +} + +TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) { + unsigned char buf[1] = { 0xee }; + mBC->set("x", 1, "y", 1); + ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1)); + ASSERT_EQ('y', buf[0]); +} + +TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) { + for (int i = 0; i < 256; i++) { + uint8_t k = i; + mBC->set(&k, 1, "x", 1); + } + int numCached = 0; + for (int i = 0; i < 256; i++) { + uint8_t k = i; + if (mBC->get(&k, 1, NULL, 0) == 1) { + numCached++; + } + } + ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached); +} + +TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) { + // Fill up the entire cache with 1 char key/value pairs. + const int maxEntries = MAX_TOTAL_SIZE / 2; + for (int i = 0; i < maxEntries; i++) { + uint8_t k = i; + mBC->set(&k, 1, "x", 1); + } + // Insert one more entry, causing a cache overflow. + { + uint8_t k = maxEntries; + mBC->set(&k, 1, "x", 1); + } + // Count the number of entries in the cache. + int numCached = 0; + for (int i = 0; i < maxEntries+1; i++) { + uint8_t k = i; + if (mBC->get(&k, 1, NULL, 0) == 1) { + numCached++; + } + } + ASSERT_EQ(maxEntries/2 + 1, numCached); +} + +class BlobCacheFlattenTest : public BlobCacheTest { +protected: + virtual void SetUp() { + BlobCacheTest::SetUp(); + mBC2.reset(new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE)); + } + + virtual void TearDown() { + mBC2.reset(); + BlobCacheTest::TearDown(); + } + + void roundTrip() { + size_t size = mBC->getFlattenedSize(); + uint8_t* flat = new uint8_t[size]; + ASSERT_EQ(OK, mBC->flatten(flat, size)); + ASSERT_EQ(OK, mBC2->unflatten(flat, size)); + delete[] flat; + } + + sp<BlobCache> mBC2; +}; + +TEST_F(BlobCacheFlattenTest, FlattenOneValue) { + unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + mBC->set("abcd", 4, "efgh", 4); + roundTrip(); + ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4)); + ASSERT_EQ('e', buf[0]); + ASSERT_EQ('f', buf[1]); + ASSERT_EQ('g', buf[2]); + ASSERT_EQ('h', buf[3]); +} + +TEST_F(BlobCacheFlattenTest, FlattenFullCache) { + // Fill up the entire cache with 1 char key/value pairs. + const int maxEntries = MAX_TOTAL_SIZE / 2; + for (int i = 0; i < maxEntries; i++) { + uint8_t k = i; + mBC->set(&k, 1, &k, 1); + } + + roundTrip(); + + // Verify the deserialized cache + for (int i = 0; i < maxEntries; i++) { + uint8_t k = i; + uint8_t v = 0xee; + ASSERT_EQ(size_t(1), mBC2->get(&k, 1, &v, 1)); + ASSERT_EQ(k, v); + } +} + +TEST_F(BlobCacheFlattenTest, FlattenDoesntChangeCache) { + // Fill up the entire cache with 1 char key/value pairs. + const int maxEntries = MAX_TOTAL_SIZE / 2; + for (int i = 0; i < maxEntries; i++) { + uint8_t k = i; + mBC->set(&k, 1, &k, 1); + } + + size_t size = mBC->getFlattenedSize(); + uint8_t* flat = new uint8_t[size]; + ASSERT_EQ(OK, mBC->flatten(flat, size)); + delete[] flat; + + // Verify the cache that we just serialized + for (int i = 0; i < maxEntries; i++) { + uint8_t k = i; + uint8_t v = 0xee; + ASSERT_EQ(size_t(1), mBC->get(&k, 1, &v, 1)); + ASSERT_EQ(k, v); + } +} + +TEST_F(BlobCacheFlattenTest, FlattenCatchesBufferTooSmall) { + // Fill up the entire cache with 1 char key/value pairs. + const int maxEntries = MAX_TOTAL_SIZE / 2; + for (int i = 0; i < maxEntries; i++) { + uint8_t k = i; + mBC->set(&k, 1, &k, 1); + } + + size_t size = mBC->getFlattenedSize() - 1; + uint8_t* flat = new uint8_t[size]; + // ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size)); + // TODO: The above fails. I expect this is so because getFlattenedSize() + // overstimates the size by using PROPERTY_VALUE_MAX. + delete[] flat; +} + +TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) { + unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + mBC->set("abcd", 4, "efgh", 4); + + size_t size = mBC->getFlattenedSize(); + uint8_t* flat = new uint8_t[size]; + ASSERT_EQ(OK, mBC->flatten(flat, size)); + flat[1] = ~flat[1]; + + // Bad magic should cause an error. + ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size)); + delete[] flat; + + // The error should cause the unflatten to result in an empty cache + ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); +} + +TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) { + unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + mBC->set("abcd", 4, "efgh", 4); + + size_t size = mBC->getFlattenedSize(); + uint8_t* flat = new uint8_t[size]; + ASSERT_EQ(OK, mBC->flatten(flat, size)); + flat[5] = ~flat[5]; + + // Version mismatches shouldn't cause errors, but should not use the + // serialized entries + ASSERT_EQ(OK, mBC2->unflatten(flat, size)); + delete[] flat; + + // The version mismatch should cause the unflatten to result in an empty + // cache + ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); +} + +TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) { + unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + mBC->set("abcd", 4, "efgh", 4); + + size_t size = mBC->getFlattenedSize(); + uint8_t* flat = new uint8_t[size]; + ASSERT_EQ(OK, mBC->flatten(flat, size)); + flat[10] = ~flat[10]; + + // Version mismatches shouldn't cause errors, but should not use the + // serialized entries + ASSERT_EQ(OK, mBC2->unflatten(flat, size)); + delete[] flat; + + // The version mismatch should cause the unflatten to result in an empty + // cache + ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); +} + +TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) { + unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + mBC->set("abcd", 4, "efgh", 4); + + size_t size = mBC->getFlattenedSize(); + uint8_t* flat = new uint8_t[size]; + ASSERT_EQ(OK, mBC->flatten(flat, size)); + + // A buffer truncation shouldt cause an error + // ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1)); + // TODO: The above appears to fail because getFlattenedSize() is + // conservative. + delete[] flat; + + // The error should cause the unflatten to result in an empty cache + ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4)); +} + +} // namespace android diff --git a/opengl/libs/EGL/CallStack.h b/opengl/libs/EGL/CallStack.h new file mode 100644 index 0000000000..0e2a9b3248 --- /dev/null +++ b/opengl/libs/EGL/CallStack.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2017 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. + */ + +#pragma once + +#include <log/log.h> +#include <backtrace/Backtrace.h> +#include <memory> + +class CallStack { +public: + // Create a callstack with the current thread's stack trace. + // Immediately dump it to logcat using the given logtag. + static void log(const char* logtag) noexcept { + std::unique_ptr<Backtrace> backtrace( + Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); + if (backtrace->Unwind(2)) { + for (size_t i = 0, c = backtrace->NumFrames(); i < c; i++) { + __android_log_print(ANDROID_LOG_DEBUG, logtag, "%s", + backtrace->FormatFrameData(i).c_str()); + } + } + } +}; + diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index ca5e6e8180..823b502ad8 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -17,25 +17,26 @@ //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <array> -#include <ctype.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <dlfcn.h> -#include <limits.h> +#include "Loader.h" + +#include <string> + #include <dirent.h> +#include <dlfcn.h> #include <android/dlext.h> -#include <cutils/log.h> #include <cutils/properties.h> -#include <utils/Trace.h> +#include <log/log.h> -#include <EGL/egl.h> +#include <ui/GraphicsEnv.h> +#include <vndksupport/linker.h> +#include "egl_trace.h" #include "egldefs.h" -#include "Loader.h" + +extern "C" { + android_namespace_t* android_get_exported_namespace(const char*); +} // ---------------------------------------------------------------------------- namespace android { @@ -65,7 +66,10 @@ namespace android { * */ -ANDROID_SINGLETON_STATIC_INSTANCE( Loader ) +Loader& Loader::getInstance() { + static Loader loader; + return loader; +} /* This function is called to check whether we run inside the emulator, * and if this is the case whether GLES GPU emulation is supported. @@ -102,27 +106,19 @@ checkGlesEmulationStatus(void) return atoi(prop); } -// ---------------------------------------------------------------------------- +static void* do_dlopen(const char* path, int mode) { + ATRACE_CALL(); + return dlopen(path, mode); +} -static char const * getProcessCmdline() { - long pid = getpid(); - char procPath[128]; - snprintf(procPath, 128, "/proc/%ld/cmdline", pid); - FILE * file = fopen(procPath, "r"); - if (file) { - static char cmdline[256]; - char *str = fgets(cmdline, sizeof(cmdline) - 1, file); - fclose(file); - if (str) { - return cmdline; - } - } - return NULL; +static void* do_android_dlopen_ext(const char* path, int mode, const android_dlextinfo* info) { + ATRACE_CALL(); + return android_dlopen_ext(path, mode, info); } -static void* do_dlopen(const char* path, int mode) { +static void* do_android_load_sphal_library(const char* path, int mode) { ATRACE_CALL(); - return dlopen(path, mode); + return android_load_sphal_library(path, mode); } // ---------------------------------------------------------------------------- @@ -144,7 +140,7 @@ Loader::driver_t::~driver_t() } } -status_t Loader::driver_t::set(void* hnd, int32_t api) +int Loader::driver_t::set(void* hnd, int32_t api) { switch (api) { case EGL: @@ -157,34 +153,19 @@ status_t Loader::driver_t::set(void* hnd, int32_t api) dso[2] = hnd; break; default: - return BAD_INDEX; + return -EOVERFLOW; } - return NO_ERROR; + return 0; } // ---------------------------------------------------------------------------- Loader::Loader() - : getProcAddress(NULL), - mLibGui(nullptr), - mGetDriverNamespace(nullptr) + : getProcAddress(NULL) { - // FIXME: See note in GraphicsEnv.h about android_getDriverNamespace(). - // libgui should already be loaded in any process that uses libEGL, but - // if for some reason it isn't, then we're not going to get a driver - // namespace anyway, so don't force it to be loaded. - mLibGui = dlopen("libgui.so", RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY); - if (!mLibGui) { - ALOGD("failed to load libgui: %s", dlerror()); - return; - } - mGetDriverNamespace = reinterpret_cast<decltype(mGetDriverNamespace)>( - dlsym(mLibGui, "android_getDriverNamespace")); } Loader::~Loader() { - if (mLibGui) - dlclose(mLibGui); } static void* load_wrapper(const char* path) { @@ -270,11 +251,10 @@ void* Loader::open(egl_connection_t* cnx) return (void*)hnd; } -status_t Loader::close(void* driver) +void Loader::close(void* driver) { driver_t* hnd = (driver_t*)driver; delete hnd; - return NO_ERROR; } void Loader::init_api(void* dso, @@ -339,23 +319,23 @@ static void* load_system_driver(const char* kind) { ATRACE_CALL(); class MatchFile { public: - static String8 find(const char* kind) { - String8 result; + static std::string find(const char* kind) { + std::string result; int emulationStatus = checkGlesEmulationStatus(); switch (emulationStatus) { case 0: #if defined(__LP64__) - result.setTo("/system/lib64/egl/libGLES_android.so"); + result = "/system/lib64/egl/libGLES_android.so"; #else - result.setTo("/system/lib/egl/libGLES_android.so"); + result = "/system/lib/egl/libGLES_android.so"; #endif return result; case 1: // Use host-side OpenGL through the "emulation" library #if defined(__LP64__) - result.appendFormat("/system/lib64/egl/lib%s_emulation.so", kind); + result = std::string("/system/lib64/egl/lib") + kind + "_emulation.so"; #else - result.appendFormat("/system/lib/egl/lib%s_emulation.so", kind); + result = std::string("/system/lib/egl/lib") + kind + "_emulation.so"; #endif return result; default: @@ -363,8 +343,7 @@ static void* load_system_driver(const char* kind) { break; } - String8 pattern; - pattern.appendFormat("lib%s", kind); + std::string pattern = std::string("lib") + kind; const char* const searchPaths[] = { #if defined(__LP64__) "/vendor/lib64/egl", @@ -405,12 +384,11 @@ static void* load_system_driver(const char* kind) { } private: - static bool find(String8& result, - const String8& pattern, const char* const search, bool exact) { + static bool find(std::string& result, + const std::string& pattern, const char* const search, bool exact) { if (exact) { - String8 absolutePath; - absolutePath.appendFormat("%s/%s.so", search, pattern.string()); - if (!access(absolutePath.string(), R_OK)) { + std::string absolutePath = std::string(search) + "/" + pattern; + if (!access(absolutePath.c_str(), R_OK)) { result = absolutePath; return true; } @@ -429,10 +407,9 @@ static void* load_system_driver(const char* kind) { // always skip the software renderer continue; } - if (strstr(e->d_name, pattern.string()) == e->d_name) { + if (strstr(e->d_name, pattern.c_str()) == e->d_name) { if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) { - result.clear(); - result.appendFormat("%s/%s", search, e->d_name); + result = std::string(search) + "/" + e->d_name; closedir(d); return true; } @@ -445,17 +422,22 @@ static void* load_system_driver(const char* kind) { }; - String8 absolutePath = MatchFile::find(kind); - if (absolutePath.isEmpty()) { + std::string absolutePath = MatchFile::find(kind); + if (absolutePath.empty()) { // this happens often, we don't want to log an error return 0; } - const char* const driver_absolute_path = absolutePath.string(); - - void* dso = do_dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL); + const char* const driver_absolute_path = absolutePath.c_str(); + + // Try to load drivers from the 'sphal' namespace, if it exist. Fall back to + // the original routine when the namespace does not exist. + // See /system/core/rootdir/etc/ld.config.txt for the configuration of the + // sphal namespace. + void* dso = do_android_load_sphal_library(driver_absolute_path, + RTLD_NOW | RTLD_LOCAL); if (dso == 0) { const char* err = dlerror(); - ALOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown"); + ALOGE("load_driver(%s): %s", driver_absolute_path, err ? err : "unknown"); return 0; } @@ -464,15 +446,10 @@ static void* load_system_driver(const char* kind) { return dso; } -static void* do_android_dlopen_ext(const char* path, int mode, const android_dlextinfo* info) { - ATRACE_CALL(); - return android_dlopen_ext(path, mode, info); -} - -static const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{ +static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = { "ro.hardware.egl", "ro.board.platform", -}}; +}; static void* load_updated_driver(const char* kind, android_namespace_t* ns) { ATRACE_CALL(); @@ -484,12 +461,11 @@ static void* load_updated_driver(const char* kind, android_namespace_t* ns) { char prop[PROPERTY_VALUE_MAX + 1]; for (auto key : HAL_SUBNAME_KEY_PROPERTIES) { if (property_get(key, prop, nullptr) > 0) { - String8 name; - name.appendFormat("lib%s_%s.so", kind, prop); - so = do_android_dlopen_ext(name.string(), RTLD_LOCAL | RTLD_NOW, - &dlextinfo); - if (so) + std::string name = std::string("lib") + kind + "_" + prop + ".so"; + so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo); + if (so) { return so; + } } } return nullptr; @@ -501,11 +477,9 @@ void *Loader::load_driver(const char* kind, ATRACE_CALL(); void* dso = nullptr; - if (mGetDriverNamespace) { - android_namespace_t* ns = mGetDriverNamespace(); - if (ns) { - dso = load_updated_driver(kind, ns); - } + android_namespace_t* ns = android_getDriverNamespace(); + if (ns) { + dso = load_updated_driver(kind, ns); } if (!dso) { dso = load_system_driver(kind); diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h index 04a8e413ad..6a32bb3066 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -17,15 +17,7 @@ #ifndef ANDROID_EGL_LOADER_H #define ANDROID_EGL_LOADER_H -#include <ctype.h> -#include <string.h> -#include <errno.h> - -#include <utils/Errors.h> -#include <utils/Singleton.h> -#include <utils/String8.h> - -#include <gui/GraphicsEnv.h> +#include <stdint.h> #include <EGL/egl.h> @@ -35,12 +27,8 @@ namespace android { struct egl_connection_t; -class Loader : public Singleton<Loader> -{ - friend class Singleton<Loader>; - - typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)( - const char*); +class Loader { + typedef __eglMustCastToProperFunctionPointerType (* getProcAddressType)(const char*); enum { EGL = 0x01, @@ -48,22 +36,21 @@ class Loader : public Singleton<Loader> GLESv2 = 0x04 }; struct driver_t { - driver_t(void* gles); + explicit driver_t(void* gles); ~driver_t(); - status_t set(void* hnd, int32_t api); + // returns -errno + int set(void* hnd, int32_t api); void* dso[3]; }; getProcAddressType getProcAddress; - void* mLibGui; - decltype(android_getDriverNamespace)* mGetDriverNamespace; - public: + static Loader& getInstance(); ~Loader(); void* open(egl_connection_t* cnx); - status_t close(void* driver); + void close(void* driver); private: Loader(); diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 18cf26174e..f53cf3f8cc 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -14,31 +14,24 @@ ** limitations under the License. */ -#include <ctype.h> #include <stdlib.h> -#include <string.h> #include <hardware/gralloc.h> -#include <system/window.h> #include <EGL/egl.h> -#include <EGL/eglext.h> -#include <cutils/log.h> -#include <cutils/atomic.h> #include <cutils/properties.h> -#include <utils/CallStack.h> -#include <utils/String8.h> +#include <log/log.h> #include "../egl_impl.h" -#include "egl_tls.h" #include "egldefs.h" -#include "Loader.h" - +#include "egl_tls.h" #include "egl_display.h" #include "egl_object.h" +#include "CallStack.h" +#include "Loader.h" typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer; @@ -71,7 +64,7 @@ static int gl_no_context() { char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.callstack", value, "0"); if (atoi(value)) { - CallStack stack(LOG_TAG); + CallStack::log(LOG_TAG); } } return 0; @@ -133,7 +126,7 @@ const GLubyte * egl_get_string_for_current_context(GLenum name) { if (name != GL_EXTENSIONS) return NULL; - return (const GLubyte *)c->gl_extensions.string(); + return (const GLubyte *)c->gl_extensions.c_str(); } const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) { @@ -156,7 +149,7 @@ const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) { if (index >= c->tokenized_gl_extensions.size()) return NULL; - return (const GLubyte *)c->tokenized_gl_extensions.itemAt(index).string(); + return (const GLubyte *)c->tokenized_gl_extensions[index].c_str(); } GLint egl_get_num_extensions_for_current_context() { @@ -213,14 +206,14 @@ EGLBoolean egl_init_drivers() { } static pthread_mutex_t sLogPrintMutex = PTHREAD_MUTEX_INITIALIZER; -static nsecs_t sLogPrintTime = 0; -#define NSECS_DURATION 1000000000 +static std::chrono::steady_clock::time_point sLogPrintTime; +static constexpr std::chrono::seconds DURATION(1); void gl_unimplemented() { bool printLog = false; - nsecs_t now = systemTime(); + auto now = std::chrono::steady_clock::now(); pthread_mutex_lock(&sLogPrintMutex); - if ((now - sLogPrintTime) > NSECS_DURATION) { + if ((now - sLogPrintTime) > DURATION) { sLogPrintTime = now; printLog = true; } @@ -230,7 +223,7 @@ void gl_unimplemented() { char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.callstack", value, "0"); if (atoi(value)) { - CallStack stack(LOG_TAG); + CallStack::log(LOG_TAG); } } } diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 436ea30800..ba3a5f91a3 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -16,56 +16,45 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <dlfcn.h> #include <ctype.h> +#include <dlfcn.h> #include <stdlib.h> #include <string.h> -#include <hardware/gralloc.h> -#include <system/window.h> +#include <hardware/gralloc1.h> #include <EGL/egl.h> #include <EGL/eglext.h> -#include <cutils/log.h> -#include <cutils/atomic.h> +#include <android/hardware_buffer.h> +#include <private/android/AHardwareBufferHelpers.h> + #include <cutils/compiler.h> #include <cutils/properties.h> -#include <cutils/memory.h> - -#include <gui/ISurfaceComposer.h> - -#include <ui/GraphicBuffer.h> - -#include <utils/KeyedVector.h> -#include <utils/SortedVector.h> -#include <utils/String8.h> -#include <utils/Trace.h> +#include <log/log.h> -#include "binder/Binder.h" -#include "binder/Parcel.h" -#include "binder/IServiceManager.h" +#include <condition_variable> +#include <deque> +#include <mutex> +#include <unordered_map> +#include <string> +#include <thread> #include "../egl_impl.h" -#include "../hooks.h" #include "egl_display.h" #include "egl_object.h" #include "egl_tls.h" -#include "egldefs.h" +#include "egl_trace.h" using namespace android; -// This extension has not been ratified yet, so can't be shipped. -// Implementation is incomplete and untested. -#define ENABLE_EGL_KHR_GL_COLORSPACE 0 - -#define ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS 0 - // ---------------------------------------------------------------------------- namespace android { +using nsecs_t = int64_t; + struct extention_map_t { const char* name; __eglMustCastToProperFunctionPointerType address; @@ -86,24 +75,25 @@ struct extention_map_t { * * NOTE: Both strings MUST have a single space as the last character. */ -extern char const * const gBuiltinExtensionString = + +extern char const * const gBuiltinExtensionString; +extern char const * const gExtensionString; + +char const * const gBuiltinExtensionString = "EGL_KHR_get_all_proc_addresses " "EGL_ANDROID_presentation_time " "EGL_KHR_swap_buffers_with_damage " - "EGL_ANDROID_create_native_client_buffer " + "EGL_ANDROID_get_native_client_buffer " "EGL_ANDROID_front_buffer_auto_refresh " -#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS "EGL_ANDROID_get_frame_timestamps " -#endif ; -extern char const * const gExtensionString = + +char const * const gExtensionString = "EGL_KHR_image " // mandatory "EGL_KHR_image_base " // mandatory "EGL_KHR_image_pixmap " "EGL_KHR_lock_surface " -#if (ENABLE_EGL_KHR_GL_COLORSPACE != 0) "EGL_KHR_gl_colorspace " -#endif "EGL_KHR_gl_texture_2D_image " "EGL_KHR_gl_texture_3D_image " "EGL_KHR_gl_texture_cubemap_image " @@ -124,11 +114,14 @@ extern char const * const gExtensionString = "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 " ; // extensions not exposed to applications but used by the ANDROID system @@ -186,9 +179,9 @@ static const extention_map_t sExtensionMap[] = { { "eglSwapBuffersWithDamageKHR", (__eglMustCastToProperFunctionPointerType)&eglSwapBuffersWithDamageKHR }, - // EGL_ANDROID_native_client_buffer - { "eglCreateNativeClientBufferANDROID", - (__eglMustCastToProperFunctionPointerType)&eglCreateNativeClientBufferANDROID }, + // EGL_ANDROID_get_native_client_buffer + { "eglGetNativeClientBufferANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetNativeClientBufferANDROID }, // EGL_KHR_partial_update { "eglSetDamageRegionKHR", @@ -220,10 +213,20 @@ static const extention_map_t sExtensionMap[] = { (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR }, // EGL_ANDROID_get_frame_timestamps + { "eglGetNextFrameIdANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetNextFrameIdANDROID }, + { "eglGetCompositorTimingANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingANDROID }, + { "eglGetCompositorTimingSupportedANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingSupportedANDROID }, { "eglGetFrameTimestampsANDROID", (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampsANDROID }, - { "eglQueryTimestampSupportedANDROID", - (__eglMustCastToProperFunctionPointerType)&eglQueryTimestampSupportedANDROID }, + { "eglGetFrameTimestampSupportedANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampSupportedANDROID }, + + // EGL_ANDROID_native_fence_sync + { "eglDupNativeFenceFDANDROID", + (__eglMustCastToProperFunctionPointerType)&eglDupNativeFenceFDANDROID }, }; /* @@ -233,13 +236,13 @@ static const extention_map_t sExtensionMap[] = { #define FILTER_EXTENSIONS(procname) \ (!strcmp((procname), "eglSetBlobCacheFuncsANDROID") || \ !strcmp((procname), "eglHibernateProcessIMG") || \ - !strcmp((procname), "eglAwakenProcessIMG") || \ - !strcmp((procname), "eglDupNativeFenceFDANDROID")) + !strcmp((procname), "eglAwakenProcessIMG")) // accesses protected by sExtensionMapMutex -static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap; +static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtentionMap; + static int sGLExtentionSlot = 0; static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER; @@ -297,7 +300,7 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) clearError(); egl_display_ptr dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); EGLBoolean res = dp->initialize(major, minor); @@ -313,7 +316,7 @@ EGLBoolean eglTerminate(EGLDisplay dpy) clearError(); egl_display_ptr dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); EGLBoolean res = dp->terminate(); @@ -334,7 +337,7 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy, if (!dp) return EGL_FALSE; if (num_config==0) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); } EGLBoolean res = EGL_FALSE; @@ -359,7 +362,7 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, if (!dp) return EGL_FALSE; if (num_config==0) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); } EGLBoolean res = EGL_FALSE; @@ -391,6 +394,8 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, case EGL_CONFIG_CAVEAT: attribCaveat = &attrib_list[attribCount]; break; + default: + break; } attribCount++; } @@ -443,12 +448,6 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, // surfaces // ---------------------------------------------------------------------------- -// The EGL_KHR_gl_colorspace spec hasn't been ratified yet, so these haven't -// been added to the Khronos egl.h. -#define EGL_GL_COLORSPACE_KHR EGL_VG_COLORSPACE -#define EGL_GL_COLORSPACE_SRGB_KHR EGL_VG_COLORSPACE_sRGB -#define EGL_GL_COLORSPACE_LINEAR_KHR EGL_VG_COLORSPACE_LINEAR - // Turn linear formats into corresponding sRGB formats when colorspace is // EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear // formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where @@ -474,8 +473,18 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, if (dp) { EGLDisplay iDpy = dp->disp.dpy; + 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); + } + int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); - if (result != OK) { + if (result < 0) { ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) " "failed (%#x) (already connected to another API?)", window, result); @@ -488,26 +497,44 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, // modify the EGLconfig's format before setting the native window's // format. - // by default, just pick RGBA_8888 - EGLint format = HAL_PIXEL_FORMAT_RGBA_8888; - android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN; + EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; + cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, + &componentType); + EGLint format; + android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN; EGLint a = 0; + EGLint r, g, b; + r = g = b = 0; + cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE, &r); + cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g); + cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE, &b); cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a); - if (a > 0) { - // alpha-channel requested, there's really only one suitable format - format = HAL_PIXEL_FORMAT_RGBA_8888; - } else { - EGLint r, g, b; - r = g = b = 0; - cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE, &r); - cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g); - cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE, &b); - EGLint colorDepth = r + g + b; + EGLint colorDepth = r + g + b; + + if (a == 0) { if (colorDepth <= 16) { format = HAL_PIXEL_FORMAT_RGB_565; } else { - format = HAL_PIXEL_FORMAT_RGBX_8888; + 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; } } @@ -515,17 +542,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) { for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) { if (*attr == EGL_GL_COLORSPACE_KHR) { - if (ENABLE_EGL_KHR_GL_COLORSPACE) { - dataSpace = modifyBufferDataspace(dataSpace, *(attr+1)); - } else { - // Normally we'd pass through unhandled attributes to - // the driver. But in case the driver implements this - // extension but we're disabling it, we want to prevent - // it getting through -- support will be broken without - // our help. - ALOGE("sRGB window surfaces not supported"); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); - } + dataSpace = modifyBufferDataspace(dataSpace, *(attr+1)); } } } @@ -618,7 +635,7 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) SurfaceRef _s(dp.get(), surface); if (!_s.get()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); + 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); @@ -638,7 +655,7 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, SurfaceRef _s(dp.get(), surface); if (!_s.get()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); egl_surface_t const * const s = get_surface(surface); return s->cnx->egl.eglQuerySurface( @@ -657,7 +674,6 @@ void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { SurfaceRef _s(dp.get(), surface); if (!_s.get()) { setError(EGL_BAD_SURFACE, EGL_FALSE); - return; } } @@ -716,7 +732,7 @@ EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) ContextRef _c(dp.get(), ctx); if (!_c.get()) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); + 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); @@ -732,14 +748,14 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, clearError(); egl_display_ptr dp = validate_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE); + 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, EGL_FALSE); + if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE); } // get a reference to the object passed in @@ -750,7 +766,7 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, // 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, EGL_FALSE); + return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); } // these are the underlying implementation's object @@ -773,7 +789,7 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, // 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, EGL_FALSE); + return setError(EGL_BAD_MATCH, (EGLBoolean)EGL_FALSE); } if (cur_c == NULL) { // no current context @@ -784,14 +800,14 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, // retrieve the underlying implementation's draw EGLSurface if (draw != EGL_NO_SURFACE) { - if (!_d.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE); + 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, EGL_FALSE); + if (!_r.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); r = get_surface(read); impl_read = r->surface; } @@ -813,9 +829,41 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, egl_tls_t::setContext(EGL_NO_CONTEXT); } } else { + + if (cur_c != NULL) { + // Force return to current context for drivers that cannot handle errors + EGLBoolean restore_result = EGL_FALSE; + // get a reference to the old current objects + ContextRef _c2(dp.get(), cur_c); + SurfaceRef _d2(dp.get(), cur_c->draw); + SurfaceRef _r2(dp.get(), cur_c->read); + + c = cur_c; + impl_ctx = c->context; + impl_draw = EGL_NO_SURFACE; + if (cur_c->draw != EGL_NO_SURFACE) { + d = get_surface(cur_c->draw); + impl_draw = d->surface; + } + impl_read = EGL_NO_SURFACE; + if (cur_c->read != EGL_NO_SURFACE) { + r = get_surface(cur_c->read); + impl_read = r->surface; + } + restore_result = dp->makeCurrent(c, cur_c, + cur_c->draw, cur_c->read, cur_c->context, + impl_draw, impl_read, impl_ctx); + if (restore_result == EGL_TRUE) { + _c2.acquire(); + _r2.acquire(); + _d2.acquire(); + } else { + ALOGE("Could not restore original EGL context"); + } + } // this will ALOGE the error egl_connection_t* const cnx = &gEGLImpl; - result = setError(cnx->egl.eglGetError(), EGL_FALSE); + result = setError(cnx->egl.eglGetError(), (EGLBoolean)EGL_FALSE); } return result; } @@ -830,7 +878,7 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, if (!dp) return EGL_FALSE; ContextRef _c(dp.get(), ctx); - if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); + if (!_c.get()) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); egl_context_t * const c = get_context(ctx); return c->cnx->egl.eglQueryContext( @@ -891,7 +939,7 @@ EGLBoolean eglWaitGL(void) egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); + return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); return cnx->egl.eglWaitGL(); } @@ -902,7 +950,7 @@ EGLBoolean eglWaitNative(EGLint engine) egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); + return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); return cnx->egl.eglWaitNative(engine); } @@ -981,8 +1029,11 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) * */ - const String8 name(procname); - addr = sGLExtentionMap.valueFor(name); + 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, @@ -1004,7 +1055,7 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) if (found) { addr = gExtensionForwarders[slot]; - sGLExtentionMap.add(name, addr); + extentionMap[name] = addr; sGLExtentionSlot++; } } @@ -1013,45 +1064,57 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) return addr; } -class FrameCompletionThread : public Thread { +class FrameCompletionThread { public: static void queueSync(EGLSyncKHR sync) { - static sp<FrameCompletionThread> thread(new FrameCompletionThread); - static bool running = false; - if (!running) { - thread->run("GPUFrameCompletion"); - running = true; - } - { - Mutex::Autolock lock(thread->mMutex); - ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d", - thread->mFramesQueued).string()); - thread->mQueue.push_back(sync); - thread->mCondition.signal(); - thread->mFramesQueued++; - ATRACE_INT("GPU Frames Outstanding", thread->mQueue.size()); - } + static FrameCompletionThread thread; + + char name[64]; + + std::lock_guard<std::mutex> lock(thread.mMutex); + snprintf(name, sizeof(name), "kicked off frame %u", (unsigned int)thread.mFramesQueued); + ATRACE_NAME(name); + + thread.mQueue.push_back(sync); + thread.mCondition.notify_one(); + thread.mFramesQueued++; + ATRACE_INT("GPU Frames Outstanding", int32_t(thread.mQueue.size())); } private: - FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {} - virtual bool threadLoop() { + 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; { - Mutex::Autolock lock(mMutex); - while (mQueue.isEmpty()) { - mCondition.wait(mMutex); + std::unique_lock<std::mutex> lock(mMutex); + while (mQueue.empty()) { + mCondition.wait(lock); } sync = mQueue[0]; frameNum = mFramesCompleted; } EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); { - ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d", - frameNum).string()); + 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()); @@ -1061,19 +1124,18 @@ private: eglDestroySyncKHR(dpy, sync); } { - Mutex::Autolock lock(mMutex); - mQueue.removeAt(0); + std::lock_guard<std::mutex> lock(mMutex); + mQueue.pop_front(); mFramesCompleted++; - ATRACE_INT("GPU Frames Outstanding", mQueue.size()); + ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size())); } - return true; } uint32_t mFramesQueued; uint32_t mFramesCompleted; - Vector<EGLSyncKHR> mQueue; - Condition mCondition; - Mutex mMutex; + std::deque<EGLSyncKHR> mQueue; + std::condition_variable mCondition; + std::mutex mMutex; }; EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, @@ -1087,7 +1149,7 @@ EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, SurfaceRef _s(dp.get(), draw); if (!_s.get()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); egl_surface_t const * const s = get_surface(draw); @@ -1112,7 +1174,7 @@ EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); } - Vector<android_native_rect_t> androidRects; + std::vector<android_native_rect_t> androidRects((size_t)n_rects); for (int r = 0; r < n_rects; ++r) { int offset = r * 4; int x = rects[offset]; @@ -1126,8 +1188,7 @@ EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, androidRect.bottom = y; androidRects.push_back(androidRect); } - native_window_set_surface_damage(s->win.get(), androidRects.array(), - androidRects.size()); + 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, @@ -1152,7 +1213,7 @@ EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, SurfaceRef _s(dp.get(), surface); if (!_s.get()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); + 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); @@ -1162,6 +1223,16 @@ 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*)0); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return (const char *) NULL; @@ -1174,6 +1245,8 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) return dp->getExtensionString(); case EGL_CLIENT_APIS: return dp->getClientApiString(); + default: + break; } return setError(EGL_BAD_PARAMETER, (const char *)0); } @@ -1194,6 +1267,8 @@ EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint na return dp->disp.queryString.extensions; case EGL_CLIENT_APIS: return dp->disp.queryString.clientApi; + default: + break; } return setError(EGL_BAD_PARAMETER, (const char *)0); } @@ -1212,29 +1287,31 @@ EGLBoolean eglSurfaceAttrib( SurfaceRef _s(dp.get(), surface); if (!_s.get()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); egl_surface_t * const s = get_surface(surface); if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) { - int err = native_window_set_auto_refresh(s->win.get(), - value ? true : false); - return (err == NO_ERROR) ? EGL_TRUE : + 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 ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS if (attribute == EGL_TIMESTAMPS_ANDROID) { - s->enableTimestamps = value; - return EGL_TRUE; + 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); } -#endif if (s->cnx->egl.eglSurfaceAttrib) { return s->cnx->egl.eglSurfaceAttrib( dp->disp.dpy, s->surface, attribute, value); } - return setError(EGL_BAD_SURFACE, EGL_FALSE); + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } EGLBoolean eglBindTexImage( @@ -1247,14 +1324,14 @@ EGLBoolean eglBindTexImage( SurfaceRef _s(dp.get(), surface); if (!_s.get()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); + 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, EGL_FALSE); + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } EGLBoolean eglReleaseTexImage( @@ -1267,14 +1344,14 @@ EGLBoolean eglReleaseTexImage( SurfaceRef _s(dp.get(), surface); if (!_s.get()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); + 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, EGL_FALSE); + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) @@ -1304,7 +1381,7 @@ EGLBoolean eglWaitClient(void) egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); + return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); EGLBoolean res; if (cnx->egl.eglWaitClient) { @@ -1320,7 +1397,7 @@ EGLBoolean eglBindAPI(EGLenum api) clearError(); if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); } // bind this API on all EGLs @@ -1337,7 +1414,7 @@ EGLenum eglQueryAPI(void) clearError(); if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); } egl_connection_t* const cnx = &gEGLImpl; @@ -1353,13 +1430,14 @@ EGLBoolean eglReleaseThread(void) { clearError(); - // If there is context bound to the thread, release it - egl_display_t::loseCurrent(get_context(getContext())); - 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; } @@ -1394,14 +1472,14 @@ EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, SurfaceRef _s(dp.get(), surface); if (!_s.get()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); + 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, EGL_FALSE); + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) @@ -1413,13 +1491,13 @@ EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) SurfaceRef _s(dp.get(), surface); if (!_s.get()) - return setError(EGL_BAD_SURFACE, EGL_FALSE); + 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, EGL_FALSE); + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, @@ -1517,7 +1595,7 @@ EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; - EGLBoolean result = EGL_FALSE; + EGLint result = EGL_FALSE; egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) { result = cnx->egl.eglClientWaitSyncKHR( @@ -1801,149 +1879,15 @@ EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, } egl_surface_t const * const s = get_surface(surface); - native_window_set_buffers_timestamp(s->win.get(), time); + native_window_set_buffers_timestamp(s->getNativeWindow(), time); return EGL_TRUE; } -EGLClientBuffer eglCreateNativeClientBufferANDROID(const EGLint *attrib_list) -{ - clearError(); - - int usage = 0; - uint32_t width = 0; - uint32_t height = 0; - uint32_t format = 0; - uint32_t red_size = 0; - uint32_t green_size = 0; - uint32_t blue_size = 0; - uint32_t alpha_size = 0; - -#define GET_NONNEGATIVE_VALUE(case_name, target) \ - case case_name: \ - if (value >= 0) { \ - target = value; \ - } else { \ - return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); \ - } \ - break - - if (attrib_list) { - while (*attrib_list != EGL_NONE) { - GLint attr = *attrib_list++; - GLint value = *attrib_list++; - switch (attr) { - GET_NONNEGATIVE_VALUE(EGL_WIDTH, width); - GET_NONNEGATIVE_VALUE(EGL_HEIGHT, height); - GET_NONNEGATIVE_VALUE(EGL_RED_SIZE, red_size); - GET_NONNEGATIVE_VALUE(EGL_GREEN_SIZE, green_size); - GET_NONNEGATIVE_VALUE(EGL_BLUE_SIZE, blue_size); - GET_NONNEGATIVE_VALUE(EGL_ALPHA_SIZE, alpha_size); - case EGL_NATIVE_BUFFER_USAGE_ANDROID: - if (value & EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID) { - usage |= GRALLOC_USAGE_PROTECTED; - } - if (value & EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID) { - usage |= GRALLOC_USAGE_HW_RENDER; - } - if (value & EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID) { - usage |= GRALLOC_USAGE_HW_TEXTURE; - } - break; - default: - return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); - } - } - } -#undef GET_NONNEGATIVE_VALUE - - // Validate format. - if (red_size == 8 && green_size == 8 && blue_size == 8) { - if (alpha_size == 8) { - format = HAL_PIXEL_FORMAT_RGBA_8888; - } else { - format = HAL_PIXEL_FORMAT_RGB_888; - } - } else if (red_size == 5 && green_size == 6 && blue_size == 5 && - alpha_size == 0) { - format = HAL_PIXEL_FORMAT_RGB_565; - } else { - ALOGE("Invalid native pixel format { r=%d, g=%d, b=%d, a=%d }", - red_size, green_size, blue_size, alpha_size); - return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); - } - -#define CHECK_ERROR_CONDITION(message) \ - if (err != NO_ERROR) { \ - ALOGE(message); \ - goto error_condition; \ - } - - // The holder is used to destroy the buffer if an error occurs. - GraphicBuffer* gBuffer = new GraphicBuffer(); - sp<IServiceManager> sm = defaultServiceManager(); - sp<IBinder> surfaceFlinger = sm->getService(String16("SurfaceFlinger")); - sp<IBinder> allocator; - Parcel sc_data, sc_reply, data, reply; - status_t err = NO_ERROR; - if (sm == NULL) { - ALOGE("Unable to connect to ServiceManager"); - goto error_condition; - } - - // Obtain an allocator. - if (surfaceFlinger == NULL) { - ALOGE("Unable to connect to SurfaceFlinger"); - goto error_condition; - } - sc_data.writeInterfaceToken(String16("android.ui.ISurfaceComposer")); - err = surfaceFlinger->transact( - BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, sc_data, &sc_reply); - CHECK_ERROR_CONDITION("Unable to obtain allocator from SurfaceFlinger"); - allocator = sc_reply.readStrongBinder(); - - if (allocator == NULL) { - ALOGE("Unable to obtain an ISurfaceComposer"); - goto error_condition; - } - data.writeInterfaceToken(String16("android.ui.IGraphicBufferAlloc")); - err = data.writeUint32(width); - CHECK_ERROR_CONDITION("Unable to write width"); - err = data.writeUint32(height); - CHECK_ERROR_CONDITION("Unable to write height"); - err = data.writeInt32(static_cast<int32_t>(format)); - CHECK_ERROR_CONDITION("Unable to write format"); - err = data.writeUint32(usage); - CHECK_ERROR_CONDITION("Unable to write usage"); - err = data.writeUtf8AsUtf16( - std::string("[eglCreateNativeClientBufferANDROID pid ") + - std::to_string(getpid()) + ']'); - CHECK_ERROR_CONDITION("Unable to write requestor name"); - err = allocator->transact(IBinder::FIRST_CALL_TRANSACTION, data, - &reply); - CHECK_ERROR_CONDITION( - "Unable to request buffer allocation from surface composer"); - err = reply.readInt32(); - CHECK_ERROR_CONDITION("Unable to obtain buffer from surface composer"); - err = reply.read(*gBuffer); - CHECK_ERROR_CONDITION("Unable to read buffer from surface composer"); - - err = gBuffer->initCheck(); - if (err != NO_ERROR) { - ALOGE("Unable to create native buffer { w=%d, h=%d, f=%d, u=%#x }: %#x", - width, height, format, usage, err); - goto error_condition; - } - ALOGD("Created new native buffer %p { w=%d, h=%d, f=%d, u=%#x }", - gBuffer, width, height, format, usage); - return static_cast<EGLClientBuffer>(gBuffer->getNativeBuffer()); - -#undef CHECK_ERROR_CONDITION - -error_condition: - // Delete the buffer. - sp<GraphicBuffer> holder(gBuffer); - return setError(EGL_BAD_ALLOC, (EGLClientBuffer)0); +EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) { + clearError(); + if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); + return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer)); } // ---------------------------------------------------------------------------- @@ -1954,7 +1898,7 @@ EGLuint64NV eglGetSystemTimeFrequencyNV() clearError(); if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); + return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); } EGLuint64NV ret = 0; @@ -1964,7 +1908,7 @@ EGLuint64NV eglGetSystemTimeFrequencyNV() return cnx->egl.eglGetSystemTimeFrequencyNV(); } - return setErrorQuiet(EGL_BAD_DISPLAY, 0); + return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); } EGLuint64NV eglGetSystemTimeNV() @@ -1972,7 +1916,7 @@ EGLuint64NV eglGetSystemTimeNV() clearError(); if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); + return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); } EGLuint64NV ret = 0; @@ -1982,7 +1926,7 @@ EGLuint64NV eglGetSystemTimeNV() return cnx->egl.eglGetSystemTimeNV(); } - return setErrorQuiet(EGL_BAD_DISPLAY, 0); + return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); } // ---------------------------------------------------------------------------- @@ -2014,103 +1958,258 @@ EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, 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, - EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, + EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) { - setError(EGL_BAD_DISPLAY, EGL_FALSE); - return EGL_FALSE; + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } SurfaceRef _s(dp.get(), surface); if (!_s.get()) { - setError(EGL_BAD_SURFACE, EGL_FALSE); - return EGL_FALSE; + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } egl_surface_t const * const s = get_surface(surface); - if (!s->enableTimestamps) { - setError(EGL_BAD_SURFACE, EGL_FALSE); - return EGL_FALSE; + if (!s->getNativeWindow()) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } - nsecs_t* postedTime = nullptr; + nsecs_t* requestedPresentTime = nullptr; nsecs_t* acquireTime = nullptr; - nsecs_t* refreshStartTime = nullptr; - nsecs_t* GLCompositionDoneTime = nullptr; - nsecs_t* displayRetireTime = 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_QUEUE_TIME_ANDROID: - postedTime = &values[i]; + case EGL_REQUESTED_PRESENT_TIME_ANDROID: + requestedPresentTime = &values[i]; break; case EGL_RENDERING_COMPLETE_TIME_ANDROID: acquireTime = &values[i]; break; - case EGL_COMPOSITION_START_TIME_ANDROID: - refreshStartTime = &values[i]; + 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_COMPOSITION_FINISHED_TIME_ANDROID: - GLCompositionDoneTime = &values[i]; + case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID: + gpuCompositionDoneTime = &values[i]; break; - case EGL_DISPLAY_RETIRE_TIME_ANDROID: - displayRetireTime = &values[i]; + 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: - setError(EGL_BAD_PARAMETER, EGL_FALSE); - return EGL_FALSE; + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); } } - status_t ret = native_window_get_frame_timestamps(s->win.get(), framesAgo, - postedTime, acquireTime, refreshStartTime, GLCompositionDoneTime, - displayRetireTime, releaseTime); + int ret = native_window_get_frame_timestamps(s->getNativeWindow(), frameId, + requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime, + lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime, + dequeueReadyTime, releaseTime); - if (ret != NO_ERROR) { - setError(EGL_BAD_ACCESS, EGL_FALSE); - return EGL_FALSE; + 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); } - - return EGL_TRUE; } -EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, - EGLint timestamp) +EGLBoolean eglGetFrameTimestampSupportedANDROID( + EGLDisplay dpy, EGLSurface surface, EGLint timestamp) { clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) { - setError(EGL_BAD_DISPLAY, EGL_FALSE); - return EGL_FALSE; + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } SurfaceRef _s(dp.get(), surface); if (!_s.get()) { - setError(EGL_BAD_SURFACE, EGL_FALSE); - return EGL_FALSE; + 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) { -#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS - case EGL_QUEUE_TIME_ANDROID: + 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_START_TIME_ANDROID: - case EGL_COMPOSITION_FINISHED_TIME_ANDROID: - case EGL_DISPLAY_RETIRE_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; -#endif + 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_cache.cpp b/opengl/libs/EGL/egl_cache.cpp index 8c135c81eb..dc1a4af46e 100644 --- a/opengl/libs/EGL/egl_cache.cpp +++ b/opengl/libs/EGL/egl_cache.cpp @@ -14,35 +14,27 @@ ** limitations under the License. */ +#include "egl_cache.h" + #include "../egl_impl.h" -#include "egl_cache.h" #include "egl_display.h" -#include "egldefs.h" -#include <fcntl.h> + +#include <private/EGL/cache.h> + #include <inttypes.h> #include <sys/mman.h> #include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#ifndef MAX_EGL_CACHE_ENTRY_SIZE -#define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024); -#endif -#ifndef MAX_EGL_CACHE_KEY_SIZE -#define MAX_EGL_CACHE_KEY_SIZE (1024); -#endif +#include <thread> -#ifndef MAX_EGL_CACHE_SIZE -#define MAX_EGL_CACHE_SIZE (64 * 1024); -#endif +#include <log/log.h> // Cache size limits. -static const size_t maxKeySize = MAX_EGL_CACHE_KEY_SIZE; -static const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE; -static const size_t maxTotalSize = MAX_EGL_CACHE_SIZE; +static const size_t maxKeySize = 12 * 1024; +static const size_t maxValueSize = 64 * 1024; +static const size_t maxTotalSize = 2 * 1024 * 1024; // Cache file header static const char* cacheFileMagic = "EGL$"; @@ -57,6 +49,11 @@ namespace android { #define BC_EXT_STR "EGL_ANDROID_blob_cache" +// called from android_view_ThreadedRenderer.cpp +void egl_set_cache_filename(const char* filename) { + egl_cache_t::get()->setCacheFilename(filename); +} + // // Callback functions passed to EGL. // @@ -74,8 +71,7 @@ static EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize, // egl_cache_t definition // egl_cache_t::egl_cache_t() : - mInitialized(false), - mBlobCache(NULL) { + mInitialized(false) { } egl_cache_t::~egl_cache_t() { @@ -88,7 +84,7 @@ egl_cache_t* egl_cache_t::get() { } void egl_cache_t::initialize(egl_display_t *display) { - Mutex::Autolock lock(mMutex); + std::lock_guard<std::mutex> lock(mMutex); egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { @@ -99,7 +95,7 @@ void egl_cache_t::initialize(egl_display_t *display) { bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); bool atEnd = (bcExtLen+1) < extsLen && !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); - bool inMiddle = strstr(exts, " " BC_EXT_STR " "); + bool inMiddle = strstr(exts, " " BC_EXT_STR " ") != nullptr; if (equal || atStart || atEnd || inMiddle) { PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; eglSetBlobCacheFuncsANDROID = @@ -126,14 +122,14 @@ void egl_cache_t::initialize(egl_display_t *display) { } void egl_cache_t::terminate() { - Mutex::Autolock lock(mMutex); + std::lock_guard<std::mutex> lock(mMutex); saveBlobCacheLocked(); mBlobCache = NULL; } void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize, const void* value, EGLsizeiANDROID valueSize) { - Mutex::Autolock lock(mMutex); + std::lock_guard<std::mutex> lock(mMutex); if (keySize < 0 || valueSize < 0) { ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); @@ -141,38 +137,27 @@ void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize, } if (mInitialized) { - sp<BlobCache> bc = getBlobCacheLocked(); + BlobCache* bc = getBlobCacheLocked(); bc->set(key, keySize, value, valueSize); if (!mSavePending) { - class DeferredSaveThread : public Thread { - public: - DeferredSaveThread() : Thread(false) {} - - virtual bool threadLoop() { - sleep(deferredSaveDelay); - egl_cache_t* c = egl_cache_t::get(); - Mutex::Autolock lock(c->mMutex); - if (c->mInitialized) { - c->saveBlobCacheLocked(); - } - c->mSavePending = false; - return false; - } - }; - - // The thread will hold a strong ref to itself until it has finished - // running, so there's no need to keep a ref around. - sp<Thread> deferredSaveThread(new DeferredSaveThread()); mSavePending = true; - deferredSaveThread->run("DeferredSaveThread"); + std::thread deferredSaveThread([this]() { + sleep(deferredSaveDelay); + std::lock_guard<std::mutex> lock(mMutex); + if (mInitialized) { + saveBlobCacheLocked(); + } + mSavePending = false; + }); + deferredSaveThread.detach(); } } } EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize, void* value, EGLsizeiANDROID valueSize) { - Mutex::Autolock lock(mMutex); + std::lock_guard<std::mutex> lock(mMutex); if (keySize < 0 || valueSize < 0) { ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); @@ -180,23 +165,23 @@ EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize, } if (mInitialized) { - sp<BlobCache> bc = getBlobCacheLocked(); + BlobCache* bc = getBlobCacheLocked(); return bc->get(key, keySize, value, valueSize); } return 0; } void egl_cache_t::setCacheFilename(const char* filename) { - Mutex::Autolock lock(mMutex); + std::lock_guard<std::mutex> lock(mMutex); mFilename = filename; } -sp<BlobCache> egl_cache_t::getBlobCacheLocked() { - if (mBlobCache == NULL) { - mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize); +BlobCache* egl_cache_t::getBlobCacheLocked() { + if (mBlobCache == nullptr) { + mBlobCache.reset(new BlobCache(maxKeySize, maxValueSize, maxTotalSize)); loadBlobCacheLocked(); } - return mBlobCache; + return mBlobCache.get(); } static uint32_t crc32c(const uint8_t* buf, size_t len) { @@ -219,7 +204,7 @@ void egl_cache_t::saveBlobCacheLocked() { if (mFilename.length() > 0 && mBlobCache != NULL) { size_t cacheSize = mBlobCache->getFlattenedSize(); size_t headerSize = cacheFileHeaderSize; - const char* fname = mFilename.string(); + const char* fname = mFilename.c_str(); // Try to create the file with no permissions so we can write it // without anyone trying to read it. @@ -254,8 +239,8 @@ void egl_cache_t::saveBlobCacheLocked() { return; } - status_t err = mBlobCache->flatten(buf + headerSize, cacheSize); - if (err != OK) { + int err = mBlobCache->flatten(buf + headerSize, cacheSize); + if (err < 0) { ALOGE("error writing cache contents: %s (%d)", strerror(-err), -err); delete [] buf; @@ -288,10 +273,10 @@ void egl_cache_t::loadBlobCacheLocked() { if (mFilename.length() > 0) { size_t headerSize = cacheFileHeaderSize; - int fd = open(mFilename.string(), O_RDONLY, 0); + int fd = open(mFilename.c_str(), O_RDONLY, 0); if (fd == -1) { if (errno != ENOENT) { - ALOGE("error opening cache file %s: %s (%d)", mFilename.string(), + ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(), strerror(errno), errno); } return; @@ -336,8 +321,8 @@ void egl_cache_t::loadBlobCacheLocked() { return; } - status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize); - if (err != OK) { + int err = mBlobCache->unflatten(buf + headerSize, cacheSize); + if (err < 0) { ALOGE("error reading cache contents: %s (%d)", strerror(-err), -err); munmap(buf, fileSize); diff --git a/opengl/libs/EGL/egl_cache.h b/opengl/libs/EGL/egl_cache.h index 876000951c..56360f0bc8 100644 --- a/opengl/libs/EGL/egl_cache.h +++ b/opengl/libs/EGL/egl_cache.h @@ -20,9 +20,11 @@ #include <EGL/egl.h> #include <EGL/eglext.h> -#include <utils/BlobCache.h> -#include <utils/String8.h> -#include <utils/StrongPointer.h> +#include "BlobCache.h" + +#include <memory> +#include <mutex> +#include <string> // ---------------------------------------------------------------------------- namespace android { @@ -78,7 +80,7 @@ private: // key/value blob pairs. If the BlobCache object has not yet been created, // this will do so, loading the serialized cache contents from disk if // possible. - sp<BlobCache> getBlobCacheLocked(); + BlobCache* getBlobCacheLocked(); // saveBlobCache attempts to save the current contents of mBlobCache to // disk. @@ -99,14 +101,14 @@ private: // mBlobCache is the cache in which the key/value blob pairs are stored. It // is initially NULL, and will be initialized by getBlobCacheLocked the // first time it's needed. - sp<BlobCache> mBlobCache; + std::unique_ptr<BlobCache> mBlobCache; // mFilename is the name of the file for storing cache contents in between // program invocations. It is initialized to an empty string at // construction time, and can be set with the setCacheFilename method. An // empty string indicates that the cache should not be saved to or restored // from disk. - String8 mFilename; + std::string mFilename; // mSavePending indicates whether or not a deferred save operation is // pending. Each time a key/value pair is inserted into the cache via @@ -117,7 +119,7 @@ private: // mMutex is the mutex used to prevent concurrent access to the member // variables. It must be locked whenever the member variables are accessed. - mutable Mutex mMutex; + mutable std::mutex mMutex; // sCache is the singleton egl_cache_t object. static egl_cache_t sCache; diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index acd70d19b4..b696920023 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -17,17 +17,18 @@ #define __STDC_LIMIT_MACROS 1 #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <string.h> +#include "egl_display.h" #include "../egl_impl.h" +#include <private/EGL/display.h> + #include "egl_cache.h" -#include "egl_display.h" #include "egl_object.h" #include "egl_tls.h" +#include "egl_trace.h" #include "Loader.h" #include <cutils/properties.h> -#include <utils/Trace.h> // ---------------------------------------------------------------------------- namespace android { @@ -55,6 +56,11 @@ static bool findExtension(const char* exts, const char* name, size_t nameLen) { return false; } +int egl_get_init_count(EGLDisplay dpy) { + egl_display_t* eglDisplay = egl_display_t::get(dpy); + return eglDisplay ? eglDisplay->getRefsCount() : 0; +} + egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS]; egl_display_t::egl_display_t() : @@ -75,18 +81,18 @@ egl_display_t* egl_display_t::get(EGLDisplay dpy) { } void egl_display_t::addObject(egl_object_t* object) { - Mutex::Autolock _l(lock); - objects.add(object); + std::lock_guard<std::mutex> _l(lock); + objects.insert(object); } void egl_display_t::removeObject(egl_object_t* object) { - Mutex::Autolock _l(lock); - objects.remove(object); + std::lock_guard<std::mutex> _l(lock); + objects.erase(object); } bool egl_display_t::getObject(egl_object_t* object) const { - Mutex::Autolock _l(lock); - if (objects.indexOf(object) >= 0) { + std::lock_guard<std::mutex> _l(lock); + if (objects.find(object) != objects.end()) { if (object->getDisplay() == this) { object->incRef(); return true; @@ -104,7 +110,7 @@ EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) { EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) { - Mutex::Autolock _l(lock); + std::lock_guard<std::mutex> _l(lock); ATRACE_CALL(); // get our driver loader @@ -125,24 +131,26 @@ EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) { EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { - { - Mutex::Autolock _rf(refLock); - + { // scope for refLock + std::unique_lock<std::mutex> _l(refLock); refs++; if (refs > 1) { if (major != NULL) *major = VERSION_MAJOR; if (minor != NULL) *minor = VERSION_MINOR; - while(!eglIsInitialized) refCond.wait(refLock); + while(!eglIsInitialized) { + refCond.wait(_l); + } return EGL_TRUE; } - - while(eglIsInitialized) refCond.wait(refLock); + while(eglIsInitialized) { + refCond.wait(_l); + } } - { - Mutex::Autolock _l(lock); + { // scope for lock + std::lock_guard<std::mutex> _l(lock); setGLHooksThreadSpecific(&gHooksNoContext); @@ -179,20 +187,19 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { } // the query strings are per-display - mVendorString.setTo(sVendorString); - mVersionString.setTo(sVersionString); - mClientApiString.setTo(sClientApiString); + mVendorString = sVendorString; + mVersionString = sVersionString; + mClientApiString = sClientApiString; - mExtensionString.setTo(gBuiltinExtensionString); + mExtensionString = gBuiltinExtensionString; char const* start = gExtensionString; do { // length of the extension name size_t len = strcspn(start, " "); if (len) { // NOTE: we could avoid the copy if we had strnstr. - const String8 ext(start, len); - if (findExtension(disp.queryString.extensions, ext.string(), - len)) { + const std::string ext(start, len); + if (findExtension(disp.queryString.extensions, ext.c_str(), len)) { mExtensionString.append(ext + " "); } // advance to the next extension name, skipping the space. @@ -218,14 +225,12 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { *major = VERSION_MAJOR; if (minor != NULL) *minor = VERSION_MINOR; - - mHibernation.setDisplayValid(true); } - { - Mutex::Autolock _rf(refLock); + { // scope for refLock + std::unique_lock<std::mutex> _l(refLock); eglIsInitialized = true; - refCond.broadcast(); + refCond.notify_all(); } return EGL_TRUE; @@ -233,8 +238,8 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { EGLBoolean egl_display_t::terminate() { - { - Mutex::Autolock _rl(refLock); + { // scope for refLock + std::unique_lock<std::mutex> _rl(refLock); if (refs == 0) { /* * From the EGL spec (3.2): @@ -254,8 +259,8 @@ EGLBoolean egl_display_t::terminate() { EGLBoolean res = EGL_FALSE; - { - Mutex::Autolock _l(lock); + { // scope for lock + std::lock_guard<std::mutex> _l(lock); egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && disp.state == egl_display_t::INITIALIZED) { @@ -268,19 +273,16 @@ EGLBoolean egl_display_t::terminate() { res = EGL_TRUE; } - mHibernation.setDisplayValid(false); - // Reset the extension string since it will be regenerated if we get // reinitialized. - mExtensionString.setTo(""); + mExtensionString.clear(); // Mark all objects remaining in the list as terminated, unless // there are no reference to them, it which case, we're free to // delete them. size_t count = objects.size(); ALOGW_IF(count, "eglTerminate() called w/ %zu objects remaining", count); - for (size_t i=0 ; i<count ; i++) { - egl_object_t* o = objects.itemAt(i); + for (auto o : objects) { o->destroy(); } @@ -288,10 +290,10 @@ EGLBoolean egl_display_t::terminate() { objects.clear(); } - { - Mutex::Autolock _rl(refLock); + { // scope for refLock + std::unique_lock<std::mutex> _rl(refLock); eglIsInitialized = false; - refCond.broadcast(); + refCond.notify_all(); } return res; @@ -316,7 +318,7 @@ void egl_display_t::loseCurrentImpl(egl_context_t * cur_c) SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL); { // scope for the lock - Mutex::Autolock _l(lock); + std::lock_guard<std::mutex> _l(lock); cur_c->onLooseCurrent(); } @@ -342,22 +344,18 @@ EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c, SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL); { // scope for the lock - Mutex::Autolock _l(lock); + std::lock_guard<std::mutex> _l(lock); if (c) { result = c->cnx->egl.eglMakeCurrent( disp.dpy, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { c->onMakeCurrent(draw, read); - if (!cur_c) { - mHibernation.incWakeCount(HibernationMachine::STRONG); - } } } else { result = cur_c->cnx->egl.eglMakeCurrent( disp.dpy, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { cur_c->onLooseCurrent(); - mHibernation.decWakeCount(HibernationMachine::STRONG); } } } @@ -378,65 +376,7 @@ bool egl_display_t::haveExtension(const char* name, size_t nameLen) const { if (!nameLen) { nameLen = strlen(name); } - return findExtension(mExtensionString.string(), name, nameLen); -} - -// ---------------------------------------------------------------------------- - -bool egl_display_t::HibernationMachine::incWakeCount(WakeRefStrength strength) { - Mutex::Autolock _l(mLock); - ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX, - "Invalid WakeCount (%d) on enter\n", mWakeCount); - - mWakeCount++; - if (strength == STRONG) - mAttemptHibernation = false; - - if (CC_UNLIKELY(mHibernating)) { - ALOGV("Awakening\n"); - egl_connection_t* const cnx = &gEGLImpl; - - // These conditions should be guaranteed before entering hibernation; - // we don't want to get into a state where we can't wake up. - ALOGD_IF(!mDpyValid || !cnx->egl.eglAwakenProcessIMG, - "Invalid hibernation state, unable to awaken\n"); - - if (!cnx->egl.eglAwakenProcessIMG()) { - ALOGE("Failed to awaken EGL implementation\n"); - return false; - } - mHibernating = false; - } - return true; -} - -void egl_display_t::HibernationMachine::decWakeCount(WakeRefStrength strength) { - Mutex::Autolock _l(mLock); - ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount); - - mWakeCount--; - if (strength == STRONG) - mAttemptHibernation = true; - - if (mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) { - egl_connection_t* const cnx = &gEGLImpl; - mAttemptHibernation = false; - if (mAllowHibernation && mDpyValid && - cnx->egl.eglHibernateProcessIMG && - cnx->egl.eglAwakenProcessIMG) { - ALOGV("Hibernating\n"); - if (!cnx->egl.eglHibernateProcessIMG()) { - ALOGE("Failed to hibernate EGL implementation\n"); - return; - } - mHibernating = true; - } - } -} - -void egl_display_t::HibernationMachine::setDisplayValid(bool valid) { - Mutex::Autolock _l(mLock); - mDpyValid = valid; + return findExtension(mExtensionString.c_str(), name, nameLen); } // ---------------------------------------------------------------------------- diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h index 2d862951c1..661f47e2f3 100644 --- a/opengl/libs/EGL/egl_display.h +++ b/opengl/libs/EGL/egl_display.h @@ -18,17 +18,18 @@ #define ANDROID_EGL_DISPLAY_H -#include <ctype.h> #include <stdint.h> -#include <stdlib.h> +#include <stddef.h> + +#include <condition_variable> +#include <mutex> +#include <string> +#include <unordered_set> #include <EGL/egl.h> #include <EGL/eglext.h> #include <cutils/compiler.h> -#include <utils/SortedVector.h> -#include <utils/threads.h> -#include <utils/String8.h> #include "egldefs.h" #include "../hooks.h" @@ -68,20 +69,6 @@ public: // add reference to this object. returns true if this is a valid object. bool getObject(egl_object_t* object) const; - // These notifications allow the display to keep track of how many window - // surfaces exist, which it uses to decide whether to hibernate the - // underlying EGL implementation. They can be called by any thread without - // holding a lock, but must be called via egl_display_ptr to ensure - // proper hibernate/wakeup sequencing. If a surface destruction triggers - // hibernation, hibernation will be delayed at least until the calling - // thread's egl_display_ptr is destroyed. - void onWindowSurfaceCreated() { - mHibernation.incWakeCount(HibernationMachine::STRONG); - } - void onWindowSurfaceDestroyed() { - mHibernation.decWakeCount(HibernationMachine::STRONG); - } - static egl_display_t* get(EGLDisplay dpy); static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp); @@ -94,10 +81,10 @@ public: inline bool isValid() const { return magic == '_dpy'; } inline bool isAlive() const { return isValid(); } - char const * getVendorString() const { return mVendorString.string(); } - char const * getVersionString() const { return mVersionString.string(); } - char const * getClientApiString() const { return mClientApiString.string(); } - char const * getExtensionString() const { return mExtensionString.string(); } + char const * getVendorString() const { return mVendorString.c_str(); } + char const * getVersionString() const { return mVersionString.c_str(); } + char const * getClientApiString() const { return mClientApiString.c_str(); } + char const * getExtensionString() const { return mExtensionString.c_str(); } bool haveExtension(const char* name, size_t nameLen = 0) const; @@ -127,59 +114,17 @@ public: private: friend class egl_display_ptr; - bool enter() { return mHibernation.incWakeCount(HibernationMachine::WEAK); } - void leave() { return mHibernation.decWakeCount(HibernationMachine::WEAK); } uint32_t refs; bool eglIsInitialized; - mutable Mutex lock, refLock; - mutable Condition refCond; - SortedVector<egl_object_t*> objects; - String8 mVendorString; - String8 mVersionString; - String8 mClientApiString; - String8 mExtensionString; - - // HibernationMachine uses its own internal mutex to protect its own data. - // The owning egl_display_t's lock may be but is not required to be held - // when calling HibernationMachine methods. As a result, nothing in this - // class may call back up to egl_display_t directly or indirectly. - class HibernationMachine { - public: - // STRONG refs cancel (inc) or initiate (dec) a hibernation attempt - // the next time the wakecount reaches zero. WEAK refs don't affect - // whether a hibernation attempt will be made. Use STRONG refs only - // for infrequent/heavy changes that are likely to indicate the - // EGLDisplay is entering or leaving a long-term idle state. - enum WakeRefStrength { - WEAK = 0, - STRONG = 1, - }; - - HibernationMachine(): mWakeCount(0), mHibernating(false), - mAttemptHibernation(false), mDpyValid(false), -#if BOARD_ALLOW_EGL_HIBERNATION - mAllowHibernation(true) -#else - mAllowHibernation(false) -#endif - {} - ~HibernationMachine() {} - - bool incWakeCount(WakeRefStrength strenth); - void decWakeCount(WakeRefStrength strenth); - - void setDisplayValid(bool valid); - - private: - Mutex mLock; - int32_t mWakeCount; - bool mHibernating; - bool mAttemptHibernation; - bool mDpyValid; - const bool mAllowHibernation; - }; - HibernationMachine mHibernation; + mutable std::mutex lock; + mutable std::mutex refLock; + mutable std::condition_variable refCond; + std::unordered_set<egl_object_t*> objects; + std::string mVendorString; + std::string mVersionString; + std::string mClientApiString; + std::string mExtensionString; }; // ---------------------------------------------------------------------------- @@ -190,13 +135,7 @@ private: // as the egl_display_ptr exists. class egl_display_ptr { public: - explicit egl_display_ptr(egl_display_t* dpy): mDpy(dpy) { - if (mDpy) { - if (CC_UNLIKELY(!mDpy->enter())) { - mDpy = NULL; - } - } - } + explicit egl_display_ptr(egl_display_t* dpy): mDpy(dpy) {} // We only really need a C++11 move constructor, not a copy constructor. // A move constructor would save an enter()/leave() pair on every EGL API @@ -208,17 +147,9 @@ public: // other.mDpy = NULL; // } // - egl_display_ptr(const egl_display_ptr& other): mDpy(other.mDpy) { - if (mDpy) { - mDpy->enter(); - } - } - - ~egl_display_ptr() { - if (mDpy) { - mDpy->leave(); - } - } + egl_display_ptr(const egl_display_ptr& other): mDpy(other.mDpy) {} + + ~egl_display_ptr() {} const egl_display_t* operator->() const { return mDpy; } egl_display_t* operator->() { return mDpy; } diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in index 2b567187ba..b587a16203 100644 --- a/opengl/libs/EGL/egl_entries.in +++ b/opengl/libs/EGL/egl_entries.in @@ -81,6 +81,7 @@ EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint EGL_ENTRY(EGLClientBuffer, eglGetRenderBufferANDROID, EGLDisplay, EGLSurface) EGL_ENTRY(EGLint, eglDupNativeFenceFDANDROID, EGLDisplay, EGLSyncKHR) EGL_ENTRY(EGLClientBuffer, eglCreateNativeClientBufferANDROID, const EGLint *) +EGL_ENTRY(EGLClientBuffer, eglGetNativeClientBufferANDROID, const AHardwareBuffer *) /* NVIDIA extensions */ diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index cfecf77021..623878062b 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -14,19 +14,10 @@ ** limitations under the License. */ -#include <string> -#include <sstream> - -#include <ctype.h> -#include <stdint.h> -#include <stdlib.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> +#include "egl_object.h" -#include <utils/threads.h> +#include <sstream> -#include "egl_object.h" // ---------------------------------------------------------------------------- namespace android { @@ -68,27 +59,25 @@ egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win, EGLSurface surface, egl_connection_t const* cnx) : egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx), - enableTimestamps(false), connected(true) + connected(true) { if (win) { - getDisplay()->onWindowSurfaceCreated(); + win->incStrong(this); } } egl_surface_t::~egl_surface_t() { - ANativeWindow* const window = win.get(); - if (window != NULL) { + if (win != NULL) { disconnect(); - getDisplay()->onWindowSurfaceDestroyed(); + win->decStrong(this); } } void egl_surface_t::disconnect() { - ANativeWindow* const window = win.get(); - if (window != NULL && connected) { - native_window_set_buffers_format(window, 0); - if (native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL)) { - ALOGW("EGLNativeWindowType %p disconnect failed", window); + if (win != NULL && connected) { + native_window_set_buffers_format(win, 0); + if (native_window_api_disconnect(win, NATIVE_WINDOW_API_EGL)) { + ALOGW("EGLNativeWindowType %p disconnect failed", win); } connected = false; } @@ -121,22 +110,20 @@ void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) { * add the extensions always handled by the wrapper */ - if (gl_extensions.isEmpty()) { + if (gl_extensions.empty()) { // call the implementation's glGetString(GL_EXTENSIONS) const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS); - gl_extensions.setTo(exts); - if (gl_extensions.find("GL_EXT_debug_marker") < 0) { - String8 temp("GL_EXT_debug_marker "); - temp.append(gl_extensions); - gl_extensions.setTo(temp); + gl_extensions = exts; + if (gl_extensions.find("GL_EXT_debug_marker") == std::string::npos) { + gl_extensions.insert(0, "GL_EXT_debug_marker "); } // tokenize the supported extensions for the glGetStringi() wrapper std::stringstream ss; std::string str; - ss << gl_extensions.string(); + ss << gl_extensions; while (ss >> str) { - tokenized_gl_extensions.push(String8(str.c_str())); + tokenized_gl_extensions.push_back(str); } } } diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h index 97eda4ce79..8988905a25 100644 --- a/opengl/libs/EGL/egl_object.h +++ b/opengl/libs/EGL/egl_object.h @@ -18,19 +18,19 @@ #define ANDROID_EGL_OBJECT_H #include <atomic> -#include <ctype.h> #include <stdint.h> -#include <stdlib.h> +#include <stddef.h> + +#include <string> +#include <vector> #include <EGL/egl.h> #include <EGL/eglext.h> -#include <utils/threads.h> -#include <utils/String8.h> -#include <utils/Vector.h> - #include <system/window.h> +#include <log/log.h> + #include "egl_display.h" // ---------------------------------------------------------------------------- @@ -48,7 +48,7 @@ protected: virtual void terminate(); public: - egl_object_t(egl_display_t* display); + explicit egl_object_t(egl_display_t* display); void destroy(); inline void incRef() { count.fetch_add(1, std::memory_order_relaxed); } @@ -62,8 +62,8 @@ public: template <typename N, typename T> class LocalRef { egl_object_t* ref; - LocalRef(); - LocalRef(const LocalRef* rhs); + LocalRef() = delete; + LocalRef(const LocalRef* rhs) = delete; public: ~LocalRef(); explicit LocalRef(egl_object_t* rhs); @@ -135,11 +135,17 @@ public: EGLNativeWindowType win, EGLSurface surface, egl_connection_t const* cnx); + ANativeWindow* getNativeWindow() { return win; } + ANativeWindow* getNativeWindow() const { return win; } + + // Try to keep the order of these fields and size unchanged. It's not public API, but + // it's not hard to imagine native games accessing them. EGLSurface surface; EGLConfig config; - sp<ANativeWindow> win; +private: + ANativeWindow* win; +public: egl_connection_t const* cnx; - bool enableTimestamps; private: bool connected; void disconnect(); @@ -164,8 +170,8 @@ public: EGLSurface draw; egl_connection_t const* cnx; int version; - String8 gl_extensions; - Vector<String8> tokenized_gl_extensions; + std::string gl_extensions; + std::vector<std::string> tokenized_gl_extensions; }; // ---------------------------------------------------------------------------- diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp index f3739aafad..8508c5fe9d 100644 --- a/opengl/libs/EGL/egl_tls.cpp +++ b/opengl/libs/EGL/egl_tls.cpp @@ -14,18 +14,13 @@ ** limitations under the License. */ +#include "egl_tls.h" + #include <stdlib.h> -#include <pthread.h> -#include <cutils/log.h> #include <cutils/properties.h> - -#include <utils/CallStack.h> - -#include <EGL/egl.h> - -#include "egl_tls.h" - +#include <log/log.h> +#include "CallStack.h" namespace android { @@ -33,7 +28,7 @@ pthread_key_t egl_tls_t::sKey = TLS_KEY_NOT_INITIALIZED; pthread_once_t egl_tls_t::sOnceKey = PTHREAD_ONCE_INIT; egl_tls_t::egl_tls_t() - : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { + : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(true) { } const char *egl_tls_t::egl_strerror(EGLint err) { @@ -78,7 +73,7 @@ void egl_tls_t::setErrorEtcImpl( char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.callstack", value, "0"); if (atoi(value)) { - CallStack stack(LOG_TAG); + CallStack::log(LOG_TAG); } } tls->error = error; @@ -87,11 +82,12 @@ void egl_tls_t::setErrorEtcImpl( bool egl_tls_t::logNoContextCall() { egl_tls_t* tls = getTLS(); - if (tls->logCallWithNoContext == true) { + if (tls->logCallWithNoContext) { tls->logCallWithNoContext = false; return true; } return false; + } egl_tls_t* egl_tls_t::getTLS() { diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h index 00eae0bdc6..9feae681bd 100644 --- a/opengl/libs/EGL/egl_tls.h +++ b/opengl/libs/EGL/egl_tls.h @@ -17,11 +17,9 @@ #ifndef ANDROID_EGL_TLS_H #define ANDROID_EGL_TLS_H -#include <pthread.h> - #include <EGL/egl.h> -#include "egldefs.h" +#include <pthread.h> // ---------------------------------------------------------------------------- namespace android { @@ -36,7 +34,7 @@ class egl_tls_t { EGLint error; EGLContext ctx; - EGLBoolean logCallWithNoContext; + bool logCallWithNoContext; egl_tls_t(); static void validateTLSKey(); diff --git a/opengl/libs/EGL/egl_trace.h b/opengl/libs/EGL/egl_trace.h new file mode 100644 index 0000000000..7664de2231 --- /dev/null +++ b/opengl/libs/EGL/egl_trace.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 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. + */ + +#pragma once + +#if defined(__ANDROID__) + +#include <stdint.h> + +#include <cutils/trace.h> + +// See <cutils/trace.h> for more ATRACE_* macros. + +// ATRACE_NAME traces from its location until the end of its enclosing scope. +#define _PASTE(x, y) x ## y +#define PASTE(x, y) _PASTE(x,y) +#define ATRACE_NAME(name) android::EglScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG, name) + +// ATRACE_CALL is an ATRACE_NAME that uses the current function name. +#define ATRACE_CALL() ATRACE_NAME(__FUNCTION__) + +namespace android { + +class EglScopedTrace { +public: + inline EglScopedTrace(uint64_t tag, const char* name) : mTag(tag) { + atrace_begin(mTag, name); + } + + inline ~EglScopedTrace() { + atrace_end(mTag); + } + +private: + uint64_t mTag; +}; + +}; // namespace android + +#else // !__ANDROID__ + +#define ATRACE_NAME(...) +#define ATRACE_CALL() + +#endif // __ANDROID__ diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp index 336c2642ad..c05e840f32 100644 --- a/opengl/libs/EGL/getProcAddress.cpp +++ b/opengl/libs/EGL/getProcAddress.cpp @@ -15,10 +15,10 @@ */ #include <ctype.h> -#include <stdlib.h> #include <errno.h> +#include <stdlib.h> -#include <cutils/log.h> +#include <log/log.h> #include "egldefs.h" diff --git a/opengl/libs/EGL/include/private/EGL/cache.h b/opengl/libs/EGL/include/private/EGL/cache.h new file mode 100644 index 0000000000..0a176a8683 --- /dev/null +++ b/opengl/libs/EGL/include/private/EGL/cache.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2017 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. + */ + +#pragma once + +#include <cutils/compiler.h> + +namespace android { + +ANDROID_API void egl_set_cache_filename(const char* filename); + +} // namespace android diff --git a/opengl/libs/EGL/include/private/EGL/display.h b/opengl/libs/EGL/include/private/EGL/display.h new file mode 100644 index 0000000000..9560de266d --- /dev/null +++ b/opengl/libs/EGL/include/private/EGL/display.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 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. + */ + +#pragma once + +#include <EGL/egl.h> + +#include <cutils/compiler.h> + +namespace android { + +ANDROID_API int egl_get_init_count(EGLDisplay dpy); + +} // namespace android diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp index 6034a8edc0..f7fde9625f 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -15,12 +15,11 @@ */ #include <ctype.h> -#include <string.h> #include <errno.h> - +#include <string.h> #include <sys/ioctl.h> -#include <cutils/log.h> +#include <log/log.h> #include <cutils/properties.h> #include "../hooks.h" @@ -34,39 +33,65 @@ using namespace android; #undef API_ENTRY #undef CALL_GL_API +#undef CALL_GL_API_INTERNAL_CALL +#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE +#undef CALL_GL_API_INTERNAL_DO_RETURN #undef CALL_GL_API_RETURN #if USE_SLOW_BINDING #define API_ENTRY(_api) _api - #define CALL_GL_API(_api, ...) \ + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ if (_c) return _c->_api(__VA_ARGS__); + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE return 0; + + // This stays blank, since void functions will implicitly return, and + // all of the other functions will return 0 based on the previous macro. + #define CALL_GL_API_INTERNAL_DO_RETURN + #elif defined(__arm__) #define GET_TLS(reg) "mrc p15, 0, " #reg ", c13, c0, 3 \n" - #define API_ENTRY(_api) __attribute__((noinline)) _api - - #define CALL_GL_API(_api, ...) \ - asm volatile( \ - GET_TLS(r12) \ - "ldr r12, [r12, %[tls]] \n" \ - "cmp r12, #0 \n" \ - "ldrne pc, [r12, %[api]] \n" \ - : \ - : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ - [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \ - : "r12" \ - ); + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api + + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ + asm volatile( \ + GET_TLS(r12) \ + "ldr r12, [r12, %[tls]] \n" \ + "cmp r12, #0 \n" \ + "ldrne pc, [r12, %[api]] \n" \ + : \ + : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ + [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \ + : "r0", "r1", "r2", "r3", "r12" \ + ); + + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \ + asm volatile( \ + "mov r0, #0 \n" \ + : \ + : \ + : "r0" \ + ); + + + #define CALL_GL_API_INTERNAL_DO_RETURN \ + asm volatile( \ + "bx lr \n" \ + : \ + : \ + : "r0" \ + ); #elif defined(__aarch64__) - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api - #define CALL_GL_API(_api, ...) \ + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ asm volatile( \ "mrs x16, tpidr_el0\n" \ "ldr x16, [x16, %[tls]]\n" \ @@ -77,121 +102,173 @@ using namespace android; : \ : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ - : "x16" \ + : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x16" \ + ); + + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \ + asm volatile( \ + "mov w0, wzr \n" \ + : \ + : \ + : "w0" \ + ); + + #define CALL_GL_API_INTERNAL_DO_RETURN \ + asm volatile( \ + "ret \n" \ + : \ + : \ + : \ ); #elif defined(__i386__) - #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api - #define CALL_GL_API(_api, ...) \ - register void** fn; \ + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ __asm__ volatile( \ - "mov %%gs:0, %[fn]\n" \ - "mov %P[tls](%[fn]), %[fn]\n" \ - "test %[fn], %[fn]\n" \ + "mov %%gs:0, %%eax\n" \ + "mov %P[tls](%%eax), %%eax\n" \ + "test %%eax, %%eax\n" \ "je 1f\n" \ - "jmp *%P[api](%[fn])\n" \ + "jmp *%P[api](%%eax)\n" \ "1:\n" \ - : [fn] "=r" (fn) \ + : \ : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ - : "cc" \ + : "cc", "%eax" \ ); + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \ + __asm__ volatile( \ + "xor %%eax, %%eax\n" \ + : \ + : \ + : "%eax" \ + ); + + #define CALL_GL_API_INTERNAL_DO_RETURN \ + __asm__ volatile( \ + "ret\n" \ + : \ + : \ + : \ + ); + #elif defined(__x86_64__) - #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api - #define CALL_GL_API(_api, ...) \ - register void** fn; \ - __asm__ volatile( \ - "mov %%fs:0, %[fn]\n" \ - "mov %P[tls](%[fn]), %[fn]\n" \ - "test %[fn], %[fn]\n" \ + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ + __asm__ volatile( \ + "mov %%fs:0, %%rax\n" \ + "mov %P[tls](%%rax), %%rax\n" \ + "test %%rax, %%rax\n" \ "je 1f\n" \ - "jmp *%P[api](%[fn])\n" \ + "jmp *%P[api](%%rax)\n" \ "1:\n" \ - : [fn] "=r" (fn) \ + : \ : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ - : "cc" \ - ); + : "cc", "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9", \ + "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", \ + "%xmm6", "%xmm7" \ + ); + + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \ + __asm__ volatile( \ + "xor %%eax, %%eax\n" \ + : \ + : \ + : "%eax" \ + ); + + #define CALL_GL_API_INTERNAL_DO_RETURN \ + __asm__ volatile( \ + "retq\n" \ + : \ + : \ + : \ + ); #elif defined(__mips64) - #define API_ENTRY(_api) __attribute__((noinline)) _api - - #define CALL_GL_API(_api, ...) \ - register unsigned long _t0 asm("$12"); \ - register unsigned long _fn asm("$25"); \ - register unsigned long _tls asm("$3"); \ - register unsigned long _v0 asm("$2"); \ - asm volatile( \ - ".set push\n\t" \ - ".set noreorder\n\t" \ - "rdhwr %[tls], $29\n\t" \ - "ld %[t0], %[OPENGL_API](%[tls])\n\t" \ - "beqz %[t0], 1f\n\t" \ - " move %[fn], $ra\n\t" \ - "ld %[t0], %[API](%[t0])\n\t" \ - "beqz %[t0], 1f\n\t" \ - " nop\n\t" \ - "move %[fn], %[t0]\n\t" \ - "1:\n\t" \ - "jalr $0, %[fn]\n\t" \ - " move %[v0], $0\n\t" \ - ".set pop\n\t" \ - : [fn] "=c"(_fn), \ - [tls] "=&r"(_tls), \ - [t0] "=&r"(_t0), \ - [v0] "=&r"(_v0) \ - : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\ - [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ - : \ + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api + + // t0: $12 + // fn: $25 + // tls: $3 + // v0: $2 + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ + asm volatile( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + "rdhwr $3, $29\n\t" \ + "ld $12, %[OPENGL_API]($3)\n\t" \ + "beqz $12, 1f\n\t" \ + " move $25, $ra\n\t" \ + "ld $12, %[API]($12)\n\t" \ + "beqz $12, 1f\n\t" \ + " nop\n\t" \ + "move $25, $12\n\t" \ + "1:\n\t" \ + "jalr $0, $25\n\t" \ + " move $2, $0\n\t" \ + ".set pop\n\t" \ + : \ + : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\ + [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", \ + "$10", "$11", "$12", "$25" \ ); + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE + #define CALL_GL_API_INTERNAL_DO_RETURN + #elif defined(__mips__) - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api - #define CALL_GL_API(_api, ...) \ - register unsigned int _t0 asm("$8"); \ - register unsigned int _fn asm("$25"); \ - register unsigned int _tls asm("$3"); \ - register unsigned int _v0 asm("$2"); \ + // t0: $8 + // fn: $25 + // tls: $3 + // v0: $2 + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ ".set mips32r2\n\t" \ - "rdhwr %[tls], $29\n\t" \ - "lw %[t0], %[OPENGL_API](%[tls])\n\t" \ - "beqz %[t0], 1f\n\t" \ - " move %[fn],$ra\n\t" \ - "lw %[t0], %[API](%[t0])\n\t" \ - "beqz %[t0], 1f\n\t" \ + "rdhwr $3, $29\n\t" \ + "lw $3, %[OPENGL_API]($3)\n\t" \ + "beqz $3, 1f\n\t" \ + " move $25,$ra\n\t" \ + "lw $3, %[API]($3)\n\t" \ + "beqz $3, 1f\n\t" \ " nop\n\t" \ - "move %[fn], %[t0]\n\t" \ + "move $25, $3\n\t" \ "1:\n\t" \ - "jalr $0, %[fn]\n\t" \ - " move %[v0], $0\n\t" \ + "jalr $0, $25\n\t" \ + " move $2, $0\n\t" \ ".set pop\n\t" \ - : [fn] "=c"(_fn), \ - [tls] "=&r"(_tls), \ - [t0] "=&r"(_t0), \ - [v0] "=&r"(_v0) \ + : \ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \ [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ - : \ - ); + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$25" \ + ); -#endif + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE + #define CALL_GL_API_INTERNAL_DO_RETURN -#define CALL_GL_API_RETURN(_api, ...) \ - CALL_GL_API(_api, __VA_ARGS__) \ - return 0; +#endif +#define CALL_GL_API(_api, ...) \ + CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \ + CALL_GL_API_INTERNAL_DO_RETURN +#define CALL_GL_API_RETURN(_api, ...) \ + CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \ + CALL_GL_API_INTERNAL_SET_RETURN_VALUE \ + CALL_GL_API_INTERNAL_DO_RETURN extern "C" { #pragma GCC diagnostic ignored "-Wunused-parameter" @@ -202,6 +279,9 @@ extern "C" { #undef API_ENTRY #undef CALL_GL_API +#undef CALL_GL_API_INTERNAL_CALL +#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE +#undef CALL_GL_API_INTERNAL_DO_RETURN #undef CALL_GL_API_RETURN /* diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp index b1b31f8294..bacd4b4bc8 100644 --- a/opengl/libs/GLES_CM/gl.cpp +++ b/opengl/libs/GLES_CM/gl.cpp @@ -1,31 +1,30 @@ -/* +/* ** 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 + ** 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 + ** 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 + ** 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 <ctype.h> -#include <string.h> #include <errno.h> - +#include <string.h> #include <sys/ioctl.h> +#include <log/log.h> +#include <cutils/properties.h> + #include <GLES/gl.h> #include <GLES/glext.h> -#include <cutils/log.h> -#include <cutils/properties.h> - #include "../hooks.h" #include "../egl_impl.h" @@ -90,39 +89,65 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, #undef API_ENTRY #undef CALL_GL_API +#undef CALL_GL_API_INTERNAL_CALL +#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE +#undef CALL_GL_API_INTERNAL_DO_RETURN #undef CALL_GL_API_RETURN #if USE_SLOW_BINDING #define API_ENTRY(_api) _api - #define CALL_GL_API(_api, ...) \ + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ if (_c) return _c->_api(__VA_ARGS__); + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE return 0; + + // This stays blank, since void functions will implicitly return, and + // all of the other functions will return 0 based on the previous macro. + #define CALL_GL_API_INTERNAL_DO_RETURN + #elif defined(__arm__) #define GET_TLS(reg) "mrc p15, 0, " #reg ", c13, c0, 3 \n" - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api + + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ + asm volatile( \ + GET_TLS(r12) \ + "ldr r12, [r12, %[tls]] \n" \ + "cmp r12, #0 \n" \ + "ldrne pc, [r12, %[api]] \n" \ + : \ + : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ + [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \ + : "r0", "r1", "r2", "r3", "r12" \ + ); + + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \ + asm volatile( \ + "mov r0, #0 \n" \ + : \ + : \ + : "r0" \ + ); - #define CALL_GL_API(_api, ...) \ - asm volatile( \ - GET_TLS(r12) \ - "ldr r12, [r12, %[tls]] \n" \ - "cmp r12, #0 \n" \ - "ldrne pc, [r12, %[api]] \n" \ - : \ - : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ - [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \ - : "r12" \ - ); + + #define CALL_GL_API_INTERNAL_DO_RETURN \ + asm volatile( \ + "bx lr \n" \ + : \ + : \ + : "r0" \ + ); #elif defined(__aarch64__) - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api - #define CALL_GL_API(_api, ...) \ + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ asm volatile( \ "mrs x16, tpidr_el0\n" \ "ldr x16, [x16, %[tls]]\n" \ @@ -133,120 +158,173 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, : \ : [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ - : "x16" \ + : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x16" \ + ); + + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \ + asm volatile( \ + "mov w0, wzr \n" \ + : \ + : \ + : "w0" \ + ); + + #define CALL_GL_API_INTERNAL_DO_RETURN \ + asm volatile( \ + "ret \n" \ + : \ + : \ + : \ ); #elif defined(__i386__) - #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api - #define CALL_GL_API(_api, ...) \ - register void* fn; \ + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ __asm__ volatile( \ - "mov %%gs:0, %[fn]\n" \ - "mov %P[tls](%[fn]), %[fn]\n" \ - "test %[fn], %[fn]\n" \ + "mov %%gs:0, %%eax\n" \ + "mov %P[tls](%%eax), %%eax\n" \ + "test %%eax, %%eax\n" \ "je 1f\n" \ - "jmp *%P[api](%[fn])\n" \ + "jmp *%P[api](%%eax)\n" \ "1:\n" \ - : [fn] "=r" (fn) \ + : \ : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ - : "cc" \ - ); + : "cc", "%eax" \ + ); + + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \ + __asm__ volatile( \ + "xor %%eax, %%eax\n" \ + : \ + : \ + : "%eax" \ + ); + + #define CALL_GL_API_INTERNAL_DO_RETURN \ + __asm__ volatile( \ + "ret\n" \ + : \ + : \ + : \ + ); #elif defined(__x86_64__) - #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api - #define CALL_GL_API(_api, ...) \ - register void** fn; \ - __asm__ volatile( \ - "mov %%fs:0, %[fn]\n" \ - "mov %P[tls](%[fn]), %[fn]\n" \ - "test %[fn], %[fn]\n" \ + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ + __asm__ volatile( \ + "mov %%fs:0, %%rax\n" \ + "mov %P[tls](%%rax), %%rax\n" \ + "test %%rax, %%rax\n" \ "je 1f\n" \ - "jmp *%P[api](%[fn])\n" \ + "jmp *%P[api](%%rax)\n" \ "1:\n" \ - : [fn] "=r" (fn) \ + : \ : [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \ [api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \ - : "cc" \ - ); + : "cc", "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9", \ + "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", \ + "%xmm6", "%xmm7" \ + ); + + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \ + __asm__ volatile( \ + "xor %%eax, %%eax\n" \ + : \ + : \ + : "%eax" \ + ); + + #define CALL_GL_API_INTERNAL_DO_RETURN \ + __asm__ volatile( \ + "retq\n" \ + : \ + : \ + : \ + ); #elif defined(__mips64) - #define API_ENTRY(_api) __attribute__((noinline)) _api - - #define CALL_GL_API(_api, ...) \ - register unsigned long _t0 asm("$12"); \ - register unsigned long _fn asm("$25"); \ - register unsigned long _tls asm("$3"); \ - register unsigned long _v0 asm("$2"); \ - asm volatile( \ - ".set push\n\t" \ - ".set noreorder\n\t" \ - "rdhwr %[tls], $29\n\t" \ - "ld %[t0], %[OPENGL_API](%[tls])\n\t" \ - "beqz %[t0], 1f\n\t" \ - " move %[fn], $ra\n\t" \ - "ld %[t0], %[API](%[t0])\n\t" \ - "beqz %[t0], 1f\n\t" \ - " nop\n\t" \ - "move %[fn], %[t0]\n\t" \ - "1:\n\t" \ - "jalr $0, %[fn]\n\t" \ - " move %[v0], $0\n\t" \ - ".set pop\n\t" \ - : [fn] "=c"(_fn), \ - [tls] "=&r"(_tls), \ - [t0] "=&r"(_t0), \ - [v0] "=&r"(_v0) \ - : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\ - [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ - : \ + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api + + // t0: $12 + // fn: $25 + // tls: $3 + // v0: $2 + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ + asm volatile( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + "rdhwr $3, $29\n\t" \ + "ld $12, %[OPENGL_API]($3)\n\t" \ + "beqz $12, 1f\n\t" \ + " move $25, $ra\n\t" \ + "ld $12, %[API]($12)\n\t" \ + "beqz $12, 1f\n\t" \ + " nop\n\t" \ + "move $25, $12\n\t" \ + "1:\n\t" \ + "jalr $0, $25\n\t" \ + " move $2, $0\n\t" \ + ".set pop\n\t" \ + : \ + : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\ + [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", \ + "$10", "$11", "$12", "$25" \ ); + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE + #define CALL_GL_API_INTERNAL_DO_RETURN + #elif defined(__mips__) - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((naked,noinline)) _api - #define CALL_GL_API(_api, ...) \ - register unsigned int _t0 asm("$8"); \ - register unsigned int _fn asm("$25"); \ - register unsigned int _tls asm("$3"); \ - register unsigned int _v0 asm("$2"); \ + // t0: $8 + // fn: $25 + // tls: $3 + // v0: $2 + #define CALL_GL_API_INTERNAL_CALL(_api, ...) \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ ".set mips32r2\n\t" \ - "rdhwr %[tls], $29\n\t" \ - "lw %[t0], %[OPENGL_API](%[tls])\n\t" \ - "beqz %[t0], 1f\n\t" \ - " move %[fn], $ra\n\t" \ - "lw %[t0], %[API](%[t0])\n\t" \ - "beqz %[t0], 1f\n\t" \ + "rdhwr $3, $29\n\t" \ + "lw $3, %[OPENGL_API]($3)\n\t" \ + "beqz $3, 1f\n\t" \ + " move $25,$ra\n\t" \ + "lw $3, %[API]($3)\n\t" \ + "beqz $3, 1f\n\t" \ " nop\n\t" \ - "move %[fn], %[t0]\n\t" \ + "move $25, $3\n\t" \ "1:\n\t" \ - "jalr $0, %[fn]\n\t" \ - " move %[v0], $0\n\t" \ + "jalr $0, $25\n\t" \ + " move $2, $0\n\t" \ ".set pop\n\t" \ - : [fn] "=c"(_fn), \ - [tls] "=&r"(_tls), \ - [t0] "=&r"(_t0), \ - [v0] "=&r"(_v0) \ + : \ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \ [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ - : \ - ); + : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$25" \ + ); + + #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE + #define CALL_GL_API_INTERNAL_DO_RETURN #endif -#define CALL_GL_API_RETURN(_api, ...) \ - CALL_GL_API(_api, __VA_ARGS__) \ - return 0; +#define CALL_GL_API(_api, ...) \ + CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \ + CALL_GL_API_INTERNAL_DO_RETURN +#define CALL_GL_API_RETURN(_api, ...) \ + CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \ + CALL_GL_API_INTERNAL_SET_RETURN_VALUE \ + CALL_GL_API_INTERNAL_DO_RETURN extern "C" { #pragma GCC diagnostic ignored "-Wunused-parameter" @@ -257,6 +335,9 @@ extern "C" { #undef API_ENTRY #undef CALL_GL_API +#undef CALL_GL_API_INTERNAL_CALL +#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE +#undef CALL_GL_API_INTERNAL_DO_RETURN #undef CALL_GL_API_RETURN /* diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h index c0990ece39..a8855efa57 100644 --- a/opengl/libs/egl_impl.h +++ b/opengl/libs/egl_impl.h @@ -17,8 +17,6 @@ #ifndef ANDROID_EGL_IMPL_H #define ANDROID_EGL_IMPL_H -#include <ctype.h> - #include <EGL/egl.h> #include <EGL/eglext.h> #include <EGL/eglplatform.h> @@ -30,8 +28,7 @@ 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 const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index); EGLAPI GLint egl_get_num_extensions_for_current_context(); // ---------------------------------------------------------------------------- diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h index e14075cdb7..81dbe0e34b 100644 --- a/opengl/libs/hooks.h +++ b/opengl/libs/hooks.h @@ -56,8 +56,8 @@ namespace android { #undef GL_ENTRY #undef EGL_ENTRY -#define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__); -#define EGL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__); +#define GL_ENTRY(_r, _api, ...) _r (*(_api))(__VA_ARGS__); +#define EGL_ENTRY(_r, _api, ...) _r (*(_api))(__VA_ARGS__); struct egl_t { #include "EGL/egl_entries.in" diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt new file mode 100644 index 0000000000..89269a0231 --- /dev/null +++ b/opengl/libs/libEGL.map.txt @@ -0,0 +1,68 @@ +LIBEGL { + global: + eglBindAPI; + eglBindTexImage; + eglChooseConfig; + eglClientWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 + eglCopyBuffers; + eglCreateContext; + eglCreateImageKHR; + eglCreateNativeClientBufferANDROID; # introduced=24 + eglCreatePbufferFromClientBuffer; + eglCreatePbufferSurface; + eglCreatePixmapSurface; + eglCreateStreamFromFileDescriptorKHR; # introduced=23 + eglCreateStreamKHR; # introduced=23 + eglCreateStreamProducerSurfaceKHR; # introduced=23 + eglCreateSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 + eglCreateWindowSurface; + eglDestroyContext; + eglDestroyImageKHR; + eglDestroyStreamKHR; # introduced=23 + eglDestroySurface; + eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 + eglGetConfigAttrib; + eglGetConfigs; + eglGetCurrentContext; + eglGetCurrentDisplay; + eglGetCurrentSurface; + eglGetDisplay; + eglGetError; + eglGetNativeClientBufferANDROID; # introduced=26 + eglGetProcAddress; + eglGetStreamFileDescriptorKHR; # introduced=23 + eglGetSyncAttribKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 + eglGetSystemTimeFrequencyNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21 + eglGetSystemTimeNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21 + eglInitialize; + eglLockSurfaceKHR; + eglMakeCurrent; + eglPresentationTimeANDROID; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 + eglQueryAPI; + eglQueryContext; + eglQueryStreamKHR; # introduced=23 + eglQueryStreamTimeKHR; # introduced=23 + eglQueryStreamu64KHR; # introduced=23 + eglQueryString; + eglQuerySurface; + eglReleaseTexImage; + eglReleaseThread; + eglSetDamageRegionKHR; # introduced=23 + eglSignalSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 + eglStreamAttribKHR; # introduced=23 + eglStreamConsumerAcquireKHR; # introduced=23 + eglStreamConsumerGLTextureExternalKHR; # introduced=23 + eglStreamConsumerReleaseKHR; # introduced=23 + eglSurfaceAttrib; + eglSwapBuffers; + eglSwapBuffersWithDamageKHR; # introduced=23 + eglSwapInterval; + eglTerminate; + eglUnlockSurfaceKHR; + eglWaitClient; + eglWaitGL; + eglWaitNative; + eglWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 + local: + *; +}; diff --git a/opengl/libs/libGLESv1_CM.map.txt b/opengl/libs/libGLESv1_CM.map.txt new file mode 100644 index 0000000000..8ba91e6e65 --- /dev/null +++ b/opengl/libs/libGLESv1_CM.map.txt @@ -0,0 +1,283 @@ +LIBGLESV1_CM { + global: + glActiveTexture; + glAlphaFunc; + glAlphaFuncx; + glAlphaFuncxOES; + glBindBuffer; + glBindFramebufferOES; + glBindRenderbufferOES; + glBindTexture; + glBindVertexArrayOES; # introduced-mips=9 introduced-x86=9 + glBlendEquationOES; + glBlendEquationSeparateOES; + glBlendFunc; + glBlendFuncSeparateOES; + glBufferData; + glBufferSubData; + glCheckFramebufferStatusOES; + glClear; + glClearColor; + glClearColorx; + glClearColorxOES; + glClearDepthf; + glClearDepthfOES; + glClearDepthx; + glClearDepthxOES; + glClearStencil; + glClientActiveTexture; + glClipPlanef; + glClipPlanefIMG; # introduced-mips=9 introduced-x86=9 + glClipPlanefOES; + glClipPlanex; + glClipPlanexIMG; # introduced-mips=9 introduced-x86=9 + glClipPlanexOES; + glColor4f; + glColor4ub; + glColor4x; + glColor4xOES; + glColorMask; + glColorPointer; + glColorPointerBounds; + glCompressedTexImage2D; + glCompressedTexSubImage2D; + glCopyTexImage2D; + glCopyTexSubImage2D; + glCullFace; + glCurrentPaletteMatrixOES; + glDeleteBuffers; + glDeleteFencesNV; # introduced-mips=9 introduced-x86=9 + glDeleteFramebuffersOES; + glDeleteRenderbuffersOES; + glDeleteTextures; + glDeleteVertexArraysOES; # introduced-mips=9 introduced-x86=9 + glDepthFunc; + glDepthMask; + glDepthRangef; + glDepthRangefOES; + glDepthRangex; + glDepthRangexOES; + glDisable; + glDisableClientState; + glDisableDriverControlQCOM; # introduced-mips=9 introduced-x86=9 + glDiscardFramebufferEXT; # introduced-mips=9 introduced-x86=9 + glDrawArrays; + glDrawElements; + glDrawTexfOES; + glDrawTexfvOES; + glDrawTexiOES; + glDrawTexivOES; + glDrawTexsOES; + glDrawTexsvOES; + glDrawTexxOES; + glDrawTexxvOES; + glEGLImageTargetRenderbufferStorageOES; + glEGLImageTargetTexture2DOES; + glEnable; + glEnableClientState; + glEnableDriverControlQCOM; # introduced-mips=9 introduced-x86=9 + glEndTilingQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetBufferPointervQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetBuffersQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetFramebuffersQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetProgramBinarySourceQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetProgramsQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetRenderbuffersQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetShadersQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetTexLevelParameterivQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetTexSubImageQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetTexturesQCOM; # introduced-mips=9 introduced-x86=9 + glExtIsProgramBinaryQCOM; # introduced-mips=9 introduced-x86=9 + glExtTexObjectStateOverrideiQCOM; # introduced-mips=9 introduced-x86=9 + glFinish; + glFinishFenceNV; # introduced-mips=9 introduced-x86=9 + glFlush; + glFogf; + glFogfv; + glFogx; + glFogxOES; + glFogxv; + glFogxvOES; + glFramebufferRenderbufferOES; + glFramebufferTexture2DMultisampleIMG; # introduced-mips=9 introduced-x86=9 + glFramebufferTexture2DOES; + glFrontFace; + glFrustumf; + glFrustumfOES; + glFrustumx; + glFrustumxOES; + glGenBuffers; + glGenFencesNV; # introduced-mips=9 introduced-x86=9 + glGenFramebuffersOES; + glGenRenderbuffersOES; + glGenTextures; + glGenVertexArraysOES; # introduced-mips=9 introduced-x86=9 + glGenerateMipmapOES; + glGetBooleanv; + glGetBufferParameteriv; + glGetBufferPointervOES; + glGetClipPlanef; + glGetClipPlanefOES; + glGetClipPlanex; + glGetClipPlanexOES; + glGetDriverControlStringQCOM; # introduced-mips=9 introduced-x86=9 + glGetDriverControlsQCOM; # introduced-mips=9 introduced-x86=9 + glGetError; + glGetFenceivNV; # introduced-mips=9 introduced-x86=9 + glGetFixedv; + glGetFixedvOES; + glGetFloatv; + glGetFramebufferAttachmentParameterivOES; + glGetIntegerv; + glGetLightfv; + glGetLightxv; + glGetLightxvOES; + glGetMaterialfv; + glGetMaterialxv; + glGetMaterialxvOES; + glGetPointerv; + glGetRenderbufferParameterivOES; + glGetString; + glGetTexEnvfv; + glGetTexEnviv; + glGetTexEnvxv; + glGetTexEnvxvOES; + glGetTexGenfvOES; + glGetTexGenivOES; + glGetTexGenxvOES; + glGetTexParameterfv; + glGetTexParameteriv; + glGetTexParameterxv; + glGetTexParameterxvOES; + glHint; + glIsBuffer; + glIsEnabled; + glIsFenceNV; # introduced-mips=9 introduced-x86=9 + glIsFramebufferOES; + glIsRenderbufferOES; + glIsTexture; + glIsVertexArrayOES; # introduced-mips=9 introduced-x86=9 + glLightModelf; + glLightModelfv; + glLightModelx; + glLightModelxOES; + glLightModelxv; + glLightModelxvOES; + glLightf; + glLightfv; + glLightx; + glLightxOES; + glLightxv; + glLightxvOES; + glLineWidth; + glLineWidthx; + glLineWidthxOES; + glLoadIdentity; + glLoadMatrixf; + glLoadMatrixx; + glLoadMatrixxOES; + glLoadPaletteFromModelViewMatrixOES; + glLogicOp; + glMapBufferOES; + glMaterialf; + glMaterialfv; + glMaterialx; + glMaterialxOES; + glMaterialxv; + glMaterialxvOES; + glMatrixIndexPointerOES; + glMatrixIndexPointerOESBounds; # introduced-mips=9 introduced-x86=9 + glMatrixMode; + glMultMatrixf; + glMultMatrixx; + glMultMatrixxOES; + glMultiDrawArraysEXT; # introduced-mips=9 introduced-x86=9 + glMultiDrawElementsEXT; # introduced-mips=9 introduced-x86=9 + glMultiTexCoord4f; + glMultiTexCoord4x; + glMultiTexCoord4xOES; + glNormal3f; + glNormal3x; + glNormal3xOES; + glNormalPointer; + glNormalPointerBounds; + glOrthof; + glOrthofOES; + glOrthox; + glOrthoxOES; + glPixelStorei; + glPointParameterf; + glPointParameterfv; + glPointParameterx; + glPointParameterxOES; + glPointParameterxv; + glPointParameterxvOES; + glPointSize; + glPointSizePointerOES; + glPointSizePointerOESBounds; # introduced-mips=9 introduced-x86=9 + glPointSizex; + glPointSizexOES; + glPolygonOffset; + glPolygonOffsetx; + glPolygonOffsetxOES; + glPopMatrix; + glPushMatrix; + glQueryMatrixxOES; + glReadPixels; + glRenderbufferStorageMultisampleIMG; # introduced-mips=9 introduced-x86=9 + glRenderbufferStorageOES; + glRotatef; + glRotatex; + glRotatexOES; + glSampleCoverage; + glSampleCoveragex; + glSampleCoveragexOES; + glScalef; + glScalex; + glScalexOES; + glScissor; + glSetFenceNV; # introduced-mips=9 introduced-x86=9 + glShadeModel; + glStartTilingQCOM; # introduced-mips=9 introduced-x86=9 + glStencilFunc; + glStencilMask; + glStencilOp; + glTestFenceNV; # introduced-mips=9 introduced-x86=9 + glTexCoordPointer; + glTexCoordPointerBounds; + glTexEnvf; + glTexEnvfv; + glTexEnvi; + glTexEnviv; + glTexEnvx; + glTexEnvxOES; + glTexEnvxv; + glTexEnvxvOES; + glTexGenfOES; + glTexGenfvOES; + glTexGeniOES; + glTexGenivOES; + glTexGenxOES; + glTexGenxvOES; + glTexImage2D; + glTexParameterf; + glTexParameterfv; + glTexParameteri; + glTexParameteriv; + glTexParameterx; + glTexParameterxOES; + glTexParameterxv; + glTexParameterxvOES; + glTexSubImage2D; + glTranslatef; + glTranslatex; + glTranslatexOES; + glUnmapBufferOES; + glVertexPointer; + glVertexPointerBounds; + glViewport; + glWeightPointerOES; + glWeightPointerOESBounds; # introduced-mips=9 introduced-x86=9 + local: + *; +}; diff --git a/opengl/libs/libGLESv2.map.txt b/opengl/libs/libGLESv2.map.txt new file mode 100644 index 0000000000..1b0042aef5 --- /dev/null +++ b/opengl/libs/libGLESv2.map.txt @@ -0,0 +1,207 @@ +LIBGLESV2 { + global: + glActiveTexture; + glAttachShader; + glBeginPerfMonitorAMD; + glBindAttribLocation; + glBindBuffer; + glBindFramebuffer; + glBindRenderbuffer; + glBindTexture; + glBindVertexArrayOES; # introduced-mips=9 introduced-x86=9 + glBlendColor; + glBlendEquation; + glBlendEquationSeparate; + glBlendFunc; + glBlendFuncSeparate; + glBufferData; + glBufferSubData; + glCheckFramebufferStatus; + glClear; + glClearColor; + glClearDepthf; + glClearStencil; + glColorMask; + glCompileShader; + glCompressedTexImage2D; + glCompressedTexImage3DOES; + glCompressedTexSubImage2D; + glCompressedTexSubImage3DOES; + glCopyTexImage2D; + glCopyTexSubImage2D; + glCopyTexSubImage3DOES; + glCoverageMaskNV; # introduced-mips=9 introduced-x86=9 + glCoverageOperationNV; # introduced-mips=9 introduced-x86=9 + glCreateProgram; + glCreateShader; + glCullFace; + glDeleteBuffers; + glDeleteFencesNV; + glDeleteFramebuffers; + glDeletePerfMonitorsAMD; + glDeleteProgram; + glDeleteRenderbuffers; + glDeleteShader; + glDeleteTextures; + glDeleteVertexArraysOES; # introduced-mips=9 introduced-x86=9 + glDepthFunc; + glDepthMask; + glDepthRangef; + glDetachShader; + glDisable; + glDisableDriverControlQCOM; + glDisableVertexAttribArray; + glDiscardFramebufferEXT; # introduced-mips=9 introduced-x86=9 + glDrawArrays; + glDrawElements; + glEGLImageTargetRenderbufferStorageOES; + glEGLImageTargetTexture2DOES; + glEnable; + glEnableDriverControlQCOM; + glEnableVertexAttribArray; + glEndPerfMonitorAMD; + glEndTilingQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetBufferPointervQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetBuffersQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetFramebuffersQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetProgramBinarySourceQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetProgramsQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetRenderbuffersQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetShadersQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetTexLevelParameterivQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetTexSubImageQCOM; # introduced-mips=9 introduced-x86=9 + glExtGetTexturesQCOM; # introduced-mips=9 introduced-x86=9 + glExtIsProgramBinaryQCOM; # introduced-mips=9 introduced-x86=9 + glExtTexObjectStateOverrideiQCOM; # introduced-mips=9 introduced-x86=9 + glFinish; + glFinishFenceNV; + glFlush; + glFramebufferRenderbuffer; + glFramebufferTexture2D; + glFramebufferTexture2DMultisampleIMG; # introduced-mips=9 introduced-x86=9 + glFramebufferTexture3DOES; + glFrontFace; + glGenBuffers; + glGenFencesNV; + glGenFramebuffers; + glGenPerfMonitorsAMD; + glGenRenderbuffers; + glGenTextures; + glGenVertexArraysOES; # introduced-mips=9 introduced-x86=9 + glGenerateMipmap; + glGetActiveAttrib; + glGetActiveUniform; + glGetAttachedShaders; + glGetAttribLocation; + glGetBooleanv; + glGetBufferParameteriv; + glGetBufferPointervOES; + glGetDriverControlStringQCOM; + glGetDriverControlsQCOM; + glGetError; + glGetFenceivNV; + glGetFloatv; + glGetFramebufferAttachmentParameteriv; + glGetIntegerv; + glGetPerfMonitorCounterDataAMD; + glGetPerfMonitorCounterInfoAMD; + glGetPerfMonitorCounterStringAMD; + glGetPerfMonitorCountersAMD; + glGetPerfMonitorGroupStringAMD; + glGetPerfMonitorGroupsAMD; + glGetProgramBinaryOES; + glGetProgramInfoLog; + glGetProgramiv; + glGetRenderbufferParameteriv; + glGetShaderInfoLog; + glGetShaderPrecisionFormat; + glGetShaderSource; + glGetShaderiv; + glGetString; + glGetTexParameterfv; + glGetTexParameteriv; + glGetUniformLocation; + glGetUniformfv; + glGetUniformiv; + glGetVertexAttribPointerv; + glGetVertexAttribfv; + glGetVertexAttribiv; + glHint; + glIsBuffer; + glIsEnabled; + glIsFenceNV; + glIsFramebuffer; + glIsProgram; + glIsRenderbuffer; + glIsShader; + glIsTexture; + glIsVertexArrayOES; # introduced-mips=9 introduced-x86=9 + glLineWidth; + glLinkProgram; + glMapBufferOES; + glMultiDrawArraysEXT; # introduced-mips=9 introduced-x86=9 + glMultiDrawElementsEXT; # introduced-mips=9 introduced-x86=9 + glPixelStorei; + glPolygonOffset; + glProgramBinaryOES; + glReadPixels; + glReleaseShaderCompiler; + glRenderbufferStorage; + glRenderbufferStorageMultisampleIMG; # introduced-mips=9 introduced-x86=9 + glSampleCoverage; + glScissor; + glSelectPerfMonitorCountersAMD; + glSetFenceNV; + glShaderBinary; + glShaderSource; + glStartTilingQCOM; # introduced-mips=9 introduced-x86=9 + glStencilFunc; + glStencilFuncSeparate; + glStencilMask; + glStencilMaskSeparate; + glStencilOp; + glStencilOpSeparate; + glTestFenceNV; + glTexImage2D; + glTexImage3DOES; + glTexParameterf; + glTexParameterfv; + glTexParameteri; + glTexParameteriv; + glTexSubImage2D; + glTexSubImage3DOES; + glUniform1f; + glUniform1fv; + glUniform1i; + glUniform1iv; + glUniform2f; + glUniform2fv; + glUniform2i; + glUniform2iv; + glUniform3f; + glUniform3fv; + glUniform3i; + glUniform3iv; + glUniform4f; + glUniform4fv; + glUniform4i; + glUniform4iv; + glUniformMatrix2fv; + glUniformMatrix3fv; + glUniformMatrix4fv; + glUnmapBufferOES; + glUseProgram; + glValidateProgram; + glVertexAttrib1f; + glVertexAttrib1fv; + glVertexAttrib2f; + glVertexAttrib2fv; + glVertexAttrib3f; + glVertexAttrib3fv; + glVertexAttrib4f; + glVertexAttrib4fv; + glVertexAttribPointer; + glViewport; + local: + *; +}; diff --git a/opengl/libs/libGLESv3.map.txt b/opengl/libs/libGLESv3.map.txt new file mode 100644 index 0000000000..21f6cb665e --- /dev/null +++ b/opengl/libs/libGLESv3.map.txt @@ -0,0 +1,416 @@ +LIBGLESV3 { + global: + glActiveShaderProgram; # introduced=21 + glActiveTexture; + glAttachShader; + glBeginQuery; + glBeginTransformFeedback; + glBindAttribLocation; + glBindBuffer; + glBindBufferBase; + glBindBufferRange; + glBindFramebuffer; + glBindImageTexture; # introduced=21 + glBindProgramPipeline; # introduced=21 + glBindRenderbuffer; + glBindSampler; + glBindTexture; + glBindTransformFeedback; + glBindVertexArray; + glBindVertexArrayOES; + glBindVertexBuffer; # introduced=21 + glBlendBarrier; # introduced=24 + glBlendBarrierKHR; # introduced=21 + glBlendColor; + glBlendEquation; + glBlendEquationSeparate; + glBlendEquationSeparatei; # introduced=24 + glBlendEquationSeparateiEXT; # introduced=21 + glBlendEquationi; # introduced=24 + glBlendEquationiEXT; # introduced=21 + glBlendFunc; + glBlendFuncSeparate; + glBlendFuncSeparatei; # introduced=24 + glBlendFuncSeparateiEXT; # introduced=21 + glBlendFunci; # introduced=24 + glBlendFunciEXT; # introduced=21 + glBlitFramebuffer; + glBufferData; + glBufferSubData; + glCheckFramebufferStatus; + glClear; + glClearBufferfi; + glClearBufferfv; + glClearBufferiv; + glClearBufferuiv; + glClearColor; + glClearDepthf; + glClearStencil; + glClientWaitSync; + glColorMask; + glColorMaski; # introduced=24 + glColorMaskiEXT; # introduced=21 + glCompileShader; + glCompressedTexImage2D; + glCompressedTexImage3D; + glCompressedTexImage3DOES; + glCompressedTexSubImage2D; + glCompressedTexSubImage3D; + glCompressedTexSubImage3DOES; + glCopyBufferSubData; + glCopyImageSubData; # introduced=24 + glCopyImageSubDataEXT; # introduced=21 + glCopyTexImage2D; + glCopyTexSubImage2D; + glCopyTexSubImage3D; + glCopyTexSubImage3DOES; + glCreateProgram; + glCreateShader; + glCreateShaderProgramv; # introduced=21 + glCullFace; + glDebugMessageCallback; # introduced=24 + glDebugMessageCallbackKHR; # introduced=21 + glDebugMessageControl; # introduced=24 + glDebugMessageControlKHR; # introduced=21 + glDebugMessageInsert; # introduced=24 + glDebugMessageInsertKHR; # introduced=21 + glDeleteBuffers; + glDeleteFramebuffers; + glDeleteProgram; + glDeleteProgramPipelines; # introduced=21 + glDeleteQueries; + glDeleteRenderbuffers; + glDeleteSamplers; + glDeleteShader; + glDeleteSync; + glDeleteTextures; + glDeleteTransformFeedbacks; + glDeleteVertexArrays; + glDeleteVertexArraysOES; + glDepthFunc; + glDepthMask; + glDepthRangef; + glDetachShader; + glDisable; + glDisableVertexAttribArray; + glDisablei; # introduced=24 + glDisableiEXT; # introduced=21 + glDispatchCompute; # introduced=21 + glDispatchComputeIndirect; # introduced=21 + glDrawArrays; + glDrawArraysIndirect; # introduced=21 + glDrawArraysInstanced; + glDrawBuffers; + glDrawElements; + glDrawElementsBaseVertex; # introduced=24 + glDrawElementsIndirect; # introduced=21 + glDrawElementsInstanced; + glDrawElementsInstancedBaseVertex; # introduced=24 + glDrawRangeElements; + glDrawRangeElementsBaseVertex; # introduced=24 + glEGLImageTargetRenderbufferStorageOES; + glEGLImageTargetTexture2DOES; + glEnable; + glEnableVertexAttribArray; + glEnablei; # introduced=24 + glEnableiEXT; # introduced=21 + glEndQuery; + glEndTransformFeedback; + glFenceSync; + glFinish; + glFlush; + glFlushMappedBufferRange; + glFramebufferParameteri; # introduced=21 + glFramebufferRenderbuffer; + glFramebufferTexture; # introduced=24 + glFramebufferTexture2D; + glFramebufferTexture3DOES; + glFramebufferTextureEXT; # introduced=21 + glFramebufferTextureLayer; + glFrontFace; + glGenBuffers; + glGenFramebuffers; + glGenProgramPipelines; # introduced=21 + glGenQueries; + glGenRenderbuffers; + glGenSamplers; + glGenTextures; + glGenTransformFeedbacks; + glGenVertexArrays; + glGenVertexArraysOES; + glGenerateMipmap; + glGetActiveAttrib; + glGetActiveUniform; + glGetActiveUniformBlockName; + glGetActiveUniformBlockiv; + glGetActiveUniformsiv; + glGetAttachedShaders; + glGetAttribLocation; + glGetBooleani_v; # introduced=21 + glGetBooleanv; + glGetBufferParameteri64v; + glGetBufferParameteriv; + glGetBufferPointerv; + glGetBufferPointervOES; + glGetDebugMessageLog; # introduced=24 + glGetDebugMessageLogKHR; # introduced=21 + glGetError; + glGetFloatv; + glGetFragDataLocation; + glGetFramebufferAttachmentParameteriv; + glGetFramebufferParameteriv; # introduced=21 + glGetGraphicsResetStatus; # introduced=24 + glGetInteger64i_v; + glGetInteger64v; + glGetIntegeri_v; + glGetIntegerv; + glGetInternalformativ; + glGetMultisamplefv; # introduced=21 + glGetObjectLabel; # introduced=24 + glGetObjectLabelKHR; # introduced=21 + glGetObjectPtrLabel; # introduced=24 + glGetObjectPtrLabelKHR; # introduced=21 + glGetPointerv; # introduced=24 + glGetPointervKHR; # introduced=21 + glGetProgramBinary; + glGetProgramBinaryOES; + glGetProgramInfoLog; + glGetProgramInterfaceiv; # introduced=21 + glGetProgramPipelineInfoLog; # introduced=21 + glGetProgramPipelineiv; # introduced=21 + glGetProgramResourceIndex; # introduced=21 + glGetProgramResourceLocation; # introduced=21 + glGetProgramResourceName; # introduced=21 + glGetProgramResourceiv; # introduced=21 + glGetProgramiv; + glGetQueryObjectuiv; + glGetQueryiv; + glGetRenderbufferParameteriv; + glGetSamplerParameterIiv; # introduced=24 + glGetSamplerParameterIivEXT; # introduced=21 + glGetSamplerParameterIuiv; # introduced=24 + glGetSamplerParameterIuivEXT; # introduced=21 + glGetSamplerParameterfv; + glGetSamplerParameteriv; + glGetShaderInfoLog; + glGetShaderPrecisionFormat; + glGetShaderSource; + glGetShaderiv; + glGetString; + glGetStringi; + glGetSynciv; + glGetTexLevelParameterfv; # introduced=21 + glGetTexLevelParameteriv; # introduced=21 + glGetTexParameterIiv; # introduced=24 + glGetTexParameterIivEXT; # introduced=21 + glGetTexParameterIuiv; # introduced=24 + glGetTexParameterIuivEXT; # introduced=21 + glGetTexParameterfv; + glGetTexParameteriv; + glGetTransformFeedbackVarying; + glGetUniformBlockIndex; + glGetUniformIndices; + glGetUniformLocation; + glGetUniformfv; + glGetUniformiv; + glGetUniformuiv; + glGetVertexAttribIiv; + glGetVertexAttribIuiv; + glGetVertexAttribPointerv; + glGetVertexAttribfv; + glGetVertexAttribiv; + glGetnUniformfv; # introduced=24 + glGetnUniformiv; # introduced=24 + glGetnUniformuiv; # introduced=24 + glHint; + glInvalidateFramebuffer; + glInvalidateSubFramebuffer; + glIsBuffer; + glIsEnabled; + glIsEnabledi; # introduced=24 + glIsEnablediEXT; # introduced=21 + glIsFramebuffer; + glIsProgram; + glIsProgramPipeline; # introduced=21 + glIsQuery; + glIsRenderbuffer; + glIsSampler; + glIsShader; + glIsSync; + glIsTexture; + glIsTransformFeedback; + glIsVertexArray; + glIsVertexArrayOES; + glLineWidth; + glLinkProgram; + glMapBufferOES; + glMapBufferRange; + glMemoryBarrier; # introduced=21 + glMemoryBarrierByRegion; # introduced=21 + glMinSampleShading; # introduced=24 + glMinSampleShadingOES; # introduced=21 + glObjectLabel; # introduced=24 + glObjectLabelKHR; # introduced=21 + glObjectPtrLabel; # introduced=24 + glObjectPtrLabelKHR; # introduced=21 + glPatchParameteri; # introduced=24 + glPatchParameteriEXT; # introduced=21 + glPauseTransformFeedback; + glPixelStorei; + glPolygonOffset; + glPopDebugGroup; # introduced=24 + glPopDebugGroupKHR; # introduced=21 + glPrimitiveBoundingBox; # introduced=24 + glPrimitiveBoundingBoxEXT; # introduced=21 + glProgramBinary; + glProgramBinaryOES; + glProgramParameteri; + glProgramUniform1f; # introduced=21 + glProgramUniform1fv; # introduced=21 + glProgramUniform1i; # introduced=21 + glProgramUniform1iv; # introduced=21 + glProgramUniform1ui; # introduced=21 + glProgramUniform1uiv; # introduced=21 + glProgramUniform2f; # introduced=21 + glProgramUniform2fv; # introduced=21 + glProgramUniform2i; # introduced=21 + glProgramUniform2iv; # introduced=21 + glProgramUniform2ui; # introduced=21 + glProgramUniform2uiv; # introduced=21 + glProgramUniform3f; # introduced=21 + glProgramUniform3fv; # introduced=21 + glProgramUniform3i; # introduced=21 + glProgramUniform3iv; # introduced=21 + glProgramUniform3ui; # introduced=21 + glProgramUniform3uiv; # introduced=21 + glProgramUniform4f; # introduced=21 + glProgramUniform4fv; # introduced=21 + glProgramUniform4i; # introduced=21 + glProgramUniform4iv; # introduced=21 + glProgramUniform4ui; # introduced=21 + glProgramUniform4uiv; # introduced=21 + glProgramUniformMatrix2fv; # introduced=21 + glProgramUniformMatrix2x3fv; # introduced=21 + glProgramUniformMatrix2x4fv; # introduced=21 + glProgramUniformMatrix3fv; # introduced=21 + glProgramUniformMatrix3x2fv; # introduced=21 + glProgramUniformMatrix3x4fv; # introduced=21 + glProgramUniformMatrix4fv; # introduced=21 + glProgramUniformMatrix4x2fv; # introduced=21 + glProgramUniformMatrix4x3fv; # introduced=21 + glPushDebugGroup; # introduced=24 + glPushDebugGroupKHR; # introduced=21 + glReadBuffer; + glReadPixels; + glReadnPixels; # introduced=24 + glReleaseShaderCompiler; + glRenderbufferStorage; + glRenderbufferStorageMultisample; + glResumeTransformFeedback; + glSampleCoverage; + glSampleMaski; # introduced=21 + glSamplerParameterIiv; # introduced=24 + glSamplerParameterIivEXT; # introduced=21 + glSamplerParameterIuiv; # introduced=24 + glSamplerParameterIuivEXT; # introduced=21 + glSamplerParameterf; + glSamplerParameterfv; + glSamplerParameteri; + glSamplerParameteriv; + glScissor; + glShaderBinary; + glShaderSource; + glStencilFunc; + glStencilFuncSeparate; + glStencilMask; + glStencilMaskSeparate; + glStencilOp; + glStencilOpSeparate; + glTexBuffer; # introduced=24 + glTexBufferEXT; # introduced=21 + glTexBufferRange; # introduced=24 + glTexBufferRangeEXT; # introduced=21 + glTexImage2D; + glTexImage3D; + glTexImage3DOES; + glTexParameterIiv; # introduced=24 + glTexParameterIivEXT; # introduced=21 + glTexParameterIuiv; # introduced=24 + glTexParameterIuivEXT; # introduced=21 + glTexParameterf; + glTexParameterfv; + glTexParameteri; + glTexParameteriv; + glTexStorage2D; + glTexStorage2DMultisample; # introduced=21 + glTexStorage3D; + glTexStorage3DMultisample; # introduced=24 + glTexStorage3DMultisampleOES; # introduced=21 + glTexSubImage2D; + glTexSubImage3D; + glTexSubImage3DOES; + glTransformFeedbackVaryings; + glUniform1f; + glUniform1fv; + glUniform1i; + glUniform1iv; + glUniform1ui; + glUniform1uiv; + glUniform2f; + glUniform2fv; + glUniform2i; + glUniform2iv; + glUniform2ui; + glUniform2uiv; + glUniform3f; + glUniform3fv; + glUniform3i; + glUniform3iv; + glUniform3ui; + glUniform3uiv; + glUniform4f; + glUniform4fv; + glUniform4i; + glUniform4iv; + glUniform4ui; + glUniform4uiv; + glUniformBlockBinding; + glUniformMatrix2fv; + glUniformMatrix2x3fv; + glUniformMatrix2x4fv; + glUniformMatrix3fv; + glUniformMatrix3x2fv; + glUniformMatrix3x4fv; + glUniformMatrix4fv; + glUniformMatrix4x2fv; + glUniformMatrix4x3fv; + glUnmapBuffer; + glUnmapBufferOES; + glUseProgram; + glUseProgramStages; # introduced=21 + glValidateProgram; + glValidateProgramPipeline; # introduced=21 + glVertexAttrib1f; + glVertexAttrib1fv; + glVertexAttrib2f; + glVertexAttrib2fv; + glVertexAttrib3f; + glVertexAttrib3fv; + glVertexAttrib4f; + glVertexAttrib4fv; + glVertexAttribBinding; # introduced=21 + glVertexAttribDivisor; + glVertexAttribFormat; # introduced=21 + glVertexAttribI4i; + glVertexAttribI4iv; + glVertexAttribI4ui; + glVertexAttribI4uiv; + glVertexAttribIFormat; # introduced=21 + glVertexAttribIPointer; + glVertexAttribPointer; + glVertexBindingDivisor; # introduced=21 + glViewport; + glWaitSync; + local: + *; +}; diff --git a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt deleted file mode 100644 index 51c6c61782..0000000000 --- a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt +++ /dev/null @@ -1,190 +0,0 @@ -Name - - ANDROID_create_native_client_buffer - -Name Strings - - EGL_ANDROID_create_native_client_buffer - -Contributors - - Craig Donner - -Contact - - Craig Donner, Google Inc. (cdonner 'at' google.com) - -Status - - Draft - -Version - - Version 1, January 19, 2016 - -Number - - EGL Extension #XXX - -Dependencies - - Requires EGL 1.2. - - EGL_ANDROID_image_native_buffer and EGL_KHR_image_base are required. - - This extension is written against the wording of the EGL 1.2 - Specification as modified by EGL_KHR_image_base and - EGL_ANDROID_image_native_buffer. - -Overview - - This extension allows creating an EGLClientBuffer backed by an Android - window buffer (struct ANativeWindowBuffer) which can be later used to - create an EGLImage. - -New Types - - None. - -New Procedures and Functions - -EGLClientBuffer eglCreateNativeClientBufferANDROID( - const EGLint *attrib_list) - -New Tokens - - EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143 - EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001 - EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002 - EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004 - -Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors) - - Add the following to section 2.5.1 "EGLImage Specification" (as modified by - the EGL_KHR_image_base and EGL_ANDROID_image_native_buffer specifications), - below the description of eglCreateImageKHR: - - "The command - - EGLClientBuffer eglCreateNativeClientBufferANDROID( - const EGLint *attrib_list) - - may be used to create an EGLClientBuffer backed by an ANativeWindowBuffer - struct. EGL implementations must guarantee that the lifetime of the - returned EGLClientBuffer is at least as long as the EGLImage(s) it is bound - to, following the lifetime semantics described below in section 2.5.2; the - EGLClientBuffer must be destroyed no earlier than when all of its associated - EGLImages are destroyed by eglDestroyImageKHR. <attrib_list> is a list of - attribute-value pairs which is used to specify the dimensions, format, and - usage of the underlying buffer structure. If <attrib_list> is non-NULL, the - last attribute specified in the list must be EGL_NONE. - - Attribute names accepted in <attrib_list> are shown in Table aaa, - together with the <target> for which each attribute name is valid, and - the default value used for each attribute if it is not included in - <attrib_list>. - - +---------------------------------+----------------------+---------------+ - | Attribute | Description | Default Value | - | | | | - +---------------------------------+----------------------+---------------+ - | EGL_NONE | Marks the end of the | N/A | - | | attribute-value list | | - | EGL_WIDTH | The width of the | 0 | - | | buffer data | | - | EGL_HEIGHT | The height of the | 0 | - | | buffer data | | - | EGL_RED_SIZE | The bits of Red in | 0 | - | | the color buffer | | - | EGL_GREEN_SIZE | The bits of Green in | 0 | - | | the color buffer | | - | EGL_BLUE_SIZE | The bits of Blue in | 0 | - | | the color buffer | | - | EGL_ALPHA_SIZE | The bits of Alpha in | 0 | - | | the color buffer | | - | | buffer data | | - | EGL_NATIVE_BUFFER_USAGE_ANDROID | The usage bits of | 0 | - | | the buffer data | | - +---------------------------------+----------------------+---------------+ - Table aaa. Legal attributes for eglCreateNativeClientBufferANDROID - <attrib_list> parameter. - - The maximum width and height may depend on the amount of available memory, - which may also depend on the format and usage flags. The values of - EGL_RED_SIZE, EGL_GREEN_SIZE, and EGL_BLUE_SIZE must be non-zero and - correspond to a valid pixel format for the implementation. If EGL_ALPHA_SIZE - is non-zero then the combination of all four sizes must correspond to a - valid pixel format for the implementation. The - EGL_NATIVE_BUFFER_USAGE_ANDROID flag may include any of the following bits: - - EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID: Indicates that the - created buffer must have a hardware-protected path to external display - sink. If a hardware-protected path is not available, then either don't - composite only this buffer (preferred) to the external sink, or (less - desirable) do not route the entire composition to the external sink. - - EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID: The buffer will be - used to create a color-renderable texture. - - EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID: The buffer will be used to - create a filterable texture. - - Errors - - If eglCreateNativeClientBufferANDROID fails, NULL will be returned, no - memory will be allocated, and one of the following errors will be - generated: - - * If the value of EGL_WIDTH or EGL_HEIGHT is not positive, the error - EGL_BAD_PARAMETER is generated. - - * If the combination of the values of EGL_RED_SIZE, EGL_GREEN_SIZE, - EGL_BLUE_SIZE, and EGL_ALPHA_SIZE is not a valid pixel format for the - EGL implementation, the error EGL_BAD_PARAMETER is generated. - - * If the value of EGL_NATIVE_BUFFER_ANDROID is not a valid combination - of gralloc usage flags for the EGL implementation, or is incompatible - with the value of EGL_FORMAT, the error EGL_BAD_PARAMETER is - Generated. - -Issues - - 1. Should this extension define what combinations of formats and usage flags - EGL implementations are required to support? - - RESOLVED: Partially. - - The set of valid color combinations is implementation-specific and may - depend on additional EGL extensions, but generally RGB565 and RGBA888 should - be supported. The particular valid combinations for a given Android version - and implementation should be documented by that version. - - 2. Should there be an eglDestroyNativeClientBufferANDROID to destroy the - client buffers created by this extension? - - RESOLVED: No. - - A destroy function would add several complications: - - a) ANativeWindowBuffer is a reference counted object, may be used - outside of EGL. - b) The same buffer may back multiple EGLImages, though this usage may - result in undefined behavior. - c) The interactions between the lifetimes of EGLImages and their - EGLClientBuffers would become needlessly complex. - - Because ANativeWindowBuffer is a reference counted object, implementations - of this extension should ensure the buffer has a lifetime at least as long - as a generated EGLImage (via EGL_ANDROID_image_native_buffer). The simplest - method is to increment the reference count of the buffer in - eglCreateImagKHR, and then decrement it in eglDestroyImageKHR. This should - ensure proper lifetime semantics. - -Revision History - -#2 (Craig Donner, April 15, 2016) - - Set color formats and usage bits explicitly using additional attributes, - and add value for new token EGL_NATIVE_BUFFER_USAGE_ANDROID. - -#1 (Craig Donner, January 19, 2016) - - Initial draft. diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt index 30337ad7a9..b8a9addbde 100644 --- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt +++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt @@ -8,11 +8,19 @@ Name Strings Contributors + Brian Anderson + Dan Stoza Pablo Ceballos + Jesse Hall + Fabien Sanglard Contact + Brian Anderson, Google Inc. (brianderson 'at' google.com) + Dan Stoza, Google Inc. (stoza 'at' google.com) Pablo Ceballos, Google Inc. (pceballos 'at' google.com) + Jesse Hall, Google Inc. (jessehall 'at' google.com) + Fabien Sanglard, Google Inc. (sanglardf 'at' google.com) Status @@ -20,7 +28,7 @@ Status Version - Version 1, May 31, 2016 + Version 8, April 11, 2017 Number @@ -38,8 +46,8 @@ Overview and display of window surfaces. Some examples of how this might be used: - - The display retire time can be used to calculate end-to-end latency of - the entire graphics pipeline. + - The display present time can be used to calculate end-to-end latency + of the entire graphics pipeline. - The queue time and rendering complete time can be used to determine how long the application's rendering took to complete. Likewise, the composition start time and finish time can be used to determine how @@ -57,22 +65,37 @@ New Types New Procedures and Functions + EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, + EGLuint64KHR *frameId); + + EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, + EGLSurface surface, EGLint numTimestamps, + const EGLint *names, EGLnsecsANDROID *values); + EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, - EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, - EGLnsecsANDROID *values); + EGLuint64KHR frameId, EGLint numTimestamps, + const EGLint *timestamps, EGLnsecsANDROID *values); - EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface - surface, EGLint timestamp); + EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, + EGLSurface surface, EGLint timestamp); New Tokens - EGL_TIMESTAMPS_ANDROID 0x314D - EGL_QUEUE_TIME_ANDROID 0x314E - EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F - EGL_COMPOSITION_START_TIME_ANDROID 0x3430 - EGL_COMPOSITION_FINISHED_TIME_ANDROID 0x3431 - EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3432 - EGL_READS_DONE_TIME_ANDROID 0x3433 + EGL_TIMESTAMPS_ANDROID 0x3430 + EGL_COMPOSITE_DEADLINE_ANDROID 0x3431 + EGL_COMPOSITE_INTERVAL_ANDROID 0x3432 + EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433 + EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434 + EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435 + EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436 + EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437 + EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438 + EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439 + EGL_DISPLAY_PRESENT_TIME_ANDROID 0x343A + EGL_DEQUEUE_READY_TIME_ANDROID 0x343B + EGL_READS_DONE_TIME_ANDROID 0x343C + EGL_TIMESTAMP_PENDING_ANDROID -2 + EGL_TIMESTAMP_INVALID_ANDROID -1 Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6 "Surface Attributes", page 43: @@ -82,7 +105,6 @@ Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6 enables timestamp collection, while a value of EGL_FALSE disables it. The initial value is false. If surface is not a window surface this has no effect. - Changes to Chapter 3 of the EGL 1.5 Specification (EGL Functions and Errors) Add a new subsection under Section 3, @@ -91,49 +113,112 @@ Changes to Chapter 3 of the EGL 1.5 Specification (EGL Functions and Errors) The function - EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface - surface, EGLint framesAgo, EGLint numTimestamps, - const EGLint *timestamps, EGLnsecsANDROID *values); + EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, + EGLuint64KHR *frameId); + + Returns an identifier for the next frame to be swapped. The identifier can + be used to correlate a particular eglSwapBuffers with its timestamps in + eglGetFrameTimestampsANDROID. If any error is generated, the function will + return EGL_FALSE. + + The function + + EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, + EGLSurface surface, EGLint numTimestamps, + const EGLint *names, EGLnsecsANDROID *values); + + allows querying anticipated timestamps and durations related to the + composition and display of a window surface. The values are not associated + with a particular frame and can be retrieved before the first swap. + + The eglGetCompositorTimingANDROID function takes an array of names to + query and returns their values in the corresponding indices of the values + array. The possible names that can be queried are: + - EGL_COMPOSITE_DEADLINE_ANDROID - The timestamp of the next time the + compositor will begin composition. This is effectively the deadline + for when the compositor must receive a newly queued frame. + - EGL_COMPOSITE_INTERVAL_ANDROID - The time delta between subsequent + composition events. + - EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID - The time delta between + the start of composition and the expected present time of that + composition. This can be used to estimate the latency of the + actual present time. + + The function - allows querying various timestamps related to the composition and display of - a window surface. + EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, + EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, + const EGLint *timestamps, EGLnsecsANDROID *values); - The framesAgo parameter indicates how many frames before the last posted - frame to query. So a value of zero would indicate that the query is for the - last posted frame. Note that the implementation maintains a limited history - of timestamp data. If a query is made for a frame whose timestamp history - no longer exists then EGL_BAD_ACCESS is generated. If timestamp collection - has not been enabled for the surface then EGL_BAD_SURFACE is generated. - Timestamps for events that will not occur or have not yet occurred will be - zero. Timestamp queries that are not supported will generate an - EGL_BAD_PARAMETER error. If any error is generated the function will return - EGL_FALSE. + allows querying various timestamps related to the composition and display + of specific frames of a window surface. + + The frameId indicates which frame to query. The implementation maintains a + limited history of timestamp data. If a query is made for a frame whose + timestamp history no longer exists then EGL_BAD_ACCESS is generated. If + timestamp collection has not been enabled for the surface then + EGL_BAD_SURFACE is generated. Timestamps for events that might still occur + will have the value EGL_TIMESTAMP_PENDING_ANDROID. Timestamps for events + that did not occur will have the value EGL_TIMESTAMP_INVALID_ANDROID. + Otherwise, the timestamp will be valid and indicate the event has occured. + Timestamp queries that are not supported will generate an EGL_BAD_PARAMETER + error. If any error is generated the function will return EGL_FALSE. + + The application can poll for the timestamp of particular events by calling + eglGetFrameTimestamps over and over without needing to call any other EGL + function between calls. This is true even for the most recently swapped + frame. eglGetFrameTimestamps is thread safe and can be called from a + different thread than the swapping thread. The eglGetFrameTimestampsANDROID function takes an array of timestamps to query and returns timestamps in the corresponding indices of the values array. The possible timestamps that can be queried are: - - EGL_QUEUE_TIME_ANDROID - The time this frame was queued by the - application. + - EGL_REQUESTED_PRESENT_TIME_ANDROID - The time the application + requested this frame be presented. See EGL_ANDROID_presentation_time. + If the application does not request a presentation time explicitly, + this will correspond to buffer's queue time. - EGL_RENDERING_COMPLETE_TIME_ANDROID - The time when all of the application's rendering to the surface was completed. - - EGL_COMPOSITION_START_TIME_ANDROID - The time at which the compositor - began preparing composition for this frame. - - EGL_COMPOSITION_FINISHED_TIME_ANDROID - The time at which the - compositor's rendering work for this frame finished. This will be zero - if composition was handled by the display and the compositor didn't do - any rendering. - - EGL_DISPLAY_RETIRE_TIME_ANDROID - The time at which this frame was - replaced by the next frame on-screen. + - EGL_COMPOSITION_LATCH_TIME_ANDROID - The time when the compositor + selected this frame as the one to use for the next composition. The + latch is the earliest indication that the frame was submitted in time + to be composited. + - EGL_FIRST_COMPOSITION_START_TIME_ANDROID - The first time at which + the compositor began preparing composition for this frame. + - EGL_LAST_COMPOSITION_START_TIME_ANDROID - The last time at which the + compositor began preparing composition for this frame. If this frame + is composited only once, it will have the same value as + EGL_FIRST_COMPOSITION_START_TIME_ANDROID. If the value is not equal, + that indicates the subsequent frame was not submitted in time to be + latched by the compositor. Note: The value may not be updated for + every display refresh if the compositor becomes idle. + - EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID - The time at which + the compositor's rendering work for this frame finished. This will be + zero if composition was handled by the display and the compositor + didn't do any rendering. + - EGL_DISPLAY_PRESENT_TIME_ANDROID - The time at which this frame + started to scan out to the physical display. + - EGL_DEQUEUE_READY_TIME_ANDROID - The time when the buffer became + available for reuse as a buffer the client can target without + blocking. This is generally the point when all read commands of the + buffer have been submitted, but not necessarily completed. - EGL_READS_DONE_TIME_ANDROID - The time at which all reads for the purpose of display/composition were completed for this frame. - Not all implementations may support all off the above timestamp queries. The - function + Not all implementations may support all of the above timestamp queries. The + functions + + EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy, + EGLSurface surface, EGLint name); + + and - EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface - surface, EGLint timestamp); + EGLBoolean eglGetFrameTimestampsSupportedANDROID(EGLDisplay dpy, + EGLSurface surface, EGLint timestamp); - allows querying which timestamps are supported on the implementation." + allows querying which values are supported by the implementations of + eglGetCompositoTimingANDROID and eglGetFrameTimestampsSupportedANDROID + respectively." Issues @@ -141,5 +226,30 @@ Issues Revision History +#8 (Brian Anderson, April 11, 2017) + - Use reserved enumerant values. + +#7 (Brian Anderson, March 21, 2017) + - Differentiate between pending events and events that did not occur. + +#6 (Brian Anderson, March 16, 2017) + - Remove DISPLAY_RETIRE_TIME_ANDROID. + +#5 (Brian Anderson, January 13, 2017) + - Add eglGetCompositorTimingANDROID. + +#4 (Brian Anderson, January 10, 2017) + - Use an absolute frameId rather than a relative framesAgo. + +#3 (Brian Anderson, November 30, 2016) + - Add EGL_COMPOSITION_LATCH_TIME_ANDROID, + EGL_LAST_COMPOSITION_START_TIME_ANDROID, and + EGL_DEQUEUE_READY_TIME_ANDROID. + +#2 (Brian Anderson, July 22, 2016) + - Replace EGL_QUEUE_TIME_ANDROID with EGL_REQUESTED_PRESENT_TIME_ANDROID. + - Add DISPLAY_PRESENT_TIME_ANDROID. + #1 (Pablo Ceballos, May 31, 2016) - Initial draft. + diff --git a/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt new file mode 100644 index 0000000000..772b21a132 --- /dev/null +++ b/opengl/specs/EGL_ANDROID_get_native_client_buffer.txt @@ -0,0 +1,99 @@ +Name + + ANDROID_get_native_client_buffer + +Name Strings + + EGL_ANDROID_get_native_client_buffer + +Contributors + + Craig Donner + +Contact + + Craig Donner, Google Inc. (cdonner 'at' google.com) + +Status + + Draft + +Version + + Version 1.0, January 27, 2017 + +Number + + EGL Extension #XXX + +Dependencies + + Requires EGL 1.2. + + EGL_ANDROID_image_native_buffer and EGL_KHR_image_base are required. + + This extension is written against the wording of the EGL 1.2 + Specification as modified by EGL_KHR_image_base and + EGL_ANDROID_image_native_buffer. + +Overview + + This extension allows creating an EGLClientBuffer from an Android + AHardwareBuffer object which can be later used to create an EGLImage. + +New Types + +struct AHardwareBuffer + +New Procedures and Functions + +EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) + +New Tokens + + None + +Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors) + + Add the following to section 2.5.1 "EGLImage Specification" (as modified by + the EGL_KHR_image_base and EGL_ANDROID_image_native_buffer specifications), + below the description of eglCreateImageKHR: + + "The command + + EGLClientBuffer eglGetNativeClientBufferANDROID( + AHardwareBuffer *buffer) + + may be used to create an EGLClientBuffer from an AHardwareBuffer object. + EGL implementations must guarantee that the lifetime of the returned + EGLClientBuffer is at least as long as the EGLImage(s) it is bound to, + following the lifetime semantics described below in section 2.5.2; the + EGLClientBuffer must be destroyed no earlier than when all of its associated + EGLImages are destroyed by eglDestroyImageKHR. + + Errors + + If eglGetNativeClientBufferANDROID fails, NULL will be returned, no + memory will be allocated, and the following error will be generated: + + * If the value of buffer is NULL, the error EGL_BAD_PARAMETER is + generated. + +Issues + + 1. Should this extension define what particular AHardwareBuffer formats EGL + implementations are required to support? + + RESOLVED: No. + + The set of valid formats is implementation-specific and may depend on + additional EGL extensions. The particular valid combinations for a given + Android version and implementation should be documented by that version. + +Revision History + +#2 (Craig Donner, February 17, 2017) + - Fix typographical errors. + +#1 (Craig Donner, January 27, 2017) + - Initial draft. diff --git a/opengl/specs/README b/opengl/specs/README index f0c024ee66..cba445389d 100644 --- a/opengl/specs/README +++ b/opengl/specs/README @@ -1,15 +1,20 @@ This directory contains OpenGL ES and EGL extension specifications that have -been or are being defined for Android. +been or are being defined for Android. The table below tracks usage of EGL enumerant values that have been reserved for use by Android extensions. +See https://github.com/KhronosGroup/EGL-Registry/blob/master/api/egl.xml +for a list of all enumarant values currently reserved and registered with +Khronos. + Value Extension ----------------- ---------------------------------- +================ ================================== +0x3140 - 0x314F Reserved block +================ ================================== 0x3140 EGL_NATIVE_BUFFER_ANDROID (EGL_ANDROID_image_native_buffer) 0x3141 EGL_PLATFORM_ANDROID_KHR (KHR_platform_android) 0x3142 EGL_RECORDABLE_ANDROID (EGL_ANDROID_recordable) -0x3143 EGL_NATIVE_BUFFER_USAGE_ANDROID (EGL_ANDROID_create_native_client_buffer) 0x3144 EGL_SYNC_NATIVE_FENCE_ANDROID (EGL_ANDROID_native_fence_sync) 0x3145 EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync) 0x3146 EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync) @@ -19,11 +24,23 @@ for use by Android extensions. 0x314A EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop) 0x314B EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop) 0x314C EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh) -0x314D EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x314E EGL_QUEUE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x314F EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3430 EGL_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3431 EGL_COMPOSITION_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3432 EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3433 EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3434 - 0x343F (unused) +0x314D - 0x314F (unused) + + Value Extension +================ ================================== +0x3430 - 0x343F Reserved block +================ ================================== +0x3430 EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3431 EGL_COMPOSITE_DEADLINE_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3432 EGL_COMPOSITE_INTERVAL_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3433 EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3434 EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3435 EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3436 EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3437 EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3438 EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3439 EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x343A EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x343B EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x343C EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x343D - 0x343F (unused) diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk index 80e4867b2e..5620496e17 100644 --- a/opengl/tests/EGLTest/Android.mk +++ b/opengl/tests/EGLTest/Android.mk @@ -12,11 +12,17 @@ LOCAL_SRC_FILES := \ EGL_test.cpp \ LOCAL_SHARED_LIBRARIES := \ + android.hardware.configstore@1.0 \ + android.hardware.configstore-utils \ libEGL \ libcutils \ libbinder \ + libhidlbase \ + libhidltransport \ libutils \ libgui \ + libbase \ + liblog \ LOCAL_C_INCLUDES := \ bionic/libc/private \ diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp index d69a27507e..24b131539a 100644 --- a/opengl/tests/EGLTest/EGL_test.cpp +++ b/opengl/tests/EGLTest/EGL_test.cpp @@ -16,14 +16,44 @@ #include <gtest/gtest.h> +#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> + +#include <configstore/Utils.h> #include <utils/String8.h> #include <EGL/egl.h> #include <gui/Surface.h> +#include <gui/IConsumerListener.h> +#include <gui/IProducerListener.h> +#include <gui/IGraphicBufferConsumer.h> +#include <gui/BufferQueue.h> + +#define PIXEL_FORMAT_FLOAT "EGL_EXT_pixel_format_float" +bool hasEglPixelFormatFloat() { + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + const char* exts = eglQueryString(dpy, EGL_EXTENSIONS); + size_t cropExtLen = strlen(PIXEL_FORMAT_FLOAT); + size_t extsLen = strlen(exts); + bool equal = !strcmp(PIXEL_FORMAT_FLOAT, exts); + bool atStart = !strncmp(PIXEL_FORMAT_FLOAT " ", exts, cropExtLen + 1); + bool atEnd = (cropExtLen + 1) < extsLen && + !strcmp(" " PIXEL_FORMAT_FLOAT, exts + extsLen - (cropExtLen + 1)); + bool inMiddle = strstr(exts, " " PIXEL_FORMAT_FLOAT " "); + return equal || atStart || atEnd || inMiddle; +} namespace android { +#define EGL_UNSIGNED_TRUE static_cast<EGLBoolean>(EGL_TRUE) + +// retrieve wide-color setting from configstore +using namespace android::hardware::configstore; +using namespace android::hardware::configstore::V1_0; + +static bool hasWideColorDisplay = + getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); + class EGLTest : public ::testing::Test { protected: EGLDisplay mEglDisplay; @@ -48,7 +78,7 @@ protected: virtual void TearDown() { EGLBoolean success = eglTerminate(mEglDisplay); - ASSERT_EQ(EGL_TRUE, success); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); } }; @@ -65,20 +95,20 @@ TEST_F(EGLTest, DISABLED_EGLConfigEightBitFirst) { }; success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); - ASSERT_EQ(EGL_TRUE, success); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_GE(numConfigs, 1); EGLint components[3]; success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); - ASSERT_EQ(EGL_TRUE, success); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); - ASSERT_EQ(EGL_TRUE, success); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); - ASSERT_EQ(EGL_TRUE, success); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EXPECT_GE(components[0], 8); @@ -101,9 +131,9 @@ TEST_F(EGLTest, EGLTerminateSucceedsWithRemainingObjects) { EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs)); struct DummyConsumer : public BnConsumerListener { - virtual void onFrameAvailable(const BufferItem& /* item */) {} - virtual void onBuffersReleased() {} - virtual void onSidebandStreamChanged() {} + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} }; // Create a EGLSurface @@ -139,23 +169,23 @@ TEST_F(EGLTest, EGLConfigRGBA8888First) { }; success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); - ASSERT_EQ(EGL_TRUE, success); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); ASSERT_GE(numConfigs, 1); EGLint components[4]; success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); - ASSERT_EQ(EGL_TRUE, success); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); - ASSERT_EQ(EGL_TRUE, success); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); - ASSERT_EQ(EGL_TRUE, success); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]); - ASSERT_EQ(EGL_TRUE, success); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); ASSERT_EQ(EGL_SUCCESS, eglGetError()); EXPECT_GE(components[0], 8); @@ -164,5 +194,75 @@ TEST_F(EGLTest, EGLConfigRGBA8888First) { EXPECT_GE(components[3], 8); } +TEST_F(EGLTest, EGLConfigFP16) { + EGLint numConfigs; + EGLConfig config; + EGLBoolean success; + + if (!hasWideColorDisplay) { + // skip this test if device does not have wide-color display + return; + } + + ASSERT_TRUE(hasEglPixelFormatFloat()); + + EGLint attrs[] = {EGL_SURFACE_TYPE, + EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, + 16, + EGL_GREEN_SIZE, + 16, + EGL_BLUE_SIZE, + 16, + EGL_ALPHA_SIZE, + 16, + EGL_COLOR_COMPONENT_TYPE_EXT, + EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, + EGL_NONE}; + success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(1, numConfigs); + + EGLint components[4]; + + success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + EXPECT_GE(components[0], 16); + EXPECT_GE(components[1], 16); + EXPECT_GE(components[2], 16); + EXPECT_GE(components[3], 16); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + // Create a EGLSurface + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} } diff --git a/opengl/tests/EGLTest/egl_cache_test.cpp b/opengl/tests/EGLTest/egl_cache_test.cpp index c5bf296e49..c974f63c13 100644 --- a/opengl/tests/EGLTest/egl_cache_test.cpp +++ b/opengl/tests/EGLTest/egl_cache_test.cpp @@ -21,9 +21,13 @@ #include <utils/Log.h> +#include <android-base/test_utils.h> + #include "egl_cache.h" #include "egl_display.h" +#include <memory> + namespace android { class EGLCacheTest : public ::testing::Test { @@ -79,23 +83,20 @@ protected: virtual void SetUp() { EGLCacheTest::SetUp(); - - char* tn = tempnam("/sdcard", "EGL_test-cache-"); - mFilename = tn; - free(tn); + mTempFile.reset(new TemporaryFile()); } virtual void TearDown() { - unlink(mFilename.string()); + mTempFile.reset(nullptr); EGLCacheTest::TearDown(); } - String8 mFilename; + std::unique_ptr<TemporaryFile> mTempFile; }; TEST_F(EGLCacheSerializationTest, ReinitializedCacheContainsValues) { uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee }; - mCache->setCacheFilename(mFilename); + mCache->setCacheFilename(&mTempFile->path[0]); mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); mCache->setBlob("abcd", 4, "efgh", 4); mCache->terminate(); diff --git a/opengl/tests/angeles/demo.c b/opengl/tests/angeles/demo.c index 802f3980fa..39d871e968 100644 --- a/opengl/tests/angeles/demo.c +++ b/opengl/tests/angeles/demo.c @@ -666,7 +666,7 @@ static void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, y[2] /= mag; } -#define M(row,col) m[col*4+row] +#define M(row,col) m[(col)*4+(row)] M(0, 0) = x[0]; M(0, 1) = x[1]; M(0, 2) = x[2]; diff --git a/opengl/tests/configdump/configdump.cpp b/opengl/tests/configdump/configdump.cpp index 69b9eb6417..2a945982a9 100644 --- a/opengl/tests/configdump/configdump.cpp +++ b/opengl/tests/configdump/configdump.cpp @@ -18,6 +18,7 @@ #include <stdio.h> #include <EGL/egl.h> +#include <EGL/eglext.h> #define ATTRIBUTE(_attr) { _attr, #_attr } @@ -26,6 +27,7 @@ struct Attribute { char const* name; }; +// clang-format off Attribute attributes[] = { ATTRIBUTE( EGL_BUFFER_SIZE ), ATTRIBUTE( EGL_ALPHA_SIZE ), @@ -60,8 +62,9 @@ Attribute attributes[] = { ATTRIBUTE( EGL_RENDERABLE_TYPE ), ATTRIBUTE( EGL_MATCH_NATIVE_PIXMAP ), ATTRIBUTE( EGL_CONFORMANT ), + ATTRIBUTE( EGL_COLOR_COMPONENT_TYPE_EXT ), }; - +// clang-format on int main(int argc, char** argv) { diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp index cdbf1cfca2..9f8d166c7a 100644 --- a/opengl/tests/gl2_basic/gl2_basic.cpp +++ b/opengl/tests/gl2_basic/gl2_basic.cpp @@ -44,6 +44,11 @@ static void printGLString(const char *name, GLenum s) { fprintf(stderr, "GL %s = %s\n", name, v); } +static void printEGLString(EGLDisplay dpy, const char *name, GLenum s) { + const char *v = (const char *) eglQueryString(dpy, s); + fprintf(stderr, "GL %s = %s\n", name, v); +} + static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { if (returnVal != EGL_TRUE) { fprintf(stderr, "%s() returned %d\n", op, returnVal); @@ -341,6 +346,7 @@ int main(int argc, char** argv) { printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); + printEGLString(dpy, "EGL Extensions", EGL_EXTENSIONS); if(!setupGraphics(w, h)) { fprintf(stderr, "Could not set up graphics.\n"); diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk index 693fba416e..13337c2753 100644 --- a/opengl/tests/hwc/Android.mk +++ b/opengl/tests/hwc/Android.mk @@ -25,6 +25,8 @@ LOCAL_SRC_FILES:= hwcTestLib.cpp LOCAL_C_INCLUDES += system/extras/tests/include \ $(call include-path-for, opengl-tests-includes) \ +LOCAL_STATIC_LIBRARIES := libarect + include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) diff --git a/opengl/tests/hwc/hwcColorEquiv.cpp b/opengl/tests/hwc/hwcColorEquiv.cpp index f1361b8c43..a9bbcb6f5f 100644 --- a/opengl/tests/hwc/hwcColorEquiv.cpp +++ b/opengl/tests/hwc/hwcColorEquiv.cpp @@ -116,7 +116,7 @@ const float defaultEndDelay = 2.0; // Default delay after rendering graphics #define CMD_START_FRAMEWORK "start 2>&1" // Macros -#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array +#define NUMA(a) (sizeof(a) / sizeof((a)[0])) // Num elements in an array #define MEMCLR(addr, size) do { \ memset((addr), 0, (size)); \ } while (0) diff --git a/opengl/tests/hwc/hwcCommit.cpp b/opengl/tests/hwc/hwcCommit.cpp index 6b287e9126..3686dab654 100644 --- a/opengl/tests/hwc/hwcCommit.cpp +++ b/opengl/tests/hwc/hwcCommit.cpp @@ -156,12 +156,12 @@ const struct blendType { #define CMD_START_FRAMEWORK "start 2>&1" // Macros -#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array +#define NUMA(a) (sizeof(a) / sizeof((a)[0])) // Num elements in an array // Local types class Rectangle { public: - Rectangle(uint32_t graphicFormat = defaultFormat, + explicit Rectangle(uint32_t graphicFormat = defaultFormat, HwcTestDim dfDim = HwcTestDim(1, 1), HwcTestDim sDim = HwcTestDim(1, 1)); void setSourceDim(HwcTestDim dim); diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp index 2e2b204b4d..69e56ff59b 100644 --- a/opengl/tests/hwc/hwcRects.cpp +++ b/opengl/tests/hwc/hwcRects.cpp @@ -137,7 +137,7 @@ const struct hwc_rect defaultDisplayFrame = {0, 0, 100, 100}; #define CMD_START_FRAMEWORK "start 2>&1" // Macros -#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array +#define NUMA(a) (sizeof(a) / sizeof((a)[0])) // Num elements in an array // Local types class Rectangle { diff --git a/opengl/tests/hwc/hwcStress.cpp b/opengl/tests/hwc/hwcStress.cpp index 60c29efa4c..1469f7c76d 100644 --- a/opengl/tests/hwc/hwcStress.cpp +++ b/opengl/tests/hwc/hwcStress.cpp @@ -162,7 +162,7 @@ bool eFlag, sFlag, pFlag; #define CMD_STOP_FRAMEWORK "stop 2>&1" #define CMD_START_FRAMEWORK "start 2>&1" -#define NUMA(a) (sizeof(a) / sizeof(a [0])) +#define NUMA(a) (sizeof(a) / sizeof((a)[0])) #define MEMCLR(addr, size) do { \ memset((addr), 0, (size)); \ } while (0) diff --git a/opengl/tests/hwc/hwcTestLib.h b/opengl/tests/hwc/hwcTestLib.h index a942c10e34..922fc1990b 100644 --- a/opengl/tests/hwc/hwcTestLib.h +++ b/opengl/tests/hwc/hwcTestLib.h @@ -71,7 +71,7 @@ class ColorFract { class ColorRGB { public: ColorRGB(): _r(0.0), _g(0.0), _b(0.0) {}; - ColorRGB(float f): _r(f), _g(f), _b(f) {}; // Gray + ColorRGB(float f): _r(f), _g(f), _b(f) {}; // Gray, NOLINT(implicit) ColorRGB(float r, float g, float b): _r(r), _g(g), _b(b) {}; float r(void) const { return _r; } float g(void) const { return _g; } diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk index 4407e7b5c5..ea94bc199f 100644 --- a/opengl/tests/lib/Android.mk +++ b/opengl/tests/lib/Android.mk @@ -24,4 +24,7 @@ LOCAL_C_INCLUDES += system/extras/tests/include \ LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror +LOCAL_SHARED_LIBRARIES += libgui +LOCAL_STATIC_LIBRARIES := libarect + include $(BUILD_STATIC_LIBRARY) diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java index 6caf07655f..e8691bb7f8 100644 --- a/opengl/tools/glgen/src/JniCodeEmitter.java +++ b/opengl/tools/glgen/src/JniCodeEmitter.java @@ -985,6 +985,7 @@ public class JniCodeEmitter { boolean emitExceptionCheck = ((numArrays > 0 || numStrings > 0) && (hasNonConstArg(jfunc, cfunc, nonPrimitiveArgs) || (cfunc.hasPointerArg() && numArrays > 0)) + || (numBufferArgs > 0) || hasCheckTest(cfunc) || hasIfTest(cfunc)) || (stringArgs.size() > 0); @@ -1308,6 +1309,8 @@ public class JniCodeEmitter { out.println(); } else if (jfunc.getArgType(idx).isBuffer()) { + needsExit = needsExit || (!nullAllowed && !isPointerFunc); + String array = numBufferArgs <= 1 ? "_array" : "_" + cfunc.getArgName(cIndex) + "Array"; String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" : @@ -1318,6 +1321,17 @@ public class JniCodeEmitter { out.println(indent + "if (" + cname + "_buf) {"); out.print(indent); } + else + { + out.println(indent + "if (!" + cname + "_buf) {"); + out.println(indent + indent + "_exception = 1;"); + out.println(indent + indent + "_exceptionType = " + + "\"java/lang/IllegalArgumentException\";"); + out.println(indent + indent + "_exceptionMessage = \"" + + cname +" == null\";"); + out.println(indent + indent + "goto exit;"); + out.println(indent + "}"); + } if (isPointerFunc) { out.println(indent + diff --git a/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if b/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if index a5a8968a9a..523bc574be 100644 --- a/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if +++ b/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if @@ -28,6 +28,7 @@ public class EGLExt { public static final int EGL_CONTEXT_MINOR_VERSION_KHR = 0x30FB; public static final int EGL_CONTEXT_FLAGS_KHR = 0x30FC; public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040; + public static final int EGL_RECORDABLE_ANDROID = 0x3142; native private static void _nativeClassInit(); static { diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp new file mode 100644 index 0000000000..3eacf3c3cd --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp @@ -0,0 +1,9 @@ +/* EGLSurface eglCreatePixmapSurface ( EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list ) */ +static jobject +android_eglCreatePixmapSurface + (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jint pixmap, jintArray attrib_list_ref, jint offset) { + jniThrowException(_env, "java/lang/UnsupportedOperationException", + "eglCreatePixmapSurface"); + return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0); +} + diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.java b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.java new file mode 100644 index 0000000000..1750b32f30 --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.java @@ -0,0 +1,11 @@ + // C function EGLSurface eglCreatePixmapSurface ( EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list ) + + @Deprecated + public static native EGLSurface eglCreatePixmapSurface( + EGLDisplay dpy, + EGLConfig config, + int pixmap, + int[] attrib_list, + int offset + ); + diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.nativeReg b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.nativeReg new file mode 100644 index 0000000000..fa260d80d9 --- /dev/null +++ b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.nativeReg @@ -0,0 +1 @@ +{"eglCreatePixmapSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;I[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePixmapSurface }, diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp index 18ec5e3e7e..7062c5751f 100644 --- a/opengl/tools/glgen/stubs/gles11/common.cpp +++ b/opengl/tools/glgen/stubs/gles11/common.cpp @@ -246,6 +246,19 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) { */ static int getNeededCount(GLint pname) { int needed = 1; +#ifdef GL_ES_VERSION_3_0 + // GLES 3.x pnames + switch (pname) { + case GL_MAX_VIEWPORT_DIMS: + needed = 2; + break; + + case GL_PROGRAM_BINARY_FORMATS: + glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &needed); + break; + } +#endif + #ifdef GL_ES_VERSION_2_0 // GLES 2.x pnames switch (pname) { diff --git a/opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.java b/opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.java index c966e11faf..57338c7d31 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.java +++ b/opengl/tools/glgen/stubs/gles11/glGetBufferPointerv.java @@ -1,5 +1,9 @@ // C function void glGetBufferPointerv ( GLenum target, GLenum pname, GLvoid** params ) + /** + * The {@link java.nio.Buffer} instance returned by this method is guaranteed + * to be an instance of {@link java.nio.ByteBuffer}. + */ public static native java.nio.Buffer glGetBufferPointerv( int target, int pname diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp index dd656b60c1..6d42e56163 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp @@ -5,15 +5,16 @@ static jstring android_glGetShaderInfoLog(JNIEnv *_env, jobject, jint shader) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (!infoLen) { - return _env->NewStringUTF(""); + infoLen = 512; } char* buf = (char*) malloc(infoLen); if (buf == NULL) { jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory"); return NULL; } - glGetShaderInfoLog(shader, infoLen, NULL, buf); - jstring result = _env->NewStringUTF(buf); + GLsizei outLen = 0; + glGetShaderInfoLog(shader, infoLen, &outLen, buf); + jstring result = _env->NewStringUTF(outLen == 0 ? "" : buf); free(buf); return result; } diff --git a/opengl/tools/glgen/stubs/gles11/glMapBufferRange.java b/opengl/tools/glgen/stubs/gles11/glMapBufferRange.java index 482ea9981c..7b1966bfb4 100644 --- a/opengl/tools/glgen/stubs/gles11/glMapBufferRange.java +++ b/opengl/tools/glgen/stubs/gles11/glMapBufferRange.java @@ -1,5 +1,9 @@ // C function GLvoid * glMapBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access ) + /** + * The {@link java.nio.Buffer} instance returned by this method is guaranteed + * to be an instance of {@link java.nio.ByteBuffer}. + */ public static native java.nio.Buffer glMapBufferRange( int target, int offset, diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp index f5506baf95..026cb371aa 100644 --- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp +++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp @@ -131,6 +131,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o pointer = _env->CallStaticLongMethod(nioAccessClass, getBasePointerID, buffer); if (pointer != 0L) { + *offset = 0; *array = NULL; return reinterpret_cast<void *>(pointer); } @@ -138,6 +139,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer); if (*array == NULL) { + *offset = 0; return (void*) NULL; } *offset = _env->CallStaticIntMethod(nioAccessClass, diff --git a/opengl/tools/glgen2/registry/egl.xml b/opengl/tools/glgen2/registry/egl.xml index c9384ce1a8..af13395bb1 100755 --- a/opengl/tools/glgen2/registry/egl.xml +++ b/opengl/tools/glgen2/registry/egl.xml @@ -720,6 +720,26 @@ <enum value="0x332D" name="EGL_YUV_PLANE1_TEXTURE_UNIT_NV"/> <enum value="0x332E" name="EGL_YUV_PLANE2_TEXTURE_UNIT_NV"/> <unused start="0x332F" end="0x339F"/> + <enum value="0x3339" name="EGL_COLOR_COMPONENT_TYPE_EXT"/> + <enum value="0x333A" name="EGL_COLOR_COMPONENT_TYPE_FIXED_EXT"/> + <enum value="0x333B" name="EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT"/> + <unused start="0x333C" end="0x333E"/> + <enum value="0x333F" name="EGL_GL_COLORSPACE_BT2020_LINEAR_EXT"/> + <enum value="0x3340" name="EGL_GL_COLORSPACE_BT2020_PQ_EXT"/> + <enum value="0x3341" name="EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT"/> + <enum value="0x3342" name="EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT"/> + <enum value="0x3343" name="EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT"/> + <enum value="0x3344" name="EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT"/> + <enum value="0x3345" name="EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT"/> + <enum value="0x3346" name="EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT"/> + <enum value="0x3347" name="EGL_SMPTE2086_WHITE_POINT_X_EXT"/> + <enum value="0x3348" name="EGL_SMPTE2086_WHITE_POINT_Y_EXT"/> + <enum value="0x3349" name="EGL_SMPTE2086_MAX_LUMINANCE_EXT"/> + <enum value="0x334A" name="EGL_SMPTE2086_MIN_LUMINANCE_EXT"/> + <enum value="50000" name="EGL_METADATA_SCALING_EXT"/> + <unused start="0x334B" end="0x334F"/> + <enum value="0x3350" name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/> + <unused start="0x3351" end="0x339F"/> </enums> <enums namespace="EGL" start="0x33A0" end="0x33AF" vendor="ANGLE" comment="Reserved for Shannon Woods (Bug 13175)"> @@ -762,8 +782,8 @@ <!-- Reservable for future use. To generate a new range, allocate multiples of 16 starting at the lowest available point in this block. --> - <enums namespace="EGL" start="0x3420" end="0x3FFF" vendor="KHR"> - <unused start="0x3420" end="0x3FFF" comment="Reserved for future use"/> + <enums namespace="EGL" start="0x3470" end="0x3FFF" vendor="KHR"> + <unused start="0x3470" end="0x3FFF" comment="Reserved for future use"/> </enums> <enums namespace="EGL" start="0x8F70" end="0x8F7F" vendor="HI" comment="For Mark Callow, Khronos bug 4055. Shared with GL."> @@ -1856,6 +1876,21 @@ <command name="eglQueryDisplayAttribEXT"/> </require> </extension> + <extension name="EGL_EXT_gl_colorspace_bt2020_linear" supported="egl"> + <require> + <enum name="EGL_GL_COLORSPACE_BT2020_LINEAR_EXT"/> + </require> + </extension> + <extension name="EGL_EXT_gl_colorspace_bt2020_pq" supported="egl"> + <require> + <enum name="EGL_GL_COLORSPACE_BT2020_PQ_EXT"/> + </require> + </extension> + <extension name="EGL_EXT_gl_colorspace_scrgb_linear" supported="egl"> + <require> + <enum name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/> + </require> + </extension> <extension name="EGL_EXT_image_dma_buf_import" supported="egl"> <require> <enum name="EGL_LINUX_DMA_BUF_EXT"/> @@ -1952,6 +1987,22 @@ <command name="eglStreamConsumerOutputEXT"/> </require> </extension> + <extension name="EGL_EXT_surface_SMPTE2086_metadata" supported="egl"> + <require> + <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT"/> + <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT"/> + <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT"/> + <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT"/> + <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT"/> + <enum name="EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT"/> + <enum name="EGL_SMPTE2086_WHITE_POINT_X_EXT"/> + <enum name="EGL_SMPTE2086_WHITE_POINT_Y_EXT"/> + <enum name="EGL_SMPTE2086_MAX_LUMINANCE_EXT"/> + <enum name="EGL_SMPTE2086_MIN_LUMINANCE_EXT"/> + <enum name="EGL_METADATA_SCALING_EXT"/> + </require> + </extension> + <extension name="EGL_EXT_swap_buffers_with_damage" supported="egl"> <require> <command name="eglSwapBuffersWithDamageEXT"/> |