OSDN Git Service

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