YaGL: eglBindTexImage/eglReleaseTexImage implemented
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Thu, 4 Jul 2013 10:24:26 +0000 (14:24 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Thu, 4 Jul 2013 10:51:02 +0000 (14:51 +0400)
YaGL: memory leak fixed in onscreen EGLImageKHR

eglBindTexImage/eglReleaseTexImage implemented for
onscreen via texture redirection. For offscreen
it's left unimplemented

Onscreen EGLImageKHR creation code didn't release
reference to image data, this is fixed

20 files changed:
Makefile.target
hw/yagl_apis/egl/yagl_egl_config.c
hw/yagl_apis/egl/yagl_host_egl_calls.c
hw/yagl_apis/egl/yagl_host_egl_calls.h
hw/yagl_apis/gles/yagl_gles_context.c
hw/yagl_apis/gles/yagl_gles_tex_image.c [new file with mode: 0644]
hw/yagl_apis/gles/yagl_gles_tex_image.h [new file with mode: 0644]
hw/yagl_apis/gles/yagl_gles_texture.c
hw/yagl_apis/gles/yagl_gles_texture.h
hw/yagl_apis/gles/yagl_host_gles_calls.c
hw/yagl_backends/egl_offscreen/yagl_egl_offscreen_surface.c
hw/yagl_backends/egl_onscreen/yagl_egl_onscreen_image.c
hw/yagl_backends/egl_onscreen/yagl_egl_onscreen_surface.c
hw/yagl_backends/egl_onscreen/yagl_egl_onscreen_surface.h
hw/yagl_client_context.h
hw/yagl_client_tex_image.c [new file with mode: 0644]
hw/yagl_client_tex_image.h [new file with mode: 0644]
hw/yagl_egl_native_config.c
hw/yagl_egl_native_config.h
hw/yagl_eglb_surface.h

index 49c3d5d4e38c598ba5d1a79cbb081ebf66f1882c..fe8664557e18469714e694e39b3b156f9623ffc1 100755 (executable)
@@ -222,6 +222,7 @@ obj-y += yagl_egl_interface.o
 obj-y += yagl_client_interface.o
 obj-y += yagl_client_context.o
 obj-y += yagl_client_image.o
+obj-y += yagl_client_tex_image.o
 obj-y += yagl_resource.o
 obj-y += yagl_resource_list.o
 obj-y += yagl_object.o
@@ -251,6 +252,7 @@ obj-y += yagl_gles_texture.o
 obj-y += yagl_gles_framebuffer.o
 obj-y += yagl_gles_renderbuffer.o
 obj-y += yagl_gles_image.o
+obj-y += yagl_gles_tex_image.o
 obj-y += yagl_gles_texture_unit.o
 obj-y += yagl_gles_validate.o
 obj-y += yagl_host_gles_calls.o
index 32f7852bbfd2fe257a15ad712dae323ef0afab1c..86cf6339b8259898e416199ba57549f843e8ece8 100644 (file)
@@ -164,6 +164,9 @@ static struct yagl_egl_config
 
     cfg->native.sample_buffers_num = (cfg->native.samples_per_pixel > 0) ? 1 : 0;
 
+    cfg->native.bind_to_texture_rgb = EGL_TRUE;
+    cfg->native.bind_to_texture_rgba = EGL_TRUE;
+
     return cfg;
 }
 
