new glx: initial implementation
This is basically just adapting old code to the new interface. A lot of the functions are still stubs, but the basic stuffs is working. What remains to be done: * Implement gl_image_op. (It should do the operation lazily, only update the flags on the texture. Actual processing will be delayed until composition.) * Implement gl_copy. Now it just return the same image after incrementing the refcount. It should actually copy the image data structure so it can have a separate set of flags. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
5d321c85f5
commit
60c10790d7
|
@ -125,7 +125,7 @@ struct backend_operations {
|
||||||
|
|
||||||
/// Free resources associated with an image data structure
|
/// Free resources associated with an image data structure
|
||||||
void (*release_image)(backend_t *backend_data, void *img_data)
|
void (*release_image)(backend_t *backend_data, void *img_data)
|
||||||
__attribute__((nonnull(1, 2)));
|
attr_nonnull(1, 2);
|
||||||
|
|
||||||
// =========== Query ===========
|
// =========== Query ===========
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ struct backend_operations {
|
||||||
/// window (e.g. when using a custom shader with the glx backend), so we only now
|
/// window (e.g. when using a custom shader with the glx backend), so we only now
|
||||||
/// the transparency after the window is rendered
|
/// the transparency after the window is rendered
|
||||||
bool (*is_image_transparent)(backend_t *backend_data, void *image_data)
|
bool (*is_image_transparent)(backend_t *backend_data, void *image_data)
|
||||||
__attribute__((nonnull(1, 2)));
|
attr_nonnull(1, 2);
|
||||||
|
|
||||||
/// Get the age of the buffer content we are currently rendering ontop
|
/// Get the age of the buffer content we are currently rendering ontop
|
||||||
/// of. The buffer that has just been `present`ed has a buffer age of 1.
|
/// of. The buffer that has just been `present`ed has a buffer age of 1.
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "kernel.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "kernel.h"
|
|
||||||
|
|
||||||
#include "backend/gl/gl_common.h"
|
#include "backend/gl/gl_common.h"
|
||||||
|
|
||||||
|
@ -39,8 +39,6 @@
|
||||||
} \
|
} \
|
||||||
while (0)
|
while (0)
|
||||||
|
|
||||||
struct gl_data {};
|
|
||||||
|
|
||||||
GLuint gl_create_shader(GLenum shader_type, const char *shader_str) {
|
GLuint gl_create_shader(GLenum shader_type, const char *shader_str) {
|
||||||
log_trace("===\n%s\n===", shader_str);
|
log_trace("===\n%s\n===", shader_str);
|
||||||
|
|
||||||
|
@ -156,7 +154,7 @@ GLuint gl_create_program_from_str(const char *vert_shader_str, const char *frag_
|
||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl_free_prog_main(session_t *ps, gl_win_shader_t *pprogram) {
|
static void gl_free_prog_main(gl_win_shader_t *pprogram) {
|
||||||
if (!pprogram)
|
if (!pprogram)
|
||||||
return;
|
return;
|
||||||
if (pprogram->prog) {
|
if (pprogram->prog) {
|
||||||
|
@ -193,18 +191,36 @@ unsigned char *gl_take_screenshot(session_t *ps, int *out_length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Render a region with texture data.
|
* Render a region with texture data.
|
||||||
|
*
|
||||||
|
* @param ptex the texture
|
||||||
|
* @param dst_x,dst_y the top left corner of region where this texture
|
||||||
|
* should go. In Xorg coordinate system (important!).
|
||||||
|
* @param reg_tgt the clip region, also in Xorg coordinate system
|
||||||
|
* @param reg_visible ignored
|
||||||
*/
|
*/
|
||||||
bool gl_compose(const gl_texture_t *ptex, int x, int y, int dx, int dy, int width,
|
void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y,
|
||||||
int height, int z, double opacity, bool argb, bool neg,
|
const region_t *reg_tgt, const region_t *reg_visible) {
|
||||||
const region_t *reg_tgt, const gl_win_shader_t *shader) {
|
|
||||||
|
gl_texture_t *ptex = image_data;
|
||||||
|
struct gl_data *gd = (void *)base;
|
||||||
|
|
||||||
|
// Until we start to use glClipControl, reg_tgt, dst_x and dst_y and
|
||||||
|
// in a different coordinate system than the one OpenGL uses.
|
||||||
|
// OpenGL window coordinate (or NDC) has the origin at the lower left of the
|
||||||
|
// screen, with y axis pointing up; Xorg has the origin at the upper left of the
|
||||||
|
// screen, with y axis pointing down. We have to do some coordinate conversion in
|
||||||
|
// this function
|
||||||
if (!ptex || !ptex->texture) {
|
if (!ptex || !ptex->texture) {
|
||||||
log_error("Missing texture.");
|
log_error("Missing texture.");
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT ==
|
// dst_y is the top coordinate, in OpenGL, it is the upper bound of the y
|
||||||
// ps->psglx->fbconfigs[ptex->depth]->texture_fmt);
|
// coordinate.
|
||||||
|
dst_y = gd->height - dst_y;
|
||||||
|
auto dst_y2 = dst_y - ptex->height;
|
||||||
|
|
||||||
bool dual_texture = false;
|
bool dual_texture = false;
|
||||||
|
|
||||||
// It's required by legacy versions of OpenGL to enable texture target
|
// It's required by legacy versions of OpenGL to enable texture target
|
||||||
|
@ -212,28 +228,28 @@ bool gl_compose(const gl_texture_t *ptex, int x, int y, int dx, int dy, int widt
|
||||||
glEnable(ptex->target);
|
glEnable(ptex->target);
|
||||||
|
|
||||||
// Enable blending if needed
|
// Enable blending if needed
|
||||||
if (opacity < 1.0 || argb) {
|
if (ptex->opacity < 1.0 || ptex->has_alpha) {
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
// Needed for handling opacity of ARGB texture
|
// Needed for handling opacity of ARGB texture
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
|
|
||||||
// This is all weird, but X Render is using premultiplied ARGB format, and
|
// X pixmap is in premultiplied ARGB format, so
|
||||||
// we need to use those things to correct it. Thanks to derhass for help.
|
// we need to do this to correct it.
|
||||||
|
// Thanks to derhass for help.
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glColor4f(opacity, opacity, opacity, opacity);
|
glColor4f(ptex->opacity, ptex->opacity, ptex->opacity, ptex->opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Programmable path
|
if (gd->win_shader.prog) {
|
||||||
if (shader->prog) {
|
glUseProgram(gd->win_shader.prog);
|
||||||
glUseProgram(shader->prog);
|
if (gd->win_shader.unifm_opacity >= 0)
|
||||||
if (shader->unifm_opacity >= 0)
|
glUniform1f(gd->win_shader.unifm_opacity, ptex->opacity);
|
||||||
glUniform1f(shader->unifm_opacity, opacity);
|
if (gd->win_shader.unifm_invert_color >= 0)
|
||||||
if (shader->unifm_invert_color >= 0)
|
glUniform1i(gd->win_shader.unifm_invert_color, ptex->color_inverted);
|
||||||
glUniform1i(shader->unifm_invert_color, neg);
|
if (gd->win_shader.unifm_tex >= 0)
|
||||||
if (shader->unifm_tex >= 0)
|
glUniform1i(gd->win_shader.unifm_tex, 0);
|
||||||
glUniform1i(shader->unifm_tex, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// log_trace("Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n",
|
// log_trace("Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n",
|
||||||
|
@ -248,12 +264,29 @@ bool gl_compose(const gl_texture_t *ptex, int x, int y, int dx, int dy, int widt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Painting
|
// Painting
|
||||||
P_PAINTREG_START(reg_tgt, crect) {
|
int nrects;
|
||||||
|
const rect_t *rects;
|
||||||
|
rects = pixman_region32_rectangles((region_t *)reg_tgt, &nrects);
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
for (int ri = 0; ri < nrects; ++ri) {
|
||||||
|
// Y-flip. Note after this, crect.y1 > crect.y2
|
||||||
|
rect_t crect = rects[ri];
|
||||||
|
crect.y1 = gd->height - crect.y1;
|
||||||
|
crect.y2 = gd->height - crect.y2;
|
||||||
|
|
||||||
// Calculate texture coordinates
|
// Calculate texture coordinates
|
||||||
GLfloat texture_x1 = (double)(crect.x1 - dx + x);
|
// (texture_x1, texture_y1), texture coord for the _bottom left_ corner
|
||||||
GLfloat texture_y1 = (double)(crect.y1 - dy + y);
|
GLfloat texture_x1 = crect.x1 - dst_x;
|
||||||
GLfloat texture_x2 = texture_x1 + (double)(crect.x2 - crect.x1);
|
GLfloat texture_y1 = crect.y2 - dst_y2;
|
||||||
GLfloat texture_y2 = texture_y1 + (double)(crect.y2 - crect.y1);
|
GLfloat texture_x2 = texture_x1 + crect.x2 - crect.x1;
|
||||||
|
GLfloat texture_y2 = texture_y1 + crect.y1 - crect.y2;
|
||||||
|
|
||||||
|
// X pixmaps might be Y inverted, invert the texture coordinates
|
||||||
|
if (ptex->y_inverted) {
|
||||||
|
texture_y1 = ptex->height - texture_y1;
|
||||||
|
texture_y2 = ptex->height - texture_y2;
|
||||||
|
}
|
||||||
|
|
||||||
if (ptex->target == GL_TEXTURE_2D) {
|
if (ptex->target == GL_TEXTURE_2D) {
|
||||||
// GL_TEXTURE_2D coordinates are 0-1
|
// GL_TEXTURE_2D coordinates are 0-1
|
||||||
|
@ -265,15 +298,9 @@ bool gl_compose(const gl_texture_t *ptex, int x, int y, int dx, int dy, int widt
|
||||||
|
|
||||||
// Vertex coordinates
|
// Vertex coordinates
|
||||||
GLint vx1 = crect.x1;
|
GLint vx1 = crect.x1;
|
||||||
GLint vy1 = crect.y1;
|
GLint vy1 = crect.y2;
|
||||||
GLint vx2 = crect.x2;
|
GLint vx2 = crect.x2;
|
||||||
GLint vy2 = crect.y2;
|
GLint vy2 = crect.y1;
|
||||||
|
|
||||||
// X pixmaps might be Y inverted, invert the texture coordinates
|
|
||||||
if (ptex->y_inverted) {
|
|
||||||
texture_y1 = 1.0 - texture_y1;
|
|
||||||
texture_y2 = 1.0 - texture_y2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// log_trace("Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d",
|
// log_trace("Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d",
|
||||||
// ri, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
|
// ri, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
|
||||||
|
@ -285,10 +312,11 @@ bool gl_compose(const gl_texture_t *ptex, int x, int y, int dx, int dy, int widt
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
glTexCoord2f(texture_x[i], texture_y[i]);
|
glTexCoord2f(texture_x[i], texture_y[i]);
|
||||||
glVertex3i(vx[i], vy[i], z);
|
glVertex3i(vx[i], vy[i], 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
P_PAINTREG_END();
|
|
||||||
|
glEnd();
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
glBindTexture(ptex->target, 0);
|
glBindTexture(ptex->target, 0);
|
||||||
|
@ -309,7 +337,7 @@ bool gl_compose(const gl_texture_t *ptex, int x, int y, int dx, int dy, int widt
|
||||||
|
|
||||||
gl_check_err();
|
gl_check_err();
|
||||||
|
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gl_dim_reg(session_t *ps, int dx, int dy, int width, int height, float z,
|
bool gl_dim_reg(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
|
@ -354,6 +382,7 @@ static inline int gl_gen_texture(GLenum tex_tgt, int width, int height, GLuint *
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/**
|
/**
|
||||||
* Blur contents in a particular region.
|
* Blur contents in a particular region.
|
||||||
*
|
*
|
||||||
|
@ -479,8 +508,10 @@ bool gl_blur_dst(session_t *ps, const gl_cap_t *cap, int dx, int dy, int width,
|
||||||
// Texture coordinates
|
// Texture coordinates
|
||||||
const GLfloat texture_x1 = (crect.x1 - dx) * texfac_x;
|
const GLfloat texture_x1 = (crect.x1 - dx) * texfac_x;
|
||||||
const GLfloat texture_y1 = (crect.y1 - dy) * texfac_y;
|
const GLfloat texture_y1 = (crect.y1 - dy) * texfac_y;
|
||||||
const GLfloat texture_x2 = texture_x1 + (crect.x2 - crect.x1) * texfac_x;
|
const GLfloat texture_x2 =
|
||||||
const GLfloat texture_y2 = texture_y1 + (crect.y2 - crect.y1) * texfac_y;
|
texture_x1 + (crect.x2 - crect.x1) * texfac_x;
|
||||||
|
const GLfloat texture_y2 =
|
||||||
|
texture_y1 + (crect.y2 - crect.y1) * texfac_y;
|
||||||
|
|
||||||
// Vertex coordinates
|
// Vertex coordinates
|
||||||
// For passes before the last one, we are drawing into a buffer,
|
// For passes before the last one, we are drawing into a buffer,
|
||||||
|
@ -537,6 +568,7 @@ end:
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set clipping region on the target window.
|
* Set clipping region on the target window.
|
||||||
|
@ -596,7 +628,7 @@ int gl_win_shader_from_string(session_t *ps, const char *vshader_str,
|
||||||
/**
|
/**
|
||||||
* Callback to run on root window size change.
|
* Callback to run on root window size change.
|
||||||
*/
|
*/
|
||||||
void gl_resize(int width, int height) {
|
void gl_resize(struct gl_data *gd, int width, int height) {
|
||||||
glViewport(0, 0, width, height);
|
glViewport(0, 0, width, height);
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
@ -604,6 +636,8 @@ void gl_resize(int width, int height) {
|
||||||
glOrtho(0, width, 0, height, -1000.0, 1000.0);
|
glOrtho(0, width, 0, height, -1000.0, 1000.0);
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
gd->height = height;
|
||||||
|
gd->width = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void attr_unused gl_destroy_win_shader(session_t *ps, gl_win_shader_t *shader) {
|
static void attr_unused gl_destroy_win_shader(session_t *ps, gl_win_shader_t *shader) {
|
||||||
|
@ -616,6 +650,7 @@ static void attr_unused gl_destroy_win_shader(session_t *ps, gl_win_shader_t *sh
|
||||||
shader->unifm_tex = -1;
|
shader->unifm_tex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/**
|
/**
|
||||||
* Initialize GL blur filters.
|
* Initialize GL blur filters.
|
||||||
*
|
*
|
||||||
|
@ -652,17 +687,22 @@ bool gl_create_blur_filters(session_t *ps, gl_blur_shader_t *passes, const gl_ca
|
||||||
"void main() {\n"
|
"void main() {\n"
|
||||||
" vec4 sum = vec4(0.0, 0.0, 0.0, "
|
" vec4 sum = vec4(0.0, 0.0, 0.0, "
|
||||||
"0.0);\n";
|
"0.0);\n";
|
||||||
static const char *FRAG_SHADER_BLUR_ADD =
|
static const char *FRAG_SHADER_BLUR_ADD = " sum += float(%.7g) * %s(tex_scr, "
|
||||||
" sum += float(%.7g) * %s(tex_scr, vec2(gl_TexCoord[0].x + offset_x "
|
"vec2(gl_TexCoord[0].x + offset_x "
|
||||||
"* float(%d), gl_TexCoord[0].y + offset_y * float(%d)));\n";
|
"* float(%d), gl_TexCoord[0].y + "
|
||||||
static const char *FRAG_SHADER_BLUR_ADD_GPUSHADER4 =
|
"offset_y * float(%d)));\n";
|
||||||
" sum += float(%.7g) * %sOffset(tex_scr, vec2(gl_TexCoord[0].x, "
|
static const char *FRAG_SHADER_BLUR_ADD_GPUSHADER4 = " sum += float(%.7g) * "
|
||||||
"gl_TexCoord[0].y), ivec2(%d, %d));\n";
|
"%sOffset(tex_scr, "
|
||||||
static const char *FRAG_SHADER_BLUR_SUFFIX =
|
"vec2(gl_TexCoord[0].x, "
|
||||||
" sum += %s(tex_scr, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y)) * "
|
"gl_TexCoord[0].y), "
|
||||||
"factor_center;\n"
|
"ivec2(%d, %d));\n";
|
||||||
" gl_FragColor = sum / (factor_center + float(%.7g));\n"
|
static const char *FRAG_SHADER_BLUR_SUFFIX = " sum += %s(tex_scr, "
|
||||||
"}\n";
|
"vec2(gl_TexCoord[0].x, "
|
||||||
|
"gl_TexCoord[0].y)) * "
|
||||||
|
"factor_center;\n"
|
||||||
|
" gl_FragColor = sum / "
|
||||||
|
"(factor_center + float(%.7g));\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
const bool use_texture_rect = !cap->non_power_of_two_texture;
|
const bool use_texture_rect = !cap->non_power_of_two_texture;
|
||||||
const char *sampler_type = (use_texture_rect ? "sampler2DRect" : "sampler2D");
|
const char *sampler_type = (use_texture_rect ? "sampler2DRect" : "sampler2D");
|
||||||
|
@ -685,7 +725,8 @@ bool gl_create_blur_filters(session_t *ps, gl_blur_shader_t *passes, const gl_ca
|
||||||
int nele = width * height - 1;
|
int nele = width * height - 1;
|
||||||
unsigned int len =
|
unsigned int len =
|
||||||
strlen(FRAG_SHADER_BLUR_PREFIX) + strlen(sampler_type) +
|
strlen(FRAG_SHADER_BLUR_PREFIX) + strlen(sampler_type) +
|
||||||
strlen(extension) + (strlen(shader_add) + strlen(texture_func) + 42) * nele +
|
strlen(extension) +
|
||||||
|
(strlen(shader_add) + strlen(texture_func) + 42) * nele +
|
||||||
strlen(FRAG_SHADER_BLUR_SUFFIX) + strlen(texture_func) + 12 + 1;
|
strlen(FRAG_SHADER_BLUR_SUFFIX) + strlen(texture_func) + 12 + 1;
|
||||||
char *shader_str = ccalloc(len, char);
|
char *shader_str = ccalloc(len, char);
|
||||||
char *pc = shader_str;
|
char *pc = shader_str;
|
||||||
|
@ -703,7 +744,8 @@ bool gl_create_blur_filters(session_t *ps, gl_blur_shader_t *passes, const gl_ca
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sum += val;
|
sum += val;
|
||||||
sprintf(pc, shader_add, val, texture_func, k - width / 2, j - height / 2);
|
sprintf(pc, shader_add, val, texture_func, k - width / 2,
|
||||||
|
j - height / 2);
|
||||||
pc += strlen(pc);
|
pc += strlen(pc);
|
||||||
assert(strlen(shader_str) < len);
|
assert(strlen(shader_str) < len);
|
||||||
}
|
}
|
||||||
|
@ -728,8 +770,10 @@ bool gl_create_blur_filters(session_t *ps, gl_blur_shader_t *passes, const gl_ca
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get uniform addresses
|
// Get uniform addresses
|
||||||
pass->unifm_factor_center =
|
pass->unifm_factor_center = glGetUniformLocationChecked(pass->prog, "fact"
|
||||||
glGetUniformLocationChecked(pass->prog, "factor_center");
|
"or_"
|
||||||
|
"cent"
|
||||||
|
"er");
|
||||||
if (!ps->o.glx_use_gpushader4) {
|
if (!ps->o.glx_use_gpushader4) {
|
||||||
pass->unifm_offset_x =
|
pass->unifm_offset_x =
|
||||||
glGetUniformLocationChecked(pass->prog, "offset_x");
|
glGetUniformLocationChecked(pass->prog, "offset_x");
|
||||||
|
@ -752,3 +796,121 @@ err:
|
||||||
free(lc_numeric_old);
|
free(lc_numeric_old);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool gl_init(struct gl_data *gd, session_t *ps) {
|
||||||
|
// Initialize GLX data structure
|
||||||
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
||||||
|
gd->blur_shader[i] = (gl_blur_shader_t){.frag_shader = 0,
|
||||||
|
.prog = 0,
|
||||||
|
.unifm_offset_x = -1,
|
||||||
|
.unifm_offset_y = -1,
|
||||||
|
.unifm_factor_center = -1};
|
||||||
|
}
|
||||||
|
|
||||||
|
gd->non_power_of_two_texture = gl_has_extension("GL_ARB_texture_non_power_of_"
|
||||||
|
"two");
|
||||||
|
|
||||||
|
// Ensure we have a stencil buffer. X Fixes does not guarantee rectangles
|
||||||
|
// in regions don't overlap, so we must use stencil buffer to make sure
|
||||||
|
// we don't paint a region for more than one time, I think?
|
||||||
|
if (!ps->o.glx_no_stencil) {
|
||||||
|
GLint val = 0;
|
||||||
|
glGetIntegerv(GL_STENCIL_BITS, &val);
|
||||||
|
if (!val) {
|
||||||
|
log_error("Target window doesn't have stencil buffer.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render preparations
|
||||||
|
gl_resize(gd, ps->root_width, ps->root_height);
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
if (!ps->o.glx_no_stencil) {
|
||||||
|
// Initialize stencil buffer
|
||||||
|
glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
glStencilMask(0x1);
|
||||||
|
glStencilFunc(GL_EQUAL, 0x1, 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
// glXSwapBuffers(ps->dpy, get_tgt_window(ps));
|
||||||
|
|
||||||
|
// Initialize blur filters
|
||||||
|
// gl_create_blur_filters(ps, gd->blur_shader, &gd->cap);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl_deinit(struct gl_data *gd) {
|
||||||
|
// Free GLSL shaders/programs
|
||||||
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
||||||
|
gl_free_blur_shader(&gd->blur_shader[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_free_prog_main(&gd->win_shader);
|
||||||
|
|
||||||
|
gl_check_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint gl_new_texture(GLenum target) {
|
||||||
|
GLuint texture;
|
||||||
|
glGenTextures(1, &texture);
|
||||||
|
if (!texture) {
|
||||||
|
log_error("Failed to generate texture");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(target, texture);
|
||||||
|
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glBindTexture(target, 0);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// stub for backend_operations::image_op
|
||||||
|
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) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// stub for backend_operations::copy
|
||||||
|
void *gl_copy(backend_t *base, const void *image_data, const region_t *reg_visible) {
|
||||||
|
struct gl_texture *t = (void *)image_data;
|
||||||
|
t->refcount++;
|
||||||
|
return (void *)image_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gl_is_image_transparent(backend_t *base, void *image_data) {
|
||||||
|
gl_texture_t *img = image_data;
|
||||||
|
return img->has_alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// stub for backend_operations::blur
|
||||||
|
bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
|
||||||
|
const region_t *reg_visible) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
#include <GL/glext.h>
|
#include <GL/glext.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "region.h"
|
#include "backend/backend.h"
|
||||||
|
#include "config.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "region.h"
|
||||||
|
|
||||||
#define CASESTRRET(s) case s: return #s
|
#define CASESTRRET(s) \
|
||||||
|
case s: return #s
|
||||||
|
|
||||||
// Program and uniforms for window shader
|
// Program and uniforms for window shader
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -39,18 +42,26 @@ typedef struct {
|
||||||
|
|
||||||
/// @brief Wrapper of a binded GLX texture.
|
/// @brief Wrapper of a binded GLX texture.
|
||||||
typedef struct gl_texture {
|
typedef struct gl_texture {
|
||||||
|
double opacity;
|
||||||
|
int refcount;
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
GLenum target;
|
GLenum target;
|
||||||
unsigned width;
|
unsigned width;
|
||||||
unsigned height;
|
unsigned height;
|
||||||
unsigned depth;
|
unsigned depth;
|
||||||
bool y_inverted;
|
bool y_inverted;
|
||||||
|
bool has_alpha;
|
||||||
|
bool color_inverted;
|
||||||
} gl_texture_t;
|
} gl_texture_t;
|
||||||
|
|
||||||
// OpenGL capabilities
|
struct gl_data {
|
||||||
typedef struct gl_cap {
|
backend_t base;
|
||||||
|
// Height and width of the viewport
|
||||||
|
int height, width;
|
||||||
|
gl_win_shader_t win_shader;
|
||||||
|
gl_blur_shader_t blur_shader[MAX_BLUR_PASS];
|
||||||
bool non_power_of_two_texture;
|
bool non_power_of_two_texture;
|
||||||
} gl_cap_t;
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/// Framebuffer used for blurring.
|
/// Framebuffer used for blurring.
|
||||||
|
@ -70,25 +81,42 @@ typedef struct session session_t;
|
||||||
|
|
||||||
GLuint gl_create_shader(GLenum shader_type, const char *shader_str);
|
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(const GLuint *const shaders, int nshaders);
|
||||||
GLuint
|
GLuint gl_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str);
|
||||||
gl_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str);
|
|
||||||
/**
|
/**
|
||||||
* @brief Render a region with texture data.
|
* @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,
|
void gl_compose(backend_t *, void *ptex, int dst_x, int dst_y, const region_t *reg_tgt,
|
||||||
int height, int z, double opacity, bool argb, bool neg,
|
const region_t *reg_visible);
|
||||||
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,
|
bool gl_load_prog_main(session_t *ps, const char *vshader_str, const char *fshader_str,
|
||||||
gl_win_shader_t *pprogram);
|
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);
|
unsigned char *gl_take_screenshot(session_t *ps, int *out_length);
|
||||||
void gl_resize(int width, int height);
|
void gl_resize(struct gl_data *, int width, int height);
|
||||||
bool gl_create_blur_filters(session_t *ps, gl_blur_shader_t *passes, const gl_cap_t *cap);
|
//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);
|
GLuint glGetUniformLocationChecked(GLuint p, const char *name);
|
||||||
|
|
||||||
|
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_copy(backend_t *base, const void *image_data, const region_t *reg_visible);
|
||||||
|
|
||||||
|
bool gl_blur(backend_t *base, double opacity, const region_t *reg_blur,
|
||||||
|
const region_t *reg_visible);
|
||||||
|
|
||||||
|
bool gl_is_image_transparent(backend_t *base, void *image_data);
|
||||||
|
|
||||||
|
static inline void gl_delete_texture(GLuint texture) {
|
||||||
|
glDeleteTextures(1, &texture);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a textual representation of an OpenGL error.
|
* Get a textual representation of an OpenGL error.
|
||||||
*/
|
*/
|
||||||
|
@ -147,13 +175,3 @@ static inline bool gl_has_extension(const char *ext) {
|
||||||
log_info("Missing GL extension %s.", ext);
|
log_info("Missing GL extension %s.", ext);
|
||||||
return false;
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
#include "backend/backend.h"
|
#include "backend/backend.h"
|
||||||
|
#include "backend/backend_common.h"
|
||||||
#include "backend/gl/gl_common.h"
|
#include "backend/gl/gl_common.h"
|
||||||
#include "backend/gl/glx.h"
|
#include "backend/gl/glx.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
@ -32,28 +33,23 @@
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "x.h"
|
#include "x.h"
|
||||||
|
|
||||||
struct _glx_win_data {
|
struct _glx_image_data {
|
||||||
gl_texture_t texture;
|
gl_texture_t texture;
|
||||||
GLXPixmap glpixmap;
|
GLXPixmap glpixmap;
|
||||||
xcb_pixmap_t pixmap;
|
xcb_pixmap_t pixmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _glx_data {
|
struct _glx_data {
|
||||||
backend_t base;
|
struct gl_data gl;
|
||||||
|
Display *display;
|
||||||
|
int screen;
|
||||||
|
int target_win;
|
||||||
int glx_event;
|
int glx_event;
|
||||||
int glx_error;
|
int glx_error;
|
||||||
GLXContext ctx;
|
GLXContext ctx;
|
||||||
gl_cap_t cap;
|
|
||||||
gl_win_shader_t win_shader;
|
|
||||||
gl_blur_shader_t blur_shader[MAX_BLUR_PASS];
|
|
||||||
|
|
||||||
void (*glXBindTexImage)(Display *display, GLXDrawable drawable, int buffer,
|
|
||||||
const int *attrib_list);
|
|
||||||
void (*glXReleaseTexImage)(Display *display, GLXDrawable drawable, int buffer);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct glx_fbconfig_info *
|
struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvisual_info m) {
|
||||||
glx_find_fbconfig(Display *dpy, int screen, struct xvisual_info m) {
|
|
||||||
log_debug("Looking for FBConfig for RGBA%d%d%d%d, depth %d", m.red_size,
|
log_debug("Looking for FBConfig for RGBA%d%d%d%d, depth %d", m.red_size,
|
||||||
m.blue_size, m.green_size, m.alpha_size, m.visual_depth);
|
m.blue_size, m.green_size, m.alpha_size, m.visual_depth);
|
||||||
|
|
||||||
|
@ -160,69 +156,47 @@ glx_find_fbconfig(Display *dpy, int screen, struct xvisual_info m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Release binding of a texture.
|
* Free a glx_texture_t.
|
||||||
*/
|
*/
|
||||||
static void glx_release_pixmap(struct _glx_data *gd, Display *dpy, struct _glx_win_data *wd) {
|
void glx_release_image(backend_t *base, void *image_data) {
|
||||||
|
struct _glx_image_data *wd = image_data;
|
||||||
|
struct _glx_data *gd = (void *)base;
|
||||||
|
wd->texture.refcount--;
|
||||||
|
if (wd->texture.refcount != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Release binding
|
// Release binding
|
||||||
if (wd->glpixmap && wd->texture.texture) {
|
if (wd->glpixmap && wd->texture.texture) {
|
||||||
glBindTexture(wd->texture.target, wd->texture.texture);
|
glBindTexture(wd->texture.target, wd->texture.texture);
|
||||||
gd->glXReleaseTexImage(dpy, wd->glpixmap, GLX_FRONT_LEFT_EXT);
|
glXReleaseTexImageEXT(gd->display, wd->glpixmap, GLX_FRONT_LEFT_EXT);
|
||||||
glBindTexture(wd->texture.target, 0);
|
glBindTexture(wd->texture.target, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free GLX Pixmap
|
// Free GLX Pixmap
|
||||||
if (wd->glpixmap) {
|
if (wd->glpixmap) {
|
||||||
glXDestroyPixmap(dpy, wd->glpixmap);
|
glXDestroyPixmap(gd->display, wd->glpixmap);
|
||||||
wd->glpixmap = 0;
|
wd->glpixmap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gl_check_err();
|
gl_delete_texture(wd->texture.texture);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free a glx_texture_t.
|
|
||||||
*/
|
|
||||||
void glx_release_win(void *backend_data, session_t *ps, win *w, void *win_data) {
|
|
||||||
struct _glx_win_data *wd = win_data;
|
|
||||||
struct _glx_data *gd = backend_data;
|
|
||||||
glx_release_pixmap(gd, ps->dpy, wd);
|
|
||||||
glDeleteTextures(1, &wd->texture.texture);
|
|
||||||
|
|
||||||
// Free structure itself
|
// Free structure itself
|
||||||
free(wd);
|
free(wd);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
gl_check_err();
|
||||||
* Free GLX part of win.
|
|
||||||
*/
|
|
||||||
static inline void free_win_res_glx(session_t *ps, win *w) {
|
|
||||||
/*free_paint_glx(ps, &w->paint);*/
|
|
||||||
/*free_paint_glx(ps, &w->shadow_paint);*/
|
|
||||||
/*free_glx_bc(ps, &w->glx_blur_cache);*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy GLX related resources.
|
* Destroy GLX related resources.
|
||||||
*/
|
*/
|
||||||
void glx_deinit(void *backend_data, session_t *ps) {
|
void glx_deinit(backend_t *base) {
|
||||||
struct _glx_data *gd = backend_data;
|
struct _glx_data *gd = (void *)base;
|
||||||
|
|
||||||
// Free all GLX resources of windows
|
gl_deinit(&gd->gl);
|
||||||
for (win *w = ps->list; w; w = w->next)
|
|
||||||
free_win_res_glx(ps, w);
|
|
||||||
|
|
||||||
// Free GLSL shaders/programs
|
|
||||||
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
|
||||||
gl_free_blur_shader(&gd->blur_shader[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
gl_free_prog_main(ps, &gd->win_shader);
|
|
||||||
|
|
||||||
gl_check_err();
|
|
||||||
|
|
||||||
// Destroy GLX context
|
// Destroy GLX context
|
||||||
if (gd->ctx) {
|
if (gd->ctx) {
|
||||||
glXDestroyContext(ps->dpy, gd->ctx);
|
glXDestroyContext(gd->display, gd->ctx);
|
||||||
gd->ctx = 0;
|
gd->ctx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,13 +206,15 @@ void glx_deinit(void *backend_data, session_t *ps) {
|
||||||
/**
|
/**
|
||||||
* Initialize OpenGL.
|
* Initialize OpenGL.
|
||||||
*/
|
*/
|
||||||
backend_t *backend_glx_init(session_t *ps) {
|
static backend_t *glx_init(session_t *ps) {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
glxext_init(ps->dpy, ps->scr);
|
glxext_init(ps->dpy, ps->scr);
|
||||||
auto gd = ccalloc(1, struct _glx_data);
|
auto gd = ccalloc(1, struct _glx_data);
|
||||||
gd->base.c = ps->c;
|
gd->gl.base.c = ps->c;
|
||||||
gd->base.root = ps->root;
|
gd->gl.base.root = ps->root;
|
||||||
gd->base.ops = NULL; // TODO
|
gd->display = ps->dpy;
|
||||||
|
gd->screen = ps->scr;
|
||||||
|
gd->target_win = ps->overlay != XCB_NONE ? ps->overlay : ps->root;
|
||||||
|
|
||||||
XVisualInfo *pvis = NULL;
|
XVisualInfo *pvis = NULL;
|
||||||
|
|
||||||
|
@ -275,15 +251,6 @@ backend_t *backend_glx_init(session_t *ps) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize GLX data structure
|
|
||||||
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
|
||||||
gd->blur_shader[i] = (gl_blur_shader_t){.frag_shader = -1,
|
|
||||||
.prog = -1,
|
|
||||||
.unifm_offset_x = -1,
|
|
||||||
.unifm_offset_y = -1,
|
|
||||||
.unifm_factor_center = -1};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get GLX context
|
// Get GLX context
|
||||||
gd->ctx = glXCreateContext(ps->dpy, pvis, NULL, GL_TRUE);
|
gd->ctx = glXCreateContext(ps->dpy, pvis, NULL, GL_TRUE);
|
||||||
|
|
||||||
|
@ -313,93 +280,51 @@ backend_t *backend_glx_init(session_t *ps) {
|
||||||
p_DebugMessageCallback(glx_debug_msg_callback, ps);
|
p_DebugMessageCallback(glx_debug_msg_callback, ps);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Ensure we have a stencil buffer. X Fixes does not guarantee rectangles
|
if (!gl_init(&gd->gl, ps)) {
|
||||||
// in regions don't overlap, so we must use stencil buffer to make sure
|
log_error("Failed to setup OpenGL");
|
||||||
// we don't paint a region for more than one time, I think?
|
|
||||||
if (!ps->o.glx_no_stencil) {
|
|
||||||
GLint val = 0;
|
|
||||||
glGetIntegerv(GL_STENCIL_BITS, &val);
|
|
||||||
if (!val) {
|
|
||||||
log_error("Target window doesn't have stencil buffer.");
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check GL_ARB_texture_non_power_of_two, requires a GLX context and
|
|
||||||
// must precede FBConfig fetching
|
|
||||||
gd->cap.non_power_of_two_texture = gl_has_extension("GL_ARB_texture_non_"
|
|
||||||
"power_of_two");
|
|
||||||
|
|
||||||
gd->glXBindTexImage = (void *)glXGetProcAddress((const GLubyte *)"glXBindTexImage"
|
|
||||||
"EXT");
|
|
||||||
gd->glXReleaseTexImage = (void *)glXGetProcAddress((const GLubyte *)"glXReleaseTe"
|
|
||||||
"xImageEXT");
|
|
||||||
if (!gd->glXBindTexImage || !gd->glXReleaseTexImage) {
|
|
||||||
log_error("Failed to acquire glXBindTexImageEXT() and/or "
|
|
||||||
"glXReleaseTexImageEXT(), make sure your OpenGL supports"
|
|
||||||
"GLX_EXT_texture_from_pixmap");
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render preparations
|
|
||||||
gl_resize(ps->root_width, ps->root_height);
|
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
|
|
||||||
if (!ps->o.glx_no_stencil) {
|
|
||||||
// Initialize stencil buffer
|
|
||||||
glClear(GL_STENCIL_BUFFER_BIT);
|
|
||||||
glDisable(GL_STENCIL_TEST);
|
|
||||||
glStencilMask(0x1);
|
|
||||||
glStencilFunc(GL_EQUAL, 0x1, 0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear screen
|
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
// glXSwapBuffers(ps->dpy, get_tgt_window(ps));
|
|
||||||
|
|
||||||
// Initialize blur filters
|
|
||||||
// gl_create_blur_filters(ps, gd->blur_shader, &gd->cap);
|
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (pvis)
|
if (pvis) {
|
||||||
XFree(pvis);
|
XFree(pvis);
|
||||||
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
glx_deinit(gd, ps);
|
glx_deinit(&gd->gl.base);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return &gd->base;
|
return &gd->gl.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *glx_prepare_win(void *backend_data, session_t *ps, win *w) {
|
static void *glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap,
|
||||||
struct _glx_data *gd = backend_data;
|
struct xvisual_info fmt, bool owned) {
|
||||||
|
struct _glx_data *gd = (void *)base;
|
||||||
// Retrieve pixmap parameters, if they aren't provided
|
// Retrieve pixmap parameters, if they aren't provided
|
||||||
if (w->g.depth > OPENGL_MAX_DEPTH) {
|
if (fmt.visual_depth > OPENGL_MAX_DEPTH) {
|
||||||
log_error("Requested depth %d higher than max possible depth %d.",
|
log_error("Requested depth %d higher than max possible depth %d.",
|
||||||
w->g.depth, OPENGL_MAX_DEPTH);
|
fmt.visual_depth, OPENGL_MAX_DEPTH);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto wd = ccalloc(1, struct _glx_win_data);
|
auto r = xcb_get_geometry_reply(base->c, xcb_get_geometry(base->c, pixmap), NULL);
|
||||||
wd->pixmap = xcb_generate_id(ps->c);
|
if (!r) {
|
||||||
xcb_composite_name_window_pixmap(ps->c, w->id, wd->pixmap);
|
log_error("Invalid pixmap %#010x", pixmap);
|
||||||
if (!wd->pixmap) {
|
return NULL;
|
||||||
log_error("Failed to get pixmap for window %#010x", w->id);
|
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto visual_info = x_get_visual_info(ps->c, w->a.visual);
|
auto wd = ccalloc(1, struct _glx_image_data);
|
||||||
auto fbcfg = glx_find_fbconfig(ps->dpy, ps->scr, visual_info);
|
wd->pixmap = pixmap;
|
||||||
|
wd->texture.width = r->width;
|
||||||
|
wd->texture.height = r->height;
|
||||||
|
free(r);
|
||||||
|
|
||||||
|
auto fbcfg = glx_find_fbconfig(gd->display, gd->screen, fmt);
|
||||||
if (!fbcfg) {
|
if (!fbcfg) {
|
||||||
log_error("Couldn't find FBConfig with requested visual %x", w->a.visual);
|
log_error("Couldn't find FBConfig with requested visual %x", fmt.visual);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,7 +332,7 @@ void *glx_prepare_win(void *backend_data, session_t *ps, win *w) {
|
||||||
// Refer to GLX_EXT_texture_om_pixmap spec to see what are the mean
|
// Refer to GLX_EXT_texture_om_pixmap spec to see what are the mean
|
||||||
// of the bits in texture_tgts
|
// of the bits in texture_tgts
|
||||||
GLenum tex_tgt = 0;
|
GLenum tex_tgt = 0;
|
||||||
if (GLX_TEXTURE_2D_BIT_EXT & fbcfg->texture_tgts && gd->cap.non_power_of_two_texture)
|
if (GLX_TEXTURE_2D_BIT_EXT & fbcfg->texture_tgts && gd->gl.non_power_of_two_texture)
|
||||||
tex_tgt = GLX_TEXTURE_2D_EXT;
|
tex_tgt = GLX_TEXTURE_2D_EXT;
|
||||||
else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & fbcfg->texture_tgts)
|
else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & fbcfg->texture_tgts)
|
||||||
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
|
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
|
||||||
|
@ -416,7 +341,7 @@ void *glx_prepare_win(void *backend_data, session_t *ps, win *w) {
|
||||||
else
|
else
|
||||||
tex_tgt = GLX_TEXTURE_2D_EXT;
|
tex_tgt = GLX_TEXTURE_2D_EXT;
|
||||||
|
|
||||||
log_debug("depth %d, tgt %#x, rgba %d\n", w->g.depth, tex_tgt,
|
log_debug("depth %d, tgt %#x, rgba %d\n", fmt.visual_depth, tex_tgt,
|
||||||
(GLX_TEXTURE_FORMAT_RGBA_EXT == fbcfg->texture_fmt));
|
(GLX_TEXTURE_FORMAT_RGBA_EXT == fbcfg->texture_fmt));
|
||||||
|
|
||||||
GLint attrs[] = {
|
GLint attrs[] = {
|
||||||
|
@ -431,122 +356,69 @@ void *glx_prepare_win(void *backend_data, session_t *ps, win *w) {
|
||||||
(GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE);
|
(GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE);
|
||||||
wd->texture.y_inverted = fbcfg->y_inverted;
|
wd->texture.y_inverted = fbcfg->y_inverted;
|
||||||
|
|
||||||
wd->glpixmap = glXCreatePixmap(ps->dpy, fbcfg->cfg, wd->pixmap, attrs);
|
wd->glpixmap = glXCreatePixmap(gd->display, fbcfg->cfg, wd->pixmap, attrs);
|
||||||
free(fbcfg);
|
free(fbcfg);
|
||||||
|
|
||||||
if (!wd->glpixmap) {
|
if (!wd->glpixmap) {
|
||||||
log_error("Failed to create glpixmap for window %#010x", w->id);
|
log_error("Failed to create glpixmap for pixmap %#010x", pixmap);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create texture
|
// Create texture
|
||||||
|
wd->texture.texture = gl_new_texture(wd->texture.target);
|
||||||
|
wd->texture.opacity = 1;
|
||||||
|
wd->texture.depth = fmt.visual_depth;
|
||||||
|
wd->texture.color_inverted = false;
|
||||||
|
wd->texture.has_alpha = fmt.alpha_size != 0;
|
||||||
|
wd->texture.refcount = 1;
|
||||||
|
glBindTexture(wd->texture.target, wd->texture.texture);
|
||||||
|
glXBindTexImageEXT(gd->display, wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
|
||||||
|
glBindTexture(wd->texture.target, 0);
|
||||||
|
|
||||||
GLuint texture = 0;
|
gl_check_err();
|
||||||
GLuint target = wd->texture.target;
|
|
||||||
glGenTextures(1, &texture);
|
|
||||||
if (!texture) {
|
|
||||||
log_error("Failed to generate texture for window %#010x", w->id);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindTexture(target, texture);
|
|
||||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glBindTexture(target, 0);
|
|
||||||
|
|
||||||
wd->texture.texture = texture;
|
|
||||||
wd->texture.width = w->widthb;
|
|
||||||
wd->texture.height = w->heightb;
|
|
||||||
return wd;
|
return wd;
|
||||||
err:
|
err:
|
||||||
if (wd->pixmap && wd->pixmap != w->id) {
|
|
||||||
xcb_free_pixmap(ps->c, wd->pixmap);
|
|
||||||
}
|
|
||||||
if (wd->glpixmap) {
|
if (wd->glpixmap) {
|
||||||
glXDestroyPixmap(ps->dpy, wd->glpixmap);
|
glXDestroyPixmap(gd->display, wd->glpixmap);
|
||||||
|
}
|
||||||
|
if (owned) {
|
||||||
|
xcb_free_pixmap(base->c, pixmap);
|
||||||
}
|
}
|
||||||
free(wd);
|
free(wd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void glx_present(backend_t *base) {
|
||||||
* Bind a X pixmap to an OpenGL texture.
|
struct _glx_data *gd = (void *)base;
|
||||||
*/
|
glXSwapBuffers(gd->display, gd->target_win);
|
||||||
void glx_render_win(void *backend_data, session_t *ps, win *w, void *win_data,
|
|
||||||
const region_t *reg_paint) {
|
|
||||||
struct _glx_data *gd = backend_data;
|
|
||||||
struct _glx_win_data *wd = win_data;
|
|
||||||
|
|
||||||
assert(wd->pixmap);
|
|
||||||
assert(wd->glpixmap);
|
|
||||||
assert(wd->texture.texture);
|
|
||||||
|
|
||||||
glBindTexture(wd->texture.target, wd->texture.texture);
|
|
||||||
gd->glXBindTexImage(ps->dpy, wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
|
|
||||||
glBindTexture(wd->texture.target, 0);
|
|
||||||
|
|
||||||
gl_check_err();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void glx_present(void *backend_data, session_t *ps) {
|
static int glx_buffer_age(backend_t *base) {
|
||||||
glXSwapBuffers(ps->dpy, ps->overlay != XCB_NONE ? ps->overlay : ps->root);
|
if (!glxext.has_GLX_EXT_buffer_age) {
|
||||||
}
|
|
||||||
|
|
||||||
int glx_buffer_age(void *backend_data, session_t *ps) {
|
|
||||||
if (ps->o.glx_swap_method == SWAPM_BUFFER_AGE) {
|
|
||||||
unsigned int val;
|
|
||||||
glXQueryDrawable(ps->dpy, get_tgt_window(ps), GLX_BACK_BUFFER_AGE_EXT, &val);
|
|
||||||
return (int)val ?: -1;
|
|
||||||
} else {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct _glx_data *gd = (void *)base;
|
||||||
|
unsigned int val;
|
||||||
|
glXQueryDrawable(gd->display, gd->target_win, GLX_BACK_BUFFER_AGE_EXT, &val);
|
||||||
|
return (int)val ?: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void glx_compose(void *backend_data, session_t *ps, win *w, void *win_data,
|
struct backend_operations glx_ops = {
|
||||||
int dst_x, int dst_y, const region_t *region) {
|
.init = glx_init,
|
||||||
struct _glx_data *gd = backend_data;
|
.deinit = glx_deinit,
|
||||||
struct _glx_win_data *wd = win_data;
|
.bind_pixmap = glx_bind_pixmap,
|
||||||
|
.release_image = glx_release_image,
|
||||||
// OpenGL and Xorg uses different coordinate systems.
|
.compose = gl_compose,
|
||||||
// First, We need to flip the y axis of the paint region
|
.image_op = gl_image_op,
|
||||||
region_t region_yflipped;
|
.copy = gl_copy,
|
||||||
pixman_region32_init(®ion_yflipped);
|
.blur = gl_blur,
|
||||||
pixman_region32_copy(®ion_yflipped, (region_t *)region);
|
.is_image_transparent = gl_is_image_transparent,
|
||||||
|
.present = glx_present,
|
||||||
int nrects;
|
.buffer_age = glx_buffer_age,
|
||||||
auto rect = pixman_region32_rectangles(®ion_yflipped, &nrects);
|
.render_shadow = default_backend_render_shadow,
|
||||||
for (int i = 0; i < nrects; i++) {
|
.max_buffer_age = 5, // Why?
|
||||||
auto tmp = rect[i].y1;
|
};
|
||||||
rect[i].y1 = ps->root_height - rect[i].y2;
|
|
||||||
rect[i].y2 = ps->root_height - tmp;
|
|
||||||
}
|
|
||||||
dump_region(®ion_yflipped);
|
|
||||||
|
|
||||||
// Then, we still need to convert the origin of painting.
|
|
||||||
// Note, in GL coordinates, we need to specified the bottom left corner of the
|
|
||||||
// rectangle, while what we get from the arguments are the top left corner.
|
|
||||||
gl_compose(&wd->texture, 0, 0, dst_x, ps->root_height - dst_y - w->heightb, w->widthb,
|
|
||||||
w->heightb, 0, 1, true, false, ®ion_yflipped, &gd->win_shader);
|
|
||||||
pixman_region32_fini(®ion_yflipped);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct backend_operations glx_ops;
|
|
||||||
|
|
||||||
/* backend_info_t glx_backend = { */
|
|
||||||
/* .init = glx_init, */
|
|
||||||
/* .deinit = glx_deinit, */
|
|
||||||
/* .prepare_win = glx_prepare_win, */
|
|
||||||
/* .render_win = glx_render_win, */
|
|
||||||
/* .release_win = glx_release_win, */
|
|
||||||
/* .present = glx_present, */
|
|
||||||
/* .compose = glx_compose, */
|
|
||||||
/* .is_win_transparent = default_is_win_transparent, */
|
|
||||||
/* .is_frame_transparent = default_is_frame_transparent, */
|
|
||||||
/* .buffer_age = glx_buffer_age, */
|
|
||||||
/* .max_buffer_age = 5, // XXX why? */
|
|
||||||
/* }; */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a GLX extension exists.
|
* Check if a GLX extension exists.
|
||||||
|
@ -605,12 +477,13 @@ void glxext_init(Display *dpy, int screen) {
|
||||||
check_ext(GLX_MESA_swap_control);
|
check_ext(GLX_MESA_swap_control);
|
||||||
check_ext(GLX_EXT_swap_control);
|
check_ext(GLX_EXT_swap_control);
|
||||||
check_ext(GLX_EXT_texture_from_pixmap);
|
check_ext(GLX_EXT_texture_from_pixmap);
|
||||||
|
check_ext(GLX_EXT_buffer_age);
|
||||||
#undef check_ext
|
#undef check_ext
|
||||||
|
|
||||||
#define lookup(name) (name = (__typeof__(name))glXGetProcAddress((GLubyte *)#name))
|
#define lookup(name) (name = (__typeof__(name))glXGetProcAddress((GLubyte *)#name))
|
||||||
// Checking if the returned function pointer is NULL is not really necessary,
|
// Checking if the returned function pointer is NULL is not really necessary,
|
||||||
// or maybe not even useful, since glXGetProcAddress might always return something.
|
// or maybe not even useful, since glXGetProcAddress might always return
|
||||||
// We are doing it just for completeness' sake.
|
// something. We are doing it just for completeness' sake.
|
||||||
if (!lookup(glXGetVideoSyncSGI) || !lookup(glXWaitVideoSyncSGI)) {
|
if (!lookup(glXGetVideoSyncSGI) || !lookup(glXWaitVideoSyncSGI)) {
|
||||||
glxext.has_GLX_SGI_video_sync = false;
|
glxext.has_GLX_SGI_video_sync = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
// Older version of glx.h defines function prototypes...
|
// Older version of glx.h defines function prototypes for these extensions...
|
||||||
|
// Rename them to avoid conflicts
|
||||||
#define glXSwapIntervalMESA glXSwapIntervalMESA_
|
#define glXSwapIntervalMESA glXSwapIntervalMESA_
|
||||||
#define glXBindTexImageEXT glXBindTexImageEXT_
|
#define glXBindTexImageEXT glXBindTexImageEXT_
|
||||||
#define glXReleaseTexImageEXT glXReleaseTexImageEXT
|
#define glXReleaseTexImageEXT glXReleaseTexImageEXT
|
||||||
|
@ -51,6 +52,7 @@ struct glxext_info {
|
||||||
bool has_GLX_MESA_swap_control;
|
bool has_GLX_MESA_swap_control;
|
||||||
bool has_GLX_EXT_swap_control;
|
bool has_GLX_EXT_swap_control;
|
||||||
bool has_GLX_EXT_texture_from_pixmap;
|
bool has_GLX_EXT_texture_from_pixmap;
|
||||||
|
bool has_GLX_EXT_buffer_age;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct glxext_info glxext;
|
extern struct glxext_info glxext;
|
||||||
|
|
Loading…
Reference in New Issue