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