blob: 1bf1638fe7b6df4a1a40e0b3b376873fe690acf5 [file] [log] [blame]
Chia-I Wu2ec32d42011-06-12 16:21:30 +08001/*
2 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
3 * Copyright (C) 2010-2011 LunarG Inc.
4 *
5 * drm_gem_intel_copy is based on xorg-driver-intel, which has
6 *
7 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
8 * All Rights Reserved.
9 * Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 */
29
30#define LOG_TAG "GRALLOC-I915"
31
32#include <cutils/log.h>
33#include <stdlib.h>
34#include <errno.h>
35#include <assert.h>
36#include <drm.h>
37#include <intel_bufmgr.h>
38#include <i915_drm.h>
39
40#include "gralloc_drm.h"
Ben Chan31b96bf2017-03-03 17:47:26 -080041#include "gralloc_drm_formats.h"
Chia-I Wu2ec32d42011-06-12 16:21:30 +080042#include "gralloc_drm_priv.h"
43
44#define MI_NOOP (0)
45#define MI_BATCH_BUFFER_END (0x0a << 23)
46#define MI_FLUSH (0x04 << 23)
47#define MI_FLUSH_DW (0x26 << 23)
48#define MI_WRITE_DIRTY_STATE (1 << 4)
49#define MI_INVALIDATE_MAP_CACHE (1 << 0)
50#define XY_SRC_COPY_BLT_CMD ((2 << 29) | (0x53 << 22) | 6)
51#define XY_SRC_COPY_BLT_WRITE_ALPHA (1 << 21)
52#define XY_SRC_COPY_BLT_WRITE_RGB (1 << 20)
53#define XY_SRC_COPY_BLT_SRC_TILED (1 << 15)
54#define XY_SRC_COPY_BLT_DST_TILED (1 << 11)
55
56struct intel_info {
57 struct gralloc_drm_drv_t base;
58
59 int fd;
60 drm_intel_bufmgr *bufmgr;
61 int gen;
62
63 drm_intel_bo *batch_ibo;
64 uint32_t *batch, *cur;
65 int capacity, size;
Chih-Wei Huang263f0c12013-06-04 22:38:15 +080066 int exec_blt;
Chia-I Wu2ec32d42011-06-12 16:21:30 +080067};
68
69struct intel_buffer {
70 struct gralloc_drm_bo_t base;
71 drm_intel_bo *ibo;
72 uint32_t tiling;
73};
74
75static int
76batch_next(struct intel_info *info)
77{
78 info->cur = info->batch;
79
80 if (info->batch_ibo)
81 drm_intel_bo_unreference(info->batch_ibo);
82
83 info->batch_ibo = drm_intel_bo_alloc(info->bufmgr,
84 "gralloc-batchbuffer", info->size, 4096);
85
86 return (info->batch_ibo) ? 0 : -ENOMEM;
87}
88
89static int
90batch_count(struct intel_info *info)
91{
92 return info->cur - info->batch;
93}
94
95static void
96batch_dword(struct intel_info *info, uint32_t dword)
97{
98 *info->cur++ = dword;
99}
100
101static int
102batch_reloc(struct intel_info *info, struct gralloc_drm_bo_t *bo,
103 uint32_t read_domains, uint32_t write_domain)
104{
105 struct intel_buffer *target = (struct intel_buffer *) bo;
106 uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]);
107 int ret;
108
109 ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset,
110 target->ibo, 0, read_domains, write_domain);
111 if (!ret)
112 batch_dword(info, target->ibo->offset);
113
114 return ret;
115}
116
117static int
118batch_flush(struct intel_info *info)
119{
120 int size, ret;
121
122 batch_dword(info, MI_BATCH_BUFFER_END);
123 size = batch_count(info);
124 if (size & 1) {
125 batch_dword(info, MI_NOOP);
126 size = batch_count(info);
127 }
128
129 size *= sizeof(info->batch[0]);
130 ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch);
131 if (ret) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700132 ALOGE("failed to subdata batch");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800133 goto fail;
134 }
Tapani Pällif3c326e2013-02-22 12:13:28 +0200135 ret = drm_intel_bo_mrb_exec(info->batch_ibo, size,
Chih-Wei Huang263f0c12013-06-04 22:38:15 +0800136 NULL, 0, 0, info->exec_blt);
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800137 if (ret) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700138 ALOGE("failed to exec batch");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800139 goto fail;
140 }
141
142 return batch_next(info);
143
144fail:
145 info->cur = info->batch;
146
147 return ret;
148}
149
150static int
151batch_reserve(struct intel_info *info, int count)
152{
153 int ret = 0;
154
155 if (batch_count(info) + count > info->capacity)
156 ret = batch_flush(info);
157
158 return ret;
159}
160
161static void
162batch_destroy(struct intel_info *info)
163{
164 if (info->batch_ibo) {
165 drm_intel_bo_unreference(info->batch_ibo);
166 info->batch_ibo = NULL;
167 }
168
169 if (info->batch) {
170 free(info->batch);
171 info->batch = NULL;
172 }
173}
174
175static int
176batch_init(struct intel_info *info)
177{
178 int ret;
179
180 info->capacity = 512;
181 info->size = (info->capacity + 16) * sizeof(info->batch[0]);
182
183 info->batch = malloc(info->size);
184 if (!info->batch)
185 return -ENOMEM;
186
187 ret = batch_next(info);
188 if (ret) {
189 free(info->batch);
190 info->batch = NULL;
191 }
192
193 return ret;
194}
195
Tapani Pällia8f03342013-01-18 15:01:43 +0200196static void intel_resolve_format(struct gralloc_drm_drv_t *drv,
197 struct gralloc_drm_bo_t *bo,
198 uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
199{
200 /*
201 * TODO - should take account hw specific padding, alignment
202 * for camera, video decoder etc.
203 */
204
205 struct intel_buffer *ib = (struct intel_buffer *) bo;
206
207 memset(pitches, 0, 4 * sizeof(uint32_t));
208 memset(offsets, 0, 4 * sizeof(uint32_t));
209 memset(handles, 0, 4 * sizeof(uint32_t));
210
211 pitches[0] = ib->base.handle->stride;
212 handles[0] = ib->base.fb_handle;
213
214 switch(ib->base.handle->format) {
215 case HAL_PIXEL_FORMAT_YV12:
216
217 // U and V stride are half of Y plane
218 pitches[2] = pitches[0]/2;
219 pitches[1] = pitches[0]/2;
220
221 // like I420 but U and V are in reverse order
222 offsets[2] = offsets[0] +
223 pitches[0] * ib->base.handle->height;
224 offsets[1] = offsets[2] +
225 pitches[2] * ib->base.handle->height/2;
226
227 handles[1] = handles[2] = handles[0];
228 break;
229
230 case HAL_PIXEL_FORMAT_DRM_NV12:
231
232 // U and V are interleaved in 2nd plane
233 pitches[1] = pitches[0];
234 offsets[1] = offsets[0] +
235 pitches[0] * ib->base.handle->height;
236
237 handles[1] = handles[0];
238 break;
239 }
240}
241
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800242static drm_intel_bo *alloc_ibo(struct intel_info *info,
243 const struct gralloc_drm_handle_t *handle,
244 uint32_t *tiling, unsigned long *stride)
245{
246 drm_intel_bo *ibo;
247 const char *name;
248 int aligned_width, aligned_height, bpp;
249 unsigned long flags;
250
251 flags = 0;
252 bpp = gralloc_drm_get_bpp(handle->format);
253 if (!bpp) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700254 ALOGE("unrecognized format 0x%x", handle->format);
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800255 return NULL;
256 }
257
Chia-I Wub65a3f82011-10-27 18:01:23 +0800258 aligned_width = handle->width;
259 aligned_height = handle->height;
260 gralloc_drm_align_geometry(handle->format,
261 &aligned_width, &aligned_height);
262
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800263 if (handle->usage & GRALLOC_USAGE_HW_FB) {
264 unsigned long max_stride;
265
266 max_stride = 32 * 1024;
267 if (info->gen < 50)
268 max_stride /= 2;
269 if (info->gen < 40)
270 max_stride /= 2;
271
272 name = "gralloc-fb";
Tapani Pällidf57ea92013-04-22 08:20:39 +0300273 aligned_width = ALIGN(aligned_width, 64);
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800274 flags = BO_ALLOC_FOR_RENDER;
275
276 *tiling = I915_TILING_X;
277 *stride = aligned_width * bpp;
278 if (*stride > max_stride) {
279 *tiling = I915_TILING_NONE;
280 max_stride = 32 * 1024;
281 if (*stride > max_stride)
282 return NULL;
283 }
284
285 while (1) {
286 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
287 aligned_width, aligned_height,
288 bpp, tiling, stride, flags);
289 if (!ibo || *stride > max_stride) {
290 if (ibo) {
291 drm_intel_bo_unreference(ibo);
292 ibo = NULL;
293 }
294
295 if (*tiling != I915_TILING_NONE) {
296 /* retry */
297 *tiling = I915_TILING_NONE;
298 max_stride = 32 * 1024;
299 continue;
300 }
301 }
302 if (ibo)
303 drm_intel_bo_disable_reuse(ibo);
304 break;
305 }
306 }
307 else {
308 if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN |
309 GRALLOC_USAGE_SW_WRITE_OFTEN))
310 *tiling = I915_TILING_NONE;
311 else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) ||
312 ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) &&
313 handle->width >= 64))
314 *tiling = I915_TILING_X;
315 else
316 *tiling = I915_TILING_NONE;
317
318 if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) {
319 name = "gralloc-texture";
320 /* see 2D texture layout of DRI drivers */
Tapani Pällidf57ea92013-04-22 08:20:39 +0300321 aligned_width = ALIGN(aligned_width, 4);
322 aligned_height = ALIGN(aligned_height, 2);
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800323 }
324 else {
325 name = "gralloc-buffer";
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800326 }
327
328 if (handle->usage & GRALLOC_USAGE_HW_RENDER)
329 flags = BO_ALLOC_FOR_RENDER;
330
331 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
332 aligned_width, aligned_height,
333 bpp, tiling, stride, flags);
334 }
335
336 return ibo;
337}
338
339static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv,
340 struct gralloc_drm_handle_t *handle)
341{
342 struct intel_info *info = (struct intel_info *) drv;
343 struct intel_buffer *ib;
344
345 ib = calloc(1, sizeof(*ib));
346 if (!ib)
347 return NULL;
348
349 if (handle->name) {
350 uint32_t dummy;
351
352 ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr,
353 "gralloc-r", handle->name);
354 if (!ib->ibo) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700355 ALOGE("failed to create ibo from name %u",
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800356 handle->name);
357 free(ib);
358 return NULL;
359 }
360
361 if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700362 ALOGE("failed to get ibo tiling");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800363 drm_intel_bo_unreference(ib->ibo);
364 free(ib);
365 return NULL;
366 }
367 }
368 else {
369 unsigned long stride;
370
371 ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride);
372 if (!ib->ibo) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700373 ALOGE("failed to allocate ibo %dx%d (format %d)",
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800374 handle->width,
375 handle->height,
376 handle->format);
377 free(ib);
378 return NULL;
379 }
380
381 handle->stride = stride;
382
383 if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700384 ALOGE("failed to flink ibo");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800385 drm_intel_bo_unreference(ib->ibo);
386 free(ib);
387 return NULL;
388 }
389 }
390
Tapani Pällic8781052012-08-31 12:56:31 +0300391 ib->base.fb_handle = ib->ibo->handle;
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800392
393 ib->base.handle = handle;
394
395 return &ib->base;
396}
397
398static void intel_free(struct gralloc_drm_drv_t *drv,
399 struct gralloc_drm_bo_t *bo)
400{
401 struct intel_buffer *ib = (struct intel_buffer *) bo;
402
403 drm_intel_bo_unreference(ib->ibo);
404 free(ib);
405}
406
407static int intel_map(struct gralloc_drm_drv_t *drv,
408 struct gralloc_drm_bo_t *bo,
409 int x, int y, int w, int h,
410 int enable_write, void **addr)
411{
412 struct intel_buffer *ib = (struct intel_buffer *) bo;
413 int err;
414
415 if (ib->tiling != I915_TILING_NONE ||
416 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
417 err = drm_intel_gem_bo_map_gtt(ib->ibo);
418 else
419 err = drm_intel_bo_map(ib->ibo, enable_write);
420 if (!err)
421 *addr = ib->ibo->virtual;
422
423 return err;
424}
425
426static void intel_unmap(struct gralloc_drm_drv_t *drv,
427 struct gralloc_drm_bo_t *bo)
428{
429 struct intel_buffer *ib = (struct intel_buffer *) bo;
430
431 if (ib->tiling != I915_TILING_NONE ||
432 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
433 drm_intel_gem_bo_unmap_gtt(ib->ibo);
434 else
435 drm_intel_bo_unmap(ib->ibo);
436}
437
Tapani Pälliebfa14d2012-11-08 09:52:27 +0200438#include "intel_chipset.h" /* for platform detection macros */
Sean Pauld81a9372015-01-21 15:12:57 -0500439static void gen_init(struct intel_info *info)
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800440{
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800441 struct drm_i915_getparam gp;
Chih-Wei Huang263f0c12013-06-04 22:38:15 +0800442 int pageflipping, id, has_blt;
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800443
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800444 memset(&gp, 0, sizeof(gp));
445 gp.param = I915_PARAM_CHIPSET_ID;
446 gp.value = &id;
Sean Pauld81a9372015-01-21 15:12:57 -0500447 if (drmCommandWriteRead(info->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800448 id = 0;
449
Chih-Wei Huang263f0c12013-06-04 22:38:15 +0800450 memset(&gp, 0, sizeof(gp));
451 gp.param = I915_PARAM_HAS_BLT;
452 gp.value = &has_blt;
Sean Pauld81a9372015-01-21 15:12:57 -0500453 if (drmCommandWriteRead(info->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
Chih-Wei Huang263f0c12013-06-04 22:38:15 +0800454 has_blt = 0;
455 info->exec_blt = has_blt ? I915_EXEC_BLT : 0;
456
Tapani Pälliebfa14d2012-11-08 09:52:27 +0200457 /* GEN4, G4X, GEN5, GEN6, GEN7 */
458 if ((IS_9XX(id) || IS_G4X(id)) && !IS_GEN3(id)) {
459 if (IS_GEN7(id))
460 info->gen = 70;
461 else if (IS_GEN6(id))
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800462 info->gen = 60;
463 else if (IS_GEN5(id))
464 info->gen = 50;
465 else
466 info->gen = 40;
467 }
468 else {
469 info->gen = 30;
470 }
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800471}
472
473static void intel_destroy(struct gralloc_drm_drv_t *drv)
474{
475 struct intel_info *info = (struct intel_info *) drv;
476
477 batch_destroy(info);
478 drm_intel_bufmgr_destroy(info->bufmgr);
479 free(info);
480}
481
482struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd)
483{
484 struct intel_info *info;
485
486 info = calloc(1, sizeof(*info));
487 if (!info) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700488 ALOGE("failed to allocate driver info");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800489 return NULL;
490 }
491
492 info->fd = fd;
493 info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
494 if (!info->bufmgr) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700495 ALOGE("failed to create buffer manager");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800496 free(info);
497 return NULL;
498 }
499
500 batch_init(info);
Sean Pauld81a9372015-01-21 15:12:57 -0500501 gen_init(info);
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800502
503 info->base.destroy = intel_destroy;
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800504 info->base.alloc = intel_alloc;
505 info->base.free = intel_free;
506 info->base.map = intel_map;
507 info->base.unmap = intel_unmap;
Tapani Pällia8f03342013-01-18 15:01:43 +0200508 info->base.resolve_format = intel_resolve_format;
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800509
510 return &info->base;
511}