OSDN Git Service

4acceb47fcfa560ac5be6c8367465f7bea4d5ceb
[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         i915_align_dimensions(bo->drv, tiling_mode, &width, &height, bpp);
264         drv_bo_from_format(bo, width, height, format);
265
266         if (!i915_verify_dimensions(bo->drv, bo->strides[0], height))
267                 return -EINVAL;
268
269         snprintf(name, sizeof(name), "i915-buffer-%u", i915_dev->count);
270         i915_dev->count++;
271
272         i915_bo = calloc(1, sizeof(*i915_bo));
273         if (!i915_bo)
274                 return -ENOMEM;
275
276         bo->priv = i915_bo;
277
278         i915_bo->ibos[0] = drm_intel_bo_alloc(i915_dev->mgr, name,
279                                               bo->total_size, 0);
280         if (!i915_bo->ibos[0]) {
281                 fprintf(stderr, "drv: drm_intel_bo_alloc failed");
282                 free(i915_bo);
283                 bo->priv = NULL;
284                 return -ENOMEM;
285         }
286
287         for (plane = 0; plane < bo->num_planes; plane++) {
288                 if (plane > 0)
289                         drm_intel_bo_reference(i915_bo->ibos[0]);
290
291                 bo->handles[plane].u32 = i915_bo->ibos[0]->handle;
292                 i915_bo->ibos[plane] = i915_bo->ibos[0];
293         }
294
295         bo->tiling = tiling_mode;
296
297         ret = drm_intel_bo_set_tiling(i915_bo->ibos[0], &bo->tiling,
298                                       bo->strides[0]);
299
300         if (ret || bo->tiling != tiling_mode) {
301                 fprintf(stderr, "drv: drm_intel_gem_bo_set_tiling failed "
302                         "errno=%x, stride=%x\n", errno, bo->strides[0]);
303                 /* Calls i915 bo destroy. */
304                 bo->drv->backend->bo_destroy(bo);
305                 return -errno;
306         }
307
308         return 0;
309 }
310
311 static int i915_bo_destroy(struct bo *bo)
312 {
313         size_t plane;
314         struct i915_bo *i915_bo = bo->priv;
315
316         for (plane = 0; plane < bo->num_planes; plane++)
317                 drm_intel_bo_unreference(i915_bo->ibos[plane]);
318
319         free(i915_bo);
320         bo->priv = NULL;
321
322         return 0;
323 }
324
325 static int i915_bo_import(struct bo *bo, struct drv_import_fd_data *data)
326 {
327         size_t plane;
328         uint32_t swizzling;
329         struct i915_bo *i915_bo;
330         struct i915_device *i915_dev = bo->drv->priv;
331
332         i915_bo = calloc(1, sizeof(*i915_bo));
333         if (!i915_bo)
334                 return -ENOMEM;
335
336         bo->priv = i915_bo;
337
338         /*
339          * When self-importing, libdrm_intel increments the reference count
340          * on the drm_intel_bo. It also returns the same drm_intel_bo per GEM
341          * handle. Thus, we don't need to increase the reference count
342          * (i.e, drv_increment_reference_count) when importing with this
343          * backend.
344          */
345         for (plane = 0; plane < bo->num_planes; plane++) {
346
347                 i915_bo->ibos[plane] = drm_intel_bo_gem_create_from_prime(i915_dev->mgr,
348                                  data->fds[plane], data->sizes[plane]);
349
350                 if (!i915_bo->ibos[plane]) {
351                         /*
352                          * Need to call GEM close on planes that were opened,
353                          * if any. Adjust the num_planes variable to be the
354                          * plane that failed, so GEM close will be called on
355                          * planes before that plane.
356                          */
357                         bo->num_planes = plane;
358                         i915_bo_destroy(bo);
359                         fprintf(stderr, "drv: i915: failed to import failed");
360                         return -EINVAL;
361                 }
362
363                 bo->handles[plane].u32 = i915_bo->ibos[plane]->handle;
364         }
365
366         if (drm_intel_bo_get_tiling(i915_bo->ibos[0], &bo->tiling,
367                                     &swizzling)) {
368                 fprintf(stderr, "drv: drm_intel_bo_get_tiling failed");
369                 i915_bo_destroy(bo);
370                 return -EINVAL;
371         }
372
373         return 0;
374 }
375
376 static void *i915_bo_map(struct bo *bo, struct map_info *data, size_t plane)
377 {
378         int ret;
379         struct i915_bo *i915_bo = bo->priv;
380
381         if (bo->tiling == I915_TILING_NONE)
382                 /* TODO(gsingh): use bo_map flags to determine if we should
383                  * enable writing.
384                  */
385                 ret = drm_intel_bo_map(i915_bo->ibos[0], 1);
386         else
387                 ret = drm_intel_gem_bo_map_gtt(i915_bo->ibos[0]);
388
389         if (ret) {
390                 fprintf(stderr, "drv: i915_bo_map failed.");
391                 return MAP_FAILED;
392         }
393
394         return i915_bo->ibos[0]->virtual;
395 }
396
397 static int i915_bo_unmap(struct bo *bo, struct map_info *data)
398 {
399         int ret;
400         struct i915_bo *i915_bo = bo->priv;
401
402         if (bo->tiling == I915_TILING_NONE)
403                 ret = drm_intel_bo_unmap(i915_bo->ibos[0]);
404         else
405                 ret = drm_intel_gem_bo_unmap_gtt(i915_bo->ibos[0]);
406
407         return ret;
408 }
409
410 static uint32_t i915_resolve_format(uint32_t format)
411 {
412         switch (format) {
413         case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
414                 /*HACK: See b/28671744 */
415                 return DRM_FORMAT_XBGR8888;
416         case DRM_FORMAT_FLEX_YCbCr_420_888:
417                 return DRM_FORMAT_YVU420_ANDROID;
418         default:
419                 return format;
420         }
421 }
422
423 struct backend backend_i915 =
424 {
425         .name = "i915",
426         .init = i915_init,
427         .close = i915_close,
428         .bo_create = i915_bo_create,
429         .bo_destroy = i915_bo_destroy,
430         .bo_import = i915_bo_import,
431         .bo_map = i915_bo_map,
432         .bo_unmap = i915_bo_unmap,
433         .resolve_format = i915_resolve_format,
434 };
435
436 #endif