blob: 8e74c660c1eb9c3494f55a21fa5563f3834f694b [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"
41#include "gralloc_drm_priv.h"
42
43#define MI_NOOP (0)
44#define MI_BATCH_BUFFER_END (0x0a << 23)
45#define MI_FLUSH (0x04 << 23)
46#define MI_FLUSH_DW (0x26 << 23)
47#define MI_WRITE_DIRTY_STATE (1 << 4)
48#define MI_INVALIDATE_MAP_CACHE (1 << 0)
49#define XY_SRC_COPY_BLT_CMD ((2 << 29) | (0x53 << 22) | 6)
50#define XY_SRC_COPY_BLT_WRITE_ALPHA (1 << 21)
51#define XY_SRC_COPY_BLT_WRITE_RGB (1 << 20)
52#define XY_SRC_COPY_BLT_SRC_TILED (1 << 15)
53#define XY_SRC_COPY_BLT_DST_TILED (1 << 11)
54
55struct intel_info {
56 struct gralloc_drm_drv_t base;
57
58 int fd;
59 drm_intel_bufmgr *bufmgr;
60 int gen;
61
62 drm_intel_bo *batch_ibo;
63 uint32_t *batch, *cur;
64 int capacity, size;
65};
66
67struct intel_buffer {
68 struct gralloc_drm_bo_t base;
69 drm_intel_bo *ibo;
70 uint32_t tiling;
71};
72
73static int
74batch_next(struct intel_info *info)
75{
76 info->cur = info->batch;
77
78 if (info->batch_ibo)
79 drm_intel_bo_unreference(info->batch_ibo);
80
81 info->batch_ibo = drm_intel_bo_alloc(info->bufmgr,
82 "gralloc-batchbuffer", info->size, 4096);
83
84 return (info->batch_ibo) ? 0 : -ENOMEM;
85}
86
87static int
88batch_count(struct intel_info *info)
89{
90 return info->cur - info->batch;
91}
92
93static void
94batch_dword(struct intel_info *info, uint32_t dword)
95{
96 *info->cur++ = dword;
97}
98
99static int
100batch_reloc(struct intel_info *info, struct gralloc_drm_bo_t *bo,
101 uint32_t read_domains, uint32_t write_domain)
102{
103 struct intel_buffer *target = (struct intel_buffer *) bo;
104 uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]);
105 int ret;
106
107 ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset,
108 target->ibo, 0, read_domains, write_domain);
109 if (!ret)
110 batch_dword(info, target->ibo->offset);
111
112 return ret;
113}
114
115static int
116batch_flush(struct intel_info *info)
117{
118 int size, ret;
119
120 batch_dword(info, MI_BATCH_BUFFER_END);
121 size = batch_count(info);
122 if (size & 1) {
123 batch_dword(info, MI_NOOP);
124 size = batch_count(info);
125 }
126
127 size *= sizeof(info->batch[0]);
128 ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch);
129 if (ret) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700130 ALOGE("failed to subdata batch");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800131 goto fail;
132 }
133 ret = drm_intel_bo_exec(info->batch_ibo, size, NULL, 0, 0);
134 if (ret) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700135 ALOGE("failed to exec batch");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800136 goto fail;
137 }
138
139 return batch_next(info);
140
141fail:
142 info->cur = info->batch;
143
144 return ret;
145}
146
147static int
148batch_reserve(struct intel_info *info, int count)
149{
150 int ret = 0;
151
152 if (batch_count(info) + count > info->capacity)
153 ret = batch_flush(info);
154
155 return ret;
156}
157
158static void
159batch_destroy(struct intel_info *info)
160{
161 if (info->batch_ibo) {
162 drm_intel_bo_unreference(info->batch_ibo);
163 info->batch_ibo = NULL;
164 }
165
166 if (info->batch) {
167 free(info->batch);
168 info->batch = NULL;
169 }
170}
171
172static int
173batch_init(struct intel_info *info)
174{
175 int ret;
176
177 info->capacity = 512;
178 info->size = (info->capacity + 16) * sizeof(info->batch[0]);
179
180 info->batch = malloc(info->size);
181 if (!info->batch)
182 return -ENOMEM;
183
184 ret = batch_next(info);
185 if (ret) {
186 free(info->batch);
187 info->batch = NULL;
188 }
189
190 return ret;
191}
192
193static void intel_copy(struct gralloc_drm_drv_t *drv,
194 struct gralloc_drm_bo_t *dst,
195 struct gralloc_drm_bo_t *src,
196 short x1, short y1, short x2, short y2)
197{
198 struct intel_info *info = (struct intel_info *) drv;
199 struct intel_buffer *dst_ib = (struct intel_buffer *) dst;
200 struct intel_buffer *src_ib = (struct intel_buffer *) src;
201 drm_intel_bo *bo_table[3];
202 uint32_t cmd, br13, dst_pitch, src_pitch;
203
204 if (dst->handle->width != src->handle->width ||
205 dst->handle->height != src->handle->height ||
206 dst->handle->stride != src->handle->stride ||
207 dst->handle->format != src->handle->format) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700208 ALOGE("copy between incompatible buffers");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800209 return;
210 }
211
212 if (x1 < 0)
213 x1 = 0;
214 if (y1 < 0)
215 y1 = 0;
216 if (x2 > dst->handle->width)
217 x2 = dst->handle->width;
218 if (y2 > dst->handle->height)
219 y2 = dst->handle->height;
220
221 if (x2 <= x1 || y2 <= y1)
222 return;
223
224 bo_table[0] = info->batch_ibo;
225 bo_table[1] = src_ib->ibo;
226 bo_table[2] = dst_ib->ibo;
227 if (drm_intel_bufmgr_check_aperture_space(bo_table, 3)) {
228 if (batch_flush(info))
229 return;
230 assert(!drm_intel_bufmgr_check_aperture_space(bo_table, 3));
231 }
232
233 cmd = XY_SRC_COPY_BLT_CMD;
234 br13 = 0xcc << 16; /* ROP_S/GXcopy */
235 dst_pitch = dst->handle->stride;
236 src_pitch = src->handle->stride;
237
238 switch (gralloc_drm_get_bpp(dst->handle->format)) {
239 case 1:
240 break;
241 case 2:
242 br13 |= (1 << 24);
243 break;
244 case 4:
245 br13 |= (1 << 24) | (1 << 25);
246 cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
247 break;
248 default:
Charles Johnsonb56dc922012-07-10 17:51:32 -0700249 ALOGE("copy with unsupported format");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800250 return;
251 }
252
253 if (info->gen >= 40) {
254 if (dst_ib->tiling != I915_TILING_NONE) {
255 assert(dst_pitch % 512 == 0);
256 dst_pitch >>= 2;
257 cmd |= XY_SRC_COPY_BLT_DST_TILED;
258 }
259 if (src_ib->tiling != I915_TILING_NONE) {
260 assert(src_pitch % 512 == 0);
261 src_pitch >>= 2;
262 cmd |= XY_SRC_COPY_BLT_SRC_TILED;
263 }
264 }
265
266 if (batch_reserve(info, 8))
267 return;
268
269 batch_dword(info, cmd);
270 batch_dword(info, br13 | dst_pitch);
271 batch_dword(info, (y1 << 16) | x1);
272 batch_dword(info, (y2 << 16) | x2);
273 batch_reloc(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
274 batch_dword(info, (y1 << 16) | x1);
275 batch_dword(info, src_pitch);
276 batch_reloc(info, src, I915_GEM_DOMAIN_RENDER, 0);
277
278 if (info->gen >= 60) {
279 batch_reserve(info, 4);
280 batch_dword(info, MI_FLUSH_DW | 2);
281 batch_dword(info, 0);
282 batch_dword(info, 0);
283 batch_dword(info, 0);
284 }
285 else {
286 int flags = (info->gen >= 40) ? 0 :
287 MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
288
289 batch_reserve(info, 1);
290 batch_dword(info, MI_FLUSH | flags);
291 }
292
293 batch_flush(info);
294}
295
296static drm_intel_bo *alloc_ibo(struct intel_info *info,
297 const struct gralloc_drm_handle_t *handle,
298 uint32_t *tiling, unsigned long *stride)
299{
300 drm_intel_bo *ibo;
301 const char *name;
302 int aligned_width, aligned_height, bpp;
303 unsigned long flags;
304
305 flags = 0;
306 bpp = gralloc_drm_get_bpp(handle->format);
307 if (!bpp) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700308 ALOGE("unrecognized format 0x%x", handle->format);
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800309 return NULL;
310 }
311
Chia-I Wub65a3f82011-10-27 18:01:23 +0800312 aligned_width = handle->width;
313 aligned_height = handle->height;
314 gralloc_drm_align_geometry(handle->format,
315 &aligned_width, &aligned_height);
316
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800317 if (handle->usage & GRALLOC_USAGE_HW_FB) {
318 unsigned long max_stride;
319
320 max_stride = 32 * 1024;
321 if (info->gen < 50)
322 max_stride /= 2;
323 if (info->gen < 40)
324 max_stride /= 2;
325
326 name = "gralloc-fb";
Chia-I Wub65a3f82011-10-27 18:01:23 +0800327 aligned_width = (aligned_width + 63) & ~63;
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800328 flags = BO_ALLOC_FOR_RENDER;
329
330 *tiling = I915_TILING_X;
331 *stride = aligned_width * bpp;
332 if (*stride > max_stride) {
333 *tiling = I915_TILING_NONE;
334 max_stride = 32 * 1024;
335 if (*stride > max_stride)
336 return NULL;
337 }
338
339 while (1) {
340 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
341 aligned_width, aligned_height,
342 bpp, tiling, stride, flags);
343 if (!ibo || *stride > max_stride) {
344 if (ibo) {
345 drm_intel_bo_unreference(ibo);
346 ibo = NULL;
347 }
348
349 if (*tiling != I915_TILING_NONE) {
350 /* retry */
351 *tiling = I915_TILING_NONE;
352 max_stride = 32 * 1024;
353 continue;
354 }
355 }
356 if (ibo)
357 drm_intel_bo_disable_reuse(ibo);
358 break;
359 }
360 }
361 else {
362 if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN |
363 GRALLOC_USAGE_SW_WRITE_OFTEN))
364 *tiling = I915_TILING_NONE;
365 else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) ||
366 ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) &&
367 handle->width >= 64))
368 *tiling = I915_TILING_X;
369 else
370 *tiling = I915_TILING_NONE;
371
372 if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) {
373 name = "gralloc-texture";
374 /* see 2D texture layout of DRI drivers */
Chia-I Wub65a3f82011-10-27 18:01:23 +0800375 aligned_width = (aligned_width + 3) & ~3;
376 aligned_height = (aligned_height + 1) & ~1;
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800377 }
378 else {
379 name = "gralloc-buffer";
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800380 }
381
382 if (handle->usage & GRALLOC_USAGE_HW_RENDER)
383 flags = BO_ALLOC_FOR_RENDER;
384
385 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
386 aligned_width, aligned_height,
387 bpp, tiling, stride, flags);
388 }
389
390 return ibo;
391}
392
393static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv,
394 struct gralloc_drm_handle_t *handle)
395{
396 struct intel_info *info = (struct intel_info *) drv;
397 struct intel_buffer *ib;
398
399 ib = calloc(1, sizeof(*ib));
400 if (!ib)
401 return NULL;
402
403 if (handle->name) {
404 uint32_t dummy;
405
406 ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr,
407 "gralloc-r", handle->name);
408 if (!ib->ibo) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700409 ALOGE("failed to create ibo from name %u",
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800410 handle->name);
411 free(ib);
412 return NULL;
413 }
414
415 if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700416 ALOGE("failed to get ibo tiling");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800417 drm_intel_bo_unreference(ib->ibo);
418 free(ib);
419 return NULL;
420 }
421 }
422 else {
423 unsigned long stride;
424
425 ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride);
426 if (!ib->ibo) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700427 ALOGE("failed to allocate ibo %dx%d (format %d)",
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800428 handle->width,
429 handle->height,
430 handle->format);
431 free(ib);
432 return NULL;
433 }
434
435 handle->stride = stride;
436
437 if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700438 ALOGE("failed to flink ibo");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800439 drm_intel_bo_unreference(ib->ibo);
440 free(ib);
441 return NULL;
442 }
443 }
444
445 if (handle->usage & GRALLOC_USAGE_HW_FB)
446 ib->base.fb_handle = ib->ibo->handle;
447
448 ib->base.handle = handle;
449
450 return &ib->base;
451}
452
453static void intel_free(struct gralloc_drm_drv_t *drv,
454 struct gralloc_drm_bo_t *bo)
455{
456 struct intel_buffer *ib = (struct intel_buffer *) bo;
457
458 drm_intel_bo_unreference(ib->ibo);
459 free(ib);
460}
461
462static int intel_map(struct gralloc_drm_drv_t *drv,
463 struct gralloc_drm_bo_t *bo,
464 int x, int y, int w, int h,
465 int enable_write, void **addr)
466{
467 struct intel_buffer *ib = (struct intel_buffer *) bo;
468 int err;
469
470 if (ib->tiling != I915_TILING_NONE ||
471 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
472 err = drm_intel_gem_bo_map_gtt(ib->ibo);
473 else
474 err = drm_intel_bo_map(ib->ibo, enable_write);
475 if (!err)
476 *addr = ib->ibo->virtual;
477
478 return err;
479}
480
481static void intel_unmap(struct gralloc_drm_drv_t *drv,
482 struct gralloc_drm_bo_t *bo)
483{
484 struct intel_buffer *ib = (struct intel_buffer *) bo;
485
486 if (ib->tiling != I915_TILING_NONE ||
487 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
488 drm_intel_gem_bo_unmap_gtt(ib->ibo);
489 else
490 drm_intel_bo_unmap(ib->ibo);
491}
492
493#include "dri/intel_chipset.h" /* for IS_965() */
494static void intel_init_kms_features(struct gralloc_drm_drv_t *drv,
495 struct gralloc_drm_t *drm)
496{
497 struct intel_info *info = (struct intel_info *) drv;
498 struct drm_i915_getparam gp;
499 int pageflipping, id;
500
Chia-I Wu333d5662011-07-30 17:06:31 +0900501 switch (drm->fb_format) {
502 case HAL_PIXEL_FORMAT_BGRA_8888:
503 case HAL_PIXEL_FORMAT_RGB_565:
504 break;
505 default:
506 drm->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
507 break;
508 }
Chia-I Wue59db8f2011-07-10 23:12:26 +0800509
Chia-I Wu8c382cc2011-08-29 14:52:55 +0800510 drm->mode_quirk_vmwgfx = 0;
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800511 /* why? */
512 drm->mode_sync_flip = 1;
513
514 memset(&gp, 0, sizeof(gp));
515 gp.param = I915_PARAM_HAS_PAGEFLIPPING;
516 gp.value = &pageflipping;
517 if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
518 pageflipping = 0;
519
520 memset(&gp, 0, sizeof(gp));
521 gp.param = I915_PARAM_CHIPSET_ID;
522 gp.value = &id;
523 if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
524 id = 0;
525
526 if (IS_965(id)) {
527 if (IS_GEN6(id))
528 info->gen = 60;
529 else if (IS_GEN5(id))
530 info->gen = 50;
531 else
532 info->gen = 40;
533 }
534 else {
535 info->gen = 30;
536 }
537
538 if (pageflipping && info->gen > 30)
539 drm->swap_mode = DRM_SWAP_FLIP;
540 else if (info->batch && info->gen == 30)
541 drm->swap_mode = DRM_SWAP_COPY;
542 else
543 drm->swap_mode = DRM_SWAP_SETCRTC;
544
545 if (drm->resources) {
546 int pipe;
547
548 pipe = drm_intel_get_pipe_from_crtc_id(info->bufmgr,
549 drm->crtc_id);
550 drm->swap_interval = (pipe >= 0) ? 1 : 0;
551 drm->vblank_secondary = (pipe > 0);
552 }
553 else {
554 drm->swap_interval = 0;
555 }
556}
557
558static void intel_destroy(struct gralloc_drm_drv_t *drv)
559{
560 struct intel_info *info = (struct intel_info *) drv;
561
562 batch_destroy(info);
563 drm_intel_bufmgr_destroy(info->bufmgr);
564 free(info);
565}
566
567struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd)
568{
569 struct intel_info *info;
570
571 info = calloc(1, sizeof(*info));
572 if (!info) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700573 ALOGE("failed to allocate driver info");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800574 return NULL;
575 }
576
577 info->fd = fd;
578 info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
579 if (!info->bufmgr) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700580 ALOGE("failed to create buffer manager");
Chia-I Wu2ec32d42011-06-12 16:21:30 +0800581 free(info);
582 return NULL;
583 }
584
585 batch_init(info);
586
587 info->base.destroy = intel_destroy;
588 info->base.init_kms_features = intel_init_kms_features;
589 info->base.alloc = intel_alloc;
590 info->base.free = intel_free;
591 info->base.map = intel_map;
592 info->base.unmap = intel_unmap;
593 info->base.copy = intel_copy;
594
595 return &info->base;
596}