1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2009 Intel Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it either under the terms of the GNU Lesser General Public
7  * License version 2.1 as published by the Free Software Foundation
8  * (the "LGPL") or, at your option, under the terms of the Mozilla
9  * Public License Version 1.1 (the "MPL"). If you do not alter this
10  * notice, a recipient may use your version of this file under either
11  * the MPL or the LGPL.
12  *
13  * You should have received a copy of the LGPL along with this library
14  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16  * You should have received a copy of the MPL along with this library
17  * in the file COPYING-MPL-1.1
18  *
19  * The contents of this file are subject to the Mozilla Public License
20  * Version 1.1 (the "License"); you may not use this file except in
21  * compliance with the License. You may obtain a copy of the License at
22  * http://www.mozilla.org/MPL/
23  *
24  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26  * the specific language governing rights and limitations.
27  *
28  * The Original Code is the cairo graphics library.
29  *
30  * Contributor(s):
31  *	Chris Wilson <chris@chris-wilson.co.uk>
32  */
33 
34 #include "cairoint.h"
35 
36 #include "cairo-error-private.h"
37 #include "cairo-drm-i915-private.h"
38 #include "cairo-surface-offset-private.h"
39 #include "cairo-surface-subsurface-private.h"
40 #include "cairo-surface-snapshot-private.h"
41 #include "cairo-image-surface-private.h"
42 
43 #if 0
44 static cairo_status_t
45 i915_packed_pixel_surface_finish (void *abstract_surface)
46 {
47     i915_packed_pixel_surface_t *surface = abstract_surface;
48     i915_device_t *device;
49 
50     device = i915_device_acquire (&surface->device->intel.base);
51 
52     intel_bo_destroy (&device->intel, surface->bo);
53 
54     if (surface->is_current_texture) {
55 	if (surface->is_current_texture & CURRENT_SOURCE)
56 	    device->current_source = NULL;
57 	if (surface->is_current_texture & CURRENT_MASK)
58 	    device->current_mask = NULL;
59 	device->current_n_samplers = 0;
60     }
61 
62     i915_device_release (device);
63 
64     return CAIRO_STATUS_SUCCESS;
65 }
66 
67 static const cairo_surface_backend_t i915_packed_pixel_surface_backend = {
68     I915_PACKED_PIXEL_SURFACE_TYPE,
69     i915_packed_pixel_surface_finish,
70 };
71 
72 static cairo_surface_t *
73 i915_packed_pixel_surface_create (i915_device_t *device,
74 				   i915_packed_pixel_t pixel,
75 				   const uint8_t *data,
76 				   uint32_t length,
77 				   uint32_t width, uint32_t height)
78 {
79     i915_packed_pixel_surface_t *surface;
80     cairo_content_t content;
81     uint32_t tiling, size;
82     uint32_t stride, half_stride;
83     uint32_t i;
84 
85     if (width > 2048 || height > 2048)
86 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
87 
88     surface = _cairo_malloc (sizeof (i915_packed_pixel_surface_t));
89     if (unlikely (surface == NULL))
90 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
91 
92     tiling = I915_TILING_NONE; /* XXX */
93     half_stride = stride = i915_tiling_stride (tiling, width/2);
94     if (stride < width)
95 	stride *= 2 ;
96     height = i915_tiling_height (tiling, height);
97 
98     switch (surface->pixel = pixel) {
99     case YUV_I420:
100 	content = CAIRO_CONTENT_COLOR;
101 
102 	surface->offset[0] = 0;
103 	surface->width[0] = width;
104 	surface->height[0] = height;
105 	surface->stride[0] = stride;
106 	surface->map0[0] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
107 	surface->map0[0] |= ((height - 1) << MS3_HEIGHT_SHIFT) |
108 			    ((width - 1)  << MS3_WIDTH_SHIFT);
109 	surface->map1[0] = (stride / 4 - 1) << MS4_PITCH_SHIFT;
110 
111 	surface->offset[1] = stride * height;
112 	surface->width[1] = width / 2;
113 	surface->height[1] = height / 2;
114 	surface->stride[1] = half_stride;
115 	surface->map0[1] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
116 	surface->map0[1] |= ((height/2 - 1) << MS3_HEIGHT_SHIFT) |
117 			    ((width/2 - 1)  << MS3_WIDTH_SHIFT);
118 	surface->map1[1] = (half_stride / 4 - 1) << MS4_PITCH_SHIFT;
119 
120 	if (width < half_stride) {
121 	    surface->offset[2] = stride * height + half_stride / 2;
122 	    size = stride * height + half_stride * height / 2;
123 	} else {
124 	    surface->offset[2] = stride * height + half_stride * height / 2;
125 	    size = stride * height + half_stride * height;
126 	}
127 	surface->width[2] = width / 2;
128 	surface->height[2] = height / 2;
129 	surface->stride[2] = half_stride;
130 	surface->map0[2] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
131 	surface->map0[2] |= ((height/2 - 1) << MS3_HEIGHT_SHIFT) |
132 			    ((width/2 - 1)  << MS3_WIDTH_SHIFT);
133 	surface->map1[2] = (half_stride / 4 - 1) << MS4_PITCH_SHIFT;
134 	break;
135 
136     case NONE:
137     case YUV_YV12:
138     case YUV_YUY2:
139     case YUV_UYVY:
140 	ASSERT_NOT_REACHED;
141 	break;
142     }
143 
144     _cairo_surface_init (&surface->base,
145 	                 &i915_packed_pixel_surface_backend,
146 			 content);
147 
148     surface->bo = intel_bo_create (&device->intel, size, FALSE);
149     assert (surface->bo->tiling == I915_TILING_NONE);
150     if (unlikely (surface->bo == NULL)) {
151 	free (surface);
152 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
153     }
154 
155     if (tiling == I915_TILING_NONE) {
156 	intel_bo_t *bo = surface->bo;
157 	uint32_t dst;
158 	int uv;
159 
160 	dst = surface->offset[0];
161 	if (width == stride) {
162 	    size = stride * height;
163 	    intel_bo_write (&device->intel, bo, dst, size, data);
164 	    data += size;
165 	} else {
166 	    for (i = 0; i < height; i++) {
167 		intel_bo_write (&device->intel, bo, dst, width, data);
168 		dst += stride;
169 		data += width;
170 	    }
171 	}
172 
173 	for (uv = 1; uv <= 2; uv++) {
174 	    dst = surface->offset[uv];
175 	    if (width / 2 == half_stride) {
176 		size = half_stride * height / 2;
177 		intel_bo_write (&device->intel, bo, dst, size, data);
178 		data += size;
179 	    } else {
180 		size = width / 2;
181 		for (i = 0; i < height / 2; i++) {
182 		    intel_bo_write (&device->intel, bo, dst, size, data);
183 		    dst += half_stride;
184 		    data += size;
185 		}
186 	    }
187 	}
188     } else {
189 	uint8_t *dst, *base;
190 
191 	base = intel_bo_map (&device->intel, surface->bo);
192 
193 	dst = base + surface->offset[0];
194 	if (width == stride) {
195 	    size = stride * height;
196 	    memcpy (dst, data, size);
197 	    data += size;
198 	} else {
199 	    for (i = 0; i < height; i++) {
200 		memcpy (dst, data, width);
201 		dst += stride;
202 		data += width;
203 	    }
204 	}
205 
206 	dst = base + surface->offset[1];
207 	if (width / 2 == half_stride) {
208 	    size = half_stride * height / 2;
209 	    memcpy (dst, data, size);
210 	    data += size;
211 	} else {
212 	    size = width / 2;
213 	    for (i = 0; i < height / 2; i++) {
214 		memcpy (dst, data, size);
215 		dst += half_stride;
216 		data += size;
217 	    }
218 	}
219 
220 	dst = base + surface->offset[2];
221 	if (width / 2 == half_stride) {
222 	    size = half_stride * height / 2;
223 	    memcpy (dst, data, size);
224 	    data += size;
225 	} else {
226 	    size = width / 2;
227 	    for (i = 0; i < height / 2; i++) {
228 		memcpy (dst, data, size);
229 		dst += half_stride;
230 		data += size;
231 	    }
232 	}
233     }
234 
235     surface->device = device;
236     surface->is_current_texture = 0;
237 
238     return &surface->base;
239 }
240 
241 static cairo_int_status_t
242 i915_clone_yuv (i915_surface_t *surface,
243 		 cairo_surface_t *source,
244 		 int width, int height,
245 		 cairo_surface_t **clone_out)
246 {
247     const uint8_t *mime_data = NULL;
248     unsigned int mime_data_length;
249     cairo_surface_t *clone;
250 
251     cairo_surface_get_mime_data (source, "video/x-raw-yuv/i420",
252 				 &mime_data, &mime_data_length);
253     if (mime_data == NULL)
254 	return CAIRO_INT_STATUS_UNSUPPORTED;
255 
256     clone =
257 	i915_packed_pixel_surface_create ((i915_device_t *) surface->base.device,
258 					   YUV_I420,
259 					   mime_data, mime_data_length,
260 					   width, height);
261     if (clone == NULL)
262 	return CAIRO_INT_STATUS_UNSUPPORTED;
263     if (unlikely (clone->status))
264 	return clone->status;
265 
266     *clone_out = clone;
267     return CAIRO_STATUS_SUCCESS;
268 }
269 #endif
270 
271 /* Max instruction count: 4 */
272 static void
i915_shader_linear_color(i915_device_t * device,enum i915_shader_linear_mode mode,int in,int c0,int c1,int out)273 i915_shader_linear_color (i915_device_t *device,
274 			  enum i915_shader_linear_mode mode,
275 			  int in, int c0, int c1, int out)
276 {
277     int tmp = FS_U0;
278 
279     switch (mode) {
280     case LINEAR_TEXTURE:
281 	ASSERT_NOT_REACHED;
282     case LINEAR_NONE:
283 	tmp = in;
284 	break;
285 
286     case LINEAR_REPEAT:
287 	i915_fs_frc (tmp, i915_fs_operand (in, X, X, X, X));
288 	break;
289 #if 0
290     case LINEAR_REFLECT:
291 	/* XXX needs an extra constant: C2 [0.5, 2.0, x, x] */
292 	i915_fs_mul (tmp, in, 0.5);
293 	i915_fs_frc (tmp, i915_fs_operand_reg (tmp));
294 	i915_fs_mul (tmp, tmp, 2.0);
295 	i915_fs_add (tmp, i915_fs_operand_one (),
296 		     i915_fs_operand_reg_negate (tmp));
297 	i915_fs_cmp (tmp,
298 		     i915_fs_operand_reg (tmp),
299 		     i915_fs_operand_reg (tmp),
300 		     i915_fs_operand_reg_negate (tmp));
301 	i915_fs_add (tmp, i915_fs_operand_one (),
302 		     i915_fs_operand_reg_negate (tmp));
303 #endif
304     case LINEAR_PAD:
305 	i915_fs_max (tmp,
306 		     i915_fs_operand_zero (),
307 		     i915_fs_operand (in, X, X, X, X));
308 	i915_fs_min (tmp,
309 		     i915_fs_operand_one (),
310 		     i915_fs_operand_reg (tmp));
311 	break;
312     }
313 
314     /* interpolate */
315     i915_fs_mad (out, 0,
316 		 i915_fs_operand (tmp, NEG_X, NEG_X, NEG_X, NEG_X),
317 		 i915_fs_operand_reg (c0),
318 		 i915_fs_operand_reg (c0));
319     i915_fs_mad (out, 0,
320 		 i915_fs_operand (tmp, X, X, X, X),
321 		 i915_fs_operand_reg (c1),
322 		 i915_fs_operand_reg (out));
323 }
324 
325 static void
i915_shader_radial_init(struct i915_shader_radial * r,const cairo_radial_pattern_t * radial)326 i915_shader_radial_init (struct i915_shader_radial *r,
327 			 const cairo_radial_pattern_t *radial)
328 {
329     double dx, dy, dr, r1;
330 
331     dx = radial->cd2.center.x - radial->cd1.center.x;
332     dy = radial->cd2.center.y - radial->cd1.center.y;
333     dr = radial->cd2.radius   - radial->cd1.radius;
334 
335     r1 = radial->cd1.radius;
336 
337     if (radial->cd2.center.x == radial->cd1.center.x &&
338 	radial->cd2.center.y == radial->cd1.center.y)
339     {
340 	/* XXX dr == 0, meaningless with anything other than PAD */
341 	r->constants[0] = radial->cd1.center.x / dr;
342 	r->constants[1] = radial->cd1.center.y / dr;
343 	r->constants[2] = 1. / dr;
344 	r->constants[3] = -r1 / dr;
345 
346 	r->constants[4] = 0;
347 	r->constants[5] = 0;
348 	r->constants[6] = 0;
349 	r->constants[7] = 0;
350 
351 	r->base.mode = RADIAL_ONE;
352     } else {
353 	r->constants[0] = -radial->cd1.center.x;
354 	r->constants[1] = -radial->cd1.center.y;
355 	r->constants[2] = r1;
356 	r->constants[3] = -4 * (dx*dx + dy*dy - dr*dr);
357 
358 	r->constants[4] = -2 * dx;
359 	r->constants[5] = -2 * dy;
360 	r->constants[6] = -2 * r1 * dr;
361 	r->constants[7] = 1 / (2 * (dx*dx + dy*dy - dr*dr));
362 
363 	r->base.mode = RADIAL_TWO;
364     }
365 
366     r->base.matrix = radial->base.base.matrix;
367 }
368 
369 /* Max instruction count: 10 */
370 static void
i915_shader_radial_coord(i915_device_t * device,enum i915_shader_radial_mode mode,int in,int g0,int g1,int out)371 i915_shader_radial_coord (i915_device_t *device,
372 			  enum i915_shader_radial_mode mode,
373 			  int in, int g0, int g1, int out)
374 {
375     switch (mode) {
376     case RADIAL_ONE:
377 	/*
378 	   pdx = (x - c1x) / dr, pdy = (y - c1y) / dr;
379 	   r² = pdx*pdx + pdy*pdy
380 	   t = r²/sqrt(r²) - r1/dr;
381 	   */
382 	i915_fs_mad (FS_U0, MASK_X | MASK_Y,
383 		     i915_fs_operand (in, X, Y, ZERO, ZERO),
384 		     i915_fs_operand (g0, Z, Z, ZERO, ZERO),
385 		     i915_fs_operand (g0, NEG_X, NEG_Y, ZERO, ZERO));
386 	i915_fs_dp2add (FS_U0, MASK_X,
387 			i915_fs_operand (FS_U0, X, Y, ZERO, ZERO),
388 			i915_fs_operand (FS_U0, X, Y, ZERO, ZERO),
389 			i915_fs_operand_zero ());
390 	i915_fs_rsq (out, MASK_X, i915_fs_operand (FS_U0, X, X, X, X));
391 	i915_fs_mad (out, MASK_X,
392 		     i915_fs_operand (FS_U0, X, ZERO, ZERO, ZERO),
393 		     i915_fs_operand (out, X, ZERO, ZERO, ZERO),
394 		     i915_fs_operand (g0, W, ZERO, ZERO, ZERO));
395 	break;
396 
397     case RADIAL_TWO:
398 	/*
399 	   pdx = x - c1x, pdy = y - c1y;
400 	   A = dx² + dy² - dr²
401 	   B = -2*(pdx*dx + pdy*dy + r1*dr);
402 	   C = pdx² + pdy² - r1²;
403 	   det = B*B - 4*A*C;
404 	   t = (-B + sqrt (det)) / (2 * A)
405 	   */
406 
407 	/* u0.x = pdx, u0.y = pdy, u[0].z = r1; */
408 	i915_fs_add (FS_U0,
409 		     i915_fs_operand (in, X, Y, ZERO, ZERO),
410 		     i915_fs_operand (g0, X, Y, Z, ZERO));
411 	/* u0.x = pdx, u0.y = pdy, u[0].z = r1, u[0].w = B; */
412 	i915_fs_dp3 (FS_U0, MASK_W,
413 		     i915_fs_operand (FS_U0, X, Y, ONE, ZERO),
414 		     i915_fs_operand (g1, X, Y, Z, ZERO));
415 	/* u1.x = pdx² + pdy² - r1²; [C] */
416 	i915_fs_dp3 (FS_U1, MASK_X,
417 		     i915_fs_operand (FS_U0, X, Y, Z, ZERO),
418 		     i915_fs_operand (FS_U0, X, Y, NEG_Z, ZERO));
419 	/* u1.x = C, u1.y = B, u1.z=-4*A; */
420 	i915_fs_mov_masked (FS_U1, MASK_Y, i915_fs_operand (FS_U0, W, W, W, W));
421 	i915_fs_mov_masked (FS_U1, MASK_Z, i915_fs_operand (g0, W, W, W, W));
422 	/* u1.x = B² - 4*A*C */
423 	i915_fs_dp2add (FS_U1, MASK_X,
424 			i915_fs_operand (FS_U1, X, Y, ZERO, ZERO),
425 			i915_fs_operand (FS_U1, Z, Y, ZERO, ZERO),
426 			i915_fs_operand_zero ());
427 	/* out.x = -B + sqrt (B² - 4*A*C),
428 	 * out.y = -B - sqrt (B² - 4*A*C),
429 	 */
430 	i915_fs_rsq (out, MASK_X, i915_fs_operand (FS_U1, X, X, X, X));
431 	i915_fs_mad (out, MASK_X | MASK_Y,
432 		     i915_fs_operand (out, X, X, ZERO, ZERO),
433 		     i915_fs_operand (FS_U1, X, NEG_X, ZERO, ZERO),
434 		     i915_fs_operand (FS_U0, NEG_W, NEG_W, ZERO, ZERO));
435 	/* out.x = (-B + sqrt (B² - 4*A*C)) / (2 * A),
436 	 * out.y = (-B - sqrt (B² - 4*A*C)) / (2 * A)
437 	 */
438 	i915_fs_mul (out,
439 		     i915_fs_operand (out, X, Y, ZERO, ZERO),
440 		     i915_fs_operand (g1, W, W, ZERO, ZERO));
441 	/* if (A > 0)
442 	 *   out = (-B + sqrt (B² - 4*A*C)) / (2 * A),
443 	 * else
444 	 *   out = (-B - sqrt (B² - 4*A*C)) / (2 * A)
445 	 */
446 	i915_fs_cmp (out,
447 		     i915_fs_operand (g1, W, ZERO, ZERO, ZERO),
448 		     i915_fs_operand (out, X, ZERO, ZERO, ZERO),
449 		     i915_fs_operand (out, Y, ZERO, ZERO, ZERO));
450 	break;
451     }
452 }
453 
454 /* Max instruction count: 7 */
455 static inline void
i915_shader_yuv_color(i915_device_t * device,int y,int u,int v,int c0,int c1,int c2,int out)456 i915_shader_yuv_color (i915_device_t *device,
457 		       int y, int u, int v,
458 		       int c0, int c1, int c2,
459 		       int out)
460 {
461     i915_fs_mov_masked (FS_U0, MASK_X, i915_fs_operand_reg (y));
462     i915_fs_mov_masked (FS_U0, MASK_Y, i915_fs_operand_reg (u));
463     i915_fs_mov_masked (FS_U0, MASK_Z, i915_fs_operand_reg (v));
464 
465     i915_fs_add (FS_U0,
466 		 i915_fs_operand_reg (FS_U0),
467 		 i915_fs_operand_reg (c0));
468     i915_fs_dp3 (out, MASK_X,
469 		 i915_fs_operand_reg (FS_U0),
470 		 i915_fs_operand (c1, X, ZERO, Y, ZERO));
471     i915_fs_dp3 (out, MASK_Z,
472 		 i915_fs_operand_reg (FS_U0),
473 		 i915_fs_operand (c1, Z, W, ZERO, ZERO));
474     i915_fs_dp3 (out, MASK_Y,
475 		 i915_fs_operand_reg (FS_U0),
476 		 i915_fs_operand_reg (c2));
477 }
478 
479 static inline uint32_t
i915_shader_channel_key(const union i915_shader_channel * channel)480 i915_shader_channel_key (const union i915_shader_channel *channel)
481 {
482     return (channel->type.fragment & 0x0f) | (channel->base.mode << FS_DETAILS_SHIFT);
483 }
484 
485 static uint32_t
i915_shader_channel_get_num_tex_coords(const union i915_shader_channel * channel)486 i915_shader_channel_get_num_tex_coords (const union i915_shader_channel *channel)
487 {
488     switch (channel->type.fragment) {
489     default:
490     case FS_ZERO:
491     case FS_ONE:
492     case FS_CONSTANT:
493     case FS_PURE:
494     case FS_DIFFUSE:
495 	return 0;
496 
497     case FS_LINEAR:
498     case FS_RADIAL:
499     case FS_TEXTURE:
500     case FS_SPANS:
501     case FS_YUV:
502 	return 1;
503     }
504 }
505 
506 static uint32_t
i915_shader_get_num_tex_coords(const i915_shader_t * shader)507 i915_shader_get_num_tex_coords (const i915_shader_t *shader)
508 {
509     uint32_t num_tex_coords;
510 
511     num_tex_coords = 0;
512 
513     num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->source);
514     num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->mask);
515     num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->clip);
516     num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->dst);
517 
518     return num_tex_coords;
519 }
520 
521 #define i915_fs_operand_impure(reg, channel, pure) \
522     (reg | \
523      (((pure & (1 << 0)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << X_CHANNEL_SHIFT) | \
524      (((pure & (1 << 1)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Y_CHANNEL_SHIFT) | \
525      (((pure & (1 << 2)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Z_CHANNEL_SHIFT) | \
526      (((pure & (1 << 3)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << W_CHANNEL_SHIFT))
527 
528 #define i915_fs_operand_pure(pure) \
529     (FS_R0 | \
530      (((pure & (1 << 0)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << X_CHANNEL_SHIFT) | \
531      (((pure & (1 << 1)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Y_CHANNEL_SHIFT) | \
532      (((pure & (1 << 2)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Z_CHANNEL_SHIFT) | \
533      (((pure & (1 << 3)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << W_CHANNEL_SHIFT))
534 
535 static void
i915_set_shader_program(i915_device_t * device,const i915_shader_t * shader)536 i915_set_shader_program (i915_device_t *device,
537 			 const i915_shader_t *shader)
538 {
539     uint32_t num_tex_coords;
540     uint32_t num_samplers;
541     uint32_t n;
542     uint32_t texture_offset = 0;
543     uint32_t constant_offset = 0;
544     uint32_t sampler_offset = 0;
545     uint32_t source_reg;
546     uint32_t source_pure;
547     uint32_t mask_reg;
548     uint32_t out_reg;
549     uint32_t dest_reg;
550     FS_LOCALS;
551 
552     n = (i915_shader_channel_key (&shader->source) <<  0) |
553 	(i915_shader_channel_key (&shader->mask)   <<  8) |
554 	(i915_shader_channel_key (&shader->clip)   << 16) |
555 	(shader->op << 24) |
556 	((shader->opacity < 1.) << 30) |
557 	(((shader->content & CAIRO_CONTENT_ALPHA) == CAIRO_CONTENT_ALPHA) << 31);
558     if (n == device->current_program)
559 	return;
560     device->current_program = n;
561 
562     FS_BEGIN ();
563 
564     if (shader->source.type.fragment == FS_ZERO) {
565 	if (shader->clip.type.fragment == FS_TEXTURE) {
566 	    /* XXX need_combine */
567 	    assert (shader->mask.type.fragment == (i915_fragment_shader_t) -1);
568 	    i915_fs_dcl (FS_T0);
569 	    i915_fs_texld (FS_U0, FS_S0, FS_T0);
570 	    if ((shader->content & CAIRO_CONTENT_COLOR) == 0)
571 		i915_fs_mov (FS_OC, i915_fs_operand (FS_U0, W, W, W, W));
572 	    else
573 		i915_fs_mov (FS_OC, i915_fs_operand (FS_U0, ZERO, ZERO, ZERO, W));
574 	} else {
575 	    i915_fs_mov (FS_OC, i915_fs_operand_zero ());
576 	}
577 
578 	FS_END ();
579 	return;
580     }
581 
582     num_tex_coords = i915_shader_get_num_tex_coords (shader);
583     for (n = 0; n < num_tex_coords; n++)
584 	i915_fs_dcl (FS_T0 + n);
585 
586     num_samplers =
587 	shader->source.base.n_samplers +
588 	shader->mask.base.n_samplers +
589 	shader->clip.base.n_samplers +
590 	shader->dst.base.n_samplers;
591     for (n = 0; n < num_samplers; n++)
592 	i915_fs_dcl (FS_S0 + n);
593 
594     source_reg = ~0;
595     source_pure = 0;
596     out_reg = FS_R0;
597     if (! shader->need_combine &&
598 	shader->mask.type.fragment == (i915_fragment_shader_t) -1 &&
599 	shader->clip.type.fragment != FS_TEXTURE &&
600 	shader->content != CAIRO_CONTENT_ALPHA)
601     {
602 	out_reg = FS_OC;
603     }
604 
605     switch (shader->source.type.fragment) {
606     default:
607     case FS_ZERO:
608     case FS_SPANS:
609 	ASSERT_NOT_REACHED;
610 
611     case FS_PURE:
612 	source_pure = shader->source.solid.pure;
613     case FS_ONE:
614 	break;
615 
616     case FS_CONSTANT:
617 	source_reg = FS_C0;
618 	constant_offset += 1;
619 	break;
620 
621     case FS_DIFFUSE:
622 	i915_fs_dcl (FS_T8);
623 	source_reg = FS_T8;
624 	break;
625 
626     case FS_LINEAR:
627 	i915_shader_linear_color (device, shader->source.base.mode,
628 				  FS_T0, /* input */
629 				  FS_C0, FS_C1, /* colour ramp */
630 				  FS_U3); /* unpremultiplied output */
631 	/* XXX can we defer premultiplication? */
632 	i915_fs_mul (out_reg,
633 		     i915_fs_operand_reg (FS_U3),
634 		     i915_fs_operand (FS_U3, W, W, W, ONE));
635 
636 	constant_offset += 2;
637 	texture_offset += 1;
638 	source_reg = out_reg;
639 	break;
640 
641     case FS_RADIAL:
642 	i915_shader_radial_coord (device, shader->source.base.mode,
643 				  FS_T0, /* input */
644 				  FS_C0, FS_C1, /* gradient constants */
645 				  FS_R0); /* coordinate */
646 
647 	i915_fs_texld (out_reg, FS_S0, FS_R0);
648 	constant_offset += 2;
649 	texture_offset += 1;
650 	sampler_offset += 1;
651 	source_reg = out_reg;
652 	break;
653 
654     case FS_TEXTURE:
655 	i915_fs_texld (out_reg, FS_S0, FS_T0);
656 	texture_offset += 1;
657 	sampler_offset += 1;
658 	source_reg = out_reg;
659 	break;
660 
661     case FS_YUV:
662 	/* Load samplers to temporaries. */
663 	i915_fs_texld (FS_R0, FS_S0, FS_T0);
664 	i915_fs_texld (FS_R1, FS_S1, FS_T0);
665 	i915_fs_texld (FS_R2, FS_S2, FS_T0);
666 
667 	i915_shader_yuv_color (device,
668 			       FS_R0, FS_R1, FS_R2, /* y, u, v */
669 			       FS_C0, FS_C1, FS_C2, /* coefficients */
670 			       out_reg);
671 
672 	constant_offset += 3;
673 	texture_offset += 1;
674 	sampler_offset += 3;
675 	source_reg = out_reg;
676 	break;
677     }
678 
679     mask_reg = ~0;
680     switch (shader->mask.type.fragment) {
681     case FS_PURE:
682     case FS_ZERO:
683     case FS_YUV:
684     case FS_DIFFUSE:
685 	ASSERT_NOT_REACHED;
686     case FS_ONE:
687     default:
688 	break;
689 
690     case FS_SPANS:
691 	mask_reg = FS_T0 + texture_offset;
692 	texture_offset += 1;
693 	break;
694 
695     case FS_CONSTANT:
696 	mask_reg = FS_C0 + constant_offset;
697 	constant_offset += 1;
698 	break;
699 
700     case FS_LINEAR:
701 	i915_shader_linear_color (device, shader->mask.base.mode,
702 				  FS_T0 + texture_offset, /* input */
703 				  FS_C0 + constant_offset,
704 				  FS_C0 + constant_offset + 1, /* colour ramp */
705 				  FS_R1); /* unpremultiplied output */
706 	constant_offset += 2;
707 	texture_offset += 1;
708 	mask_reg = FS_R1;
709 	break;
710 
711     case FS_RADIAL:
712 	i915_shader_radial_coord (device, shader->mask.base.mode,
713 				  FS_T0 + texture_offset, /* input */
714 				  FS_C0 + constant_offset,
715 				  FS_C0 + constant_offset + 1, /* gradient constants */
716 				  FS_R1); /* coordinate */
717 
718 	i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_R1);
719 	constant_offset += 2;
720 	texture_offset += 1;
721 	sampler_offset += 1;
722 	mask_reg = FS_R1;
723 	break;
724 
725     case FS_TEXTURE:
726 	i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_T0 + texture_offset);
727 	texture_offset += 1;
728 	sampler_offset += 1;
729 	mask_reg = FS_R1;
730 	break;
731     }
732 
733     if (mask_reg != ~0U) {
734 	if (! shader->need_combine &&
735 	    shader->clip.type.fragment != FS_TEXTURE &&
736 	    (shader->content != CAIRO_CONTENT_ALPHA || source_reg == ~0U))
737 	{
738 	    out_reg = FS_OC;
739 	}
740 	if (source_reg == ~0U) {
741 	    if (source_pure) {
742 		if (shader->mask.type.fragment == FS_SPANS) {
743 		    if (out_reg == FS_OC && shader->content == CAIRO_CONTENT_ALPHA) {
744 			if (source_pure & (1 << 3))
745 			    i915_fs_mov (out_reg, i915_fs_operand (mask_reg, X, X, X, X));
746 			else
747 			    i915_fs_mov (out_reg, i915_fs_operand_zero ());
748 		    } else {
749 			i915_fs_mov (out_reg,
750 				     i915_fs_operand_impure (mask_reg, X, source_pure));
751 		    }
752 		} else {
753 		    /* XXX ComponentAlpha
754 		       i915_fs_mov (out_reg,
755 		       i915_fs_operand_pure (mask_reg,
756 		       shader->source.solid.pure));
757 		       */
758 		    if (out_reg == FS_OC && shader->content == CAIRO_CONTENT_ALPHA) {
759 			if (source_pure & (1 << 3))
760 			    i915_fs_mov (out_reg, i915_fs_operand (mask_reg, W, W, W, W));
761 			else
762 			    i915_fs_mov (out_reg, i915_fs_operand_zero ());
763 		    } else {
764 			i915_fs_mov (out_reg,
765 				     i915_fs_operand_impure (mask_reg, W, source_pure));
766 		    }
767 		}
768 		source_reg = out_reg;
769 	    } else if (shader->mask.type.fragment == FS_SPANS) {
770 		i915_fs_mov (out_reg,
771 			     i915_fs_operand (mask_reg, X, X, X, X));
772 		source_reg = out_reg;
773 	    } else {
774 		source_reg = mask_reg;
775 	    }
776 	} else {
777 	    if (shader->mask.type.fragment == FS_SPANS) {
778 		    if (out_reg == FS_OC && shader->content == CAIRO_CONTENT_ALPHA) {
779 			i915_fs_mul (out_reg,
780 				     i915_fs_operand (source_reg, W, W, W, W),
781 				     i915_fs_operand (mask_reg, X, X, X, X));
782 		    } else {
783 			i915_fs_mul (out_reg,
784 				     i915_fs_operand_reg (source_reg),
785 				     i915_fs_operand (mask_reg, X, X, X, X));
786 		    }
787 	    } else {
788 		/* XXX ComponentAlpha
789 		i915_fs_mul (FS_R0,
790 			     i915_fs_operand_reg (source_reg),
791 			     i915_fs_operand_reg (mask_reg));
792 		 */
793 		if (out_reg == FS_OC && shader->content == CAIRO_CONTENT_ALPHA) {
794 		    i915_fs_mul (out_reg,
795 				 i915_fs_operand (source_reg, W, W, W, W),
796 				 i915_fs_operand (mask_reg, W, W, W, W));
797 		} else {
798 		    i915_fs_mul (out_reg,
799 				 i915_fs_operand_reg (source_reg),
800 				 i915_fs_operand (mask_reg, W, W, W, W));
801 		}
802 	    }
803 
804 	    source_reg = out_reg;
805 	}
806     }
807 
808     if (shader->opacity < 1.) {
809 	i915_fs_mul (source_reg,
810 		     i915_fs_operand_reg (source_reg),
811 		     i915_fs_operand_reg (FS_C0 + constant_offset));
812 	constant_offset++;
813     }
814 
815     /* need to preserve order of src, mask, clip, dst */
816     mask_reg = ~0;
817     if (shader->clip.type.fragment == FS_TEXTURE) {
818 	i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_T0 + texture_offset);
819 	texture_offset += 1;
820 	sampler_offset += 1;
821 	mask_reg = FS_R1;
822     }
823 
824     if (shader->need_combine) {
825 	assert (shader->dst.type.fragment == FS_TEXTURE);
826 
827 	i915_fs_texld (FS_R2, FS_S0 + sampler_offset, FS_T0 + texture_offset);
828 	texture_offset += 1;
829 	sampler_offset += 1;
830 	dest_reg = FS_R2;
831 
832 	switch (shader->op) {
833 	case CAIRO_OPERATOR_CLEAR:
834 	case CAIRO_OPERATOR_SOURCE:
835 	    ASSERT_NOT_REACHED;
836 
837 	case CAIRO_OPERATOR_OVER:
838 	    if (source_reg == ~0U) {
839 		/* XXX shader->source.type.fragment == FS_PURE */
840 		dest_reg = FS_OC;
841 	    } else {
842 		i915_fs_add (FS_U0,
843 			     i915_fs_operand (source_reg, NEG_W, NEG_W, NEG_W, NEG_W),
844 			     i915_fs_operand_one ());
845 		i915_fs_mul (FS_U0,
846 			     i915_fs_operand_reg (FS_U0),
847 			     dest_reg);
848 		i915_fs_add (FS_R3,
849 			     i915_fs_operand_reg (source_reg),
850 			     i915_fs_operand_reg (FS_U0));
851 		source_reg = FS_R3;
852 	    }
853 	    break;
854 
855 	case CAIRO_OPERATOR_IN:
856 	    if (source_reg == ~0U) {
857 		/* XXX shader->source.type.fragment == FS_PURE */
858 		source_reg = dest_reg;
859 	    } else {
860 		i915_fs_mul (FS_R3,
861 			     i915_fs_operand_reg (source_reg),
862 			     dest_reg);
863 		source_reg = FS_R3;
864 	    }
865 	    break;
866 
867 	case CAIRO_OPERATOR_OUT:
868 	    if (source_reg == ~0U) {
869 		/* XXX shader->source.type.fragment == FS_PURE */
870 		i915_fs_mov (FS_R3, i915_fs_operand_zero ());
871 		source_reg = FS_R3;
872 	    } else {
873 		i915_fs_add (FS_U0,
874 			     i915_fs_operand (source_reg, NEG_W, NEG_W, NEG_W, NEG_W),
875 			     i915_fs_operand_one ());
876 		i915_fs_mul (FS_R3,
877 			     i915_fs_operand_reg (FS_U0),
878 			     dest_reg);
879 		source_reg = FS_R3;
880 	    }
881 	    break;
882 
883 	case CAIRO_OPERATOR_ATOP:
884 
885 	case CAIRO_OPERATOR_DEST:
886 	case CAIRO_OPERATOR_DEST_OVER:
887 	case CAIRO_OPERATOR_DEST_IN:
888 	case CAIRO_OPERATOR_DEST_OUT:
889 	case CAIRO_OPERATOR_DEST_ATOP:
890 
891 	case CAIRO_OPERATOR_XOR:
892 	case CAIRO_OPERATOR_ADD:
893 	case CAIRO_OPERATOR_SATURATE:
894 
895 	case CAIRO_OPERATOR_MULTIPLY:
896 	case CAIRO_OPERATOR_SCREEN:
897 	case CAIRO_OPERATOR_OVERLAY:
898 	case CAIRO_OPERATOR_DARKEN:
899 	case CAIRO_OPERATOR_LIGHTEN:
900 	case CAIRO_OPERATOR_COLOR_DODGE:
901 	case CAIRO_OPERATOR_COLOR_BURN:
902 	case CAIRO_OPERATOR_HARD_LIGHT:
903 	case CAIRO_OPERATOR_SOFT_LIGHT:
904 	case CAIRO_OPERATOR_DIFFERENCE:
905 	case CAIRO_OPERATOR_EXCLUSION:
906 	case CAIRO_OPERATOR_HSL_HUE:
907 	case CAIRO_OPERATOR_HSL_SATURATION:
908 	case CAIRO_OPERATOR_HSL_COLOR:
909 	case CAIRO_OPERATOR_HSL_LUMINOSITY:
910 	    ASSERT_NOT_REACHED;
911 	    break;
912 	}
913     }
914 
915     if (shader->clip.type.fragment == FS_TEXTURE) {
916 	assert (mask_reg != ~0U);
917 
918 	if (! shader->need_combine) {
919 	    /* (source IN clip) */
920 	    if (source_reg == ~0U) {
921 		if (source_pure == 0) {
922 		    source_reg = mask_reg;
923 		} else {
924 		    out_reg = FS_OC;
925 		    if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
926 			if (source_pure & (1 << 3))
927 			    i915_fs_mov (out_reg, i915_fs_operand (mask_reg, W, W, W, W));
928 			else
929 			    i915_fs_mov (out_reg, i915_fs_operand_zero ());
930 		    } else {
931 			i915_fs_mov (out_reg,
932 				     i915_fs_operand_impure (mask_reg, W, source_pure));
933 		    }
934 		    source_reg = out_reg;
935 		}
936 	    } else if (mask_reg) {
937 		out_reg = FS_OC;
938 		if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
939 		    i915_fs_mul (out_reg,
940 				 i915_fs_operand (source_reg, W, W, W, W),
941 				 i915_fs_operand (mask_reg, W, W, W, W));
942 		} else {
943 		    i915_fs_mul (out_reg,
944 				 i915_fs_operand_reg (source_reg),
945 				 i915_fs_operand (mask_reg, W, W, W, W));
946 		}
947 
948 		source_reg = out_reg;
949 	    }
950 	} else {
951 	    /* (source OP dest) LERP_clip dest */
952 	    if (source_reg == ~0U) {
953 		if (source_pure == 0) {
954 		    i915_fs_mov (FS_R3,
955 				 i915_fs_operand (mask_reg, W, W, W, W));
956 		} else {
957 		    i915_fs_mov (FS_R3,
958 				 i915_fs_operand_impure (mask_reg, W, source_pure));
959 		}
960 	    } else {
961 		i915_fs_mul (FS_R3,
962 			     i915_fs_operand_reg (source_reg),
963 			     i915_fs_operand (mask_reg, W, W, W, W));
964 	    }
965 
966 	    i915_fs_add (mask_reg,
967 			 i915_fs_operand_one (),
968 			 i915_fs_operand (mask_reg, NEG_W, NEG_W, NEG_W, NEG_W));
969 
970 	    if (dest_reg != FS_OC) {
971 		if (dest_reg == ~0U) {
972 		    assert (shader->dst.type.fragment == FS_TEXTURE);
973 
974 		    i915_fs_texld (FS_R2, FS_S0 + sampler_offset, FS_T0 + texture_offset);
975 		    texture_offset += 1;
976 		    sampler_offset += 1;
977 		    dest_reg = FS_R2;
978 		}
979 
980 		i915_fs_mul (FS_U1,
981 			     i915_fs_operand_reg (dest_reg),
982 			     i915_fs_operand_reg (mask_reg));
983 		mask_reg = FS_U1;
984 	    }
985 
986 	    source_reg = FS_OC;
987 	    if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
988 		i915_fs_add (source_reg,
989 			     i915_fs_operand (FS_R3, W, W, W, W),
990 			     i915_fs_operand (mask_reg, W, W, W, W));
991 	    } else {
992 		i915_fs_add (source_reg,
993 			     i915_fs_operand_reg (FS_R3),
994 			     i915_fs_operand_reg (mask_reg));
995 	    }
996 	}
997     }
998 
999     if (source_reg != FS_OC) {
1000 	if (source_reg == ~0U) {
1001 	    if (source_pure) {
1002 		if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
1003 		    if (source_pure & (1 << 3))
1004 			i915_fs_mov (FS_OC, i915_fs_operand_one ());
1005 		    else
1006 			i915_fs_mov (FS_OC, i915_fs_operand_zero ());
1007 		} else
1008 		    i915_fs_mov (FS_OC, i915_fs_operand_pure (source_pure));
1009 	    } else {
1010 		i915_fs_mov (FS_OC, i915_fs_operand_one ());
1011 	    }
1012 	} else if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
1013 	    i915_fs_mov (FS_OC, i915_fs_operand (source_reg, W, W, W, W));
1014 	} else {
1015 	    i915_fs_mov (FS_OC, i915_fs_operand_reg (source_reg));
1016 	}
1017     }
1018 
1019     FS_END ();
1020 }
1021 
1022 static cairo_bool_t
i915_shader_linear_init(struct i915_shader_linear * l,const cairo_linear_pattern_t * linear)1023 i915_shader_linear_init (struct i915_shader_linear *l,
1024 			 const cairo_linear_pattern_t *linear)
1025 {
1026     double x0, y0, sf;
1027     double dx, dy, offset;
1028 
1029     dx = linear->pd2.x - linear->pd1.x;
1030     dy = linear->pd2.y - linear->pd1.y;
1031     sf = dx * dx + dy * dy;
1032     if (sf <= 1e-5)
1033 	return FALSE;
1034 
1035     dx /= sf;
1036     dy /= sf;
1037 
1038     x0 = linear->pd1.x;
1039     y0 = linear->pd1.y;
1040     offset = dx*x0 + dy*y0;
1041 
1042     if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
1043 	l->dx = dx;
1044 	l->dy = dy;
1045 	l->offset = -offset;
1046     } else {
1047 	cairo_matrix_t m;
1048 
1049 	cairo_matrix_init (&m, dx, 0, dy, 0, -offset, 0);
1050 	cairo_matrix_multiply (&m, &linear->base.base.matrix, &m);
1051 	l->dx = m.xx;
1052 	l->dy = m.xy;
1053 	l->offset = m.x0;
1054     }
1055 
1056     return TRUE;
1057 }
1058 
1059 static cairo_bool_t
i915_shader_linear_contains_rectangle(struct i915_shader_linear * l,const cairo_rectangle_int_t * extents)1060 i915_shader_linear_contains_rectangle (struct i915_shader_linear *l,
1061 				       const cairo_rectangle_int_t *extents)
1062 {
1063     double v;
1064 
1065     v = i915_shader_linear_texcoord (l,
1066 				     extents->x,
1067 				     extents->y);
1068     if (v < 0.)
1069 	return FALSE;
1070     if (v > 1.)
1071 	return FALSE;
1072 
1073     v = i915_shader_linear_texcoord (l,
1074 				     extents->x + extents->width,
1075 				     extents->y);
1076     if (v < 0.)
1077 	return FALSE;
1078     if (v > 1.)
1079 	return FALSE;
1080 
1081     v = i915_shader_linear_texcoord (l,
1082 				     extents->x,
1083 				     extents->y + extents->height);
1084     if (v < 0.)
1085 	return FALSE;
1086     if (v > 1.)
1087 	return FALSE;
1088 
1089     v = i915_shader_linear_texcoord (l,
1090 				     extents->x + extents->width,
1091 				     extents->y + extents->height);
1092     if (v < 0.)
1093 	return FALSE;
1094     if (v > 1.)
1095 	return FALSE;
1096 
1097     return TRUE;
1098 }
1099 
1100 #define is_pure(C,mask) (((mask) == 0) || (C) <= 0x00ff || (C) >= 0xff00)
1101 #define is_one(C,mask) (((mask) != 0) && (C) >= 0xff00)
1102 #define is_zero(C,mask) (((mask) != 0) && (C) <= 0x00ff)
1103 
1104 static cairo_status_t
i915_shader_acquire_solid(i915_shader_t * shader,union i915_shader_channel * src,const cairo_solid_pattern_t * solid,const cairo_rectangle_int_t * extents)1105 i915_shader_acquire_solid (i915_shader_t *shader,
1106 			   union i915_shader_channel *src,
1107 			   const cairo_solid_pattern_t *solid,
1108 			   const cairo_rectangle_int_t *extents)
1109 {
1110     cairo_content_t content;
1111 
1112     content = CAIRO_CONTENT_COLOR_ALPHA;
1113     src->solid.color = solid->color;
1114     if (content == 0 || solid->color.alpha_short <= 0x00ff)
1115     {
1116 	src->base.content = CAIRO_CONTENT_ALPHA;
1117 	src->type.fragment = FS_ZERO;
1118     }
1119     else if ((((content & CAIRO_CONTENT_COLOR) == 0)  ||
1120 	      (solid->color.red_short >= 0xff00 &&
1121 	       solid->color.green_short >= 0xff00 &&
1122 	       solid->color.blue_short >= 0xff00)) &&
1123 	     ((content & CAIRO_CONTENT_ALPHA) == 0 ||
1124 	      solid->color.alpha_short >= 0xff00))
1125     {
1126 	src->base.content = CAIRO_CONTENT_ALPHA;
1127 	src->type.fragment = FS_ONE;
1128     }
1129     else if (is_pure (solid->color.red_short, content & CAIRO_CONTENT_COLOR) &&
1130 	     is_pure (solid->color.green_short, content & CAIRO_CONTENT_COLOR) &&
1131 	     is_pure (solid->color.blue_short, content & CAIRO_CONTENT_COLOR) &&
1132 	     is_pure (solid->color.alpha_short, content & CAIRO_CONTENT_ALPHA))
1133     {
1134 	src->solid.pure = 0;
1135 	src->solid.pure |= is_one (solid->color.red_short,   content & CAIRO_CONTENT_COLOR) << 0;
1136 	src->solid.pure |= is_one (solid->color.green_short, content & CAIRO_CONTENT_COLOR) << 1;
1137 	src->solid.pure |= is_one (solid->color.blue_short,  content & CAIRO_CONTENT_COLOR) << 2;
1138 	src->solid.pure |= (! is_zero (solid->color.alpha_short, content & CAIRO_CONTENT_ALPHA)) << 3;
1139 
1140 	if (src->solid.pure == 0) {
1141 	    src->base.content = CAIRO_CONTENT_ALPHA;
1142 	    src->type.fragment = FS_ZERO;
1143 	} else if (src->solid.pure == 0x7) {
1144 	    src->base.content = CAIRO_CONTENT_ALPHA;
1145 	    src->type.fragment = FS_ONE;
1146 	} else {
1147 	    src->base.content = content;
1148 	    src->type.fragment = FS_PURE;
1149 	    src->base.mode = src->solid.pure;
1150 	}
1151     }
1152     else
1153     {
1154 	src->base.content = content;
1155 	src->type.fragment = src == &shader->source ? FS_DIFFUSE : FS_CONSTANT;
1156     }
1157     src->type.vertex = src->type.fragment == FS_ZERO ? VS_ZERO : VS_CONSTANT;
1158     src->type.pattern = PATTERN_CONSTANT;
1159 
1160     return CAIRO_STATUS_SUCCESS;
1161 }
1162 
1163 static cairo_status_t
i915_shader_acquire_linear(i915_shader_t * shader,union i915_shader_channel * src,const cairo_linear_pattern_t * linear,const cairo_rectangle_int_t * extents)1164 i915_shader_acquire_linear (i915_shader_t *shader,
1165 			    union i915_shader_channel *src,
1166 			    const cairo_linear_pattern_t *linear,
1167 			    const cairo_rectangle_int_t *extents)
1168 {
1169     cairo_bool_t mode = LINEAR_TEXTURE;
1170     cairo_status_t status;
1171 
1172     if (i915_shader_linear_init (&src->linear, linear) &&
1173 	linear->base.n_stops == 2 &&
1174 	linear->base.stops[0].offset == 0.0 &&
1175 	linear->base.stops[1].offset == 1.0)
1176     {
1177 	if (i915_shader_linear_contains_rectangle (&src->linear,
1178 						   extents))
1179 	{
1180 	    /* XXX can also lerp if contained within offset range */
1181 	    mode = LINEAR_NONE;
1182 	}
1183 	else switch (linear->base.base.extend) {
1184 	case CAIRO_EXTEND_REPEAT:
1185 	    mode = LINEAR_REPEAT;
1186 	    break;
1187 	case CAIRO_EXTEND_PAD:
1188 	    mode = LINEAR_PAD;
1189 	    break;
1190 	case CAIRO_EXTEND_NONE:
1191 	    break;
1192 	case CAIRO_EXTEND_REFLECT:
1193 	    break;
1194 	default:
1195 	    ASSERT_NOT_REACHED;
1196 	    break;
1197 	}
1198     }
1199 
1200     src->type.vertex = VS_LINEAR;
1201     src->type.pattern = PATTERN_LINEAR;
1202     src->base.texfmt = TEXCOORDFMT_1D;
1203     src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
1204     src->base.mode = mode;
1205     if (mode == LINEAR_TEXTURE) {
1206 	intel_buffer_t buffer;
1207 
1208 	status = intel_gradient_render ((intel_device_t *) shader->target->intel.drm.base.device,
1209 					&linear->base, &buffer);
1210 	if (unlikely (status))
1211 	    return status;
1212 
1213 	src->type.fragment = FS_TEXTURE;
1214 	src->base.bo = intel_bo_reference (buffer.bo);
1215 	src->base.n_samplers = 1;
1216 	src->base.offset[0] = buffer.offset;
1217 	src->base.map[0] = buffer.map0;
1218 	src->base.map[1] = buffer.map1;
1219 	src->base.sampler[0] =
1220 	    (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
1221 	    i915_texture_filter (CAIRO_FILTER_BILINEAR);
1222 	src->base.sampler[1] =
1223 	    SS3_NORMALIZED_COORDS |
1224 	    i915_texture_extend (linear->base.base.extend);
1225     } else {
1226 	src->type.fragment = FS_LINEAR;
1227 	src->linear.color0.red   = linear->base.stops[0].color.red;
1228 	src->linear.color0.green = linear->base.stops[0].color.green;
1229 	src->linear.color0.blue  = linear->base.stops[0].color.blue;
1230 	src->linear.color0.alpha = linear->base.stops[0].color.alpha;
1231 
1232 	src->linear.color1.red   = linear->base.stops[1].color.red;
1233 	src->linear.color1.green = linear->base.stops[1].color.green;
1234 	src->linear.color1.blue  = linear->base.stops[1].color.blue;
1235 	src->linear.color1.alpha = linear->base.stops[1].color.alpha;
1236     }
1237 
1238     return CAIRO_STATUS_SUCCESS;
1239 }
1240 
1241 static cairo_status_t
i915_shader_acquire_radial(i915_shader_t * shader,union i915_shader_channel * src,const cairo_radial_pattern_t * radial,const cairo_rectangle_int_t * extents)1242 i915_shader_acquire_radial (i915_shader_t *shader,
1243 			    union i915_shader_channel *src,
1244 			    const cairo_radial_pattern_t *radial,
1245 			    const cairo_rectangle_int_t *extents)
1246 {
1247     intel_buffer_t buffer;
1248     cairo_status_t status;
1249 
1250     status = intel_gradient_render ((intel_device_t *) shader->target->intel.drm.base.device,
1251 				    &radial->base, &buffer);
1252     if (unlikely (status))
1253 	return status;
1254 
1255     i915_shader_radial_init (&src->radial, radial);
1256 
1257     src->type.vertex = VS_TEXTURE;
1258     src->type.fragment = FS_RADIAL;
1259     src->type.pattern = PATTERN_RADIAL;
1260     src->base.texfmt = TEXCOORDFMT_2D;
1261 
1262     src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
1263     src->base.bo = intel_bo_reference (buffer.bo);
1264     src->base.n_samplers = 1;
1265     src->base.offset[0] = buffer.offset;
1266     src->base.map[0] = buffer.map0;
1267     src->base.map[1] = buffer.map1;
1268     src->base.sampler[0] =
1269 	(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
1270 	i915_texture_filter (CAIRO_FILTER_BILINEAR);
1271     src->base.sampler[1] =
1272 	SS3_NORMALIZED_COORDS |
1273 	i915_texture_extend (radial->base.base.extend);
1274 
1275     return CAIRO_STATUS_SUCCESS;
1276 }
1277 
1278 static cairo_status_t
i915_surface_clone(i915_device_t * device,cairo_image_surface_t * image,i915_surface_t ** clone_out)1279 i915_surface_clone (i915_device_t *device,
1280 		    cairo_image_surface_t *image,
1281 		    i915_surface_t **clone_out)
1282 {
1283     i915_surface_t *clone;
1284     cairo_status_t status;
1285 
1286 #if 0
1287     clone =
1288 	i915_surface_create_from_cacheable_image_internal (device, image);
1289     if (unlikely (clone->intel.drm.base.status))
1290 	return clone->intel.drm.base.status;
1291 #else
1292     cairo_format_t format;
1293 
1294     format = image->format;
1295     if (format == CAIRO_FORMAT_A1)
1296 	format = CAIRO_FORMAT_A8;
1297 
1298     clone = (i915_surface_t *)
1299 	i915_surface_create_internal (&device->intel.base,
1300 				      format,
1301 				      image->width,
1302 				      image->height,
1303 				      I915_TILING_DEFAULT,
1304 				      FALSE);
1305     if (unlikely (clone->intel.drm.base.status))
1306 	return clone->intel.drm.base.status;
1307 
1308     status = intel_bo_put_image (&device->intel,
1309 				 to_intel_bo (clone->intel.drm.bo),
1310 				 image,
1311 				 0, 0,
1312 				 image->width, image->height,
1313 				 0, 0);
1314 
1315     if (unlikely (status))
1316 	return status;
1317 #endif
1318 
1319     *clone_out = clone;
1320     return CAIRO_STATUS_SUCCESS;
1321 }
1322 
1323 static cairo_status_t
i915_surface_clone_subimage(i915_device_t * device,cairo_image_surface_t * image,const cairo_rectangle_int_t * extents,i915_surface_t ** clone_out)1324 i915_surface_clone_subimage (i915_device_t *device,
1325 			     cairo_image_surface_t *image,
1326 			     const cairo_rectangle_int_t *extents,
1327 			     i915_surface_t **clone_out)
1328 {
1329     i915_surface_t *clone;
1330     cairo_status_t status;
1331     cairo_format_t format;
1332 
1333     format = image->format;
1334     if (format == CAIRO_FORMAT_A1)
1335 	format = CAIRO_FORMAT_A8;
1336 
1337     clone = (i915_surface_t *)
1338 	i915_surface_create_internal (&device->intel.base,
1339 				      format,
1340 				      extents->width,
1341 				      extents->height,
1342 				      I915_TILING_NONE,
1343 				      FALSE);
1344     if (unlikely (clone->intel.drm.base.status))
1345 	return clone->intel.drm.base.status;
1346 
1347     status = intel_bo_put_image (&device->intel,
1348 				 to_intel_bo (clone->intel.drm.bo),
1349 				 image,
1350 				 extents->x, extents->y,
1351 				 extents->width, extents->height,
1352 				 0, 0);
1353 
1354     if (unlikely (status))
1355 	return status;
1356 
1357     *clone_out = clone;
1358     return CAIRO_STATUS_SUCCESS;
1359 }
1360 
1361 static cairo_status_t
i915_surface_render_pattern(i915_device_t * device,const cairo_surface_pattern_t * pattern,const cairo_rectangle_int_t * extents,i915_surface_t ** clone_out)1362 i915_surface_render_pattern (i915_device_t *device,
1363 			     const cairo_surface_pattern_t *pattern,
1364 			     const cairo_rectangle_int_t *extents,
1365 			     i915_surface_t **clone_out)
1366 {
1367     i915_surface_t *clone;
1368     cairo_surface_t *image;
1369     cairo_status_t status;
1370     void *ptr;
1371 
1372     clone = (i915_surface_t *)
1373 	i915_surface_create_internal (&device->intel.base,
1374 				      _cairo_format_from_content (pattern->surface->content),
1375 				      extents->width,
1376 				      extents->height,
1377 				      I915_TILING_NONE,
1378 				      FALSE);
1379     if (unlikely (clone->intel.drm.base.status))
1380 	return clone->intel.drm.base.status;
1381 
1382     ptr = intel_bo_map (&device->intel,
1383 			to_intel_bo (clone->intel.drm.bo));
1384     if (unlikely (ptr == NULL)) {
1385 	cairo_surface_destroy (&clone->intel.drm.base);
1386 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1387     }
1388 
1389     image = cairo_image_surface_create_for_data (ptr,
1390 						 clone->intel.drm.format,
1391 						 clone->intel.drm.width,
1392 						 clone->intel.drm.height,
1393 						 clone->intel.drm.stride);
1394     if (unlikely (image->status)) {
1395 	cairo_surface_destroy (&clone->intel.drm.base);
1396 	return image->status;
1397     }
1398 
1399     status = _cairo_surface_offset_paint (image,
1400 					  extents->x, extents->y,
1401 					  CAIRO_OPERATOR_SOURCE,
1402 					  &pattern->base,
1403 					  NULL);
1404     cairo_surface_destroy (image);
1405 
1406     if (unlikely (status)) {
1407 	cairo_surface_destroy (&clone->intel.drm.base);
1408 	return status;
1409     }
1410 
1411     *clone_out = clone;
1412     return CAIRO_STATUS_SUCCESS;
1413 }
1414 
1415 static cairo_status_t
i915_shader_acquire_solid_surface(i915_shader_t * shader,union i915_shader_channel * src,cairo_surface_t * surface,const cairo_rectangle_int_t * extents)1416 i915_shader_acquire_solid_surface (i915_shader_t *shader,
1417 				   union i915_shader_channel *src,
1418 				   cairo_surface_t *surface,
1419 				   const cairo_rectangle_int_t *extents)
1420 {
1421     cairo_surface_pattern_t pattern;
1422     cairo_surface_t *pixel;
1423     cairo_image_surface_t *image;
1424     void *image_extra;
1425     cairo_status_t status;
1426     uint32_t argb;
1427 
1428     status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
1429     if (unlikely (status))
1430 	return status;
1431 
1432     /* extract the pixel as argb32 */
1433     pixel = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
1434     _cairo_pattern_init_for_surface (&pattern, &image->base);
1435     cairo_matrix_init_translate (&pattern.base.matrix, extents->x, extents->y);
1436     pattern.base.filter = CAIRO_FILTER_NEAREST;
1437     status = _cairo_surface_paint (pixel, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL);
1438     _cairo_pattern_fini (&pattern.base);
1439 
1440     _cairo_surface_release_source_image (surface, image, image_extra);
1441 
1442     if (unlikely (status)) {
1443 	cairo_surface_destroy (pixel);
1444 	return status;
1445     }
1446 
1447     image = (cairo_image_surface_t *) pixel;
1448     argb = *(uint32_t *) image->data;
1449     cairo_surface_destroy (pixel);
1450 
1451     if (argb >> 24 == 0) {
1452 	_cairo_color_init_rgba (&src->solid.color, 0, 0, 0, 0);
1453     } else {
1454 	uint8_t alpha = argb >> 24;
1455 
1456 	_cairo_color_init_rgba (&src->solid.color,
1457 				((((argb >> 16) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
1458 				((((argb >>  8) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
1459 				((((argb >>  0) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
1460 				alpha / 255.);
1461     }
1462 
1463     src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
1464     src->type.fragment = FS_CONSTANT;
1465     src->type.vertex = VS_CONSTANT;
1466     src->type.pattern = PATTERN_CONSTANT;
1467 
1468     return CAIRO_STATUS_SUCCESS;
1469 }
1470 
1471 static cairo_status_t
i915_shader_acquire_surface(i915_shader_t * shader,union i915_shader_channel * src,const cairo_surface_pattern_t * pattern,const cairo_rectangle_int_t * extents)1472 i915_shader_acquire_surface (i915_shader_t *shader,
1473 			     union i915_shader_channel *src,
1474 			     const cairo_surface_pattern_t *pattern,
1475 			     const cairo_rectangle_int_t *extents)
1476 {
1477     int surface_width, surface_height;
1478     cairo_surface_t *surface, *drm;
1479     cairo_extend_t extend;
1480     cairo_filter_t filter;
1481     cairo_matrix_t m;
1482     int src_x = 0, src_y = 0;
1483     cairo_surface_t *free_me = NULL;
1484     cairo_status_t status;
1485     cairo_rectangle_int_t sample;
1486 
1487     assert (src->type.fragment == (i915_fragment_shader_t) -1);
1488     drm = surface = pattern->surface;
1489 
1490     extend = pattern->base.extend;
1491     src->base.matrix = pattern->base.matrix;
1492     filter = pattern->base.filter;
1493     _cairo_pattern_sampled_area(&pattern->base, extents, sample);
1494 
1495     if (surface->type == CAIRO_SURFACE_TYPE_DRM) {
1496 	if (surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1497 	    drm = ((cairo_surface_subsurface_t *) surface)->target;
1498 	} else if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
1499 	    drm = ((cairo_surface_snapshot_t *) surface)->target;
1500 	}
1501     }
1502 
1503     if (drm->type == CAIRO_SURFACE_TYPE_DRM) {
1504 	i915_surface_t *s = (i915_surface_t *) drm;
1505 
1506 	if (surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1507 	    if (s->intel.drm.base.device == shader->target->intel.drm.base.device &&
1508 		s != shader->target)
1509 	    {
1510 		cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surface;
1511 		int x;
1512 
1513 		status = i915_surface_fallback_flush (s);
1514 		if (unlikely (status))
1515 		    return status;
1516 
1517 		/* XXX blt subimage and cache snapshot */
1518 
1519 		if (to_intel_bo (s->intel.drm.bo)->batch_write_domain) {
1520 		    /* XXX pipelined flush of RENDER/TEXTURE cache */
1521 		}
1522 
1523 		src->type.fragment = FS_TEXTURE;
1524 		src->surface.pixel = NONE;
1525 		surface_width  = sub->extents.width;
1526 		surface_height = sub->extents.height;
1527 
1528 		src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
1529 		src->base.n_samplers = 1;
1530 
1531 		x = sub->extents.x;
1532 		if (s->intel.drm.format != CAIRO_FORMAT_A8)
1533 		    x *= 4;
1534 
1535 		/* XXX tiling restrictions upon offset? */
1536 		src->base.offset[0] = s->offset + sub->extents.y * s->intel.drm.stride + x;
1537 		src->base.map[0] = s->map0;
1538 		src->base.map[0] &= ~((2047 << MS3_HEIGHT_SHIFT) | (2047 << MS3_WIDTH_SHIFT));
1539 		src->base.map[0] |=
1540 		    ((sub->extents.height - 1) << MS3_HEIGHT_SHIFT) |
1541 		    ((sub->extents.width - 1)  << MS3_WIDTH_SHIFT);
1542 		src->base.map[1] = (s->intel.drm.stride / 4 - 1) << MS4_PITCH_SHIFT;
1543 	    }
1544 	} else {
1545 	    /* XXX if s == shader->dst allow if FILTER_NEAREST, EXTEND_NONE? */
1546 	    if (s->intel.drm.base.device == shader->target->intel.drm.base.device) {
1547 		status = i915_surface_fallback_flush (s);
1548 		if (unlikely (status))
1549 		    return status;
1550 
1551 		if (s == shader->target || i915_surface_needs_tiling (s)) {
1552 		    status = i915_surface_copy_subimage (i915_device (shader->target),
1553 							 s, &sample, TRUE, &s);
1554 		    if (unlikely (status))
1555 			return status;
1556 
1557 		    free_me = drm = &s->intel.drm.base;
1558 		}
1559 
1560 		src->type.fragment = FS_TEXTURE;
1561 		src->surface.pixel = NONE;
1562 
1563 		surface_width  = s->intel.drm.width;
1564 		surface_height = s->intel.drm.height;
1565 
1566 		src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
1567 		src->base.n_samplers = 1;
1568 		src->base.offset[0] = s->offset;
1569 		src->base.map[0] = s->map0;
1570 		src->base.map[1] = s->map1;
1571 	    }
1572 	}
1573     }
1574 
1575     if (src->type.fragment == (i915_fragment_shader_t) -1) {
1576 	i915_surface_t *s;
1577 
1578 	if (extents->width == 1 && extents->height == 1) {
1579 	    return i915_shader_acquire_solid_surface (shader, src,
1580 						      surface, extents);
1581 	}
1582 
1583 	s = (i915_surface_t *)
1584 	    _cairo_surface_has_snapshot (surface,
1585 					 shader->target->intel.drm.base.backend);
1586 	if (s == NULL) {
1587 	    cairo_status_t status;
1588 
1589 #if 0
1590 	    /* XXX hackity hack hack */
1591 	    status = i915_clone_yuv (surface, src,
1592 				     image->width, image->height,
1593 				     clone_out);
1594 #endif
1595 
1596 	    if (sample.width > 2048 || sample.height > 2048) {
1597 		status = i915_surface_render_pattern (i915_device (shader->target),
1598 						      pattern, extents,
1599 						      &s);
1600 		if (unlikely (status))
1601 		    return status;
1602 
1603 		extend = CAIRO_EXTEND_NONE;
1604 		filter = CAIRO_FILTER_NEAREST;
1605 		cairo_matrix_init_translate (&src->base.matrix,
1606 					     -extents->x, -extents->y);
1607 	    } else {
1608 		cairo_image_surface_t *image;
1609 		void *image_extra;
1610 
1611 		status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
1612 		if (unlikely (status))
1613 		    return status;
1614 
1615 		if (image->width  < 2048 &&
1616 		    image->height < 2048 &&
1617 		    sample.width  >= image->width / 4 &&
1618 		    sample.height >= image->height /4)
1619 		{
1620 
1621 		    status = i915_surface_clone (i915_device (shader->target),
1622 						 image, &s);
1623 
1624 		    if (likely (status == CAIRO_STATUS_SUCCESS)) {
1625 			_cairo_surface_attach_snapshot (surface,
1626 							&s->intel.drm.base,
1627 							intel_surface_detach_snapshot);
1628 
1629 			status = intel_snapshot_cache_insert (&i915_device (shader->target)->intel,
1630 							      &s->intel);
1631 			if (unlikely (status)) {
1632 			    cairo_surface_finish (&s->intel.drm.base);
1633 			    cairo_surface_destroy (&s->intel.drm.base);
1634 			}
1635 		    }
1636 		}
1637 		else
1638 		{
1639 		    status = i915_surface_clone_subimage (i915_device (shader->target),
1640 							  image, &sample, &s);
1641 		    src_x = -extents->x;
1642 		    src_y = -extents->y;
1643 		}
1644 
1645 		_cairo_surface_release_source_image (surface, image, image_extra);
1646 		if (unlikely (status))
1647 		    return status;
1648 	    }
1649 
1650 	    free_me = &s->intel.drm.base;
1651 	}
1652 
1653 	src->type.fragment = FS_TEXTURE;
1654 	src->surface.pixel = NONE;
1655 
1656 	src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
1657 	src->base.n_samplers = 1;
1658 	src->base.offset[0] = s->offset;
1659 	src->base.map[0] = s->map0;
1660 	src->base.map[1] = s->map1;
1661 
1662 	drm = &s->intel.drm.base;
1663 
1664 	surface_width  = s->intel.drm.width;
1665 	surface_height = s->intel.drm.height;
1666     }
1667 
1668     /* XXX transform nx1 or 1xn surfaces to 1D */
1669 
1670     src->type.pattern = PATTERN_TEXTURE;
1671     if (extend != CAIRO_EXTEND_NONE &&
1672 	sample.x >= 0 && sample.y >= 0 &&
1673 	sample.x + sample.width  <= surface_width &&
1674 	sample.y + sample.height <= surface_height)
1675     {
1676 	extend = CAIRO_EXTEND_NONE;
1677     }
1678     if (extend == CAIRO_EXTEND_NONE) {
1679 	src->type.vertex = VS_TEXTURE_16;
1680 	src->base.texfmt = TEXCOORDFMT_2D_16;
1681     } else {
1682 	src->type.vertex = VS_TEXTURE;
1683 	src->base.texfmt = TEXCOORDFMT_2D;
1684     }
1685     src->base.content = drm->content;
1686 
1687     src->base.sampler[0] =
1688 	(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
1689 	i915_texture_filter (filter);
1690     src->base.sampler[1] =
1691 	SS3_NORMALIZED_COORDS |
1692 	i915_texture_extend (extend);
1693 
1694     /* tweak the src matrix to map from dst to texture coordinates */
1695     if (src_x | src_y)
1696 	cairo_matrix_translate (&src->base.matrix, src_x, src_x);
1697     cairo_matrix_init_scale (&m, 1. / surface_width, 1. / surface_height);
1698     cairo_matrix_multiply (&src->base.matrix, &src->base.matrix, &m);
1699 
1700     if (free_me != NULL)
1701 	cairo_surface_destroy (free_me);
1702 
1703     return CAIRO_STATUS_SUCCESS;
1704 }
1705 
1706 cairo_status_t
i915_shader_acquire_pattern(i915_shader_t * shader,union i915_shader_channel * src,const cairo_pattern_t * pattern,const cairo_rectangle_int_t * extents)1707 i915_shader_acquire_pattern (i915_shader_t *shader,
1708 			     union i915_shader_channel *src,
1709 			     const cairo_pattern_t *pattern,
1710 			     const cairo_rectangle_int_t *extents)
1711 {
1712     switch (pattern->type) {
1713     case CAIRO_PATTERN_TYPE_SOLID:
1714 	return i915_shader_acquire_solid (shader, src,
1715 					  (cairo_solid_pattern_t *) pattern,
1716 					  extents);
1717 
1718     case CAIRO_PATTERN_TYPE_LINEAR:
1719 	return i915_shader_acquire_linear (shader, src,
1720 					   (cairo_linear_pattern_t *) pattern,
1721 					   extents);
1722 
1723     case CAIRO_PATTERN_TYPE_RADIAL:
1724 	return i915_shader_acquire_radial (shader, src,
1725 					   (cairo_radial_pattern_t *) pattern,
1726 					   extents);
1727 
1728     case CAIRO_PATTERN_TYPE_SURFACE:
1729 	return i915_shader_acquire_surface (shader, src,
1730 					    (cairo_surface_pattern_t *) pattern,
1731 					    extents);
1732 
1733     default:
1734 	ASSERT_NOT_REACHED;
1735 	return CAIRO_STATUS_SUCCESS;
1736     }
1737 }
1738 
1739 static uint32_t
i915_get_blend(cairo_operator_t op,i915_surface_t * dst)1740 i915_get_blend (cairo_operator_t op,
1741 		i915_surface_t *dst)
1742 {
1743 #define SBLEND(X) ((BLENDFACT_##X) << S6_CBUF_SRC_BLEND_FACT_SHIFT)
1744 #define DBLEND(X) ((BLENDFACT_##X) << S6_CBUF_DST_BLEND_FACT_SHIFT)
1745     static const struct blendinfo {
1746 	cairo_bool_t dst_alpha;
1747 	uint32_t src_blend;
1748 	uint32_t dst_blend;
1749 	enum {
1750 	    BOUNDED,
1751 	    SIMPLE,
1752 	    XRENDER,
1753 	} kind;
1754     } i915_blend_op[] = {
1755 	{0, SBLEND (ZERO),          DBLEND (ZERO), BOUNDED}, /* Clear */
1756 	{0, SBLEND (ONE),           DBLEND (ZERO), BOUNDED}, /* Src */
1757 
1758 	{0, SBLEND (ONE),           DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Over */
1759 	{1, SBLEND (DST_ALPHA),     DBLEND (ZERO), XRENDER}, /* In */
1760 	{1, SBLEND (INV_DST_ALPHA), DBLEND (ZERO), XRENDER}, /* Out */
1761 	{1, SBLEND (DST_ALPHA),     DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Atop */
1762 
1763 	{0, SBLEND (ZERO),          DBLEND (ONE), SIMPLE}, /* Dst */
1764 	{1, SBLEND (INV_DST_ALPHA), DBLEND (ONE), SIMPLE}, /* OverReverse */
1765 	{0, SBLEND (ZERO),          DBLEND (SRC_ALPHA), XRENDER}, /* InReverse */
1766 	{0, SBLEND (ZERO),          DBLEND (INV_SRC_ALPHA), SIMPLE}, /* OutReverse */
1767 	{1, SBLEND (INV_DST_ALPHA), DBLEND (SRC_ALPHA), XRENDER}, /* AtopReverse */
1768 
1769 	{1, SBLEND (INV_DST_ALPHA), DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Xor */
1770 	{0, SBLEND (ONE),           DBLEND (ONE), SIMPLE}, /* Add */
1771 	//{0, 0, SBLEND (SRC_ALPHA_SATURATE),	    DBLEND (ONE), SIMPLE}, /* XXX Saturate */
1772     };
1773     uint32_t sblend, dblend;
1774 
1775     if (op >= ARRAY_LENGTH (i915_blend_op))
1776 	return 0;
1777 
1778     if (i915_blend_op[op].kind == BOUNDED)
1779 	return 0;
1780 
1781     sblend = i915_blend_op[op].src_blend;
1782     dblend = i915_blend_op[op].dst_blend;
1783 
1784     /* If there's no dst alpha channel, adjust the blend op so that we'll treat
1785      * it as always 1.
1786      */
1787     if ((dst->intel.drm.base.content & CAIRO_CONTENT_ALPHA) == 0 &&
1788 	i915_blend_op[op].dst_alpha)
1789     {
1790 	if (sblend == SBLEND (DST_ALPHA))
1791 	    sblend = SBLEND (ONE);
1792 	else if (sblend == SBLEND (INV_DST_ALPHA))
1793 	    sblend = SBLEND (ZERO);
1794     }
1795 
1796     /* i915 engine reads 8bit color buffer into green channel in cases
1797        like color buffer blending etc., and also writes back green channel.
1798        So with dst_alpha blend we should use color factor. See spec on
1799        "8-bit rendering" */
1800     if (dst->intel.drm.format == CAIRO_FORMAT_A8 && i915_blend_op[op].dst_alpha) {
1801 	if (sblend == SBLEND (DST_ALPHA))
1802 	    sblend = SBLEND (DST_COLR);
1803 	else if (sblend == SBLEND (INV_DST_ALPHA))
1804 	    sblend = SBLEND (INV_DST_COLR);
1805     }
1806 
1807     return sblend | dblend;
1808 #undef SBLEND
1809 #undef DBLEND
1810 }
1811 
1812 static void
i915_shader_channel_init(union i915_shader_channel * channel)1813 i915_shader_channel_init (union i915_shader_channel *channel)
1814 {
1815     channel->type.vertex = (i915_vertex_shader_t) -1;
1816     channel->type.fragment = (i915_fragment_shader_t) -1;
1817     channel->type.pattern = (i915_shader_channel_t) -1;
1818     channel->base.texfmt = TEXCOORDFMT_NOT_PRESENT;
1819     channel->base.bo = NULL;
1820     channel->base.n_samplers = 0;
1821     channel->base.mode = 0;
1822 }
1823 
1824 static void
i915_shader_channel_fini(i915_device_t * device,union i915_shader_channel * channel)1825 i915_shader_channel_fini (i915_device_t *device,
1826 			   union i915_shader_channel *channel)
1827 {
1828     switch (channel->type.pattern) {
1829     case PATTERN_TEXTURE:
1830     case PATTERN_BASE:
1831     case PATTERN_LINEAR:
1832     case PATTERN_RADIAL:
1833 	if (channel->base.bo != NULL)
1834 	    intel_bo_destroy (&device->intel, channel->base.bo);
1835 	break;
1836 
1837     default:
1838     case PATTERN_CONSTANT:
1839 	break;
1840     }
1841 }
1842 
1843 static void
i915_shader_channel_reset(i915_device_t * device,union i915_shader_channel * channel)1844 i915_shader_channel_reset (i915_device_t *device,
1845 			   union i915_shader_channel *channel)
1846 {
1847     i915_shader_channel_fini (device, channel);
1848     i915_shader_channel_init (channel);
1849 }
1850 
1851 void
i915_shader_init(i915_shader_t * shader,i915_surface_t * dst,cairo_operator_t op,double opacity)1852 i915_shader_init (i915_shader_t *shader,
1853 		  i915_surface_t *dst,
1854 		  cairo_operator_t op,
1855 		  double opacity)
1856 {
1857     shader->committed = FALSE;
1858     shader->device = i915_device (dst);
1859     shader->target = dst;
1860     shader->op = op;
1861     shader->opacity = opacity;
1862 
1863     shader->blend = i915_get_blend (op, dst);
1864     shader->need_combine = FALSE;
1865 
1866     shader->content = dst->intel.drm.base.content;
1867 
1868     i915_shader_channel_init (&shader->source);
1869     i915_shader_channel_init (&shader->mask);
1870     i915_shader_channel_init (&shader->clip);
1871     i915_shader_channel_init (&shader->dst);
1872 }
1873 
1874 static void
i915_set_shader_samplers(i915_device_t * device,const i915_shader_t * shader)1875 i915_set_shader_samplers (i915_device_t *device,
1876 	                  const i915_shader_t *shader)
1877 {
1878     uint32_t n_samplers, n_maps, n;
1879     uint32_t samplers[2*4];
1880     uint32_t maps[4*4];
1881     uint32_t mask, s, m;
1882 
1883     n_maps =
1884 	shader->source.base.n_samplers +
1885 	shader->mask.base.n_samplers +
1886 	shader->clip.base.n_samplers +
1887 	shader->dst.base.n_samplers;
1888     assert (n_maps <= 4);
1889 
1890     if (n_maps == 0)
1891 	return;
1892 
1893     n_samplers =
1894 	!! shader->source.base.bo +
1895 	!! shader->mask.base.bo +
1896 	!! shader->clip.base.bo +
1897 	!! shader->dst.base.bo;
1898 
1899     mask  = (1 << n_maps) - 1;
1900 
1901     /* We check for repeated setting of sample state mainly to catch
1902      * continuation of text strings across multiple show-glyphs.
1903      */
1904     s = m = 0;
1905     if (shader->source.base.bo != NULL) {
1906 	samplers[s++] = shader->source.base.sampler[0];
1907 	samplers[s++] = shader->source.base.sampler[1];
1908 	maps[m++] = shader->source.base.bo->base.handle;
1909 	for (n = 0; n < shader->source.base.n_samplers; n++) {
1910 	    maps[m++] = shader->source.base.offset[n];
1911 	    maps[m++] = shader->source.base.map[2*n+0];
1912 	    maps[m++] = shader->source.base.map[2*n+1];
1913 	}
1914     }
1915     if (shader->mask.base.bo != NULL) {
1916 	samplers[s++] = shader->mask.base.sampler[0];
1917 	samplers[s++] = shader->mask.base.sampler[1];
1918 	maps[m++] = shader->mask.base.bo->base.handle;
1919 	for (n = 0; n < shader->mask.base.n_samplers; n++) {
1920 	    maps[m++] = shader->mask.base.offset[n];
1921 	    maps[m++] = shader->mask.base.map[2*n+0];
1922 	    maps[m++] = shader->mask.base.map[2*n+1];
1923 	}
1924     }
1925     if (shader->clip.base.bo != NULL) {
1926 	samplers[s++] = shader->clip.base.sampler[0];
1927 	samplers[s++] = shader->clip.base.sampler[1];
1928 	maps[m++] = shader->clip.base.bo->base.handle;
1929 	for (n = 0; n < shader->clip.base.n_samplers; n++) {
1930 	    maps[m++] = shader->clip.base.offset[n];
1931 	    maps[m++] = shader->clip.base.map[2*n+0];
1932 	    maps[m++] = shader->clip.base.map[2*n+1];
1933 	}
1934     }
1935     if (shader->dst.base.bo != NULL) {
1936 	samplers[s++] = shader->dst.base.sampler[0];
1937 	samplers[s++] = shader->dst.base.sampler[1];
1938 	maps[m++] = shader->dst.base.bo->base.handle;
1939 	for (n = 0; n < shader->dst.base.n_samplers; n++) {
1940 	    maps[m++] = shader->dst.base.offset[n];
1941 	    maps[m++] = shader->dst.base.map[2*n+0];
1942 	    maps[m++] = shader->dst.base.map[2*n+1];
1943 	}
1944     }
1945 
1946     if (n_maps > device->current_n_maps ||
1947 	memcmp (device->current_maps,
1948 		maps,
1949 		m * sizeof (uint32_t)))
1950     {
1951 	memcpy (device->current_maps, maps, m * sizeof (uint32_t));
1952 	device->current_n_maps = n_maps;
1953 
1954 	if (device->current_source != NULL)
1955 	    *device->current_source = 0;
1956 	if (device->current_mask != NULL)
1957 	    *device->current_mask = 0;
1958 	if (device->current_clip != NULL)
1959 	    *device->current_clip = 0;
1960 
1961 #if 0
1962 	if (shader->source.type.pattern == PATTERN_TEXTURE) {
1963 	    switch ((int) shader->source.surface.surface->type) {
1964 	    case CAIRO_SURFACE_TYPE_DRM:
1965 		{
1966 		    i915_surface_t *surface =
1967 			(i915_surface_t *) shader->source.surface.surface;
1968 		    device->current_source = &surface->is_current_texture;
1969 		    surface->is_current_texture |= CURRENT_SOURCE;
1970 		    break;
1971 		}
1972 
1973 	    case I915_PACKED_PIXEL_SURFACE_TYPE:
1974 		{
1975 		    i915_packed_pixel_surface_t *surface =
1976 			(i915_packed_pixel_surface_t *) shader->source.surface.surface;
1977 		    device->current_source = &surface->is_current_texture;
1978 		    surface->is_current_texture |= CURRENT_SOURCE;
1979 		    break;
1980 		}
1981 
1982 	    default:
1983 		device->current_source = NULL;
1984 		break;
1985 	    }
1986 	} else
1987 	    device->current_source = NULL;
1988 
1989 	if (shader->mask.type.pattern == PATTERN_TEXTURE) {
1990 	    switch ((int) shader->mask.surface.surface->type) {
1991 	    case CAIRO_SURFACE_TYPE_DRM:
1992 		{
1993 		    i915_surface_t *surface =
1994 			(i915_surface_t *) shader->mask.surface.surface;
1995 		    device->current_mask = &surface->is_current_texture;
1996 		    surface->is_current_texture |= CURRENT_MASK;
1997 		    break;
1998 		}
1999 
2000 	    case I915_PACKED_PIXEL_SURFACE_TYPE:
2001 		{
2002 		    i915_packed_pixel_surface_t *surface =
2003 			(i915_packed_pixel_surface_t *) shader->mask.surface.surface;
2004 		    device->current_mask = &surface->is_current_texture;
2005 		    surface->is_current_texture |= CURRENT_MASK;
2006 		    break;
2007 		}
2008 
2009 	    default:
2010 		device->current_mask = NULL;
2011 		break;
2012 	    }
2013 	} else
2014 	    device->current_mask = NULL;
2015 #endif
2016 
2017 	OUT_DWORD (_3DSTATE_MAP_STATE | (3 * n_maps));
2018 	OUT_DWORD (mask);
2019 	for (n = 0; n < shader->source.base.n_samplers; n++) {
2020 	    i915_batch_emit_reloc (device, shader->source.base.bo,
2021 				   shader->source.base.offset[n],
2022 				   I915_GEM_DOMAIN_SAMPLER, 0,
2023 				   FALSE);
2024 	    OUT_DWORD (shader->source.base.map[2*n+0]);
2025 	    OUT_DWORD (shader->source.base.map[2*n+1]);
2026 	}
2027 	for (n = 0; n < shader->mask.base.n_samplers; n++) {
2028 	    i915_batch_emit_reloc (device, shader->mask.base.bo,
2029 				   shader->mask.base.offset[n],
2030 				   I915_GEM_DOMAIN_SAMPLER, 0,
2031 				   FALSE);
2032 	    OUT_DWORD (shader->mask.base.map[2*n+0]);
2033 	    OUT_DWORD (shader->mask.base.map[2*n+1]);
2034 	}
2035 	for (n = 0; n < shader->clip.base.n_samplers; n++) {
2036 	    i915_batch_emit_reloc (device, shader->clip.base.bo,
2037 				   shader->clip.base.offset[n],
2038 				   I915_GEM_DOMAIN_SAMPLER, 0,
2039 				   FALSE);
2040 	    OUT_DWORD (shader->clip.base.map[2*n+0]);
2041 	    OUT_DWORD (shader->clip.base.map[2*n+1]);
2042 	}
2043 	for (n = 0; n < shader->dst.base.n_samplers; n++) {
2044 	    i915_batch_emit_reloc (device, shader->dst.base.bo,
2045 				   shader->dst.base.offset[n],
2046 				   I915_GEM_DOMAIN_SAMPLER, 0,
2047 				   FALSE);
2048 	    OUT_DWORD (shader->dst.base.map[2*n+0]);
2049 	    OUT_DWORD (shader->dst.base.map[2*n+1]);
2050 	}
2051     }
2052 
2053     if (n_samplers > device->current_n_samplers ||
2054 	memcmp (device->current_samplers,
2055 		samplers,
2056 		s * sizeof (uint32_t)))
2057     {
2058 	device->current_n_samplers = s;
2059 	memcpy (device->current_samplers, samplers, s * sizeof (uint32_t));
2060 
2061 	OUT_DWORD (_3DSTATE_SAMPLER_STATE | (3 * n_maps));
2062 	OUT_DWORD (mask);
2063 	s = 0;
2064 	for (n = 0; n < shader->source.base.n_samplers; n++) {
2065 	    OUT_DWORD (shader->source.base.sampler[0]);
2066 	    OUT_DWORD (shader->source.base.sampler[1] |
2067 		       (s << SS3_TEXTUREMAP_INDEX_SHIFT));
2068 	    OUT_DWORD (0x0);
2069 	    s++;
2070 	}
2071 	for (n = 0; n < shader->mask.base.n_samplers; n++) {
2072 	    OUT_DWORD (shader->mask.base.sampler[0]);
2073 	    OUT_DWORD (shader->mask.base.sampler[1] |
2074 		       (s << SS3_TEXTUREMAP_INDEX_SHIFT));
2075 	    OUT_DWORD (0x0);
2076 	    s++;
2077 	}
2078 	for (n = 0; n < shader->clip.base.n_samplers; n++) {
2079 	    OUT_DWORD (shader->clip.base.sampler[0]);
2080 	    OUT_DWORD (shader->clip.base.sampler[1] |
2081 		       (s << SS3_TEXTUREMAP_INDEX_SHIFT));
2082 	    OUT_DWORD (0x0);
2083 	    s++;
2084 	}
2085 	for (n = 0; n < shader->dst.base.n_samplers; n++) {
2086 	    OUT_DWORD (shader->dst.base.sampler[0]);
2087 	    OUT_DWORD (shader->dst.base.sampler[1] |
2088 		       (s << SS3_TEXTUREMAP_INDEX_SHIFT));
2089 	    OUT_DWORD (0x0);
2090 	    s++;
2091 	}
2092     }
2093 }
2094 
2095 static uint32_t
i915_shader_get_texcoords(const i915_shader_t * shader)2096 i915_shader_get_texcoords (const i915_shader_t *shader)
2097 {
2098     uint32_t texcoords;
2099     uint32_t tu;
2100 
2101     texcoords = S2_TEXCOORD_NONE;
2102     tu = 0;
2103     if (shader->source.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
2104 	texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
2105 	texcoords |= S2_TEXCOORD_FMT (tu, shader->source.base.texfmt);
2106 	tu++;
2107     }
2108     if (shader->mask.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
2109 	texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
2110 	texcoords |= S2_TEXCOORD_FMT (tu, shader->mask.base.texfmt);
2111 	tu++;
2112     }
2113     if (shader->clip.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
2114 	texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
2115 	texcoords |= S2_TEXCOORD_FMT (tu, shader->clip.base.texfmt);
2116 	tu++;
2117     }
2118     if (shader->dst.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
2119 	texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
2120 	texcoords |= S2_TEXCOORD_FMT (tu, shader->dst.base.texfmt);
2121 	tu++;
2122     }
2123 
2124     return texcoords;
2125 }
2126 
2127 static void
i915_set_shader_mode(i915_device_t * device,const i915_shader_t * shader)2128 i915_set_shader_mode (i915_device_t *device,
2129 	              const i915_shader_t *shader)
2130 {
2131     uint32_t texcoords;
2132     uint32_t mask, cnt;
2133 
2134     texcoords = i915_shader_get_texcoords (shader);
2135 
2136     mask = cnt = 0;
2137 
2138     if (device->current_texcoords != texcoords)
2139 	mask |= I1_LOAD_S (2), cnt++;
2140 
2141     if (device->current_blend != shader->blend)
2142 	mask |= I1_LOAD_S (6), cnt++;
2143 
2144     if (cnt == 0)
2145 	return;
2146 
2147     OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | mask | (cnt-1));
2148 
2149     if (device->current_texcoords != texcoords) {
2150 	OUT_DWORD (texcoords);
2151 	device->current_texcoords = texcoords;
2152     }
2153 
2154     if (device->current_blend != shader->blend) {
2155 	if (shader->blend) {
2156 	    OUT_DWORD (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE |
2157 		       (BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT) |
2158 		       shader->blend);
2159 	} else {
2160 	    OUT_DWORD (S6_COLOR_WRITE_ENABLE);
2161 	}
2162 
2163 	device->current_blend = shader->blend;
2164     }
2165 }
2166 
2167 static void
i915_set_constants(i915_device_t * device,const uint32_t * constants,uint32_t n_constants)2168 i915_set_constants (i915_device_t *device,
2169 		    const uint32_t *constants,
2170 		    uint32_t n_constants)
2171 {
2172     uint32_t n;
2173 
2174     OUT_DWORD (_3DSTATE_PIXEL_SHADER_CONSTANTS | n_constants);
2175     OUT_DWORD ((1 << (n_constants >> 2)) - 1);
2176 
2177     for (n = 0; n < n_constants; n++)
2178 	OUT_DWORD (constants[n]);
2179 
2180     device->current_n_constants = n_constants;
2181     memcpy (device->current_constants, constants, n_constants*4);
2182 }
2183 
2184 static uint32_t
pack_constants(const union i915_shader_channel * channel,uint32_t * constants)2185 pack_constants (const union i915_shader_channel *channel,
2186 		uint32_t *constants)
2187 {
2188     uint32_t count = 0, n;
2189 
2190     switch (channel->type.fragment) {
2191     case FS_ZERO:
2192     case FS_ONE:
2193     case FS_PURE:
2194     case FS_DIFFUSE:
2195 	break;
2196 
2197     case FS_CONSTANT:
2198 	constants[count++] = pack_float (channel->solid.color.red);
2199 	constants[count++] = pack_float (channel->solid.color.green);
2200 	constants[count++] = pack_float (channel->solid.color.blue);
2201 	constants[count++] = pack_float (channel->solid.color.alpha);
2202 	break;
2203 
2204     case FS_LINEAR:
2205 	constants[count++] = pack_float (channel->linear.color0.red);
2206 	constants[count++] = pack_float (channel->linear.color0.green);
2207 	constants[count++] = pack_float (channel->linear.color0.blue);
2208 	constants[count++] = pack_float (channel->linear.color0.alpha);
2209 
2210 	constants[count++] = pack_float (channel->linear.color1.red);
2211 	constants[count++] = pack_float (channel->linear.color1.green);
2212 	constants[count++] = pack_float (channel->linear.color1.blue);
2213 	constants[count++] = pack_float (channel->linear.color1.alpha);
2214 	break;
2215 
2216     case FS_RADIAL:
2217 	for (n = 0; n < ARRAY_LENGTH (channel->radial.constants); n++)
2218 	    constants[count++] = pack_float (channel->radial.constants[n]);
2219 	break;
2220 
2221     case FS_TEXTURE:
2222     case FS_YUV:
2223     case FS_SPANS:
2224 	break;
2225     }
2226 
2227     return count;
2228 }
2229 
2230 static void
i915_set_shader_constants(i915_device_t * device,const i915_shader_t * shader)2231 i915_set_shader_constants (i915_device_t *device,
2232 	                   const i915_shader_t *shader)
2233 {
2234     uint32_t constants[4*4*3+4];
2235     unsigned n_constants;
2236 
2237     n_constants = 0;
2238     if (shader->source.type.fragment == FS_DIFFUSE) {
2239 	uint32_t diffuse;
2240 
2241 	diffuse =
2242 	    ((shader->source.solid.color.alpha_short >> 8) << 24) |
2243 	    ((shader->source.solid.color.red_short   >> 8) << 16) |
2244 	    ((shader->source.solid.color.green_short >> 8) << 8) |
2245 	    ((shader->source.solid.color.blue_short  >> 8) << 0);
2246 
2247 	if (diffuse != device->current_diffuse) {
2248 	    OUT_DWORD (_3DSTATE_DFLT_DIFFUSE_CMD);
2249 	    OUT_DWORD (diffuse);
2250 	    device->current_diffuse = diffuse;
2251 	}
2252     } else {
2253 	n_constants += pack_constants (&shader->source, constants + n_constants);
2254     }
2255     n_constants += pack_constants (&shader->mask, constants + n_constants);
2256 
2257     if (shader->opacity < 1.) {
2258 	constants[n_constants+0] =
2259 	    constants[n_constants+1] =
2260 	    constants[n_constants+2] =
2261 	    constants[n_constants+3] = pack_float (shader->opacity);
2262 	n_constants += 4;
2263     }
2264 
2265     if (n_constants != 0 &&
2266 	(device->current_n_constants != n_constants ||
2267 	 memcmp (device->current_constants, constants, n_constants*4)))
2268     {
2269 	i915_set_constants (device, constants, n_constants);
2270     }
2271 }
2272 
2273 static cairo_bool_t
i915_shader_needs_update(const i915_shader_t * shader,const i915_device_t * device)2274 i915_shader_needs_update (const i915_shader_t *shader,
2275 			  const i915_device_t *device)
2276 {
2277     uint32_t count, n;
2278     uint32_t buf[64];
2279 
2280     if (device->current_target != shader->target)
2281 	return TRUE;
2282 
2283     count =
2284 	!! shader->source.base.bo +
2285 	!! shader->mask.base.bo +
2286 	!! shader->clip.base.bo +
2287 	!! shader->dst.base.bo;
2288     if (count > device->current_n_samplers)
2289 	return TRUE;
2290 
2291     count =
2292 	shader->source.base.n_samplers +
2293 	shader->mask.base.n_samplers +
2294 	shader->clip.base.n_samplers +
2295 	shader->dst.base.n_samplers;
2296     if (count > device->current_n_maps)
2297 	return TRUE;
2298 
2299     if (count) {
2300 	count = 0;
2301 	if (shader->source.base.bo != NULL) {
2302 	    buf[count++] = shader->source.base.sampler[0];
2303 	    buf[count++] = shader->source.base.sampler[1];
2304 	}
2305 	if (shader->mask.base.bo != NULL) {
2306 	    buf[count++] = shader->mask.base.sampler[0];
2307 	    buf[count++] = shader->mask.base.sampler[1];
2308 	}
2309 	if (shader->clip.base.bo != NULL) {
2310 	    buf[count++] = shader->clip.base.sampler[0];
2311 	    buf[count++] = shader->clip.base.sampler[1];
2312 	}
2313 	if (shader->dst.base.bo != NULL) {
2314 	    buf[count++] = shader->dst.base.sampler[0];
2315 	    buf[count++] = shader->dst.base.sampler[1];
2316 	}
2317 	if (memcmp (device->current_samplers, buf, count * sizeof (uint32_t)))
2318 	    return TRUE;
2319 
2320 	count = 0;
2321 	if (shader->source.base.bo != NULL) {
2322 	    buf[count++] = shader->source.base.bo->base.handle;
2323 	    for (n = 0; n < shader->source.base.n_samplers; n++) {
2324 		buf[count++] = shader->source.base.offset[n];
2325 		buf[count++] = shader->source.base.map[2*n+0];
2326 		buf[count++] = shader->source.base.map[2*n+1];
2327 	    }
2328 	}
2329 	if (shader->mask.base.bo != NULL) {
2330 	    buf[count++] = shader->mask.base.bo->base.handle;
2331 	    for (n = 0; n < shader->mask.base.n_samplers; n++) {
2332 		buf[count++] = shader->mask.base.offset[n];
2333 		buf[count++] = shader->mask.base.map[2*n+0];
2334 		buf[count++] = shader->mask.base.map[2*n+1];
2335 	    }
2336 	}
2337 	if (shader->clip.base.bo != NULL) {
2338 	    buf[count++] = shader->clip.base.bo->base.handle;
2339 	    for (n = 0; n < shader->clip.base.n_samplers; n++) {
2340 		buf[count++] = shader->clip.base.offset[n];
2341 		buf[count++] = shader->clip.base.map[2*n+0];
2342 		buf[count++] = shader->clip.base.map[2*n+1];
2343 	    }
2344 	}
2345 	if (shader->dst.base.bo != NULL) {
2346 	    buf[count++] = shader->dst.base.bo->base.handle;
2347 	    for (n = 0; n < shader->dst.base.n_samplers; n++) {
2348 		buf[count++] = shader->dst.base.offset[n];
2349 		buf[count++] = shader->dst.base.map[2*n+0];
2350 		buf[count++] = shader->dst.base.map[2*n+1];
2351 	    }
2352 	}
2353 	if (memcmp (device->current_maps, buf, count * sizeof (uint32_t)))
2354 	    return TRUE;
2355     }
2356 
2357     if (i915_shader_get_texcoords (shader) != device->current_texcoords)
2358 	return TRUE;
2359     if (device->current_blend != shader->blend)
2360 	return TRUE;
2361 
2362     count = 0;
2363     if (shader->source.type.fragment == FS_DIFFUSE) {
2364 	uint32_t diffuse;
2365 
2366 	diffuse =
2367 	    ((shader->source.solid.color.alpha_short >> 8) << 24) |
2368 	    ((shader->source.solid.color.red_short   >> 8) << 16) |
2369 	    ((shader->source.solid.color.green_short >> 8) << 8) |
2370 	    ((shader->source.solid.color.blue_short  >> 8) << 0);
2371 
2372 	if (diffuse != device->current_diffuse)
2373 	    return TRUE;
2374     } else {
2375 	count += pack_constants (&shader->source, buf + count);
2376     }
2377     count += pack_constants (&shader->mask, buf + count);
2378 
2379     if (count &&
2380 	(device->current_n_constants != count ||
2381 	 memcmp (device->current_constants, buf, count*4)))
2382     {
2383 	return TRUE;
2384     }
2385 
2386     n = (i915_shader_channel_key (&shader->source) <<  0) |
2387 	(i915_shader_channel_key (&shader->mask)   <<  8) |
2388 	(i915_shader_channel_key (&shader->clip)   << 16) |
2389 	(shader->op << 24) |
2390 	((shader->opacity < 1.) << 30) |
2391 	(((shader->content & CAIRO_CONTENT_ALPHA) == CAIRO_CONTENT_ALPHA) << 31);
2392     return n != device->current_program;
2393 }
2394 
2395 void
i915_set_dst(i915_device_t * device,i915_surface_t * dst)2396 i915_set_dst (i915_device_t *device, i915_surface_t *dst)
2397 {
2398     uint32_t size;
2399 
2400     if (device->current_target != dst) {
2401 	intel_bo_t *bo;
2402 
2403 	bo = to_intel_bo (dst->intel.drm.bo);
2404 	assert (bo != NULL);
2405 
2406 	OUT_DWORD (_3DSTATE_BUF_INFO_CMD);
2407 	OUT_DWORD (BUF_3D_ID_COLOR_BACK |
2408 		   BUF_tiling (bo->tiling) |
2409 		   BUF_3D_PITCH (dst->intel.drm.stride));
2410 	OUT_RELOC (dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
2411 
2412 	device->current_target = dst;
2413     }
2414 
2415     if (dst->colorbuf != device->current_colorbuf) {
2416 	OUT_DWORD (_3DSTATE_DST_BUF_VARS_CMD);
2417 	OUT_DWORD (dst->colorbuf);
2418 	device->current_colorbuf = dst->colorbuf;
2419     }
2420 
2421     size = DRAW_YMAX (dst->intel.drm.height) | DRAW_XMAX (dst->intel.drm.width);
2422     if (size != device->current_size) {
2423 	OUT_DWORD (_3DSTATE_DRAW_RECT_CMD);
2424 	OUT_DWORD (0); /* dither */
2425 	OUT_DWORD (0); /* top-left */
2426 	OUT_DWORD (size);
2427 	OUT_DWORD (0);  /* origin */
2428 	device->current_size = size;
2429     }
2430 }
2431 
2432 static void
i915_set_shader_target(i915_device_t * device,const i915_shader_t * shader)2433 i915_set_shader_target (i915_device_t *device,
2434 		        const i915_shader_t *shader)
2435 {
2436     i915_set_dst (device, shader->target);
2437 }
2438 
2439 int
i915_shader_num_texcoords(const i915_shader_t * shader)2440 i915_shader_num_texcoords (const i915_shader_t *shader)
2441 {
2442     int cnt = 0;
2443 
2444     switch (shader->source.base.texfmt) {
2445     default:
2446 	ASSERT_NOT_REACHED;
2447     case TEXCOORDFMT_NOT_PRESENT: break;
2448     case TEXCOORDFMT_2D: cnt += 2; break;
2449     case TEXCOORDFMT_3D: cnt += 3; break;
2450     case TEXCOORDFMT_4D: cnt += 4; break;
2451     case TEXCOORDFMT_1D: cnt += 1; break;
2452     case TEXCOORDFMT_2D_16: cnt += 1; break;
2453     }
2454 
2455     switch (shader->mask.base.texfmt) {
2456     default:
2457 	ASSERT_NOT_REACHED;
2458     case TEXCOORDFMT_NOT_PRESENT: break;
2459     case TEXCOORDFMT_2D: cnt += 2; break;
2460     case TEXCOORDFMT_3D: cnt += 3; break;
2461     case TEXCOORDFMT_4D: cnt += 4; break;
2462     case TEXCOORDFMT_1D: cnt += 1; break;
2463     case TEXCOORDFMT_2D_16: cnt += 1; break;
2464     }
2465 
2466     switch (shader->clip.base.texfmt) {
2467     default:
2468 	ASSERT_NOT_REACHED;
2469     case TEXCOORDFMT_NOT_PRESENT: break;
2470     case TEXCOORDFMT_2D: cnt += 2; break;
2471     case TEXCOORDFMT_3D: cnt += 3; break;
2472     case TEXCOORDFMT_4D: cnt += 4; break;
2473     case TEXCOORDFMT_1D: cnt += 1; break;
2474     case TEXCOORDFMT_2D_16: cnt += 1; break;
2475     }
2476 
2477     switch (shader->dst.base.texfmt) {
2478     default:
2479 	ASSERT_NOT_REACHED;
2480     case TEXCOORDFMT_NOT_PRESENT: break;
2481     case TEXCOORDFMT_2D: cnt += 2; break;
2482     case TEXCOORDFMT_3D: cnt += 3; break;
2483     case TEXCOORDFMT_4D: cnt += 4; break;
2484     case TEXCOORDFMT_1D: cnt += 1; break;
2485     case TEXCOORDFMT_2D_16: cnt += 1; break;
2486     }
2487 
2488     return cnt;
2489 }
2490 
2491 void
i915_shader_fini(i915_shader_t * shader)2492 i915_shader_fini (i915_shader_t *shader)
2493 {
2494     i915_device_t *device = i915_device (shader->target);
2495 
2496     i915_shader_channel_fini (device, &shader->source);
2497     i915_shader_channel_fini (device, &shader->mask);
2498     i915_shader_channel_fini (device, &shader->clip);
2499 }
2500 
2501 void
i915_shader_set_clip(i915_shader_t * shader,cairo_clip_t * clip)2502 i915_shader_set_clip (i915_shader_t *shader,
2503 		      cairo_clip_t *clip)
2504 {
2505     cairo_surface_t *clip_surface;
2506     int clip_x, clip_y;
2507     union i915_shader_channel *channel;
2508     i915_surface_t *s;
2509 
2510     clip_surface = _cairo_clip_get_surface (clip, &shader->target->intel.drm.base, &clip_x, &clip_y);
2511     assert (clip_surface->status == CAIRO_STATUS_SUCCESS);
2512     assert (clip_surface->type == CAIRO_SURFACE_TYPE_DRM);
2513 
2514     channel = &shader->clip;
2515     channel->type.vertex = VS_TEXTURE_16;
2516     channel->base.texfmt = TEXCOORDFMT_2D_16;
2517     channel->base.content = CAIRO_CONTENT_ALPHA;
2518 
2519     channel->type.fragment = FS_TEXTURE;
2520     channel->surface.pixel = NONE;
2521 
2522     s = (i915_surface_t *) clip_surface;
2523     channel->base.bo = to_intel_bo (s->intel.drm.bo);
2524     channel->base.n_samplers = 1;
2525     channel->base.offset[0] = s->offset;
2526     channel->base.map[0] = s->map0;
2527     channel->base.map[1] = s->map1;
2528 
2529     channel->base.sampler[0] =
2530 	(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
2531 	i915_texture_filter (CAIRO_FILTER_NEAREST);
2532     channel->base.sampler[1] =
2533 	SS3_NORMALIZED_COORDS |
2534 	i915_texture_extend (CAIRO_EXTEND_NONE);
2535 
2536     cairo_matrix_init_scale (&shader->clip.base.matrix,
2537 			     1. / s->intel.drm.width,
2538 			     1. / s->intel.drm.height);
2539     cairo_matrix_translate (&shader->clip.base.matrix,
2540 			    -clip_x, -clip_y);
2541 }
2542 
2543 static cairo_status_t
i915_shader_check_aperture(i915_shader_t * shader,i915_device_t * device)2544 i915_shader_check_aperture (i915_shader_t *shader,
2545 			    i915_device_t *device)
2546 {
2547     cairo_status_t status;
2548     intel_bo_t *bo_array[4];
2549     uint32_t n = 0;
2550 
2551     if (shader->target != device->current_target)
2552 	bo_array[n++] = to_intel_bo (shader->target->intel.drm.bo);
2553 
2554     if (shader->source.base.bo != NULL)
2555 	bo_array[n++] = shader->source.base.bo;
2556 
2557     if (shader->mask.base.bo != NULL)
2558 	bo_array[n++] = shader->mask.base.bo;
2559 
2560     if (shader->clip.base.bo != NULL)
2561 	bo_array[n++] = shader->clip.base.bo;
2562 
2563     if (n == 0 || i915_check_aperture (device, bo_array, n))
2564 	return CAIRO_STATUS_SUCCESS;
2565 
2566     status = i915_batch_flush (device);
2567     if (unlikely (status))
2568 	return status;
2569 
2570     assert (i915_check_aperture (device, bo_array, n));
2571     return CAIRO_STATUS_SUCCESS;
2572 }
2573 
2574 static void
i915_shader_combine_mask(i915_shader_t * shader,i915_device_t * device)2575 i915_shader_combine_mask (i915_shader_t *shader, i915_device_t *device)
2576 {
2577     if (shader->mask.type.fragment == (i915_fragment_shader_t) -1 ||
2578 	shader->mask.type.fragment == FS_CONSTANT)
2579     {
2580 	return;
2581     }
2582 
2583     if (shader->mask.type.fragment == FS_PURE) {
2584 	if (shader->mask.solid.pure & (1<<3)) {
2585 	    shader->mask.type.fragment = FS_ONE;
2586 	} else {
2587 	    shader->mask.type.fragment = FS_ZERO;
2588 	}
2589     }
2590 
2591     if (shader->mask.type.fragment == FS_ONE ||
2592 	(shader->mask.base.content & CAIRO_CONTENT_ALPHA) == 0)
2593     {
2594 	i915_shader_channel_reset (device, &shader->mask);
2595     }
2596 
2597     if (shader->mask.type.fragment == FS_ZERO) {
2598 	i915_shader_channel_fini (device, &shader->source);
2599 
2600 	shader->source.type.fragment = FS_ZERO;
2601 	shader->source.type.vertex = VS_ZERO;
2602 	shader->source.base.texfmt = TEXCOORDFMT_NOT_PRESENT;
2603 	shader->source.base.mode = 0;
2604 	shader->source.base.n_samplers = 0;
2605     }
2606 
2607     if (shader->source.type.fragment == FS_ZERO) {
2608 	i915_shader_channel_reset (device, &shader->mask);
2609 	i915_shader_channel_reset (device, &shader->clip);
2610     }
2611 }
2612 
2613 static void
i915_shader_setup_dst(i915_shader_t * shader)2614 i915_shader_setup_dst (i915_shader_t *shader)
2615 {
2616     union i915_shader_channel *channel;
2617     i915_surface_t *s;
2618 
2619     /* We need to manual blending if we have a clip surface and an unbounded op,
2620      * or an extended blend mode.
2621      */
2622     if (shader->need_combine ||
2623 	(shader->op < CAIRO_OPERATOR_SATURATE &&
2624 	 (shader->clip.type.fragment == (i915_fragment_shader_t) -1 ||
2625 	  _cairo_operator_bounded_by_mask (shader->op))))
2626     {
2627 	return;
2628     }
2629 
2630     shader->need_combine = TRUE;
2631 
2632     channel = &shader->dst;
2633     channel->type.vertex = VS_TEXTURE_16;
2634     channel->base.texfmt = TEXCOORDFMT_2D_16;
2635     channel->base.content = shader->content;
2636 
2637     channel->type.fragment = FS_TEXTURE;
2638     channel->surface.pixel = NONE;
2639 
2640     s = shader->target;
2641     channel->base.bo = to_intel_bo (s->intel.drm.bo);
2642     channel->base.n_samplers = 1;
2643     channel->base.offset[0] = s->offset;
2644     channel->base.map[0] = s->map0;
2645     channel->base.map[1] = s->map1;
2646 
2647     channel->base.sampler[0] =
2648 	(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
2649 	i915_texture_filter (CAIRO_FILTER_NEAREST);
2650     channel->base.sampler[1] =
2651 	SS3_NORMALIZED_COORDS |
2652 	i915_texture_extend (CAIRO_EXTEND_NONE);
2653 
2654     cairo_matrix_init_scale (&shader->dst.base.matrix,
2655 			     1. / s->intel.drm.width,
2656 			     1. / s->intel.drm.height);
2657 }
2658 
2659 static void
i915_shader_combine_source(i915_shader_t * shader,i915_device_t * device)2660 i915_shader_combine_source (i915_shader_t *shader,
2661 			    i915_device_t *device)
2662 {
2663     if (device->last_source_fragment == shader->source.type.fragment)
2664 	return;
2665 
2666     if (device->last_source_fragment == FS_DIFFUSE) {
2667 	switch (shader->source.type.fragment) {
2668 	case FS_ONE:
2669 	case FS_PURE:
2670 	case FS_CONSTANT:
2671 	case FS_DIFFUSE:
2672 	    shader->source.type.fragment = FS_DIFFUSE;
2673 	    shader->source.base.mode = 0;
2674 	    break;
2675 	case FS_ZERO:
2676 	case FS_LINEAR:
2677 	case FS_RADIAL:
2678 	case FS_TEXTURE:
2679 	case FS_YUV:
2680 	case FS_SPANS:
2681 	default:
2682 	    break;
2683 	}
2684     }
2685 
2686     device->last_source_fragment = shader->source.type.fragment;
2687 }
2688 
2689 static inline float *
i915_composite_vertex(float * v,const i915_shader_t * shader,double x,double y)2690 i915_composite_vertex (float *v,
2691 		       const i915_shader_t *shader,
2692 		       double x, double y)
2693 {
2694     double s, t;
2695 
2696     /* Each vertex is:
2697      *   2 vertex coordinates
2698      *   [0-2] source texture coordinates
2699      *   [0-2] mask texture coordinates
2700      */
2701 
2702     *v++ = x; *v++ = y;
2703     switch (shader->source.type.vertex) {
2704     case VS_ZERO:
2705     case VS_CONSTANT:
2706 	break;
2707     case VS_LINEAR:
2708 	*v++ = i915_shader_linear_texcoord (&shader->source.linear, x, y);
2709 	break;
2710     case VS_TEXTURE:
2711 	s = x, t = y;
2712 	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
2713 	*v++ = s; *v++ = t;
2714 	break;
2715     case VS_TEXTURE_16:
2716 	s = x, t = y;
2717 	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
2718 	*v++ = texcoord_2d_16 (s, t);
2719 	break;
2720     }
2721     switch (shader->mask.type.vertex) {
2722     case VS_ZERO:
2723     case VS_CONSTANT:
2724 	break;
2725     case VS_LINEAR:
2726 	*v++ = i915_shader_linear_texcoord (&shader->mask.linear, x, y);
2727 	break;
2728     case VS_TEXTURE:
2729 	s = x, t = y;
2730 	cairo_matrix_transform_point (&shader->mask.base.matrix, &s, &t);
2731 	*v++ = s; *v++ = t;
2732 	break;
2733     case VS_TEXTURE_16:
2734 	s = x, t = y;
2735 	cairo_matrix_transform_point (&shader->mask.base.matrix, &s, &t);
2736 	*v++ = texcoord_2d_16 (s, t);
2737 	break;
2738     }
2739 
2740     return v;
2741 }
2742 
2743 static inline void
i915_shader_add_rectangle_general(const i915_shader_t * shader,int x,int y,int w,int h)2744 i915_shader_add_rectangle_general (const i915_shader_t *shader,
2745 				   int x, int y,
2746 				   int w, int h)
2747 {
2748     float *vertices;
2749 
2750     vertices = i915_add_rectangle (shader->device);
2751     vertices = i915_composite_vertex (vertices, shader, x + w, y + h);
2752     vertices = i915_composite_vertex (vertices, shader, x, y + h);
2753     vertices = i915_composite_vertex (vertices, shader, x, y);
2754     /* XXX overflow! */
2755 }
2756 
2757 void
i915_vbo_flush(i915_device_t * device)2758 i915_vbo_flush (i915_device_t *device)
2759 {
2760     assert (device->floats_per_vertex);
2761     assert (device->vertex_count);
2762 
2763     if (device->vbo == 0) {
2764 	OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
2765 		   I1_LOAD_S (0) |
2766 		   I1_LOAD_S (1) |
2767 		   1);
2768 	device->vbo = device->batch.used++;
2769 	device->vbo_max_index = device->batch.used;
2770 	OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
2771 		   (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
2772     }
2773 
2774     OUT_DWORD (PRIM3D_RECTLIST |
2775 	       PRIM3D_INDIRECT_SEQUENTIAL |
2776 	       device->vertex_count);
2777     OUT_DWORD (device->vertex_index);
2778 
2779     device->vertex_index += device->vertex_count;
2780     device->vertex_count = 0;
2781 }
2782 
2783 cairo_status_t
i915_shader_commit(i915_shader_t * shader,i915_device_t * device)2784 i915_shader_commit (i915_shader_t *shader,
2785 		    i915_device_t *device)
2786 {
2787     unsigned floats_per_vertex;
2788     cairo_status_t status;
2789 
2790     assert (CAIRO_MUTEX_IS_LOCKED (device->intel.base.base.mutex));
2791 
2792     if (! shader->committed) {
2793 	device->shader = shader;
2794 
2795 	i915_shader_combine_mask (shader, device);
2796 	i915_shader_combine_source (shader, device);
2797 	i915_shader_setup_dst (shader);
2798 
2799 	shader->add_rectangle = i915_shader_add_rectangle_general;
2800 
2801 	if ((status = setjmp (shader->unwind)))
2802 	    return status;
2803 
2804 	shader->committed = TRUE;
2805     }
2806 
2807     if (i915_shader_needs_update (shader, device)) {
2808 	if (i915_batch_space (device) < 256) {
2809 	    status = i915_batch_flush (device);
2810 	    if (unlikely (status))
2811 		return status;
2812 	}
2813 
2814 	if (device->vertex_count)
2815 	    i915_vbo_flush (device);
2816 
2817 	status = i915_shader_check_aperture (shader, device);
2818 	if (unlikely (status))
2819 	    return status;
2820 
2821   update_shader:
2822 	i915_set_shader_target (device, shader);
2823 	i915_set_shader_mode (device, shader);
2824 	i915_set_shader_samplers (device, shader);
2825 	i915_set_shader_constants (device, shader);
2826 	i915_set_shader_program (device, shader);
2827     }
2828 
2829     floats_per_vertex = 2 + i915_shader_num_texcoords (shader);
2830     if (device->floats_per_vertex == floats_per_vertex)
2831 	return CAIRO_STATUS_SUCCESS;
2832 
2833     if (i915_batch_space (device) < 8) {
2834 	status = i915_batch_flush (device);
2835 	if (unlikely (status))
2836 	    return status;
2837 
2838 	goto update_shader;
2839     }
2840 
2841     if (device->vertex_count)
2842 	i915_vbo_flush (device);
2843 
2844     if (device->vbo) {
2845 	device->batch_base[device->vbo_max_index] |= device->vertex_index;
2846 	OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S (1) | 0);
2847 	device->vbo_max_index = device->batch.used;
2848 	OUT_DWORD ((floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
2849 		   (floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
2850     }
2851 
2852     device->floats_per_vertex = floats_per_vertex;
2853     device->rectangle_size = floats_per_vertex * 3 * sizeof (float);
2854     device->vertex_index =
2855 	(device->vbo_used + 4*floats_per_vertex - 1) / (4 * floats_per_vertex);
2856     device->vbo_offset = 4 * device->vertex_index * floats_per_vertex;
2857 
2858     return CAIRO_STATUS_SUCCESS;
2859 }
2860