VIGS: Using ARB_sync instead of glFinish when possible
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Thu, 27 Dec 2012 12:49:51 +0000 (16:49 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Mon, 15 Apr 2013 11:24:18 +0000 (15:24 +0400)
hw/vigs_gl_backend.c
hw/vigs_gl_backend.h
hw/vigs_gl_backend_glx.c
hw/vigs_gl_backend_wgl.c

index b92b62d..b9a3874 100644 (file)
@@ -84,6 +84,22 @@ struct vigs_gl_surface
      * Allocated on first access.
      */
     GLuint tmp_tex;
+
+    /*
+     * Fence that gets inserted into GL stream
+     * that comes from windowing system.
+     *
+     * 0 if no GL commands are pending.
+     */
+    GLsync fence_2d;
+
+    /*
+     * Fence that gets inserted into GL stream
+     * that comes from 3D renderer.
+     *
+     * 0 if no GL commands are pending.
+     */
+    GLsync fence_3d;
 };
 
 static __inline struct vigs_winsys_gl_surface
@@ -181,6 +197,70 @@ static void vigs_gl_surface_setup_framebuffer(struct vigs_gl_surface *gl_sfc)
     gl_backend->Disable(GL_BLEND);
 }
 
+static void vigs_gl_surface_set_fence_2d(struct vigs_gl_surface *gl_sfc)
+{
+    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)gl_sfc->base.backend;
+
+    if (!gl_backend->has_arb_sync) {
+        gl_backend->Finish();
+        return;
+    }
+
+    if (gl_sfc->fence_2d) {
+        gl_backend->DeleteSync(gl_sfc->fence_2d);
+    }
+
+    gl_sfc->fence_2d = gl_backend->FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+    gl_backend->Flush();
+}
+
+static void vigs_gl_surface_wait_fence_2d(struct vigs_gl_surface *gl_sfc)
+{
+    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)gl_sfc->base.backend;
+
+    if (!gl_backend->has_arb_sync) {
+        return;
+    }
+
+    if (gl_sfc->fence_2d) {
+        gl_backend->WaitSync(gl_sfc->fence_2d, 0, GL_TIMEOUT_IGNORED);
+        gl_backend->DeleteSync(gl_sfc->fence_2d);
+        gl_sfc->fence_2d = 0;
+    }
+}
+
+static void vigs_gl_surface_set_fence_3d(struct vigs_gl_surface *gl_sfc)
+{
+    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)gl_sfc->base.backend;
+
+    if (!gl_backend->has_arb_sync) {
+        gl_backend->Finish();
+        return;
+    }
+
+    if (gl_sfc->fence_3d) {
+        gl_backend->DeleteSync(gl_sfc->fence_3d);
+    }
+
+    gl_sfc->fence_3d = gl_backend->FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+    gl_backend->Flush();
+}
+
+static void vigs_gl_surface_wait_fence_3d(struct vigs_gl_surface *gl_sfc)
+{
+    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)gl_sfc->base.backend;
+
+    if (!gl_backend->has_arb_sync) {
+        return;
+    }
+
+    if (gl_sfc->fence_3d) {
+        gl_backend->WaitSync(gl_sfc->fence_3d, 0, GL_TIMEOUT_IGNORED);
+        gl_backend->DeleteSync(gl_sfc->fence_3d);
+        gl_sfc->fence_3d = 0;
+    }
+}
+
 /*
  * @}
  */
@@ -259,6 +339,8 @@ static void vigs_winsys_gl_surface_swap_buffers(struct winsys_gl_surface *sfc)
         return;
     }
 
+    vigs_gl_surface_wait_fence_2d(vigs_sfc->parent);
+
     vigs_sfc->backend->GetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&cur_fb);
 
     vigs_sfc->backend->BindFramebuffer(GL_READ_FRAMEBUFFER,
@@ -276,7 +358,7 @@ static void vigs_winsys_gl_surface_swap_buffers(struct winsys_gl_surface *sfc)
     vigs_sfc->backend->BindFramebuffer(GL_FRAMEBUFFER,
                                        cur_fb);
 
-    vigs_sfc->backend->Finish();
+    vigs_gl_surface_set_fence_3d(vigs_sfc->parent);
 
     vigs_sfc->parent->base.is_dirty = true;
 }
@@ -300,6 +382,8 @@ static void vigs_winsys_gl_surface_copy_buffers(uint32_t width,
         return;
     }
 
