1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Intel Corporation
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.
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
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/
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.
28 * The Original Code is the cairo graphics library.
31 * Chris Wilson <chris@chris-wilson.co.uk>
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"
44 i915_packed_pixel_surface_finish (void *abstract_surface)
46 i915_packed_pixel_surface_t *surface = abstract_surface;
47 i915_device_t *device;
49 device = i915_device_acquire (&surface->device->intel.base);
51 intel_bo_destroy (&device->intel, surface->bo);
53 if (surface->is_current_texture) {
54 if (surface->is_current_texture & CURRENT_SOURCE)
55 device->current_source = NULL;
56 if (surface->is_current_texture & CURRENT_MASK)
57 device->current_mask = NULL;
58 device->current_n_samplers = 0;
61 i915_device_release (device);
63 return CAIRO_STATUS_SUCCESS;
66 static const cairo_surface_backend_t i915_packed_pixel_surface_backend = {
67 I915_PACKED_PIXEL_SURFACE_TYPE,
68 i915_packed_pixel_surface_finish,
71 static cairo_surface_t *
72 i915_packed_pixel_surface_create (i915_device_t *device,
73 i915_packed_pixel_t pixel,
76 uint32_t width, uint32_t height)
78 i915_packed_pixel_surface_t *surface;
79 cairo_content_t content;
80 uint32_t tiling, size;
81 uint32_t stride, half_stride;
84 if (width > 2048 || height > 2048)
85 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
87 surface = malloc (sizeof (i915_packed_pixel_surface_t));
88 if (unlikely (surface == NULL))
89 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
91 tiling = I915_TILING_NONE; /* XXX */
92 half_stride = stride = i915_tiling_stride (tiling, width/2);
95 height = i915_tiling_height (tiling, height);
97 switch (surface->pixel = pixel) {
99 content = CAIRO_CONTENT_COLOR;
101 surface->offset[0] = 0;
102 surface->width[0] = width;
103 surface->height[0] = height;
104 surface->stride[0] = stride;
105 surface->map0[0] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
106 surface->map0[0] |= ((height - 1) << MS3_HEIGHT_SHIFT) |
107 ((width - 1) << MS3_WIDTH_SHIFT);
108 surface->map1[0] = (stride / 4 - 1) << MS4_PITCH_SHIFT;
110 surface->offset[1] = stride * height;
111 surface->width[1] = width / 2;
112 surface->height[1] = height / 2;
113 surface->stride[1] = half_stride;
114 surface->map0[1] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
115 surface->map0[1] |= ((height/2 - 1) << MS3_HEIGHT_SHIFT) |
116 ((width/2 - 1) << MS3_WIDTH_SHIFT);
117 surface->map1[1] = (half_stride / 4 - 1) << MS4_PITCH_SHIFT;
119 if (width < half_stride) {
120 surface->offset[2] = stride * height + half_stride / 2;
121 size = stride * height + half_stride * height / 2;
123 surface->offset[2] = stride * height + half_stride * height / 2;
124 size = stride * height + half_stride * height;
126 surface->width[2] = width / 2;
127 surface->height[2] = height / 2;
128 surface->stride[2] = half_stride;
129 surface->map0[2] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
130 surface->map0[2] |= ((height/2 - 1) << MS3_HEIGHT_SHIFT) |
131 ((width/2 - 1) << MS3_WIDTH_SHIFT);
132 surface->map1[2] = (half_stride / 4 - 1) << MS4_PITCH_SHIFT;
143 _cairo_surface_init (&surface->base,
144 &i915_packed_pixel_surface_backend,
147 surface->bo = intel_bo_create (&device->intel, size, FALSE);
148 assert (surface->bo->tiling == I915_TILING_NONE);
149 if (unlikely (surface->bo == NULL)) {
151 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
154 if (tiling == I915_TILING_NONE) {
155 intel_bo_t *bo = surface->bo;
159 dst = surface->offset[0];
160 if (width == stride) {
161 size = stride * height;
162 intel_bo_write (&device->intel, bo, dst, size, data);
165 for (i = 0; i < height; i++) {
166 intel_bo_write (&device->intel, bo, dst, width, data);
172 for (uv = 1; uv <= 2; uv++) {
173 dst = surface->offset[uv];
174 if (width / 2 == half_stride) {
175 size = half_stride * height / 2;
176 intel_bo_write (&device->intel, bo, dst, size, data);
180 for (i = 0; i < height / 2; i++) {
181 intel_bo_write (&device->intel, bo, dst, size, data);
190 base = intel_bo_map (&device->intel, surface->bo);
192 dst = base + surface->offset[0];
193 if (width == stride) {
194 size = stride * height;
195 memcpy (dst, data, size);
198 for (i = 0; i < height; i++) {
199 memcpy (dst, data, width);
205 dst = base + surface->offset[1];
206 if (width / 2 == half_stride) {
207 size = half_stride * height / 2;
208 memcpy (dst, data, size);
212 for (i = 0; i < height / 2; i++) {
213 memcpy (dst, data, size);
219 dst = base + surface->offset[2];
220 if (width / 2 == half_stride) {
221 size = half_stride * height / 2;
222 memcpy (dst, data, size);
226 for (i = 0; i < height / 2; i++) {
227 memcpy (dst, data, size);
234 surface->device = device;
235 surface->is_current_texture = 0;
237 return &surface->base;
240 static cairo_int_status_t
241 i915_clone_yuv (i915_surface_t *surface,
242 cairo_surface_t *source,
243 int width, int height,
244 cairo_surface_t **clone_out)
246 const uint8_t *mime_data = NULL;
247 unsigned int mime_data_length;
248 cairo_surface_t *clone;
250 cairo_surface_get_mime_data (source, "video/x-raw-yuv/i420",
251 &mime_data, &mime_data_length);
252 if (mime_data == NULL)
253 return CAIRO_INT_STATUS_UNSUPPORTED;
256 i915_packed_pixel_surface_create ((i915_device_t *) surface->base.device,
258 mime_data, mime_data_length,
261 return CAIRO_INT_STATUS_UNSUPPORTED;
262 if (unlikely (clone->status))
263 return clone->status;
266 return CAIRO_STATUS_SUCCESS;
270 /* Max instruction count: 4 */
272 i915_shader_linear_color (i915_device_t *device,
273 enum i915_shader_linear_mode mode,
274 int in, int c0, int c1, int out)
286 i915_fs_frc (tmp, i915_fs_operand (in, X, X, X, X));
290 /* XXX needs an extra constant: C2 [0.5, 2.0, x, x] */
291 i915_fs_mul (tmp, in, 0.5);
292 i915_fs_frc (tmp, i915_fs_operand_reg (tmp));
293 i915_fs_mul (tmp, tmp, 2.0);
294 i915_fs_add (tmp, i915_fs_operand_one (),
295 i915_fs_operand_reg_negate (tmp));
297 i915_fs_operand_reg (tmp),
298 i915_fs_operand_reg (tmp),
299 i915_fs_operand_reg_negate (tmp));
300 i915_fs_add (tmp, i915_fs_operand_one (),
301 i915_fs_operand_reg_negate (tmp));
305 i915_fs_operand_zero (),
306 i915_fs_operand (in, X, X, X, X));
308 i915_fs_operand_one (),
309 i915_fs_operand_reg (tmp));
315 i915_fs_operand (tmp, NEG_X, NEG_X, NEG_X, NEG_X),
316 i915_fs_operand_reg (c0),
317 i915_fs_operand_reg (c0));
319 i915_fs_operand (tmp, X, X, X, X),
320 i915_fs_operand_reg (c1),
321 i915_fs_operand_reg (out));
325 i915_shader_radial_init (struct i915_shader_radial *r,
326 const cairo_radial_pattern_t *radial)
328 double dx, dy, dr, r1;
330 dx = radial->cd2.center.x - radial->cd1.center.x;
331 dy = radial->cd2.center.y - radial->cd1.center.y;
332 dr = radial->cd2.radius - radial->cd1.radius;
334 r1 = radial->cd1.radius;
336 if (radial->cd2.center.x == radial->cd1.center.x &&
337 radial->cd2.center.y == radial->cd1.center.y)
339 /* XXX dr == 0, meaningless with anything other than PAD */
340 r->constants[0] = radial->cd1.center.x / dr;
341 r->constants[1] = radial->cd1.center.y / dr;
342 r->constants[2] = 1. / dr;
343 r->constants[3] = -r1 / dr;
350 r->base.mode = RADIAL_ONE;
352 r->constants[0] = -radial->cd1.center.x;
353 r->constants[1] = -radial->cd1.center.y;
354 r->constants[2] = r1;
355 r->constants[3] = -4 * (dx*dx + dy*dy - dr*dr);
357 r->constants[4] = -2 * dx;
358 r->constants[5] = -2 * dy;
359 r->constants[6] = -2 * r1 * dr;
360 r->constants[7] = 1 / (2 * (dx*dx + dy*dy - dr*dr));
362 r->base.mode = RADIAL_TWO;
365 r->base.matrix = radial->base.base.matrix;
368 /* Max instruction count: 10 */
370 i915_shader_radial_coord (i915_device_t *device,
371 enum i915_shader_radial_mode mode,
372 int in, int g0, int g1, int out)
377 pdx = (x - c1x) / dr, pdy = (y - c1y) / dr;
378 r² = pdx*pdx + pdy*pdy
379 t = r²/sqrt(r²) - r1/dr;
381 i915_fs_mad (FS_U0, MASK_X | MASK_Y,
382 i915_fs_operand (in, X, Y, ZERO, ZERO),
383 i915_fs_operand (g0, Z, Z, ZERO, ZERO),
384 i915_fs_operand (g0, NEG_X, NEG_Y, ZERO, ZERO));
385 i915_fs_dp2add (FS_U0, MASK_X,
386 i915_fs_operand (FS_U0, X, Y, ZERO, ZERO),
387 i915_fs_operand (FS_U0, X, Y, ZERO, ZERO),
388 i915_fs_operand_zero ());
389 i915_fs_rsq (out, MASK_X, i915_fs_operand (FS_U0, X, X, X, X));
390 i915_fs_mad (out, MASK_X,
391 i915_fs_operand (FS_U0, X, ZERO, ZERO, ZERO),
392 i915_fs_operand (out, X, ZERO, ZERO, ZERO),
393 i915_fs_operand (g0, W, ZERO, ZERO, ZERO));
398 pdx = x - c1x, pdy = y - c1y;
400 B = -2*(pdx*dx + pdy*dy + r1*dr);
401 C = pdx² + pdy² - r1²;
403 t = (-B + sqrt (det)) / (2 * A)
406 /* u0.x = pdx, u0.y = pdy, u[0].z = r1; */
408 i915_fs_operand (in, X, Y, ZERO, ZERO),
409 i915_fs_operand (g0, X, Y, Z, ZERO));
410 /* u0.x = pdx, u0.y = pdy, u[0].z = r1, u[0].w = B; */
411 i915_fs_dp3 (FS_U0, MASK_W,
412 i915_fs_operand (FS_U0, X, Y, ONE, ZERO),
413 i915_fs_operand (g1, X, Y, Z, ZERO));
414 /* u1.x = pdx² + pdy² - r1²; [C] */
415 i915_fs_dp3 (FS_U1, MASK_X,
416 i915_fs_operand (FS_U0, X, Y, Z, ZERO),
417 i915_fs_operand (FS_U0, X, Y, NEG_Z, ZERO));
418 /* u1.x = C, u1.y = B, u1.z=-4*A; */
419 i915_fs_mov_masked (FS_U1, MASK_Y, i915_fs_operand (FS_U0, W, W, W, W));
420 i915_fs_mov_masked (FS_U1, MASK_Z, i915_fs_operand (g0, W, W, W, W));
421 /* u1.x = B² - 4*A*C */
422 i915_fs_dp2add (FS_U1, MASK_X,
423 i915_fs_operand (FS_U1, X, Y, ZERO, ZERO),
424 i915_fs_operand (FS_U1, Z, Y, ZERO, ZERO),
425 i915_fs_operand_zero ());
426 /* out.x = -B + sqrt (B² - 4*A*C),
427 * out.y = -B - sqrt (B² - 4*A*C),
429 i915_fs_rsq (out, MASK_X, i915_fs_operand (FS_U1, X, X, X, X));
430 i915_fs_mad (out, MASK_X | MASK_Y,
431 i915_fs_operand (out, X, X, ZERO, ZERO),
432 i915_fs_operand (FS_U1, X, NEG_X, ZERO, ZERO),
433 i915_fs_operand (FS_U0, NEG_W, NEG_W, ZERO, ZERO));
434 /* out.x = (-B + sqrt (B² - 4*A*C)) / (2 * A),
435 * out.y = (-B - sqrt (B² - 4*A*C)) / (2 * A)
438 i915_fs_operand (out, X, Y, ZERO, ZERO),
439 i915_fs_operand (g1, W, W, ZERO, ZERO));
441 * out = (-B + sqrt (B² - 4*A*C)) / (2 * A),
443 * out = (-B - sqrt (B² - 4*A*C)) / (2 * A)
446 i915_fs_operand (g1, W, ZERO, ZERO, ZERO),
447 i915_fs_operand (out, X, ZERO, ZERO, ZERO),
448 i915_fs_operand (out, Y, ZERO, ZERO, ZERO));
453 /* Max instruction count: 7 */
455 i915_shader_yuv_color (i915_device_t *device,
457 int c0, int c1, int c2,
460 i915_fs_mov_masked (FS_U0, MASK_X, i915_fs_operand_reg (y));
461 i915_fs_mov_masked (FS_U0, MASK_Y, i915_fs_operand_reg (u));
462 i915_fs_mov_masked (FS_U0, MASK_Z, i915_fs_operand_reg (v));
465 i915_fs_operand_reg (FS_U0),
466 i915_fs_operand_reg (c0));
467 i915_fs_dp3 (out, MASK_X,
468 i915_fs_operand_reg (FS_U0),
469 i915_fs_operand (c1, X, ZERO, Y, ZERO));
470 i915_fs_dp3 (out, MASK_Z,
471 i915_fs_operand_reg (FS_U0),
472 i915_fs_operand (c1, Z, W, ZERO, ZERO));
473 i915_fs_dp3 (out, MASK_Y,
474 i915_fs_operand_reg (FS_U0),
475 i915_fs_operand_reg (c2));
478 static inline uint32_t
479 i915_shader_channel_key (const union i915_shader_channel *channel)
481 return (channel->type.fragment & 0x0f) | (channel->base.mode << FS_DETAILS_SHIFT);
485 i915_shader_channel_get_num_tex_coords (const union i915_shader_channel *channel)
487 switch (channel->type.fragment) {
506 i915_shader_get_num_tex_coords (const i915_shader_t *shader)
508 uint32_t num_tex_coords;
512 num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->source);
513 num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->mask);
514 num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->clip);
515 num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->dst);
517 return num_tex_coords;
520 #define i915_fs_operand_impure(reg, channel, pure) \
522 (((pure & (1 << 0)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << X_CHANNEL_SHIFT) | \
523 (((pure & (1 << 1)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Y_CHANNEL_SHIFT) | \
524 (((pure & (1 << 2)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Z_CHANNEL_SHIFT) | \
525 (((pure & (1 << 3)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << W_CHANNEL_SHIFT))
527 #define i915_fs_operand_pure(pure) \
529 (((pure & (1 << 0)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << X_CHANNEL_SHIFT) | \
530 (((pure & (1 << 1)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Y_CHANNEL_SHIFT) | \
531 (((pure & (1 << 2)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Z_CHANNEL_SHIFT) | \
532 (((pure & (1 << 3)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << W_CHANNEL_SHIFT))
535 i915_set_shader_program (i915_device_t *device,
536 const i915_shader_t *shader)
538 uint32_t num_tex_coords;
539 uint32_t num_samplers;
541 uint32_t texture_offset = 0;
542 uint32_t constant_offset = 0;
543 uint32_t sampler_offset = 0;
545 uint32_t source_pure;
551 n = (i915_shader_channel_key (&shader->source) << 0) |
552 (i915_shader_channel_key (&shader->mask) << 8) |
553 (i915_shader_channel_key (&shader->clip) << 16) |
555 ((shader->opacity < 1.) << 30) |
556 (((shader->content & CAIRO_CONTENT_ALPHA) == CAIRO_CONTENT_ALPHA) << 31);
557 if (n == device->current_program)
559 device->current_program = n;
563 if (shader->source.type.fragment == FS_ZERO) {
564 if (shader->clip.type.fragment == FS_TEXTURE) {
565 /* XXX need_combine */
566 assert (shader->mask.type.fragment == (i915_fragment_shader_t) -1);
568 i915_fs_texld (FS_U0, FS_S0, FS_T0);
569 if ((shader->content & CAIRO_CONTENT_COLOR) == 0)
570 i915_fs_mov (FS_OC, i915_fs_operand (FS_U0, W, W, W, W));
572 i915_fs_mov (FS_OC, i915_fs_operand (FS_U0, ZERO, ZERO, ZERO, W));
574 i915_fs_mov (FS_OC, i915_fs_operand_zero ());
581 num_tex_coords = i915_shader_get_num_tex_coords (shader);
582 for (n = 0; n < num_tex_coords; n++)
583 i915_fs_dcl (FS_T0 + n);
586 shader->source.base.n_samplers +
587 shader->mask.base.n_samplers +
588 shader->clip.base.n_samplers +
589 shader->dst.base.n_samplers;
590 for (n = 0; n < num_samplers; n++)
591 i915_fs_dcl (FS_S0 + n);
596 if (! shader->need_combine &&
597 shader->mask.type.fragment == (i915_fragment_shader_t) -1 &&
598 shader->clip.type.fragment != FS_TEXTURE &&
599 shader->content != CAIRO_CONTENT_ALPHA)
604 switch (shader->source.type.fragment) {
611 source_pure = shader->source.solid.pure;
617 constant_offset += 1;
626 i915_shader_linear_color (device, shader->source.base.mode,
628 FS_C0, FS_C1, /* colour ramp */
629 FS_U3); /* unpremultiplied output */
630 /* XXX can we defer premultiplication? */
631 i915_fs_mul (out_reg,
632 i915_fs_operand_reg (FS_U3),
633 i915_fs_operand (FS_U3, W, W, W, ONE));
635 constant_offset += 2;
637 source_reg = out_reg;
641 i915_shader_radial_coord (device, shader->source.base.mode,
643 FS_C0, FS_C1, /* gradient constants */
644 FS_R0); /* coordinate */
646 i915_fs_texld (out_reg, FS_S0, FS_R0);
647 constant_offset += 2;
650 source_reg = out_reg;
654 i915_fs_texld (out_reg, FS_S0, FS_T0);
657 source_reg = out_reg;
661 /* Load samplers to temporaries. */
662 i915_fs_texld (FS_R0, FS_S0, FS_T0);
663 i915_fs_texld (FS_R1, FS_S1, FS_T0);
664 i915_fs_texld (FS_R2, FS_S2, FS_T0);
666 i915_shader_yuv_color (device,
667 FS_R0, FS_R1, FS_R2, /* y, u, v */
668 FS_C0, FS_C1, FS_C2, /* coefficients */
671 constant_offset += 3;
674 source_reg = out_reg;
679 switch (shader->mask.type.fragment) {
690 mask_reg = FS_T0 + texture_offset;
695 mask_reg = FS_C0 + constant_offset;
696 constant_offset += 1;
700 i915_shader_linear_color (device, shader->mask.base.mode,
701 FS_T0 + texture_offset, /* input */
702 FS_C0 + constant_offset,
703 FS_C0 + constant_offset + 1, /* colour ramp */
704 FS_R1); /* unpremultiplied output */
705 constant_offset += 2;
711 i915_shader_radial_coord (device, shader->mask.base.mode,
712 FS_T0 + texture_offset, /* input */
713 FS_C0 + constant_offset,
714 FS_C0 + constant_offset + 1, /* gradient constants */
715 FS_R1); /* coordinate */
717 i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_R1);
718 constant_offset += 2;
725 i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_T0 + texture_offset);
732 if (mask_reg != ~0U) {
733 if (! shader->need_combine &&
734 shader->clip.type.fragment != FS_TEXTURE &&
735 (shader->content != CAIRO_CONTENT_ALPHA || source_reg == ~0U))
739 if (source_reg == ~0U) {
741 if (shader->mask.type.fragment == FS_SPANS) {
742 if (out_reg == FS_OC && shader->content == CAIRO_CONTENT_ALPHA) {
743 if (source_pure & (1 << 3))
744 i915_fs_mov (out_reg, i915_fs_operand (mask_reg, X, X, X, X));
746 i915_fs_mov (out_reg, i915_fs_operand_zero ());
748 i915_fs_mov (out_reg,
749 i915_fs_operand_impure (mask_reg, X, source_pure));
752 /* XXX ComponentAlpha
753 i915_fs_mov (out_reg,
754 i915_fs_operand_pure (mask_reg,
755 shader->source.solid.pure));
757 if (out_reg == FS_OC && shader->content == CAIRO_CONTENT_ALPHA) {
758 if (source_pure & (1 << 3))
759 i915_fs_mov (out_reg, i915_fs_operand (mask_reg, W, W, W, W));
761 i915_fs_mov (out_reg, i915_fs_operand_zero ());
763 i915_fs_mov (out_reg,
764 i915_fs_operand_impure (mask_reg, W, source_pure));
767 source_reg = out_reg;
768 } else if (shader->mask.type.fragment == FS_SPANS) {
769 i915_fs_mov (out_reg,
770 i915_fs_operand (mask_reg, X, X, X, X));
771 source_reg = out_reg;
773 source_reg = mask_reg;
776 if (shader->mask.type.fragment == FS_SPANS) {
777 if (out_reg == FS_OC && shader->content == CAIRO_CONTENT_ALPHA) {
778 i915_fs_mul (out_reg,
779 i915_fs_operand (source_reg, W, W, W, W),
780 i915_fs_operand (mask_reg, X, X, X, X));
782 i915_fs_mul (out_reg,
783 i915_fs_operand_reg (source_reg),
784 i915_fs_operand (mask_reg, X, X, X, X));
787 /* XXX ComponentAlpha
789 i915_fs_operand_reg (source_reg),
790 i915_fs_operand_reg (mask_reg));
792 if (out_reg == FS_OC && shader->content == CAIRO_CONTENT_ALPHA) {
793 i915_fs_mul (out_reg,
794 i915_fs_operand (source_reg, W, W, W, W),
795 i915_fs_operand (mask_reg, W, W, W, W));
797 i915_fs_mul (out_reg,
798 i915_fs_operand_reg (source_reg),
799 i915_fs_operand (mask_reg, W, W, W, W));
803 source_reg = out_reg;
807 if (shader->opacity < 1.) {
808 i915_fs_mul (source_reg,
809 i915_fs_operand_reg (source_reg),
810 i915_fs_operand_reg (FS_C0 + constant_offset));
814 /* need to preserve order of src, mask, clip, dst */
816 if (shader->clip.type.fragment == FS_TEXTURE) {
817 i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_T0 + texture_offset);
823 if (shader->need_combine) {
824 assert (shader->dst.type.fragment == FS_TEXTURE);
826 i915_fs_texld (FS_R2, FS_S0 + sampler_offset, FS_T0 + texture_offset);
831 switch (shader->op) {
832 case CAIRO_OPERATOR_CLEAR:
833 case CAIRO_OPERATOR_SOURCE:
836 case CAIRO_OPERATOR_OVER:
837 if (source_reg == ~0U) {
838 /* XXX shader->source.type.fragment == FS_PURE */
842 i915_fs_operand (source_reg, NEG_W, NEG_W, NEG_W, NEG_W),
843 i915_fs_operand_one ());
845 i915_fs_operand_reg (FS_U0),
848 i915_fs_operand_reg (source_reg),
849 i915_fs_operand_reg (FS_U0));
854 case CAIRO_OPERATOR_IN:
855 if (source_reg == ~0U) {
856 /* XXX shader->source.type.fragment == FS_PURE */
857 source_reg = dest_reg;
860 i915_fs_operand_reg (source_reg),
866 case CAIRO_OPERATOR_OUT:
867 if (source_reg == ~0U) {
868 /* XXX shader->source.type.fragment == FS_PURE */
869 i915_fs_mov (FS_R3, i915_fs_operand_zero ());
873 i915_fs_operand (source_reg, NEG_W, NEG_W, NEG_W, NEG_W),
874 i915_fs_operand_one ());
876 i915_fs_operand_reg (FS_U0),
882 case CAIRO_OPERATOR_ATOP:
884 case CAIRO_OPERATOR_DEST:
885 case CAIRO_OPERATOR_DEST_OVER:
886 case CAIRO_OPERATOR_DEST_IN:
887 case CAIRO_OPERATOR_DEST_OUT:
888 case CAIRO_OPERATOR_DEST_ATOP:
890 case CAIRO_OPERATOR_XOR:
891 case CAIRO_OPERATOR_ADD:
892 case CAIRO_OPERATOR_SATURATE:
894 case CAIRO_OPERATOR_MULTIPLY:
895 case CAIRO_OPERATOR_SCREEN:
896 case CAIRO_OPERATOR_OVERLAY:
897 case CAIRO_OPERATOR_DARKEN:
898 case CAIRO_OPERATOR_LIGHTEN:
899 case CAIRO_OPERATOR_COLOR_DODGE:
900 case CAIRO_OPERATOR_COLOR_BURN:
901 case CAIRO_OPERATOR_HARD_LIGHT:
902 case CAIRO_OPERATOR_SOFT_LIGHT:
903 case CAIRO_OPERATOR_DIFFERENCE:
904 case CAIRO_OPERATOR_EXCLUSION:
905 case CAIRO_OPERATOR_HSL_HUE:
906 case CAIRO_OPERATOR_HSL_SATURATION:
907 case CAIRO_OPERATOR_HSL_COLOR:
908 case CAIRO_OPERATOR_HSL_LUMINOSITY:
914 if (shader->clip.type.fragment == FS_TEXTURE) {
915 assert (mask_reg != ~0U);
917 if (! shader->need_combine) {
918 /* (source IN clip) */
919 if (source_reg == ~0U) {
920 if (source_pure == 0) {
921 source_reg = mask_reg;
924 if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
925 if (source_pure & (1 << 3))
926 i915_fs_mov (out_reg, i915_fs_operand (mask_reg, W, W, W, W));
928 i915_fs_mov (out_reg, i915_fs_operand_zero ());
930 i915_fs_mov (out_reg,
931 i915_fs_operand_impure (mask_reg, W, source_pure));
933 source_reg = out_reg;
935 } else if (mask_reg) {
937 if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
938 i915_fs_mul (out_reg,
939 i915_fs_operand (source_reg, W, W, W, W),
940 i915_fs_operand (mask_reg, W, W, W, W));
942 i915_fs_mul (out_reg,
943 i915_fs_operand_reg (source_reg),
944 i915_fs_operand (mask_reg, W, W, W, W));
947 source_reg = out_reg;
950 /* (source OP dest) LERP_clip dest */
951 if (source_reg == ~0U) {
952 if (source_pure == 0) {
954 i915_fs_operand (mask_reg, W, W, W, W));
957 i915_fs_operand_impure (mask_reg, W, source_pure));
961 i915_fs_operand_reg (source_reg),
962 i915_fs_operand (mask_reg, W, W, W, W));
965 i915_fs_add (mask_reg,
966 i915_fs_operand_one (),
967 i915_fs_operand (mask_reg, NEG_W, NEG_W, NEG_W, NEG_W));
969 if (dest_reg != FS_OC) {
970 if (dest_reg == ~0U) {
971 assert (shader->dst.type.fragment == FS_TEXTURE);
973 i915_fs_texld (FS_R2, FS_S0 + sampler_offset, FS_T0 + texture_offset);
980 i915_fs_operand_reg (dest_reg),
981 i915_fs_operand_reg (mask_reg));
986 if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
987 i915_fs_add (source_reg,
988 i915_fs_operand (FS_R3, W, W, W, W),
989 i915_fs_operand (mask_reg, W, W, W, W));
991 i915_fs_add (source_reg,
992 i915_fs_operand_reg (FS_R3),
993 i915_fs_operand_reg (mask_reg));
998 if (source_reg != FS_OC) {
999 if (source_reg == ~0U) {
1001 if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
1002 if (source_pure & (1 << 3))
1003 i915_fs_mov (FS_OC, i915_fs_operand_one ());
1005 i915_fs_mov (FS_OC, i915_fs_operand_zero ());
1007 i915_fs_mov (FS_OC, i915_fs_operand_pure (source_pure));
1009 i915_fs_mov (FS_OC, i915_fs_operand_one ());
1011 } else if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
1012 i915_fs_mov (FS_OC, i915_fs_operand (source_reg, W, W, W, W));
1014 i915_fs_mov (FS_OC, i915_fs_operand_reg (source_reg));
1022 i915_shader_linear_init (struct i915_shader_linear *l,
1023 const cairo_linear_pattern_t *linear)
1026 double dx, dy, offset;
1028 dx = linear->pd2.x - linear->pd1.x;
1029 dy = linear->pd2.y - linear->pd1.y;
1030 sf = dx * dx + dy * dy;
1039 offset = dx*x0 + dy*y0;
1041 if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
1044 l->offset = -offset;
1048 cairo_matrix_init (&m, dx, 0, dy, 0, -offset, 0);
1049 cairo_matrix_multiply (&m, &linear->base.base.matrix, &m);
1059 i915_shader_linear_contains_rectangle (struct i915_shader_linear *l,
1060 const cairo_rectangle_int_t *extents)
1064 v = i915_shader_linear_texcoord (l,
1072 v = i915_shader_linear_texcoord (l,
1073 extents->x + extents->width,
1080 v = i915_shader_linear_texcoord (l,
1082 extents->y + extents->height);
1088 v = i915_shader_linear_texcoord (l,
1089 extents->x + extents->width,
1090 extents->y + extents->height);
1099 #define is_pure(C,mask) (((mask) == 0) || (C) <= 0x00ff || (C) >= 0xff00)
1100 #define is_one(C,mask) (((mask) != 0) && (C) >= 0xff00)
1101 #define is_zero(C,mask) (((mask) != 0) && (C) <= 0x00ff)
1103 static cairo_status_t
1104 i915_shader_acquire_solid (i915_shader_t *shader,
1105 union i915_shader_channel *src,
1106 const cairo_solid_pattern_t *solid,
1107 const cairo_rectangle_int_t *extents)
1109 cairo_content_t content;
1111 content = CAIRO_CONTENT_COLOR_ALPHA;
1112 src->solid.color = solid->color;
1113 if (content == 0 || solid->color.alpha_short <= 0x00ff)
1115 src->base.content = CAIRO_CONTENT_ALPHA;
1116 src->type.fragment = FS_ZERO;
1118 else if ((((content & CAIRO_CONTENT_COLOR) == 0) ||
1119 (solid->color.red_short >= 0xff00 &&
1120 solid->color.green_short >= 0xff00 &&
1121 solid->color.blue_short >= 0xff00)) &&
1122 ((content & CAIRO_CONTENT_ALPHA) == 0 ||
1123 solid->color.alpha_short >= 0xff00))
1125 src->base.content = CAIRO_CONTENT_ALPHA;
1126 src->type.fragment = FS_ONE;
1128 else if (is_pure (solid->color.red_short, content & CAIRO_CONTENT_COLOR) &&
1129 is_pure (solid->color.green_short, content & CAIRO_CONTENT_COLOR) &&
1130 is_pure (solid->color.blue_short, content & CAIRO_CONTENT_COLOR) &&
1131 is_pure (solid->color.alpha_short, content & CAIRO_CONTENT_ALPHA))
1133 src->solid.pure = 0;
1134 src->solid.pure |= is_one (solid->color.red_short, content & CAIRO_CONTENT_COLOR) << 0;
1135 src->solid.pure |= is_one (solid->color.green_short, content & CAIRO_CONTENT_COLOR) << 1;
1136 src->solid.pure |= is_one (solid->color.blue_short, content & CAIRO_CONTENT_COLOR) << 2;
1137 src->solid.pure |= (! is_zero (solid->color.alpha_short, content & CAIRO_CONTENT_ALPHA)) << 3;
1139 if (src->solid.pure == 0) {
1140 src->base.content = CAIRO_CONTENT_ALPHA;
1141 src->type.fragment = FS_ZERO;
1142 } else if (src->solid.pure == 0x7) {
1143 src->base.content = CAIRO_CONTENT_ALPHA;
1144 src->type.fragment = FS_ONE;
1146 src->base.content = content;
1147 src->type.fragment = FS_PURE;
1148 src->base.mode = src->solid.pure;
1153 src->base.content = content;
1154 src->type.fragment = src == &shader->source ? FS_DIFFUSE : FS_CONSTANT;
1156 src->type.vertex = src->type.fragment == FS_ZERO ? VS_ZERO : VS_CONSTANT;
1157 src->type.pattern = PATTERN_CONSTANT;
1159 return CAIRO_STATUS_SUCCESS;
1162 static cairo_status_t
1163 i915_shader_acquire_linear (i915_shader_t *shader,
1164 union i915_shader_channel *src,
1165 const cairo_linear_pattern_t *linear,
1166 const cairo_rectangle_int_t *extents)
1168 cairo_bool_t mode = LINEAR_TEXTURE;
1169 cairo_status_t status;
1171 if (i915_shader_linear_init (&src->linear, linear) &&
1172 linear->base.n_stops == 2 &&
1173 linear->base.stops[0].offset == 0.0 &&
1174 linear->base.stops[1].offset == 1.0)
1176 if (i915_shader_linear_contains_rectangle (&src->linear,
1179 /* XXX can also lerp if contained within offset range */
1182 else switch (linear->base.base.extend) {
1183 case CAIRO_EXTEND_REPEAT:
1184 mode = LINEAR_REPEAT;
1186 case CAIRO_EXTEND_PAD:
1189 case CAIRO_EXTEND_NONE:
1191 case CAIRO_EXTEND_REFLECT:
1199 src->type.vertex = VS_LINEAR;
1200 src->type.pattern = PATTERN_LINEAR;
1201 src->base.texfmt = TEXCOORDFMT_1D;
1202 src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
1203 src->base.mode = mode;
1204 if (mode == LINEAR_TEXTURE) {
1205 intel_buffer_t buffer;
1207 status = intel_gradient_render ((intel_device_t *) shader->target->intel.drm.base.device,
1208 &linear->base, &buffer);
1209 if (unlikely (status))
1212 src->type.fragment = FS_TEXTURE;
1213 src->base.bo = intel_bo_reference (buffer.bo);
1214 src->base.n_samplers = 1;
1215 src->base.offset[0] = buffer.offset;
1216 src->base.map[0] = buffer.map0;
1217 src->base.map[1] = buffer.map1;
1218 src->base.sampler[0] =
1219 (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
1220 i915_texture_filter (CAIRO_FILTER_BILINEAR);
1221 src->base.sampler[1] =
1222 SS3_NORMALIZED_COORDS |
1223 i915_texture_extend (linear->base.base.extend);
1225 src->type.fragment = FS_LINEAR;
1226 src->linear.color0.red = linear->base.stops[0].color.red;
1227 src->linear.color0.green = linear->base.stops[0].color.green;
1228 src->linear.color0.blue = linear->base.stops[0].color.blue;
1229 src->linear.color0.alpha = linear->base.stops[0].color.alpha;
1231 src->linear.color1.red = linear->base.stops[1].color.red;
1232 src->linear.color1.green = linear->base.stops[1].color.green;
1233 src->linear.color1.blue = linear->base.stops[1].color.blue;
1234 src->linear.color1.alpha = linear->base.stops[1].color.alpha;
1237 return CAIRO_STATUS_SUCCESS;
1240 static cairo_status_t
1241 i915_shader_acquire_radial (i915_shader_t *shader,
1242 union i915_shader_channel *src,
1243 const cairo_radial_pattern_t *radial,
1244 const cairo_rectangle_int_t *extents)
1246 intel_buffer_t buffer;
1247 cairo_status_t status;
1249 status = intel_gradient_render ((intel_device_t *) shader->target->intel.drm.base.device,
1250 &radial->base, &buffer);
1251 if (unlikely (status))
1254 i915_shader_radial_init (&src->radial, radial);
1256 src->type.vertex = VS_TEXTURE;
1257 src->type.fragment = FS_RADIAL;
1258 src->type.pattern = PATTERN_RADIAL;
1259 src->base.texfmt = TEXCOORDFMT_2D;
1261 src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
1262 src->base.bo = intel_bo_reference (buffer.bo);
1263 src->base.n_samplers = 1;
1264 src->base.offset[0] = buffer.offset;
1265 src->base.map[0] = buffer.map0;
1266 src->base.map[1] = buffer.map1;
1267 src->base.sampler[0] =
1268 (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
1269 i915_texture_filter (CAIRO_FILTER_BILINEAR);
1270 src->base.sampler[1] =
1271 SS3_NORMALIZED_COORDS |
1272 i915_texture_extend (radial->base.base.extend);
1274 return CAIRO_STATUS_SUCCESS;
1277 static cairo_status_t
1278 i915_surface_clone (i915_device_t *device,
1279 cairo_image_surface_t *image,
1280 i915_surface_t **clone_out)
1282 i915_surface_t *clone;
1283 cairo_status_t status;
1287 i915_surface_create_from_cacheable_image_internal (device, image);
1288 if (unlikely (clone->intel.drm.base.status))
1289 return clone->intel.drm.base.status;
1291 cairo_format_t format;
1293 format = image->format;
1294 if (format == CAIRO_FORMAT_A1)
1295 format = CAIRO_FORMAT_A8;
1297 clone = (i915_surface_t *)
1298 i915_surface_create_internal (&device->intel.base,
1302 I915_TILING_DEFAULT,
1304 if (unlikely (clone->intel.drm.base.status))
1305 return clone->intel.drm.base.status;
1307 status = intel_bo_put_image (&device->intel,
1308 to_intel_bo (clone->intel.drm.bo),
1311 image->width, image->height,
1314 if (unlikely (status))
1319 return CAIRO_STATUS_SUCCESS;
1322 static cairo_status_t
1323 i915_surface_clone_subimage (i915_device_t *device,
1324 cairo_image_surface_t *image,
1325 const cairo_rectangle_int_t *extents,
1326 i915_surface_t **clone_out)
1328 i915_surface_t *clone;
1329 cairo_status_t status;
1330 cairo_format_t format;
1332 format = image->format;
1333 if (format == CAIRO_FORMAT_A1)
1334 format = CAIRO_FORMAT_A8;
1336 clone = (i915_surface_t *)
1337 i915_surface_create_internal (&device->intel.base,
1343 if (unlikely (clone->intel.drm.base.status))
1344 return clone->intel.drm.base.status;
1346 status = intel_bo_put_image (&device->intel,
1347 to_intel_bo (clone->intel.drm.bo),
1349 extents->x, extents->y,
1350 extents->width, extents->height,
1353 if (unlikely (status))
1357 return CAIRO_STATUS_SUCCESS;
1360 static cairo_status_t
1361 i915_surface_render_pattern (i915_device_t *device,
1362 const cairo_surface_pattern_t *pattern,
1363 const cairo_rectangle_int_t *extents,
1364 i915_surface_t **clone_out)
1366 i915_surface_t *clone;
1367 cairo_surface_t *image;
1368 cairo_status_t status;
1371 clone = (i915_surface_t *)
1372 i915_surface_create_internal (&device->intel.base,
1373 _cairo_format_from_content (pattern->surface->content),
1378 if (unlikely (clone->intel.drm.base.status))
1379 return clone->intel.drm.base.status;
1381 ptr = intel_bo_map (&device->intel,
1382 to_intel_bo (clone->intel.drm.bo));
1383 if (unlikely (ptr == NULL)) {
1384 cairo_surface_destroy (&clone->intel.drm.base);
1385 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1388 image = cairo_image_surface_create_for_data (ptr,
1389 clone->intel.drm.format,
1390 clone->intel.drm.width,
1391 clone->intel.drm.height,
1392 clone->intel.drm.stride);
1393 if (unlikely (image->status)) {
1394 cairo_surface_destroy (&clone->intel.drm.base);
1395 return image->status;
1398 status = _cairo_surface_offset_paint (image,
1399 extents->x, extents->y,
1400 CAIRO_OPERATOR_SOURCE,
1403 cairo_surface_destroy (image);
1405 if (unlikely (status)) {
1406 cairo_surface_destroy (&clone->intel.drm.base);
1411 return CAIRO_STATUS_SUCCESS;
1414 static cairo_status_t
1415 i915_shader_acquire_solid_surface (i915_shader_t *shader,
1416 union i915_shader_channel *src,
1417 cairo_surface_t *surface,
1418 const cairo_rectangle_int_t *extents)
1420 cairo_surface_pattern_t pattern;
1421 cairo_surface_t *pixel;
1422 cairo_image_surface_t *image;
1424 cairo_status_t status;
1427 status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
1428 if (unlikely (status))
1431 /* extract the pixel as argb32 */
1432 pixel = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
1433 _cairo_pattern_init_for_surface (&pattern, &image->base);
1434 cairo_matrix_init_translate (&pattern.base.matrix, extents->x, extents->y);
1435 pattern.base.filter = CAIRO_FILTER_NEAREST;
1436 status = _cairo_surface_paint (pixel, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL);
1437 _cairo_pattern_fini (&pattern.base);
1439 _cairo_surface_release_source_image (surface, image, image_extra);
1441 if (unlikely (status)) {
1442 cairo_surface_destroy (pixel);
1446 image = (cairo_image_surface_t *) pixel;
1447 argb = *(uint32_t *) image->data;
1448 cairo_surface_destroy (pixel);
1450 if (argb >> 24 == 0) {
1451 _cairo_color_init_rgba (&src->solid.color, 0, 0, 0, 0);
1453 uint8_t alpha = argb >> 24;
1455 _cairo_color_init_rgba (&src->solid.color,
1456 ((((argb >> 16) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
1457 ((((argb >> 8) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
1458 ((((argb >> 0) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
1462 src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
1463 src->type.fragment = FS_CONSTANT;
1464 src->type.vertex = VS_CONSTANT;
1465 src->type.pattern = PATTERN_CONSTANT;
1467 return CAIRO_STATUS_SUCCESS;
1470 static cairo_filter_t
1471 sampled_area (const cairo_surface_pattern_t *pattern,
1472 const cairo_rectangle_int_t *extents,
1473 cairo_rectangle_int_t *sample)
1475 cairo_rectangle_int_t surface_extents;
1476 cairo_filter_t filter;
1477 double x1, x2, y1, y2;
1482 x2 = extents->x + (int) extents->width;
1483 y2 = extents->y + (int) extents->height;
1485 if (_cairo_matrix_is_translation (&pattern->base.matrix)) {
1486 x1 += pattern->base.matrix.x0; x2 += pattern->base.matrix.x0;
1487 y1 += pattern->base.matrix.y0; y2 += pattern->base.matrix.y0;
1489 _cairo_matrix_transform_bounding_box (&pattern->base.matrix,
1494 filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
1495 sample->x = floor (x1 - pad);
1496 sample->y = floor (y1 - pad);
1497 sample->width = ceil (x2 + pad) - sample->x;
1498 sample->height = ceil (y2 + pad) - sample->y;
1500 if (_cairo_surface_get_extents (pattern->surface, &surface_extents))
1501 _cairo_rectangle_intersect (sample, &surface_extents);
1506 static cairo_status_t
1507 i915_shader_acquire_surface (i915_shader_t *shader,
1508 union i915_shader_channel *src,
1509 const cairo_surface_pattern_t *pattern,
1510 const cairo_rectangle_int_t *extents)
1512 int surface_width, surface_height;
1513 cairo_surface_t *surface, *drm;
1514 cairo_extend_t extend;
1515 cairo_filter_t filter;
1517 int src_x = 0, src_y = 0;
1518 cairo_surface_t *free_me = NULL;
1519 cairo_status_t status;
1520 cairo_rectangle_int_t sample;
1522 assert (src->type.fragment == (i915_fragment_shader_t) -1);
1523 drm = surface = pattern->surface;
1525 extend = pattern->base.extend;
1526 src->base.matrix = pattern->base.matrix;
1527 filter = sampled_area (pattern, extents, &sample);
1529 if (surface->type == CAIRO_SURFACE_TYPE_DRM) {
1530 if (surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1531 drm = ((cairo_surface_subsurface_t *) surface)->target;
1532 } else if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
1533 drm = ((cairo_surface_snapshot_t *) surface)->target;
1537 if (drm->type == CAIRO_SURFACE_TYPE_DRM) {
1538 i915_surface_t *s = (i915_surface_t *) drm;
1540 if (surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
1541 if (s->intel.drm.base.device == shader->target->intel.drm.base.device &&
1542 s != shader->target)
1544 cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surface;
1547 status = i915_surface_fallback_flush (s);
1548 if (unlikely (status))
1551 /* XXX blt subimage and cache snapshot */
1553 if (to_intel_bo (s->intel.drm.bo)->batch_write_domain) {
1554 /* XXX pipelined flush of RENDER/TEXTURE cache */
1557 src->type.fragment = FS_TEXTURE;
1558 src->surface.pixel = NONE;
1559 surface_width = sub->extents.width;
1560 surface_height = sub->extents.height;
1562 src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
1563 src->base.n_samplers = 1;
1566 if (s->intel.drm.format != CAIRO_FORMAT_A8)
1569 /* XXX tiling restrictions upon offset? */
1570 src->base.offset[0] = s->offset + sub->extents.y * s->intel.drm.stride + x;
1571 src->base.map[0] = s->map0;
1572 src->base.map[0] &= ~((2047 << MS3_HEIGHT_SHIFT) | (2047 << MS3_WIDTH_SHIFT));
1574 ((sub->extents.height - 1) << MS3_HEIGHT_SHIFT) |
1575 ((sub->extents.width - 1) << MS3_WIDTH_SHIFT);
1576 src->base.map[1] = (s->intel.drm.stride / 4 - 1) << MS4_PITCH_SHIFT;
1579 /* XXX if s == shader->dst allow if FILTER_NEAREST, EXTEND_NONE? */
1580 if (s->intel.drm.base.device == shader->target->intel.drm.base.device) {
1581 status = i915_surface_fallback_flush (s);
1582 if (unlikely (status))
1585 if (s == shader->target || i915_surface_needs_tiling (s)) {
1586 status = i915_surface_copy_subimage (i915_device (shader->target),
1587 s, &sample, TRUE, &s);
1588 if (unlikely (status))
1591 free_me = drm = &s->intel.drm.base;
1594 src->type.fragment = FS_TEXTURE;
1595 src->surface.pixel = NONE;
1597 surface_width = s->intel.drm.width;
1598 surface_height = s->intel.drm.height;
1600 src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
1601 src->base.n_samplers = 1;
1602 src->base.offset[0] = s->offset;
1603 src->base.map[0] = s->map0;
1604 src->base.map[1] = s->map1;
1609 if (src->type.fragment == (i915_fragment_shader_t) -1) {
1612 if (extents->width == 1 && extents->height == 1) {
1613 return i915_shader_acquire_solid_surface (shader, src,
1617 s = (i915_surface_t *)
1618 _cairo_surface_has_snapshot (surface,
1619 shader->target->intel.drm.base.backend);
1621 cairo_status_t status;
1624 /* XXX hackity hack hack */
1625 status = i915_clone_yuv (surface, src,
1626 image->width, image->height,
1630 if (sample.width > 2048 || sample.height > 2048) {
1631 status = i915_surface_render_pattern (i915_device (shader->target),
1634 if (unlikely (status))
1637 extend = CAIRO_EXTEND_NONE;
1638 filter = CAIRO_FILTER_NEAREST;
1639 cairo_matrix_init_translate (&src->base.matrix,
1640 -extents->x, -extents->y);
1642 cairo_image_surface_t *image;
1645 status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
1646 if (unlikely (status))
1649 if (image->width < 2048 &&
1650 image->height < 2048 &&
1651 sample.width >= image->width / 4 &&
1652 sample.height >= image->height /4)
1655 status = i915_surface_clone (i915_device (shader->target),
1658 if (likely (status == CAIRO_STATUS_SUCCESS)) {
1659 _cairo_surface_attach_snapshot (surface,
1661 intel_surface_detach_snapshot);
1663 status = intel_snapshot_cache_insert (&i915_device (shader->target)->intel,
1665 if (unlikely (status)) {
1666 cairo_surface_finish (&s->intel.drm.base);
1667 cairo_surface_destroy (&s->intel.drm.base);
1673 status = i915_surface_clone_subimage (i915_device (shader->target),
1674 image, &sample, &s);
1675 src_x = -extents->x;
1676 src_y = -extents->y;
1679 _cairo_surface_release_source_image (surface, image, image_extra);
1680 if (unlikely (status))
1684 free_me = &s->intel.drm.base;
1687 src->type.fragment = FS_TEXTURE;
1688 src->surface.pixel = NONE;
1690 src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
1691 src->base.n_samplers = 1;
1692 src->base.offset[0] = s->offset;
1693 src->base.map[0] = s->map0;
1694 src->base.map[1] = s->map1;
1696 drm = &s->intel.drm.base;
1698 surface_width = s->intel.drm.width;
1699 surface_height = s->intel.drm.height;
1702 /* XXX transform nx1 or 1xn surfaces to 1D */
1704 src->type.pattern = PATTERN_TEXTURE;
1705 if (extend != CAIRO_EXTEND_NONE &&
1706 sample.x >= 0 && sample.y >= 0 &&
1707 sample.x + sample.width <= surface_width &&
1708 sample.y + sample.height <= surface_height)
1710 extend = CAIRO_EXTEND_NONE;
1712 if (extend == CAIRO_EXTEND_NONE) {
1713 src->type.vertex = VS_TEXTURE_16;
1714 src->base.texfmt = TEXCOORDFMT_2D_16;
1716 src->type.vertex = VS_TEXTURE;
1717 src->base.texfmt = TEXCOORDFMT_2D;
1719 src->base.content = drm->content;
1721 src->base.sampler[0] =
1722 (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
1723 i915_texture_filter (filter);
1724 src->base.sampler[1] =
1725 SS3_NORMALIZED_COORDS |
1726 i915_texture_extend (extend);
1728 /* tweak the src matrix to map from dst to texture coordinates */
1730 cairo_matrix_translate (&src->base.matrix, src_x, src_x);
1731 cairo_matrix_init_scale (&m, 1. / surface_width, 1. / surface_height);
1732 cairo_matrix_multiply (&src->base.matrix, &src->base.matrix, &m);
1734 if (free_me != NULL)
1735 cairo_surface_destroy (free_me);
1737 return CAIRO_STATUS_SUCCESS;
1741 i915_shader_acquire_pattern (i915_shader_t *shader,
1742 union i915_shader_channel *src,
1743 const cairo_pattern_t *pattern,
1744 const cairo_rectangle_int_t *extents)
1746 switch (pattern->type) {
1747 case CAIRO_PATTERN_TYPE_SOLID:
1748 return i915_shader_acquire_solid (shader, src,
1749 (cairo_solid_pattern_t *) pattern,
1752 case CAIRO_PATTERN_TYPE_LINEAR:
1753 return i915_shader_acquire_linear (shader, src,
1754 (cairo_linear_pattern_t *) pattern,
1757 case CAIRO_PATTERN_TYPE_RADIAL:
1758 return i915_shader_acquire_radial (shader, src,
1759 (cairo_radial_pattern_t *) pattern,
1762 case CAIRO_PATTERN_TYPE_SURFACE:
1763 return i915_shader_acquire_surface (shader, src,
1764 (cairo_surface_pattern_t *) pattern,
1769 return CAIRO_STATUS_SUCCESS;
1774 i915_get_blend (cairo_operator_t op,
1775 i915_surface_t *dst)
1777 #define SBLEND(X) ((BLENDFACT_##X) << S6_CBUF_SRC_BLEND_FACT_SHIFT)
1778 #define DBLEND(X) ((BLENDFACT_##X) << S6_CBUF_DST_BLEND_FACT_SHIFT)
1779 static const struct blendinfo {
1780 cairo_bool_t dst_alpha;
1788 } i915_blend_op[] = {
1789 {0, SBLEND (ZERO), DBLEND (ZERO), BOUNDED}, /* Clear */
1790 {0, SBLEND (ONE), DBLEND (ZERO), BOUNDED}, /* Src */
1792 {0, SBLEND (ONE), DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Over */
1793 {1, SBLEND (DST_ALPHA), DBLEND (ZERO), XRENDER}, /* In */
1794 {1, SBLEND (INV_DST_ALPHA), DBLEND (ZERO), XRENDER}, /* Out */
1795 {1, SBLEND (DST_ALPHA), DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Atop */
1797 {0, SBLEND (ZERO), DBLEND (ONE), SIMPLE}, /* Dst */
1798 {1, SBLEND (INV_DST_ALPHA), DBLEND (ONE), SIMPLE}, /* OverReverse */
1799 {0, SBLEND (ZERO), DBLEND (SRC_ALPHA), XRENDER}, /* InReverse */
1800 {0, SBLEND (ZERO), DBLEND (INV_SRC_ALPHA), SIMPLE}, /* OutReverse */
1801 {1, SBLEND (INV_DST_ALPHA), DBLEND (SRC_ALPHA), XRENDER}, /* AtopReverse */
1803 {1, SBLEND (INV_DST_ALPHA), DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Xor */
1804 {0, SBLEND (ONE), DBLEND (ONE), SIMPLE}, /* Add */
1805 //{0, 0, SBLEND (SRC_ALPHA_SATURATE), DBLEND (ONE), SIMPLE}, /* XXX Saturate */
1807 uint32_t sblend, dblend;
1809 if (op >= ARRAY_LENGTH (i915_blend_op))
1812 if (i915_blend_op[op].kind == BOUNDED)
1815 sblend = i915_blend_op[op].src_blend;
1816 dblend = i915_blend_op[op].dst_blend;
1818 /* If there's no dst alpha channel, adjust the blend op so that we'll treat
1821 if ((dst->intel.drm.base.content & CAIRO_CONTENT_ALPHA) == 0 &&
1822 i915_blend_op[op].dst_alpha)
1824 if (sblend == SBLEND (DST_ALPHA))
1825 sblend = SBLEND (ONE);
1826 else if (sblend == SBLEND (INV_DST_ALPHA))
1827 sblend = SBLEND (ZERO);
1830 /* i915 engine reads 8bit color buffer into green channel in cases
1831 like color buffer blending etc., and also writes back green channel.
1832 So with dst_alpha blend we should use color factor. See spec on
1833 "8-bit rendering" */
1834 if (dst->intel.drm.format == CAIRO_FORMAT_A8 && i915_blend_op[op].dst_alpha) {
1835 if (sblend == SBLEND (DST_ALPHA))
1836 sblend = SBLEND (DST_COLR);
1837 else if (sblend == SBLEND (INV_DST_ALPHA))
1838 sblend = SBLEND (INV_DST_COLR);
1841 return sblend | dblend;
1847 i915_shader_channel_init (union i915_shader_channel *channel)
1849 channel->type.vertex = (i915_vertex_shader_t) -1;
1850 channel->type.fragment = (i915_fragment_shader_t) -1;
1851 channel->type.pattern = (i915_shader_channel_t) -1;
1852 channel->base.texfmt = TEXCOORDFMT_NOT_PRESENT;
1853 channel->base.bo = NULL;
1854 channel->base.n_samplers = 0;
1855 channel->base.mode = 0;
1859 i915_shader_channel_fini (i915_device_t *device,
1860 union i915_shader_channel *channel)
1862 switch (channel->type.pattern) {
1863 case PATTERN_TEXTURE:
1865 case PATTERN_LINEAR:
1866 case PATTERN_RADIAL:
1867 if (channel->base.bo != NULL)
1868 intel_bo_destroy (&device->intel, channel->base.bo);
1872 case PATTERN_CONSTANT:
1878 i915_shader_channel_reset (i915_device_t *device,
1879 union i915_shader_channel *channel)
1881 i915_shader_channel_fini (device, channel);
1882 i915_shader_channel_init (channel);
1886 i915_shader_init (i915_shader_t *shader,
1887 i915_surface_t *dst,
1888 cairo_operator_t op,
1891 shader->committed = FALSE;
1892 shader->device = i915_device (dst);
1893 shader->target = dst;
1895 shader->opacity = opacity;
1897 shader->blend = i915_get_blend (op, dst);
1898 shader->need_combine = FALSE;
1900 shader->content = dst->intel.drm.base.content;
1902 i915_shader_channel_init (&shader->source);
1903 i915_shader_channel_init (&shader->mask);
1904 i915_shader_channel_init (&shader->clip);
1905 i915_shader_channel_init (&shader->dst);
1909 i915_set_shader_samplers (i915_device_t *device,
1910 const i915_shader_t *shader)
1912 uint32_t n_samplers, n_maps, n;
1913 uint32_t samplers[2*4];
1915 uint32_t mask, s, m;
1918 shader->source.base.n_samplers +
1919 shader->mask.base.n_samplers +
1920 shader->clip.base.n_samplers +
1921 shader->dst.base.n_samplers;
1922 assert (n_maps <= 4);
1928 !! shader->source.base.bo +
1929 !! shader->mask.base.bo +
1930 !! shader->clip.base.bo +
1931 !! shader->dst.base.bo;
1933 mask = (1 << n_maps) - 1;
1935 /* We check for repeated setting of sample state mainly to catch
1936 * continuation of text strings across multiple show-glyphs.
1939 if (shader->source.base.bo != NULL) {
1940 samplers[s++] = shader->source.base.sampler[0];
1941 samplers[s++] = shader->source.base.sampler[1];
1942 maps[m++] = shader->source.base.bo->base.handle;
1943 for (n = 0; n < shader->source.base.n_samplers; n++) {
1944 maps[m++] = shader->source.base.offset[n];
1945 maps[m++] = shader->source.base.map[2*n+0];
1946 maps[m++] = shader->source.base.map[2*n+1];
1949 if (shader->mask.base.bo != NULL) {
1950 samplers[s++] = shader->mask.base.sampler[0];
1951 samplers[s++] = shader->mask.base.sampler[1];
1952 maps[m++] = shader->mask.base.bo->base.handle;
1953 for (n = 0; n < shader->mask.base.n_samplers; n++) {
1954 maps[m++] = shader->mask.base.offset[n];
1955 maps[m++] = shader->mask.base.map[2*n+0];
1956 maps[m++] = shader->mask.base.map[2*n+1];
1959 if (shader->clip.base.bo != NULL) {
1960 samplers[s++] = shader->clip.base.sampler[0];
1961 samplers[s++] = shader->clip.base.sampler[1];
1962 maps[m++] = shader->clip.base.bo->base.handle;
1963 for (n = 0; n < shader->clip.base.n_samplers; n++) {
1964 maps[m++] = shader->clip.base.offset[n];
1965 maps[m++] = shader->clip.base.map[2*n+0];
1966 maps[m++] = shader->clip.base.map[2*n+1];
1969 if (shader->dst.base.bo != NULL) {
1970 samplers[s++] = shader->dst.base.sampler[0];
1971 samplers[s++] = shader->dst.base.sampler[1];
1972 maps[m++] = shader->dst.base.bo->base.handle;
1973 for (n = 0; n < shader->dst.base.n_samplers; n++) {
1974 maps[m++] = shader->dst.base.offset[n];
1975 maps[m++] = shader->dst.base.map[2*n+0];
1976 maps[m++] = shader->dst.base.map[2*n+1];
1980 if (n_maps > device->current_n_maps ||
1981 memcmp (device->current_maps,
1983 m * sizeof (uint32_t)))
1985 memcpy (device->current_maps, maps, m * sizeof (uint32_t));
1986 device->current_n_maps = n_maps;
1988 if (device->current_source != NULL)
1989 *device->current_source = 0;
1990 if (device->current_mask != NULL)
1991 *device->current_mask = 0;
1992 if (device->current_clip != NULL)
1993 *device->current_clip = 0;
1996 if (shader->source.type.pattern == PATTERN_TEXTURE) {
1997 switch ((int) shader->source.surface.surface->type) {
1998 case CAIRO_SURFACE_TYPE_DRM:
2000 i915_surface_t *surface =
2001 (i915_surface_t *) shader->source.surface.surface;
2002 device->current_source = &surface->is_current_texture;
2003 surface->is_current_texture |= CURRENT_SOURCE;
2007 case I915_PACKED_PIXEL_SURFACE_TYPE:
2009 i915_packed_pixel_surface_t *surface =
2010 (i915_packed_pixel_surface_t *) shader->source.surface.surface;
2011 device->current_source = &surface->is_current_texture;
2012 surface->is_current_texture |= CURRENT_SOURCE;
2017 device->current_source = NULL;
2021 device->current_source = NULL;
2023 if (shader->mask.type.pattern == PATTERN_TEXTURE) {
2024 switch ((int) shader->mask.surface.surface->type) {
2025 case CAIRO_SURFACE_TYPE_DRM:
2027 i915_surface_t *surface =
2028 (i915_surface_t *) shader->mask.surface.surface;
2029 device->current_mask = &surface->is_current_texture;
2030 surface->is_current_texture |= CURRENT_MASK;
2034 case I915_PACKED_PIXEL_SURFACE_TYPE:
2036 i915_packed_pixel_surface_t *surface =
2037 (i915_packed_pixel_surface_t *) shader->mask.surface.surface;
2038 device->current_mask = &surface->is_current_texture;
2039 surface->is_current_texture |= CURRENT_MASK;
2044 device->current_mask = NULL;
2048 device->current_mask = NULL;
2051 OUT_DWORD (_3DSTATE_MAP_STATE | (3 * n_maps));
2053 for (n = 0; n < shader->source.base.n_samplers; n++) {
2054 i915_batch_emit_reloc (device, shader->source.base.bo,
2055 shader->source.base.offset[n],
2056 I915_GEM_DOMAIN_SAMPLER, 0,
2058 OUT_DWORD (shader->source.base.map[2*n+0]);
2059 OUT_DWORD (shader->source.base.map[2*n+1]);
2061 for (n = 0; n < shader->mask.base.n_samplers; n++) {
2062 i915_batch_emit_reloc (device, shader->mask.base.bo,
2063 shader->mask.base.offset[n],
2064 I915_GEM_DOMAIN_SAMPLER, 0,
2066 OUT_DWORD (shader->mask.base.map[2*n+0]);
2067 OUT_DWORD (shader->mask.base.map[2*n+1]);
2069 for (n = 0; n < shader->clip.base.n_samplers; n++) {
2070 i915_batch_emit_reloc (device, shader->clip.base.bo,
2071 shader->clip.base.offset[n],
2072 I915_GEM_DOMAIN_SAMPLER, 0,
2074 OUT_DWORD (shader->clip.base.map[2*n+0]);
2075 OUT_DWORD (shader->clip.base.map[2*n+1]);
2077 for (n = 0; n < shader->dst.base.n_samplers; n++) {
2078 i915_batch_emit_reloc (device, shader->dst.base.bo,
2079 shader->dst.base.offset[n],
2080 I915_GEM_DOMAIN_SAMPLER, 0,
2082 OUT_DWORD (shader->dst.base.map[2*n+0]);
2083 OUT_DWORD (shader->dst.base.map[2*n+1]);
2087 if (n_samplers > device->current_n_samplers ||
2088 memcmp (device->current_samplers,
2090 s * sizeof (uint32_t)))
2092 device->current_n_samplers = s;
2093 memcpy (device->current_samplers, samplers, s * sizeof (uint32_t));
2095 OUT_DWORD (_3DSTATE_SAMPLER_STATE | (3 * n_maps));
2098 for (n = 0; n < shader->source.base.n_samplers; n++) {
2099 OUT_DWORD (shader->source.base.sampler[0]);
2100 OUT_DWORD (shader->source.base.sampler[1] |
2101 (s << SS3_TEXTUREMAP_INDEX_SHIFT));
2105 for (n = 0; n < shader->mask.base.n_samplers; n++) {
2106 OUT_DWORD (shader->mask.base.sampler[0]);
2107 OUT_DWORD (shader->mask.base.sampler[1] |
2108 (s << SS3_TEXTUREMAP_INDEX_SHIFT));
2112 for (n = 0; n < shader->clip.base.n_samplers; n++) {
2113 OUT_DWORD (shader->clip.base.sampler[0]);
2114 OUT_DWORD (shader->clip.base.sampler[1] |
2115 (s << SS3_TEXTUREMAP_INDEX_SHIFT));
2119 for (n = 0; n < shader->dst.base.n_samplers; n++) {
2120 OUT_DWORD (shader->dst.base.sampler[0]);
2121 OUT_DWORD (shader->dst.base.sampler[1] |
2122 (s << SS3_TEXTUREMAP_INDEX_SHIFT));
2130 i915_shader_get_texcoords (const i915_shader_t *shader)
2135 texcoords = S2_TEXCOORD_NONE;
2137 if (shader->source.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
2138 texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
2139 texcoords |= S2_TEXCOORD_FMT (tu, shader->source.base.texfmt);
2142 if (shader->mask.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
2143 texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
2144 texcoords |= S2_TEXCOORD_FMT (tu, shader->mask.base.texfmt);
2147 if (shader->clip.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
2148 texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
2149 texcoords |= S2_TEXCOORD_FMT (tu, shader->clip.base.texfmt);
2152 if (shader->dst.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
2153 texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
2154 texcoords |= S2_TEXCOORD_FMT (tu, shader->dst.base.texfmt);
2162 i915_set_shader_mode (i915_device_t *device,
2163 const i915_shader_t *shader)
2168 texcoords = i915_shader_get_texcoords (shader);
2172 if (device->current_texcoords != texcoords)
2173 mask |= I1_LOAD_S (2), cnt++;
2175 if (device->current_blend != shader->blend)
2176 mask |= I1_LOAD_S (6), cnt++;
2181 OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | mask | (cnt-1));
2183 if (device->current_texcoords != texcoords) {
2184 OUT_DWORD (texcoords);
2185 device->current_texcoords = texcoords;
2188 if (device->current_blend != shader->blend) {
2189 if (shader->blend) {
2190 OUT_DWORD (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE |
2191 (BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT) |
2194 OUT_DWORD (S6_COLOR_WRITE_ENABLE);
2197 device->current_blend = shader->blend;
2202 i915_set_constants (i915_device_t *device,
2203 const uint32_t *constants,
2204 uint32_t n_constants)
2208 OUT_DWORD (_3DSTATE_PIXEL_SHADER_CONSTANTS | n_constants);
2209 OUT_DWORD ((1 << (n_constants >> 2)) - 1);
2211 for (n = 0; n < n_constants; n++)
2212 OUT_DWORD (constants[n]);
2214 device->current_n_constants = n_constants;
2215 memcpy (device->current_constants, constants, n_constants*4);
2219 pack_constants (const union i915_shader_channel *channel,
2220 uint32_t *constants)
2222 uint32_t count = 0, n;
2224 switch (channel->type.fragment) {
2232 constants[count++] = pack_float (channel->solid.color.red);
2233 constants[count++] = pack_float (channel->solid.color.green);
2234 constants[count++] = pack_float (channel->solid.color.blue);
2235 constants[count++] = pack_float (channel->solid.color.alpha);
2239 constants[count++] = pack_float (channel->linear.color0.red);
2240 constants[count++] = pack_float (channel->linear.color0.green);
2241 constants[count++] = pack_float (channel->linear.color0.blue);
2242 constants[count++] = pack_float (channel->linear.color0.alpha);
2244 constants[count++] = pack_float (channel->linear.color1.red);
2245 constants[count++] = pack_float (channel->linear.color1.green);
2246 constants[count++] = pack_float (channel->linear.color1.blue);
2247 constants[count++] = pack_float (channel->linear.color1.alpha);
2251 for (n = 0; n < ARRAY_LENGTH (channel->radial.constants); n++)
2252 constants[count++] = pack_float (channel->radial.constants[n]);
2265 i915_set_shader_constants (i915_device_t *device,
2266 const i915_shader_t *shader)
2268 uint32_t constants[4*4*3+4];
2269 unsigned n_constants;
2272 if (shader->source.type.fragment == FS_DIFFUSE) {
2276 ((shader->source.solid.color.alpha_short >> 8) << 24) |
2277 ((shader->source.solid.color.red_short >> 8) << 16) |
2278 ((shader->source.solid.color.green_short >> 8) << 8) |
2279 ((shader->source.solid.color.blue_short >> 8) << 0);
2281 if (diffuse != device->current_diffuse) {
2282 OUT_DWORD (_3DSTATE_DFLT_DIFFUSE_CMD);
2283 OUT_DWORD (diffuse);
2284 device->current_diffuse = diffuse;
2287 n_constants += pack_constants (&shader->source, constants + n_constants);
2289 n_constants += pack_constants (&shader->mask, constants + n_constants);
2291 if (shader->opacity < 1.) {
2292 constants[n_constants+0] =
2293 constants[n_constants+1] =
2294 constants[n_constants+2] =
2295 constants[n_constants+3] = pack_float (shader->opacity);
2299 if (n_constants != 0 &&
2300 (device->current_n_constants != n_constants ||
2301 memcmp (device->current_constants, constants, n_constants*4)))
2303 i915_set_constants (device, constants, n_constants);
2308 i915_shader_needs_update (const i915_shader_t *shader,
2309 const i915_device_t *device)
2314 if (device->current_target != shader->target)
2318 !! shader->source.base.bo +
2319 !! shader->mask.base.bo +
2320 !! shader->clip.base.bo +
2321 !! shader->dst.base.bo;
2322 if (count > device->current_n_samplers)
2326 shader->source.base.n_samplers +
2327 shader->mask.base.n_samplers +
2328 shader->clip.base.n_samplers +
2329 shader->dst.base.n_samplers;
2330 if (count > device->current_n_maps)
2335 if (shader->source.base.bo != NULL) {
2336 buf[count++] = shader->source.base.sampler[0];
2337 buf[count++] = shader->source.base.sampler[1];
2339 if (shader->mask.base.bo != NULL) {
2340 buf[count++] = shader->mask.base.sampler[0];
2341 buf[count++] = shader->mask.base.sampler[1];
2343 if (shader->clip.base.bo != NULL) {
2344 buf[count++] = shader->clip.base.sampler[0];
2345 buf[count++] = shader->clip.base.sampler[1];
2347 if (shader->dst.base.bo != NULL) {
2348 buf[count++] = shader->dst.base.sampler[0];
2349 buf[count++] = shader->dst.base.sampler[1];
2351 if (memcmp (device->current_samplers, buf, count * sizeof (uint32_t)))
2355 if (shader->source.base.bo != NULL) {
2356 buf[count++] = shader->source.base.bo->base.handle;
2357 for (n = 0; n < shader->source.base.n_samplers; n++) {
2358 buf[count++] = shader->source.base.offset[n];
2359 buf[count++] = shader->source.base.map[2*n+0];
2360 buf[count++] = shader->source.base.map[2*n+1];
2363 if (shader->mask.base.bo != NULL) {
2364 buf[count++] = shader->mask.base.bo->base.handle;
2365 for (n = 0; n < shader->mask.base.n_samplers; n++) {
2366 buf[count++] = shader->mask.base.offset[n];
2367 buf[count++] = shader->mask.base.map[2*n+0];
2368 buf[count++] = shader->mask.base.map[2*n+1];
2371 if (shader->clip.base.bo != NULL) {
2372 buf[count++] = shader->clip.base.bo->base.handle;
2373 for (n = 0; n < shader->clip.base.n_samplers; n++) {
2374 buf[count++] = shader->clip.base.offset[n];
2375 buf[count++] = shader->clip.base.map[2*n+0];
2376 buf[count++] = shader->clip.base.map[2*n+1];
2379 if (shader->dst.base.bo != NULL) {
2380 buf[count++] = shader->dst.base.bo->base.handle;
2381 for (n = 0; n < shader->dst.base.n_samplers; n++) {
2382 buf[count++] = shader->dst.base.offset[n];
2383 buf[count++] = shader->dst.base.map[2*n+0];
2384 buf[count++] = shader->dst.base.map[2*n+1];
2387 if (memcmp (device->current_maps, buf, count * sizeof (uint32_t)))
2391 if (i915_shader_get_texcoords (shader) != device->current_texcoords)
2393 if (device->current_blend != shader->blend)
2397 if (shader->source.type.fragment == FS_DIFFUSE) {
2401 ((shader->source.solid.color.alpha_short >> 8) << 24) |
2402 ((shader->source.solid.color.red_short >> 8) << 16) |
2403 ((shader->source.solid.color.green_short >> 8) << 8) |
2404 ((shader->source.solid.color.blue_short >> 8) << 0);
2406 if (diffuse != device->current_diffuse)
2409 count += pack_constants (&shader->source, buf + count);
2411 count += pack_constants (&shader->mask, buf + count);
2414 (device->current_n_constants != count ||
2415 memcmp (device->current_constants, buf, count*4)))
2420 n = (i915_shader_channel_key (&shader->source) << 0) |
2421 (i915_shader_channel_key (&shader->mask) << 8) |
2422 (i915_shader_channel_key (&shader->clip) << 16) |
2423 (shader->op << 24) |
2424 ((shader->opacity < 1.) << 30) |
2425 (((shader->content & CAIRO_CONTENT_ALPHA) == CAIRO_CONTENT_ALPHA) << 31);
2426 return n != device->current_program;
2430 i915_set_dst (i915_device_t *device, i915_surface_t *dst)
2434 if (device->current_target != dst) {
2437 bo = to_intel_bo (dst->intel.drm.bo);
2438 assert (bo != NULL);
2440 OUT_DWORD (_3DSTATE_BUF_INFO_CMD);
2441 OUT_DWORD (BUF_3D_ID_COLOR_BACK |
2442 BUF_tiling (bo->tiling) |
2443 BUF_3D_PITCH (dst->intel.drm.stride));
2444 OUT_RELOC (dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
2446 device->current_target = dst;
2449 if (dst->colorbuf != device->current_colorbuf) {
2450 OUT_DWORD (_3DSTATE_DST_BUF_VARS_CMD);
2451 OUT_DWORD (dst->colorbuf);
2452 device->current_colorbuf = dst->colorbuf;
2455 size = DRAW_YMAX (dst->intel.drm.height) | DRAW_XMAX (dst->intel.drm.width);
2456 if (size != device->current_size) {
2457 OUT_DWORD (_3DSTATE_DRAW_RECT_CMD);
2458 OUT_DWORD (0); /* dither */
2459 OUT_DWORD (0); /* top-left */
2461 OUT_DWORD (0); /* origin */
2462 device->current_size = size;
2467 i915_set_shader_target (i915_device_t *device,
2468 const i915_shader_t *shader)
2470 i915_set_dst (device, shader->target);
2474 i915_shader_num_texcoords (const i915_shader_t *shader)
2478 switch (shader->source.base.texfmt) {
2481 case TEXCOORDFMT_NOT_PRESENT: break;
2482 case TEXCOORDFMT_2D: cnt += 2; break;
2483 case TEXCOORDFMT_3D: cnt += 3; break;
2484 case TEXCOORDFMT_4D: cnt += 4; break;
2485 case TEXCOORDFMT_1D: cnt += 1; break;
2486 case TEXCOORDFMT_2D_16: cnt += 1; break;
2489 switch (shader->mask.base.texfmt) {
2492 case TEXCOORDFMT_NOT_PRESENT: break;
2493 case TEXCOORDFMT_2D: cnt += 2; break;
2494 case TEXCOORDFMT_3D: cnt += 3; break;
2495 case TEXCOORDFMT_4D: cnt += 4; break;
2496 case TEXCOORDFMT_1D: cnt += 1; break;
2497 case TEXCOORDFMT_2D_16: cnt += 1; break;
2500 switch (shader->clip.base.texfmt) {
2503 case TEXCOORDFMT_NOT_PRESENT: break;
2504 case TEXCOORDFMT_2D: cnt += 2; break;
2505 case TEXCOORDFMT_3D: cnt += 3; break;
2506 case TEXCOORDFMT_4D: cnt += 4; break;
2507 case TEXCOORDFMT_1D: cnt += 1; break;
2508 case TEXCOORDFMT_2D_16: cnt += 1; break;
2511 switch (shader->dst.base.texfmt) {
2514 case TEXCOORDFMT_NOT_PRESENT: break;
2515 case TEXCOORDFMT_2D: cnt += 2; break;
2516 case TEXCOORDFMT_3D: cnt += 3; break;
2517 case TEXCOORDFMT_4D: cnt += 4; break;
2518 case TEXCOORDFMT_1D: cnt += 1; break;
2519 case TEXCOORDFMT_2D_16: cnt += 1; break;
2526 i915_shader_fini (i915_shader_t *shader)
2528 i915_device_t *device = i915_device (shader->target);
2530 i915_shader_channel_fini (device, &shader->source);
2531 i915_shader_channel_fini (device, &shader->mask);
2532 i915_shader_channel_fini (device, &shader->clip);
2536 i915_shader_set_clip (i915_shader_t *shader,
2539 cairo_surface_t *clip_surface;
2541 union i915_shader_channel *channel;
2544 clip_surface = _cairo_clip_get_surface (clip, &shader->target->intel.drm.base, &clip_x, &clip_y);
2545 assert (clip_surface->status == CAIRO_STATUS_SUCCESS);
2546 assert (clip_surface->type == CAIRO_SURFACE_TYPE_DRM);
2548 channel = &shader->clip;
2549 channel->type.vertex = VS_TEXTURE_16;
2550 channel->base.texfmt = TEXCOORDFMT_2D_16;
2551 channel->base.content = CAIRO_CONTENT_ALPHA;
2553 channel->type.fragment = FS_TEXTURE;
2554 channel->surface.pixel = NONE;
2556 s = (i915_surface_t *) clip_surface;
2557 channel->base.bo = to_intel_bo (s->intel.drm.bo);
2558 channel->base.n_samplers = 1;
2559 channel->base.offset[0] = s->offset;
2560 channel->base.map[0] = s->map0;
2561 channel->base.map[1] = s->map1;
2563 channel->base.sampler[0] =
2564 (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
2565 i915_texture_filter (CAIRO_FILTER_NEAREST);
2566 channel->base.sampler[1] =
2567 SS3_NORMALIZED_COORDS |
2568 i915_texture_extend (CAIRO_EXTEND_NONE);
2570 cairo_matrix_init_scale (&shader->clip.base.matrix,
2571 1. / s->intel.drm.width,
2572 1. / s->intel.drm.height);
2573 cairo_matrix_translate (&shader->clip.base.matrix,
2577 static cairo_status_t
2578 i915_shader_check_aperture (i915_shader_t *shader,
2579 i915_device_t *device)
2581 cairo_status_t status;
2582 intel_bo_t *bo_array[4];
2585 if (shader->target != device->current_target)
2586 bo_array[n++] = to_intel_bo (shader->target->intel.drm.bo);
2588 if (shader->source.base.bo != NULL)
2589 bo_array[n++] = shader->source.base.bo;
2591 if (shader->mask.base.bo != NULL)
2592 bo_array[n++] = shader->mask.base.bo;
2594 if (shader->clip.base.bo != NULL)
2595 bo_array[n++] = shader->clip.base.bo;
2597 if (n == 0 || i915_check_aperture (device, bo_array, n))
2598 return CAIRO_STATUS_SUCCESS;
2600 status = i915_batch_flush (device);
2601 if (unlikely (status))
2604 assert (i915_check_aperture (device, bo_array, n));
2605 return CAIRO_STATUS_SUCCESS;
2609 i915_shader_combine_mask (i915_shader_t *shader, i915_device_t *device)
2611 if (shader->mask.type.fragment == (i915_fragment_shader_t) -1 ||
2612 shader->mask.type.fragment == FS_CONSTANT)
2617 if (shader->mask.type.fragment == FS_PURE) {
2618 if (shader->mask.solid.pure & (1<<3)) {
2619 shader->mask.type.fragment = FS_ONE;
2621 shader->mask.type.fragment = FS_ZERO;
2625 if (shader->mask.type.fragment == FS_ONE ||
2626 (shader->mask.base.content & CAIRO_CONTENT_ALPHA) == 0)
2628 i915_shader_channel_reset (device, &shader->mask);
2631 if (shader->mask.type.fragment == FS_ZERO) {
2632 i915_shader_channel_fini (device, &shader->source);
2634 shader->source.type.fragment = FS_ZERO;
2635 shader->source.type.vertex = VS_ZERO;
2636 shader->source.base.texfmt = TEXCOORDFMT_NOT_PRESENT;
2637 shader->source.base.mode = 0;
2638 shader->source.base.n_samplers = 0;
2641 if (shader->source.type.fragment == FS_ZERO) {
2642 i915_shader_channel_reset (device, &shader->mask);
2643 i915_shader_channel_reset (device, &shader->clip);
2648 i915_shader_setup_dst (i915_shader_t *shader)
2650 union i915_shader_channel *channel;
2653 /* We need to manual blending if we have a clip surface and an unbounded op,
2654 * or an extended blend mode.
2656 if (shader->need_combine ||
2657 (shader->op < CAIRO_OPERATOR_SATURATE &&
2658 (shader->clip.type.fragment == (i915_fragment_shader_t) -1 ||
2659 _cairo_operator_bounded_by_mask (shader->op))))
2664 shader->need_combine = TRUE;
2666 channel = &shader->dst;
2667 channel->type.vertex = VS_TEXTURE_16;
2668 channel->base.texfmt = TEXCOORDFMT_2D_16;
2669 channel->base.content = shader->content;
2671 channel->type.fragment = FS_TEXTURE;
2672 channel->surface.pixel = NONE;
2675 channel->base.bo = to_intel_bo (s->intel.drm.bo);
2676 channel->base.n_samplers = 1;
2677 channel->base.offset[0] = s->offset;
2678 channel->base.map[0] = s->map0;
2679 channel->base.map[1] = s->map1;
2681 channel->base.sampler[0] =
2682 (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
2683 i915_texture_filter (CAIRO_FILTER_NEAREST);
2684 channel->base.sampler[1] =
2685 SS3_NORMALIZED_COORDS |
2686 i915_texture_extend (CAIRO_EXTEND_NONE);
2688 cairo_matrix_init_scale (&shader->dst.base.matrix,
2689 1. / s->intel.drm.width,
2690 1. / s->intel.drm.height);
2694 i915_shader_combine_source (i915_shader_t *shader,
2695 i915_device_t *device)
2697 if (device->last_source_fragment == shader->source.type.fragment)
2700 if (device->last_source_fragment == FS_DIFFUSE) {
2701 switch (shader->source.type.fragment) {
2706 shader->source.type.fragment = FS_DIFFUSE;
2707 shader->source.base.mode = 0;
2720 device->last_source_fragment = shader->source.type.fragment;
2723 static inline float *
2724 i915_composite_vertex (float *v,
2725 const i915_shader_t *shader,
2731 * 2 vertex coordinates
2732 * [0-2] source texture coordinates
2733 * [0-2] mask texture coordinates
2737 switch (shader->source.type.vertex) {
2742 *v++ = i915_shader_linear_texcoord (&shader->source.linear, x, y);
2746 cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
2751 cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
2752 *v++ = texcoord_2d_16 (s, t);
2755 switch (shader->mask.type.vertex) {
2760 *v++ = i915_shader_linear_texcoord (&shader->mask.linear, x, y);
2764 cairo_matrix_transform_point (&shader->mask.base.matrix, &s, &t);
2769 cairo_matrix_transform_point (&shader->mask.base.matrix, &s, &t);
2770 *v++ = texcoord_2d_16 (s, t);
2778 i915_shader_add_rectangle_general (const i915_shader_t *shader,
2784 vertices = i915_add_rectangle (shader->device);
2785 vertices = i915_composite_vertex (vertices, shader, x + w, y + h);
2786 vertices = i915_composite_vertex (vertices, shader, x, y + h);
2787 vertices = i915_composite_vertex (vertices, shader, x, y);
2792 i915_vbo_flush (i915_device_t *device)
2794 assert (device->floats_per_vertex);
2795 assert (device->vertex_count);
2797 if (device->vbo == 0) {
2798 OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
2802 device->vbo = device->batch.used++;
2803 device->vbo_max_index = device->batch.used;
2804 OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
2805 (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
2808 OUT_DWORD (PRIM3D_RECTLIST |
2809 PRIM3D_INDIRECT_SEQUENTIAL |
2810 device->vertex_count);
2811 OUT_DWORD (device->vertex_index);
2813 device->vertex_index += device->vertex_count;
2814 device->vertex_count = 0;
2818 i915_shader_commit (i915_shader_t *shader,
2819 i915_device_t *device)
2821 unsigned floats_per_vertex;
2822 cairo_status_t status;
2824 assert (CAIRO_MUTEX_IS_LOCKED (device->intel.base.base.mutex));
2826 if (! shader->committed) {
2827 device->shader = shader;
2829 i915_shader_combine_mask (shader, device);
2830 i915_shader_combine_source (shader, device);
2831 i915_shader_setup_dst (shader);
2833 shader->add_rectangle = i915_shader_add_rectangle_general;
2835 if ((status = setjmp (shader->unwind)))
2838 shader->committed = TRUE;
2841 if (i915_shader_needs_update (shader, device)) {
2842 if (i915_batch_space (device) < 256) {
2843 status = i915_batch_flush (device);
2844 if (unlikely (status))
2848 if (device->vertex_count)
2849 i915_vbo_flush (device);
2851 status = i915_shader_check_aperture (shader, device);
2852 if (unlikely (status))
2856 i915_set_shader_target (device, shader);
2857 i915_set_shader_mode (device, shader);
2858 i915_set_shader_samplers (device, shader);
2859 i915_set_shader_constants (device, shader);
2860 i915_set_shader_program (device, shader);
2863 floats_per_vertex = 2 + i915_shader_num_texcoords (shader);
2864 if (device->floats_per_vertex == floats_per_vertex)
2865 return CAIRO_STATUS_SUCCESS;
2867 if (i915_batch_space (device) < 8) {
2868 status = i915_batch_flush (device);
2869 if (unlikely (status))
2875 if (device->vertex_count)
2876 i915_vbo_flush (device);
2879 device->batch_base[device->vbo_max_index] |= device->vertex_index;
2880 OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S (1) | 0);
2881 device->vbo_max_index = device->batch.used;
2882 OUT_DWORD ((floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
2883 (floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
2886 device->floats_per_vertex = floats_per_vertex;
2887 device->rectangle_size = floats_per_vertex * 3 * sizeof (float);
2888 device->vertex_index =
2889 (device->vbo_used + 4*floats_per_vertex - 1) / (4 * floats_per_vertex);
2890 device->vbo_offset = 4 * device->vertex_index * floats_per_vertex;
2892 return CAIRO_STATUS_SUCCESS;