summaryrefslogtreecommitdiffstats
path: root/opengl.c
diff options
context:
space:
mode:
Diffstat (limited to 'opengl.c')
-rw-r--r--opengl.c202
1 files changed, 137 insertions, 65 deletions
diff --git a/opengl.c b/opengl.c
index 71017f7bf..d7b411622 100644
--- a/opengl.c
+++ b/opengl.c
@@ -197,23 +197,41 @@ glx_init_blur(session_t *ps) {
{
static const char *FRAG_SHADER_BLUR_PREFIX =
"#version 110\n"
+ "%s"
"uniform float offset_x;\n"
"uniform float offset_y;\n"
"uniform float factor_center;\n"
- "uniform sampler2D tex_scr;\n"
+ "uniform %s tex_scr;\n"
"\n"
"void main() {\n"
" vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);\n";
static const char *FRAG_SHADER_BLUR_ADD =
- " sum += float(%.7g) * texture2D(tex_scr, vec2(gl_TexCoord[0].x + offset_x * float(%d), gl_TexCoord[0].y + offset_y * float(%d)));\n";
+ " sum += float(%.7g) * %s(tex_scr, vec2(gl_TexCoord[0].x + offset_x * float(%d), gl_TexCoord[0].y + offset_y * float(%d)));\n";
+ static const char *FRAG_SHADER_BLUR_ADD_GPUSHADER4 =
+ " sum += float(%.7g) * %sOffset(tex_scr, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y), ivec2(%d, %d));\n";
static const char *FRAG_SHADER_BLUR_SUFFIX =
- " sum += texture2D(tex_scr, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y)) * factor_center;\n"
+ " sum += %s(tex_scr, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y)) * factor_center;\n"
" gl_FragColor = sum / (factor_center + float(%.7g));\n"
"}\n";
- int wid = XFixedToDouble(ps->o.blur_kern[0]), hei = XFixedToDouble(ps->o.blur_kern[1]);
+
+ const bool use_texture_rect = !ps->glx_has_texture_non_power_of_two;
+ const char *sampler_type = (use_texture_rect ?
+ "sampler2DRect": "sampler2D");
+ const char *texture_func = (use_texture_rect ?
+ "texture2DRect": "texture2D");
+ const char *shader_add = FRAG_SHADER_BLUR_ADD;
+ char *extension = mstrcpy("");
+ if (use_texture_rect)
+ mstrextend(&extension, "#extension GL_ARB_texture_rectangle : require\n");
+ if (ps->o.glx_use_gpushader4) {
+ mstrextend(&extension, "#extension GL_EXT_gpu_shader4 : require\n");
+ shader_add = FRAG_SHADER_BLUR_ADD_GPUSHADER4;
+ }
+
+ int wid = XFixedToDouble(ps->o.blur_kern[0]),
+ hei = XFixedToDouble(ps->o.blur_kern[1]);
int nele = wid * hei - 1;
- int len = strlen(FRAG_SHADER_BLUR_PREFIX) + (strlen(FRAG_SHADER_BLUR_ADD) + 42) * nele
- + strlen(FRAG_SHADER_BLUR_SUFFIX) + 12 + 1;
+ int len = strlen(FRAG_SHADER_BLUR_PREFIX) + strlen(sampler_type) + strlen(extension) + (strlen(shader_add) + strlen(texture_func) + 42) * nele + strlen(FRAG_SHADER_BLUR_SUFFIX) + strlen(texture_func) + 12 + 1;
char *shader_str = calloc(len, sizeof(char));
if (!shader_str) {
printf_errf("(): Failed to allocate %d bytes for shader string.", len);
@@ -221,8 +239,8 @@ glx_init_blur(session_t *ps) {
}
{
char *pc = shader_str;
- strcpy(pc, FRAG_SHADER_BLUR_PREFIX);
- pc += strlen(FRAG_SHADER_BLUR_PREFIX);
+ sprintf(pc, FRAG_SHADER_BLUR_PREFIX, extension, sampler_type);
+ pc += strlen(pc);
assert(strlen(shader_str) < len);
double sum = 0.0;
@@ -232,13 +250,13 @@ glx_init_blur(session_t *ps) {
continue;
double val = XFixedToDouble(ps->o.blur_kern[2 + i * wid + j]);
sum += val;
- sprintf(pc, FRAG_SHADER_BLUR_ADD, val, j - wid / 2, i - hei / 2);
+ sprintf(pc, shader_add, val, texture_func, j - wid / 2, i - hei / 2);
pc += strlen(pc);
assert(strlen(shader_str) < len);
}
}
- sprintf(pc, FRAG_SHADER_BLUR_SUFFIX, sum);
+ sprintf(pc, FRAG_SHADER_BLUR_SUFFIX, texture_func, sum);
assert(strlen(shader_str) < len);
#ifdef DEBUG_GLX_GLSL
fputs(shader_str, stdout);
@@ -246,6 +264,7 @@ glx_init_blur(session_t *ps) {
#endif
}
ps->glx_frag_shader_blur = glx_create_shader(GL_FRAGMENT_SHADER, shader_str);
+ free(extension);
free(shader_str);
}
@@ -268,8 +287,10 @@ glx_init_blur(session_t *ps) {
}
P_GET_UNIFM_LOC("factor_center", glx_prog_blur_unifm_factor_center);
- P_GET_UNIFM_LOC("offset_x", glx_prog_blur_unifm_offset_x);
- P_GET_UNIFM_LOC("offset_y", glx_prog_blur_unifm_offset_y);
+ if (!ps->o.glx_use_gpushader4) {
+ P_GET_UNIFM_LOC("offset_x", glx_prog_blur_unifm_offset_x);
+ P_GET_UNIFM_LOC("offset_y", glx_prog_blur_unifm_offset_y);
+ }
#undef P_GET_UNIFM_LOC
@@ -593,24 +614,8 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) {
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Get buffer age
- int buffer_age = ps->o.glx_swap_method;
bool trace_damage = (ps->o.glx_swap_method < 0 || ps->o.glx_swap_method > 1);
- // Query GLX_EXT_buffer_age for buffer age
- if (SWAPM_BUFFER_AGE == buffer_age) {
- unsigned val = 0;
- glXQueryDrawable(ps->dpy, get_tgt_window(ps),
- GLX_BACK_BUFFER_AGE_EXT, &val);
- buffer_age = val;
- }
-
- // Buffer age too high
- if (buffer_age > CGLX_MAX_BUFFER_AGE + 1)
- buffer_age = 0;
-
- // Make sure buffer age >= 0
- buffer_age = max_i(buffer_age, 0);
-
// Trace raw damage regions
XserverRegion newdamage = None;
if (trace_damage && *preg)
@@ -619,37 +624,89 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) {
// OpenGL doesn't support partial repaint without GLX_MESA_copy_sub_buffer,
// we could redraw the whole screen or copy unmodified pixels from
// front buffer with --glx-copy-from-front.
- if (ps->o.glx_use_copysubbuffermesa || 1 == buffer_age || !*preg) {
- }
- else if (buffer_age > 1) {
- for (int i = 0; i < buffer_age - 1; ++i) {
- XserverRegion dmg = ps->all_damage_last[i];
- if (!dmg) {
- free_region(ps, preg);
- break;
- }
- XFixesUnionRegion(ps->dpy, *preg, *preg, dmg);
- }
- }
- else if (!ps->o.glx_copy_from_front) {
- free_region(ps, preg);
+ if (ps->o.glx_use_copysubbuffermesa || !*preg) {
}
else {
+ int buffer_age = ps->o.glx_swap_method;
+
+ // Getting buffer age
{
- XserverRegion reg_copy = XFixesCreateRegion(ps->dpy, NULL, 0);
- XFixesSubtractRegion(ps->dpy, reg_copy, ps->screen_reg, *preg);
- glx_set_clip(ps, reg_copy, NULL);
- free_region(ps, &reg_copy);
+ // Query GLX_EXT_buffer_age for buffer age
+ if (SWAPM_BUFFER_AGE == buffer_age) {
+ unsigned val = 0;
+ glXQueryDrawable(ps->dpy, get_tgt_window(ps),
+ GLX_BACK_BUFFER_AGE_EXT, &val);
+ buffer_age = val;
+ }
+
+ // Buffer age too high
+ if (buffer_age > CGLX_MAX_BUFFER_AGE + 1)
+ buffer_age = 0;
+
+ // Make sure buffer age >= 0
+ buffer_age = max_i(buffer_age, 0);
+
+ // Check if we have we have empty regions
+ if (buffer_age > 1) {
+ for (int i = 0; i < buffer_age - 1; ++i)
+ if (!ps->all_damage_last[i]) { buffer_age = 0; break; }
+ }
}
- {
- GLfloat raster_pos[4];
- glGetFloatv(GL_CURRENT_RASTER_POSITION, raster_pos);
- glReadBuffer(GL_FRONT);
- glRasterPos2f(0.0, 0.0);
- glCopyPixels(0, 0, ps->root_width, ps->root_height, GL_COLOR);
- glReadBuffer(GL_BACK);
- glRasterPos4fv(raster_pos);
+ // Do nothing for buffer_age 1 (copy)
+ if (1 != buffer_age) {
+ // Copy pixels
+ if (ps->o.glx_copy_from_front) {
+ // Determine copy area
+ XserverRegion reg_copy = XFixesCreateRegion(ps->dpy, NULL, 0);
+ if (!buffer_age) {
+ XFixesSubtractRegion(ps->dpy, reg_copy, ps->screen_reg, *preg);
+ }
+ else {
+ for (int i = 0; i < buffer_age - 1; ++i)
+ XFixesUnionRegion(ps->dpy, reg_copy, reg_copy,
+ ps->all_damage_last[i]);
+ XFixesSubtractRegion(ps->dpy, reg_copy, reg_copy, *preg);
+ }
+
+ // Actually copy pixels
+ {
+ GLfloat raster_pos[4];
+ GLfloat curx = 0.0f, cury = 0.0f;
+ glGetFloatv(GL_CURRENT_RASTER_POSITION, raster_pos);
+ glReadBuffer(GL_FRONT);
+ glRasterPos2f(0.0, 0.0);
+ {
+ int nrects = 0;
+ XRectangle *rects = XFixesFetchRegion(ps->dpy, reg_copy, &nrects);
+ for (int i = 0; i < nrects; ++i) {
+ const int x = rects[i].x;
+ const int y = ps->root_height - rects[i].y - rects[i].height;
+ // Kwin patch says glRasterPos2f() causes artifacts on bottom
+ // screen edge with some drivers
+ glBitmap(0, 0, 0, 0, x - curx, y - cury, NULL);
+ curx = x;
+ cury = y;
+ glCopyPixels(x, y, rects[i].width, rects[i].height, GL_COLOR);
+ }
+ cxfree(rects);
+ }
+ glReadBuffer(GL_BACK);
+ glRasterPos4fv(raster_pos);
+ }
+
+ free_region(ps, &reg_copy);
+ }
+
+ // Determine paint area
+ if (ps->o.glx_copy_from_front) { }
+ else if (buffer_age) {
+ for (int i = 0; i < buffer_age - 1; ++i)
+ XFixesUnionRegion(ps->dpy, *preg, *preg, ps->all_damage_last[i]);
+ }
+ else {
+ free_region(ps, preg);
+ }
}
}
@@ -819,13 +876,20 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
glTexParameteri(tex_tgt, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(tex_tgt, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(tex_tgt, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexImage2D(tex_tgt, 0, GL_RGB, mwidth, mheight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(tex_tgt, 0, GL_RGB, mwidth, mheight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glCopyTexSubImage2D(tex_tgt, 0, 0, 0, mdx, ps->root_height - mdy - mheight, mwidth, mheight);
#ifdef DEBUG_GLX
printf_dbgf("(): %d, %d, %d, %d\n", mdx, ps->root_height - mdy - mheight, mwidth, mheight);
#endif
+ // Texture scaling factor
+ GLfloat texfac_x = 1.0f, texfac_y = 1.0f;
+ if (GL_TEXTURE_2D == tex_tgt) {
+ texfac_x /= mwidth;
+ texfac_y /= mheight;
+ }
+
// Paint it back
// Color negation for testing...
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
@@ -836,9 +900,9 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
#ifdef CONFIG_VSYNC_OPENGL_GLSL
glUseProgram(ps->glx_prog_blur);
if (ps->glx_prog_blur_unifm_offset_x >= 0)
- glUniform1f(ps->glx_prog_blur_unifm_offset_x, 1.0f / mwidth);
+ glUniform1f(ps->glx_prog_blur_unifm_offset_x, texfac_x);
if (ps->glx_prog_blur_unifm_offset_y >= 0)
- glUniform1f(ps->glx_prog_blur_unifm_offset_y, 1.0f / mheight);
+ glUniform1f(ps->glx_prog_blur_unifm_offset_y, texfac_y);
if (ps->glx_prog_blur_unifm_factor_center >= 0)
glUniform1f(ps->glx_prog_blur_unifm_factor_center, factor_center);
#endif
@@ -846,10 +910,10 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
{
P_PAINTREG_START();
{
- const GLfloat rx = (double) (crect.x - mdx) / mwidth;
- const GLfloat ry = 1.0 - (double) (crect.y - mdy) / mheight;
- const GLfloat rxe = rx + (double) crect.width / mwidth;
- const GLfloat rye = ry - (double) crect.height / mheight;
+ const GLfloat rx = (crect.x - mdx) * texfac_x;
+ const GLfloat ry = (mheight - (crect.y - mdy)) * texfac_y;
+ const GLfloat rxe = rx + crect.width * texfac_x;
+ const GLfloat rye = ry - crect.height * texfac_y;
const GLfloat rdx = crect.x;
const GLfloat rdy = ps->root_height - crect.y;
const GLfloat rdxe = rdx + crect.width;
@@ -1049,10 +1113,18 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
{
P_PAINTREG_START();
{
- GLfloat rx = (double) (crect.x - dx + x) / ptex->width;
- GLfloat ry = (double) (crect.y - dy + y) / ptex->height;
- GLfloat rxe = rx + (double) crect.width / ptex->width;
- GLfloat rye = ry + (double) crect.height / ptex->height;
+ GLfloat rx = (double) (crect.x - dx + x);
+ GLfloat ry = (double) (crect.y - dy + y);
+ GLfloat rxe = rx + (double) crect.width;
+ GLfloat rye = ry + (double) crect.height;
+ // Rectangle textures have [0-w] [0-h] while 2D texture has [0-1] [0-1]
+ // Thanks to amonakov for pointing out!
+ if (GL_TEXTURE_2D == ptex->target) {
+ rx = rx / ptex->width;
+ ry = ry / ptex->height;
+ rxe = rxe / ptex->width;
+ rye = rye / ptex->height;
+ }
GLint rdx = crect.x;
GLint rdy = ps->root_height - crect.y;
GLint rdxe = rdx + crect.width;