mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-10-22 23:38:14 +00:00
[client] egl: moved egl sources into subdirectory
This commit is contained in:
159
client/renderers/egl/model.c
Normal file
159
client/renderers/egl/model.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
|
||||
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 "model.h"
|
||||
#include "shader.h"
|
||||
#include "texture.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <SDL2/SDL_egl.h>
|
||||
|
||||
struct EGL_Model
|
||||
{
|
||||
bool hasVertexBuffer;
|
||||
GLuint vertexBuffer;
|
||||
GLsizei vertexCount;
|
||||
|
||||
bool hasUVBuffer;
|
||||
GLuint uvBuffer;
|
||||
|
||||
EGL_Shader * shader;
|
||||
EGL_Texture * texture;
|
||||
};
|
||||
|
||||
void update_uniform_bindings(EGL_Model * model);
|
||||
|
||||
bool egl_model_init(EGL_Model ** model)
|
||||
{
|
||||
*model = (EGL_Model *)malloc(sizeof(EGL_Model));
|
||||
if (!*model)
|
||||
{
|
||||
DEBUG_ERROR("Failed to malloc EGL_Model");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(*model, 0, sizeof(EGL_Model));
|
||||
return true;
|
||||
}
|
||||
|
||||
void egl_model_free(EGL_Model ** model)
|
||||
{
|
||||
if (!*model)
|
||||
return;
|
||||
|
||||
if ((*model)->hasVertexBuffer)
|
||||
glDeleteBuffers(1, &(*model)->vertexBuffer);
|
||||
|
||||
if ((*model)->hasUVBuffer)
|
||||
glDeleteBuffers(1, &(*model)->uvBuffer);
|
||||
|
||||
free(*model);
|
||||
*model = NULL;
|
||||
}
|
||||
|
||||
void egl_model_set_verticies(EGL_Model * model, const GLfloat * verticies, const size_t count)
|
||||
{
|
||||
if (model->hasVertexBuffer)
|
||||
glDeleteBuffers(1, &model->vertexBuffer);
|
||||
|
||||
glGenBuffers(1, &model->vertexBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, model->vertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * count, verticies, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
model->hasVertexBuffer = true;
|
||||
model->vertexCount = count / 3;
|
||||
}
|
||||
|
||||
void egl_model_set_uvs(EGL_Model * model, const GLfloat * uvs, const size_t count)
|
||||
{
|
||||
if (model->hasUVBuffer)
|
||||
glDeleteBuffers(1, &model->uvBuffer);
|
||||
|
||||
glGenBuffers(1, &model->uvBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, model->uvBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * count, uvs, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
model->hasUVBuffer = true;
|
||||
}
|
||||
|
||||
void egl_model_render(EGL_Model * model)
|
||||
{
|
||||
if (!model->hasVertexBuffer)
|
||||
{
|
||||
DEBUG_ERROR("Model has no verticies");
|
||||
return;
|
||||
}
|
||||
|
||||
if (model->shader)
|
||||
egl_shader_use(model->shader);
|
||||
|
||||
GLuint location = 0;
|
||||
glEnableVertexAttribArray(location);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, model->vertexBuffer);
|
||||
glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
|
||||
|
||||
if (model->hasUVBuffer)
|
||||
{
|
||||
++location;
|
||||
glEnableVertexAttribArray(location);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, model->uvBuffer);
|
||||
glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
|
||||
}
|
||||
|
||||
if (model->texture)
|
||||
egl_texture_bind(model->texture);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, model->vertexCount);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
while(location > 0)
|
||||
glDisableVertexAttribArray(location--);
|
||||
glDisableVertexAttribArray(0);
|
||||
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void egl_model_set_shader(EGL_Model * model, EGL_Shader * shader)
|
||||
{
|
||||
model->shader = shader;
|
||||
update_uniform_bindings(model);
|
||||
}
|
||||
|
||||
void egl_model_set_texture(EGL_Model * model, EGL_Texture * texture)
|
||||
{
|
||||
model->texture = texture;
|
||||
update_uniform_bindings(model);
|
||||
}
|
||||
|
||||
void update_uniform_bindings(EGL_Model * model)
|
||||
{
|
||||
if (!model->shader || !model->texture)
|
||||
return;
|
||||
|
||||
const int count = egl_texture_count(model->texture);
|
||||
egl_shader_associate_textures(model->shader, count);
|
||||
}
|
||||
39
client/renderers/egl/model.h
Normal file
39
client/renderers/egl/model.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
|
||||
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 <stdbool.h>
|
||||
#include "shader.h"
|
||||
#include "texture.h"
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
|
||||
typedef struct EGL_Model EGL_Model;
|
||||
|
||||
bool egl_model_init(EGL_Model ** model);
|
||||
void egl_model_free(EGL_Model ** model);
|
||||
|
||||
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);
|
||||
void egl_model_set_texture (EGL_Model * model, EGL_Texture * texture);
|
||||
|
||||
void egl_model_render(EGL_Model * model);
|
||||
201
client/renderers/egl/progs.h
Normal file
201
client/renderers/egl/progs.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
|
||||
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_vertex_shader_mouse[] = "\
|
||||
#version 300 es\n\
|
||||
\
|
||||
layout(location = 0) in vec3 vertexPosition_modelspace;\
|
||||
layout(location = 1) in vec2 vertexUV;\
|
||||
\
|
||||
uniform vec4 mouse;\
|
||||
\
|
||||
out highp vec2 uv;\
|
||||
\
|
||||
void main()\
|
||||
{\
|
||||
gl_Position.xyz = vertexPosition_modelspace;\
|
||||
gl_Position.w = 1.0;\
|
||||
\
|
||||
gl_Position.x += 1.0f;\
|
||||
gl_Position.y -= 1.0f;\
|
||||
\
|
||||
gl_Position.x *= mouse.z;\
|
||||
gl_Position.y *= mouse.w;\
|
||||
\
|
||||
gl_Position.x += mouse.x;\
|
||||
gl_Position.y -= mouse.y;\
|
||||
\
|
||||
uv = vertexUV;\
|
||||
}\
|
||||
";
|
||||
|
||||
static const char egl_fragment_shader_mouse_mono[] = "\
|
||||
#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.rgb == vec3(0.0, 0.0, 0.0))\
|
||||
discard;\
|
||||
color = tmp;\
|
||||
}\
|
||||
";
|
||||
|
||||
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;\
|
||||
}\
|
||||
";
|
||||
|
||||
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
|
||||
225
client/renderers/egl/shader.c
Normal file
225
client/renderers/egl/shader.c
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
|
||||
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 "shader.h"
|
||||
#include "debug.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <SDL2/SDL_egl.h>
|
||||
|
||||
struct EGL_Shader
|
||||
{
|
||||
bool hasShader;
|
||||
GLuint shader;
|
||||
};
|
||||
|
||||
bool egl_shader_init(EGL_Shader ** this)
|
||||
{
|
||||
*this = (EGL_Shader *)malloc(sizeof(EGL_Shader));
|
||||
if (!*this)
|
||||
{
|
||||
DEBUG_ERROR("Failed to malloc EGL_Shader");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(*this, 0, sizeof(EGL_Shader));
|
||||
return true;
|
||||
}
|
||||
|
||||
void egl_shader_free(EGL_Shader ** this)
|
||||
{
|
||||
if (!*this)
|
||||
return;
|
||||
|
||||
if ((*this)->hasShader)
|
||||
glDeleteProgram((*this)->shader);
|
||||
|
||||
free(*this);
|
||||
*this = NULL;
|
||||
}
|
||||
|
||||
bool egl_shader_load(EGL_Shader * this, const char * vertex_file, const char * fragment_file)
|
||||
{
|
||||
char * vertex_code, * fragment_code;
|
||||
size_t vertex_size, fragment_size;
|
||||
|
||||
if (!file_get_contents(vertex_file, &vertex_code, &vertex_size))
|
||||
{
|
||||
DEBUG_ERROR("Failed to read vertex shader");
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_INFO("Loaded vertex shader: %s", vertex_file);
|
||||
|
||||
if (!file_get_contents(fragment_file, &fragment_code, &fragment_size))
|
||||
{
|
||||
DEBUG_ERROR("Failed to read fragment shader");
|
||||
free(vertex_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_INFO("Loaded fragment shader: %s", fragment_file);
|
||||
|
||||
bool ret = egl_shader_compile(this, vertex_code, vertex_size, fragment_code, fragment_size);
|
||||
free(vertex_code);
|
||||
free(fragment_code);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool egl_shader_compile(EGL_Shader * this, const char * vertex_code, size_t vertex_size, const char * fragment_code, size_t fragment_size)
|
||||
{
|
||||
if (this->hasShader)
|
||||
{
|
||||
glDeleteProgram(this->shader);
|
||||
this->hasShader = false;
|
||||
}
|
||||
|
||||
GLint length;
|
||||
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
|
||||
length = vertex_size;
|
||||
glShaderSource(vertexShader, 1, (const char**)&vertex_code, &length);
|
||||
glCompileShader(vertexShader);
|
||||
|
||||
GLint result = GL_FALSE;
|
||||
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &result);
|
||||
if (result == GL_FALSE)
|
||||
{
|
||||
DEBUG_ERROR("Failed to compile vertex shader");
|
||||
|
||||
int logLength;
|
||||
glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0)
|
||||
{
|
||||
char *log = malloc(logLength + 1);
|
||||
glGetShaderInfoLog(vertexShader, logLength, NULL, log);
|
||||
log[logLength] = 0;
|
||||
DEBUG_ERROR("%s", log);
|
||||
free(log);
|
||||
}
|
||||
|
||||
glDeleteShader(vertexShader);
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
length = fragment_size;
|
||||
glShaderSource(fragmentShader, 1, (const char**)&fragment_code, &length);
|
||||
glCompileShader(fragmentShader);
|
||||
|
||||
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &result);
|
||||
if (result == GL_FALSE)
|
||||
{
|
||||
DEBUG_ERROR("Failed to compile fragment shader");
|
||||
|
||||
int logLength;
|
||||
glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0)
|
||||
{
|
||||
char *log = malloc(logLength + 1);
|
||||
glGetShaderInfoLog(fragmentShader, logLength, NULL, log);
|
||||
log[logLength] = 0;
|
||||
DEBUG_ERROR("%s", log);
|
||||
free(log);
|
||||
}
|
||||
|
||||
glDeleteShader(fragmentShader);
|
||||
glDeleteShader(vertexShader );
|
||||
return false;
|
||||
}
|
||||
|
||||
this->shader = glCreateProgram();
|
||||
glAttachShader(this->shader, vertexShader );
|
||||
glAttachShader(this->shader, fragmentShader);
|
||||
glLinkProgram(this->shader);
|
||||
|
||||
glGetProgramiv(this->shader, GL_LINK_STATUS, &result);
|
||||
if (result == GL_FALSE)
|
||||
{
|
||||
DEBUG_ERROR("Failed to link shader program");
|
||||
|
||||
int logLength;
|
||||
glGetProgramiv(this->shader, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0)
|
||||
{
|
||||
char *log = malloc(logLength + 1);
|
||||
glGetProgramInfoLog(this->shader, logLength, NULL, log);
|
||||
log[logLength] = 0;
|
||||
DEBUG_ERROR("%s", log);
|
||||
free(log);
|
||||
}
|
||||
|
||||
glDetachShader(this->shader, vertexShader );
|
||||
glDetachShader(this->shader, fragmentShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
glDeleteShader(vertexShader );
|
||||
glDeleteProgram(this->shader );
|
||||
return false;
|
||||
}
|
||||
|
||||
glDetachShader(this->shader, vertexShader );
|
||||
glDetachShader(this->shader, fragmentShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
glDeleteShader(vertexShader );
|
||||
|
||||
this->hasShader = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void egl_shader_use(EGL_Shader * this)
|
||||
{
|
||||
if (this->hasShader)
|
||||
glUseProgram(this->shader);
|
||||
else
|
||||
DEBUG_ERROR("Shader program has not been compiled");
|
||||
}
|
||||
|
||||
void egl_shader_associate_textures(EGL_Shader * this, const int count)
|
||||
{
|
||||
char name[] = "sampler1";
|
||||
glUseProgram(this->shader);
|
||||
for(int i = 0; i < count; ++i, name[7]++)
|
||||
{
|
||||
GLint loc = glGetUniformLocation(this->shader, name);
|
||||
if (loc == -1)
|
||||
{
|
||||
DEBUG_WARN("Shader uniform location `%s` not found", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
glUniform1i(loc, i);
|
||||
}
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
GLint egl_shader_get_uniform_location(EGL_Shader * this, const char * name)
|
||||
{
|
||||
if (!this->shader)
|
||||
{
|
||||
DEBUG_ERROR("Shader program has not been compiled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return glGetUniformLocation(this->shader, name);
|
||||
}
|
||||
37
client/renderers/egl/shader.h
Normal file
37
client/renderers/egl/shader.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
|
||||
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 <stdbool.h>
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
|
||||
typedef struct EGL_Shader EGL_Shader;
|
||||
|
||||
bool egl_shader_init(EGL_Shader ** shader);
|
||||
void egl_shader_free(EGL_Shader ** shader);
|
||||
|
||||
bool egl_shader_load (EGL_Shader * model, const char * vertex_file, const char * fragment_file);
|
||||
bool egl_shader_compile(EGL_Shader * model, const char * vertex_code, size_t vertex_size, const char * fragment_code, size_t fragment_size);
|
||||
void egl_shader_use (EGL_Shader * shader);
|
||||
|
||||
void egl_shader_associate_textures(EGL_Shader * shader, const int count);
|
||||
GLint egl_shader_get_uniform_location(EGL_Shader * shader, const char * name);
|
||||
256
client/renderers/egl/texture.c
Normal file
256
client/renderers/egl/texture.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
|
||||
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 "texture.h"
|
||||
#include "debug.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <SDL2/SDL_egl.h>
|
||||
|
||||
struct EGL_Texture
|
||||
{
|
||||
enum EGL_PixelFormat pixFmt;
|
||||
size_t width, height;
|
||||
bool streaming;
|
||||
|
||||
int textureCount;
|
||||
GLuint textures[3];
|
||||
GLuint samplers[3];
|
||||
size_t planes[3][2];
|
||||
GLintptr offsets[3];
|
||||
GLenum intFormat;
|
||||
GLenum format;
|
||||
GLenum dataType;
|
||||
|
||||
bool hasPBO;
|
||||
GLuint pbo[2];
|
||||
int pboIndex;
|
||||
bool needsUpdate;
|
||||
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));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void egl_texture_free(EGL_Texture ** texture)
|
||||
{
|
||||
if (!*texture)
|
||||
return;
|
||||
|
||||
if ((*texture)->textureCount > 0)
|
||||
{
|
||||
glDeleteTextures((*texture)->textureCount, (*texture)->textures);
|
||||
glDeleteSamplers((*texture)->textureCount, (*texture)->samplers);
|
||||
}
|
||||
|
||||
if ((*texture)->hasPBO)
|
||||
glDeleteBuffers(2, (*texture)->pbo);
|
||||
|
||||
free(*texture);
|
||||
*texture = NULL;
|
||||
}
|
||||
|
||||
bool egl_texture_setup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt, size_t width, size_t height, size_t bufferSize, bool streaming)
|
||||
{
|
||||
int textureCount;
|
||||
|
||||
texture->pixFmt = pixFmt;
|
||||
texture->width = width;
|
||||
texture->height = height;
|
||||
texture->pboBufferSize = bufferSize;
|
||||
texture->streaming = streaming;
|
||||
|
||||
switch(pixFmt)
|
||||
{
|
||||
case EGL_PF_BGRA:
|
||||
textureCount = 1;
|
||||
texture->format = GL_BGRA;
|
||||
texture->planes[0][0] = width;
|
||||
texture->planes[0][1] = height;
|
||||
texture->offsets[0] = 0;
|
||||
texture->intFormat = GL_BGRA;
|
||||
texture->dataType = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
case EGL_PF_RGBA:
|
||||
textureCount = 1;
|
||||
texture->format = GL_RGBA;
|
||||
texture->planes[0][0] = width;
|
||||
texture->planes[0][1] = height;
|
||||
texture->offsets[0] = 0;
|
||||
texture->intFormat = GL_BGRA;
|
||||
texture->dataType = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
case EGL_PF_RGBA10:
|
||||
textureCount = 1;
|
||||
texture->format = GL_RGBA;
|
||||
texture->planes[0][0] = width;
|
||||
texture->planes[0][1] = height;
|
||||
texture->offsets[0] = 0;
|
||||
texture->intFormat = GL_RGB10_A2;
|
||||
texture->dataType = GL_UNSIGNED_INT_2_10_10_10_REV;
|
||||
break;
|
||||
|
||||
case EGL_PF_YUV420:
|
||||
textureCount = 3;
|
||||
texture->format = GL_RED;
|
||||
texture->planes[0][0] = width;
|
||||
texture->planes[0][1] = height;
|
||||
texture->planes[1][0] = width / 2;
|
||||
texture->planes[1][1] = height / 2;
|
||||
texture->planes[2][0] = width / 2;
|
||||
texture->planes[2][1] = height / 2;
|
||||
texture->offsets[0] = 0;
|
||||
texture->offsets[1] = width * height;
|
||||
texture->offsets[2] = texture->offsets[1] + (texture->offsets[1] / 4);
|
||||
texture->dataType = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Unsupported pixel format");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (textureCount > texture->textureCount)
|
||||
{
|
||||
if (texture->textureCount > 0)
|
||||
{
|
||||
glDeleteTextures(texture->textureCount, texture->textures);
|
||||
glDeleteSamplers(texture->textureCount, texture->samplers);
|
||||
}
|
||||
|
||||
texture->textureCount = textureCount;
|
||||
glGenTextures(texture->textureCount, texture->textures);
|
||||
glGenSamplers(texture->textureCount, texture->samplers);
|
||||
}
|
||||
|
||||
for(int i = 0; i < textureCount; ++i)
|
||||
{
|
||||
glSamplerParameteri(texture->samplers[i], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(texture->samplers[i], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(texture->samplers[i], GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(texture->samplers[i], GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture->textures[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, texture->intFormat, texture->planes[i][0], texture->planes[i][1],
|
||||
0, texture->format, texture->dataType, NULL);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
if (streaming)
|
||||
{
|
||||
if (!texture->hasPBO)
|
||||
{
|
||||
glGenBuffers(2, texture->pbo);
|
||||
texture->hasPBO = true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool egl_texture_update(EGL_Texture * texture, const uint8_t * buffer)
|
||||
{
|
||||
if (texture->streaming)
|
||||
{
|
||||
if (texture->needsUpdate)
|
||||
{
|
||||
DEBUG_ERROR("Previous frame was not consumed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (++texture->pboIndex == 2)
|
||||
texture->pboIndex = 0;
|
||||
|
||||
/* initiate the data upload */
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->pbo[texture->pboIndex]);
|
||||
glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, texture->pboBufferSize, buffer);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
texture->needsUpdate = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < texture->textureCount; ++i)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, texture->textures[i]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->planes[i][0], texture->planes[i][1],
|
||||
texture->format, texture->dataType, buffer + texture->offsets[i]);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void egl_texture_bind(EGL_Texture * texture)
|
||||
{
|
||||
if (texture->streaming && texture->needsUpdate)
|
||||
{
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->pbo[texture->pboIndex]);
|
||||
for(int i = 0; i < texture->textureCount; ++i)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, texture->textures[i]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->planes[i][0], texture->planes[i][1],
|
||||
texture->format, texture->dataType, (const void *)texture->offsets[i]);
|
||||
}
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
texture->needsUpdate = false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < texture->textureCount; ++i)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->textures[i]);
|
||||
glBindSampler(i, texture->samplers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int egl_texture_count(EGL_Texture * texture)
|
||||
{
|
||||
return texture->textureCount;
|
||||
}
|
||||
44
client/renderers/egl/texture.h
Normal file
44
client/renderers/egl/texture.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
|
||||
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 <stdbool.h>
|
||||
#include "shader.h"
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
|
||||
typedef struct EGL_Texture EGL_Texture;
|
||||
|
||||
enum EGL_PixelFormat
|
||||
{
|
||||
EGL_PF_RGBA,
|
||||
EGL_PF_BGRA,
|
||||
EGL_PF_RGBA10,
|
||||
EGL_PF_YUV420
|
||||
};
|
||||
|
||||
bool egl_texture_init(EGL_Texture ** tex);
|
||||
void egl_texture_free(EGL_Texture ** tex);
|
||||
|
||||
bool egl_texture_setup (EGL_Texture * texture, enum EGL_PixelFormat pixfmt, size_t width, size_t height, size_t bufferSize, bool streaming);
|
||||
bool egl_texture_update(EGL_Texture * texture, const uint8_t * buffer);
|
||||
void egl_texture_bind (EGL_Texture * texture);
|
||||
int egl_texture_count (EGL_Texture * texture);
|
||||
Reference in New Issue
Block a user