diff options
author | Richard Grenville <pyxlcy@gmail.com> | 2013-03-19 20:58:55 +0800 |
---|---|---|
committer | Richard Grenville <pyxlcy@gmail.com> | 2013-03-19 20:58:55 +0800 |
commit | cdd6a73836cc2c1943cdbceab4328dec96949d51 (patch) | |
tree | 3c76c912830222e532272b84fa73d5bf6fe97428 /opengl.c | |
parent | 69c3579a24635e9504bceabc1c76dfe96342c3b0 (diff) | |
download | tdebase-cdd6a73836cc2c1943cdbceab4328dec96949d51.tar.gz tdebase-cdd6a73836cc2c1943cdbceab4328dec96949d51.zip |
Improvement: --glx-copy-from-front & benchmark mode
- GLX backend: Add --glx-copy-front, which copies all unmodified regions
from front buffer to back buffer instead of redrawing the whole
screen. Unfortunately, probably because glCopyPixels() isn't usually
well-optimized on graphic cards, this option appears very unstable in
its effect: Over 20% boost in performance when only 1/4 of the screen
is modified, but 10% decrease when the whole screen is. Thus, not
enabled by default.
- GLX backend: Add glx_blur_dst(), to prepare for the background blur
feature. It currently is capable to modify background in the desired
way, but the core blur shader is absent. glConvolution2D() seemingly
relies entirely on CPU and has horrifying performance. I've hesitating
about whether I should use ARB assembly language or GLSL for the
shader.
- GLX backend: Invert y-axis GL matrix. It's upside-down previously
because that's what dcompmgr uses. Seemingly a "normal" y-axis is
required for glCopyPixels() to operate correctly.
- GLX backend: Fix some GLX_TEXTURE_RECTANGLE compatibility issues.
Still, not actually tested.
- Add benchmark mode (--benchmark & --benchmark-wid).
- Misc changes.
Diffstat (limited to 'opengl.c')
-rw-r--r-- | opengl.c | 199 |
1 files changed, 158 insertions, 41 deletions
@@ -163,7 +163,7 @@ glx_on_root_change(session_t *ps) { // Initialize matrix, copied from dcompmgr glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glOrtho(0, ps->root_width, ps->root_height, 0, -100.0, 100.0); + glOrtho(0, ps->root_width, 0, ps->root_height, -1000.0, 1000.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } @@ -328,7 +328,6 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, return false; } - const GLenum target = GL_TEXTURE_2D; glx_texture_t *ptex = *pptex; bool need_release = true; @@ -338,6 +337,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, .texture = 0, .glpixmap = 0, .pixmap = 0, + .target = 0, .width = 0, .height = 0, .depth = 0, @@ -350,37 +350,11 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, *pptex = ptex; } - glEnable(target); - // Release pixmap if parameters are inconsistent if (ptex->texture && ptex->pixmap != pixmap) { glx_release_pixmap(ps, ptex); } - // Create texture - if (!ptex->texture) { - need_release = false; - - GLuint texture = 0; - glGenTextures(1, &texture); - 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); - - ptex->texture = texture; - } - if (!ptex->texture) { - printf_errf("(): Failed to allocate texture."); - return false; - } - - glBindTexture(target, ptex->texture); - // Create GLX pixmap if (!ptex->glpixmap) { need_release = false; @@ -409,7 +383,9 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, } // Determine texture target, copied from compiz - GLint tex_tgt = 0; + // The assumption we made here is the target never changes based on any + // pixmap-specific parameters, and this may change in the future + GLenum tex_tgt = 0; if (GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts && ps->glx_has_texture_non_power_of_two) tex_tgt = GLX_TEXTURE_2D_EXT; @@ -435,6 +411,8 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, ptex->glpixmap = glXCreatePixmap(ps->dpy, pcfg->cfg, pixmap, attrs); ptex->pixmap = pixmap; + ptex->target = (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D: + GL_TEXTURE_RECTANGLE); ptex->width = width; ptex->height = height; ptex->depth = depth; @@ -445,6 +423,32 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, return false; } + glEnable(ptex->target); + + // Create texture + if (!ptex->texture) { + need_release = false; + + GLuint texture = 0; + glGenTextures(1, &texture); + glBindTexture(ptex->target, texture); + + glTexParameteri(ptex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(ptex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(ptex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(ptex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(ptex->target, 0); + + ptex->texture = texture; + } + if (!ptex->texture) { + printf_errf("(): Failed to allocate texture."); + return false; + } + + glBindTexture(ptex->target, ptex->texture); + // The specification requires rebinding whenever the content changes... // We can't follow this, too slow. if (need_release) @@ -453,8 +457,8 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, ps->glXBindTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL); // Cleanup - glBindTexture(target, 0); - glDisable(target); + glBindTexture(ptex->target, 0); + glDisable(ptex->target); return true; } @@ -466,9 +470,9 @@ void glx_release_pixmap(session_t *ps, glx_texture_t *ptex) { // Release binding if (ptex->glpixmap && ptex->texture) { - glBindTexture(GL_TEXTURE_2D, ptex->texture); + glBindTexture(ptex->target, ptex->texture); ps->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(ptex->target, 0); } // Free GLX Pixmap @@ -479,6 +483,41 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) { } /** + * Preprocess function before start painting. + */ +void +glx_paint_pre(session_t *ps, XserverRegion *preg) { + ps->glx_z = 0.0; + // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // OpenGL doesn't support partial repaint without GLX_MESA_copy_sub_buffer, + // we currently redraw the whole screen or copy unmodified pixels from + // front buffer with --glx-copy-from-front. + if (!ps->o.glx_copy_from_front || !*preg) { + free_region(ps, preg); + } + else { + { + XserverRegion reg_copy = XFixesCreateRegion(ps->dpy, NULL, 0); + XFixesSubtractRegion(ps->dpy, reg_copy, ps->screen_reg, *preg); + glx_set_clip(ps, reg_copy); + free_region(ps, ®_copy); + } + + { + 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); + } + } + + glx_set_clip(ps, *preg); +} + +/** * Set clipping region on the target window. */ void @@ -524,9 +563,9 @@ glx_set_clip(session_t *ps, XserverRegion reg) { for (int i = 0; i < nrects; ++i) { GLint rx = rects[i].x; - GLint ry = rects[i].y; + GLint ry = ps->root_height - rects[i].y; GLint rxe = rx + rects[i].width; - GLint rye = ry + rects[i].height; + GLint rye = ry - rects[i].height; GLint z = 0; #ifdef DEBUG_GLX @@ -550,6 +589,78 @@ glx_set_clip(session_t *ps, XserverRegion reg) { XFree(rects); } +bool +glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z) { + // Read destination pixels into a texture + GLuint tex_scr = 0; + glGenTextures(1, &tex_scr); + if (!tex_scr) { + printf_errf("(): Failed to allocate texture."); + return false; + } + + GLenum tex_tgt = GL_TEXTURE_RECTANGLE; + if (ps->glx_has_texture_non_power_of_two) + tex_tgt = GL_TEXTURE_2D; + + glEnable(tex_tgt); + glBindTexture(tex_tgt, tex_scr); + glTexParameteri(tex_tgt, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + 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, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + glCopyTexSubImage2D(tex_tgt, 0, 0, 0, dx, ps->root_height - dy - height, width, height); + +#ifdef DEBUG_GLX + printf_dbgf("(): %d, %d, %d, %d\n", dx, ps->root_height - dy - height, width, height); +#endif + + // Paint it back + // TODO: Blur function. We are using color negation for testing now. + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); + glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR); + + glBegin(GL_QUADS); + + { + const GLfloat rx = 0.0; + const GLfloat ry = 1.0; + const GLfloat rxe = 1.0; + const GLfloat rye = 0.0; + const GLint rdx = dx; + const GLint rdy = ps->root_height - dy; + const GLint rdxe = rdx + width; + const GLint rdye = rdy - height; + +#ifdef DEBUG_GLX + printf_dbgf("(): %f, %f, %f, %f -> %d, %d, %d, %d\n", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); +#endif + + glTexCoord2f(rx, ry); + glVertex3f(rdx, rdy, z); + + glTexCoord2f(rxe, ry); + glVertex3f(rdxe, rdy, z); + + glTexCoord2f(rxe, rye); + glVertex3f(rdxe, rdye, z); + + glTexCoord2f(rx, rye); + glVertex3f(rdx, rdye, z); + } + + glEnd(); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBindTexture(tex_tgt, 0); + glDeleteTextures(1, &tex_scr); + glDisable(tex_tgt); + + return true; +} + /** * @brief Render a region with texture data. */ @@ -557,6 +668,8 @@ 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 neg, XserverRegion reg_tgt) { + bool blur_background = false; + if (!ptex || !ptex->texture) { printf_errf("(): Missing texture."); return false; @@ -565,12 +678,15 @@ glx_render(session_t *ps, const glx_texture_t *ptex, // Enable blending if needed if (opacity < 1.0 || GLX_TEXTURE_FORMAT_RGBA_EXT == ps->glx_fbconfigs[ptex->depth]->texture_fmt) { + if (!ps->o.glx_no_stencil && blur_background) + glx_blur_dst(ps, dx, dy, width, height, z - 0.5); + glEnable(GL_BLEND); // Needed for handling opacity of ARGB texture glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - // This is all weird, but X Render is using a strange ARGB format, and + // This is all weird, but X Render is using premulitplied ARGB format, and // we need to use those things to correct it. Thanks to derhass for help. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glColor4f(opacity, opacity, opacity, opacity); @@ -618,8 +734,8 @@ glx_render(session_t *ps, const glx_texture_t *ptex, rects = XFixesFetchRegion(ps->dpy, reg_new, &nrects); } - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, ptex->texture); + glEnable(ptex->target); + glBindTexture(ptex->target, ptex->texture); glBegin(GL_QUADS); @@ -629,9 +745,9 @@ glx_render(session_t *ps, const glx_texture_t *ptex, GLfloat rxe = rx + (double) rects[i].width / ptex->width; GLfloat rye = ry + (double) rects[i].height / ptex->height; GLint rdx = rects[i].x; - GLint rdy = rects[i].y; + GLint rdy = ps->root_height - rects[i].y; GLint rdxe = rdx + rects[i].width; - GLint rdye = rdy + rects[i].height; + GLint rdye = rdy - rects[i].height; // Invert Y if needed, this may not work as expected, though. I don't // have such a FBConfig to test with. @@ -665,11 +781,12 @@ glx_render(session_t *ps, const glx_texture_t *ptex, } // Cleanup - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(ptex->target, 0); glColor4f(0.0f, 0.0f, 0.0f, 0.0f); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glDisable(GL_BLEND); glDisable(GL_COLOR_LOGIC_OP); + glDisable(ptex->target); return true; } |