2 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
3 * Copyright (C) 2010-2011 LunarG Inc.
5 * drm_gem_intel_copy is based on xorg-driver-intel, which has
7 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
9 * Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org>
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:
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
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.
30 #define LOG_TAG "GRALLOC-I915"
32 #include <cutils/log.h>
37 #include <intel_bufmgr.h>
40 #include "gralloc_drm.h"
41 #include "gralloc_drm_priv.h"
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))
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)
58 struct gralloc_drm_drv_t base;
61 drm_intel_bufmgr *bufmgr;
64 drm_intel_bo *batch_ibo;
65 uint32_t *batch, *cur;
71 struct gralloc_drm_bo_t base;
77 batch_next(struct intel_info *info)
79 info->cur = info->batch;
82 drm_intel_bo_unreference(info->batch_ibo);
84 info->batch_ibo = drm_intel_bo_alloc(info->bufmgr,
85 "gralloc-batchbuffer", info->size, 4096);
87 return (info->batch_ibo) ? 0 : -ENOMEM;
91 batch_count(struct intel_info *info)
93 return info->cur - info->batch;
97 batch_dword(struct intel_info *info, uint32_t dword)
103 batch_reloc(struct intel_info *info, struct gralloc_drm_bo_t *bo,
104 uint32_t read_domains, uint32_t write_domain)
106 struct intel_buffer *target = (struct intel_buffer *) bo;
107 uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]);
110 ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset,
111 target->ibo, 0, read_domains, write_domain);
113 batch_dword(info, target->ibo->offset);
119 batch_reloc64(struct intel_info *info, struct gralloc_drm_bo_t *bo,
120 uint32_t read_domains, uint32_t write_domain)
122 struct intel_buffer *target = (struct intel_buffer *) bo;
123 uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]);
126 ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset,
127 target->ibo, 0, read_domains, write_domain);
129 batch_dword(info, target->ibo->offset64);
130 batch_dword(info, target->ibo->offset64 >> 32);
137 batch_flush(struct intel_info *info)
141 batch_dword(info, MI_BATCH_BUFFER_END);
142 size = batch_count(info);
144 batch_dword(info, MI_NOOP);
145 size = batch_count(info);
148 size *= sizeof(info->batch[0]);
149 ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch);
151 ALOGE("failed to subdata batch");
154 ret = drm_intel_bo_mrb_exec(info->batch_ibo, size,
155 NULL, 0, 0, info->exec_blt);
157 ALOGE("failed to exec batch");
161 return batch_next(info);
164 info->cur = info->batch;
170 batch_reserve(struct intel_info *info, int count)
174 if (batch_count(info) + count > info->capacity)
175 ret = batch_flush(info);
181 batch_destroy(struct intel_info *info)
183 if (info->batch_ibo) {
184 drm_intel_bo_unreference(info->batch_ibo);
185 info->batch_ibo = NULL;
195 batch_init(struct intel_info *info)
199 info->capacity = 512;
200 info->size = (info->capacity + 16) * sizeof(info->batch[0]);
202 info->batch = malloc(info->size);
206 ret = batch_next(info);
215 static void intel_resolve_format(struct gralloc_drm_drv_t *drv,
216 struct gralloc_drm_bo_t *bo,
217 uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
220 * TODO - should take account hw specific padding, alignment
221 * for camera, video decoder etc.
224 struct intel_buffer *ib = (struct intel_buffer *) bo;
226 memset(pitches, 0, 4 * sizeof(uint32_t));
227 memset(offsets, 0, 4 * sizeof(uint32_t));
228 memset(handles, 0, 4 * sizeof(uint32_t));
230 pitches[0] = ib->base.handle->stride;
231 handles[0] = ib->base.fb_handle;
233 switch(ib->base.handle->format) {
234 case HAL_PIXEL_FORMAT_YV12:
236 // U and V stride are half of Y plane
237 pitches[2] = pitches[0]/2;
238 pitches[1] = pitches[0]/2;
240 // like I420 but U and V are in reverse order
241 offsets[2] = offsets[0] +
242 pitches[0] * ib->base.handle->height;
243 offsets[1] = offsets[2] +
244 pitches[2] * ib->base.handle->height/2;
246 handles[1] = handles[2] = handles[0];
249 case HAL_PIXEL_FORMAT_DRM_NV12:
251 // U and V are interleaved in 2nd plane
252 pitches[1] = pitches[0];
253 offsets[1] = offsets[0] +
254 pitches[0] * ib->base.handle->height;
256 handles[1] = handles[0];
262 static void intel_blit(struct gralloc_drm_drv_t *drv,
263 struct gralloc_drm_bo_t *dst,
264 struct gralloc_drm_bo_t *src,
265 uint16_t dst_x1, uint16_t dst_y1,
266 uint16_t dst_x2, uint16_t dst_y2,
267 uint16_t src_x1, uint16_t src_y1,
268 uint16_t src_x2, uint16_t src_y2)
270 struct intel_info *info = (struct intel_info *) drv;
271 struct intel_buffer *dst_ib = (struct intel_buffer *) dst;
272 struct intel_buffer *src_ib = (struct intel_buffer *) src;
273 drm_intel_bo *bo_table[3];
274 uint32_t cmd, br13, dst_pitch, src_pitch;
277 * XY_SRC_COPY_BLT_CMD does not support scaling,
278 * rectangle dimensions much match
280 if (src_x2 - src_x1 != dst_x2 - dst_x1 ||
281 src_y2 - src_y1 != dst_y2 - dst_y1) {
282 ALOGE("%s, src and dst rect must match", __func__);
286 if (dst->handle->format != src->handle->format) {
287 ALOGE("%s, src and dst format must match", __func__);
291 /* nothing to blit */
292 if (src_x2 <= src_x1 || src_y2 <= src_y1)
295 /* clamp x2, y2 to surface size */
296 if (src_x2 > src->handle->width)
297 src_x2 = src->handle->width;
298 if (src_y2 > src->handle->height)
299 src_y2 = src->handle->height;
301 if (dst_x2 > dst->handle->width)
302 dst_x2 = dst->handle->width;
303 if (dst_y2 > dst->handle->height)
304 dst_y2 = dst->handle->height;
306 bo_table[0] = info->batch_ibo;
307 bo_table[1] = src_ib->ibo;
308 bo_table[2] = dst_ib->ibo;
309 if (drm_intel_bufmgr_check_aperture_space(bo_table, 3)) {
310 if (batch_flush(info))
312 assert(!drm_intel_bufmgr_check_aperture_space(bo_table, 3));
315 cmd = XY_SRC_COPY_BLT_CMD;
316 br13 = 0xcc << 16; /* ROP_S/GXcopy */
317 dst_pitch = dst->handle->stride;
318 src_pitch = src->handle->stride;
320 /* Blit pitch must be dword-aligned. Otherwise, the hardware appears to
323 if (src_pitch % 4 != 0 || dst_pitch % 4 != 0) {
324 ALOGE("%s, src and dst pitch must be dword aligned", __func__);
328 switch (gralloc_drm_get_bpp(dst->handle->format)) {
335 br13 |= (1 << 24) | (1 << 25);
336 cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
339 ALOGE("%s, copy with unsupported format", __func__);
343 if (info->gen >= 40) {
344 if (dst_ib->tiling != I915_TILING_NONE) {
345 assert(dst_pitch % 512 == 0);
347 cmd |= XY_SRC_COPY_BLT_DST_TILED;
349 if (src_ib->tiling != I915_TILING_NONE) {
350 assert(src_pitch % 512 == 0);
352 cmd |= XY_SRC_COPY_BLT_SRC_TILED;
356 unsigned length = (info->gen >= 80) ? 10 : 8;
357 if (batch_reserve(info, length))
360 ALOGD_IF(DEBUG_BLT, "running batch commands, gen=%d tiling: [%d, %d]. dst=[%d, %d, %d, %d], "
361 "src=[%d, %d, %d, %d], pitch=[%d, %d]",
362 info->gen, dst_ib->tiling, src_ib->tiling,
363 dst_x1, dst_y1, dst_x2, dst_y2,
364 src_x1, src_y1, src_x2, src_y2,
365 dst_pitch, src_pitch);
367 batch_dword(info, cmd | (length - 2));
368 batch_dword(info, br13 | (uint16_t)dst_pitch);
369 batch_dword(info, (dst_y1 << 16) | dst_x1);
370 batch_dword(info, (dst_y2 << 16) | dst_x2);
371 if (info->gen >= 80) {
372 batch_reloc64(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
374 batch_reloc(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
376 batch_dword(info, (src_y1 << 16) | src_x1);
377 batch_dword(info, (uint16_t)src_pitch);
378 if (info->gen >= 80) {
379 batch_reloc64(info, src, I915_GEM_DOMAIN_RENDER, 0);
381 batch_reloc(info, src, I915_GEM_DOMAIN_RENDER, 0);
384 if (info->gen >= 60) {
385 batch_reserve(info, 4);
386 batch_dword(info, MI_FLUSH_DW | 2);
387 batch_dword(info, 0);
388 batch_dword(info, 0);
389 batch_dword(info, 0);
392 int flags = (info->gen >= 40) ? 0 :
393 MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
395 batch_reserve(info, 1);
396 batch_dword(info, MI_FLUSH | flags);
402 static drm_intel_bo *alloc_ibo(struct intel_info *info,
403 const struct gralloc_drm_handle_t *handle,
404 uint32_t *tiling, unsigned long *stride)
408 int aligned_width, aligned_height, bpp;
412 bpp = gralloc_drm_get_bpp(handle->format);
414 ALOGE("unrecognized format 0x%x", handle->format);
418 aligned_width = handle->width;
419 aligned_height = handle->height;
420 gralloc_drm_align_geometry(handle->format,
421 &aligned_width, &aligned_height);
423 if (handle->usage & GRALLOC_USAGE_HW_FB) {
424 unsigned long max_stride;
426 max_stride = 32 * 1024;
433 aligned_width = ALIGN(aligned_width, 64);
434 flags = BO_ALLOC_FOR_RENDER;
436 *tiling = I915_TILING_X;
437 *stride = aligned_width * bpp;
438 if (*stride > max_stride) {
439 *tiling = I915_TILING_NONE;
440 max_stride = 32 * 1024;
441 if (*stride > max_stride)
446 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
447 aligned_width, aligned_height,
448 bpp, tiling, stride, flags);
449 if (!ibo || *stride > max_stride) {
451 drm_intel_bo_unreference(ibo);
455 if (*tiling != I915_TILING_NONE) {
457 *tiling = I915_TILING_NONE;
458 max_stride = 32 * 1024;
463 drm_intel_bo_disable_reuse(ibo);
468 if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN |
469 GRALLOC_USAGE_SW_WRITE_OFTEN))
470 *tiling = I915_TILING_NONE;
471 else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) ||
472 ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) &&
473 handle->width >= 64))
474 *tiling = I915_TILING_X;
476 *tiling = I915_TILING_NONE;
478 if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) {
479 name = "gralloc-texture";
480 /* see 2D texture layout of DRI drivers */
481 aligned_width = ALIGN(aligned_width, 4);
482 aligned_height = ALIGN(aligned_height, 2);
485 name = "gralloc-buffer";
488 if (handle->usage & GRALLOC_USAGE_HW_RENDER)
489 flags = BO_ALLOC_FOR_RENDER;
491 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
492 aligned_width, aligned_height,
493 bpp, tiling, stride, flags);
499 static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv,
500 struct gralloc_drm_handle_t *handle)
502 struct intel_info *info = (struct intel_info *) drv;
503 struct intel_buffer *ib;
505 ib = calloc(1, sizeof(*ib));
512 ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr,
513 "gralloc-r", handle->name);
515 ALOGE("failed to create ibo from name %u",
521 if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
522 ALOGE("failed to get ibo tiling");
523 drm_intel_bo_unreference(ib->ibo);
529 unsigned long stride;
531 ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride);
533 ALOGE("failed to allocate ibo %dx%d (format %d)",
541 handle->stride = stride;
543 if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) {
544 ALOGE("failed to flink ibo");
545 drm_intel_bo_unreference(ib->ibo);
551 ib->base.fb_handle = ib->ibo->handle;
553 ib->base.handle = handle;
558 static void intel_free(struct gralloc_drm_drv_t *drv,
559 struct gralloc_drm_bo_t *bo)
561 struct intel_buffer *ib = (struct intel_buffer *) bo;
563 drm_intel_bo_unreference(ib->ibo);
567 static int intel_map(struct gralloc_drm_drv_t *drv,
568 struct gralloc_drm_bo_t *bo,
569 int x, int y, int w, int h,
570 int enable_write, void **addr)
572 struct intel_buffer *ib = (struct intel_buffer *) bo;
575 if (ib->tiling != I915_TILING_NONE ||
576 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
577 err = drm_intel_gem_bo_map_gtt(ib->ibo);
579 err = drm_intel_bo_map(ib->ibo, enable_write);
581 *addr = ib->ibo->virtual;
586 static void intel_unmap(struct gralloc_drm_drv_t *drv,
587 struct gralloc_drm_bo_t *bo)
589 struct intel_buffer *ib = (struct intel_buffer *) bo;
591 if (ib->tiling != I915_TILING_NONE ||
592 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
593 drm_intel_gem_bo_unmap_gtt(ib->ibo);
595 drm_intel_bo_unmap(ib->ibo);
598 #include "intel_chipset.h" /* for platform detection macros */
599 static void intel_init_kms_features(struct gralloc_drm_drv_t *drv,
600 struct gralloc_drm_t *drm)
602 struct intel_info *info = (struct intel_info *) drv;
603 struct drm_i915_getparam gp;
604 int pageflipping, id, has_blt;
606 drm->mode_quirk_vmwgfx = 0;
608 drm->mode_sync_flip = 1;
610 memset(&gp, 0, sizeof(gp));
611 gp.param = I915_PARAM_HAS_PAGEFLIPPING;
612 gp.value = &pageflipping;
613 if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
616 memset(&gp, 0, sizeof(gp));
617 gp.param = I915_PARAM_CHIPSET_ID;
619 if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
622 memset(&gp, 0, sizeof(gp));
623 gp.param = I915_PARAM_HAS_BLT;
625 if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
627 info->exec_blt = has_blt ? I915_EXEC_BLT : 0;
629 /* GEN4, G4X, GEN5, GEN6, GEN7 */
630 if ((IS_9XX(id) || IS_G4X(id)) && !IS_GEN3(id)) {
633 else if (IS_GEN8(id))
635 else if (IS_GEN7(id))
637 else if (IS_GEN6(id))
639 else if (IS_GEN5(id))
648 if (pageflipping && info->gen > 30)
649 drm->swap_mode = DRM_SWAP_FLIP;
650 else if (info->batch && info->gen == 30)
651 drm->swap_mode = DRM_SWAP_COPY;
653 drm->swap_mode = DRM_SWAP_SETCRTC;
655 if (drm->resources) {
658 pipe = drm_intel_get_pipe_from_crtc_id(info->bufmgr,
659 drm->primary->crtc_id);
660 drm->swap_interval = (pipe >= 0) ? 1 : 0;
661 drm->vblank_secondary = (pipe > 0);
664 drm->swap_interval = 0;
667 switch (drm->primary->fb_format) {
668 case HAL_PIXEL_FORMAT_BGRA_8888:
669 case HAL_PIXEL_FORMAT_RGB_565:
671 case HAL_PIXEL_FORMAT_RGBA_8888:
672 if (drm->swap_mode == DRM_SWAP_FLIP)
676 drm->primary->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
681 static void intel_destroy(struct gralloc_drm_drv_t *drv)
683 struct intel_info *info = (struct intel_info *) drv;
686 drm_intel_bufmgr_destroy(info->bufmgr);
690 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd)
692 struct intel_info *info;
694 info = calloc(1, sizeof(*info));
696 ALOGE("failed to allocate driver info");
701 info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
703 ALOGE("failed to create buffer manager");
710 info->base.destroy = intel_destroy;
711 info->base.init_kms_features = intel_init_kms_features;
712 info->base.alloc = intel_alloc;
713 info->base.free = intel_free;
714 info->base.map = intel_map;
715 info->base.unmap = intel_unmap;
716 info->base.blit = intel_blit;
717 info->base.resolve_format = intel_resolve_format;