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

Imre Deak imre.deak at intel.com
Thu Aug 2 11:16:53 PDT 2012


Hi,

On Thu, 2012-08-02 at 18:25 +0100, José Fonseca 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 discussed this possibility with Pauli earlier and I think he was right
saying that retracing should show the fact that EGL images are involved.
That should reveal a lot about the underlying problem we are tracing.

> 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.

Hm, I'm not sure what's the reason for this. But my version did a
texture from EGL image too, so the same restrictions apply there.

I will run our test case with your version and get back to you with the
result. I'm also in the process of going through your earlier comments
about the remaining parts of the patchset.

--Imre


> 
> 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
> >
> _______________________________________________
> apitrace mailing list
> apitrace at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/apitrace




More information about the apitrace mailing list