OSDN Git Service

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