OSDN Git Service

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