VIGS: Add framebuffer and temporary texture pool 68/19568/1
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Tue, 15 Apr 2014 11:24:31 +0000 (15:24 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Tue, 15 Apr 2014 11:54:48 +0000 (15:54 +0400)
In order not to waste host GPU resources we now
have 2 OpenGL object pools - for temporary textures
and for framebuffers. These used to be allocated for
every surface, but now we allocate only one object
per distinct format, i.e. one
object per (width, height, format) tuple

Change-Id: Ie63e571045a2477043e8e08da3a50765523e54fc
Signed-off-by: Stanislav Vorobiov <s.vorobiov@samsung.com>
hw/vigs/Makefile.objs
hw/vigs/vigs_gl_backend.c
hw/vigs/vigs_gl_backend.h
hw/vigs/vigs_gl_pool.c [new file with mode: 0644]
hw/vigs/vigs_gl_pool.h [new file with mode: 0644]

index 93f7e3b8d9e7a8bef2f37b88f750b2343788f3ed..d2c4353d9fa124aac3103ba4c286c602f003a9b5 100644 (file)
@@ -11,6 +11,7 @@ obj-y += vigs_utils.o
 obj-y += vigs_vector.o
 obj-y += vigs_ref.o
 obj-y += vigs_fenceman.o
+obj-y += vigs_gl_pool.o
 obj-y += vigs_gl_backend.o
 obj-y += vigs_sw_backend.o
 # GL GLX backend
index db077dbbf3fcf94881dbe66251e502f98a795501..0e16603ae4c5e1eabd29a62c218cad9aa0a19813 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 #include "vigs_gl_backend.h"
+#include "vigs_gl_pool.h"
 #include "vigs_surface.h"
 #include "vigs_plane.h"
 #include "vigs_log.h"
@@ -97,10 +98,6 @@ struct vigs_gl_surface
      * into front buffer.
      *
      * Allocated on first access.
-     *
-     * TODO: Make a global framebuffer pool and use framebuffers from
-     * it. Framebuffer pool must contain one framebuffer per distinct
-     * surface format.
      */
     GLuint fb;
 
@@ -206,6 +203,82 @@ static const char *g_fs_color_source_gl3 =
     "    FragColor = color;\n"
     "}\n";
 
+static GLuint vigs_gl_backend_alloc_tmp_texture(void *user_data,
+                                                uint32_t width,
+                                                uint32_t height,
+                                                vigsp_surface_format format)
+{
+    struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data;
+    GLint tex_internalformat;
+    GLenum tex_format;
+    GLenum tex_type;
+    GLuint tex = 0, cur_tex = 0;
+
+    backend->GenTextures(1, &tex);
+
+    if (!tex) {
+        return 0;
+    }
+
+    switch (format) {
+    case vigsp_surface_bgrx8888:
+    case vigsp_surface_bgra8888:
+        tex_internalformat = GL_RGBA8;
+        tex_format = GL_BGRA;
+        tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+        break;
+    default:
+        assert(false);
+        return 0;
+    }
+
+    backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&cur_tex);
+    backend->BindTexture(GL_TEXTURE_2D, tex);
+
+    /*
+     * Workaround for problem in "Mesa DRI Intel(R) Ivybridge Desktop x86/MMX/SSE2, version 9.0.3":
+     * These lines used to be in 'vigs_gl_backend_init', but it turned out that they must
+     * be called after 'glBindTexture'.
+     */
+    backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+    backend->TexImage2D(GL_TEXTURE_2D, 0, tex_internalformat,
+                        width, height, 0,
+                        tex_format, tex_type,
+                        NULL);
+    backend->BindTexture(GL_TEXTURE_2D, cur_tex);
+
+    return tex;
+}
+
+static void vigs_gl_backend_release_tmp_texture(void *user_data, GLuint id)
+{
+    struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data;
+
+    backend->DeleteTextures(1, &id);
+}
+
+static GLuint vigs_gl_backend_alloc_framebuffer(void *user_data,
+                                                uint32_t width,
+                                                uint32_t height,
+                                                vigsp_surface_format format)
+{
+    struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data;
+    GLuint fb = 0;
+
+    backend->GenFramebuffers(1, &fb);
+
+    return fb;
+}
+
+static void vigs_gl_backend_release_framebuffer(void *user_data, GLuint id)
+{
+    struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data;
+
+    backend->DeleteFramebuffers(1, &id);
+}
+
 static GLuint vigs_gl_create_shader(struct vigs_gl_backend *backend,
                                     const char *source,
                                     GLenum type)
