diff --git a/client/renderers/EGL/CMakeLists.txt b/client/renderers/EGL/CMakeLists.txt index ecf04064..5d3a7ff2 100644 --- a/client/renderers/EGL/CMakeLists.txt +++ b/client/renderers/EGL/CMakeLists.txt @@ -43,6 +43,7 @@ add_library(renderer_EGL STATIC texture_dmabuf.c model.c desktop.c + desktop_rects.c cursor.c draw.c splash.c diff --git a/client/renderers/EGL/damage.c b/client/renderers/EGL/damage.c index 883f6b9f..73faaef4 100644 --- a/client/renderers/EGL/damage.c +++ b/client/renderers/EGL/damage.c @@ -24,6 +24,7 @@ #include "common/locking.h" #include "app.h" +#include "desktop_rects.h" #include "shader.h" #include @@ -35,12 +36,9 @@ struct EGL_Damage { - EGL_Shader * shader; - - GLfloat transform[6]; - GLuint buffers[2]; - GLuint vao; - int count; + EGL_Shader * shader; + EGL_DesktopRects * mesh; + GLfloat transform[6]; bool show; KeybindHandle toggleHandle; @@ -48,7 +46,7 @@ struct EGL_Damage int width , height; float translateX, translateY; float scaleX , scaleY; - bool rotate; + LG_RendererRotate rotate; // uniforms GLint uTransform; @@ -65,7 +63,7 @@ bool egl_damage_init(EGL_Damage ** damage) *damage = (EGL_Damage *)malloc(sizeof(EGL_Damage)); if (!*damage) { - DEBUG_ERROR("Failed to malloc EGL_Alert"); + DEBUG_ERROR("Failed to malloc EGL_Damage"); return false; } @@ -85,33 +83,12 @@ bool egl_damage_init(EGL_Damage ** damage) return false; } - glGenVertexArrays(1, &(*damage)->vao); - glBindVertexArray((*damage)->vao); - - glGenBuffers(2, (*damage)->buffers); - glBindBuffer(GL_ARRAY_BUFFER, (*damage)->buffers[0]); - glBufferData(GL_ARRAY_BUFFER, KVMFR_MAX_DAMAGE_RECTS * 8 * sizeof(GLfloat), NULL, GL_STREAM_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - GLushort indices[KVMFR_MAX_DAMAGE_RECTS * 6]; - for (int i = 0; i < KVMFR_MAX_DAMAGE_RECTS; ++i) + if (!egl_desktopRectsInit(&(*damage)->mesh, KVMFR_MAX_DAMAGE_RECTS)) { - indices[6 * i + 0] = 4 * i + 0; - indices[6 * i + 1] = 4 * i + 1; - indices[6 * i + 2] = 4 * i + 2; - indices[6 * i + 3] = 4 * i + 0; - indices[6 * i + 4] = 4 * i + 2; - indices[6 * i + 5] = 4 * i + 3; + DEBUG_ERROR("Failed to initialize the mesh"); + return false; } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (*damage)->buffers[1]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof indices, indices, GL_STATIC_DRAW); - - glBindVertexArray(0); - - (*damage)->count = -1; (*damage)->uTransform = egl_shader_get_uniform_location((*damage)->shader, "transform"); (*damage)->toggleHandle = app_registerKeybind(KEY_A, egl_damage_show_toggle, *damage, "Toggle damage display"); @@ -124,8 +101,7 @@ void egl_damage_free(EGL_Damage ** damage) return; app_releaseKeybind(&(*damage)->toggleHandle); - glDeleteVertexArrays(1, &(*damage)->vao); - glDeleteBuffers(2, (*damage)->buffers); + egl_desktopRectsFree(&(*damage)->mesh); egl_shader_free(&(*damage)->shader); free(*damage); @@ -134,14 +110,8 @@ void egl_damage_free(EGL_Damage ** damage) static void update_matrix(EGL_Damage * damage) { - int width = damage->rotate ? damage->height : damage->width; - int height = damage->rotate ? damage->width : damage->height; - damage->transform[0] = 2.0f * damage->scaleX / width; - damage->transform[1] = 0.0f; - damage->transform[2] = 0.0f; - damage->transform[3] = -2.0f * damage->scaleY / height; - damage->transform[4] = damage->translateX - damage->scaleX; - damage->transform[5] = damage->translateY + damage->scaleY; + egl_desktopRectsMatrix(damage->transform, damage->width, damage->height, + damage->translateX, damage->translateY, damage->scaleX, damage->scaleY, damage->rotate); } void egl_damage_setup(EGL_Damage * damage, int width, int height) @@ -161,21 +131,9 @@ void egl_damage_resize(EGL_Damage * damage, float translateX, float translateY, update_matrix(damage); } -inline static void rectToVertices(GLfloat * vertex, const FrameDamageRect * rect) +bool egl_damage_render(EGL_Damage * damage, LG_RendererRotate rotate, const struct DesktopDamage * data) { - vertex[0] = rect->x; - vertex[1] = rect->y; - vertex[2] = rect->x + rect->width; - vertex[3] = rect->y; - vertex[4] = rect->x + rect->width; - vertex[5] = rect->y + rect->height; - vertex[6] = rect->x; - vertex[7] = rect->y + rect->height; -} - -bool egl_damage_render(EGL_Damage * damage, bool rotate, const struct DesktopDamage * data) -{ - if (!damage->show || (!data && damage->count == -1)) + if (!damage->show) return false; if (rotate != damage->rotate) @@ -191,32 +149,10 @@ bool egl_damage_render(EGL_Damage * damage, bool rotate, const struct DesktopDam glUniformMatrix3x2fv(damage->uTransform, 1, GL_FALSE, damage->transform); if (data && data->count != 0) - { - damage->count = data->count; - GLfloat vertices[KVMFR_MAX_DAMAGE_RECTS * 8]; - if (damage->count == -1) - { - FrameDamageRect full = { - .x = 0, .y = 0, .width = damage->width, .height = damage->height, - }; - damage->count = 1; - rectToVertices(vertices, &full); - } - else - { - for (int i = 0; i < damage->count; ++i) - rectToVertices(vertices + i * 8, data->rects + i); - } + egl_desktopRectsUpdate(damage->mesh, (const struct DamageRects *) data, + damage->width, damage->height); - glBindBuffer(GL_ARRAY_BUFFER, damage->buffers[0]); - glBufferSubData(GL_ARRAY_BUFFER, 0, damage->count * 8 * sizeof(GLfloat), - vertices); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - glBindVertexArray(damage->vao); - glDrawElements(GL_TRIANGLES, 6 * damage->count, GL_UNSIGNED_SHORT, NULL); - glBindVertexArray(0); + egl_desktopRectsRender(damage->mesh); glDisable(GL_BLEND); return true; diff --git a/client/renderers/EGL/damage.h b/client/renderers/EGL/damage.h index 8c9b51a7..caab243e 100644 --- a/client/renderers/EGL/damage.h +++ b/client/renderers/EGL/damage.h @@ -22,6 +22,8 @@ #include #include "common/KVMFR.h" +#include "interface/renderer.h" +#include "desktop_rects.h" struct DesktopDamage { @@ -37,4 +39,5 @@ void egl_damage_free(EGL_Damage ** damage); void egl_damage_setup(EGL_Damage * damage, int width, int height); void egl_damage_resize(EGL_Damage * damage, float translateX, float translateY, float scaleX, float scaleY); -bool egl_damage_render(EGL_Damage * damage, bool rotate, const struct DesktopDamage * data); +bool egl_damage_render(EGL_Damage * damage, LG_RendererRotate rotate, + const struct DesktopDamage * data); diff --git a/client/renderers/EGL/desktop_rects.c b/client/renderers/EGL/desktop_rects.c new file mode 100644 index 00000000..e58f0264 --- /dev/null +++ b/client/renderers/EGL/desktop_rects.c @@ -0,0 +1,230 @@ +/** + * Looking Glass + * Copyright (C) 2017-2021 The Looking Glass Authors + * https://looking-glass.io + * + * 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., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "desktop_rects.h" +#include "common/debug.h" +#include "common/KVMFR.h" +#include "common/locking.h" + +#include +#include +#include +#include + +#include "util.h" + +struct EGL_DesktopRects +{ + GLuint buffers[2]; + GLuint vao; + int count; + int maxCount; +}; + +bool egl_desktopRectsInit(EGL_DesktopRects ** rects_, int maxCount) +{ + EGL_DesktopRects * rects = malloc(sizeof(EGL_DesktopRects)); + if (!rects) + { + DEBUG_ERROR("Failed to malloc EGL_DesktopRects"); + return false; + } + *rects_ = rects; + memset(rects, 0, sizeof(EGL_DesktopRects)); + + glGenVertexArrays(1, &rects->vao); + glBindVertexArray(rects->vao); + + glGenBuffers(2, rects->buffers); + glBindBuffer(GL_ARRAY_BUFFER, rects->buffers[0]); + glBufferData(GL_ARRAY_BUFFER, maxCount * 8 * sizeof(GLfloat), NULL, GL_STREAM_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + GLushort indices[maxCount * 6]; + for (int i = 0; i < maxCount; ++i) + { + indices[6 * i + 0] = 4 * i + 0; + indices[6 * i + 1] = 4 * i + 1; + indices[6 * i + 2] = 4 * i + 2; + indices[6 * i + 3] = 4 * i + 0; + indices[6 * i + 4] = 4 * i + 2; + indices[6 * i + 5] = 4 * i + 3; + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rects->buffers[1]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof indices, indices, GL_STATIC_DRAW); + + glBindVertexArray(0); + + rects->count = 0; + rects->maxCount = maxCount; + return true; +} + +void egl_desktopRectsFree(EGL_DesktopRects ** rects_) +{ + EGL_DesktopRects * rects = *rects_; + if (!rects) + return; + + glDeleteVertexArrays(1, &rects->vao); + glDeleteBuffers(2, rects->buffers); + free(rects); + *rects_ = NULL; +} + +inline static void rectToVertices(GLfloat * vertex, const FrameDamageRect * rect) +{ + vertex[0] = rect->x; + vertex[1] = rect->y; + vertex[2] = rect->x + rect->width; + vertex[3] = rect->y; + vertex[4] = rect->x + rect->width; + vertex[5] = rect->y + rect->height; + vertex[6] = rect->x; + vertex[7] = rect->y + rect->height; +} + +void egl_desktopRectsUpdate(EGL_DesktopRects * rects, const struct DamageRects * data, + int width, int height) +{ + GLfloat vertices[KVMFR_MAX_DAMAGE_RECTS * 8]; + if (!data || data->count < 0) + { + FrameDamageRect full = { + .x = 0, .y = 0, .width = width, .height = height, + }; + rects->count = 1; + rectToVertices(vertices, &full); + } + else + { + rects->count = data->count; + assert(rects->count <= rects->maxCount); + + for (int i = 0; i < rects->count; ++i) + rectToVertices(vertices + i * 8, data->rects + i); + } + + glBindBuffer(GL_ARRAY_BUFFER, rects->buffers[0]); + glBufferSubData(GL_ARRAY_BUFFER, 0, rects->count * 8 * sizeof(GLfloat), vertices); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +static void desktopToGLSpace(double matrix[6], int width, int height, double translateX, + double translateY, double scaleX, double scaleY, LG_RendererRotate rotate) +{ + switch (rotate) + { + case LG_ROTATE_0: + matrix[0] = 2.0 * scaleX / width; + matrix[1] = 0.0; + matrix[2] = 0.0; + matrix[3] = -2.0 * scaleY / height; + matrix[4] = translateX - scaleX; + matrix[5] = translateY + scaleY; + return; + + case LG_ROTATE_90: + matrix[0] = 0.0; + matrix[1] = -2.0 * scaleY / width; + matrix[2] = -2.0 * scaleX / height; + matrix[3] = 0.0; + matrix[4] = translateX + scaleX; + matrix[5] = translateY + scaleY; + return; + + case LG_ROTATE_180: + matrix[0] = -2.0 * scaleX / width; + matrix[1] = 0.0; + matrix[2] = 0.0; + matrix[3] = 2.0 * scaleY / height; + matrix[4] = translateX + scaleX; + matrix[5] = translateY - scaleY; + return; + + case LG_ROTATE_270: + matrix[0] = 0.0; + matrix[1] = 2.0 * scaleY / width; + matrix[2] = 2.0 * scaleX / height; + matrix[3] = 0.0; + matrix[4] = translateX - scaleX; + matrix[5] = translateY - scaleY; + } +} + +void egl_desktopRectsMatrix(float matrix[6], int width, int height, float translateX, + float translateY, float scaleX, float scaleY, LG_RendererRotate rotate) +{ + double temp[6]; + desktopToGLSpace(temp, width, height, translateX, translateY, scaleX, scaleY, rotate); + for (int i = 0; i < 6; ++i) + matrix[i] = temp[i]; +} + +void egl_desktopToScreenMatrix(double matrix[6], int frameWidth, int frameHeight, + double translateX, double translateY, double scaleX, double scaleY, LG_RendererRotate rotate, + double windowWidth, double windowHeight) +{ + desktopToGLSpace(matrix, frameWidth, frameHeight, translateX, translateY, scaleX, scaleY, rotate); + + double hw = windowWidth / 2; + double hh = windowHeight / 2; + matrix[0] *= hw; + matrix[1] *= hh; + matrix[2] *= hw; + matrix[3] *= hh; + matrix[4] = matrix[4] * hw + hw; + matrix[5] = matrix[5] * hh + hh; +} + +inline static void matrixMultiply(const double matrix[6], double * nx, double * ny, double x, double y) +{ + *nx = matrix[0] * x + matrix[2] * y + matrix[4]; + *ny = matrix[1] * x + matrix[3] * y + matrix[5]; +} + +struct Rect egl_desktopToScreen(const double matrix[6], const struct FrameDamageRect * rect) +{ + double x1, y1, x2, y2; + matrixMultiply(matrix, &x1, &y1, rect->x, rect->y); + matrixMultiply(matrix, &x2, &y2, rect->x + rect->width, rect->y + rect->height); + + int x3 = min(x1, x2); + int y3 = min(y1, y2); + return (struct Rect) { + .x = x3, + .y = y3, + .w = ceil(max(x1, x2)) - x3, + .h = ceil(max(y1, y2)) - y3, + }; +} + +void egl_desktopRectsRender(EGL_DesktopRects * rects) +{ + if (!rects->count) + return; + + glBindVertexArray(rects->vao); + glDrawElements(GL_TRIANGLES, 6 * rects->count, GL_UNSIGNED_SHORT, NULL); + glBindVertexArray(0); +} diff --git a/client/renderers/EGL/desktop_rects.h b/client/renderers/EGL/desktop_rects.h new file mode 100644 index 00000000..7ee38009 --- /dev/null +++ b/client/renderers/EGL/desktop_rects.h @@ -0,0 +1,47 @@ +/** + * Looking Glass + * Copyright (C) 2017-2021 The Looking Glass Authors + * https://looking-glass.io + * + * 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., 59 + * Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma once + +#include +#include "common/types.h" +#include "interface/renderer.h" + +struct DamageRects +{ + int count; + FrameDamageRect rects[]; +}; + +typedef struct EGL_DesktopRects EGL_DesktopRects; + +bool egl_desktopRectsInit(EGL_DesktopRects ** rects, int maxCount); +void egl_desktopRectsFree(EGL_DesktopRects ** rects); + +void egl_desktopRectsMatrix(float matrix[6], int width, int height, float translateX, + float translateY, float scaleX, float scaleY, LG_RendererRotate rotate); +void egl_desktopToScreenMatrix(double matrix[6], int frameWidth, int frameHeight, + double translateX, double translateY, double scaleX, double scaleY, LG_RendererRotate rotate, + double windowWidth, double windowHeight); +struct Rect egl_desktopToScreen(const double matrix[6], const struct FrameDamageRect * rect); + +void egl_desktopRectsUpdate(EGL_DesktopRects * rects, const struct DamageRects * data, + int width, int height); +void egl_desktopRectsRender(EGL_DesktopRects * rects); \ No newline at end of file diff --git a/client/renderers/EGL/egl.c b/client/renderers/EGL/egl.c index 15031217..3ea043d6 100644 --- a/client/renderers/EGL/egl.c +++ b/client/renderers/EGL/egl.c @@ -880,69 +880,7 @@ static bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFr hasOverlay = true; } - if (desktopDamage->count > 0 && rotate != LG_ROTATE_0) - { - for (int i = 0; i < desktopDamage->count; ++i) - { - FrameDamageRect * r = desktopDamage->rects + i; - - switch (rotate) - { - case LG_ROTATE_90: - *r = (FrameDamageRect) { - .x = this->format.height - r->y - r->height, - .y = r->x, - .width = r->height, - .height = r->width, - }; - break; - - case LG_ROTATE_180: - r->x = this->format.width - r->x - r->width; - r->y = this->format.height - r->y - r->height; - break; - - case LG_ROTATE_270: - *r = (FrameDamageRect) { - .x = r->y, - .y = this->format.width - r->x - r->width, - .width = r->height, - .height = r->width, - }; - break; - - case LG_ROTATE_0: - default: - assert(!"unreachable"); - } - } - } - - double scaleX = 0; - double scaleY = 0; - bool rotated = false; - - switch (rotate) - { - case LG_ROTATE_0: - case LG_ROTATE_180: - scaleX = (double) this->destRect.w / this->format.width; - scaleY = (double) this->destRect.h / this->format.height; - rotated = false; - break; - - case LG_ROTATE_90: - case LG_ROTATE_270: - scaleX = (double) this->destRect.w / this->format.height; - scaleY = (double) this->destRect.h / this->format.width; - rotated = true; - break; - - default: - assert(!"unreachable"); - } - - hasOverlay |= egl_damage_render(this->damage, rotated, newFrame ? desktopDamage : NULL); + hasOverlay |= egl_damage_render(this->damage, rotate, newFrame ? desktopDamage : NULL); hasOverlay |= invalidateWindow; struct Rect damage[KVMFR_MAX_DAMAGE_RECTS + MAX_OVERLAY_RECTS + 2]; @@ -976,20 +914,13 @@ static bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFr damageIdx = 0; else { + double matrix[6]; + egl_desktopToScreenMatrix(matrix, this->format.width, this->format.height, + this->translateX, this->translateY, this->scaleX, this->scaleY, rotate, + this->width, this->height); + for (int i = 0; i < desktopDamage->count; ++i) - { - FrameDamageRect rect = desktopDamage->rects[i]; - int x1 = (int) (rect.x * scaleX); - int y1 = (int) (rect.y * scaleY); - int x2 = (int) ceil((rect.x + rect.width) * scaleX); - int y2 = (int) ceil((rect.y + rect.height) * scaleY); - damage[damageIdx++] = (struct Rect) { - .x = this->destRect.x + x1, - .y = this->height - (this->destRect.y + y2), - .w = x2 - x1, - .h = y2 - y1, - }; - } + damage[damageIdx++] = egl_desktopToScreen(matrix, desktopDamage->rects + i); } } else