[PATCH v5 10/10] egl: EGL image trace support

Imre Deak imre.deak at intel.com
Tue Jul 17 05:39:20 PDT 2012


Getting the dimension / format of EGL images is not straitghforward.
One way to get these would be through glGetTexLevelParameter, but it's
not supported by GLES. Another way is to attach the EGL image to a
renderbuffer and call glGetRenderbufferParameter on it, but at least
mesa doesn't support attaching images in RGBA_REV format. And that
format happens to be an important one in applications we care about
(like the Android browser). We could also check the parameters of the
underlying native buffer, but these are not exposed through any API (for
either Xpixmaps or Android native buffers)

So the only way I found is to try a non-destructive glCopyTexSubImage2D
with sizes starting from GL_MAX_TEXTURE_SIZE down to 1 and determine the
correct size based on whether this returns an error or not.

Signed-off-by: Imre Deak <imre.deak at intel.com>
---
 helpers/eglsize.cpp       |  260 +++++++++++++++++++++++++++++++++++++++++++++
 helpers/eglsize.hpp       |   64 +++++++++++
 retrace/glretrace_egl.cpp |   20 ++++
 wrappers/CMakeLists.txt   |    1 +
 wrappers/egltrace.py      |   22 ++++
 5 files changed, 367 insertions(+), 0 deletions(-)
 create mode 100644 helpers/eglsize.cpp
 create mode 100644 helpers/eglsize.hpp