@@ -279,6 +282,8 @@ bool yagl_egl_config_is_chosen_by(const struct yagl_egl_config *cfg,
     YAGL_CHECK_ATTRIB_CAST(caveat, !=);
     YAGL_CHECK_ATTRIB_CAST(native_renderable, !=);
     YAGL_CHECK_ATTRIB_CAST(transparent_type, !=);
+    YAGL_CHECK_ATTRIB_CAST(bind_to_texture_rgb, !=);
+    YAGL_CHECK_ATTRIB_CAST(bind_to_texture_rgba, !=);
 
     /*
      * Mask.
@@ -332,10 +337,10 @@ bool yagl_egl_config_get_attrib(const struct yagl_egl_config *cfg,
         *value = cfg->native.alpha_size;
         break;
     case EGL_BIND_TO_TEXTURE_RGB:
-        *value = EGL_FALSE;
+        *value = cfg->native.bind_to_texture_rgb;
         break;
     case EGL_BIND_TO_TEXTURE_RGBA:
-        *value = EGL_FALSE;
+        *value = cfg->native.bind_to_texture_rgba;
         break;
     case EGL_CONFIG_CAVEAT:
         *value = cfg->native.caveat;
index a9415cf887dac260af3e88a49bb5e173b83fa51f..56a4d81b1cc1f59ede4b7d188da1a8cf9fb7d726 100644 (file)
@@ -529,6 +529,8 @@ bool yagl_host_eglChooseConfig(EGLBoolean* retval,
     dummy.trans_blue_val = EGL_DONT_CARE;
     dummy.transparent_type = EGL_NONE;
     dummy.match_format_khr = EGL_DONT_CARE;
+    dummy.bind_to_texture_rgb = EGL_DONT_CARE;
+    dummy.bind_to_texture_rgba = EGL_DONT_CARE;
 
     if (!yagl_egl_is_attrib_list_empty(attrib_list)) {
         bool has_config_id = false;
@@ -540,8 +542,12 @@ bool yagl_host_eglChooseConfig(EGLBoolean* retval,
             case EGL_MAX_PBUFFER_HEIGHT:
             case EGL_MAX_PBUFFER_PIXELS:
             case EGL_NATIVE_VISUAL_ID:
+                break;
             case EGL_BIND_TO_TEXTURE_RGB:
+                dummy.bind_to_texture_rgb = attrib_list[i + 1];
+                break;
             case EGL_BIND_TO_TEXTURE_RGBA:
+                dummy.bind_to_texture_rgba = attrib_list[i + 1];
                 break;
             case EGL_SURFACE_TYPE:
                 dummy.surface_type = attrib_list[i + 1];
@@ -1071,19 +1077,115 @@ out:
 }
 
 bool yagl_host_eglBindTexImage(EGLBoolean* retval,
-    yagl_host_handle dpy,
-    yagl_host_handle surface,
+    yagl_host_handle dpy_,
+    yagl_host_handle surface_,
     EGLint buffer)
 {
-    YAGL_UNIMPLEMENTED(eglBindTexImage, EGL_FALSE);
+    struct yagl_egl_display *dpy = NULL;
+    struct yagl_egl_surface *surface = NULL;
+
+    YAGL_LOG_FUNC_SET(eglBindTexImage);
+
+    if (!egl_api_ts->context) {
+        YAGL_LOG_WARN("No context");
+        *retval = EGL_TRUE;
+        goto out;
+    }
+
+    *retval = EGL_FALSE;
+
+    if (!yagl_validate_display(dpy_, &dpy)) {
+        goto out;
+    }
+
+    if (!yagl_validate_surface(dpy, surface_, &surface)) {
+        goto out;
+    }
+
+    if (buffer != EGL_BACK_BUFFER) {
+        YAGL_SET_ERR(EGL_BAD_PARAMETER);
+        goto out;
+    }
+
+    if (surface->backend_sfc->type != EGL_PBUFFER_BIT) {
+        YAGL_SET_ERR(EGL_BAD_SURFACE);
+        goto out;
+    }
+
+    if (surface->backend_sfc->attribs.pbuffer.tex_format == EGL_NO_TEXTURE) {
+        YAGL_SET_ERR(EGL_BAD_MATCH);
+        goto out;
+    }
+
+    if (surface->backend_sfc->attribs.pbuffer.tex_target == EGL_NO_TEXTURE) {
+        YAGL_SET_ERR(EGL_BAD_MATCH);
+        goto out;
+    }
+
+    if (!surface->backend_sfc->bind_tex_image(surface->backend_sfc)) {
+        YAGL_SET_ERR(EGL_BAD_ACCESS);
+        goto out;
+    }
+
+    *retval = EGL_TRUE;
+
+out:
+    yagl_egl_surface_release(surface);
+
+    return true;
 }
 
 bool yagl_host_eglReleaseTexImage(EGLBoolean* retval,
-    yagl_host_handle dpy,
-    yagl_host_handle surface,
+    yagl_host_handle dpy_,
+    yagl_host_handle surface_,
     EGLint buffer)
 {
-    YAGL_UNIMPLEMENTED(eglReleaseTexImage, EGL_FALSE);
+    struct yagl_egl_display *dpy = NULL;
+    struct yagl_egl_surface *surface = NULL;
+
+    YAGL_LOG_FUNC_SET(eglReleaseTexImage);
+
+    *retval = EGL_FALSE;
+
+    if (!yagl_validate_display(dpy_, &dpy)) {
+        goto out;
+    }
+
+    if (!yagl_validate_surface(dpy, surface_, &surface)) {
+        goto out;
+    }
+
+    if (buffer != EGL_BACK_BUFFER) {
+        YAGL_SET_ERR(EGL_BAD_PARAMETER);
+        goto out;
+    }
+
+    if (surface->backend_sfc->type != EGL_PBUFFER_BIT) {
+        YAGL_SET_ERR(EGL_BAD_SURFACE);
+        goto out;
+    }
+
+    if (surface->backend_sfc->attribs.pbuffer.tex_format == EGL_NO_TEXTURE) {
+        YAGL_SET_ERR(EGL_BAD_MATCH);
+        goto out;
+    }
+
+    if (surface->backend_sfc->attribs.pbuffer.tex_target == EGL_NO_TEXTURE) {
+        YAGL_SET_ERR(EGL_BAD_MATCH);
+        goto out;
+    }
+
+    if (!surface->backend_sfc->release_tex_image(surface->backend_sfc)) {
+        YAGL_SET_ERR(EGL_BAD_ACCESS);
+        goto out;
+    }
+
+    *retval = EGL_TRUE;
+
+out:
+    yagl_egl_surface_release(surface);
+
+    return true;
 }
 
 bool yagl_host_eglCreateContext(yagl_host_handle* retval,
index de12ed0eb53c821a7e2d187a5bd50fdcd36a1836..fa335e76669d8b8b5294f763640fe45193aa4819 100644 (file)
@@ -55,12 +55,12 @@ bool yagl_host_eglSurfaceAttrib(EGLBoolean* retval,
     EGLint attribute,
     EGLint value);
 bool yagl_host_eglBindTexImage(EGLBoolean* retval,
-    yagl_host_handle dpy,
-    yagl_host_handle surface,
+    yagl_host_handle dpy_,
+    yagl_host_handle surface_,
     EGLint buffer);
 bool yagl_host_eglReleaseTexImage(EGLBoolean* retval,
-    yagl_host_handle dpy,
-    yagl_host_handle surface,
+    yagl_host_handle dpy_,
+    yagl_host_handle surface_,
     EGLint buffer);
 bool yagl_host_eglCreateContext(yagl_host_handle* retval,
     yagl_host_handle dpy_,
index f76e36f10b53d7c11d528c0eeee329d1f2fe0811..3565f2680f9fe557e3dde7c16d4a12a704c8ddf2 100644 (file)
@@ -7,6 +7,7 @@
 #include "yagl_gles_texture_unit.h"
 #include "yagl_gles_validate.h"
 #include "yagl_gles_image.h"
+#include "yagl_gles_tex_image.h"
 #include "yagl_gles_texture.h"
 #include "yagl_log.h"
 #include "yagl_process.h"
@@ -171,6 +172,28 @@ static struct yagl_client_image
     return image ? &image->base : NULL;
 }
 
+static struct yagl_client_tex_image
+    *yagl_gles_context_create_tex_image(struct yagl_client_context *ctx,
+                                        yagl_object_name tex_global_name,
+                                        struct yagl_ref *tex_data)
+{
+    struct yagl_gles_context *gles_ctx = (struct yagl_gles_context*)ctx;
+    struct yagl_gles_texture_target_state *texture_target_state =
+        yagl_gles_context_get_active_texture_target_state(gles_ctx,
+                                                          yagl_gles_texture_target_2d);
+
+    if (!texture_target_state->texture) {
+        return NULL;
+    }
+
+    yagl_gles_tex_image_create(tex_global_name,
+                               tex_data,
+                               texture_target_state->texture);
+
+    return texture_target_state->texture->tex_image ?
+           &texture_target_state->texture->tex_image->base : NULL;
+}
+
 void yagl_gles_context_init(struct yagl_gles_context *ctx,
                             struct yagl_gles_driver *driver)
 {
@@ -178,6 +201,7 @@ void yagl_gles_context_init(struct yagl_gles_context *ctx,
     ctx->base.finish = &yagl_gles_context_finish;
     ctx->base.read_pixels = &yagl_gles_context_read_pixels;
     ctx->base.create_image = &yagl_gles_context_create_image;
+    ctx->base.create_tex_image = &yagl_gles_context_create_tex_image;
 
     ctx->driver = driver;
 
diff --git a/hw/yagl_apis/gles/yagl_gles_tex_image.c b/hw/yagl_apis/gles/yagl_gles_tex_image.c
new file mode 100644 (file)
index 0000000..7d14afe
--- /dev/null
@@ -0,0 +1,68 @@
+#include <GL/gl.h>
+#include "yagl_gles_tex_image.h"
+#include "yagl_gles_texture.h"
+
+static void yagl_gles_tex_image_unbind(struct yagl_client_tex_image *tex_image)
+{
+    struct yagl_gles_tex_image *gles_tex_image =
+        (struct yagl_gles_tex_image*)tex_image;
+    struct yagl_ref *data = tex_image->data;
+
+    assert(gles_tex_image->bound_texture);
+
+    yagl_gles_texture_unset_tex_image(gles_tex_image->bound_texture);
+
+    gles_tex_image->tex_global_name = 0;
+    gles_tex_image->bound_texture = NULL;
+
+    tex_image->data = NULL;
+    yagl_ref_release(data);
+}
+
+static void yagl_gles_tex_image_destroy(struct yagl_ref *ref)
+{
+    struct yagl_gles_tex_image *tex_image = (struct yagl_gles_tex_image*)ref;
+
+    /*
+     * Can't get here if bound to texture.
+     */
+    assert(!tex_image->bound_texture);
+
+    yagl_client_tex_image_cleanup(&tex_image->base);
+
+    g_free(tex_image);
+}
+
+void yagl_gles_tex_image_create(yagl_object_name tex_global_name,
+                                struct yagl_ref *tex_data,
+                                struct yagl_gles_texture *bound_texture)
+{
+    struct yagl_gles_tex_image *tex_image;
+
+    tex_image = g_malloc0(sizeof(*tex_image));
+
+    yagl_client_tex_image_init(&tex_image->base,
+                               &yagl_gles_tex_image_destroy,
+                               tex_data);
+
+    tex_image->base.unbind = &yagl_gles_tex_image_unbind;
+
+    tex_image->tex_global_name = tex_global_name;
+    tex_image->bound_texture = bound_texture;
+
+    yagl_gles_texture_set_tex_image(bound_texture, tex_image);
+}
+
+void yagl_gles_tex_image_acquire(struct yagl_gles_tex_image *tex_image)
+{
+    if (tex_image) {
+        yagl_client_tex_image_acquire(&tex_image->base);
+    }
+}
+
+void yagl_gles_tex_image_release(struct yagl_gles_tex_image *tex_image)
+{
+    if (tex_image) {
+        yagl_client_tex_image_release(&tex_image->base);
+    }
+}
diff --git a/hw/yagl_apis/gles/yagl_gles_tex_image.h b/hw/yagl_apis/gles/yagl_gles_tex_image.h
new file mode 100644 (file)
index 0000000..9efa656
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _QEMU_YAGL_GLES_TEX_IMAGE_H
+#define _QEMU_YAGL_GLES_TEX_IMAGE_H
+
+#include "yagl_types.h"
+#include "yagl_client_tex_image.h"
+
+struct yagl_gles_driver;
+struct yagl_gles_texture;
+
+struct yagl_gles_tex_image
+{
+    struct yagl_client_tex_image base;
+
+    yagl_object_name tex_global_name;
+
+    /*
+     * Weak pointer, no ref.
+     */
+    struct yagl_gles_texture *bound_texture;
+};
+
+/*
+ * Does NOT take ownership of 'bound_texture'.
+ */
+void yagl_gles_tex_image_create(yagl_object_name tex_global_name,
+                                struct yagl_ref *tex_data,
+                                struct yagl_gles_texture *bound_texture);
+
+/*
+ * Passing NULL won't hurt, this is for convenience.
+ */
+void yagl_gles_tex_image_acquire(struct yagl_gles_tex_image *tex_image);
+
+/*
+ * Passing NULL won't hurt, this is for convenience.
+ */
+void yagl_gles_tex_image_release(struct yagl_gles_tex_image *tex_image);
+
+#endif
index e1499cc592063468d68eeb1975ea30584fdec7db..e0a8c2e3f30052966498094bdc7c7dc44e56b42c 100644 (file)
@@ -1,15 +1,34 @@
 #include <GL/gl.h>
 #include "yagl_gles_texture.h"
 #include "yagl_gles_image.h"
