VIGS/YaGL: Use glMapBufferRange instead of glBufferSubData 54/16754/1
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Mon, 24 Feb 2014 08:40:08 +0000 (12:40 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Mon, 24 Feb 2014 10:07:14 +0000 (14:07 +0400)
glBufferSubData is broken on windows, it cannot be used to
subsequently replace part of buffer data between drawing
calls, so use glMapBufferRange instead. If glMapBufferRange
is not available then use glFinish + glBufferSubData to
guarantee synchronization

Change-Id: Ic9ff0ad0ca0f18f38c92dddfc382e504b3573761

hw/vigs/vigs_gl_backend.c
hw/vigs/vigs_gl_backend.h
hw/vigs/vigs_gl_backend_cgl.c
hw/vigs/vigs_gl_backend_glx.c
hw/vigs/vigs_gl_backend_wgl.c
hw/yagl/yagl_apis/gles/yagl_gles_api_ts.c
hw/yagl/yagl_apis/gles/yagl_gles_api_ts.h
hw/yagl/yagl_apis/gles/yagl_host_gles_calls.c
hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl.c
hw/yagl/yagl_drivers/gles_ogl/yagl_gles_ogl_macros.h
hw/yagl/yagl_gles_driver.h

index de3d99c..80dd36e 100644 (file)
@@ -246,6 +246,7 @@ static void vigs_gl_draw_tex_prog(struct vigs_gl_backend *backend,
                                   uint32_t count)
 {
     uint32_t size = count * 16;
+    void *ptr;
 
     if (size > backend->vbo_size) {
         backend->vbo_size = size;
@@ -255,10 +256,25 @@ static void vigs_gl_draw_tex_prog(struct vigs_gl_backend *backend,
                             GL_STREAM_DRAW);
     }
 
-    backend->BufferSubData(GL_ARRAY_BUFFER, 0,
-                           (size / 2), vigs_vector_data(&backend->v1));
-    backend->BufferSubData(GL_ARRAY_BUFFER, (size / 2),
-                           (size / 2), vigs_vector_data(&backend->v2));
+    if (backend->MapBufferRange) {
+        ptr = backend->MapBufferRange(GL_ARRAY_BUFFER, 0, size,
+                                      GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
+
+        if (ptr) {
+            memcpy(ptr, vigs_vector_data(&backend->v1), size / 2);
+            memcpy(ptr + (size / 2), vigs_vector_data(&backend->v2), size / 2);
+
+            backend->UnmapBuffer(GL_ARRAY_BUFFER);
+        } else {
+            VIGS_LOG_ERROR("glMapBufferRange failed");
+        }
+    } else {
+        backend->Finish();
+        backend->BufferSubData(GL_ARRAY_BUFFER, 0,
+                               (size / 2), vigs_vector_data(&backend->v1));
+        backend->BufferSubData(GL_ARRAY_BUFFER, (size / 2),
+                               (size / 2), vigs_vector_data(&backend->v2));
+    }
 
     backend->EnableVertexAttribArray(backend->tex_prog_vertCoord_loc);
     backend->EnableVertexAttribArray(backend->tex_prog_texCoord_loc);
@@ -279,6 +295,7 @@ static void vigs_gl_draw_color_prog(struct vigs_gl_backend *backend,
                                     uint32_t count)
 {
     uint32_t size = count * 8;
+    void *ptr;
 
     if (size > backend->vbo_size) {
         backend->vbo_size = size;
@@ -288,8 +305,22 @@ static void vigs_gl_draw_color_prog(struct vigs_gl_backend *backend,
                             GL_STREAM_DRAW);
     }
 
-    backend->BufferSubData(GL_ARRAY_BUFFER, 0, size,
-                           vigs_vector_data(&backend->v1));
+    if (backend->MapBufferRange) {
+        ptr = backend->MapBufferRange(GL_ARRAY_BUFFER, 0, size,
+                                      GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
+
+        if (ptr) {
+            memcpy(ptr, vigs_vector_data(&backend->v1), size);
+
+            backend->UnmapBuffer(GL_ARRAY_BUFFER);
+        } else {
+            VIGS_LOG_ERROR("glMapBufferRange failed");
+        }
+    } else {
+        backend->Finish();
+        backend->BufferSubData(GL_ARRAY_BUFFER, 0, size,
+                               vigs_vector_data(&backend->v1));
+    }
 
     backend->Uniform4fv(backend->color_prog_color_loc, 1, color);
 
@@ -1316,7 +1347,15 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
         return false;
     }
 
-    if (!gl_backend->is_gl_2) {
+    if (gl_backend->is_gl_2) {
+        const char *tmp = (const char*)gl_backend->GetString(GL_EXTENSIONS);
+
+        if (!tmp || (strstr(tmp, "GL_ARB_map_buffer_range ") == NULL)) {
+            VIGS_LOG_WARN("glMapBufferRange not supported, using glBufferSubData");
+        }
+
+        gl_backend->MapBufferRange = NULL;
+    } else {
         gl_backend->GenVertexArrays(1, &gl_backend->vao);
 
         if (!gl_backend->vao) {
index 8a4109a..68835e3 100644 (file)
@@ -89,6 +89,7 @@ struct vigs_gl_backend
     void (GLAPIENTRY *FramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
     void (GLAPIENTRY *FramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
     void (GLAPIENTRY *GetIntegerv)(GLenum pname, GLint *params);
+    const GLubyte *(GLAPIENTRY *GetString)(GLenum name);
     void (GLAPIENTRY *DrawArrays)(GLenum mode, GLint first, GLsizei count);
     void (GLAPIENTRY *GenBuffers)(GLsizei n, GLuint *buffers);
     void (GLAPIENTRY *DeleteBuffers)(GLsizei n, const GLuint *buffers);
@@ -124,6 +125,11 @@ struct vigs_gl_backend
      */
 
     /*
+     * Only OpenGL 2.1 + GL_ARB_map_buffer_range or OpenGL 3.1+ core.
+     */
+    GLvoid *(GLAPIENTRY *MapBufferRange)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+
+    /*
      * OpenGL 3.1+ core functions and extensions.
      * @{
      */
index 2112138..fd22577 100644 (file)
@@ -50,6 +50,9 @@
         } \
     } while (0)
 
+#define VIGS_GL_GET_PROC_OPTIONAL(func, proc_name) \
+    *(void**)(&gl_backend_cgl->base.func) = dlsym(gl_backend_cgl->handle, #proc_name)
+
 static const CGLPixelFormatAttribute pixel_format_legacy_attrs[] =
 {
     kCGLPFAAccelerated,
@@ -272,6 +275,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(FramebufferRenderbuffer, glFramebufferRenderbufferEXT);
     VIGS_GL_GET_PROC(FramebufferTexture2D, glFramebufferTexture2DEXT);
     VIGS_GL_GET_PROC(GetIntegerv, glGetIntegerv);
+    VIGS_GL_GET_PROC(GetString, glGetString);
     VIGS_GL_GET_PROC(DrawArrays, glDrawArrays);
     VIGS_GL_GET_PROC(GenBuffers, glGenBuffers);
     VIGS_GL_GET_PROC(DeleteBuffers, glDeleteBuffers);
@@ -302,6 +306,8 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(Uniform4fv, glUniform4fv);
     VIGS_GL_GET_PROC(UniformMatrix4fv, glUniformMatrix4fv);
 
+    VIGS_GL_GET_PROC_OPTIONAL(MapBufferRange, glMapBufferRange);
+
     if (!vigs_gl_backend_cgl_check_gl_version(gl_backend_cgl,
                                               &gl_backend_cgl->base.is_gl_2)) {
         goto fail2;
index 6d6c242..2232c2b 100644 (file)
@@ -448,6 +448,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(FramebufferRenderbuffer, glFramebufferRenderbufferEXT);
     VIGS_GL_GET_PROC(FramebufferTexture2D, glFramebufferTexture2DEXT);
     VIGS_GL_GET_PROC(GetIntegerv, glGetIntegerv);
+    VIGS_GL_GET_PROC(GetString, glGetString);
     VIGS_GL_GET_PROC(DrawArrays, glDrawArrays);
     VIGS_GL_GET_PROC(GenBuffers, glGenBuffers);
     VIGS_GL_GET_PROC(DeleteBuffers, glDeleteBuffers);
@@ -478,6 +479,8 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(Uniform4fv, glUniform4fv);
     VIGS_GL_GET_PROC(UniformMatrix4fv, glUniformMatrix4fv);
 
+    VIGS_GL_GET_PROC_OPTIONAL(MapBufferRange, glMapBufferRange);
+
     gl_backend_glx->dpy = x_display;
 
     if (!vigs_gl_backend_glx_check_gl_version(gl_backend_glx,
index 3762696..99e059b 100644 (file)
@@ -447,6 +447,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(FramebufferRenderbuffer, glFramebufferRenderbufferEXT);
     VIGS_GL_GET_PROC(FramebufferTexture2D, glFramebufferTexture2DEXT);
     VIGS_GL_GET_PROC(GetIntegerv, glGetIntegerv);
+    VIGS_GL_GET_PROC(GetString, glGetString);
     VIGS_GL_GET_PROC(DrawArrays, glDrawArrays);
     VIGS_GL_GET_PROC(GenBuffers, glGenBuffers);
     VIGS_GL_GET_PROC(DeleteBuffers, glDeleteBuffers);
@@ -477,6 +478,8 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(Uniform4fv, glUniform4fv);
     VIGS_GL_GET_PROC(UniformMatrix4fv, glUniformMatrix4fv);
 
+    VIGS_GL_GET_PROC_OPTIONAL(MapBufferRange, glMapBufferRange);
+
     gl_backend_wgl->wglMakeCurrent(NULL, NULL);
     gl_backend_wgl->wglDeleteContext(tmp_ctx);
     tmp_ctx = NULL;
index 8a2c418..1debb5c 100644 (file)
@@ -39,6 +39,7 @@ void yagl_gles_api_ts_init(struct yagl_gles_api_ts *gles_api_ts,
 {
     gles_api_ts->driver = driver;
     gles_api_ts->ps = ps;
+    gles_api_ts->use_map_buffer_range = -1;
 }
 
 void yagl_gles_api_ts_cleanup(struct yagl_gles_api_ts *gles_api_ts)
index faf6d83..8c4ca86 100644 (file)
@@ -54,6 +54,11 @@ struct yagl_gles_api_ts
 
     struct yagl_gles_array *arrays;
     uint32_t num_arrays;
+
+    /*
+     * -1 when undecided, 0/1 when decided.
+     */
+    int use_map_buffer_range;
 };
 
 void yagl_gles_api_ts_init(struct yagl_gles_api_ts *gles_api_ts,
index f9eeee2..2b9e866 100644 (file)
@@ -61,6 +61,28 @@ typedef enum
     yagl_gles1_array_texcoord,
 } yagl_gles1_array_type;
 
+static bool yagl_gles_use_map_buffer_range(void)
+{
+    YAGL_LOG_FUNC_SET(yagl_gles_use_map_buffer_range);
+
+    if (gles_api_ts->use_map_buffer_range == -1) {
+        if (gles_api_ts->driver->gl_version > yagl_gl_2) {
+            gles_api_ts->use_map_buffer_range = 1;
+        } else {
+            const char *tmp = (const char*)gles_api_ts->driver->GetString(GL_EXTENSIONS);
+
+            gles_api_ts->use_map_buffer_range =
+                (tmp && (strstr(tmp, "GL_ARB_map_buffer_range ") != NULL));
+
+            if (!gles_api_ts->use_map_buffer_range) {
+                YAGL_LOG_WARN("glMapBufferRange not supported, using glBufferSubData");
+            }
+        }
+    }
+
+    return gles_api_ts->use_map_buffer_range;
+}
+
 static GLuint yagl_gles_bind_array(uint32_t indx,
                                    GLint first,
                                    GLsizei stride,
@@ -69,6 +91,9 @@ static GLuint yagl_gles_bind_array(uint32_t indx,
 {
     GLuint current_vbo;
     uint32_t size;
+    void *ptr;
+
+    YAGL_LOG_FUNC_SET(yagl_gles_bind_array);
 
     if (indx >= gles_api_ts->num_arrays) {
         struct yagl_gles_array *arrays;
@@ -105,9 +130,25 @@ static GLuint yagl_gles_bind_array(uint32_t indx,
         gles_api_ts->arrays[indx].size = size;
     }
 
+    if (yagl_gles_use_map_buffer_range()) {
+        ptr = gles_api_ts->driver->MapBufferRange(GL_ARRAY_BUFFER,
+                                                  first * stride,
+                                                  data_count,
+                                                  GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
 
-    gles_api_ts->driver->BufferSubData(GL_ARRAY_BUFFER,
-                                       first * stride, data_count, data);
+        if (ptr) {
+            memcpy(ptr, data, data_count);
+
+            gles_api_ts->driver->UnmapBuffer(GL_ARRAY_BUFFER);
+        } else {
+            YAGL_LOG_ERROR("glMapBufferRange failed");
+        }
+    } else {
+        gles_api_ts->driver->Finish();
+        gles_api_ts->driver->BufferSubData(GL_ARRAY_BUFFER,
+                                           first * stride, data_count,
+                                           data);
+    }
 
     return current_vbo;
 }
@@ -819,7 +860,27 @@ void yagl_host_glBufferSubData(GLenum target,
     GLsizei offset,
     const GLvoid *data, int32_t data_count)
 {
-    gles_api_ts->driver->BufferSubData(target, offset, data_count, data);
+    void *ptr;
+
+    YAGL_LOG_FUNC_SET(glBufferSubData);
+
+    if (yagl_gles_use_map_buffer_range()) {
+        ptr = gles_api_ts->driver->MapBufferRange(target,
+                                                  offset,
+                                                  data_count,
+                                                  GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
+
+        if (ptr) {
+            memcpy(ptr, data, data_count);
+
+            gles_api_ts->driver->UnmapBuffer(target);
+        } else {
+            YAGL_LOG_ERROR("glMapBufferRange failed");
+        }
+    } else {
+        gles_api_ts->driver->Finish();
+        gles_api_ts->driver->BufferSubData(target, offset, data_count, data);
+    }
 }
 
 void yagl_host_glBindBufferBase(GLenum target,
index 45b6c9b..660f2af 100644 (file)
@@ -237,6 +237,7 @@ struct yagl_gles_driver *yagl_gles_ogl_create(struct yagl_dyn_lib *dyn_lib,
     YAGL_GLES_OGL_GET_PROC(driver, Finish, glFinish);
 
     if (gl_version > yagl_gl_2) {
+        YAGL_GLES_OGL_GET_PROC(driver, MapBufferRange, glMapBufferRange);
         YAGL_GLES_OGL_GET_PROC(driver, GetStringi, glGetStringi);
         YAGL_GLES_OGL_GET_PROC(driver, GenVertexArrays, glGenVertexArrays);
         YAGL_GLES_OGL_GET_PROC(driver, BindVertexArray, glBindVertexArray);
@@ -304,6 +305,8 @@ struct yagl_gles_driver *yagl_gles_ogl_create(struct yagl_dyn_lib *dyn_lib,
         YAGL_GLES_OGL_GET_PROC(driver, ClearBufferfv, glClearBufferfv);
         YAGL_GLES_OGL_GET_PROC(driver, GetFragDataLocation, glGetFragDataLocation);
         YAGL_GLES_OGL_GET_PROC(driver, DrawRangeElements, glDrawRangeElements);
+    } else {
+        YAGL_GLES_OGL_GET_PROC_OPT(driver, MapBufferRange, glMapBufferRange);
     }
 
     driver->destroy = &yagl_gles_ogl_destroy;
index e6e1878..d3a0267 100644 (file)
@@ -47,6 +47,9 @@
         } \
     } while (0)
 
+#define YAGL_GLES_OGL_GET_PROC_OPT(driver, func, sym) \
+    *(void**)(&driver->func) = yagl_dyn_lib_get_ogl_procaddr(dyn_lib, #sym)
+
 /*
  * @}
  */
index 89f30ac..22eafbd 100644 (file)
@@ -62,6 +62,9 @@ void (YAGL_GLES_APIENTRY *func)(arg0_type arg0, arg1_type arg1, arg2_type arg2);
 #define YAGL_GLES_DRIVER_FUNC4(func, arg0_type, arg1_type, arg2_type, arg3_type, arg0, arg1, arg2, arg3) \
 void (YAGL_GLES_APIENTRY *func)(arg0_type arg0, arg1_type arg1, arg2_type arg2, arg3_type arg3);
 
+#define YAGL_GLES_DRIVER_FUNC_RET4(ret_type, func, arg0_type, arg1_type, arg2_type, arg3_type, arg0, arg1, arg2, arg3) \
+ret_type (YAGL_GLES_APIENTRY *func)(arg0_type arg0, arg1_type arg1, arg2_type arg2, arg3_type arg3);
+
 #define YAGL_GLES_DRIVER_FUNC5(func, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type, arg0, arg1, arg2, arg3, arg4) \
 void (YAGL_GLES_APIENTRY *func)(arg0_type arg0, arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4);
 
@@ -288,6 +291,11 @@ struct yagl_gles_driver
     YAGL_GLES_DRIVER_FUNC0(Finish)
 
     /*
+     * Only OpenGL 2.1 + GL_ARB_map_buffer_range or OpenGL 3.1+ core.
+     */
+    YAGL_GLES_DRIVER_FUNC_RET4(GLvoid*, MapBufferRange, GLenum, GLintptr, GLsizeiptr, GLbitfield, target, offset, length, access)
+
+    /*
      * @}
      */