blob: 3040619848e27cbf9b98904e7a506c6b36653a87 [file] [log] [blame]
Stéphane Marchesin25a26062014-09-12 16:18:59 -07001/*
Daniele Castagna7a755de2016-12-16 17:32:30 -05002 * Copyright 2014 The Chromium OS Authors. All rights reserved.
Stéphane Marchesin25a26062014-09-12 16:18:59 -07003 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Gurchetan Singh46faf6b2016-08-05 14:40:07 -07007#ifdef DRV_I915
Stéphane Marchesin25a26062014-09-12 16:18:59 -07008
9#include <errno.h>
Gurchetan Singh82a8eed2017-01-03 13:01:37 -080010#include <i915_drm.h>
11#include <intel_bufmgr.h>
Stéphane Marchesin25a26062014-09-12 16:18:59 -070012#include <string.h>
Gurchetan Singhef920532016-08-12 16:38:25 -070013#include <sys/mman.h>
Stéphane Marchesin25a26062014-09-12 16:18:59 -070014#include <xf86drm.h>
Stéphane Marchesin25a26062014-09-12 16:18:59 -070015
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070016#include "drv_priv.h"
Stéphane Marchesin25a26062014-09-12 16:18:59 -070017#include "helpers.h"
18#include "util.h"
19
Gurchetan Singh6b41fb52017-03-01 20:14:39 -080020static 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
26static const uint32_t linear_only_formats[] = {
27 DRM_FORMAT_GR88, DRM_FORMAT_R8, DRM_FORMAT_YVU420
Gurchetan Singh179687e2016-10-28 10:07:35 -070028};
29
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070030struct i915_device
Stéphane Marchesin25a26062014-09-12 16:18:59 -070031{
32 int gen;
Gurchetan Singh82a8eed2017-01-03 13:01:37 -080033 drm_intel_bufmgr *mgr;
34 uint32_t count;
35};
36
37struct i915_bo
38{
39 drm_intel_bo *ibos[DRV_MAX_PLANES];
Stéphane Marchesin25a26062014-09-12 16:18:59 -070040};
41
Stéphane Marchesin25a26062014-09-12 16:18:59 -070042static int get_gen(int device_id)
43{
Stéphane Marchesinec88e892015-11-03 16:14:59 -080044 const uint16_t gen3_ids[] = {0x2582, 0x2592, 0x2772, 0x27A2, 0x27AE,
45 0x29C2, 0x29B2, 0x29D2, 0xA001, 0xA011};
Stéphane Marchesina39dfde2014-09-15 15:38:25 -070046 unsigned i;
Stéphane Marchesin25a26062014-09-12 16:18:59 -070047 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
Gurchetan Singh6b41fb52017-03-01 20:14:39 -080054static 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
81static 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
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700148static void i915_align_dimensions(struct driver *drv, uint32_t tiling_mode,
Stéphane Marchesinec88e892015-11-03 16:14:59 -0800149 uint32_t *width, uint32_t *height, int bpp)
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700150{
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800151 struct i915_device *i915_dev = (struct i915_device *)drv->priv;
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800152 uint32_t width_alignment = 4, height_alignment = 4;
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700153
Gurchetan Singhd6fb5772016-08-29 19:13:51 -0700154 switch (tiling_mode) {
155 default:
156 case I915_TILING_NONE:
157 width_alignment = 64 / bpp;
158 break;
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800159
Gurchetan Singhd6fb5772016-08-29 19:13:51 -0700160 case I915_TILING_X:
161 width_alignment = 512 / bpp;
162 height_alignment = 8;
163 break;
164
165 case I915_TILING_Y:
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800166 if (i915_dev->gen == 3) {
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800167 width_alignment = 512 / bpp;
168 height_alignment = 8;
Gurchetan Singhd6fb5772016-08-29 19:13:51 -0700169 } else {
170 width_alignment = 128 / bpp;
171 height_alignment = 32;
172 }
173 break;
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700174 }
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800175
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800176 if (i915_dev->gen > 3) {
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800177 *width = ALIGN(*width, width_alignment);
178 *height = ALIGN(*height, height_alignment);
179 } else {
180 uint32_t w;
Stéphane Marchesine3d7c1f2015-03-31 13:47:22 -0700181 for (w = width_alignment; w < *width; w <<= 1)
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800182 ;
183 *width = w;
184 *height = ALIGN(*height, height_alignment);
185 }
186}
187
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700188static int i915_verify_dimensions(struct driver *drv, uint32_t stride,
Stéphane Marchesinec88e892015-11-03 16:14:59 -0800189 uint32_t height)
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800190{
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800191 struct i915_device *i915_dev = (struct i915_device *)drv->priv;
192 if (i915_dev->gen <= 3 && stride > 8192)
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800193 return 0;
194
195 return 1;
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700196}
197
Gurchetan Singh3eb8d8f2017-01-03 13:36:13 -0800198static int i915_init(struct driver *drv)
199{
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800200 struct i915_device *i915_dev;
Gurchetan Singh3eb8d8f2017-01-03 13:36:13 -0800201 drm_i915_getparam_t get_param;
202 int device_id;
203 int ret;
204
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800205 i915_dev = calloc(1, sizeof(*i915_dev));
206 if (!i915_dev)
Gurchetan Singh3eb8d8f2017-01-03 13:36:13 -0800207 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");
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800215 free(i915_dev);
216 return -EINVAL;
Gurchetan Singh3eb8d8f2017-01-03 13:36:13 -0800217 }
218
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800219 i915_dev->gen = get_gen(device_id);
220 i915_dev->count = 0;
Gurchetan Singh3eb8d8f2017-01-03 13:36:13 -0800221
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800222 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;
Gurchetan Singh3eb8d8f2017-01-03 13:36:13 -0800230
Gurchetan Singh6b41fb52017-03-01 20:14:39 -0800231 return i915_add_combinations(drv);
Gurchetan Singh3eb8d8f2017-01-03 13:36:13 -0800232}
233
234static void i915_close(struct driver *drv)
235{
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800236 struct i915_device *i915_dev = drv->priv;
237 drm_intel_bufmgr_destroy(i915_dev->mgr);
238 free(i915_dev);
Gurchetan Singh3eb8d8f2017-01-03 13:36:13 -0800239 drv->priv = NULL;
240}
241
Gurchetan Singhd7c84fd2016-08-16 18:18:24 -0700242static int i915_bo_create(struct bo *bo, uint32_t width, uint32_t height,
243 uint32_t format, uint32_t flags)
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700244{
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700245 int ret;
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800246 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;
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700253
Gurchetan Singh458976f2016-11-23 17:32:33 -0800254 if (flags & (BO_USE_CURSOR | BO_USE_LINEAR |
255 BO_USE_SW_READ_OFTEN | BO_USE_SW_WRITE_OFTEN))
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700256 tiling_mode = I915_TILING_NONE;
Gurchetan Singh458976f2016-11-23 17:32:33 -0800257 else if (flags & BO_USE_SCANOUT)
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700258 tiling_mode = I915_TILING_X;
Gurchetan Singh6bab0c12016-10-13 19:08:48 -0700259 else
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700260 tiling_mode = I915_TILING_Y;
261
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800262 i915_align_dimensions(bo->drv, tiling_mode, &width, &height, bpp);
Gurchetan Singh42cc6d62016-08-29 18:19:19 -0700263 drv_bo_from_format(bo, width, height, format);
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800264
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800265 if (!i915_verify_dimensions(bo->drv, bo->strides[0], height))
266 return -EINVAL;
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800267
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800268 snprintf(name, sizeof(name), "i915-buffer-%u", i915_dev->count);
269 i915_dev->count++;
Stéphane Marchesin5d867a42014-11-24 17:09:49 -0800270
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800271 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;
Ilja H. Friedelf9d2ab72015-04-09 14:08:36 -0700284 }
Gurchetan Singh83dc4fb2016-07-19 15:52:33 -0700285
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800286 for (plane = 0; plane < bo->num_planes; plane++) {
287 if (plane > 0)
288 drm_intel_bo_reference(i915_bo->ibos[0]);
Daniel Nicoara1de26dc2014-09-25 18:53:19 -0400289
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800290 bo->handles[plane].u32 = i915_bo->ibos[0]->handle;
291 i915_bo->ibos[plane] = i915_bo->ibos[0];
292 }
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700293
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800294 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);
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700304 return -errno;
305 }
306
307 return 0;
308}
309
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800310static 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
324static 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
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700375static void *i915_bo_map(struct bo *bo, struct map_info *data, size_t plane)
Gurchetan Singhef920532016-08-12 16:38:25 -0700376{
377 int ret;
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800378 struct i915_bo *i915_bo = bo->priv;
Gurchetan Singhef920532016-08-12 16:38:25 -0700379
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800380 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]);
Gurchetan Singhef920532016-08-12 16:38:25 -0700387
Gurchetan Singhef920532016-08-12 16:38:25 -0700388 if (ret) {
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800389 fprintf(stderr, "drv: i915_bo_map failed.");
Gurchetan Singhef920532016-08-12 16:38:25 -0700390 return MAP_FAILED;
391 }
392
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800393 return i915_bo->ibos[0]->virtual;
394}
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700395
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800396static 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;
Gurchetan Singhef920532016-08-12 16:38:25 -0700407}
408
Gurchetan Singhf3b22da2016-11-21 10:46:38 -0800409static uint32_t i915_resolve_format(uint32_t format)
Gurchetan Singhbfba8c22016-08-16 17:57:10 -0700410{
411 switch (format) {
Gurchetan Singhf3b22da2016-11-21 10:46:38 -0800412 case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
Gurchetan Singhd6fb5772016-08-29 19:13:51 -0700413 /*HACK: See b/28671744 */
Gurchetan Singhf3b22da2016-11-21 10:46:38 -0800414 return DRM_FORMAT_XBGR8888;
415 case DRM_FORMAT_FLEX_YCbCr_420_888:
416 return DRM_FORMAT_YVU420;
Gurchetan Singhd6fb5772016-08-29 19:13:51 -0700417 default:
418 return format;
Gurchetan Singhbfba8c22016-08-16 17:57:10 -0700419 }
420}
421
Gurchetan Singh179687e2016-10-28 10:07:35 -0700422struct backend backend_i915 =
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700423{
424 .name = "i915",
Gurchetan Singhd7c84fd2016-08-16 18:18:24 -0700425 .init = i915_init,
426 .close = i915_close,
427 .bo_create = i915_bo_create,
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800428 .bo_destroy = i915_bo_destroy,
429 .bo_import = i915_bo_import,
Gurchetan Singhd7c84fd2016-08-16 18:18:24 -0700430 .bo_map = i915_bo_map,
Gurchetan Singh82a8eed2017-01-03 13:01:37 -0800431 .bo_unmap = i915_bo_unmap,
Gurchetan Singhbfba8c22016-08-16 17:57:10 -0700432 .resolve_format = i915_resolve_format,
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700433};
434
435#endif