diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index c51677e1..fc7847a2 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -59,6 +59,7 @@ set(SOURCES renderers/opengl.c renderers/egl.c renderers/egl_shader.c + renderers/egl_texture.c renderers/egl_model.c ) diff --git a/client/lg-renderers.h b/client/lg-renderers.h index 71be68d4..1c112001 100644 --- a/client/lg-renderers.h +++ b/client/lg-renderers.h @@ -20,13 +20,13 @@ Place, Suite 330, Boston, MA 02111-1307 USA #pragma once #include "lg-renderer.h" +extern const LG_Renderer LGR_EGL; extern const LG_Renderer LGR_OpenGL; -//extern const LG_Renderer LGR_OpenGLBasic; const LG_Renderer * LG_Renderers[] = { + &LGR_EGL, &LGR_OpenGL, -// &LGR_OpenGLBasic, NULL // end of array sentinal }; diff --git a/client/renderers/egl.c b/client/renderers/egl.c index bd693ef5..0dff3814 100644 --- a/client/renderers/egl.c +++ b/client/renderers/egl.c @@ -47,6 +47,11 @@ struct Shaders struct EGL_Shader * desktop; }; +struct Textures +{ + struct EGL_Texture * desktop; +}; + struct Inst { LG_RendererParams params; @@ -61,8 +66,10 @@ struct Inst struct Models models; struct Shaders shaders; + struct Textures textures; LG_RendererFormat format; + bool sourceChanged; size_t frameSize; const uint8_t * data; bool update; @@ -106,8 +113,9 @@ void egl_deinitialize(void * opaque) { struct Inst * this = (struct Inst *)opaque; - egl_model_free (&this->models .desktop); - egl_shader_free(&this->shaders.desktop); + egl_model_free (&this->models .desktop); + egl_shader_free (&this->shaders .desktop); + egl_texture_free(&this->textures.desktop); free(this); } @@ -132,10 +140,22 @@ bool egl_on_frame_event(void * opaque, const LG_RendererFormat format, const uin if (format.type != FRAME_TYPE_ARGB) return false; - memcpy(&this->format, &format, sizeof(LG_RendererFormat)); - this->frameSize = format.height * format.pitch; - this->data = data; - this->update = true; + this->sourceChanged = ( + this->sourceChanged || + this->format.type != format.type || + this->format.width != format.width || + this->format.height != format.height || + this->format.pitch != format.pitch + ); + + if (this->sourceChanged) + { + memcpy(&this->format, &format, sizeof(LG_RendererFormat)); + this->frameSize = format.height * format.pitch; + } + + this->data = data; + this->update = true; return true; } @@ -238,11 +258,16 @@ bool egl_render_startup(void * opaque, SDL_Window * window) )) return false; + if (!egl_texture_init(&this->textures.desktop)) + return false; + if (!egl_model_init(&this->models.desktop)) return false; + egl_model_set_verticies(this->models.desktop, desktop, sizeof(desktop) / sizeof(GLfloat)); egl_model_set_uvs (this->models.desktop, uvs , sizeof(uvs ) / sizeof(GLfloat)); - egl_model_set_shader (this->models.desktop, this->shaders.desktop); + egl_model_set_shader (this->models.desktop, this->shaders .desktop); + egl_model_set_texture (this->models.desktop, this->textures.desktop); eglSwapInterval(this->display, this->opt.vsync ? 1 : 0); return true; @@ -254,16 +279,19 @@ bool egl_render(void * opaque, SDL_Window * window) if (this->update) { - if (!egl_model_is_streaming(this->models.desktop)) - egl_model_init_streaming( - this->models.desktop, + if (this->sourceChanged) + { + this->sourceChanged = false; + egl_texture_init_streaming( + this->textures.desktop, this->format.width, this->format.height, this->frameSize ); + } - egl_model_stream_buffer( - this->models.desktop, + egl_texture_stream_buffer( + this->textures.desktop, this->data, this->frameSize ); diff --git a/client/renderers/egl_model.c b/client/renderers/egl_model.c index 926e1fab..e3fd87c4 100644 --- a/client/renderers/egl_model.c +++ b/client/renderers/egl_model.c @@ -19,6 +19,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include "egl_model.h" #include "egl_shader.h" +#include "egl_texture.h" + #include "debug.h" #include "utils.h" @@ -37,15 +39,8 @@ struct EGL_Model bool hasUVBuffer; GLuint uvBuffer; - EGL_Shader * shader; - - bool hasTexture; - GLuint texture; - - bool hasPBO; - GLuint pbo[2]; - int pboIndex; - size_t pboWidth, pboHeight; + EGL_Shader * shader; + EGL_Texture * texture; }; bool egl_model_init(EGL_Model ** model) @@ -72,69 +67,10 @@ void egl_model_free(EGL_Model ** model) if ((*model)->hasUVBuffer) glDeleteBuffers(1, &(*model)->uvBuffer); - if ((*model)->hasTexture) - glDeleteTextures(1, &(*model)->texture); - - if ((*model)->hasPBO) - glDeleteBuffers(2, (*model)->pbo); - free(*model); *model = NULL; } -bool egl_model_init_streaming(EGL_Model * model, size_t width, size_t height, size_t bufferSize) -{ - model->pboWidth = width; - model->pboHeight = height; - - glBindTexture(GL_TEXTURE_2D, egl_model_get_texture_id(model)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glBindTexture(GL_TEXTURE_2D, 0); - - if (!model->hasPBO) - glGenBuffers(2, model->pbo); - - for(int i = 0; i < 2; ++i) - { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, model->pbo[i]); - glBufferData( - GL_PIXEL_UNPACK_BUFFER, - bufferSize, - NULL, - GL_DYNAMIC_DRAW - ); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } - - model->hasPBO = true; - return true; -} - -bool egl_model_is_streaming(EGL_Model * model) -{ - return model->hasPBO; -} - -bool egl_model_stream_buffer(EGL_Model * model, const uint8_t * buffer, size_t bufferSize) -{ - if (++model->pboIndex == 2) - model->pboIndex = 0; - - glBindTexture(GL_TEXTURE_2D, egl_model_get_texture_id(model)); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, model->pbo[model->pboIndex]); - glBufferData(GL_PIXEL_UNPACK_BUFFER, bufferSize, 0, GL_DYNAMIC_DRAW); - glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, bufferSize, buffer); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, model->pboWidth, model->pboHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - - return true; -} - void egl_model_set_verticies(EGL_Model * model, const GLfloat * verticies, const size_t count) { if (model->hasVertexBuffer) @@ -186,20 +122,17 @@ void egl_model_render(EGL_Model * model) glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); } - if (model->hasTexture) - glBindTexture(GL_TEXTURE_2D, model->texture); + if (model->texture) + egl_texture_bind(model->texture); glDrawArrays(GL_TRIANGLE_STRIP, 0, model->vertexCount); - - if (model->hasTexture) - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D, 0); while(location > 0) glDisableVertexAttribArray(location--); glDisableVertexAttribArray(0); - if (model->shader) - glUseProgram(0); + glUseProgram(0); } void egl_model_set_shader(EGL_Model * model, EGL_Shader * shader) @@ -207,13 +140,7 @@ void egl_model_set_shader(EGL_Model * model, EGL_Shader * shader) model->shader = shader; } -GLuint egl_model_get_texture_id(EGL_Model * model) +void egl_model_set_texture(EGL_Model * model, EGL_Texture * texture) { - if (model->hasTexture) - return model->texture; - - glGenTextures(1, &model->texture); - model->hasTexture = true; - - return model->texture; + model->texture = texture; } \ No newline at end of file diff --git a/client/renderers/egl_model.h b/client/renderers/egl_model.h index f2b422aa..1034d11f 100644 --- a/client/renderers/egl_model.h +++ b/client/renderers/egl_model.h @@ -21,6 +21,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include #include "egl_shader.h" +#include "egl_texture.h" #define GL_GLEXT_PROTOTYPES #include @@ -30,12 +31,9 @@ typedef struct EGL_Model EGL_Model; bool egl_model_init(EGL_Model ** model); void egl_model_free(EGL_Model ** model); -bool egl_model_init_streaming(EGL_Model * model, size_t width, size_t height, size_t bufferSize); -bool egl_model_is_streaming (EGL_Model * model); -bool egl_model_stream_buffer (EGL_Model * model, const uint8_t * buffer, size_t bufferSize); void egl_model_set_verticies (EGL_Model * model, const GLfloat * verticies, const size_t count); void egl_model_set_uvs (EGL_Model * model, const GLfloat * uvs , const size_t count); -void egl_model_set_shader (EGL_Model * model, EGL_Shader * shader); -GLuint egl_model_get_texture_id(EGL_Model * model); +void egl_model_set_shader (EGL_Model * model, EGL_Shader * shader); +void egl_model_set_texture (EGL_Model * model, EGL_Texture * texture); void egl_model_render(EGL_Model * model); \ No newline at end of file diff --git a/client/renderers/egl_texture.c b/client/renderers/egl_texture.c new file mode 100644 index 00000000..29572b39 --- /dev/null +++ b/client/renderers/egl_texture.c @@ -0,0 +1,125 @@ +/* +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 +*/ + +#include "egl_texture.h" +#include "debug.h" +#include "utils.h" + +#include +#include +#include + +#include + +struct EGL_Texture +{ + GLuint texture; + bool hasPBO; + GLuint pbo[2]; + int pboIndex; + size_t pboWidth, pboHeight; + size_t pboBufferSize; +}; + +bool egl_texture_init(EGL_Texture ** texture) +{ + *texture = (EGL_Texture *)malloc(sizeof(EGL_Texture)); + if (!*texture) + { + DEBUG_ERROR("Failed to malloc EGL_Texture"); + return false; + } + + memset(*texture, 0, sizeof(EGL_Texture)); + glGenTextures(1, &(*texture)->texture); + + return true; +} + +void egl_texture_free(EGL_Texture ** texture) +{ + if (!*texture) + return; + + glDeleteTextures(1, &(*texture)->texture); + + if ((*texture)->hasPBO) + glDeleteBuffers(2, (*texture)->pbo); + + free(*texture); + *texture = NULL; +} + +bool egl_texture_init_streaming(EGL_Texture * texture, size_t width, size_t height, size_t bufferSize) +{ + texture->pboWidth = width; + texture->pboHeight = height; + + glBindTexture(GL_TEXTURE_2D, texture->texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + if (!texture->hasPBO) + glGenBuffers(2, texture->pbo); + + for(int i = 0; i < 2; ++i) + { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->pbo[i]); + glBufferData( + GL_PIXEL_UNPACK_BUFFER, + bufferSize, + NULL, + GL_DYNAMIC_DRAW + ); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + } + + texture->hasPBO = true; + return true; +} + +bool egl_texture_is_streaming(EGL_Texture * texture) +{ + return texture->hasPBO; +} + +bool egl_texture_stream_buffer(EGL_Texture * texture, const uint8_t * buffer, size_t bufferSize) +{ + if (++texture->pboIndex == 2) + texture->pboIndex = 0; + + glBindTexture(GL_TEXTURE_2D, texture->texture); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->pbo[texture->pboIndex]); + glBufferData(GL_PIXEL_UNPACK_BUFFER, bufferSize, 0, GL_DYNAMIC_DRAW); + glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, bufferSize, buffer); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->pboWidth, texture->pboHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + return true; +} + +void egl_texture_bind(EGL_Texture * texture) +{ + glBindTexture(GL_TEXTURE_2D, texture->texture); +} \ No newline at end of file diff --git a/client/renderers/egl_texture.h b/client/renderers/egl_texture.h new file mode 100644 index 00000000..4566fae2 --- /dev/null +++ b/client/renderers/egl_texture.h @@ -0,0 +1,36 @@ +/* +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 "egl_shader.h" + +#define GL_GLEXT_PROTOTYPES +#include + +typedef struct EGL_Texture EGL_Texture; + +bool egl_texture_init(EGL_Texture ** tex); +void egl_texture_free(EGL_Texture ** tex); + +bool egl_texture_init_streaming(EGL_Texture * texture, size_t width, size_t height, size_t bufferSize); +bool egl_texture_is_streaming (EGL_Texture * texture); +bool egl_texture_stream_buffer (EGL_Texture * texture, const uint8_t * buffer, size_t bufferSize); +void egl_texture_bind (EGL_Texture * texture); \ No newline at end of file