diff --git a/helpers/eglsize.cpp b/helpers/eglsize.cpp
new file mode 100644
index 0000000..20dc172
--- /dev/null
+++ b/helpers/eglsize.cpp
@@ -0,0 +1,260 @@
+/*********************************************************************
+ *
+ * Copyright 2012 Intel Corporation
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * 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 Software.
+ *
+ * THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *********************************************************************/
+
+/*
+ * Auxiliary functions to compute the size of array/blob arguments.
+ */
+#include <string.h>
+#include <map>
+
+#include "os_thread.hpp"
+#include "glimports.hpp"
+#include "glproc.hpp"
+#include "eglsize.hpp"
+#include "assert.h"
+
+
+static os::recursive_mutex image_map_mutex;
+static std::map<EGLImageKHR, struct image_info *>image_map;
+
+static int
+bisect_val(int min, int max, bool is_valid_val(int val))
+{
+    bool valid;
+
+    while (1) {
+        int try_val = min + (max - min + 1) / 2;
+
+        valid = is_valid_val(try_val);
+        if (min == max)
+            break;
+
+        if (valid)
+            min = try_val;
+        else
+            max = try_val - 1;
+    }
+
+    return valid ? min : -1;
+}
+
+static bool
+is_valid_width(int val)
+{
+    _glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, val, 1);
+    return _glGetError() == GL_NO_ERROR;
+}
+
+static bool
+is_valid_height(int val)
+{
+    _glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, val);
+    return _glGetError() == GL_NO_ERROR;
+}
+
+static int
+detect_size(int *width_ret, int *height_ret)
+{
+    static GLint max_tex_size;
+    int width;
+    int height;
+
+    if (!max_tex_size)
+        _glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
+
+    width = bisect_val(1, max_tex_size, is_valid_width);
+    if (width < 0)
+        return -1;
+
+    height = bisect_val(1, max_tex_size, is_valid_height);
+    if (height < 0)
+        return -1;
+
+    *width_ret = width;
+    *height_ret = height;
+
+    return 0;
+}
+
+void
+_eglCreateImageKHR_get_image_info(EGLImageKHR image, struct image_info *info)
+{
+    GLuint fbo = 0;
+    GLuint orig_fbo = 0;
+    GLuint texture = 0;
+    GLuint orig_texture;
+    GLenum status;
+
+    _glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)&orig_fbo);
+    _glGenFramebuffers(1, &fbo);
+    _glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+    _glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *)&orig_texture);
+    _glGenTextures(1, &texture);
+    _glBindTexture(GL_TEXTURE_2D, texture);
+
+    _glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+
+    memset(info, sizeof *info, 0);
+
+    _glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                            GL_TEXTURE_2D, texture, 0);
+    status = _glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (status == GL_FRAMEBUFFER_COMPLETE) {
+        if (detect_size(&info->width, &info->height) != 0)
+            os::log("%s: can't detect image size\n", __func__);
+    } else {
+        os::log("%s: error: %x\n", __func__, status);
+    }
+
+    /* Don't leak errors to the traced application. */
+    (void)_glGetError();
+
+    _glBindTexture(GL_TEXTURE_2D, orig_texture);
+    _glDeleteTextures(1, &texture);
+
+    _glBindFramebuffer(GL_FRAMEBUFFER, orig_fbo);
+    _glDeleteFramebuffers(1, &fbo);
+
+    return;
+}
+
+static struct image_info *
+get_image_info(EGLImageKHR image)
+{
+    struct image_info *info;
+
+    image_map_mutex.lock();
+    info = image_map[image];
+    image_map_mutex.unlock();
+
+    return info;
+}
+
+void
+_eglCreateImageKHR_epilog(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+                            EGLClientBuffer buffer, const EGLint *attrib_list,
+                            EGLImageKHR image)
+{
+    struct image_info *info;
+
+    info = (struct image_info *)malloc(sizeof *info);
+    _eglCreateImageKHR_get_image_info(image, info);
+
+    image_map_mutex.lock();
+    assert(image_map.find(image) == image_map.end());
+    image_map[image] = info;
+    image_map_mutex.unlock();
+}
+
+void
+_eglDestroyImageKHR_epilog(EGLImageKHR image)
+{
+    struct image_info *info;
+
+    info = get_image_info(image);
+
+    image_map_mutex.lock();
+    image_map.erase(image);
+    image_map_mutex.unlock();
+
+    free(info);
+}
+
+void
+get_texture_2d_image(struct image_blob *blob)
+{
+    GLuint fbo = 0;
+    GLint prev_fbo = 0;
+    GLint texture;
+    GLenum status;
+
+    _glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture);
+    if (!texture)
+        return;
+
+    _glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo);
+    _glGenFramebuffers(1, &fbo);
+    _glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+    _glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+                            texture, 0);
+    status = _glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (status != GL_FRAMEBUFFER_COMPLETE)
+        os::log("%s: error: %d\n", __func__, status);
+    _glReadPixels(0, 0, blob->info.width, blob->info.height, GL_RGBA,
+                  GL_UNSIGNED_BYTE, blob->data);
+    /* Don't leak errors to the traced application. */
+    (void)_glGetError();
+
+    _glBindFramebuffer(GL_FRAMEBUFFER, prev_fbo);
+    _glDeleteFramebuffers(1, &fbo);
+}
+
+size_t
+_glEGLImageTargetTexture2DOES_size(GLint target, EGLImageKHR image)
+{
+    struct image_info *info;
+    size_t size;
+
+    info = get_image_info(image);
+    size = sizeof(struct image_blob) - 1;
+    /* We always read out the pixels in RGBA format */
+    size += info->width * info->height * 4;
+
+    return size;
+}
+
+void *
+_glEGLImageTargetTexture2DOES_get_ptr(GLenum target, EGLImageKHR image)
+{
+    GLuint tex;
+    GLuint bound_tex;
+    size_t image_blob_size = _glEGLImageTargetTexture2DOES_size(target, image);
+    struct image_blob *blob;
+    struct image_info *info;
+
+    _glGenTextures(1, &tex);
+    _glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *)&bound_tex);
+    _glBindTexture(GL_TEXTURE_2D, tex);
+    _glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+    blob = (struct image_blob *)malloc(image_blob_size);
+    info = get_image_info(image);
+    blob->info = *info;
+    get_texture_2d_image(blob);
+    _glBindTexture(GL_TEXTURE_2D, bound_tex);
+    _glDeleteBuffers(1, &tex);
+
+    return (void *)blob;
+}
+
+void
+_glEGLImageTargetTexture2DOES_put_ptr(const void *buffer)
+{
+    free((void *)buffer);
+}
+
diff --git a/helpers/eglsize.hpp b/helpers/eglsize.hpp
new file mode 100644
index 0000000..edb2fa6
--- /dev/null
+++ b/helpers/eglsize.hpp
@@ -0,0 +1,64 @@
+
+/*********************************************************************
+ *
+ * Copyright 2012 Intel Corporation
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * 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 Software.
+ *
+ * THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ *********************************************************************/
+
+/*
+ * Auxiliary functions to compute the size of array/blob arguments.
+ */
+#ifndef _EGLSIZE_HPP_
+#define _EGLSIZE_HPP_
+
+struct image_info
+{
+    int width;
+    int height;
+};
+
+struct image_blob
+{
+    struct image_info info;
+    char data[1];
+};
+
+void
+_eglDestroyImageKHR_epilog(EGLImageKHR image);
+
+void
+_eglCreateImageKHR_epilog(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+                            EGLClientBuffer buffer, const EGLint *attrib_list,
+                            EGLImageKHR image);
+
+size_t
+_glEGLImageTargetTexture2DOES_size(GLint target, EGLImageKHR image);
+
+void *
+_glEGLImageTargetTexture2DOES_get_ptr(GLenum target, EGLImageKHR image);
+
+void
+_glEGLImageTargetTexture2DOES_put_ptr(const void *buffer);
+
+#endif
diff --git a/retrace/glretrace_egl.cpp b/retrace/glretrace_egl.cpp
index 4603b9f..048c061 100644
--- a/retrace/glretrace_egl.cpp
+++ b/retrace/glretrace_egl.cpp
@@ -33,6 +33,7 @@
 #include "glretrace.hpp"
 #include "os.hpp"
 #include "os_thread.hpp"
