OSDN Git Service

minigbm: add bytes per pixel function
[android-x86/external-minigbm.git] / i915.c
1 /*
2  * Copyright 2014 The Chromium OS Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #ifdef DRV_I915
8
9 #include <errno.h>
10 #include <i915_drm.h>
11 #include <intel_bufmgr.h>
12 #include <string.h>
13 #include <sys/mman.h>
14 #include <xf86drm.h>
15
16 #include "drv_priv.h"
17 #include "helpers.h"
18 #include "util.h"
19
20 static const uint32_t tileable_formats[] = {
21         DRM_FORMAT_ARGB1555, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888,
22         DRM_FORMAT_RGB565, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB1555,
23         DRM_FORMAT_XRGB8888, DRM_FORMAT_UYVY, DRM_FORMAT_YUYV
24 };
25
26 static const uint32_t linear_only_formats[] = {
27         DRM_FORMAT_GR88, DRM_FORMAT_R8, DRM_FORMAT_YVU420,
28         DRM_FORMAT_YVU420_ANDROID
29 };
30
31 struct i915_device
32 {
33         int gen;
34         drm_intel_bufmgr *mgr;
35         uint32_t count;
36 };
37
38 struct i915_bo
39 {
40         drm_intel_bo *ibos[DRV_MAX_PLANES];
41 };
42
43 static int get_gen(int device_id)
44 {
45         const uint16_t gen3_ids[] = {0x2582, 0x2592, 0x2772, 0x27A2, 0x27AE,
46                                      0x29C2, 0x29B2, 0x29D2, 0xA001, 0xA011};
47         unsigned i;
48         for(i = 0; i < ARRAY_SIZE(gen3_ids); i++)
49                 if (gen3_ids[i] == device_id)
50                         return 3;
51
52         return 4;
53 }
54
55 static int i915_add_kms_item(struct driver *drv, const struct kms_item *item)
56 {
57         uint32_t i;
58         struct combination *combo;
59
60         /*
61          * Older hardware can't scanout Y-tiled formats. Newer devices can, and
62          * report this functionality via format modifiers.
63          */
64         for (i = 0; i < drv->backend->combos.size; i++) {
65                 combo = &drv->backend->combos.data[i];
66                 if (combo->format == item->format) {
67                         if ((combo->metadata.tiling == I915_TILING_Y &&
68                             item->modifier == I915_FORMAT_MOD_Y_TILED) ||
69                             (combo->metadata.tiling == I915_TILING_X &&
70                             item->modifier == I915_FORMAT_MOD_X_TILED)) {
71                                 combo->metadata.modifier = item->modifier;
72                                 combo->usage |= item->usage;
73                         } else if (combo->metadata.tiling != I915_TILING_Y) {
74                                 combo->usage |= item->usage;
75                         }
76                 }
77         }
78
79         return 0;
80 }
81
82 static int i915_add_combinations(struct driver *drv)
83 {
84         int ret;
85         uint32_t i, num_items;
86         struct kms_item *items;
87         struct format_metadata metadata;
88         uint64_t flags = BO_COMMON_USE_MASK;
89
90         metadata.tiling = I915_TILING_NONE;
91         metadata.priority = 1;
92         metadata.modifier = DRM_FORMAT_MOD_NONE;
93
94         ret = drv_add_combinations(drv, linear_only_formats,
95                                    ARRAY_SIZE(linear_only_formats), &metadata,
96                                    flags);
97         if (ret)
98                 return ret;
99
100         ret = drv_add_combinations(drv, tileable_formats,
101                                    ARRAY_SIZE(tileable_formats), &metadata,
102                                    flags);
103         if (ret)
104                 return ret;
105
106         drv_modify_combination(drv, DRM_FORMAT_XRGB8888, &metadata,
107                                BO_USE_CURSOR | BO_USE_SCANOUT);
108         drv_modify_combination(drv, DRM_FORMAT_ARGB8888, &metadata,
109                                BO_USE_CURSOR | BO_USE_SCANOUT);
110
111         flags &= ~BO_USE_SW_WRITE_OFTEN;
112         flags &= ~BO_USE_SW_READ_OFTEN;
113         flags &= ~BO_USE_LINEAR;
114
115         metadata.tiling = I915_TILING_X;
116         metadata.priority = 2;
117
118         ret = drv_add_combinations(drv, tileable_formats,
119                                    ARRAY_SIZE(tileable_formats), &metadata,
120                                    flags);
121         if (ret)
122                 return ret;
123
124         metadata.tiling = I915_TILING_Y;
125         metadata.priority = 3;
126
127         ret = drv_add_combinations(drv, tileable_formats,
128                                    ARRAY_SIZE(tileable_formats), &metadata,
129                                    flags);
130         if (ret)
131                 return ret;
132
133         items = drv_query_kms(drv, &num_items);
134         if (!items || !num_items)
135                 return 0;
136
137         for (i = 0; i < num_items; i++) {
138                 ret = i915_add_kms_item(drv, &items[i]);
139                 if (ret) {
140                         free(items);
141                         return ret;
142                 }
143         }
144
145         free(items);
146         return 0;
147 }
148
149 static void i915_align_dimensions(struct driver *drv, uint32_t tiling_mode,
150                                   uint32_t *width, uint32_t *height, int bpp)
151 {
152         struct i915_device *i915_dev = (struct i915_device *)drv->priv;
153         uint32_t width_alignment = 4, height_alignment = 4;
154
155         switch (tiling_mode) {
156         default:
157         case I915_TILING_NONE:
158                 width_alignment = 64 / bpp;
159                 break;
160
161         case I915_TILING_X:
162                 width_alignment = 512 / bpp;
163                 height_alignment = 8;
164                 break;
165
166         case I915_TILING_Y:
167                 if (i915_dev->gen == 3) {
168                         width_alignment = 512 / bpp;
169                         height_alignment = 8;
170                 } else  {
171                         width_alignment = 128 / bpp;
172                         height_alignment = 32;
173                 }
174                 break;
175         }
176
177         if (i915_dev->gen > 3) {
178                 *width = ALIGN(*width, width_alignment);
179                 *height = ALIGN(*height, height_alignment);
180         } else {
181                 uint32_t w;
182                 for (w = width_alignment; w < *width;  w <<= 1)
183                         ;
184                 *width = w;
185                 *height = ALIGN(*height, height_alignment);
186         }
187 }
188
189 static int i915_verify_dimensions(struct driver *drv, uint32_t stride,
190                                   uint32_t height)
191 {
192         struct i915_device *i915_dev = (struct i915_device *)drv->priv;
193         if (i915_dev->gen <= 3 && stride > 8192)
194                 return 0;
195
196         return 1;
197 }
198
199 static int i915_init(struct driver *drv)
200 {
201         struct i915_device *i915_dev;
202         drm_i915_getparam_t get_param;
203         int device_id;
204         int ret;
205
206         i915_dev = calloc(1, sizeof(*i915_dev));
207         if (!i915_dev)
208                 return -1;
209
210         memset(&get_param, 0, sizeof(get_param));
211         get_param.param = I915_PARAM_CHIPSET_ID;
212         get_param.value = &device_id;
213         ret = drmIoctl(drv->fd, DRM_IOCTL_I915_GETPARAM, &get_param);
214         if (ret) {
215                 fprintf(stderr, "drv: DRM_IOCTL_I915_GETPARAM failed\n");
216                 free(i915_dev);
217                 return -EINVAL;
218         }
219
220         i915_dev->gen = get_gen(device_id);
221         i915_dev->count = 0;
222
223         i915_dev->mgr = drm_intel_bufmgr_gem_init(drv->fd, 16 * 1024);
224         if (!i915_dev->mgr) {
225                 fprintf(stderr, "drv: drm_intel_bufmgr_gem_init failed\n");
226                 free(i915_dev);
227                 return -EINVAL;
228         }
229
230         drv->priv = i915_dev;
231
232         return i915_add_combinations(drv);
233 }
234
235 static void i915_close(struct driver *drv)
236 {
237         struct i915_device *i915_dev = drv->priv;
238         drm_intel_bufmgr_destroy(i915_dev->mgr);
239         free(i915_dev);
240         drv->priv = NULL;
241 }
242
243 static int i915_bo_create(struct bo *bo, uint32_t width, uint32_t height,
244                           uint32_t format, uint32_t flags)
245 {
246         int ret;
247         size_t plane;
248         char name[20];
249         uint32_t tiling_mode;
250         struct i915_bo *i915_bo;
251
252         int bpp = drv_stride_from_format(format, 1, 0);
253         struct i915_device *i915_dev = (struct i915_device *)bo->drv->priv;
254
255         if (flags & (BO_USE_CURSOR | BO_USE_LINEAR |
256                      BO_USE_SW_READ_OFTEN | BO_USE_SW_WRITE_OFTEN))
257                 tiling_mode = I915_TILING_NONE;
258         else if (flags & BO_USE_SCANOUT)
259                 tiling_mode = I915_TILING_X;
260         else
261                 tiling_mode = I915_TILING_Y;
262
263         /*
264          * Align the Y plane to 128 bytes so the chroma planes would be aligned
265          * to 64 byte boundaries. This is an Intel HW requirement.
266          */
267         if (format == DRM_FORMAT_YVU420 ||
268             format == DRM_FORMAT_YVU420_ANDROID) {
269                 width = ALIGN(width, 128);
270                 tiling_mode = I915_TILING_NONE;
271         }
272
273         i915_align_dimensions(bo->drv, tiling_mode, &width, &height, bpp);
274         drv_bo_from_format(bo, width, height, format);
275
276         if (!i915_verify_dimensions(bo->drv, bo->strides[0], height))
277                 return -EINVAL;
278
279         snprintf(name, sizeof(name), "i915-buffer-%u", i915_dev->count);
280         i915_dev->count++;
281
282         i915_bo = calloc(1, sizeof(*i915_bo));
283         if (!i915_bo)
284                 return -ENOMEM;
285
286         bo->priv = i915_bo;
287
288         i915_bo->ibos[0] = drm_intel_bo_alloc(i915_dev->mgr, name,
289                                               bo->total_size, 0);
290         if (!i915_bo->ibos[0]) {
291                 fprintf(stderr, "drv: drm_intel_bo_alloc failed");
292                 free(i915_bo);
293                 bo->priv = NULL;
294                 return -ENOMEM;
295         }
296
297         for (plane = 0; plane < bo->num_planes; plane++) {
298                 if (plane > 0)
299                         drm_intel_bo_reference(i915_bo->ibos[0]);
300
301                 bo->handles[plane].u32 = i915_bo->ibos[0]->handle;
302                 i915_bo->ibos[plane] = i915_bo->ibos[0];
303         }
304
305         bo->tiling = tiling_mode;
306
307         ret = drm_intel_bo_set_tiling(i915_bo->ibos[0], &bo->tiling,
308                                       bo->strides[0]);
309
310         if (ret || bo->tiling != tiling_mode) {
311                 fprintf(stderr, "drv: drm_intel_gem_bo_set_tiling failed "
312                         "errno=%x, stride=%x\n", errno, bo->strides[0]);
313                 /* Calls i915 bo destroy. */
314                 bo->drv->backend->bo_destroy(bo);
315                 return -errno;
316         }
317
318         return 0;
319 }
320
321 static int i915_bo_destroy(struct bo *bo)
322 {
323         size_t plane;
324         struct i915_bo *i915_bo = bo->priv;
325
326         for (plane = 0; plane < bo->num_planes; plane++)
327                 drm_intel_bo_unreference(i915_bo->ibos[plane]);
328
329         free(i915_bo);
330         bo->priv = NULL;
331
332         return 0;
333 }
334
335 static int i915_bo_import(struct bo *bo, struct drv_import_fd_data *data)
336 {
337         size_t plane;
338         uint32_t swizzling;
339         struct i915_bo *i915_bo;
340         struct i915_device *i915_dev = bo->drv->priv;
341
342         i915_bo = calloc(1, sizeof(*i915_bo));
343         if (!i915_bo)
344                 return -ENOMEM;
345
346         bo->priv = i915_bo;
347
348         /*
349          * When self-importing, libdrm_intel increments the reference count
350          * on the drm_intel_bo. It also returns the same drm_intel_bo per GEM
351          * handle. Thus, we don't need to increase the reference count
352          * (i.e, drv_increment_reference_count) when importing with this
353          * backend.
354          */
355         for (plane = 0; plane < bo->num_planes; plane++) {
356
357                 i915_bo->ibos[plane] = drm_intel_bo_gem_create_from_prime(i915_dev->mgr,
358                                  data->fds[plane], data->sizes[plane]);
359
360                 if (!i915_bo->ibos[plane]) {
361                         /*
362                          * Need to call GEM close on planes that were opened,
363                          * if any. Adjust the num_planes variable to be the
364                          * plane that failed, so GEM close will be called on
365                          * planes before that plane.
366                          */
367                         bo->num_planes = plane;
368                         i915_bo_destroy(bo);
369                         fprintf(stderr, "drv: i915: failed to import failed");
370                         return -EINVAL;
371                 }
372
373                 bo->handles[plane].u32 = i915_bo->ibos[plane]->handle;
374         }
375
376         if (drm_intel_bo_get_tiling(i915_bo->ibos[0], &bo->tiling,
377                                     &swizzling)) {
378                 fprintf(stderr, "drv: drm_intel_bo_get_tiling failed");
379                 i915_bo_destroy(bo);
380                 return -EINVAL;
381         }
382
383         return 0;
384 }
385
386 static void *i915_bo_map(struct bo *bo, struct map_info *data, size_t plane)
387 {
388         int ret;
389         struct i915_bo *i915_bo = bo->priv;
390
391         if (bo->tiling == I915_TILING_NONE)
392                 /* TODO(gsingh): use bo_map flags to determine if we should
393                  * enable writing.
394                  */
395                 ret = drm_intel_bo_map(i915_bo->ibos[0], 1);
396         else
397                 ret = drm_intel_gem_bo_map_gtt(i915_bo->ibos[0]);
398
399         if (ret) {
400                 fprintf(stderr, "drv: i915_bo_map failed.");
401                 return MAP_FAILED;
402         }
403
404         return i915_bo->ibos[0]->virtual;
405 }
406
407 static int i915_bo_unmap(struct bo *bo, struct map_info *data)
408 {
409         int ret;
410         struct i915_bo *i915_bo = bo->priv;
411
412         if (bo->tiling == I915_TILING_NONE)
413                 ret = drm_intel_bo_unmap(i915_bo->ibos[0]);
414         else
415                 ret = drm_intel_gem_bo_unmap_gtt(i915_bo->ibos[0]);
416
417         return ret;
418 }
419
420 static uint32_t i915_resolve_format(uint32_t format)
421 {
422         switch (format) {
423         case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
424                 /*HACK: See b/28671744 */
425                 return DRM_FORMAT_XBGR8888;
426         case DRM_FORMAT_FLEX_YCbCr_420_888:
427                 return DRM_FORMAT_YVU420_ANDROID;
428         default:
429                 return format;
430         }
431 }
432
433 struct backend backend_i915 =
434 {
435         .name = "i915",
436         .init = i915_init,
437         .close = i915_close,
438         .bo_create = i915_bo_create,
439         .bo_destroy = i915_bo_destroy,
440         .bo_import = i915_bo_import,
441         .bo_map = i915_bo_map,
442         .bo_unmap = i915_bo_unmap,
443         .resolve_format = i915_resolve_format,
444 };
445
446 #endif