1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <[email protected]>
#pragma once
#include <GL/gl.h>
#include <GL/glext.h>
#include <stdbool.h>
#include <string.h>
#include "backend/backend.h"
#include "log.h"
#include "region.h"
#define CASESTRRET(s) \
case s: return #s
// Program and uniforms for window shader
typedef struct {
GLuint prog;
GLint unifm_opacity;
GLint unifm_invert_color;
GLint unifm_tex;
GLint unifm_dim;
GLint unifm_brightness;
GLint unifm_max_brightness;
} gl_win_shader_t;
// Program and uniforms for brightness shader
typedef struct {
GLuint prog;
} gl_brightness_shader_t;
// Program and uniforms for blur shader
typedef struct {
GLuint prog;
GLint unifm_pixel_norm;
GLint unifm_opacity;
GLint texorig_loc;
GLint scale_loc;
} gl_blur_shader_t;
typedef struct {
GLuint prog;
GLint color_loc;
} gl_fill_shader_t;
/// @brief Wrapper of a binded GLX texture.
struct gl_texture {
int refcount;
bool has_alpha;
GLuint texture;
int width, height;
bool y_inverted;
// Textures for auxiliary uses.
GLuint auxiliary_texture[2];
void *user_data;
};
struct gl_data {
backend_t base;
// If we are using proprietary NVIDIA driver
bool is_nvidia;
// Height and width of the root window
int height, width;
gl_win_shader_t win_shader;
gl_brightness_shader_t brightness_shader;
gl_fill_shader_t fill_shader;
GLuint back_texture, back_fbo;
GLuint present_prog;
/// Called when an gl_texture is decoupled from the texture it refers. Returns
/// the decoupled user_data
void *(*decouple_texture_user_data)(backend_t *base, void *user_data);
/// Release the user data attached to a gl_texture
void (*release_user_data)(backend_t *base, struct gl_texture *);
struct log_target *logger;
};
typedef struct session session_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.
*/
void gl_compose(backend_t *, void *ptex,
int dst_x1, int dst_y1, int dst_x2, int dst_y2,
const region_t *reg_tgt, const region_t *reg_visible);
void gl_resize(struct gl_data *, int width, int height);
bool gl_init(struct gl_data *gd, session_t *);
void gl_deinit(struct gl_data *gd);
GLuint gl_new_texture(GLenum target);
bool gl_image_op(backend_t *base, enum image_operations op, void *image_data,
const region_t *reg_op, const region_t *reg_visible, void *arg);
void gl_release_image(backend_t *base, void *image_data);
void *gl_clone(backend_t *base, const void *image_data, const region_t *reg_visible);
bool gl_blur(backend_t *base, double opacity, void *, const region_t *reg_blur,
const region_t *reg_visible);
void *gl_create_blur_context(backend_t *base, enum blur_method, void *args);
void gl_destroy_blur_context(backend_t *base, void *ctx);
void gl_get_blur_size(void *blur_context, int *width, int *height);
void gl_fill(backend_t *base, struct color, const region_t *clip);
void gl_present(backend_t *base, const region_t *);
bool gl_read_pixel(backend_t *base, void *image_data, int x, int y, struct color *output);
static inline void gl_delete_texture(GLuint texture) {
glDeleteTextures(1, &texture);
}
/**
* 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);
CASESTRRET(GL_FRAMEBUFFER_UNDEFINED);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER);
CASESTRRET(GL_FRAMEBUFFER_UNSUPPORTED);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE);
CASESTRRET(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS);
}
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);
}
}
}
static inline void gl_clear_err(void) {
while (glGetError() != GL_NO_ERROR)
;
}
#define gl_check_err() gl_check_err_(__func__, __LINE__)
/**
* Check for GL framebuffer completeness.
*/
static inline bool gl_check_fb_complete_(const char *func, int line, GLenum fb) {
GLenum status = glCheckFramebufferStatus(fb);
if (status == GL_FRAMEBUFFER_COMPLETE) {
return true;
}
const char *stattext = gl_get_err_str(status);
if (stattext) {
log_printf(tls_logger, LOG_LEVEL_ERROR, func,
"Framebuffer attachment failed at line %d: %s", line, stattext);
} else {
log_printf(tls_logger, LOG_LEVEL_ERROR, func,
"Framebuffer attachment failed at line %d: %d", line, status);
}
return false;
}
#define gl_check_fb_complete(fb) gl_check_fb_complete_(__func__, __LINE__, (fb))
/**
* Check if a GLX extension exists.
*/
static inline bool gl_has_extension(const char *ext) {
int nexts = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &nexts);
for (int i = 0; i < nexts || !nexts; i++) {
const char *exti = (const char *)glGetStringi(GL_EXTENSIONS, (GLuint)i);
if (exti == NULL) {
break;
}
if (strcmp(ext, exti) == 0) {
return true;
}
}
gl_clear_err();
log_info("Missing GL extension %s.", ext);
return false;
}
|