OSDN Git Service

Add the EGL_ANDROID_get_frame_timestamps extension
authorPablo Ceballos <pceballos@google.com>
Tue, 31 May 2016 21:55:42 +0000 (14:55 -0700)
committerPablo Ceballos <pceballos@google.com>
Fri, 8 Jul 2016 18:49:39 +0000 (18:49 +0000)
Change-Id: Ia7d1c10f0b8bd1f2f6dc7dc180764cb1b4fdbf6f

opengl/include/EGL/eglext.h
opengl/libs/EGL/eglApi.cpp
opengl/libs/EGL/egl_object.cpp
opengl/libs/EGL/egl_object.h
opengl/specs/EGL_ANDROID_get_frame_timestamps.txt [new file with mode: 0644]
opengl/specs/README

index bef5f02..2e18698 100644 (file)
@@ -621,6 +621,24 @@ typedef EGLAPI EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDRO
 #define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000
 #endif
 
+#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
+#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);
+#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
+
 #ifdef __cplusplus
 }
 #endif
index e793852..7a0cce4 100644 (file)
@@ -84,6 +84,7 @@ extern char const * const gBuiltinExtensionString =
         "EGL_KHR_swap_buffers_with_damage "
         "EGL_ANDROID_create_native_client_buffer "
         "EGL_ANDROID_front_buffer_auto_refresh "
+        "EGL_ANDROID_get_frame_timestamps "
         ;
 extern char const * const gExtensionString  =
         "EGL_KHR_image "                        // mandatory
