display: fix blinking display issue with OpenGL 2.1
authorJinhyung Jo <jinhyung.jo@samsung.com>
Wed, 9 Nov 2016 06:52:27 +0000 (15:52 +0900)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Fri, 2 Dec 2016 08:31:25 +0000 (17:31 +0900)
Use the texture arrays to avoid collisions.

The glBufferSubData function makes the display blink
with OpenGL verion 2.1 have no glMapBufferRange support.
The glMapBuffer function helps to solve this problem.

Use the Qt5 class API(QOpenGLShaderProgram) instead of the OpenGL API.
That's a little clearer and better to watch.

Use multiple buffering to avoid performance degration.

Change-Id: I819a52f7e0db5accded86b71c8a15fa1a9e65e28
Signed-off-by: Jinhyung Jo <jinhyung.jo@samsung.com>
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
hw/vigs/vigs_gl_backend.c
hw/vigs/vigs_gl_backend.h
hw/vigs/vigs_qt5.cpp
hw/vigs/vigs_qt5.h
hw/yagl/yagl_apis/gles/yagl_host_gles_calls.c
tizen/src/ui/displayglwidget.cpp
tizen/src/ui/displayglwidget.h
tizen/src/ui/mainwindow.cpp
tizen/src/ui/mainwindow.h
tizen/src/ui/qt5_supplement.cpp

index 9995d1c..c09e081 100644 (file)
@@ -527,11 +527,19 @@ static void vigs_gl_draw_update_vert_tex_buffer(struct vigs_gl_backend *backend,
             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));
+        ptr = backend->MapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+        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 {
+            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));
+        }
     }
 }
 
@@ -583,9 +591,16 @@ static void vigs_gl_draw_color_prog(struct vigs_gl_backend *backend,
             VIGS_LOG_ERROR("glMapBufferRange failed");
         }
     } else {
-        backend->Finish();
-        backend->BufferSubData(GL_ARRAY_BUFFER, 0, size,
-                               vigs_vector_data(&backend->v1));
+        ptr = backend->MapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+        if (ptr) {
+            memcpy(ptr, vigs_vector_data(&backend->v1), size);
+
+            backend->UnmapBuffer(GL_ARRAY_BUFFER);
+        } else {
+            backend->Finish();
+            backend->BufferSubData(GL_ARRAY_BUFFER, 0, size,
+                                   vigs_vector_data(&backend->v1));
+        }
     }
 
     backend->Uniform4fv(backend->color_prog_color_loc, 1, color);
@@ -770,14 +785,40 @@ static bool vigs_gl_update_dpy_texture(struct vigs_gl_backend *gl_backend,
 {
     GLuint cur_tex = 0;
 
-    gl_backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&cur_tex);
+    if (vigs_qt5_onscreen_enabled()) {
+        // find available texture by iteration.
+        // it is OK, since we have only very few textures.
+        gl_backend->current_dpy = NULL;
+        int i;
+        for (i = 0; i < TEXTURE_NUM; ++i) {
+            struct dpy_item *item = &(gl_backend->dpy_items[i]);
+            if(likely(!qemu_mutex_trylock(&item->mutex))) {
+                if (item->available) {
+                    item->available = false;
+                    gl_backend->current_dpy = item;
+                    qemu_mutex_unlock(&item->mutex);
+                    break;
+                }
+                qemu_mutex_unlock(&item->mutex);
+            }
+        }
+        if (unlikely(!gl_backend->current_dpy)) {
+            // can not enter here.
+            // simply we drop this frame.
+            return false;
+        }
+    } else {
+        gl_backend->current_dpy = &gl_backend->dpy_items[0];
+    }
+
+    gl_backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *)&cur_tex);
 