+    vigs_gl_surface_wait_fence_2d(vigs_target->parent);
+
     vigs_target->backend->GetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&cur_fb);
 
     vigs_target->backend->BindFramebuffer(GL_READ_FRAMEBUFFER,
@@ -317,7 +401,7 @@ static void vigs_winsys_gl_surface_copy_buffers(uint32_t width,
     vigs_target->backend->BindFramebuffer(GL_FRAMEBUFFER,
                                           cur_fb);
 
-    vigs_target->backend->Finish();
+    vigs_gl_surface_set_fence_3d(vigs_target->parent);
 
     vigs_target->parent->base.is_dirty = true;
 }
@@ -420,6 +504,8 @@ static void vigs_gl_surface_update(struct vigs_surface *sfc,
         goto out;
     }
 
+    vigs_gl_surface_wait_fence_3d(gl_sfc);
+
     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_sfc->fb);
 
     vigs_gl_surface_setup_framebuffer(gl_sfc);
@@ -436,7 +522,7 @@ static void vigs_gl_surface_update(struct vigs_surface *sfc,
                            ws_sfc->tex_type,
                            data);
 
-    gl_backend->Finish();
+    vigs_gl_surface_set_fence_2d(gl_sfc);
 
     sfc->is_dirty = false;
 
@@ -492,6 +578,8 @@ static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc,
         goto out;
     }
 
+    vigs_gl_surface_wait_fence_3d(gl_sfc);
+
     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_sfc->fb);
 
     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
@@ -549,6 +637,9 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
     src_w = gl_src->base.width;
     src_h = gl_src->base.height;
 
+    vigs_gl_surface_wait_fence_3d(gl_src);
+    vigs_gl_surface_wait_fence_3d(gl_dst);
+
     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_dst->fb);
 
     vigs_gl_surface_setup_framebuffer(gl_dst);
@@ -683,7 +774,7 @@ static void vigs_gl_surface_copy(struct vigs_surface *dst,
     gl_backend->DisableClientState(GL_TEXTURE_COORD_ARRAY);
     gl_backend->DisableClientState(GL_VERTEX_ARRAY);
 
-    gl_backend->Finish();
+    vigs_gl_surface_set_fence_2d(gl_dst);
 
     gl_dst->base.is_dirty = true;
 
@@ -716,6 +807,8 @@ static void vigs_gl_surface_solid_fill(struct vigs_surface *sfc,
         goto out;
     }
 
+    vigs_gl_surface_wait_fence_3d(gl_sfc);
+
     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_sfc->fb);
 
     vigs_gl_surface_setup_framebuffer(gl_sfc);
@@ -758,7 +851,7 @@ static void vigs_gl_surface_solid_fill(struct vigs_surface *sfc,
 
     gl_backend->DisableClientState(GL_VERTEX_ARRAY);
 
-    gl_backend->Finish();
+    vigs_gl_surface_set_fence_2d(gl_sfc);
 
     gl_sfc->base.is_dirty = true;
 
@@ -794,6 +887,8 @@ static void vigs_gl_surface_put_image(struct vigs_surface *sfc,
         goto out;
     }
 
+    vigs_gl_surface_wait_fence_3d(gl_sfc);
+
     gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_sfc->fb);
 
     vigs_gl_surface_setup_framebuffer(gl_sfc);
@@ -810,7 +905,7 @@ static void vigs_gl_surface_put_image(struct vigs_surface *sfc,
                            ws_sfc->tex_type,
                            src);
 
-    gl_backend->Finish();
+    vigs_gl_surface_set_fence_2d(gl_sfc);
 
     gl_sfc->base.is_dirty = true;
 
@@ -836,6 +931,15 @@ static void vigs_gl_surface_destroy(struct vigs_surface *sfc)
             gl_backend->DeleteTextures(1, &gl_sfc->tmp_tex);
         }
 
+        if (gl_backend->has_arb_sync) {
+            if (gl_sfc->fence_2d) {
+                gl_backend->DeleteSync(gl_sfc->fence_2d);
+            }
+            if (gl_sfc->fence_3d) {
+                gl_backend->DeleteSync(gl_sfc->fence_3d);
+            }
+        }
+
         gl_backend->make_current(gl_backend, false);
     }
 
@@ -953,6 +1057,20 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
         goto fail;
     }
 
+    /*
+     * ARB_sync is not mandatory, but if present gives additional
+     * performance.
+     */
+    gl_backend->has_arb_sync = (strstr(extensions, "GL_ARB_sync ") != NULL) &&
+                               gl_backend->FenceSync &&
+                               gl_backend->DeleteSync &&
+                               gl_backend->WaitSync;
+    if (gl_backend->has_arb_sync) {
+        VIGS_LOG_INFO("ARB_sync supported");
+    } else {
+        VIGS_LOG_WARN("ARB_sync not supported!");
+    }
+
     gl_backend->base.create_surface = &vigs_gl_backend_create_surface;
 
     gl_backend->make_current(gl_backend, false);
