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

José Fonseca jose.r.fonseca at gmail.com
Thu Aug 2 10:26:19 PDT 2012


Oh, code is in https://github.com/apitrace/apitrace/tree/egl-image .
I'll merge if you have no objection.

Jose

On Thu, Aug 2, 2012 at 6:25 PM, José Fonseca <jose.r.fonseca at gmail.com> wrote:
> Imre,
>
> I've refactored this change so that instead of lumping image info and
> data into a blob, we simply emit a fake glTexImage2D.
>
> I've been using fake calls in other cases (most notably for user guest
> drivers). I hope to use this trick for GLX_texture_from_pixmap, and
> alike. I also hope one day to make it easier to distinguish fake vs
> real, but's its not urgent.
>
> I tested that this works using mesa demos
> src/egl/opengles1/texture_from_pixmap.c . But I had to tweak the image
> to be a power-of-two -- it looks like EGLImageKHR don't need to be a
> power-of-two size, but regular textures do. A bit confusing.
> Eitherway, I believe this is a problem with your original solution
> too.
>
> Jose
>
> On Tue, Jul 17, 2012 at 1:39 PM, Imre Deak <imre.deak at intel.com> wrote:
>> 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