From b47e44375996667d0dd0b64b3ee0f6fe183ca2c4 Mon Sep 17 00:00:00 2001 From: Stanislav Vorobiov Date: Tue, 15 Apr 2014 15:24:31 +0400 Subject: [PATCH] VIGS: Add framebuffer and temporary texture pool 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 --- hw/vigs/Makefile.objs | 1 + hw/vigs/vigs_gl_backend.c | 163 ++++++++++++++++++++++++++++------- hw/vigs/vigs_gl_backend.h | 4 + hw/vigs/vigs_gl_pool.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++ hw/vigs/vigs_gl_pool.h | 77 +++++++++++++++++ 5 files changed, 427 insertions(+), 29 deletions(-) create mode 100644 hw/vigs/vigs_gl_pool.c create mode 100644 hw/vigs/vigs_gl_pool.h diff --git a/hw/vigs/Makefile.objs b/hw/vigs/Makefile.objs index 93f7e3b..d2c4353 100644 --- a/hw/vigs/Makefile.objs +++ b/hw/vigs/Makefile.objs @@ -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 diff --git a/hw/vigs/vigs_gl_backend.c b/hw/vigs/vigs_gl_backend.c index db077db..0e16603 100644 --- a/hw/vigs/vigs_gl_backend.c +++ b/hw/vigs/vigs_gl_backend.c @@ -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); } diff --git a/hw/vigs/vigs_gl_backend.h b/hw/vigs/vigs_gl_backend.h index 68835e3..e761ed1 100644 --- a/hw/vigs/vigs_gl_backend.h +++ b/hw/vigs/vigs_gl_backend.h @@ -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 index 0000000..ca84650 --- /dev/null +++ b/hw/vigs/vigs_gl_pool.c @@ -0,0 +1,211 @@ +/* + * vigs + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Stanislav Vorobiov + * Jinhyung Jo + * YeongKyoon Lee + * + * 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 index 0000000..fa00ccf --- /dev/null +++ b/hw/vigs/vigs_gl_pool.h @@ -0,0 +1,77 @@ +/* + * vigs + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Stanislav Vorobiov + * Jinhyung Jo + * YeongKyoon Lee + * + * 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 +#include +#include + +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 -- 2.7.4