@@ -414,23 +487,22 @@ static void vigs_gl_translate_color(vigsp_color color,
     }
 }
 
-static bool vigs_winsys_gl_surface_create_texture(struct vigs_winsys_gl_surface *ws_sfc,
-                                                  GLuint *tex)
+static bool vigs_winsys_gl_surface_create_texture(struct vigs_winsys_gl_surface *ws_sfc)
 {
     GLuint cur_tex = 0;
 
-    if (*tex) {
+    if (ws_sfc->tex) {
         return true;
     }
 
-    ws_sfc->backend->GenTextures(1, tex);
+    ws_sfc->backend->GenTextures(1, &ws_sfc->tex);
 
-    if (!*tex) {
-        goto fail;
+    if (!ws_sfc->tex) {
+        return false;
     }
 
     ws_sfc->backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&cur_tex);
-    ws_sfc->backend->BindTexture(GL_TEXTURE_2D, *tex);
+    ws_sfc->backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
 
     /*
      * Workaround for problem in "Mesa DRI Intel(R) Ivybridge Desktop x86/MMX/SSE2, version 9.0.3":
@@ -447,9 +519,22 @@ static bool vigs_winsys_gl_surface_create_texture(struct vigs_winsys_gl_surface
     ws_sfc->backend->BindTexture(GL_TEXTURE_2D, cur_tex);
 
     return true;
+}
 
-fail:
-    return false;
+static bool vigs_gl_surface_create_tmp_texture(struct vigs_gl_surface *gl_sfc)
+{
+    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)gl_sfc->base.backend;
+
+    if (gl_sfc->tmp_tex) {
+        return true;
+    }
+
+    gl_sfc->tmp_tex = vigs_gl_pool_alloc(gl_backend->tex_pool,
+                                         gl_sfc->base.ws_sfc->width,
+                                         gl_sfc->base.ws_sfc->height,
+                                         gl_sfc->base.format);
+
+    return gl_sfc->tmp_tex != 0;
 }
 
 static bool vigs_gl_surface_setup_framebuffer(struct vigs_gl_surface *gl_sfc,
@@ -459,7 +544,10 @@ static bool vigs_gl_surface_setup_framebuffer(struct vigs_gl_surface *gl_sfc,
     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)gl_sfc->base.backend;
 
     if (!gl_sfc->fb) {
-        gl_backend->GenFramebuffers(1, &gl_sfc->fb);
+        gl_sfc->fb = vigs_gl_pool_alloc(gl_backend->fb_pool,
+                                        gl_sfc->base.ws_sfc->width,
+                                        gl_sfc->base.ws_sfc->height,
+                                        gl_sfc->base.format);
 
         if (!gl_sfc->fb) {
             return false;
@@ -555,8 +643,7 @@ static GLuint vigs_winsys_gl_surface_get_texture(struct winsys_gl_surface *sfc)
         (has_current ||
         vigs_sfc->backend->make_current(vigs_sfc->backend, true))) {
 
-        vigs_winsys_gl_surface_create_texture(vigs_sfc,
-                                              &vigs_sfc->tex);
+        vigs_winsys_gl_surface_create_texture(vigs_sfc);
 
         if (!has_current) {
             vigs_sfc->backend->make_current(vigs_sfc->backend, false);
@@ -657,11 +744,11 @@ static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc,
         goto out;
     }
 
-    if (!vigs_winsys_gl_surface_create_texture(ws_sfc, &ws_sfc->tex)) {
+    if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
         goto out;
     }
 
-    if (!vigs_winsys_gl_surface_create_texture(ws_sfc, &gl_sfc->tmp_tex)) {
+    if (!vigs_gl_surface_create_tmp_texture(gl_sfc)) {
         goto out;
     }
 
@@ -729,11 +816,11 @@ static void vigs_gl_surface_draw_pixels(struct vigs_surface *sfc,
     GLfloat *tex_coords;
     uint32_t i;
 
-    if (!vigs_winsys_gl_surface_create_texture(ws_sfc, &ws_sfc->tex)) {
+    if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
         goto out;
     }
 
-    if (!vigs_winsys_gl_surface_create_texture(ws_sfc, &gl_sfc->tmp_tex)) {
+    if (!vigs_gl_surface_create_tmp_texture(gl_sfc)) {
         goto out;
     }
 
@@ -821,7 +908,7 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
     GLfloat *vert_coords;
     GLfloat *tex_coords;
 
-    if (!vigs_winsys_gl_surface_create_texture(ws_dst, &ws_dst->tex)) {
+    if (!vigs_winsys_gl_surface_create_texture(ws_dst)) {
         goto out;
     }
 
@@ -829,7 +916,7 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
         VIGS_LOG_WARN("copying garbage ???");
     }
 
-    if (!vigs_winsys_gl_surface_create_texture(ws_src, &ws_src->tex)) {
+    if (!vigs_winsys_gl_surface_create_texture(ws_src)) {
         goto out;
     }
 
@@ -851,7 +938,7 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
          * Feedback loop is possible, use 'tmp_tex' instead.
          */
 
-        if (!vigs_winsys_gl_surface_create_texture(ws_dst, &gl_dst->tmp_tex)) {
+        if (!vigs_gl_surface_create_tmp_texture(gl_dst)) {
             goto out;
         }
 
@@ -971,7 +1058,7 @@ static void vigs_gl_surface_solid_fill(struct vigs_surface *sfc,
     GLfloat colorf[4];
     GLfloat sfc_h;
 
-    if (!vigs_winsys_gl_surface_create_texture(ws_sfc, &ws_sfc->tex)) {
+    if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
         goto out;
     }
 
@@ -1019,10 +1106,16 @@ static void vigs_gl_surface_destroy(struct vigs_surface *sfc)
     vigs_winsys_gl_surface_orphan(ws_sfc);
 
     if (gl_sfc->fb) {
-        gl_backend->DeleteFramebuffers(1, &gl_sfc->fb);
+        vigs_gl_pool_release(gl_backend->fb_pool,
+                             sfc->ws_sfc->width,
+                             sfc->ws_sfc->height,
+                             sfc->format);
     }
     if (gl_sfc->tmp_tex) {
-        gl_backend->DeleteTextures(1, &gl_sfc->tmp_tex);
+        vigs_gl_pool_release(gl_backend->tex_pool,
+                             sfc->ws_sfc->width,
+                             sfc->ws_sfc->height,
+                             sfc->format);
     }
 
     vigs_surface_cleanup(&gl_sfc->base);
@@ -1160,12 +1253,12 @@ static void vigs_gl_backend_composite(struct vigs_surface *surface,
             VIGS_LOG_WARN("compositing garbage (root surface) ???");
         }
 
-        if (!vigs_winsys_gl_surface_create_texture(ws_root_sfc, &ws_root_sfc->tex)) {
+        if (!vigs_winsys_gl_surface_create_texture(ws_root_sfc)) {
             goto out;
         }
     }
 
-    if (!vigs_winsys_gl_surface_create_texture(ws_root_sfc, &gl_root_sfc->tmp_tex)) {
+    if (!vigs_gl_surface_create_tmp_texture(gl_root_sfc)) {
         goto out;
     }
 
@@ -1184,7 +1277,7 @@ static void vigs_gl_backend_composite(struct vigs_surface *surface,
             VIGS_LOG_WARN("compositing garbage (plane %u) ???", i);
         }
 
-        if (!vigs_winsys_gl_surface_create_texture(ws_sfc, &ws_sfc->tex)) {
+        if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
             goto out;
         }
     }
@@ -1378,6 +1471,15 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
         return false;
     }
 
+    gl_backend->tex_pool = vigs_gl_pool_create("tmp_tex",
+                                               &vigs_gl_backend_alloc_tmp_texture,
+                                               &vigs_gl_backend_release_tmp_texture,
+                                               gl_backend);
+    gl_backend->fb_pool = vigs_gl_pool_create("fb",
+                                              &vigs_gl_backend_alloc_framebuffer,
+                                              &vigs_gl_backend_release_framebuffer,
+                                              gl_backend);
+
     if (gl_backend->is_gl_2) {
         const char *tmp = (const char*)gl_backend->GetString(GL_EXTENSIONS);
 
@@ -1521,6 +1623,9 @@ void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend)
             gl_backend->DeleteVertexArrays(1, &gl_backend->vao);
         }
 
+        vigs_gl_pool_destroy(gl_backend->fb_pool);
+        vigs_gl_pool_destroy(gl_backend->tex_pool);
+
         gl_backend->make_current(gl_backend, false);
     }
 
index 68835e3a3f4ab6206a0d065802edbe40ae8a85d7..e761ed196c370555936a7cffa5008397c4c98f8b 100644 (file)
@@ -38,6 +38,7 @@
 #include "winsys_gl.h"
 
 struct work_queue;
+struct vigs_gl_pool;
 
 struct vigs_gl_backend
 {
@@ -142,6 +143,9 @@ struct vigs_gl_backend
      * @}
      */
 
+    struct vigs_gl_pool *tex_pool;
+    struct vigs_gl_pool *fb_pool;
+
     /*
      * General purpose vectors.
      * @{
diff --git a/hw/vigs/vigs_gl_pool.c b/hw/vigs/vigs_gl_pool.c
new file mode 100644 (file)
index 0000000..ca84650
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * vigs
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Stanislav Vorobiov <s.vorobiov@samsung.com>
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "vigs_gl_pool.h"
+#include "vigs_log.h"
+
+struct vigs_gl_pool_key
+{
+    uint32_t width;
+    uint32_t height;
+    vigsp_surface_format format;
+};
+
+struct vigs_gl_pool_value
+{
+    struct vigs_gl_pool *pool;
+
+    GLuint id;
+
+    /*
+     * We don't want to use struct vigs_ref here since
+     * these objects are owned by hash table, i.e. destruction
+     * must be performed from outside when needed.
+     */
+    uint32_t user_count;
+};
+
+static guint vigs_gl_pool_hash(gconstpointer a)
+{
+    const struct vigs_gl_pool_key *key = a;
+
+    return (key->width |
+            (key->height << 13) |
+            ((uint32_t)key->format << 26));
+}
+
+static gboolean vigs_gl_pool_equal(gconstpointer a, gconstpointer b)
+{
+    const struct vigs_gl_pool_key *left = a;
+    const struct vigs_gl_pool_key *right = b;
+
+    if (left->width != right->width) {
+        return FALSE;
+    }
+
+    if (left->height != right->height) {
+        return FALSE;
+    }
+
+    if (left->format != right->format) {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static void vigs_gl_pool_key_destroy(gpointer data)
+{
+    struct vigs_gl_pool_key *key = data;
+
+    g_free(key);
+}
+
+static void vigs_gl_pool_value_destroy(gpointer data)
+{
+    struct vigs_gl_pool_value *value = data;
+
+    assert(value->user_count == 0);
+
+    value->pool->release_func(value->pool->user_data, value->id);
+
+    g_free(value);
+}
+
+struct vigs_gl_pool
+    *vigs_gl_pool_create(const char *name,
+                         vigs_gl_pool_alloc_func alloc_func,
+                         vigs_gl_pool_release_func release_func,
+                         void *user_data)
+{
+    struct vigs_gl_pool *pool;
+
+    pool = g_malloc0(sizeof(*pool));
+
+    strncpy(pool->name, name, sizeof(pool->name)/sizeof(pool->name[0]));
+    pool->name[sizeof(pool->name)/sizeof(pool->name[0]) - 1] = '\0';
+
+    pool->entries = g_hash_table_new_full(vigs_gl_pool_hash,
+                                          vigs_gl_pool_equal,
+                                          vigs_gl_pool_key_destroy,
+                                          vigs_gl_pool_value_destroy);
+
+    pool->alloc_func = alloc_func;
+    pool->release_func = release_func;
+    pool->user_data = user_data;
+
+    return pool;
+}
+
+void vigs_gl_pool_destroy(struct vigs_gl_pool *pool)
+{
+    g_hash_table_destroy(pool->entries);
+
+    g_free(pool);
+}
+
+GLuint vigs_gl_pool_alloc(struct vigs_gl_pool *pool,
+                          uint32_t width,
+                          uint32_t height,
+                          vigsp_surface_format format)
+{
+    struct vigs_gl_pool_key tmp_key;
+    GLuint id;
+    struct vigs_gl_pool_key *key;
+    struct vigs_gl_pool_value *value;
+
+    tmp_key.width = width;
+    tmp_key.height = height;
+    tmp_key.format = format;
+
+    value = g_hash_table_lookup(pool->entries, &tmp_key);
+
+    if (value) {
+        ++value->user_count;
+
+        return value->id;
+    }
+
+    id = pool->alloc_func(pool->user_data, width, height, format);
+
+    if (!id) {
+        return id;
+    }
+
+    key = g_malloc0(sizeof(*key));
+
+    key->width = width;
+    key->height = height;
+    key->format = format;
+
+    value = g_malloc0(sizeof(*value));
+
+    value->pool = pool;
+    value->id = id;
+    value->user_count = 1;
+
+    g_hash_table_insert(pool->entries, key, value);
+
+    VIGS_LOG_TRACE("pool %s: num_entries = %u",
+                   pool->name,
+                   g_hash_table_size(pool->entries));
+
+    return value->id;
+}
+
+void vigs_gl_pool_release(struct vigs_gl_pool *pool,
+                          uint32_t width,
+                          uint32_t height,
+                          vigsp_surface_format format)
+{
+    struct vigs_gl_pool_key tmp_key;
+    struct vigs_gl_pool_value *value;
+
+    tmp_key.width = width;
+    tmp_key.height = height;
+    tmp_key.format = format;
+
+    value = g_hash_table_lookup(pool->entries, &tmp_key);
+
+    assert(value);
+
+    if (!value) {
+        return;
+    }
+
+    assert(value->user_count > 0);
+
+    if (--value->user_count == 0) {
+        g_hash_table_remove(pool->entries, &tmp_key);
+
+        VIGS_LOG_TRACE("pool %s: num_entries = %u",
+                       pool->name,
+                       g_hash_table_size(pool->entries));
+    }
+}
diff --git a/hw/vigs/vigs_gl_pool.h b/hw/vigs/vigs_gl_pool.h
new file mode 100644 (file)
index 0000000..fa00ccf
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * vigs
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Stanislav Vorobiov <s.vorobiov@samsung.com>
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef _QEMU_VIGS_GL_POOL_H
+#define _QEMU_VIGS_GL_POOL_H
+
+#include "vigs_types.h"
+#include <glib.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+typedef GLuint (*vigs_gl_pool_alloc_func)(void */*user_data*/,
+                                          uint32_t /*width*/,
+                                          uint32_t /*height*/,
+                                          vigsp_surface_format /*format*/);
+
+typedef void (*vigs_gl_pool_release_func)(void */*user_data*/,
+                                          GLuint /*id*/);
+
+struct vigs_gl_pool
+{
+    char name[255];
+
+    GHashTable *entries;
+
+    vigs_gl_pool_alloc_func alloc_func;
+
+    vigs_gl_pool_release_func release_func;
+
+    void *user_data;
+};
+
+struct vigs_gl_pool
+    *vigs_gl_pool_create(const char *name,
+                         vigs_gl_pool_alloc_func alloc_func,
+                         vigs_gl_pool_release_func release_func,
+                         void *user_data);
+
+void vigs_gl_pool_destroy(struct vigs_gl_pool *pool);
+
+GLuint vigs_gl_pool_alloc(struct vigs_gl_pool *pool,
+                          uint32_t width,
+                          uint32_t height,
+                          vigsp_surface_format format);
+
+void vigs_gl_pool_release(struct vigs_gl_pool *pool,
+                          uint32_t width,
+                          uint32_t height,
+                          vigsp_surface_format format);
+
+#endif