glamor_transform.c (9674B)
1 /* 2 * Copyright © 2014 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23 #include "glamor_priv.h" 24 #include "glamor_transform.h" 25 26 27 /* 28 * Set up rendering to target the specified drawable, computing an 29 * appropriate transform for the vertex shader to convert 30 * drawable-relative coordinates into pixmap-relative coordinates. If 31 * requested, the offset from pixmap origin coordinates back to window 32 * system coordinates will be returned in *p_off_x, *p_off_y so that 33 * clipping computations can be adjusted as appropriate 34 */ 35 36 Bool 37 glamor_set_destination_drawable(DrawablePtr drawable, 38 int box_index, 39 Bool do_drawable_translate, 40 Bool center_offset, 41 GLint matrix_uniform_location, 42 int *p_off_x, 43 int *p_off_y) 44 { 45 ScreenPtr screen = drawable->pScreen; 46 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 47 PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); 48 glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); 49 int off_x, off_y; 50 BoxPtr box = glamor_pixmap_box_at(pixmap_priv, box_index); 51 int w = box->x2 - box->x1; 52 int h = box->y2 - box->y1; 53 float scale_x = 2.0f / (float) w; 54 float scale_y = 2.0f / (float) h; 55 float center_adjust = 0.0f; 56 glamor_pixmap_fbo *pixmap_fbo; 57 58 pixmap_fbo = glamor_pixmap_fbo_at(pixmap_priv, box_index); 59 if (!pixmap_fbo) 60 return FALSE; 61 62 glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); 63 64 off_x -= box->x1; 65 off_y -= box->y1; 66 67 if (p_off_x) { 68 *p_off_x = off_x; 69 *p_off_y = off_y; 70 } 71 72 /* A tricky computation to find the right value for the two linear functions 73 * that transform rendering coordinates to pixmap coordinates 74 * 75 * pixmap_x = render_x + drawable->x + off_x 76 * pixmap_y = render_y + drawable->y + off_y 77 * 78 * gl_x = pixmap_x * 2 / width - 1 79 * gl_y = pixmap_y * 2 / height - 1 80 * 81 * gl_x = (render_x + drawable->x + off_x) * 2 / width - 1 82 * 83 * gl_x = (render_x) * 2 / width + (drawable->x + off_x) * 2 / width - 1 84 */ 85 86 if (do_drawable_translate) { 87 off_x += drawable->x; 88 off_y += drawable->y; 89 } 90 91 /* 92 * To get GL_POINTS drawn in the right spot, we need to adjust the 93 * coordinates by 1/2 a pixel. 94 */ 95 if (center_offset) 96 center_adjust = 0.5f; 97 98 glUniform4f(matrix_uniform_location, 99 scale_x, (off_x + center_adjust) * scale_x - 1.0f, 100 scale_y, (off_y + center_adjust) * scale_y - 1.0f); 101 102 glamor_set_destination_pixmap_fbo(glamor_priv, pixmap_fbo, 103 0, 0, w, h); 104 105 return TRUE; 106 } 107 108 /* 109 * Set up for solid rendering to the specified pixmap using alu, fg and planemask 110 * from the specified GC. Load the target color into the specified uniform 111 */ 112 113 void 114 glamor_set_color_depth(ScreenPtr pScreen, 115 int depth, 116 CARD32 pixel, 117 GLint uniform) 118 { 119 glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen); 120 float color[4]; 121 122 glamor_get_rgba_from_pixel(pixel, 123 &color[0], &color[1], &color[2], &color[3], 124 glamor_priv->formats[depth].render_format); 125 126 if ((depth <= 8) && glamor_priv->formats[8].format == GL_RED) 127 color[0] = color[3]; 128 129 glUniform4fv(uniform, 1, color); 130 } 131 132 Bool 133 glamor_set_solid(PixmapPtr pixmap, 134 GCPtr gc, 135 Bool use_alu, 136 GLint uniform) 137 { 138 CARD32 pixel; 139 int alu = use_alu ? gc->alu : GXcopy; 140 141 if (!glamor_set_planemask(gc->depth, gc->planemask)) 142 return FALSE; 143 144 pixel = gc->fgPixel; 145 146 if (!glamor_set_alu(pixmap->drawable.pScreen, alu)) { 147 switch (gc->alu) { 148 case GXclear: 149 pixel = 0; 150 break; 151 case GXcopyInverted: 152 pixel = ~pixel; 153 break; 154 case GXset: 155 pixel = ~0 & gc->planemask; 156 break; 157 default: 158 return FALSE; 159 } 160 } 161 glamor_set_color(pixmap, pixel, uniform); 162 163 return TRUE; 164 } 165 166 Bool 167 glamor_set_texture_pixmap(PixmapPtr texture, Bool destination_red) 168 { 169 glamor_pixmap_private *texture_priv; 170 171 texture_priv = glamor_get_pixmap_private(texture); 172 173 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(texture_priv)) 174 return FALSE; 175 176 if (glamor_pixmap_priv_is_large(texture_priv)) 177 return FALSE; 178 179 glamor_bind_texture(glamor_get_screen_private(texture->drawable.pScreen), 180 GL_TEXTURE0, 181 texture_priv->fbo, destination_red); 182 183 /* we're not setting the sampler uniform here as we always use 184 * GL_TEXTURE0, and the default value for uniforms is zero. So, 185 * save a bit of CPU time by taking advantage of that. 186 */ 187 return TRUE; 188 } 189 190 Bool 191 glamor_set_texture(PixmapPtr texture, 192 Bool destination_red, 193 int off_x, 194 int off_y, 195 GLint offset_uniform, 196 GLint size_inv_uniform) 197 { 198 if (!glamor_set_texture_pixmap(texture, destination_red)) 199 return FALSE; 200 201 glUniform2f(offset_uniform, off_x, off_y); 202 glUniform2f(size_inv_uniform, 1.0f/texture->drawable.width, 1.0f/texture->drawable.height); 203 return TRUE; 204 } 205 206 Bool 207 glamor_set_tiled(PixmapPtr pixmap, 208 GCPtr gc, 209 GLint offset_uniform, 210 GLint size_inv_uniform) 211 { 212 if (!glamor_set_alu(pixmap->drawable.pScreen, gc->alu)) 213 return FALSE; 214 215 if (!glamor_set_planemask(gc->depth, gc->planemask)) 216 return FALSE; 217 218 return glamor_set_texture(gc->tile.pixmap, 219 TRUE, 220 -gc->patOrg.x, 221 -gc->patOrg.y, 222 offset_uniform, 223 size_inv_uniform); 224 } 225 226 static PixmapPtr 227 glamor_get_stipple_pixmap(GCPtr gc) 228 { 229 glamor_gc_private *gc_priv = glamor_get_gc_private(gc); 230 ScreenPtr screen = gc->pScreen; 231 PixmapPtr bitmap; 232 PixmapPtr pixmap; 233 GCPtr scratch_gc; 234 ChangeGCVal changes[2]; 235 236 if (gc_priv->stipple) 237 return gc_priv->stipple; 238 239 bitmap = gc->stipple; 240 if (!bitmap) 241 goto bail; 242 243 pixmap = glamor_create_pixmap(screen, 244 bitmap->drawable.width, 245 bitmap->drawable.height, 246 8, GLAMOR_CREATE_NO_LARGE); 247 if (!pixmap) 248 goto bail; 249 250 scratch_gc = GetScratchGC(8, screen); 251 if (!scratch_gc) 252 goto bail_pixmap; 253 254 changes[0].val = 0xff; 255 changes[1].val = 0x00; 256 if (ChangeGC(NullClient, scratch_gc, 257 GCForeground|GCBackground, changes) != Success) 258 goto bail_gc; 259 ValidateGC(&pixmap->drawable, scratch_gc); 260 261 (*scratch_gc->ops->CopyPlane)(&bitmap->drawable, 262 &pixmap->drawable, 263 scratch_gc, 264 0, 0, 265 bitmap->drawable.width, 266 bitmap->drawable.height, 267 0, 0, 0x1); 268 269 FreeScratchGC(scratch_gc); 270 gc_priv->stipple = pixmap; 271 272 glamor_track_stipple(gc); 273 274 return pixmap; 275 276 bail_gc: 277 FreeScratchGC(scratch_gc); 278 bail_pixmap: 279 glamor_destroy_pixmap(pixmap); 280 bail: 281 return NULL; 282 } 283 284 Bool 285 glamor_set_stippled(PixmapPtr pixmap, 286 GCPtr gc, 287 GLint fg_uniform, 288 GLint offset_uniform, 289 GLint size_uniform) 290 { 291 PixmapPtr stipple; 292 293 stipple = glamor_get_stipple_pixmap(gc); 294 if (!stipple) 295 return FALSE; 296 297 if (!glamor_set_solid(pixmap, gc, TRUE, fg_uniform)) 298 return FALSE; 299 300 return glamor_set_texture(stipple, 301 FALSE, 302 -gc->patOrg.x, 303 -gc->patOrg.y, 304 offset_uniform, 305 size_uniform); 306 }