aboutsummaryrefslogtreecommitdiff
path: root/src/opengl.h
blob: 492451ac5429446a0ad620937c54ca95c2dc5ff5 (plain) (blame)
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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
// SPDX-License-Identifier: MIT

#pragma once

#include "common.h"
#include "compiler.h"
#include "log.h"
#include "region.h"
#include "render.h"
#include "win.h"

#include <GL/gl.h>
#include <GL/glx.h>
#include <ctype.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <xcb/render.h>
#include <xcb/xcb.h>

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;
} glx_blur_pass_t;

typedef struct {
	/// Fragment shader for rounded corners.
	GLuint frag_shader;
	/// GLSL program for rounded corners.
	GLuint prog;
	/// Location of uniform "radius" in rounded-corners GLSL program.
	GLint unifm_radius;
	/// Location of uniform "texcoord" in rounded-corners GLSL program.
	GLint unifm_texcoord;
	/// Location of uniform "texsize" in rounded-corners GLSL program.
	GLint unifm_texsize;
	/// Location of uniform "borderw" in rounded-corners GLSL program.
	GLint unifm_borderw;
	/// Location of uniform "borderc" in rounded-corners GLSL program.
	GLint unifm_borderc;
	/// Location of uniform "resolution" in rounded-corners GLSL program.
	GLint unifm_resolution;
	/// Location of uniform "texture_scr" in rounded-corners GLSL program.
	GLint unifm_tex_scr;

} glx_round_pass_t;

/// Structure containing GLX-dependent data for a session.
typedef struct glx_session {
	// === OpenGL related ===
	/// GLX context.
	GLXContext context;
	/// Whether we have GL_ARB_texture_non_power_of_two.
	bool has_texture_non_power_of_two;
	/// Current GLX Z value.
	int z;
	glx_blur_pass_t *blur_passes;
	glx_round_pass_t *round_passes;
} glx_session_t;

/// @brief Wrapper of a binded GLX texture.
typedef struct _glx_texture {
	GLuint texture;
	GLXPixmap glpixmap;
	xcb_pixmap_t pixmap;
	GLenum target;
	int width;
	int height;
	bool y_inverted;
} glx_texture_t;

#define CGLX_SESSION_INIT                                                                \
	{ .context = NULL }

bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z,
                 GLfloat factor, const region_t *reg_tgt);

bool glx_render(session_t *ps, const glx_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 glx_prog_main_t *pprogram);

bool glx_init(session_t *ps, bool need_render);

void glx_destroy(session_t *ps);

void glx_on_root_change(session_t *ps);

bool glx_init_blur(session_t *ps);

bool glx_init_rounded_corners(session_t *ps);

#ifdef CONFIG_OPENGL
bool glx_load_prog_main(const char *vshader_str, const char *fshader_str,
                        glx_prog_main_t *pprogram);
#endif

bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, int width,
                     int height, bool repeat, const struct glx_fbconfig_info *);

void glx_release_pixmap(session_t *ps, glx_texture_t *ptex);

bool glx_bind_texture(session_t *ps, glx_texture_t **pptex, int x, int y, int width, int height);

void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2);

/**
 * Check if a texture is binded, or is binded to the given pixmap.
 */
static inline bool glx_tex_binded(const glx_texture_t *ptex, xcb_pixmap_t pixmap) {
	return ptex && ptex->glpixmap && ptex->texture && (!pixmap || pixmap == ptex->pixmap);
}

void glx_set_clip(session_t *ps, const region_t *reg);

bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
                  GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc);

bool glx_round_corners_dst(session_t *ps, struct managed_win *w,
                           const glx_texture_t *ptex, int dx, int dy, int width,
                           int height, float z, float cr, const region_t *reg_tgt);

GLuint glx_create_shader(GLenum shader_type, const char *shader_str);

GLuint glx_create_program(const GLuint *const shaders, int nshaders);

GLuint glx_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str);

unsigned char *glx_take_screenshot(session_t *ps, int *out_length);

/**
 * Check if there's a GLX context.
 */
static inline bool glx_has_context(session_t *ps) {
	return ps->psglx && ps->psglx->context;
}

/**
 * Ensure we have a GLX context.
 */
static inline bool ensure_glx_context(session_t *ps) {
	// Create GLX context
	if (!glx_has_context(ps))
		glx_init(ps, false);

	return ps->psglx->context;
}

/**
 * Free a GLX texture.
 */
static inline void free_texture_r(session_t *ps attr_unused, GLuint *ptexture) {
	if (*ptexture) {
		assert(glx_has_context(ps));
		glDeleteTextures(1, ptexture);
		*ptexture = 0;
	}
}

/**
 * Free a GLX Framebuffer object.
 */
static inline void free_glx_fbo(GLuint *pfbo) {
	if (*pfbo) {
		glDeleteFramebuffers(1, pfbo);
		*pfbo = 0;
	}
	assert(!*pfbo);
}

/**
 * Free data in glx_blur_cache_t on resize.
 */
static inline void free_glx_bc_resize(session_t *ps, glx_blur_cache_t *pbc) {
	free_texture_r(ps, &pbc->textures[0]);
	free_texture_r(ps, &pbc->textures[1]);
	pbc->width = 0;
	pbc->height = 0;
}

/**
 * Free a glx_blur_cache_t
 */
static inline void free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
	free_glx_fbo(&pbc->fbo);
	free_glx_bc_resize(ps, pbc);
}

/**
 * Free a glx_texture_t.
 */
static inline void free_texture(session_t *ps, glx_texture_t **pptex) {
	glx_texture_t *ptex = *pptex;

	// Quit if there's nothing
	if (!ptex) {
		return;
	}

	glx_release_pixmap(ps, ptex);

	free_texture_r(ps, &ptex->texture);

	// Free structure itself
	free(ptex);
	*pptex = NULL;
}

/**
 * Free GLX part of paint_t.
 */
static inline void free_paint_glx(session_t *ps, paint_t *ppaint) {
	free_texture(ps, &ppaint->ptex);
#ifdef CONFIG_OPENGL
	free(ppaint->fbcfg);
#endif
	ppaint->fbcfg = NULL;
}

/**
 * Free GLX part of win.
 */
static inline void free_win_res_glx(session_t *ps, struct managed_win *w) {
	free_paint_glx(ps, &w->paint);
	free_paint_glx(ps, &w->shadow_paint);
#ifdef CONFIG_OPENGL
	free_glx_bc(ps, &w->glx_blur_cache);
	free_texture(ps, &w->glx_texture_bg);
#endif
}