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#include "glamor_transfer.h" 26 27glamor_program fill_spans_progs[4]; 28 29static const glamor_facet glamor_facet_fillspans_130 = { 30 .name = "fill_spans", 31 .version = 130, 32 .vs_vars = "attribute vec3 primitive;\n", 33 .vs_exec = (" vec2 pos = vec2(primitive.z,1) * vec2(gl_VertexID&1, (gl_VertexID&2)>>1);\n" 34 GLAMOR_POS(gl_Position, (primitive.xy + pos))), 35}; 36 37static const glamor_facet glamor_facet_fillspans_120 = { 38 .name = "fill_spans", 39 .vs_vars = "attribute vec2 primitive;\n", 40 .vs_exec = (" vec2 pos = vec2(0,0);\n" 41 GLAMOR_POS(gl_Position, primitive.xy)), 42}; 43 44static Bool 45glamor_fill_spans_gl(DrawablePtr drawable, 46 GCPtr gc, 47 int n, DDXPointPtr points, int *widths, int sorted) 48{ 49 ScreenPtr screen = drawable->pScreen; 50 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 51 PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); 52 glamor_pixmap_private *pixmap_priv; 53 glamor_program *prog; 54 int off_x, off_y; 55 GLshort *v; 56 char *vbo_offset; 57 int c; 58 int box_index; 59 Bool ret = FALSE; 60 61 pixmap_priv = glamor_get_pixmap_private(pixmap); 62 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) 63 goto bail; 64 65 glamor_make_current(glamor_priv); 66 67 if (glamor_glsl_has_ints(glamor_priv)) { 68 prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->fill_spans_program, 69 &glamor_facet_fillspans_130); 70 71 if (!prog) 72 goto bail; 73 74 /* Set up the vertex buffers for the points */ 75 76 v = glamor_get_vbo_space(drawable->pScreen, n * (4 * sizeof (GLshort)), &vbo_offset); 77 78 glEnableVertexAttribArray(GLAMOR_VERTEX_POS); 79 glVertexAttribDivisor(GLAMOR_VERTEX_POS, 1); 80 glVertexAttribPointer(GLAMOR_VERTEX_POS, 3, GL_SHORT, GL_FALSE, 81 4 * sizeof (GLshort), vbo_offset); 82 83 for (c = 0; c < n; c++) { 84 v[0] = points->x; 85 v[1] = points->y; 86 v[2] = *widths++; 87 points++; 88 v += 4; 89 } 90 91 glamor_put_vbo_space(screen); 92 } else { 93 prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->fill_spans_program, 94 &glamor_facet_fillspans_120); 95 96 if (!prog) 97 goto bail; 98 99 /* Set up the vertex buffers for the points */ 100 101 v = glamor_get_vbo_space(drawable->pScreen, n * 8 * sizeof (short), &vbo_offset); 102 103 glEnableVertexAttribArray(GLAMOR_VERTEX_POS); 104 glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE, 105 2 * sizeof (short), vbo_offset); 106 107 for (c = 0; c < n; c++) { 108 v[0] = points->x; v[1] = points->y; 109 v[2] = points->x; v[3] = points->y + 1; 110 v[4] = points->x + *widths; v[5] = points->y + 1; 111 v[6] = points->x + *widths; v[7] = points->y; 112 113 widths++; 114 points++; 115 v += 8; 116 } 117 118 glamor_put_vbo_space(screen); 119 } 120 121 glEnable(GL_SCISSOR_TEST); 122 123 glamor_pixmap_loop(pixmap_priv, box_index) { 124 int nbox = RegionNumRects(gc->pCompositeClip); 125 BoxPtr box = RegionRects(gc->pCompositeClip); 126 127 if (!glamor_set_destination_drawable(drawable, box_index, FALSE, FALSE, 128 prog->matrix_uniform, &off_x, &off_y)) 129 goto bail; 130 131 while (nbox--) { 132 glScissor(box->x1 + off_x, 133 box->y1 + off_y, 134 box->x2 - box->x1, 135 box->y2 - box->y1); 136 box++; 137 if (glamor_glsl_has_ints(glamor_priv)) 138 glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, n); 139 else { 140 glamor_glDrawArrays_GL_QUADS(glamor_priv, n); 141 } 142 } 143 } 144 145 ret = TRUE; 146 147bail: 148 glDisable(GL_SCISSOR_TEST); 149 if (glamor_glsl_has_ints(glamor_priv)) 150 glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0); 151 glDisableVertexAttribArray(GLAMOR_VERTEX_POS); 152 153 return ret; 154} 155 156static void 157glamor_fill_spans_bail(DrawablePtr drawable, 158 GCPtr gc, 159 int n, DDXPointPtr points, int *widths, int sorted) 160{ 161 if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW) && 162 glamor_prepare_access_gc(gc)) { 163 fbFillSpans(drawable, gc, n, points, widths, sorted); 164 } 165 glamor_finish_access_gc(gc); 166 glamor_finish_access(drawable); 167} 168 169void 170glamor_fill_spans(DrawablePtr drawable, 171 GCPtr gc, 172 int n, DDXPointPtr points, int *widths, int sorted) 173{ 174 if (glamor_fill_spans_gl(drawable, gc, n, points, widths, sorted)) 175 return; 176 glamor_fill_spans_bail(drawable, gc, n, points, widths, sorted); 177} 178 179static Bool 180glamor_get_spans_gl(DrawablePtr drawable, int wmax, 181 DDXPointPtr points, int *widths, int count, char *dst) 182{ 183 ScreenPtr screen = drawable->pScreen; 184 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 185 PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); 186 glamor_pixmap_private *pixmap_priv; 187 int box_index; 188 int n; 189 char *d; 190 int off_x, off_y; 191 const struct glamor_format *f = glamor_format_for_pixmap(pixmap); 192 193 pixmap_priv = glamor_get_pixmap_private(pixmap); 194 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) 195 goto bail; 196 197 glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); 198 199 glamor_make_current(glamor_priv); 200 201 glamor_pixmap_loop(pixmap_priv, box_index) { 202 BoxPtr box = glamor_pixmap_box_at(pixmap_priv, box_index); 203 glamor_pixmap_fbo *fbo = glamor_pixmap_fbo_at(pixmap_priv, box_index); 204 205 glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb); 206 glPixelStorei(GL_PACK_ALIGNMENT, 4); 207 208 d = dst; 209 for (n = 0; n < count; n++) { 210 int x1 = points[n].x + off_x; 211 int y = points[n].y + off_y; 212 int w = widths[n]; 213 int x2 = x1 + w; 214 char *l; 215 216 l = d; 217 d += PixmapBytePad(w, drawable->depth); 218 219 /* clip */ 220 if (x1 < box->x1) { 221 l += (box->x1 - x1) * (drawable->bitsPerPixel >> 3); 222 x1 = box->x1; 223 } 224 if (x2 > box->x2) 225 x2 = box->x2; 226 227 if (x1 >= x2) 228 continue; 229 if (y < box->y1) 230 continue; 231 if (y >= box->y2) 232 continue; 233 234 glReadPixels(x1 - box->x1, y - box->y1, x2 - x1, 1, 235 f->format, f->type, l); 236 } 237 } 238 239 return TRUE; 240bail: 241 return FALSE; 242} 243 244static void 245glamor_get_spans_bail(DrawablePtr drawable, int wmax, 246 DDXPointPtr points, int *widths, int count, char *dst) 247{ 248 if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RO)) 249 fbGetSpans(drawable, wmax, points, widths, count, dst); 250 glamor_finish_access(drawable); 251} 252 253void 254glamor_get_spans(DrawablePtr drawable, int wmax, 255 DDXPointPtr points, int *widths, int count, char *dst) 256{ 257 if (glamor_get_spans_gl(drawable, wmax, points, widths, count, dst)) 258 return; 259 glamor_get_spans_bail(drawable, wmax, points, widths, count, dst); 260} 261 262static Bool 263glamor_set_spans_gl(DrawablePtr drawable, GCPtr gc, char *src, 264 DDXPointPtr points, int *widths, int numPoints, int sorted) 265{ 266 ScreenPtr screen = drawable->pScreen; 267 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 268 PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable); 269 glamor_pixmap_private *pixmap_priv; 270 const struct glamor_format *f = glamor_format_for_pixmap(pixmap); 271 int box_index; 272 int n; 273 char *s; 274 int off_x, off_y; 275 276 pixmap_priv = glamor_get_pixmap_private(pixmap); 277 if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv)) 278 goto bail; 279 280 if (gc->alu != GXcopy) 281 goto bail; 282 283 if (!glamor_pm_is_solid(gc->depth, gc->planemask)) 284 goto bail; 285 286 glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y); 287 288 glamor_make_current(glamor_priv); 289 290 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 291 292 glamor_pixmap_loop(pixmap_priv, box_index) { 293 BoxPtr box = glamor_pixmap_box_at(pixmap_priv, box_index); 294 glamor_pixmap_fbo *fbo = glamor_pixmap_fbo_at(pixmap_priv, box_index); 295 296 glamor_bind_texture(glamor_priv, GL_TEXTURE0, fbo, TRUE); 297 298 s = src; 299 for (n = 0; n < numPoints; n++) { 300 301 BoxPtr clip_box = RegionRects(gc->pCompositeClip); 302 int nclip_box = RegionNumRects(gc->pCompositeClip); 303 int w = widths[n]; 304 int y = points[n].y; 305 int x = points[n].x; 306 307 while (nclip_box--) { 308 int x1 = x; 309 int x2 = x + w; 310 int y1 = y; 311 char *l = s; 312 313 /* clip to composite clip */ 314 if (x1 < clip_box->x1) { 315 l += (clip_box->x1 - x1) * (drawable->bitsPerPixel >> 3); 316 x1 = clip_box->x1; 317 } 318 if (x2 > clip_box->x2) 319 x2 = clip_box->x2; 320 321 if (y < clip_box->y1) 322 continue; 323 if (y >= clip_box->y2) 324 continue; 325 326 /* adjust to pixmap coordinates */ 327 x1 += off_x; 328 x2 += off_x; 329 y1 += off_y; 330 331 if (x1 < box->x1) { 332 l += (box->x1 - x1) * (drawable->bitsPerPixel >> 3); 333 x1 = box->x1; 334 } 335 if (x2 > box->x2) 336 x2 = box->x2; 337 338 if (x1 >= x2) 339 continue; 340 if (y1 < box->y1) 341 continue; 342 if (y1 >= box->y2) 343 continue; 344 345 glTexSubImage2D(GL_TEXTURE_2D, 0, 346 x1 - box->x1, y1 - box->y1, x2 - x1, 1, 347 f->format, f->type, 348 l); 349 } 350 s += PixmapBytePad(w, drawable->depth); 351 } 352 } 353 354 return TRUE; 355 356bail: 357 return FALSE; 358} 359 360static void 361glamor_set_spans_bail(DrawablePtr drawable, GCPtr gc, char *src, 362 DDXPointPtr points, int *widths, int numPoints, int sorted) 363{ 364 if (glamor_prepare_access(drawable, GLAMOR_ACCESS_RW) && glamor_prepare_access_gc(gc)) 365 fbSetSpans(drawable, gc, src, points, widths, numPoints, sorted); 366 glamor_finish_access_gc(gc); 367 glamor_finish_access(drawable); 368} 369 370void 371glamor_set_spans(DrawablePtr drawable, GCPtr gc, char *src, 372 DDXPointPtr points, int *widths, int numPoints, int sorted) 373{ 374 if (glamor_set_spans_gl(drawable, gc, src, points, widths, numPoints, sorted)) 375 return; 376 glamor_set_spans_bail(drawable, gc, src, points, widths, numPoints, sorted); 377} 378