1 /* Cairo - a vector graphics library with display and print output
2 *
3 * Copyright © 2009 Chris Wilson
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 */
29
30 #include "cairoint.h"
31
32 #include "cairo-drm-private.h"
33 #include "cairo-drm-intel-private.h"
34
35 #include "cairo-default-context-private.h"
36 #include "cairo-error-private.h"
37 #include "cairo-image-surface-private.h"
38
39 /* Basic generic/stub surface for intel chipsets */
40
41 #define MAX_SIZE 2048
42
43 static cairo_surface_t *
intel_surface_create_similar(void * abstract_surface,cairo_content_t content,int width,int height)44 intel_surface_create_similar (void *abstract_surface,
45 cairo_content_t content,
46 int width,
47 int height)
48 {
49 return cairo_image_surface_create (_cairo_format_from_content (content),
50 width, height);
51 }
52
53 cairo_status_t
intel_surface_finish(void * abstract_surface)54 intel_surface_finish (void *abstract_surface)
55 {
56 intel_surface_t *surface = abstract_surface;
57
58 intel_bo_in_flight_add (to_intel_device (surface->drm.base.device),
59 to_intel_bo (surface->drm.bo));
60 return _cairo_drm_surface_finish (&surface->drm);
61 }
62
63 static void
surface_finish_and_destroy(cairo_surface_t * surface)64 surface_finish_and_destroy (cairo_surface_t *surface)
65 {
66 cairo_surface_finish (surface);
67 cairo_surface_destroy (surface);
68 }
69
70 cairo_status_t
intel_surface_acquire_source_image(void * abstract_surface,cairo_image_surface_t ** image_out,void ** image_extra)71 intel_surface_acquire_source_image (void *abstract_surface,
72 cairo_image_surface_t **image_out,
73 void **image_extra)
74 {
75 intel_surface_t *surface = abstract_surface;
76 cairo_surface_t *image;
77 cairo_status_t status;
78 void *ptr;
79
80 if (surface->drm.fallback != NULL) {
81 image = surface->drm.fallback;
82 goto DONE;
83 }
84
85 image = _cairo_surface_has_snapshot (&surface->drm.base,
86 &_cairo_image_surface_backend);
87 if (image != NULL)
88 goto DONE;
89
90 if (surface->drm.base.backend->flush != NULL) {
91 status = surface->drm.base.backend->flush (surface);
92 if (unlikely (status))
93 return status;
94 }
95
96 ptr = intel_bo_map (to_intel_device (surface->drm.base.device),
97 to_intel_bo (surface->drm.bo));
98 if (unlikely (ptr == NULL))
99 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
100
101 image = cairo_image_surface_create_for_data (ptr,
102 surface->drm.format,
103 surface->drm.width,
104 surface->drm.height,
105 surface->drm.stride);
106 if (unlikely (image->status))
107 return image->status;
108
109 _cairo_surface_attach_snapshot (&surface->drm.base, image, surface_finish_and_destroy);
110
111 DONE:
112 *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
113 *image_extra = NULL;
114 return CAIRO_STATUS_SUCCESS;
115 }
116
117 void
intel_surface_release_source_image(void * abstract_surface,cairo_image_surface_t * image,void * image_extra)118 intel_surface_release_source_image (void *abstract_surface,
119 cairo_image_surface_t *image,
120 void *image_extra)
121 {
122 cairo_surface_destroy (&image->base);
123 }
124
125 cairo_surface_t *
intel_surface_map_to_image(void * abstract_surface)126 intel_surface_map_to_image (void *abstract_surface)
127 {
128 intel_surface_t *surface = abstract_surface;
129
130 if (surface->drm.fallback == NULL) {
131 cairo_surface_t *image;
132 cairo_status_t status;
133 void *ptr;
134
135 if (surface->drm.base.backend->flush != NULL) {
136 status = surface->drm.base.backend->flush (surface);
137 if (unlikely (status))
138 return _cairo_surface_create_in_error (status);
139 }
140
141 ptr = intel_bo_map (to_intel_device (surface->drm.base.device),
142 to_intel_bo (surface->drm.bo));
143 if (unlikely (ptr == NULL))
144 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
145
146 image = cairo_image_surface_create_for_data (ptr,
147 surface->drm.format,
148 surface->drm.width,
149 surface->drm.height,
150 surface->drm.stride);
151 if (unlikely (image->status))
152 return image;
153
154 surface->drm.fallback = image;
155 }
156
157 return surface->drm.fallback;
158 }
159
160 cairo_status_t
intel_surface_flush(void * abstract_surface,unsigned flags)161 intel_surface_flush (void *abstract_surface, unsigned flags)
162 {
163 intel_surface_t *surface = abstract_surface;
164 cairo_status_t status;
165
166 if (flags)
167 return CAIRO_STATUS_SUCCESS;
168
169 if (surface->drm.fallback == NULL)
170 return CAIRO_STATUS_SUCCESS;
171
172 /* kill any outstanding maps */
173 cairo_surface_finish (surface->drm.fallback);
174
175 status = cairo_surface_status (surface->drm.fallback);
176 cairo_surface_destroy (surface->drm.fallback);
177 surface->drm.fallback = NULL;
178
179 return status;
180 }
181
182 static cairo_int_status_t
intel_surface_paint(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_clip_t * clip)183 intel_surface_paint (void *abstract_surface,
184 cairo_operator_t op,
185 const cairo_pattern_t *source,
186 cairo_clip_t *clip)
187 {
188 return _cairo_surface_paint (intel_surface_map_to_image (abstract_surface),
189 op, source, clip);
190 }
191
192 static cairo_int_status_t
intel_surface_mask(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_pattern_t * mask,cairo_clip_t * clip)193 intel_surface_mask (void *abstract_surface,
194 cairo_operator_t op,
195 const cairo_pattern_t *source,
196 const cairo_pattern_t *mask,
197 cairo_clip_t *clip)
198 {
199 return _cairo_surface_mask (intel_surface_map_to_image (abstract_surface),
200 op, source, mask, clip);
201 }
202
203 static cairo_int_status_t
intel_surface_stroke(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,const cairo_stroke_style_t * stroke_style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)204 intel_surface_stroke (void *abstract_surface,
205 cairo_operator_t op,
206 const cairo_pattern_t *source,
207 cairo_path_fixed_t *path,
208 const cairo_stroke_style_t *stroke_style,
209 const cairo_matrix_t *ctm,
210 const cairo_matrix_t *ctm_inverse,
211 double tolerance,
212 cairo_antialias_t antialias,
213 cairo_clip_t *clip)
214 {
215 return _cairo_surface_stroke (intel_surface_map_to_image (abstract_surface),
216 op, source, path, stroke_style, ctm, ctm_inverse,
217 tolerance, antialias, clip);
218 }
219
220 static cairo_int_status_t
intel_surface_fill(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)221 intel_surface_fill (void *abstract_surface,
222 cairo_operator_t op,
223 const cairo_pattern_t *source,
224 cairo_path_fixed_t *path,
225 cairo_fill_rule_t fill_rule,
226 double tolerance,
227 cairo_antialias_t antialias,
228 cairo_clip_t *clip)
229 {
230 return _cairo_surface_fill (intel_surface_map_to_image (abstract_surface),
231 op, source, path, fill_rule,
232 tolerance, antialias, clip);
233 }
234
235 static cairo_int_status_t
intel_surface_glyphs(void * abstract_surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_glyph_t * glyphs,int num_glyphs,cairo_scaled_font_t * scaled_font,cairo_clip_t * clip,int * num_remaining)236 intel_surface_glyphs (void *abstract_surface,
237 cairo_operator_t op,
238 const cairo_pattern_t *source,
239 cairo_glyph_t *glyphs,
240 int num_glyphs,
241 cairo_scaled_font_t *scaled_font,
242 cairo_clip_t *clip,
243 int *num_remaining)
244 {
245 *num_remaining = 0;
246 return _cairo_surface_show_text_glyphs (intel_surface_map_to_image (abstract_surface),
247 op, source,
248 NULL, 0,
249 glyphs, num_glyphs,
250 NULL, 0, 0,
251 scaled_font, clip);
252 }
253
254 static const cairo_surface_backend_t intel_surface_backend = {
255 CAIRO_SURFACE_TYPE_DRM,
256 _cairo_default_context_create,
257
258 intel_surface_create_similar,
259 intel_surface_finish,
260
261 NULL,
262 intel_surface_acquire_source_image,
263 intel_surface_release_source_image,
264
265 NULL, NULL, NULL,
266 NULL, /* composite */
267 NULL, /* fill */
268 NULL, /* trapezoids */
269 NULL, /* span */
270 NULL, /* check-span */
271
272 NULL, /* copy_page */
273 NULL, /* show_page */
274 _cairo_drm_surface_get_extents,
275 NULL, /* old-glyphs */
276 _cairo_drm_surface_get_font_options,
277
278 intel_surface_flush,
279 NULL, /* mark dirty */
280 NULL, NULL, /* font/glyph fini */
281
282 intel_surface_paint,
283 intel_surface_mask,
284 intel_surface_stroke,
285 intel_surface_fill,
286 intel_surface_glyphs,
287 };
288
289 void
intel_surface_init(intel_surface_t * surface,const cairo_surface_backend_t * backend,cairo_drm_device_t * device,cairo_format_t format,int width,int height)290 intel_surface_init (intel_surface_t *surface,
291 const cairo_surface_backend_t *backend,
292 cairo_drm_device_t *device,
293 cairo_format_t format,
294 int width, int height)
295 {
296 _cairo_surface_init (&surface->drm.base,
297 backend,
298 &device->base,
299 _cairo_content_from_format (format),
300 FALSE);
301
302 _cairo_drm_surface_init (&surface->drm, format, width, height);
303
304 surface->snapshot_cache_entry.hash = 0;
305 }
306
307 static cairo_surface_t *
intel_surface_create(cairo_drm_device_t * device,cairo_format_t format,int width,int height)308 intel_surface_create (cairo_drm_device_t *device,
309 cairo_format_t format,
310 int width, int height)
311 {
312 intel_surface_t *surface;
313 cairo_status_t status;
314
315 surface = _cairo_malloc (sizeof (intel_surface_t));
316 if (unlikely (surface == NULL))
317 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
318
319 intel_surface_init (surface, &intel_surface_backend, device,
320 format, width, height);
321
322 if (width && height) {
323 /* Vol I, p134: size restrictions for textures */
324 width = (width + 3) & -4;
325 height = (height + 1) & -2;
326 surface->drm.stride =
327 cairo_format_stride_for_width (surface->drm.format, width);
328 surface->drm.bo = &intel_bo_create (to_intel_device (&device->base),
329 surface->drm.stride * height,
330 surface->drm.stride * height,
331 TRUE, I915_TILING_NONE, surface->drm.stride)->base;
332 if (surface->drm.bo == NULL) {
333 status = _cairo_drm_surface_finish (&surface->drm);
334 free (surface);
335 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
336 }
337 }
338
339 return &surface->drm.base;
340 }
341
342 static cairo_surface_t *
intel_surface_create_for_name(cairo_drm_device_t * device,unsigned int name,cairo_format_t format,int width,int height,int stride)343 intel_surface_create_for_name (cairo_drm_device_t *device,
344 unsigned int name,
345 cairo_format_t format,
346 int width, int height, int stride)
347 {
348 intel_surface_t *surface;
349 cairo_status_t status;
350
351 switch (format) {
352 default:
353 case CAIRO_FORMAT_INVALID:
354 case CAIRO_FORMAT_A1:
355 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
356 case CAIRO_FORMAT_ARGB32:
357 case CAIRO_FORMAT_RGB16_565:
358 case CAIRO_FORMAT_RGB24:
359 case CAIRO_FORMAT_A8:
360 break;
361 }
362
363 if (stride < cairo_format_stride_for_width (format, width))
364 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
365
366 surface = _cairo_malloc (sizeof (intel_surface_t));
367 if (unlikely (surface == NULL))
368 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
369
370 intel_surface_init (surface, &intel_surface_backend,
371 device, format, width, height);
372
373 if (width && height) {
374 surface->drm.stride = stride;
375
376 surface->drm.bo = &intel_bo_create_for_name (to_intel_device (&device->base),
377 name)->base;
378 if (unlikely (surface->drm.bo == NULL)) {
379 status = _cairo_drm_surface_finish (&surface->drm);
380 free (surface);
381 return _cairo_surface_create_in_error (_cairo_error
382 (CAIRO_STATUS_NO_MEMORY));
383 }
384 }
385
386 return &surface->drm.base;
387 }
388
389 static cairo_status_t
intel_surface_enable_scan_out(void * abstract_surface)390 intel_surface_enable_scan_out (void *abstract_surface)
391 {
392 intel_surface_t *surface = abstract_surface;
393
394 if (unlikely (surface->drm.bo == NULL))
395 return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
396
397 to_intel_bo (surface->drm.bo)->tiling = I915_TILING_X;
398
399 return CAIRO_STATUS_SUCCESS;
400 }
401
402 static cairo_int_status_t
intel_device_throttle(cairo_drm_device_t * device)403 intel_device_throttle (cairo_drm_device_t *device)
404 {
405 intel_throttle (to_intel_device (&device->base));
406 return CAIRO_STATUS_SUCCESS;
407 }
408
409 static void
intel_device_destroy(void * data)410 intel_device_destroy (void *data)
411 {
412 intel_device_t *device = data;
413
414 intel_device_fini (device);
415
416 free (data);
417 }
418
419 cairo_drm_device_t *
_cairo_drm_intel_device_create(int fd,dev_t dev,int vendor_id,int chip_id)420 _cairo_drm_intel_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
421 {
422 intel_device_t *device;
423 cairo_status_t status;
424
425 if (! intel_info (fd, NULL))
426 return NULL;
427
428 device = _cairo_malloc (sizeof (intel_device_t));
429 if (unlikely (device == NULL))
430 return (cairo_drm_device_t *) _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
431
432 status = intel_device_init (device, fd);
433 if (unlikely (status)) {
434 free (device);
435 return (cairo_drm_device_t *) _cairo_device_create_in_error (status);
436 }
437
438 device->base.surface.create = intel_surface_create;
439 device->base.surface.create_for_name = intel_surface_create_for_name;
440 device->base.surface.create_from_cacheable_image = NULL;
441 device->base.surface.flink = _cairo_drm_surface_flink;
442 device->base.surface.enable_scan_out = intel_surface_enable_scan_out;
443
444 device->base.surface.map_to_image = intel_surface_map_to_image;
445
446 device->base.device.flush = NULL;
447 device->base.device.throttle = intel_device_throttle;
448 device->base.device.destroy = intel_device_destroy;
449
450 return _cairo_drm_device_init (&device->base,
451 fd, dev,
452 vendor_id, chip_id,
453 MAX_SIZE);
454 }
455