tizen 2.3.1 release
[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, unsigned flags)
161 {
162     intel_surface_t *surface = abstract_surface;
163     cairo_status_t status;
164
165     if (flags)
166         return CAIRO_STATUS_SUCCESS;
167
168     if (surface->drm.fallback == NULL)
169         return CAIRO_STATUS_SUCCESS;
170
171     /* kill any outstanding maps */
172     cairo_surface_finish (surface->drm.fallback);
173
174     status = cairo_surface_status (surface->drm.fallback);
175     cairo_surface_destroy (surface->drm.fallback);
176     surface->drm.fallback = NULL;
177
178     return status;
179 }
180
181 static cairo_int_status_t
182 intel_surface_paint (void *abstract_surface,
183                      cairo_operator_t            op,
184                      const cairo_pattern_t      *source,
185                      cairo_clip_t               *clip)
186 {
187     return _cairo_surface_paint (intel_surface_map_to_image (abstract_surface),
188                                  op, source, clip);
189 }
190
191 static cairo_int_status_t
192 intel_surface_mask (void                        *abstract_surface,
193                     cairo_operator_t             op,
194                     const cairo_pattern_t       *source,
195                     const cairo_pattern_t       *mask,
196                     cairo_clip_t                *clip)
197 {
198     return _cairo_surface_mask (intel_surface_map_to_image (abstract_surface),
199                                 op, source, mask, clip);
200 }
201
202 static cairo_int_status_t
203 intel_surface_stroke (void                      *abstract_surface,
204                       cairo_operator_t           op,
205                       const cairo_pattern_t     *source,
206                       cairo_path_fixed_t        *path,
207                       const cairo_stroke_style_t        *stroke_style,
208                       const cairo_matrix_t              *ctm,
209                       const cairo_matrix_t              *ctm_inverse,
210                       double                     tolerance,
211                       cairo_antialias_t          antialias,
212                       cairo_clip_t              *clip)
213 {
214     return _cairo_surface_stroke (intel_surface_map_to_image (abstract_surface),
215                                   op, source, path, stroke_style, ctm, ctm_inverse,
216                                   tolerance, antialias, clip);
217 }
218
219 static cairo_int_status_t
220 intel_surface_fill (void                        *abstract_surface,
221                     cairo_operator_t             op,
222                     const cairo_pattern_t       *source,
223                     cairo_path_fixed_t          *path,
224                     cairo_fill_rule_t            fill_rule,
225                     double                       tolerance,
226                     cairo_antialias_t            antialias,
227                     cairo_clip_t                *clip)
228 {
229     return _cairo_surface_fill (intel_surface_map_to_image (abstract_surface),
230                                 op, source, path, fill_rule,
231                                 tolerance, antialias, clip);
232 }
233
234 static cairo_int_status_t
235 intel_surface_glyphs (void                      *abstract_surface,
236                       cairo_operator_t           op,
237                       const cairo_pattern_t     *source,
238                       cairo_glyph_t             *glyphs,
239                       int                        num_glyphs,
240                       cairo_scaled_font_t       *scaled_font,
241                       cairo_clip_t              *clip,
242                       int *num_remaining)
243 {
244     *num_remaining = 0;
245     return _cairo_surface_show_text_glyphs (intel_surface_map_to_image (abstract_surface),
246                                             op, source,
247                                             NULL, 0,
248                                             glyphs, num_glyphs,
249                                             NULL, 0, 0,
250                                             scaled_font, clip);
251 }
252
253 static const cairo_surface_backend_t intel_surface_backend = {
254     CAIRO_SURFACE_TYPE_DRM,
255     _cairo_default_context_create,
256
257     intel_surface_create_similar,
258     intel_surface_finish,
259
260     NULL,
261     intel_surface_acquire_source_image,
262     intel_surface_release_source_image,
263
264     NULL, NULL, NULL,
265     NULL, /* composite */
266     NULL, /* fill */
267     NULL, /* trapezoids */
268     NULL, /* span */
269     NULL, /* check-span */
270
271     NULL, /* copy_page */
272     NULL, /* show_page */
273     _cairo_drm_surface_get_extents,
274     NULL, /* old-glyphs */
275     _cairo_drm_surface_get_font_options,
276
277     intel_surface_flush,
278     NULL, /* mark dirty */
279     NULL, NULL, /* font/glyph fini */
280
281     intel_surface_paint,
282     intel_surface_mask,
283     intel_surface_stroke,
284     intel_surface_fill,
285     intel_surface_glyphs,
286 };
287
288 void
289 intel_surface_init (intel_surface_t *surface,
290                     const cairo_surface_backend_t *backend,
291                     cairo_drm_device_t *device,
292                     cairo_format_t format,
293                     int width, int height)
294 {
295     _cairo_surface_init (&surface->drm.base,
296                          backend,
297                          &device->base,
298                          _cairo_content_from_format (format));
299     _cairo_drm_surface_init (&surface->drm, format, width, height);
300
301     surface->snapshot_cache_entry.hash = 0;
302 }
303
304 static cairo_surface_t *
305 intel_surface_create (cairo_drm_device_t *device,
306                       cairo_format_t format,
307                       int width, int height)
308 {
309     intel_surface_t *surface;
310     cairo_status_t status;
311
312     surface = malloc (sizeof (intel_surface_t));
313     if (unlikely (surface == NULL))
314         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
315
316     intel_surface_init (surface, &intel_surface_backend, device,
317                         format, width, height);
318
319     if (width && height) {
320         /* Vol I, p134: size restrictions for textures */
321         width  = (width  + 3) & -4;
322         height = (height + 1) & -2;
323         surface->drm.stride =
324             cairo_format_stride_for_width (surface->drm.format, width);
325         surface->drm.bo = &intel_bo_create (to_intel_device (&device->base),
326                                             surface->drm.stride * height,
327                                             surface->drm.stride * height,
328                                             TRUE, I915_TILING_NONE, surface->drm.stride)->base;
329         if (surface->drm.bo == NULL) {
330             status = _cairo_drm_surface_finish (&surface->drm);
331             free (surface);
332             return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
333         }
334     }
335
336     return &surface->drm.base;
337 }
338
339 static cairo_surface_t *
340 intel_surface_create_for_name (cairo_drm_device_t *device,
341                                unsigned int name,
342                                cairo_format_t format,
343                                int width, int height, int stride)
344 {
345     intel_surface_t *surface;
346     cairo_status_t status;
347
348     switch (format) {
349     default:
350     case CAIRO_FORMAT_INVALID:
351     case CAIRO_FORMAT_A1:
352         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
353     case CAIRO_FORMAT_ARGB32:
354     case CAIRO_FORMAT_RGB16_565:
355     case CAIRO_FORMAT_RGB24:
356     case CAIRO_FORMAT_A8:
357         break;
358     }
359
360     if (stride < cairo_format_stride_for_width (format, width))
361         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
362
363     surface = malloc (sizeof (intel_surface_t));
364     if (unlikely (surface == NULL))
365         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
366
367     intel_surface_init (surface, &intel_surface_backend,
368                         device, format, width, height);
369
370     if (width && height) {
371         surface->drm.stride = stride;
372
373         surface->drm.bo = &intel_bo_create_for_name (to_intel_device (&device->base),
374                                                       name)->base;
375         if (unlikely (surface->drm.bo == NULL)) {
376             status = _cairo_drm_surface_finish (&surface->drm);
377             free (surface);
378             return _cairo_surface_create_in_error (_cairo_error
379                                                    (CAIRO_STATUS_NO_MEMORY));
380         }
381     }
382
383     return &surface->drm.base;
384 }
385
386 static cairo_status_t
387 intel_surface_enable_scan_out (void *abstract_surface)
388 {
389     intel_surface_t *surface = abstract_surface;
390
391     if (unlikely (surface->drm.bo == NULL))
392         return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
393
394     to_intel_bo (surface->drm.bo)->tiling = I915_TILING_X;
395
396     return CAIRO_STATUS_SUCCESS;
397 }
398
399 static cairo_int_status_t
400 intel_device_throttle (cairo_drm_device_t *device)
401 {
402     intel_throttle (to_intel_device (&device->base));
403     return CAIRO_STATUS_SUCCESS;
404 }
405
406 static void
407 intel_device_destroy (void *data)
408 {
409     intel_device_t *device = data;
410
411     intel_device_fini (device);
412
413     free (data);
414 }
415
416 cairo_drm_device_t *
417 _cairo_drm_intel_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
418 {
419     intel_device_t *device;
420     cairo_status_t status;
421
422     if (! intel_info (fd, NULL))
423         return NULL;
424
425     device = malloc (sizeof (intel_device_t));
426     if (unlikely (device == NULL))
427         return (cairo_drm_device_t *) _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
428
429     status = intel_device_init (device, fd);
430     if (unlikely (status)) {
431         free (device);
432         return (cairo_drm_device_t *) _cairo_device_create_in_error (status);
433     }
434
435     device->base.surface.create = intel_surface_create;
436     device->base.surface.create_for_name = intel_surface_create_for_name;
437     device->base.surface.create_from_cacheable_image = NULL;
438     device->base.surface.flink = _cairo_drm_surface_flink;
439     device->base.surface.enable_scan_out = intel_surface_enable_scan_out;
440
441     device->base.surface.map_to_image = intel_surface_map_to_image;
442
443     device->base.device.flush = NULL;
444     device->base.device.throttle = intel_device_throttle;
445     device->base.device.destroy = intel_device_destroy;
446
447     return _cairo_drm_device_init (&device->base,
448                                    fd, dev,
449                                    vendor_id, chip_id,
450                                    MAX_SIZE);
451 }