[PATCH v4 19/19] egl: EGL image trace support
José Fonseca
jose.r.fonseca at gmail.com
Sat Jul 14 00:31:31 PDT 2012
On Thu, Jun 14, 2012 at 4:55 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 | 231 +++++++++++++++++++++++++++++++++++++++++++++
> helpers/eglsize.hpp | 37 +++++++
> helpers/glsize.hpp | 1 -
> retrace/glretrace_egl.cpp | 20 ++++
> specs/eglapi.py | 4 +-
> specs/stdapi.py | 4 +-
Imre,
Looks good overall, but I'd prefer that stdapi.py type system was not
extended to support this. Overriding the behavior of EGLImageKHR
serialization should be done in the egltrace.py/gltrace.py, e.g., by
looking at the argument type, or funtion/arg name, in
serializeArgValue() method. There are several other special cases are
handled this way too.
Jose
> wrappers/CMakeLists.txt | 1 +
> wrappers/egltrace.py | 9 ++
> wrappers/trace.py | 9 ++-
> 9 files changed, 311 insertions(+), 5 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..2c3e13a
> --- /dev/null
> +++ b/helpers/eglsize.cpp
> @@ -0,0 +1,231 @@
> +/*
> + * 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;
> +}
> +
> +struct image_info *
> +get_image_info(EGLImageKHR image)
> +{
> + struct image_info *info;
> +
> + image_map_mutex.lock();
> + info = image_map[image];
> + image_map.erase(info);
> + image_map_mutex.unlock();
> +
> + return info;
> +}
> +
> +void
> +_eglCreateImageKHR_prolog(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_prolog(EGLImageKHR image)
> +{
> + image_map_mutex.lock();
> + image_map.erase(image);
> + image_map_mutex.unlock();
> +
> + free(get_image_info(image));
> +}
> +
> +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..a6fd377
> --- /dev/null
> +++ b/helpers/eglsize.hpp
> @@ -0,0 +1,37 @@
> +/*
> + * 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_prolog(EGLImageKHR image);
> +
> +void
> +_eglCreateImageKHR_prolog(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/helpers/glsize.hpp b/helpers/glsize.hpp
> index 0103ecb..39f1dc9 100644
> --- a/helpers/glsize.hpp
> +++ b/helpers/glsize.hpp
> @@ -813,5 +813,4 @@ _AttribPairList_size(const T *pAttribList, const T terminator = static_cast<T>(0
> return size;
> }
>
> -
> #endif /* _GL_SIZE_HPP_ */
> 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/specs/eglapi.py b/specs/eglapi.py
> index d1ba647..6da9990 100644
> --- a/specs/eglapi.py
> +++ b/specs/eglapi.py
> @@ -356,7 +356,7 @@ eglapi.addFunctions([
> Function(EGLBoolean, "eglUnlockSurfaceKHR", [(EGLDisplay, "display"), (EGLSurface, "surface")]),
>
> # EGL_KHR_image_base
> - Function(EGLImageKHR, "eglCreateImageKHR", [(EGLDisplay, "dpy"), (EGLContext, "ctx"), (EGLenum, "target"), (EGLClientBuffer, "buffer"), (EGLAttribList, "attrib_list")]),
> + Function(EGLImageKHR, "eglCreateImageKHR", [(EGLDisplay, "dpy"), (EGLContext, "ctx"), (EGLenum, "target"), (EGLImageKHR, "buffer"), (EGLAttribList, "attrib_list")]),
> Function(EGLBoolean, "eglDestroyImageKHR", [(EGLDisplay, "dpy"), (EGLImageKHR, "image")]),
>
> # EGL_KHR_reusable_sync
> @@ -392,6 +392,6 @@ eglapi.addFunctions([
> Function(EGLuint64NV, "eglGetSystemTimeNV", [], sideeffects=False),
>
> # GL_OES_EGL_image
> - GlFunction(Void, "glEGLImageTargetTexture2DOES", [(GLenum, "target"), (EGLImageKHR, "image")]),
> + GlFunction(Void, "glEGLImageTargetTexture2DOES", [(GLenum, "target"), (Blob(GLvoid, "_glEGLImageTargetTexture2DOES_size(target, image)", get_ptr="_glEGLImageTargetTexture2DOES_get_ptr(target, image)", put_ptr="_glEGLImageTargetTexture2DOES_put_ptr"), "image")]),
> GlFunction(Void, "glEGLImageTargetRenderbufferStorageOES", [(GLenum, "target"), (EGLImageKHR, "image")]),
> ])
> diff --git a/specs/stdapi.py b/specs/stdapi.py
> index b2bd904..1e74f5d 100644
> --- a/specs/stdapi.py
> +++ b/specs/stdapi.py
> @@ -246,10 +246,12 @@ class Array(Type):
>
> class Blob(Type):
>
> - def __init__(self, type, size):
> + def __init__(self, type, size, get_ptr=None, put_ptr=None):
> Type.__init__(self, type.expr + ' *')
> self.type = type
> self.size = size
> + self.get_ptr = get_ptr
> + self.put_ptr = put_ptr
>
> def visit(self, visitor, *args, **kwargs):
> return visitor.visitBlob(self, *args, **kwargs)
> diff --git a/wrappers/CMakeLists.txt b/wrappers/CMakeLists.txt
> index 461656e..13e8208 100644
> --- a/wrappers/CMakeLists.txt
> +++ b/wrappers/CMakeLists.txt
> @@ -362,6 +362,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 48c15e6..04251a0 100644
> --- a/wrappers/egltrace.py
> +++ b/wrappers/egltrace.py
> @@ -88,6 +88,14 @@ class EglTracer(GlTracer):
> print ' if (_result)'
> print ' gltrace::destroyContext((uintptr_t)ctx);'
>
> +
> + if function.name == 'eglCreateImageKHR':
> + print ' _eglCreateImageKHR_prolog(dpy, ctx, target, buffer,'
> + print ' attrib_list, _result);'
> +
> + if function.name == 'eglDestroyImageKHR':
> + print ' _eglDestroyImageKHR_prolog(image);'
> +
> if __name__ == '__main__':
> print '#include <stdlib.h>'
> print '#include <string.h>'
> @@ -101,6 +109,7 @@ if __name__ == '__main__':
> print
> print '#include "glproc.hpp"'
> print '#include "glsize.hpp"'
> + print '#include "eglsize.hpp"'
> print
>
> api = API()
> diff --git a/wrappers/trace.py b/wrappers/trace.py
> index 749aff3..a1dec83 100644
> --- a/wrappers/trace.py
> +++ b/wrappers/trace.py
> @@ -200,7 +200,14 @@ class ValueSerializer(stdapi.Visitor):
> print ' }'
>
> def visitBlob(self, blob, instance):
> - print ' trace::localWriter.writeBlob(%s, %s);' % (instance, blob.size)
> + print ' const void *_ptr_%s;' % instance
> + if blob.get_ptr:
> + print ' _ptr_%s = %s;' % (instance, blob.get_ptr)
> + else:
> + print ' _ptr_%s = %s;' % (instance, instance)
> + print ' trace::localWriter.writeBlob(_ptr_%s, %s);' % (instance, blob.size)
> + if blob.put_ptr:
> + print ' %s(_ptr_%s);' % (blob.put_ptr, instance)
>
> def visitEnum(self, enum, instance):
> print ' trace::localWriter.writeEnum(&_enum%s_sig, %s);' % (enum.tag, instance)
> --
> 1.7.5.4
>
More information about the apitrace
mailing list