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.
30 * The Initial Developer of the Original Code is Red Hat, Inc.
33 * Chris Wilson <chris@chris-wilson.co.uk>
38 #include "cairo-composite-rectangles-private.h"
39 #include "cairo-boxes-private.h"
40 #include "cairo-error-private.h"
41 #include "cairo-drm-i915-private.h"
43 /* Operates in either immediate or retained mode.
44 * When given a clip region we record the sequence of vbo and then
45 * replay them for each clip rectangle, otherwise we simply emit
46 * the vbo straight into the command stream.
49 typedef struct _i915_spans i915_spans_t;
52 (*i915_get_rectangle_func_t) (i915_spans_t *spans);
55 (*i915_span_func_t) (i915_spans_t *spans,
56 int x0, int x1, int y0, int y1,
60 cairo_span_renderer_t renderer;
62 i915_device_t *device;
65 cairo_bool_t is_bounded;
66 const cairo_rectangle_int_t *extents;
68 i915_get_rectangle_func_t get_rectangle;
69 i915_span_func_t span;
72 cairo_region_t *clip_region;
73 cairo_bool_t need_clip_surface;
81 unsigned int vbo_offset;
86 i915_emit_rectangle (i915_spans_t *spans)
88 return i915_add_rectangle (spans->device);
92 i915_accumulate_rectangle (i915_spans_t *spans)
97 size = spans->device->rectangle_size;
98 if (unlikely (spans->vbo_offset + size > I915_VBO_SIZE)) {
101 vbo = malloc (sizeof (struct vbo));
102 if (unlikely (vbo == NULL)) {
106 spans->tail->next = vbo;
110 vbo->bo = intel_bo_create (&spans->device->intel,
111 I915_VBO_SIZE, I915_VBO_SIZE,
112 FALSE, I915_TILING_NONE, 0);
115 spans->vbo_offset = 0;
116 spans->vbo_base = intel_bo_map (&spans->device->intel, vbo->bo);
119 vertices = spans->vbo_base + spans->vbo_offset;
120 spans->vbo_offset += size;
121 spans->tail->count += 3;
127 i915_span_zero (i915_spans_t *spans,
128 int x0, int x1, int y0, int y1,
133 vertices = spans->get_rectangle (spans);
146 i915_span_constant (i915_spans_t *spans,
147 int x0, int x1, int y0, int y1,
151 float a = alpha / 255.;
153 vertices = spans->get_rectangle (spans);
169 i915_span_linear (i915_spans_t *spans,
170 int x0, int x1, int y0, int y1,
174 float a = alpha / 255.;
177 vertices = spans->get_rectangle (spans);
182 *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
188 *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
194 *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
199 i915_span_texture (i915_spans_t *spans,
200 int x0, int x1, int y0, int y1,
204 float a = alpha / 255.;
207 vertices = spans->get_rectangle (spans);
212 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
213 *vertices++ = s; *vertices++ = t;
219 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
220 *vertices++ = s; *vertices++ = t;
226 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
227 *vertices++ = s; *vertices++ = t;
232 i915_span_texture16 (i915_spans_t *spans,
233 int x0, int x1, int y0, int y1, int alpha)
236 float a = alpha / 255.;
239 vertices = spans->get_rectangle (spans);
244 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
245 *vertices++ = texcoord_2d_16 (s, t);
251 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
252 *vertices++ = texcoord_2d_16 (s, t);
258 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
259 *vertices++ = texcoord_2d_16 (s, t);
264 i915_span_generic (i915_spans_t *spans,
265 int x0, int x1, int y0, int y1, int alpha)
269 float a = alpha / 255.;
272 * 2 vertex coordinates
273 * [0-2] source texture coordinates
275 * [0,2] clip mask coordinates
278 vertices = spans->get_rectangle (spans);
281 *vertices++ = x1; *vertices++ = y1;
283 switch (spans->shader.source.type.vertex) {
288 *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
291 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
292 *vertices++ = s; *vertices++ = t;
295 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
296 *vertices++ = texcoord_2d_16 (s, t);
300 if (spans->need_clip_surface) {
302 cairo_matrix_transform_point (&spans->shader.clip.base.matrix, &s, &t);
303 *vertices++ = texcoord_2d_16 (s, t);
305 if (spans->shader.need_combine) {
307 cairo_matrix_transform_point (&spans->shader.dst.base.matrix, &s, &t);
308 *vertices++ = texcoord_2d_16 (s, t);
312 *vertices++ = x0; *vertices++ = y1;
314 switch (spans->shader.source.type.vertex) {
319 *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
322 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
323 *vertices++ = s; *vertices++ = t;
326 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
327 *vertices++ = texcoord_2d_16 (s, t);
331 if (spans->need_clip_surface) {
333 cairo_matrix_transform_point (&spans->shader.clip.base.matrix, &s, &t);
334 *vertices++ = texcoord_2d_16 (s, t);
336 if (spans->shader.need_combine) {
338 cairo_matrix_transform_point (&spans->shader.dst.base.matrix, &s, &t);
339 *vertices++ = texcoord_2d_16 (s, t);
343 *vertices++ = x0; *vertices++ = y0;
345 switch (spans->shader.source.type.vertex) {
350 *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
353 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
354 *vertices++ = s; *vertices++ = t;
357 cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
358 *vertices++ = texcoord_2d_16 (s, t);
362 if (spans->need_clip_surface) {
364 cairo_matrix_transform_point (&spans->shader.clip.base.matrix, &s, &t);
365 *vertices++ = texcoord_2d_16 (s, t);
367 if (spans->shader.need_combine) {
369 cairo_matrix_transform_point (&spans->shader.dst.base.matrix, &s, &t);
370 *vertices++ = texcoord_2d_16 (s, t);
374 static cairo_status_t
375 i915_zero_spans_mono (void *abstract_renderer,
377 const cairo_half_open_span_t *half,
380 i915_spans_t *spans = abstract_renderer;
384 return CAIRO_STATUS_SUCCESS;
387 while (num_spans && half[0].coverage < 128)
393 while (num_spans--) {
397 if (half[0].coverage < 128)
401 i915_span_zero (spans,
407 return CAIRO_STATUS_SUCCESS;
410 static cairo_status_t
411 i915_zero_spans (void *abstract_renderer,
413 const cairo_half_open_span_t *half,
416 i915_spans_t *spans = abstract_renderer;
420 return CAIRO_STATUS_SUCCESS;
423 while (num_spans && half[0].coverage == 0)
429 while (num_spans--) {
433 if (half[0].coverage == 0)
437 i915_span_zero (spans,
443 return CAIRO_STATUS_SUCCESS;
446 static cairo_status_t
447 i915_bounded_spans_mono (void *abstract_renderer,
449 const cairo_half_open_span_t *half,
452 i915_spans_t *spans = abstract_renderer;
455 return CAIRO_STATUS_SUCCESS;
458 if (half[0].coverage >= 128) {
460 half[0].x, half[1].x,
465 } while (--num_spans > 1);
467 return CAIRO_STATUS_SUCCESS;
470 static cairo_status_t
471 i915_bounded_spans (void *abstract_renderer,
473 const cairo_half_open_span_t *half,
476 i915_spans_t *spans = abstract_renderer;
479 return CAIRO_STATUS_SUCCESS;
482 if (half[0].coverage) {
484 half[0].x, half[1].x,
489 } while (--num_spans > 1);
491 return CAIRO_STATUS_SUCCESS;
494 static cairo_status_t
495 i915_unbounded_spans (void *abstract_renderer,
497 const cairo_half_open_span_t *half,
500 i915_spans_t *spans = abstract_renderer;
502 if (num_spans == 0) {
504 spans->xmin, spans->xmax,
507 return CAIRO_STATUS_SUCCESS;
510 if (half[0].x != spans->xmin) {
512 spans->xmin, half[0].x,
519 half[0].x, half[1].x,
523 } while (--num_spans > 1);
525 if (half[0].x != spans->xmax) {
527 half[0].x, spans->xmax,
532 return CAIRO_STATUS_SUCCESS;
535 static cairo_status_t
536 i915_unbounded_spans_mono (void *abstract_renderer,
538 const cairo_half_open_span_t *half,
541 i915_spans_t *spans = abstract_renderer;
543 if (num_spans == 0) {
545 spans->xmin, spans->xmax,
548 return CAIRO_STATUS_SUCCESS;
551 if (half[0].x != spans->xmin) {
553 spans->xmin, half[0].x,
560 if (half[0].coverage >= 128)
563 half[0].x, half[1].x,
567 } while (--num_spans > 1);
569 if (half[0].x != spans->xmax) {
571 half[0].x, spans->xmax,
576 return CAIRO_STATUS_SUCCESS;
579 static cairo_status_t
580 i915_spans_init (i915_spans_t *spans,
583 const cairo_pattern_t *pattern,
584 cairo_antialias_t antialias,
587 const cairo_composite_rectangles_t *extents)
589 cairo_status_t status;
591 spans->device = (i915_device_t *) dst->intel.drm.base.device;
593 spans->is_bounded = extents->is_bounded;
594 if (extents->is_bounded) {
595 if (antialias == CAIRO_ANTIALIAS_NONE)
596 spans->renderer.render_rows = i915_bounded_spans_mono;
598 spans->renderer.render_rows = i915_bounded_spans;
600 spans->extents = &extents->bounded;
602 if (antialias == CAIRO_ANTIALIAS_NONE)
603 spans->renderer.render_rows = i915_unbounded_spans_mono;
605 spans->renderer.render_rows = i915_unbounded_spans;
607 spans->extents = &extents->unbounded;
609 spans->xmin = spans->extents->x;
610 spans->xmax = spans->extents->x + spans->extents->width;
612 spans->clip_region = NULL;
613 spans->need_clip_surface = FALSE;
615 cairo_region_t *clip_region = NULL;
617 status = _cairo_clip_get_region (clip, &clip_region);
618 assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
620 if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
623 spans->clip_region = clip_region;
624 spans->need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
627 spans->head.next = NULL;
628 spans->head.bo = NULL;
629 spans->head.count = 0;
630 spans->tail = &spans->head;
632 if (spans->clip_region == NULL) {
633 spans->get_rectangle = i915_emit_rectangle;
635 assert (! extents->is_bounded);
636 spans->get_rectangle = i915_accumulate_rectangle;
637 spans->head.bo = intel_bo_create (&spans->device->intel,
638 I915_VBO_SIZE, I915_VBO_SIZE,
639 FALSE, I915_TILING_NONE, 0);
640 if (unlikely (spans->head.bo == NULL))
641 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
643 spans->vbo_base = intel_bo_map (&spans->device->intel, spans->head.bo);
645 spans->vbo_offset = 0;
647 i915_shader_init (&spans->shader, dst, op, opacity);
648 if (spans->need_clip_surface)
649 i915_shader_set_clip (&spans->shader, clip);
651 status = i915_shader_acquire_pattern (&spans->shader, &spans->shader.source,
652 pattern, &extents->bounded);
653 if (unlikely (status))
656 return CAIRO_STATUS_SUCCESS;
660 i915_spans_fini (i915_spans_t *spans)
662 i915_shader_fini (&spans->shader);
664 if (spans->head.bo != NULL) {
665 struct vbo *vbo, *next;
667 intel_bo_destroy (&spans->device->intel, spans->head.bo);
668 for (vbo = spans->head.next; vbo != NULL; vbo = next) {
670 intel_bo_destroy (&spans->device->intel, vbo->bo);
677 i915_clip_and_composite_spans (i915_surface_t *dst,
679 const cairo_pattern_t *pattern,
680 cairo_antialias_t antialias,
681 i915_spans_func_t draw_func,
683 const cairo_composite_rectangles_t*extents,
688 i915_device_t *device;
689 cairo_status_t status;
692 if (i915_surface_needs_tiling (dst)) {
694 return CAIRO_INT_STATUS_UNSUPPORTED;
697 if (op == CAIRO_OPERATOR_CLEAR) {
698 pattern = &_cairo_pattern_white.base;
699 op = CAIRO_OPERATOR_DEST_OUT;
702 status = i915_spans_init (&spans, dst, op, pattern, antialias, clip, opacity, extents);
703 if (unlikely (status))
706 spans.shader.mask.base.texfmt = TEXCOORDFMT_1D;
707 spans.shader.mask.base.content = CAIRO_CONTENT_ALPHA;
708 spans.shader.mask.type.fragment = FS_SPANS;
710 status = cairo_device_acquire (dst->intel.drm.base.device);
711 if (unlikely (status))
714 if (dst->deferred_clear) {
715 status = i915_surface_clear (dst);
716 if (unlikely (status))
720 device = i915_device (dst);
721 status = i915_shader_commit (&spans.shader, device);
722 if (unlikely (status))
725 if (! spans.shader.need_combine && ! spans.need_clip_surface) {
726 switch (spans.shader.source.type.vertex) {
728 spans.span = i915_span_zero;
729 if (extents->is_bounded) {
730 if (antialias == CAIRO_ANTIALIAS_NONE)
731 spans.renderer.render_rows = i915_zero_spans_mono;
733 spans.renderer.render_rows = i915_zero_spans;
737 spans.span = i915_span_constant;
740 spans.span = i915_span_linear;
743 spans.span = i915_span_texture;
746 spans.span = i915_span_texture16;
749 spans.span = i915_span_generic;
753 spans.span = i915_span_generic;
756 status = draw_func (draw_closure, &spans.renderer, spans.extents);
757 if (spans.clip_region != NULL && status == CAIRO_STATUS_SUCCESS) {
758 i915_vbo_finish (device);
760 OUT_DWORD (_3DSTATE_SCISSOR_ENABLE_CMD | ENABLE_SCISSOR_RECT);
761 for (vbo = &spans.head; vbo != NULL; vbo = vbo->next) {
762 int i, num_rectangles;
764 /* XXX require_space & batch_flush */
766 OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S (0) | I1_LOAD_S (1) | 1);
767 i915_batch_emit_reloc (device, vbo->bo, 0,
768 I915_GEM_DOMAIN_VERTEX, 0,
770 OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
771 (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT) |
774 num_rectangles = cairo_region_num_rectangles (spans.clip_region);
775 for (i = 0; i < num_rectangles; i++) {
776 cairo_rectangle_int_t rect;
778 cairo_region_get_rectangle (spans.clip_region, i, &rect);
780 OUT_DWORD (_3DSTATE_SCISSOR_RECT_0_CMD);
781 OUT_DWORD (SCISSOR_RECT_0_XMIN (rect.x) |
782 SCISSOR_RECT_0_YMIN (rect.y));
783 OUT_DWORD (SCISSOR_RECT_0_XMAX (rect.x + rect.width) |
784 SCISSOR_RECT_0_YMAX (rect.y + rect.height));
786 OUT_DWORD (PRIM3D_RECTLIST | PRIM3D_INDIRECT_SEQUENTIAL | vbo->count);
790 OUT_DWORD (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
794 cairo_device_release (dst->intel.drm.base.device);
796 i915_spans_fini (&spans);