OSDN Git Service

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