diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 586b01e9..cd2019c0 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -63,6 +63,7 @@ set(SOURCES renderers/egl/shader.c renderers/egl/texture.c renderers/egl/model.c + renderers/egl/desktop.c renderers/egl/cursor.c renderers/egl/fps.c fonts/sdl.c diff --git a/client/renderers/egl.c b/client/renderers/egl.c index 647e8a95..ff5e0901 100644 --- a/client/renderers/egl.c +++ b/client/renderers/egl.c @@ -28,7 +28,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "egl/model.h" #include "egl/shader.h" -#include "egl/progs.h" +#include "egl/desktop.h" #include "egl/cursor.h" #include "egl/fps.h" @@ -42,23 +42,6 @@ static struct Options defaultOptions = .vsync = false }; -struct Models -{ - struct EGL_Model * desktop; -}; - -struct Shaders -{ - struct EGL_Shader * rgba; - struct EGL_Shader * bgra; - struct EGL_Shader * yuv; -}; - -struct Textures -{ - struct EGL_Texture * desktop; -}; - struct Inst { LG_RendererParams params; @@ -71,27 +54,18 @@ struct Inst EGLSurface surface; EGLContext context; - EGL_Cursor * cursor; // the mouse cursor - EGL_FPS * fps; // the fps display - - struct Models models; - struct Shaders shaders; - struct Textures textures; + EGL_Desktop * desktop; // the desktop + EGL_Cursor * cursor; // the mouse cursor + EGL_FPS * fps; // the fps display LG_RendererFormat format; - enum EGL_PixelFormat pixFmt; - EGL_Shader * shader; bool sourceChanged; - size_t frameSize; - const uint8_t * data; - bool update; int width, height; LG_RendererRect destRect; float translateX, translateY; float scaleX , scaleY; - GLint uDesktopPos; float mouseWidth , mouseHeight; float mouseScaleX, mouseScaleY; @@ -157,14 +131,9 @@ void egl_deinitialize(void * opaque) if (this->font && this->fontObj) this->font->destroy(this->fontObj); - egl_cursor_free(&this->cursor); - egl_fps_free (&this->fps ); - - egl_model_free (&this->models .desktop ); - egl_shader_free (&this->shaders .rgba ); - egl_shader_free (&this->shaders .bgra ); - egl_shader_free (&this->shaders .yuv ); - egl_texture_free(&this->textures.desktop ); + egl_desktop_free(&this->desktop); + egl_cursor_free (&this->cursor); + egl_fps_free (&this->fps ); free(this); } @@ -231,7 +200,6 @@ bool egl_on_mouse_event(void * opaque, const bool visible , const int x, const i bool egl_on_frame_event(void * opaque, const LG_RendererFormat format, const uint8_t * data) { struct Inst * this = (struct Inst *)opaque; - this->sourceChanged = ( this->sourceChanged || this->format.type != format.type || @@ -241,46 +209,14 @@ bool egl_on_frame_event(void * opaque, const LG_RendererFormat format, const uin ); if (this->sourceChanged) - { memcpy(&this->format, &format, sizeof(LG_RendererFormat)); - switch(format.type) - { - case FRAME_TYPE_BGRA: - this->pixFmt = EGL_PF_BGRA; - this->shader = this->shaders.bgra; - this->frameSize = format.height * format.pitch; - break; - - case FRAME_TYPE_RGBA: - this->pixFmt = EGL_PF_RGBA; - this->shader = this->shaders.rgba; - this->frameSize = format.height * format.pitch; - break; - - case FRAME_TYPE_RGBA10: - this->pixFmt = EGL_PF_RGBA10; - this->shader = this->shaders.rgba; - this->frameSize = format.height * format.pitch; - break; - - case FRAME_TYPE_YUV420: - this->pixFmt = EGL_PF_YUV420; - this->shader = this->shaders.yuv; - this->frameSize = format.width * format.height * 3 / 2; - break; - - default: - DEBUG_ERROR("Unsupported frame format"); - return false; - } - - this->uDesktopPos = egl_shader_get_uniform_location(this->shader, "position"); + if (!egl_desktop_prepare_update(this->desktop, this->sourceChanged, format, data)) + { + DEBUG_INFO("Failed to prepare to update the desktop"); + return false; } - this->data = data; - this->update = true; - return true; } @@ -356,35 +292,14 @@ bool egl_render_startup(void * opaque, SDL_Window * window) DEBUG_INFO("Renderer: %s", glGetString(GL_RENDERER)); DEBUG_INFO("Version : %s", glGetString(GL_VERSION )); - if (!egl_shader_init(&this->shaders.rgba)) - return false; - - if (!egl_shader_init(&this->shaders.bgra)) - return false; - - if (!egl_shader_init(&this->shaders.yuv)) - return false; - - if (!egl_shader_compile(this->shaders.rgba, egl_vertex_shader_desktop, sizeof(egl_vertex_shader_desktop), egl_fragment_shader_rgba, sizeof(egl_fragment_shader_rgba))) - return false; - - if (!egl_shader_compile(this->shaders.bgra, egl_vertex_shader_desktop, sizeof(egl_vertex_shader_desktop), egl_fragment_shader_bgra, sizeof(egl_fragment_shader_bgra))) - return false; - - if (!egl_shader_compile(this->shaders.yuv, egl_vertex_shader_desktop, sizeof(egl_vertex_shader_desktop), egl_fragment_shader_yuv, sizeof(egl_fragment_shader_yuv))) - return false; - - if (!egl_texture_init(&this->textures.desktop)) - return false; - - if (!egl_model_init(&this->models.desktop)) - return false; - - egl_model_set_default(this->models.desktop); - egl_model_set_texture(this->models.desktop, this->textures.desktop); - eglSwapInterval(this->display, this->opt.vsync ? 1 : 0); + if (!egl_desktop_init(&this->desktop)) + { + DEBUG_ERROR("Failed to initialize the desktop"); + return false; + } + if (!egl_cursor_init(&this->cursor)) { DEBUG_ERROR("Failed to initialize the cursor"); @@ -407,42 +322,19 @@ bool egl_render(void * opaque, SDL_Window * window) glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); - if (this->shader) - { - egl_shader_use(this->shader); - glUniform4f(this->uDesktopPos, this->translateX, this->translateY, this->scaleX, this->scaleY); - egl_model_render(this->models.desktop); - } - + egl_desktop_render(this->desktop, this->translateX, this->translateY, this->scaleX, this->scaleY); egl_cursor_render(this->cursor); egl_fps_render(this->fps, this->width, this->height); eglSwapBuffers(this->display, this->surface); // defer texture uploads until after the flip to avoid stalling - if (this->update) + if (!egl_desktop_perform_update(this->desktop, this->sourceChanged)) { - if (this->sourceChanged) - { - this->sourceChanged = false; - if (!egl_texture_setup( - this->textures.desktop, - this->pixFmt, - this->format.width, - this->format.height, - this->frameSize, - true - )) - return false; - - egl_model_set_shader(this->models.desktop, this->shader); - } - - if (!egl_texture_update(this->textures.desktop, this->data)) - return false; - - this->update = false; + DEBUG_ERROR("Failed to perform the desktop update"); + return false; } + this->sourceChanged = false; return true; } diff --git a/client/renderers/egl/desktop.c b/client/renderers/egl/desktop.c new file mode 100644 index 00000000..5556315c --- /dev/null +++ b/client/renderers/egl/desktop.c @@ -0,0 +1,278 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +cahe 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.h" +#include "debug.h" +#include "utils.h" + +#include "texture.h" +#include "shader.h" +#include "model.h" + +#include +#include + +struct EGL_Desktop +{ + EGL_Texture * texture; + EGL_Shader * shader; // the active shader + EGL_Model * model; + + // shader instances + EGL_Shader * shader_generic; + EGL_Shader * shader_yuv; + + // uniforms + GLint uDesktopPos; + + // internals + enum EGL_PixelFormat pixFmt; + unsigned int width, height; + size_t frameSize; + const uint8_t * data; + bool update; +}; + +static const char vertex_shader[] = "\ +#version 300 es\n\ +\ +layout(location = 0) in vec3 vertexPosition_modelspace;\ +layout(location = 1) in vec2 vertexUV;\ +\ +uniform vec4 position;\ +\ +out highp vec2 uv;\ +\ +void main()\ +{\ + gl_Position.xyz = vertexPosition_modelspace; \ + gl_Position.w = 1.0; \ + gl_Position.x -= position.x; \ + gl_Position.y -= position.y; \ + gl_Position.x *= position.z; \ + gl_Position.y *= position.w; \ +\ + uv = vertexUV;\ +}\ +"; + + +static const char frag_generic[] = "\ +#version 300 es\n\ +\ +in highp vec2 uv;\ +out highp vec4 color;\ +\ +uniform sampler2D sampler1;\ + \ +void main()\ +{\ + color = texture(sampler1, uv);\ +}\ +"; + +static const char frag_yuv[] = "\ +#version 300 es\n\ +\ +in highp vec2 uv;\ +out highp vec4 color;\ +\ +uniform sampler2D sampler1;\ +uniform sampler2D sampler2;\ +uniform sampler2D sampler3;\ +\ +void main()\ +{\ + highp vec4 yuv = vec4(\ + texture(sampler1, uv).r,\ + texture(sampler2, uv).r,\ + texture(sampler3, uv).r,\ + 1.0\ + );\ + \ + highp mat4 yuv_to_rgb = mat4(\ + 1.0, 0.0 , 1.402, -0.701,\ + 1.0, -0.344, -0.714, 0.529,\ + 1.0, 1.772, 0.0 , -0.886,\ + 1.0, 1.0 , 1.0 , 1.0\ + );\ + \ + color = yuv * yuv_to_rgb;\ +}\ +"; + +bool egl_desktop_init(EGL_Desktop ** desktop) +{ + *desktop = (EGL_Desktop *)malloc(sizeof(EGL_Desktop)); + if (!*desktop) + { + DEBUG_ERROR("Failed to malloc EGL_Desktop"); + return false; + } + + memset(*desktop, 0, sizeof(EGL_Desktop)); + + if (!egl_texture_init(&(*desktop)->texture)) + { + DEBUG_ERROR("Failed to initialize the desktop texture"); + return false; + } + + if (!egl_shader_init(&(*desktop)->shader_generic)) + { + DEBUG_ERROR("Failed to initialize the generic desktop shader"); + return false; + } + + if (!egl_shader_init(&(*desktop)->shader_yuv)) + { + DEBUG_ERROR("Failed to initialize the yuv desktop shader"); + return false; + } + + if (!egl_shader_compile((*desktop)->shader_generic, + vertex_shader, sizeof(vertex_shader), + frag_generic , sizeof(frag_generic))) + { + DEBUG_ERROR("Failed to compile the generic desktop shader"); + return false; + } + + if (!egl_shader_compile((*desktop)->shader_yuv, + vertex_shader, sizeof(vertex_shader), + frag_yuv , sizeof(frag_yuv ))) + { + DEBUG_ERROR("Failed to compile the yuv desktop shader"); + return false; + } + + if (!egl_model_init(&(*desktop)->model)) + { + DEBUG_ERROR("Failed to initialize the desktop model"); + return false; + } + + egl_model_set_default((*desktop)->model); + egl_model_set_texture((*desktop)->model, (*desktop)->texture); + + return true; +} + +void egl_desktop_free(EGL_Desktop ** desktop) +{ + if (!*desktop) + return; + + egl_texture_free(&(*desktop)->texture ); + egl_shader_free (&(*desktop)->shader_generic); + egl_shader_free (&(*desktop)->shader_yuv ); + egl_model_free (&(*desktop)->model ); + + free(*desktop); + *desktop = NULL; +} + +bool egl_desktop_prepare_update(EGL_Desktop * desktop, const bool sourceChanged, const LG_RendererFormat format, const uint8_t * data) +{ + if (sourceChanged) + { + switch(format.type) + { + case FRAME_TYPE_BGRA: + desktop->pixFmt = EGL_PF_BGRA; + desktop->shader = desktop->shader_generic; + desktop->frameSize = format.height * format.pitch; + break; + + case FRAME_TYPE_RGBA: + desktop->pixFmt = EGL_PF_RGBA; + desktop->shader = desktop->shader_generic; + desktop->frameSize = format.height * format.pitch; + break; + + case FRAME_TYPE_RGBA10: + desktop->pixFmt = EGL_PF_RGBA10; + desktop->shader = desktop->shader_generic; + desktop->frameSize = format.height * format.pitch; + break; + + case FRAME_TYPE_YUV420: + desktop->pixFmt = EGL_PF_YUV420; + desktop->shader = desktop->shader_yuv; + desktop->frameSize = format.width * format.height * 3 / 2; + break; + + default: + DEBUG_ERROR("Unsupported frame format"); + return false; + } + + desktop->width = format.width; + desktop->height = format.height; + } + + desktop->data = data; + desktop->update = true; + + return true; +} + +bool egl_desktop_perform_update(EGL_Desktop * desktop, const bool sourceChanged) +{ + if (sourceChanged) + { + if (desktop->shader) + desktop->uDesktopPos = egl_shader_get_uniform_location(desktop->shader, "position"); + + if (!egl_texture_setup( + desktop->texture, + desktop->pixFmt, + desktop->width, + desktop->height, + desktop->frameSize, + true // streaming texture + )) + { + DEBUG_ERROR("Failed to setup the desktop texture"); + return false; + } + } + + if (!desktop->update) + return true; + + if (!egl_texture_update(desktop->texture, desktop->data)) + { + DEBUG_ERROR("Failed to update the desktop texture"); + return false; + } + + desktop->update = false; + return true; +} + +void egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY) +{ + if (!desktop->shader) + return; + + egl_shader_use(desktop->shader); + glUniform4f(desktop->uDesktopPos, x, y, scaleX, scaleY); + egl_model_render(desktop->model); +} \ No newline at end of file diff --git a/client/renderers/egl/desktop.h b/client/renderers/egl/desktop.h new file mode 100644 index 00000000..76cbd87e --- /dev/null +++ b/client/renderers/egl/desktop.h @@ -0,0 +1,33 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2017 Geoffrey McRae +https://looking-glass.hostfission.com + +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 "lg-renderer.h" + +typedef struct EGL_Desktop EGL_Desktop; + +bool egl_desktop_init(EGL_Desktop ** desktop); +void egl_desktop_free(EGL_Desktop ** desktop); + +bool egl_desktop_prepare_update(EGL_Desktop * desktop, const bool sourceChanged, const LG_RendererFormat format, const uint8_t * data); +bool egl_desktop_perform_update(EGL_Desktop * desktop, const bool sourceChanged); +void egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY); \ No newline at end of file diff --git a/client/renderers/egl/progs.h b/client/renderers/egl/progs.h deleted file mode 100644 index de4ece5f..00000000 --- a/client/renderers/egl/progs.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -Looking Glass - KVM FrameRelay (KVMFR) Client -Copyright (C) 2017 Geoffrey McRae -https://looking-glass.hostfission.com - -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 -*/ - -#ifndef _EGL_PROGS_H -#define _EGL_PROGS_H - -static const char egl_vertex_shader_desktop[] = "\ -#version 300 es\n\ -\ -layout(location = 0) in vec3 vertexPosition_modelspace;\ -layout(location = 1) in vec2 vertexUV;\ -\ -uniform vec4 position;\ -\ -out highp vec2 uv;\ -\ -void main()\ -{\ - gl_Position.xyz = vertexPosition_modelspace; \ - gl_Position.w = 1.0; \ - gl_Position.x -= position.x; \ - gl_Position.y -= position.y; \ - gl_Position.x *= position.z; \ - gl_Position.y *= position.w; \ -\ - uv = vertexUV;\ -}\ -"; - -static const char egl_fragment_shader_rgba[] = "\ -#version 300 es\n\ -\ -in highp vec2 uv;\ -out highp vec4 color;\ -\ -uniform sampler2D sampler1;\ - \ -void main()\ -{\ - color = texture(sampler1, uv);\ -}\ -"; - -static const char egl_fragment_shader_bgra[] = "\ -#version 300 es\n\ -\ -in highp vec2 uv;\ -out highp vec4 color;\ -\ -uniform sampler2D sampler1;\ -\ -void main()\ -{\ - color = texture(sampler1, uv);\ -}\ -"; - -static const char egl_fragment_shader_yuv[] = "\ -#version 300 es\n\ -\ -in highp vec2 uv;\ -out highp vec4 color;\ -\ -uniform sampler2D sampler1;\ -uniform sampler2D sampler2;\ -uniform sampler2D sampler3;\ -\ -void main()\ -{\ - highp vec4 yuv = vec4(\ - texture(sampler1, uv).r,\ - texture(sampler2, uv).r,\ - texture(sampler3, uv).r,\ - 1.0\ - );\ - \ - highp mat4 yuv_to_rgb = mat4(\ - 1.0, 0.0 , 1.402, -0.701,\ - 1.0, -0.344, -0.714, 0.529,\ - 1.0, 1.772, 0.0 , -0.886,\ - 1.0, 1.0 , 1.0 , 1.0\ - );\ - \ - color = yuv * yuv_to_rgb;\ -}\ -"; - -#endif \ No newline at end of file