157 lines
4.2 KiB
C
157 lines
4.2 KiB
C
#pragma once
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <GL/gl.h>
|
|
#include <GL/glext.h>
|
|
|
|
#include "common.h"
|
|
#include "region.h"
|
|
#include "log.h"
|
|
|
|
#define CASESTRRET(s) case s: return #s
|
|
|
|
// Program and uniforms for window shader
|
|
typedef struct {
|
|
/// GLSL program.
|
|
GLuint prog;
|
|
/// Location of uniform "opacity" in window GLSL program.
|
|
GLint unifm_opacity;
|
|
/// Location of uniform "invert_color" in blur GLSL program.
|
|
GLint unifm_invert_color;
|
|
/// Location of uniform "tex" in window GLSL program.
|
|
GLint unifm_tex;
|
|
} gl_win_shader_t;
|
|
|
|
// Program and uniforms for blur shader
|
|
typedef struct {
|
|
/// Fragment shader for blur.
|
|
GLuint frag_shader;
|
|
/// GLSL program for blur.
|
|
GLuint prog;
|
|
/// Location of uniform "offset_x" in blur GLSL program.
|
|
GLint unifm_offset_x;
|
|
/// Location of uniform "offset_y" in blur GLSL program.
|
|
GLint unifm_offset_y;
|
|
/// Location of uniform "factor_center" in blur GLSL program.
|
|
GLint unifm_factor_center;
|
|
} gl_blur_shader_t;
|
|
|
|
/// @brief Wrapper of a binded GLX texture.
|
|
typedef struct gl_texture {
|
|
GLuint texture;
|
|
GLenum target;
|
|
unsigned width;
|
|
unsigned height;
|
|
unsigned depth;
|
|
bool y_inverted;
|
|
} gl_texture_t;
|
|
|
|
// OpenGL capabilities
|
|
typedef struct gl_cap {
|
|
bool non_power_of_two_texture;
|
|
} gl_cap_t;
|
|
|
|
typedef struct {
|
|
/// Framebuffer used for blurring.
|
|
GLuint fbo;
|
|
/// Textures used for blurring.
|
|
GLuint textures[2];
|
|
/// Width of the textures.
|
|
int width;
|
|
/// Height of the textures.
|
|
int height;
|
|
} gl_blur_cache_t;
|
|
|
|
#define GL_PROG_MAIN_INIT \
|
|
{ .prog = 0, .unifm_opacity = -1, .unifm_invert_color = -1, .unifm_tex = -1, }
|
|
|
|
GLuint gl_create_shader(GLenum shader_type, const char *shader_str);
|
|
GLuint gl_create_program(const GLuint *const shaders, int nshaders);
|
|
GLuint
|
|
gl_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str);
|
|
/**
|
|
* @brief Render a region with texture data.
|
|
*/
|
|
bool gl_compose(const gl_texture_t *ptex, int x, int y, int dx, int dy, int width,
|
|
int height, int z, double opacity, bool argb, bool neg,
|
|
const region_t *reg_tgt, const gl_win_shader_t *shader);
|
|
|
|
bool gl_load_prog_main(session_t *ps, const char *vshader_str, const char *fshader_str,
|
|
gl_win_shader_t *pprogram);
|
|
void gl_free_prog_main(session_t *ps, gl_win_shader_t *prog);
|
|
|
|
unsigned char *gl_take_screenshot(session_t *ps, int *out_length);
|
|
void gl_resize(int width, int height);
|
|
bool gl_create_blur_filters(session_t *ps, gl_blur_shader_t *passes, const gl_cap_t *cap);
|
|
|
|
GLuint glGetUniformLocationChecked(GLuint p, const char *name);
|
|
|
|
/**
|
|
* Get a textual representation of an OpenGL error.
|
|
*/
|
|
static inline const char *gl_get_err_str(GLenum err) {
|
|
switch (err) {
|
|
CASESTRRET(GL_NO_ERROR);
|
|
CASESTRRET(GL_INVALID_ENUM);
|
|
CASESTRRET(GL_INVALID_VALUE);
|
|
CASESTRRET(GL_INVALID_OPERATION);
|
|
CASESTRRET(GL_INVALID_FRAMEBUFFER_OPERATION);
|
|
CASESTRRET(GL_OUT_OF_MEMORY);
|
|
CASESTRRET(GL_STACK_UNDERFLOW);
|
|
CASESTRRET(GL_STACK_OVERFLOW);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Check for GLX error.
|
|
*
|
|
* http://blog.nobel-joergensen.com/2013/01/29/debugging-opengl-using-glgeterror/
|
|
*/
|
|
static inline void gl_check_err_(const char *func, int line) {
|
|
GLenum err = GL_NO_ERROR;
|
|
|
|
while (GL_NO_ERROR != (err = glGetError())) {
|
|
const char *errtext = gl_get_err_str(err);
|
|
if (errtext) {
|
|
log_printf(tls_logger, LOG_LEVEL_ERROR, func,
|
|
"GLX error at line %d: %s", line, errtext);
|
|
} else {
|
|
log_printf(tls_logger, LOG_LEVEL_ERROR, func,
|
|
"GLX error at line %d: %d", line, err);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define gl_check_err() gl_check_err_(__func__, __LINE__)
|
|
|
|
/**
|
|
* Check if a GLX extension exists.
|
|
*/
|
|
static inline bool gl_has_extension(const char *ext) {
|
|
GLint nexts = 0;
|
|
glGetIntegerv(GL_NUM_EXTENSIONS, &nexts);
|
|
if (!nexts) {
|
|
log_error("Failed to get GL extension list.");
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < nexts; i++) {
|
|
const char *exti = (const char *)glGetStringi(GL_EXTENSIONS, i);
|
|
if (strcmp(ext, exti) == 0)
|
|
return true;
|
|
}
|
|
log_info("Missing GL extension %s.", ext);
|
|
return false;
|
|
}
|
|
|
|
static inline void gl_free_blur_shader(gl_blur_shader_t *shader) {
|
|
if (shader->prog)
|
|
glDeleteShader(shader->prog);
|
|
if (shader->frag_shader)
|
|
glDeleteShader(shader->frag_shader);
|
|
|
|
shader->prog = 0;
|
|
shader->frag_shader = 0;
|
|
}
|