From ab98c87e7c4797ba5bb049a7deca84d964058bcb Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Tue, 20 Nov 2018 09:50:09 +1100 Subject: [PATCH] [client] egl: added FPS rendering --- client/CMakeLists.txt | 3 +- client/fonts/sdl.c | 4 +- client/lg-font.h | 1 + client/lg-fonts.h | 10 +-- client/renderers/egl.c | 108 ++++++++++++++++++++++++++-- client/renderers/egl_shader_progs.h | 56 +++++++++++++++ 6 files changed, 165 insertions(+), 17 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 90166c7c..24741c43 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -50,6 +50,7 @@ link_libraries( set(SOURCES main.c lg-renderer.c + lg-fonts.c ll.c utils.c spice/rsa.c @@ -60,7 +61,7 @@ set(SOURCES renderers/egl.c renderers/egl_shader.c renderers/egl_texture.c - renderers/egl_model.c + renderers/egl_model.c fonts/sdl.c ) diff --git a/client/fonts/sdl.c b/client/fonts/sdl.c index c2a4fadc..b783d34a 100644 --- a/client/fonts/sdl.c +++ b/client/fonts/sdl.c @@ -116,7 +116,7 @@ static LG_FontBitmap * lgf_sdl_render(LG_FontObj opaque, unsigned int fg_color, if (!(surface = TTF_RenderText_Blended(this->font, text, color))) { DEBUG_ERROR("Failed to render text: %s", TTF_GetError()); - return false; + return NULL; } LG_FontBitmap * out = malloc(sizeof(LG_FontBitmap)); @@ -124,7 +124,7 @@ static LG_FontBitmap * lgf_sdl_render(LG_FontObj opaque, unsigned int fg_color, { SDL_FreeSurface(surface); DEBUG_ERROR("Failed to allocate memory for font bitmap"); - return false; + return NULL; } out->reserved = surface; diff --git a/client/lg-font.h b/client/lg-font.h index 898bd471..f5b3b921 100644 --- a/client/lg-font.h +++ b/client/lg-font.h @@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #pragma once #include +#include typedef void * LG_FontObj; typedef struct LG_FontBitmap diff --git a/client/lg-fonts.h b/client/lg-fonts.h index 82c6d04c..7ab815bb 100644 --- a/client/lg-fonts.h +++ b/client/lg-fonts.h @@ -20,12 +20,4 @@ Place, Suite 330, Boston, MA 02111-1307 USA #pragma once #include "lg-font.h" -extern const LG_Font LGF_SDL; - -const LG_Font * LG_Fonts[] = -{ - &LGF_SDL, - NULL // end of array sentinal -}; - -#define LG_FONT_COUNT ((sizeof(LG_Font) / sizeof(LG_Font *)) - 1) \ No newline at end of file +extern const LG_Font * LG_Fonts[]; \ No newline at end of file diff --git a/client/renderers/egl.c b/client/renderers/egl.c index a5e6ac7e..c776989b 100644 --- a/client/renderers/egl.c +++ b/client/renderers/egl.c @@ -18,8 +18,10 @@ Place, Suite 330, Boston, MA 02111-1307 USA */ #include "lg-renderer.h" + #include "debug.h" #include "utils.h" +#include "lg-fonts.h" #include #include @@ -42,6 +44,7 @@ struct Models { struct EGL_Model * desktop; struct EGL_Model * mouse; + struct EGL_Model * fps; }; struct Shaders @@ -52,6 +55,8 @@ struct Shaders struct EGL_Shader * mouse; struct EGL_Shader * mouse_mono; + + struct EGL_Shader * fps; }; struct Textures @@ -59,6 +64,7 @@ struct Textures struct EGL_Texture * desktop; struct EGL_Texture * mouse; struct EGL_Texture * mouse_mono; + struct EGL_Texture * fps; }; struct Inst @@ -85,6 +91,9 @@ struct Inst const uint8_t * data; bool update; + int width, height; + LG_RendererRect destRect; + float translateX, translateY; float scaleX , scaleY; GLint uDesktopPos; @@ -102,6 +111,13 @@ struct Inst uint8_t * mouseData; size_t mouseDataSize; bool mouseUpdate; + + const LG_Font * font; + LG_FontObj fontObj; + + bool fpsReady; + float fpsWidth, fpsHeight; + GLint uFPSScreen, uFPSSize; }; @@ -134,6 +150,13 @@ bool egl_create(void ** opaque, const LG_RendererParams params) this->scaleX = 1.0f; this->scaleY = 1.0f; + this->font = LG_Fonts[0]; + if (!this->font->create(&this->fontObj, NULL, 14)) + { + DEBUG_ERROR("Failed to create a font instance"); + return false; + } + return true; } @@ -151,16 +174,22 @@ void egl_deinitialize(void * opaque) { struct Inst * this = (struct Inst *)opaque; + if (this->font && this->fontObj) + this->font->destroy(this->fontObj); + egl_model_free (&this->models .desktop ); egl_model_free (&this->models .mouse ); + 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 .mouse ); egl_shader_free (&this->shaders .mouse_mono); + egl_shader_free (&this->shaders .fps ); egl_texture_free(&this->textures.desktop ); egl_texture_free(&this->textures.mouse ); egl_texture_free(&this->textures.mouse_mono); + egl_texture_free(&this->textures.fps ); LG_LOCK_FREE(this->mouseLock); if (this->mouseData) @@ -173,6 +202,10 @@ void egl_on_resize(void * opaque, const int width, const int height, const LG_Re { struct Inst * this = (struct Inst *)opaque; + this->width = width; + this->height = height; + memcpy(&this->destRect, &destRect, sizeof(LG_RendererRect)); + glViewport(0, 0, width, height); if (destRect.valid) @@ -260,6 +293,8 @@ bool egl_on_frame_event(void * opaque, const LG_RendererFormat format, const uin default: return false; } + + this->uDesktopPos = egl_shader_get_uniform_location(this->shader, "position"); } this->data = data; @@ -371,6 +406,9 @@ bool egl_render_startup(void * opaque, SDL_Window * window) if (!egl_shader_init(&this->shaders.mouse_mono)) 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; @@ -386,8 +424,13 @@ bool egl_render_startup(void * opaque, SDL_Window * window) if (!egl_shader_compile(this->shaders.mouse_mono, egl_vertex_shader_mouse, sizeof(egl_vertex_shader_mouse), egl_fragment_shader_mouse_mono, sizeof(egl_fragment_shader_mouse_mono))) return false; - this->uMousePos = egl_shader_get_uniform_location(this->shaders.mouse , "mouse"); - this->uMousePosMono = egl_shader_get_uniform_location(this->shaders.mouse_mono, "mouse"); + 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->uMousePos = egl_shader_get_uniform_location(this->shaders.mouse , "mouse" ); + this->uMousePosMono = egl_shader_get_uniform_location(this->shaders.mouse_mono, "mouse" ); + 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; @@ -398,19 +441,29 @@ bool egl_render_startup(void * opaque, SDL_Window * window) if (!egl_texture_init(&this->textures.mouse_mono)) 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.mouse)) 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.mouse , square , sizeof(square) / sizeof(GLfloat)); - egl_model_set_uvs (this->models.mouse , uvs , sizeof(uvs ) / sizeof(GLfloat)); + egl_model_set_verticies(this->models.mouse, square, sizeof(square) / sizeof(GLfloat)); + egl_model_set_uvs (this->models.mouse, uvs , sizeof(uvs ) / sizeof(GLfloat)); + + 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); @@ -461,6 +514,17 @@ bool egl_render(void * opaque, SDL_Window * window) } } + 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); + } + eglSwapBuffers(this->display, this->surface); // defer texture uploads until after the flip to avoid stalling @@ -491,8 +555,42 @@ bool egl_render(void * opaque, SDL_Window * window) return true; } -void egl_update_fps(void * opaque, const float avgFps, const float renderFps) +void egl_update_fps(void * opaque, const float avgFPS, const float renderFPS) { + struct Inst * this = (struct Inst *)opaque; + 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); } void update_mouse_shape(struct Inst * this) diff --git a/client/renderers/egl_shader_progs.h b/client/renderers/egl_shader_progs.h index 8e95202b..0e51a22d 100644 --- a/client/renderers/egl_shader_progs.h +++ b/client/renderers/egl_shader_progs.h @@ -150,4 +150,60 @@ 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);\ + if (tmp.a == 0.0) \ + { \ + color.r = 0.0;\ + color.g = 0.0;\ + color.b = 1.0;\ + color.a = 0.5;\ + } \ + else \ + { \ + color.r = tmp.b;\ + color.g = tmp.g;\ + color.b = tmp.r;\ + color.a = tmp.a;\ + } \ +}\ +"; + + #endif \ No newline at end of file