+#include "eglsize.hpp"
 
 #ifndef EGL_OPENGL_ES_API
 #define EGL_OPENGL_ES_API		0x30A0
@@ -266,6 +267,23 @@ static void retrace_eglSwapBuffers(trace::Call &call) {
     }
 }
 
+static void retrace_glEGLImageTargetTexture2DOES(trace::Call &call)
+{
+    EGLenum target = call.arg(0).toUInt();
+    struct image_blob *iblob;
+    struct image_info *info;
+
+    if (target != GL_TEXTURE_2D) {
+        os::log("%s: target %d not supported\n", __func__, target);
+        return;
+    }
+    iblob = static_cast<struct image_blob *>((call.arg(1)).toPointer());
+    info = &iblob->info;
+
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, info->width, info->height, 0,
+                 GL_RGBA, GL_UNSIGNED_BYTE, iblob->data);
+}
+
 const retrace::Entry egl_callbacks[] = {
     {"eglGetError", &retrace::ignore},
     {"eglGetDisplay", &retrace::ignore},
@@ -301,6 +319,8 @@ const retrace::Entry egl_callbacks[] = {
     {"eglSwapBuffers", &retrace_eglSwapBuffers},
     //{"eglCopyBuffers", &retrace::ignore},
     {"eglGetProcAddress", &retrace::ignore},
+    {"eglCreateImageKHR", &retrace::ignore},
+    {"glEGLImageTargetTexture2DOES", &retrace_glEGLImageTargetTexture2DOES},
     {NULL, NULL},
 };
 
diff --git a/wrappers/CMakeLists.txt b/wrappers/CMakeLists.txt
index c179ee1..4a8e5fd 100644
--- a/wrappers/CMakeLists.txt
+++ b/wrappers/CMakeLists.txt
@@ -379,6 +379,7 @@ if (ENABLE_EGL AND NOT WIN32 AND NOT APPLE)
         egltrace.cpp
         glcaps.cpp
         gltrace_state.cpp
+        ${CMAKE_SOURCE_DIR}/helpers/eglsize.cpp
     )
 
     add_dependencies (egltrace glproc)
diff --git a/wrappers/egltrace.py b/wrappers/egltrace.py
index 32f29bd..b21b5f9 100644
--- a/wrappers/egltrace.py
+++ b/wrappers/egltrace.py
@@ -89,6 +89,27 @@ class EglTracer(GlTracer):
             print '        gltrace::releaseContext((uintptr_t)ctx);'
             print '    }'
 
+        if function.name == 'eglCreateImageKHR':
+            print '    _eglCreateImageKHR_epilog(dpy, ctx, target, buffer,'
+            print '                              attrib_list, _result);'
+
+        if function.name == 'eglDestroyImageKHR':
+            print '    _eglDestroyImageKHR_epilog(image);'
+
+    def serializeArgValue(self, function, arg):
+        if function.name == 'glEGLImageTargetTexture2DOES' and \
+          arg.name == 'image':
+            print '    GLsizei blob_size;'
+            print '    GLvoid *blob_ptr;'
+            print '    blob_size = _glEGLImageTargetTexture2DOES_size(target, image);'
+            print '    blob_ptr = _glEGLImageTargetTexture2DOES_get_ptr(target, image);'
+            print '    trace::localWriter.writeBlob(blob_ptr, blob_size);'
+            print '    _glEGLImageTargetTexture2DOES_put_ptr(blob_ptr);'
+
+            return
+
+        GlTracer.serializeArgValue(self, function, arg)
+
 if __name__ == '__main__':
     print '#include <stdlib.h>'
     print '#include <string.h>'
@@ -102,6 +123,7 @@ if __name__ == '__main__':
     print
     print '#include "glproc.hpp"'
     print '#include "glsize.hpp"'
+    print '#include "eglsize.hpp"'
     print
     
     api = API()
-- 
1.7.5.4



More information about the apitrace mailing list