index 51ee57a..9b3ae8a 100644 (file)
@@ -5,6 +5,7 @@
 #include "vigs_backend.h"
 #include "vigs_vector.h"
 #include <GL/gl.h>
+#include <GL/glext.h>
 #include "winsys_gl.h"
 
 struct vigs_gl_backend
@@ -18,6 +19,11 @@ struct vigs_gl_backend
     bool (*make_current)(struct vigs_gl_backend */*gl_backend*/,
                          bool /*enable*/);
 
+    /*
+     * Mandatory GL functions and extensions.
+     * @{
+     */
+
     void (GLAPIENTRY *GenTextures)(GLsizei n, GLuint *textures);
     void (GLAPIENTRY *DeleteTextures)(GLsizei n, const GLuint *textures);
     void (GLAPIENTRY *BindTexture)(GLenum target, GLuint texture);
@@ -73,6 +79,23 @@ struct vigs_gl_backend
     void (GLAPIENTRY *BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
 
     /*
+     * @}
+     */
+
+    /*
+     * Optional GL extensions.
+     * @{
+     */
+
+    GLsync (GLAPIENTRY *FenceSync)(GLenum condition, GLbitfield flags);
+    void (GLAPIENTRY *DeleteSync)(GLsync sync);
+    void (GLAPIENTRY *WaitSync)(GLsync sync, GLbitfield flags, GLuint64 timeout);
+
+    /*
+     * @}
+     */
+
+    /*
      * General purpose vectors.
      * @{
      */
@@ -83,6 +106,8 @@ struct vigs_gl_backend
     /*
      * @}
      */
+
+    bool has_arb_sync;
 };
 
 bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend);
index 932a1cc..7a1cf70 100644 (file)
         } \
     } while (0)
 
+#define VIGS_GL_GET_PROC_OPTIONAL(func, proc_name) \
+    do { \
+        *(void**)(&gl_backend_glx->base.func) = gl_backend_glx->glXGetProcAddress((const GLubyte*)#proc_name); \
+        if (!gl_backend_glx->base.func) { \
+            *(void**)(&gl_backend_glx->base.func) = dlsym(gl_backend_glx->handle, #proc_name); \
+        } \
+    } while (0)
+
 /* GLX 1.0 */
 typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display *dpy, GLXContext ctx);
 typedef GLXContext (*PFNGLXGETCURRENTCONTEXTPROC)(void);
@@ -289,6 +297,9 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(BlendFunc, glBlendFunc);
     VIGS_GL_GET_PROC(CopyTexImage2D, glCopyTexImage2D);
     VIGS_GL_GET_PROC(BlitFramebuffer, glBlitFramebufferEXT);
+    VIGS_GL_GET_PROC_OPTIONAL(FenceSync, glFenceSync);
+    VIGS_GL_GET_PROC_OPTIONAL(DeleteSync, glDeleteSync);
+    VIGS_GL_GET_PROC_OPTIONAL(WaitSync, glWaitSync);
 
     gl_backend_glx->dpy = x_display;
 
index 2481091..0e26294 100644 (file)
         } \
     } while (0)
 
+#define VIGS_GL_GET_PROC_OPTIONAL(func, proc_name) \
+    do { \
+        *(void**)(&gl_backend_wgl->base.func) = gl_backend_wgl->wglGetProcAddress((LPCSTR)#proc_name); \
+        if (!gl_backend_wgl->base.func) { \
+            *(void**)(&gl_backend_wgl->base.func) = GetProcAddress(gl_backend_wgl->handle, #proc_name); \
+        } \
+    } while (0)
+
 typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTPROC)(HDC hdl);
 typedef BOOL (WINAPI *PFNWGLDELETECONTEXTPROC)(HGLRC hdl);
 typedef PROC (WINAPI *PFNWGLGETPROCADDRESSPROC)(LPCSTR sym);
@@ -401,6 +409,9 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(BlendFunc, glBlendFunc);
     VIGS_GL_GET_PROC(CopyTexImage2D, glCopyTexImage2D);
     VIGS_GL_GET_PROC(BlitFramebuffer, glBlitFramebufferEXT);
+    VIGS_GL_GET_PROC_OPTIONAL(FenceSync, glFenceSync);
+    VIGS_GL_GET_PROC_OPTIONAL(DeleteSync, glDeleteSync);
+    VIGS_GL_GET_PROC_OPTIONAL(WaitSync, glWaitSync);
 
     gl_backend_wgl->wglMakeCurrent(NULL, NULL);
     gl_backend_wgl->wglDeleteContext(tmp_ctx);