+#include "yagl_gles_tex_image.h"
 #include "yagl_gles_driver.h"
 
+static bool yagl_gles_texture_unset_internal(struct yagl_gles_texture *texture)
+{
+    bool ret = false;
+
+    if (texture->image) {
+        yagl_gles_image_release(texture->image);
+        texture->image = NULL;
+        ret = true;
+    }
+
+    if (texture->tex_image) {
+        texture->tex_image->base.unbind(&texture->tex_image->base);
+        assert(!texture->tex_image);
+        texture->tex_image = NULL;
+        ret = true;
+    }
+
+    return ret;
+}
+
 static void yagl_gles_texture_destroy(struct yagl_ref *ref)
 {
     struct yagl_gles_texture *texture = (struct yagl_gles_texture*)ref;
 
-    yagl_gles_image_release(texture->image);
-
-    if (!texture->image) {
+    if (!yagl_gles_texture_unset_internal(texture)) {
         yagl_ensure_ctx();
         texture->driver->DeleteTextures(1, &texture->global_name);
         yagl_unensure_ctx();
@@ -84,9 +103,8 @@ void yagl_gles_texture_set_image(struct yagl_gles_texture *texture,
     }
 
     yagl_gles_image_acquire(image);
-    yagl_gles_image_release(texture->image);
 
-    if (!texture->image) {
+    if (!yagl_gles_texture_unset_internal(texture)) {
         texture->driver->DeleteTextures(1, &texture->global_name);
     }
 
@@ -102,8 +120,7 @@ void yagl_gles_texture_unset_image(struct yagl_gles_texture *texture)
     if (texture->image) {
         GLuint global_name = 0;
 
-        yagl_gles_image_release(texture->image);
-        texture->image = NULL;
+        yagl_gles_texture_unset_internal(texture);
 
         texture->driver->GenTextures(1, &global_name);
 
@@ -113,3 +130,54 @@ void yagl_gles_texture_unset_image(struct yagl_gles_texture *texture)
                                      texture->global_name);
     }
 }
+
+void yagl_gles_texture_set_tex_image(struct yagl_gles_texture *texture,
+                                     struct yagl_gles_tex_image *tex_image)
+{
+    assert(texture->target);
+    assert(tex_image);
+
+    yagl_gles_tex_image_acquire(tex_image);
+
+    if (!yagl_gles_texture_unset_internal(texture)) {
+        texture->driver->DeleteTextures(1, &texture->global_name);
+    }
+
+    texture->global_name = tex_image->tex_global_name;
+    texture->tex_image = tex_image;
+
+    texture->driver->BindTexture(texture->target,
+                                 texture->global_name);
+}
+
+void yagl_gles_texture_unset_tex_image(struct yagl_gles_texture *texture)
+{
+    GLuint global_name = 0;
+
+    assert(texture->tex_image);
+
+    yagl_gles_tex_image_release(texture->tex_image);
+    texture->tex_image = NULL;
+
+    /*
+     * Should ensure context here since this function
+     * can be called when no context is active.
+     */
+    yagl_ensure_ctx();
+    texture->driver->GenTextures(1, &global_name);
+    yagl_unensure_ctx();
+
+    texture->global_name = global_name;
+}
+
+void yagl_gles_texture_release_tex_image(struct yagl_gles_texture *texture)
+{
+    if (texture->tex_image) {
+        yagl_gles_texture_unset_internal(texture);
+
+        assert(texture->global_name);
+
+        texture->driver->BindTexture(texture->target,
+                                     texture->global_name);
+    }
+}
index fc4196bef5b1b15bbb1482c707446e317ef48630..7395ff9e945ea5fcccdc3c3789dfd003898af381 100644 (file)
@@ -8,6 +8,7 @@
 
 struct yagl_gles_driver;
 struct yagl_gles_image;
+struct yagl_gles_tex_image;
 
 struct yagl_gles_texture
 {
@@ -23,6 +24,11 @@ struct yagl_gles_texture
      * Non-NULL if it's an EGLImage target.
      */
     struct yagl_gles_image *image;
+
+    /*
+     * Non-NULL if eglBindTexImage bound.
+     */
+    struct yagl_gles_tex_image *tex_image;
 };
 
 struct yagl_gles_texture
@@ -44,8 +50,22 @@ bool yagl_gles_texture_bind(struct yagl_gles_texture *texture,
 GLenum yagl_gles_texture_get_target(struct yagl_gles_texture *texture);
 
 void yagl_gles_texture_set_image(struct yagl_gles_texture *texture,
-                                  struct yagl_gles_image *image);
+                                 struct yagl_gles_image *image);
 
 void yagl_gles_texture_unset_image(struct yagl_gles_texture *texture);
 
+/*
+ * Helpers for use in yagl_gles_tex_image only.
+ * @{
+ */
+void yagl_gles_texture_set_tex_image(struct yagl_gles_texture *texture,
+                                     struct yagl_gles_tex_image *tex_image);
+
+void yagl_gles_texture_unset_tex_image(struct yagl_gles_texture *texture);
+/*
+ * @}
+ */
+
+void yagl_gles_texture_release_tex_image(struct yagl_gles_texture *texture);
+
 #endif
index 257f5b372930e5205a17e25d2e4285a4c6e0ca7d..632ac0a2b8d54b28cbcbbe3401db6784ac8cd813 100644 (file)
@@ -519,6 +519,12 @@ bool yagl_host_glCompressedTexImage2D(GLenum target,
              * to OES_EGL_image specs.
              */
             yagl_gles_texture_unset_image(tex_target_state->texture);
+
+            /*
+             * This operation should release TexImage according
+             * to eglBindTexImage spec.
+             */
+            yagl_gles_texture_release_tex_image(tex_target_state->texture);
         }
     }
 
@@ -1534,6 +1540,12 @@ bool yagl_host_glTexImage2D(GLenum target,
              * to OES_EGL_image specs.
              */
             yagl_gles_texture_unset_image(tex_target_state->texture);
+
+            /*
+             * This operation should release TexImage according
+             * to eglBindTexImage spec.
+             */
+            yagl_gles_texture_release_tex_image(tex_target_state->texture);
         }
     }
 
