diff --git a/glamor/Makefile.am b/glamor/Makefile.am index 2d9fdf57c..2453566fc 100644 --- a/glamor/Makefile.am +++ b/glamor/Makefile.am @@ -19,4 +19,5 @@ libglamor_la_SOURCES = \ glamor_fill.c \ glamor_fillspans.c \ glamor_getspans.c \ + glamor_tile.c \ glamor.h diff --git a/glamor/glamor.c b/glamor/glamor.c index 7b81abab2..c3e4eb9f8 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -187,6 +187,7 @@ glamor_init(ScreenPtr screen) screen->GetSpans = glamor_get_spans; glamor_init_solid_shader(screen); + glamor_init_tile_shader(screen); return TRUE; diff --git a/glamor/glamor_core.c b/glamor/glamor_core.c index e4aa95dbc..549a5f313 100644 --- a/glamor/glamor_core.c +++ b/glamor/glamor_core.c @@ -198,15 +198,6 @@ glamor_stipple(PixmapPtr pixmap, PixmapPtr stipple, ErrorF("stubbed out stipple\n"); } -void -glamor_tile(PixmapPtr pixmap, PixmapPtr tile, - int x, int y, int width, int height, - unsigned char alu, unsigned long planemask, - int tile_x, int tile_y) -{ - ErrorF("stubbed out tile\n"); -} - static void glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y, int w, int h, int leftPad, int format, char *bits) diff --git a/glamor/glamor_fill.c b/glamor/glamor_fill.c index 0d87bd037..11d5f9841 100644 --- a/glamor/glamor_fill.c +++ b/glamor/glamor_fill.c @@ -168,3 +168,23 @@ glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height, glUseProgramObjectARB(0); } + +/* Highlight places where we're doing it wrong. */ +void +glamor_solid_fail_region(PixmapPtr pixmap, int x, int y, int width, int height) +{ + unsigned long pixel; + + switch (pixmap->drawable.depth) { + case 24: + case 32: + pixel = 0x00ff00ff; /* our favorite color */ + break; + default: + case 8: + pixel = 0xd0d0d0d0; + break; + } + + glamor_solid(pixmap, x, y, width, height, GXcopy, ~0, pixel); +} diff --git a/glamor/glamor_priv.h b/glamor/glamor_priv.h index 6d08b00c6..9bae8144b 100644 --- a/glamor/glamor_priv.h +++ b/glamor/glamor_priv.h @@ -48,6 +48,9 @@ typedef struct glamor_screen_private { GLint solid_prog; GLint solid_color_uniform_location; glamor_transform_uniforms solid_transform; + + GLint tile_prog; + glamor_transform_uniforms tile_transform; } glamor_screen_private; typedef struct glamor_pixmap_private { @@ -69,6 +72,17 @@ glamor_get_pixmap_private(PixmapPtr pixmap) return dixLookupPrivate(&pixmap->devPrivates, glamor_pixmap_private_key); } +/** + * Returns TRUE if the given planemask covers all the significant bits in the + * pixel values for pDrawable. + */ +static inline Bool +glamor_pm_is_solid(DrawablePtr drawable, unsigned long planemask) +{ + return (planemask & FbFullMask(drawable->depth)) == + FbFullMask(drawable->depth); +} + /* glamor.c */ PixmapPtr glamor_get_drawable_pixmap(DrawablePtr drawable); @@ -79,10 +93,6 @@ void glamor_stipple(PixmapPtr pixmap, PixmapPtr stipple, unsigned char alu, unsigned long planemask, unsigned long fg_pixel, unsigned long bg_pixel, int stipple_x, int stipple_y); -void glamor_tile(PixmapPtr pixmap, PixmapPtr tile, - int x, int y, int width, int height, - unsigned char alu, unsigned long planemask, - int tile_x, int tile_y); GLint glamor_compile_glsl_prog(GLenum type, const char *source); void glamor_link_glsl_prog(GLint prog); void glamor_get_color_4f_from_pixel(PixmapPtr pixmap, unsigned long fg_pixel, @@ -103,6 +113,8 @@ void glamor_fill(DrawablePtr drawable, void glamor_solid(PixmapPtr pixmap, int x, int y, int width, int height, unsigned char alu, unsigned long planemask, unsigned long fg_pixel); +void glamor_solid_fail_region(PixmapPtr pixmap, + int x, int y, int width, int height); /* glamor_fillspans.c */ void glamor_fill_spans(DrawablePtr drawable, @@ -123,4 +135,11 @@ glamor_get_spans(DrawablePtr drawable, int nspans, char *dst_start); +/* glamor_tile.c */ +void glamor_tile(PixmapPtr pixmap, PixmapPtr tile, + int x, int y, int width, int height, + unsigned char alu, unsigned long planemask, + int tile_x, int tile_y); +void glamor_init_tile_shader(ScreenPtr screen); + #endif /* GLAMOR_PRIV_H */ diff --git a/glamor/glamor_tile.c b/glamor/glamor_tile.c new file mode 100644 index 000000000..d47644297 --- /dev/null +++ b/glamor/glamor_tile.c @@ -0,0 +1,151 @@ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "glamor_priv.h" + +/** @file glamor_tile.c + * + * Implements the basic fill-with-a-tile support used by multiple GC ops. + */ + +void +glamor_init_tile_shader(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + const char *tile_vs = + "uniform float x_bias;\n" + "uniform float x_scale;\n" + "uniform float y_bias;\n" + "uniform float y_scale;\n" + "void main()\n" + "{\n" + " gl_Position = vec4((gl_Vertex.x + x_bias) * x_scale,\n" + " (gl_Vertex.y + y_bias) * y_scale,\n" + " 0,\n" + " 1);\n" + " gl_TexCoord[0] = vec4(gl_MultiTexCoord0.xy, 0, 1);\n" + "}\n"; + const char *tile_fs = + "uniform sampler2D sampler;\n" + "void main()\n" + "{\n" + " gl_FragColor = texture2D(sampler, gl_TexCoord[0].xy);\n" + "}\n"; + GLint fs_prog, vs_prog; + GLint sampler_uniform_location; + + if (!GLEW_ARB_fragment_shader) + return; + + glamor_priv->tile_prog = glCreateProgramObjectARB(); + vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER_ARB, tile_vs); + fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER_ARB, tile_fs); + glAttachObjectARB(glamor_priv->tile_prog, vs_prog); + glAttachObjectARB(glamor_priv->tile_prog, fs_prog); + glamor_link_glsl_prog(glamor_priv->tile_prog); + + sampler_uniform_location = + glGetUniformLocationARB(glamor_priv->tile_prog, "sampler"); + glUseProgramObjectARB(glamor_priv->tile_prog); + glUniform1iARB(sampler_uniform_location, 0); + glamor_get_transform_uniform_locations(glamor_priv->tile_prog, + &glamor_priv->tile_transform); +} + +void +glamor_tile(PixmapPtr pixmap, PixmapPtr tile, + int x, int y, int width, int height, + unsigned char alu, unsigned long planemask, + int tile_x, int tile_y) +{ + ScreenPtr screen = pixmap->drawable.pScreen; + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + int x1 = x; + int x2 = x + width; + int y1 = y; + int y2 = y + height; + int tile_x1 = tile_x + tile->screen_x; + int tile_x2 = tile_x + tile->screen_x + width; + int tile_y1 = tile_y + tile->screen_y; + int tile_y2 = tile_y + tile->screen_y + height; + glamor_pixmap_private *tile_priv = glamor_get_pixmap_private(tile); + + if (glamor_priv->tile_prog == 0) { + ErrorF("Tiling unsupported\n"); + goto fail; + } + + if (!glamor_set_destination_pixmap(pixmap)) + goto fail; + if (tile_priv->fb == 0) { + ErrorF("Non-FBO tile pixmap\n"); + goto fail; + } + if (alu != GXcopy) { + ErrorF("tile alu\n"); + goto fail; + } + if (!glamor_pm_is_solid(&pixmap->drawable, planemask)) { + ErrorF("tile pm\n"); + goto fail; + } + + glUseProgramObjectARB(glamor_priv->tile_prog); + glamor_set_transform_for_pixmap(pixmap, &glamor_priv->tile_transform); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tile_priv->tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glEnable(GL_TEXTURE_2D); + + tile_x += tile->screen_x; + tile_y += tile->screen_y; + + glBegin(GL_TRIANGLE_FAN); + glMultiTexCoord2f(0, tile_x1, tile_y1); + glVertex2f(x1, y1); + glMultiTexCoord2f(0, tile_x1, tile_y2); + glVertex2f(x1, y2); + glMultiTexCoord2f(0, tile_x2, tile_y2); + glVertex2f(x2, y2); + glMultiTexCoord2f(0, tile_x2, tile_y1); + glVertex2f(x2, y1); + glEnd(); + + glUseProgramObjectARB(0); + glDisable(GL_TEXTURE_2D); + return; + +fail: + glamor_solid_fail_region(pixmap, x, y, width, height); + return; +}