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