index ea78cdc3c9030b93db52619818b9eda45d74d97d..277f3aca4ac6828eb951607450088eb58afafc03 100644 (file)
@@ -139,6 +139,24 @@ static bool yagl_egl_offscreen_surface_copy_buffers(struct yagl_eglb_surface *sf
     return true;
 }
 
+static bool yagl_egl_offscreen_surface_bind_tex_image(struct yagl_eglb_surface *sfc)
+{
+    YAGL_LOG_FUNC_SET(eglBindTexImage);
+
+    YAGL_LOG_WARN("Not supported!");
+
+    return false;
+}
+
+static bool yagl_egl_offscreen_surface_release_tex_image(struct yagl_eglb_surface *sfc)
+{
+    YAGL_LOG_FUNC_SET(eglReleaseTexImage);
+
+    YAGL_LOG_WARN("Not supported!");
+
+    return false;
+}
+
 static void yagl_egl_offscreen_surface_destroy(struct yagl_eglb_surface *sfc)
 {
     struct yagl_egl_offscreen_surface *egl_offscreen_sfc =
@@ -234,6 +252,8 @@ struct yagl_egl_offscreen_surface
     sfc->base.query = &yagl_egl_offscreen_surface_query;
     sfc->base.swap_buffers = &yagl_egl_offscreen_surface_swap_buffers;
     sfc->base.copy_buffers = &yagl_egl_offscreen_surface_copy_buffers;
+    sfc->base.bind_tex_image = &yagl_egl_offscreen_surface_bind_tex_image;
+    sfc->base.release_tex_image = &yagl_egl_offscreen_surface_release_tex_image;
     sfc->base.destroy = &yagl_egl_offscreen_surface_destroy;
 
     YAGL_LOG_FUNC_EXIT(NULL);
index f4368f234c3566f43e5a5727655a18153f7e5ecb..33e61523397693ef51a0acfb31fc43b97f2a84ef 100644 (file)
@@ -73,20 +73,19 @@ struct yagl_egl_onscreen_image
     image_data = g_malloc0(sizeof(*image_data));
 
     yagl_ref_init(&image_data->ref, &yagl_egl_onscreen_image_data_destroy);
+    ws_sfc->base.acquire(&ws_sfc->base);
+    image_data->ws_sfc = ws_sfc;
 
     glegl_image = client_iface->create_image(client_iface,
                                              ws_sfc->get_texture(ws_sfc),
                                              &image_data->ref);
 
+    yagl_ref_release(&image_data->ref);
+
     if (!glegl_image) {
-        yagl_ref_cleanup(&image_data->ref);
-        g_free(image_data);
         goto out;
     }
 
-    ws_sfc->base.acquire(&ws_sfc->base);
-    image_data->ws_sfc = ws_sfc;
-
     image = g_malloc0(sizeof(*image));
 
     yagl_eglb_image_init(&image->base, buffer, &dpy->base);
index f029c194119aa1fb84dd6ed84c885a4f5775639f..cad9ba2b331b627b3944a20288f4c06fd4e74036 100644 (file)
@@ -8,10 +8,34 @@
 #include "yagl_process.h"
 #include "yagl_thread.h"
 #include "yagl_gles_driver.h"
+#include "yagl_client_tex_image.h"
+#include "yagl_client_context.h"
 #include "winsys_gl.h"
 
 YAGL_DECLARE_TLS(struct yagl_egl_onscreen_ts*, egl_onscreen_ts);
 
+struct yagl_egl_onscreen_surface_data
+{
+    struct yagl_ref ref;
+
+    struct yagl_egl_onscreen_surface *sfc;
+};
+
+static void yagl_egl_onscreen_surface_data_destroy(struct yagl_ref *ref)
+{
+    struct yagl_egl_onscreen_surface_data *surface_data =
+        (struct yagl_egl_onscreen_surface_data*)ref;
+
+    if (surface_data->sfc->tex_image) {
+        yagl_client_tex_image_release(surface_data->sfc->tex_image);
+        surface_data->sfc->tex_image = NULL;
+    }
+
+    yagl_ref_cleanup(ref);
+
+    g_free(surface_data);
+}
+
 static void yagl_egl_onscreen_surface_invalidate(struct yagl_eglb_surface *sfc,
                                                  yagl_winsys_id id)
 {
@@ -96,6 +120,53 @@ static bool yagl_egl_onscreen_surface_copy_buffers(struct yagl_eglb_surface *sfc
     return true;
 }
 
+static bool yagl_egl_onscreen_surface_bind_tex_image(struct yagl_eglb_surface *sfc)
+{
+    struct yagl_egl_onscreen_surface *osfc =
+        (struct yagl_egl_onscreen_surface*)sfc;
+    struct yagl_eglb_context *ctx =
+        (egl_onscreen_ts->ctx ? &egl_onscreen_ts->ctx->base : NULL);
+    struct yagl_egl_onscreen_surface_data *surface_data = NULL;
+
+    if (osfc->tex_image) {
+        return false;
+    }
+
+    if (!ctx) {
+        return true;
+    }
+
+    surface_data = g_malloc0(sizeof(*surface_data));
+
+    yagl_ref_init(&surface_data->ref, &yagl_egl_onscreen_surface_data_destroy);
+    surface_data->sfc = osfc;
+
+    osfc->tex_image =
+        ctx->client_ctx->create_tex_image(ctx->client_ctx,
+                                          osfc->ws_sfc->get_texture(osfc->ws_sfc),
+                                          &surface_data->ref);
+
+    yagl_ref_release(&surface_data->ref);
+
+    return osfc->tex_image != NULL;
+}
+
+static bool yagl_egl_onscreen_surface_release_tex_image(struct yagl_eglb_surface *sfc)
+{
+    struct yagl_egl_onscreen_surface *osfc =
+        (struct yagl_egl_onscreen_surface*)sfc;
+
+    if (!osfc->tex_image) {
+        return true;
+    }
+
+    osfc->tex_image->unbind(osfc->tex_image);
+    assert(!osfc->tex_image);
+    osfc->tex_image = NULL;
+
+    return true;
+}
+
 static void yagl_egl_onscreen_surface_destroy(struct yagl_eglb_surface *sfc)
 {
     struct yagl_egl_onscreen_surface *osfc =
@@ -105,6 +176,12 @@ static void yagl_egl_onscreen_surface_destroy(struct yagl_eglb_surface *sfc)
 
     YAGL_LOG_FUNC_ENTER(yagl_egl_onscreen_surface_destroy, NULL);
 
+    if (osfc->tex_image) {
+        osfc->tex_image->unbind(osfc->tex_image);
+        assert(!osfc->tex_image);
+        osfc->tex_image = NULL;
+    }
+
     egl_onscreen->egl_driver->pbuffer_surface_destroy(
         egl_onscreen->egl_driver,
         ((struct yagl_egl_onscreen_display*)sfc->dpy)->native_dpy,
@@ -178,6 +255,8 @@ struct yagl_egl_onscreen_surface
     sfc->base.query = &yagl_egl_onscreen_surface_query;
     sfc->base.swap_buffers = &yagl_egl_onscreen_surface_swap_buffers;
     sfc->base.copy_buffers = &yagl_egl_onscreen_surface_copy_buffers;
+    sfc->base.bind_tex_image = &yagl_egl_onscreen_surface_bind_tex_image;
+    sfc->base.release_tex_image = &yagl_egl_onscreen_surface_release_tex_image;
     sfc->base.destroy = &yagl_egl_onscreen_surface_destroy;
 
     YAGL_LOG_FUNC_EXIT(NULL);
@@ -243,6 +322,8 @@ struct yagl_egl_onscreen_surface
     sfc->base.query = &yagl_egl_onscreen_surface_query;
     sfc->base.swap_buffers = &yagl_egl_onscreen_surface_swap_buffers;
     sfc->base.copy_buffers = &yagl_egl_onscreen_surface_copy_buffers;
+    sfc->base.bind_tex_image = &yagl_egl_onscreen_surface_bind_tex_image;
+    sfc->base.release_tex_image = &yagl_egl_onscreen_surface_release_tex_image;
     sfc->base.destroy = &yagl_egl_onscreen_surface_destroy;
 
     YAGL_LOG_FUNC_EXIT(NULL);
@@ -308,6 +389,8 @@ struct yagl_egl_onscreen_surface
     sfc->base.query = &yagl_egl_onscreen_surface_query;
     sfc->base.swap_buffers = &yagl_egl_onscreen_surface_swap_buffers;
     sfc->base.copy_buffers = &yagl_egl_onscreen_surface_copy_buffers;
+    sfc->base.bind_tex_image = &yagl_egl_onscreen_surface_bind_tex_image;
+    sfc->base.release_tex_image = &yagl_egl_onscreen_surface_release_tex_image;
     sfc->base.destroy = &yagl_egl_onscreen_surface_destroy;
 
     YAGL_LOG_FUNC_EXIT(NULL);
index fe1a4249d057c1d298b705ca99266b7c6e8ec8ff..ae826fad74baec872498d8f7968ee8a5ccb6a028 100644 (file)
@@ -6,6 +6,7 @@
 
 struct yagl_egl_onscreen_display;
 struct yagl_egl_native_config;
+struct yagl_client_tex_image;
 
 struct winsys_gl_surface;
 
@@ -29,6 +30,11 @@ struct yagl_egl_onscreen_surface
      * when this surface is made current for the first time.
      */
     GLuint rb;
+
+    /*
+     * eglBindTexImage result.
+     */
+    struct yagl_client_tex_image *tex_image;
 };
 
 struct yagl_egl_onscreen_surface
index 4c8b2c0d1c838a5d9952933ff066e2289450759a..c97f94c8b420cbc652b7155752e874902e5fbb28 100644 (file)
@@ -3,8 +3,10 @@
 
 #include "yagl_types.h"
 
+struct yagl_ref;
 struct yagl_sharegroup;
 struct yagl_client_image;
+struct yagl_client_tex_image;
 
 struct yagl_client_context
 {
@@ -37,6 +39,11 @@ struct yagl_client_context
     struct yagl_client_image
         *(*create_image)(struct yagl_client_context */*ctx*/);
 
+    struct yagl_client_tex_image
+        *(*create_tex_image)(struct yagl_client_context */*ctx*/,
+                             yagl_object_name /*tex_global_name*/,
+                             struct yagl_ref */*tex_data*/);
+
     /*
      * 'deactivate' is called whenever this context resigns
      * current state for the thread. This is the last
diff --git a/hw/yagl_client_tex_image.c b/hw/yagl_client_tex_image.c
new file mode 100644 (file)
index 0000000..9c8740c
--- /dev/null
@@ -0,0 +1,32 @@
+#include "yagl_client_tex_image.h"
+
+void yagl_client_tex_image_init(struct yagl_client_tex_image *tex_image,
+                                yagl_ref_destroy_func destroy_func,
+                                struct yagl_ref *data)
+{
+    yagl_object_init(&tex_image->base, destroy_func);
+    yagl_ref_acquire(data);
+    tex_image->data = data;
+}
+
+void yagl_client_tex_image_cleanup(struct yagl_client_tex_image *tex_image)
+{
+    if (tex_image->data) {
+        yagl_ref_release(tex_image->data);
+    }
+    yagl_object_cleanup(&tex_image->base);
+}
+
+void yagl_client_tex_image_acquire(struct yagl_client_tex_image *tex_image)
+{
+    if (tex_image) {
+        yagl_object_acquire(&tex_image->base);
+    }
+}
+
+void yagl_client_tex_image_release(struct yagl_client_tex_image *tex_image)
+{
+    if (tex_image) {
+        yagl_object_release(&tex_image->base);
+    }
+}
diff --git a/hw/yagl_client_tex_image.h b/hw/yagl_client_tex_image.h
new file mode 100644 (file)
index 0000000..53d8565
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _QEMU_YAGL_CLIENT_TEX_IMAGE_H
+#define _QEMU_YAGL_CLIENT_TEX_IMAGE_H
+
+#include "yagl_types.h"
+#include "yagl_object.h"
+
+struct yagl_client_tex_image
+{
+    struct yagl_object base;
+
+    struct yagl_ref *data;
+
+    void (*unbind)(struct yagl_client_tex_image */*tex_image*/);
+};
+
+void yagl_client_tex_image_init(struct yagl_client_tex_image *tex_image,
+                                yagl_ref_destroy_func destroy_func,
+                                struct yagl_ref *data);
+
+void yagl_client_tex_image_cleanup(struct yagl_client_tex_image *tex_image);
+
+/*
+ * Helper functions that simply acquire/release yagl_client_tex_image::ref
+ * @{
+ */
+
+/*
+ * Passing NULL won't hurt, this is for convenience.
+ */
+void yagl_client_tex_image_acquire(struct yagl_client_tex_image *tex_image);
+
+/*
+ * Passing NULL won't hurt, this is for convenience.
+ */
+void yagl_client_tex_image_release(struct yagl_client_tex_image *tex_image);
+
+/*
+ * @}
+ */
+
+#endif
index 3669ee2883dcc050a29ba76565e0df078eea6379..facf648b2cc9908b8919fa7ac180e46af0637514 100644 (file)
@@ -16,4 +16,6 @@ void yagl_egl_native_config_init(struct yagl_egl_native_config *cfg)
     cfg->trans_green_val = EGL_DONT_CARE;
     cfg->trans_blue_val = EGL_DONT_CARE;
     cfg->match_format_khr = EGL_DONT_CARE;
+    cfg->bind_to_texture_rgb = EGL_DONT_CARE;
+    cfg->bind_to_texture_rgba = EGL_DONT_CARE;
 }
index 4f402c3afddaec550ef405445f42d53c0213fba2..88cee2b3f77abdaad64270f30977b889596d60b9 100644 (file)
@@ -45,6 +45,8 @@ struct yagl_egl_native_config
     EGLenum conformant;
     EGLint sample_buffers_num;
     EGLint match_format_khr;
+    EGLBoolean bind_to_texture_rgb;
+    EGLBoolean bind_to_texture_rgba;
 };
 
 /*
index 229d7ccf01bcfaad9d6330186d13f10c4be1f2c8..2c4ee4f15f7b94fa89ff2e843e2e35fe02d608c9 100644 (file)
@@ -46,6 +46,17 @@ struct yagl_eglb_surface
 
     bool (*copy_buffers)(struct yagl_eglb_surface */*sfc*/);
 
+    /*
+     * Can be called even when this surface is not current!
+     * @{
+     */
+    bool (*bind_tex_image)(struct yagl_eglb_surface */*sfc*/);
+
+    bool (*release_tex_image)(struct yagl_eglb_surface */*sfc*/);
+    /*
+     * @}
+     */
+
     void (*destroy)(struct yagl_eglb_surface */*sfc*/);
 };