@@ -207,6 +208,12 @@ static const extention_map_t sExtensionMap[] = {
             (__eglMustCastToProperFunctionPointerType)&eglGetStreamFileDescriptorKHR },
     { "eglCreateStreamFromFileDescriptorKHR",
             (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR },
+
+    // EGL_ANDROID_get_frame_timestamps
+    { "eglGetFrameTimestampsANDROID",
+            (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampsANDROID },
+    { "eglQueryTimestampSupportedANDROID",
+            (__eglMustCastToProperFunctionPointerType)&eglQueryTimestampSupportedANDROID },
 };
 
 /*
@@ -1196,7 +1203,7 @@ EGLBoolean eglSurfaceAttrib(
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
-    egl_surface_t const * const s = get_surface(surface);
+    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(),
@@ -1205,6 +1212,11 @@ EGLBoolean eglSurfaceAttrib(
             setError(EGL_BAD_SURFACE, EGL_FALSE);
     }
 
+    if (attribute == EGL_TIMESTAMPS_ANDROID) {
+        s->enableTimestamps = value;
+        return EGL_TRUE;
+    }
+
     if (s->cnx->egl.eglSurfaceAttrib) {
         return s->cnx->egl.eglSurfaceAttrib(
                 dp->disp.dpy, s->surface, attribute, value);
@@ -1935,3 +1947,103 @@ EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface,
 
     return EGL_FALSE;
 }
+
+EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
+        EGLint framesAgo, 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;
+    }
+
+    SurfaceRef _s(dp.get(), surface);
+    if (!_s.get()) {
+        setError(EGL_BAD_SURFACE, EGL_FALSE);
+        return EGL_FALSE;
+    }
+
+    egl_surface_t const * const s = get_surface(surface);
+
+    if (!s->enableTimestamps) {
+        setError(EGL_BAD_SURFACE, EGL_FALSE);
+        return EGL_FALSE;
+    }
+
+    nsecs_t* postedTime = nullptr;
+    nsecs_t* acquireTime = nullptr;
+    nsecs_t* refreshStartTime = nullptr;
+    nsecs_t* GLCompositionDoneTime = nullptr;
+    nsecs_t* displayRetireTime = nullptr;
+    nsecs_t* releaseTime = nullptr;
+
+    for (int i = 0; i < numTimestamps; i++) {
+        switch (timestamps[i]) {
+            case EGL_QUEUE_TIME_ANDROID:
+                postedTime = &values[i];
+                break;
+            case EGL_RENDERING_COMPLETE_TIME_ANDROID:
+                acquireTime = &values[i];
+                break;
+            case EGL_COMPOSITION_START_TIME_ANDROID:
+                refreshStartTime = &values[i];
+                break;
+            case EGL_COMPOSITION_FINISHED_TIME_ANDROID:
+                GLCompositionDoneTime = &values[i];
+                break;
+            case EGL_DISPLAY_RETIRE_TIME_ANDROID:
+                displayRetireTime = &values[i];
+                break;
+            case EGL_READS_DONE_TIME_ANDROID:
+                releaseTime = &values[i];
+                break;
+            default:
+                setError(EGL_BAD_PARAMETER, EGL_FALSE);
+                return EGL_FALSE;
+        }
+    }
+
+    status_t ret = native_window_get_frame_timestamps(s->win.get(), framesAgo,
+            postedTime, acquireTime, refreshStartTime, GLCompositionDoneTime,
+            displayRetireTime, releaseTime);
+
+    if (ret != NO_ERROR) {
+        setError(EGL_BAD_ACCESS, EGL_FALSE);
+        return EGL_FALSE;
+    }
+
+    return EGL_TRUE;
+}
+
+EGLBoolean eglQueryTimestampSupportedANDROID(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;
+    }
+
+    SurfaceRef _s(dp.get(), surface);
+    if (!_s.get()) {
+        setError(EGL_BAD_SURFACE, EGL_FALSE);
+        return EGL_FALSE;
+    }
+
+    switch (timestamp) {
+        case EGL_QUEUE_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_READS_DONE_TIME_ANDROID:
+            return EGL_TRUE;
+        default:
+            return EGL_FALSE;
+    }
+}
index 90f27d1..cfecf77 100644 (file)
@@ -68,7 +68,7 @@ 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),
-    connected(true)
+    enableTimestamps(false), connected(true)
 {
     if (win) {
         getDisplay()->onWindowSurfaceCreated();
index 8f3b9cb..97eda4c 100644 (file)
@@ -139,6 +139,7 @@ public:
     EGLConfig config;
     sp<ANativeWindow> win;
     egl_connection_t const* cnx;
+    bool enableTimestamps;
 private:
     bool connected;
     void disconnect();
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
new file mode 100644 (file)
index 0000000..30337ad
--- /dev/null
@@ -0,0 +1,145 @@
+Name
+
+    ANDROID_get_frame_timestamps
+
+Name Strings
+
+    EGL_ANDROID_get_frame_timestamps
+
+Contributors
+
+    Pablo Ceballos
+
+Contact
+
+    Pablo Ceballos, Google Inc. (pceballos 'at' google.com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, May 31, 2016
+
+Number
+
+    EGL Extension #XXX
+
+Dependencies
+
+    Requires EGL 1.2
+
+    This extension is written against the wording of the EGL 1.5 Specification
+
+Overview
+
+    This extension allows querying various timestamps related to the composition
+    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 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
+          long the compositor's rendering work took. In combination these can be
+          used to help determine if the system is GPU or CPU bound.
+
+New Types
+
+    /*
+     * EGLnsecsANDROID is a signed integer type for representing a time in
+     * nanoseconds.
+     */
+    #include <khrplatform.h>
+    typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
+
+New Procedures and Functions
+
+    EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
+            EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps,
+            EGLnsecsANDROID *values);
+
+    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
+
+Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
+"Surface Attributes", page 43:
+
+    If attribute is EGL_TIMESTAMPS_ANDROID, then values specifies whether to
+    enable/disable timestamp collection for this surface. A value of EGL_TRUE
+    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,
+
+    "3.13 Composition and Display Timestamps
+
+    The function
+
+        EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface
+            surface, EGLint framesAgo, EGLint numTimestamps,
+            const EGLint *timestamps, EGLnsecsANDROID *values);
+
+    allows querying various timestamps related to the composition and display of
+    a window surface.
+
+    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.
+
+    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_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_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
+
+        EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface
+            surface, EGLint timestamp);
+
+    allows querying which timestamps are supported on the implementation."
+
+Issues
+
+    None
+
+Revision History
+
+#1 (Pablo Ceballos, May 31, 2016)
+    - Initial draft.
index 8f1eaf3..f0c024e 100644 (file)
@@ -19,4 +19,11 @@ 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 - 0x314F      (unused)
+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)