-    if (gl_backend->dpy_tex) {
-        if ((gl_backend->dpy_tex_width == width) &&
-            (gl_backend->dpy_tex_height == height)) {
+    if (gl_backend->current_dpy->tex) {
+        if ((gl_backend->current_dpy->width == width) &&
+            (gl_backend->current_dpy->height == height)) {
             return true;
         }
-        gl_backend->BindTexture(GL_TEXTURE_2D, gl_backend->dpy_tex);
+        gl_backend->BindTexture(GL_TEXTURE_2D, gl_backend->current_dpy->tex);
     } else {
         GLuint tmp_tex = 0;
 
@@ -787,7 +828,7 @@ static bool vigs_gl_update_dpy_texture(struct vigs_gl_backend *gl_backend,
             return false;
         }
 
-        gl_backend->dpy_tex = tmp_tex;
+        gl_backend->current_dpy->tex = tmp_tex;
 
         gl_backend->BindTexture(GL_TEXTURE_2D, tmp_tex);
 
@@ -804,8 +845,8 @@ static bool vigs_gl_update_dpy_texture(struct vigs_gl_backend *gl_backend,
 
     gl_backend->BindTexture(GL_TEXTURE_2D, cur_tex);
 
-    gl_backend->dpy_tex_width = width;
-    gl_backend->dpy_tex_height = height;
+    gl_backend->current_dpy->width = width;
+    gl_backend->current_dpy->height = height;
 
     return true;
 }
@@ -2040,7 +2081,7 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
     }
 
     gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                     GL_TEXTURE_2D, gl_backend->dpy_tex, 0);
+                                     GL_TEXTURE_2D, gl_backend->current_dpy->tex, 0);
 
     gl_backend->Clear(GL_COLOR_BUFFER_BIT);
 
@@ -2144,10 +2185,10 @@ static bool vigs_gl_backend_capture(struct vigs_surface *surface,
 
         gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_backend->dpy_fb);
         gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                         GL_TEXTURE_2D, gl_backend->dpy_tex, 0);
+                                         GL_TEXTURE_2D, gl_backend->current_dpy->tex, 0);
 
-        gl_backend->ReadPixels(0, 0, gl_backend->dpy_tex_width,
-                               gl_backend->dpy_tex_height,
+        gl_backend->ReadPixels(0, 0, gl_backend->current_dpy->width,
+                               gl_backend->current_dpy->height,
                                GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
                                pixels);
         gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -2176,7 +2217,9 @@ static bool vigs_gl_backend_display(struct vigs_backend *backend,
     VIGS_LOG_TRACE("enter");
 
     if (vigs_qt5_onscreen_enabled()) {
-        vigs_qt5_dpy_render_texture(gl_backend->dpy_tex);
+        if (gl_backend->current_dpy && gl_backend->current_dpy->tex) {
+            vigs_qt5_dpy_render_texture(gl_backend->current_dpy);
+        }
         return true;
     }
 
@@ -2192,10 +2235,10 @@ static bool vigs_gl_backend_display(struct vigs_backend *backend,
         }
 
         gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                         GL_TEXTURE_2D, gl_backend->dpy_tex, 0);
+                                         GL_TEXTURE_2D, gl_backend->current_dpy->tex, 0);
 
