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>
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));
+ }
}
}
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);
{
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;
return false;
}
- gl_backend->dpy_tex = tmp_tex;
+ gl_backend->current_dpy->tex = tmp_tex;
gl_backend->BindTexture(GL_TEXTURE_2D, tmp_tex);
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;
}
}
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);
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);
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;
}
}
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);
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:
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);
#include <GL/glext.h>
#include "winsys_gl.h"
+#define TEXTURE_NUM 5
+
struct vigs_gl_pool;
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;
/*
* @}
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)
{
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);
}
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
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;
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;
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);
+ }
}
}
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();
}
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];
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);
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(),
-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);
(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) {
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(¤t->mutex);
+ current->available = true;
+ qemu_mutex_unlock(¤t->mutex);
+ }
+ current = next;
+ next = NULL;
+ }
+ textureListMutex.unlock();
+
+ if (current) {
+ drawQuad(current->tex, false);
+ }
- drawQuad(dpyTexture, false);
if (isTsEnabled) {
drawMultiTouchPoints();
}
#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;
QSize resolution, qreal scaleFactor);
~DisplayGLWidget();
- void changedTexture(unsigned int texture);
+ void changedTexture(struct dpy_item *tex);
protected:
void initializeGL();
QImage maskQImage;
GLuint maskTexture;
- GLuint dpyTexture;
+ dpy_item* current;
+ dpy_item* next;
+ QMutex textureListMutex;
+
GLuint mtTexture;
QMatrix4x4 mOrtho;
GLfloat mVertCoords[12];
QOpenGLBuffer *mVBO;
QOpenGLShaderProgram *texProgram;
QOpenGLShaderProgram *scaleProgram;
+
};
#endif // DISPLAYGLWIDGET_H
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 */
void turnOnMovingMode();
void turnOffMovingMode();
- void updateTexture(unsigned int texture);
+ void updateTexture(void *dpy_item);
public slots:
void slotContextMenu(const QPoint &pos);
}
}
-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);
}
}