diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index c90b85d3..586b01e9 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -64,6 +64,7 @@ set(SOURCES renderers/egl/texture.c renderers/egl/model.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 01f00eb2..29c4cbe0 100644 --- a/client/renderers/egl.c +++ b/client/renderers/egl.c @@ -30,6 +30,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "egl/shader.h" #include "egl/progs.h" #include "egl/cursor.h" +#include "egl/fps.h" struct Options { @@ -44,7 +45,6 @@ static struct Options defaultOptions = struct Models { struct EGL_Model * desktop; - struct EGL_Model * fps; }; struct Shaders @@ -52,13 +52,11 @@ struct Shaders struct EGL_Shader * rgba; struct EGL_Shader * bgra; struct EGL_Shader * yuv; - struct EGL_Shader * fps; }; struct Textures { struct EGL_Texture * desktop; - struct EGL_Texture * fps; }; struct Inst @@ -74,6 +72,7 @@ struct Inst EGLContext context; EGL_Cursor * cursor; // the mouse cursor + EGL_FPS * fps; // the fps display struct Models models; struct Shaders shaders; @@ -99,10 +98,6 @@ struct Inst const LG_Font * font; LG_FontObj fontObj; - - bool fpsReady; - float fpsWidth, fpsHeight; - GLint uFPSScreen, uFPSSize; }; @@ -163,15 +158,13 @@ void egl_deinitialize(void * opaque) this->font->destroy(this->fontObj); egl_cursor_free(&this->cursor); + egl_fps_free (&this->fps ); egl_model_free (&this->models .desktop ); - egl_model_free (&this->models .fps ); egl_shader_free (&this->shaders .rgba ); egl_shader_free (&this->shaders .bgra ); egl_shader_free (&this->shaders .yuv ); - egl_shader_free (&this->shaders .fps ); egl_texture_free(&this->textures.desktop ); - egl_texture_free(&this->textures.fps ); free(this); } @@ -388,9 +381,6 @@ bool egl_render_startup(void * opaque, SDL_Window * window) if (!egl_shader_init(&this->shaders.yuv)) return false; - if (!egl_shader_init(&this->shaders.fps)) - 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; @@ -400,33 +390,16 @@ bool egl_render_startup(void * opaque, SDL_Window * window) 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_shader_compile(this->shaders.fps, egl_vertex_shader_fps, sizeof(egl_vertex_shader_fps), egl_fragment_shader_fps, sizeof(egl_fragment_shader_fps))) - return false; - - this->uFPSSize = egl_shader_get_uniform_location(this->shaders.fps , "size" ); - this->uFPSScreen = egl_shader_get_uniform_location(this->shaders.fps , "screen" ); - if (!egl_texture_init(&this->textures.desktop)) return false; - if (!egl_texture_init(&this->textures.fps)) - return false; - if (!egl_model_init(&this->models.desktop)) return false; - if (!egl_model_init(&this->models.fps)) - return false; - - egl_model_set_verticies(this->models.desktop, square , sizeof(square) / sizeof(GLfloat)); egl_model_set_uvs (this->models.desktop, uvs , sizeof(uvs ) / sizeof(GLfloat)); egl_model_set_texture (this->models.desktop, this->textures.desktop); - egl_model_set_verticies(this->models.fps, square, sizeof(square) / sizeof(GLfloat)); - egl_model_set_uvs (this->models.fps, uvs , sizeof(uvs ) / sizeof(GLfloat)); - egl_model_set_texture (this->models.fps, this->textures.fps); - eglSwapInterval(this->display, this->opt.vsync ? 1 : 0); if (!egl_cursor_init(&this->cursor)) @@ -435,6 +408,12 @@ bool egl_render_startup(void * opaque, SDL_Window * window) return false; } + if (!egl_fps_init(&this->fps, this->font, this->fontObj)) + { + DEBUG_ERROR("Failed to initialize the FPS display"); + return false; + } + return true; } @@ -453,17 +432,7 @@ bool egl_render(void * opaque, SDL_Window * window) } egl_cursor_render(this->cursor); - - if (this->fpsReady) - { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - egl_shader_use(this->shaders.fps); - glUniform2f(this->uFPSScreen, this->width , this->height ); - glUniform2f(this->uFPSSize , this->fpsWidth, this->fpsHeight); - egl_model_render(this->models.fps); - glDisable(GL_BLEND); - } + egl_fps_render(this->fps, this->width, this->height); eglSwapBuffers(this->display, this->surface); @@ -501,36 +470,7 @@ void egl_update_fps(void * opaque, const float avgFPS, const float renderFPS) if (!this->params.showFPS) return; - char str[128]; - snprintf(str, sizeof(str), "UPS: %8.4f, FPS: %8.4f", avgFPS, renderFPS); - - LG_FontBitmap * bmp = this->font->render(this->fontObj, 0xffffff00, str); - if (!bmp) - { - DEBUG_ERROR("Failed to render FPS text"); - return; - } - - egl_texture_setup( - this->textures.fps, - EGL_PF_BGRA, - bmp->width , - bmp->height, - bmp->width * bmp->height * bmp->bpp, - false - ); - - egl_texture_update - ( - this->textures.fps, - bmp->pixels - ); - - this->fpsWidth = bmp->width; - this->fpsHeight = bmp->height; - this->fpsReady = true; - - this->font->release(this->fontObj, bmp); + egl_fps_update(this->fps, avgFPS, renderFPS); } static void handle_opt_vsync(void * opaque, const char *value) diff --git a/client/renderers/egl/fps.c b/client/renderers/egl/fps.c new file mode 100644 index 00000000..5b5c4589 --- /dev/null +++ b/client/renderers/egl/fps.c @@ -0,0 +1,223 @@ +/* +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 "fps.h" +#include "debug.h" +#include "utils.h" + +#include "texture.h" +#include "shader.h" +#include "model.h" + +#include +#include + +struct EGL_FPS +{ + const LG_Font * font; + LG_FontObj fontObj; + + EGL_Texture * texture; + EGL_Shader * shader; + EGL_Model * model; + + bool ready; + float width, height; + + // uniforms + GLint uScreen, uSize; +}; + +static const char vertex_shader[] = "\ +#version 300 es\n\ +\ +layout(location = 0) in vec3 vertexPosition_modelspace;\ +layout(location = 1) in vec2 vertexUV;\ +\ +uniform vec2 screen;\ +uniform vec2 size;\ +\ +out highp vec2 uv;\ +\ +void main()\ +{\ + highp vec2 pix = (vec2(1.0, 1.0) / screen); \ + gl_Position.xyz = vertexPosition_modelspace; \ + gl_Position.w = 1.0; \ + gl_Position.x *= pix.x * size.x; \ + gl_Position.y *= pix.y * size.y; \ + gl_Position.x -= 1.0 - (pix.x * size.x);\ + gl_Position.y += 1.0 - (pix.y * size.y);\ + gl_Position.x += pix.x * 10.0; \ + gl_Position.y -= pix.y * 10.0; \ +\ + uv = vertexUV;\ +}\ +"; + +static const char frag_shader[] = "\ +#version 300 es\n\ +\ +in highp vec2 uv;\ +out highp vec4 color;\ +\ +uniform sampler2D sampler1;\ +\ +void main()\ +{\ + highp vec4 tmp = texture(sampler1, uv);\ + color.r = tmp.b; \ + color.g = tmp.g; \ + color.b = tmp.r; \ + color.a = tmp.a; \ + if (color.a == 0.0) \ + {\ + color.a = 0.5; \ + color.r = 0.0; \ + color.g = 0.0; \ + }\ +}\ +"; + +bool egl_fps_init(EGL_FPS ** fps, const LG_Font * font, LG_FontObj fontObj) +{ + *fps = (EGL_FPS *)malloc(sizeof(EGL_FPS)); + if (!*fps) + { + DEBUG_ERROR("Failed to malloc EGL_FPS"); + return false; + } + + memset(*fps, 0, sizeof(EGL_FPS)); + + (*fps)->font = font; + (*fps)->fontObj = fontObj; + + if (!egl_texture_init(&(*fps)->texture)) + { + DEBUG_ERROR("Failed to initialize the fps texture"); + return false; + } + + if (!egl_shader_init(&(*fps)->shader)) + { + DEBUG_ERROR("Failed to initialize the fps shader"); + return false; + } + + if (!egl_shader_compile((*fps)->shader, + vertex_shader, sizeof(vertex_shader), + frag_shader, sizeof(frag_shader))) + { + DEBUG_ERROR("Failed to compile the fps shader"); + return false; + } + + (*fps)->uSize = egl_shader_get_uniform_location((*fps)->shader, "size" ); + (*fps)->uScreen = egl_shader_get_uniform_location((*fps)->shader, "screen"); + + if (!egl_model_init(&(*fps)->model)) + { + DEBUG_ERROR("Failed to initialize the fps model"); + return false; + } + + static const GLfloat square[] = + { + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.0f + }; + + static const GLfloat uvs[] = + { + 0.0f, 1.0f, + 1.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f + }; + + egl_model_set_verticies((*fps)->model, square, sizeof(square) / sizeof(GLfloat)); + egl_model_set_uvs ((*fps)->model, uvs , sizeof(uvs ) / sizeof(GLfloat)); + egl_model_set_texture ((*fps)->model, (*fps)->texture); + + return true; +} + +void egl_fps_free(EGL_FPS ** fps) +{ + if (!*fps) + return; + + egl_texture_free(&(*fps)->texture); + egl_shader_free (&(*fps)->shader ); + egl_model_free (&(*fps)->model ); + + free(*fps); + *fps = NULL; +} + +void egl_fps_update(EGL_FPS * fps, const float avgFPS, const float renderFPS) +{ + char str[128]; + snprintf(str, sizeof(str), "UPS: %8.4f, FPS: %8.4f", avgFPS, renderFPS); + + LG_FontBitmap * bmp = fps->font->render(fps->fontObj, 0xffffff00, str); + if (!bmp) + { + DEBUG_ERROR("Failed to render fps text"); + return; + } + + egl_texture_setup( + fps->texture, + EGL_PF_BGRA, + bmp->width , + bmp->height, + bmp->width * bmp->height * bmp->bpp, + false + ); + + egl_texture_update + ( + fps->texture, + bmp->pixels + ); + + fps->width = bmp->width; + fps->height = bmp->height; + fps->ready = true; + + fps->font->release(fps->fontObj, bmp); +} + +void egl_fps_render(EGL_FPS * fps, float screenWidth, float screenHeight) +{ + if (!fps->ready) + return; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + egl_shader_use(fps->shader); + glUniform2f(fps->uScreen, screenWidth, screenHeight); + glUniform2f(fps->uSize , fps->width , fps->height ); + egl_model_render(fps->model); + glDisable(GL_BLEND); +} \ No newline at end of file diff --git a/client/renderers/egl/fps.h b/client/renderers/egl/fps.h new file mode 100644 index 00000000..c73919e7 --- /dev/null +++ b/client/renderers/egl/fps.h @@ -0,0 +1,32 @@ +/* +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-fonts.h" + +typedef struct EGL_FPS EGL_FPS; + +bool egl_fps_init(EGL_FPS ** fps, const LG_Font * font, LG_FontObj fontObj); +void egl_fps_free(EGL_FPS ** fps); + +void egl_fps_update(EGL_FPS * fps, const float avgFPS, const float renderFPS); +void egl_fps_render(EGL_FPS * fps, const float screenWidth, const float screenHeight); \ No newline at end of file diff --git a/client/renderers/egl/progs.h b/client/renderers/egl/progs.h index cf0835a9..de4ece5f 100644 --- a/client/renderers/egl/progs.h +++ b/client/renderers/egl/progs.h @@ -101,56 +101,4 @@ void main()\ }\ "; -static const char egl_vertex_shader_fps[] = "\ -#version 300 es\n\ -\ -layout(location = 0) in vec3 vertexPosition_modelspace;\ -layout(location = 1) in vec2 vertexUV;\ -\ -uniform vec2 screen;\ -uniform vec2 size;\ -\ -out highp vec2 uv;\ -\ -void main()\ -{\ - highp vec2 pix = (vec2(1.0, 1.0) / screen); \ - gl_Position.xyz = vertexPosition_modelspace; \ - gl_Position.w = 1.0; \ - gl_Position.x *= pix.x * size.x; \ - gl_Position.y *= pix.y * size.y; \ - gl_Position.x -= 1.0 - (pix.x * size.x);\ - gl_Position.y += 1.0 - (pix.y * size.y);\ - gl_Position.x += pix.x * 10.0; \ - gl_Position.y -= pix.y * 10.0; \ -\ - uv = vertexUV;\ -}\ -"; - -static const char egl_fragment_shader_fps[] = "\ -#version 300 es\n\ -\ -in highp vec2 uv;\ -out highp vec4 color;\ -\ -uniform sampler2D sampler1;\ -\ -void main()\ -{\ - highp vec4 tmp = texture(sampler1, uv);\ - color.r = tmp.b; \ - color.g = tmp.g; \ - color.b = tmp.r; \ - color.a = tmp.a; \ - if (color.a == 0.0) \ - {\ - color.a = 0.5; \ - color.r = 0.0; \ - color.g = 0.0; \ - }\ -}\ -"; - - #endif \ No newline at end of file