-        gl_backend->ReadPixels(0, 0, gl_backend->dpy_tex_width,
-                               gl_backend->dpy_tex_height,
+        gl_backend->ReadPixels(0, 0, gl_backend->current_dpy->width,
+                               gl_backend->current_dpy->height,
                                GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
                                display_data);
 
@@ -2408,6 +2451,12 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
     vigs_vector_init(&gl_backend->v1, 0);
     vigs_vector_init(&gl_backend->v2, 0);
 
+    int i;
+    for (i = 0; i < TEXTURE_NUM; ++i) {
+        gl_backend->dpy_items[i].available = true;
+        qemu_mutex_init(&gl_backend->dpy_items[i].mutex);
+    }
+
     return true;
 
 fail:
@@ -2419,8 +2468,12 @@ fail:
 void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend)
 {
     if (gl_backend->make_current(gl_backend, true)) {
-        if (gl_backend->dpy_tex) {
-            gl_backend->DeleteTextures(1, &gl_backend->dpy_tex);
+        int i;
+        for (i = 0; i < TEXTURE_NUM; i++) {
+            if (gl_backend->dpy_items[i].tex) {
+                gl_backend->DeleteTextures(1, &gl_backend->dpy_items[i].tex);
+            }
+            qemu_mutex_destroy(&gl_backend->dpy_items[i].mutex);
         }
         if (gl_backend->dpy_fb) {
             gl_backend->DeleteFramebuffers(1, &gl_backend->dpy_fb);
index ca2d365..c9cd54e 100644 (file)
@@ -37,6 +37,8 @@
 #include <GL/glext.h>
 #include "winsys_gl.h"
 
+#define TEXTURE_NUM 5
+
 struct vigs_gl_pool;
 
 struct vigs_gl_backend
@@ -220,10 +222,19 @@ struct vigs_gl_backend
      * Display thread related.
      * @{
      */
-    GLuint dpy_tex;
+
+    struct dpy_item {
+        GLuint tex;
+        uint32_t width;
+        uint32_t height;
+
+        bool available;
+        QemuMutex mutex;
+    } dpy_items[TEXTURE_NUM], *current_dpy;
+
+    uint32_t dpy_idx;
+
     GLuint dpy_fb;
-    uint32_t dpy_tex_width;
-    uint32_t dpy_tex_height;
 
     /*
      * @}
index 286014e..e33817a 100644 (file)
@@ -43,7 +43,7 @@ extern void qt5_register_capture_request_listener(void *listener,
 extern void qt5_unregister_capture_request_listener(void *listener);
 extern void qt5_process_captured(bool captured, void *pixels,
                                  int width, int height);
-extern void qt5_update_texture(unsigned int tex_id);
+extern void qt5_update_texture(void *dpy_item);
 
 bool vigs_qt5_onscreen_enabled(void)
 {
@@ -114,7 +114,7 @@ void vigs_qt5_process_captured(bool captured, void *pixels,
     qt5_process_captured(captured, pixels, width, height);
 }
 
-void vigs_qt5_dpy_render_texture(uint32_t tex_id)
+void vigs_qt5_dpy_render_texture(void *dpy_item)
 {
-    qt5_update_texture(tex_id);
+    qt5_update_texture(dpy_item);
 }
index a27ae61..168095b 100644 (file)
@@ -45,7 +45,7 @@ void vigs_qt5_register_capture_request_listener(void *listener,
 void vigs_qt5_unregister_capture_request_listener(void *listener);
 void vigs_qt5_process_captured(bool captured, void *pixels,
                                int width, int height);
-void vigs_qt5_dpy_render_texture(uint32_t tex_id);
+void vigs_qt5_dpy_render_texture(void *dpy_item);
 #ifdef __cplusplus
 };
 #endif
index d6eae0c..af3efbd 100644 (file)
@@ -122,10 +122,20 @@ static GLuint yagl_gles_bind_array(uint32_t indx,
             YAGL_LOG_ERROR("glMapBufferRange failed");
         }
     } else {
-        gles_api_ts->driver->Finish();
-        gles_api_ts->driver->BufferSubData(GL_ARRAY_BUFFER,
-                                           first * stride, data_count,
-                                           data);
+        ptr = gles_api_ts->driver->MapBuffer(GL_ARRAY_BUFFER,
+                                             GL_WRITE_ONLY);
+
+        if (ptr) {
+            void *addr = (void *)((uintptr_t)ptr + (uintptr_t)(first * stride));
+            memcpy(addr, data, data_count);
+
+            gles_api_ts->driver->UnmapBuffer(GL_ARRAY_BUFFER);
+        } else {
+            gles_api_ts->driver->Finish();
+            gles_api_ts->driver->BufferSubData(GL_ARRAY_BUFFER,
+                                               first * stride, data_count,
+                                               data);
+        }
     }
 
     return current_vbo;
@@ -168,9 +178,18 @@ static GLuint yagl_gles_bind_ebo(const GLvoid *data, int32_t size)
             YAGL_LOG_ERROR("glMapBufferRange failed");
         }
     } else {
-        gles_api_ts->driver->Finish();
-        gles_api_ts->driver->BufferSubData(GL_ELEMENT_ARRAY_BUFFER,
-                                           0, size, data);
+        ptr = gles_api_ts->driver->MapBuffer(GL_ELEMENT_ARRAY_BUFFER,
+                                             GL_WRITE_ONLY);
+
+        if (ptr) {
+            memcpy(ptr, data, size);
+
+            gles_api_ts->driver->UnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+        } else {
+            gles_api_ts->driver->Finish();
+            gles_api_ts->driver->BufferSubData(GL_ELEMENT_ARRAY_BUFFER,
+                                               0, size, data);
+        }
     }
 
     return current_ebo;
@@ -913,8 +932,25 @@ void yagl_host_glBufferSubData(GLenum target,
             YAGL_LOG_ERROR("glMapBufferRange failed");
         }
     } else {
-        gles_api_ts->driver->Finish();
-        gles_api_ts->driver->BufferSubData(target, offset, data_count, data);
+        if (target == GL_ARRAY_BUFFER ||
+            target == GL_ELEMENT_ARRAY_BUFFER ||
+            target == GL_PIXEL_PACK_BUFFER ||
+            target == GL_PIXEL_UNPACK_BUFFER) {
+            ptr = gles_api_ts->driver->MapBuffer(target, GL_WRITE_ONLY);
+
+            if (ptr) {
+                void *addr = (void *)((uintptr_t)ptr + (uintptr_t)(offset));
+                memcpy(addr, data, data_count);
+
+                gles_api_ts->driver->UnmapBuffer(target);
+            } else {
+                YAGL_LOG_ERROR("glMapBuffer failed");
+            }
+        } else {
+            gles_api_ts->driver->Finish();
+            gles_api_ts->driver->BufferSubData(target, offset,
+                                               data_count, data);
+        }
     }
 }
 
index 0a9d06d..14aa91b 100644 (file)
@@ -212,20 +212,28 @@ DisplayGLWidget::DisplayGLWidget(QWidget *parent,
     this->maskQImage = displayForm->getMask().toImage();
     this->maskTexture = 0;
     this->needScale = false;
-    this->dpyTexture = 0;
     this->mtTexture = 0;
     this->texProgram = NULL;
     this->scaleProgram = NULL;
+    this->next = NULL;
+    this->current = NULL;
 
     /* to be enable to drop events */
     setAcceptDrops(true);
 }
 
-void DisplayGLWidget::changedTexture(unsigned int id)
+void DisplayGLWidget::changedTexture(struct dpy_item *item)
 {
-    if (dpyTexture != id) {
-        dpyTexture = id;
+    // wait while "next" is being updated since it is fast enough.
+    textureListMutex.lock();
+    if (next) {
+        qemu_mutex_lock(&next->mutex);
+        next->available = true;
+        qemu_mutex_unlock(&next->mutex);
     }
+    next = item;
+    textureListMutex.unlock();
+
     this->update();
 }
 
@@ -247,8 +255,6 @@ void DisplayGLWidget::drawQuad(GLuint textureID, bool isMask)
     program->bind();
     program->enableAttributeArray("vertCoord");
     program->enableAttributeArray("texCoord");
-    int vertCoordLoc = program->attributeLocation("vertCoord");
-    int texCoordLoc = program->attributeLocation("texCoord");
     program->setUniformValue("proj", mOrtho);
     if (needScale) {
         GLfloat texSize[2];
@@ -261,9 +267,8 @@ void DisplayGLWidget::drawQuad(GLuint textureID, bool isMask)
     mVBO->bind();
     mVBO->write(0, mVertCoords, COORDS_SIZE);
     mVBO->write(COORDS_SIZE, mTexCoords, COORDS_SIZE);
-    mFuncs->glVertexAttribPointer(vertCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
-    mFuncs->glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0,
-                                  TO_VOIDP(COORDS_SIZE));
+    program->setAttributeArray("vertCoord", GL_FLOAT, NULL, 2, 0);
+    program->setAttributeArray("texCoord", GL_FLOAT, TO_VOIDP(COORDS_SIZE), 2, 0);
     mVBO->release();
 
     mFuncs->glDrawArrays(GL_TRIANGLES, 0, COORD_COUNT);
@@ -314,8 +319,6 @@ void DisplayGLWidget::drawMultiTouchPoints()
     texProgram->bind();
     texProgram->enableAttributeArray("vertCoord");
     texProgram->enableAttributeArray("texCoord");
-    int vertCoordLoc = texProgram->attributeLocation("vertCoord");
-    int texCoordLoc = texProgram->attributeLocation("texCoord");
 
     QMatrix4x4 mat;
     mat.ortho(0.0f, (float)width(),
@@ -323,10 +326,10 @@ void DisplayGLWidget::drawMultiTouchPoints()
               -1.0f, 1.0f);
     texProgram->setUniformValue("proj", mat);
     texProgram->setUniformValue("brightness", 0.7f);
-
-    mFuncs->glVertexAttribPointer(vertCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
-    mFuncs->glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0,
-                                  TO_VOIDP(pointList.count() * COORDS_SIZE));
+    texProgram->setAttributeArray("vertCoord", GL_FLOAT, NULL, 2, 0);
+    texProgram->setAttributeArray("texCoord", GL_FLOAT,
+                                  TO_VOIDP(pointList.count() * COORDS_SIZE),
+                                  2, 0);
     mVBO->release();
 
     mFuncs->glDrawArrays(GL_TRIANGLES, 0, pointList.count() * COORD_COUNT);
@@ -427,14 +430,14 @@ void DisplayGLWidget::initializeGL()
                              (const void *)maskQImage.constBits());
         mFuncs->glBindTexture(GL_TEXTURE_2D, curTexture);
     }
+    mFuncs->glDisable(GL_DEPTH_TEST);
+    mFuncs->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    mFuncs->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 }
 
 /* override */
 void DisplayGLWidget::paintGL()
 {
-    mFuncs->glDisable(GL_DEPTH_TEST);
-    mFuncs->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-    mFuncs->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
     mFuncs->glEnable(GL_BLEND);
 
     if (maskTexture) {
@@ -450,9 +453,25 @@ void DisplayGLWidget::paintGL()
                  0.0f, (float)mGuestResolution.height(),
                  -1.0f, 1.0f);
     needScale = (mGuestResolution.width() != width())
-                 || (mGuestResolution.height() != height());
+        || (mGuestResolution.height() != height());
+
+    // wait while "next" is being updated since it is fast enough.
+    textureListMutex.lock();
+    if (next) {
+        if (current) {
+            qemu_mutex_lock(&current->mutex);
+            current->available = true;
+            qemu_mutex_unlock(&current->mutex);
+        }
+        current = next;
+        next = NULL;
+    }
+    textureListMutex.unlock();
+
+    if (current) {
+        drawQuad(current->tex, false);
+    }
 
-    drawQuad(dpyTexture, false);
     if (isTsEnabled) {
         drawMultiTouchPoints();
     }
index cc327f5..2008fc7 100644 (file)
 
 
 #include "displaybase.h"
+#include <QMutex>
 #include <QOpenGLWidget>
 #include <QMatrix4x4>
 
+extern "C" {
+#include "qemu/thread.h"
+
+// FIXME: move it to common header
+struct dpy_item {
+    GLuint tex;
+    uint32_t width;
+    uint32_t height;
+
+    bool available;
+    QemuMutex mutex;
+};
+}
+
+
 class QOpenGLFunctions;
 class QOpenGLShaderProgram;
 class QOpenGLVertexArrayObject;
@@ -53,7 +69,7 @@ public:
                     QSize resolution, qreal scaleFactor);
     ~DisplayGLWidget();
 
-    void changedTexture(unsigned int texture);
+    void changedTexture(struct dpy_item *tex);
 
 protected:
     void initializeGL();
@@ -82,7 +98,10 @@ private:
     QImage maskQImage;
     GLuint maskTexture;
 
-    GLuint dpyTexture;
+    dpy_item* current;
+    dpy_item* next;
+    QMutex textureListMutex;
+
     GLuint mtTexture;
     QMatrix4x4 mOrtho;
     GLfloat mVertCoords[12];
@@ -92,6 +111,7 @@ private:
     QOpenGLBuffer *mVBO;
     QOpenGLShaderProgram *texProgram;
     QOpenGLShaderProgram *scaleProgram;
+
 };
 
 #endif // DISPLAYGLWIDGET_H
index de3818d..5216608 100644 (file)
@@ -533,9 +533,9 @@ void MainWindow::turnOffMovingMode()
     isMovingMode = false;
 }
 
-void MainWindow::updateTexture(unsigned int texture)
+void MainWindow::updateTexture(void *item)
 {
-    ((DisplayGLWidget *)getDisplay())->changedTexture(texture);
+    ((DisplayGLWidget *)getDisplay())->changedTexture((struct dpy_item *)item);
 }
 
 /* override */
index 5569607..84159c7 100644 (file)
@@ -88,7 +88,7 @@ public:
     void turnOnMovingMode();
     void turnOffMovingMode();
 
-    void updateTexture(unsigned int texture);
+    void updateTexture(void *dpy_item);
 
 public slots:
     void slotContextMenu(const QPoint &pos);
index 4ae6a2b..ba7091f 100644 (file)
@@ -594,9 +594,9 @@ void qt5_process_captured(bool captured, void *pixels, int width, int height)
     }
 }
 
-void qt5_update_texture(unsigned int tex_id)
+void qt5_update_texture(void *dpy_item)
 {
     if (mainwindow) {
-        mainwindow->updateTexture(tex_id);
+        mainwindow->updateTexture(dpy_item);
     }
 }