Home | History | Annotate | Download | only in drm_gralloc
      1 /*
      2  * Copyright (C) 2010-2011 Chia-I Wu <olvaffe (at) 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 (at) 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 
     55 struct 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 	int exec_blt;
     66 };
     67 
     68 struct intel_buffer {
     69 	struct gralloc_drm_bo_t base;
     70 	drm_intel_bo *ibo;
     71 	uint32_t tiling;
     72 };
     73 
     74 static int
     75 batch_next(struct intel_info *info)
     76 {
     77 	info->cur = info->batch;
     78 
     79 	if (info->batch_ibo)
     80 		drm_intel_bo_unreference(info->batch_ibo);
     81 
     82 	info->batch_ibo = drm_intel_bo_alloc(info->bufmgr,
     83 			"gralloc-batchbuffer", info->size, 4096);
     84 
     85 	return (info->batch_ibo) ? 0 : -ENOMEM;
     86 }
     87 
     88 static int
     89 batch_count(struct intel_info *info)
     90 {
     91 	return info->cur - info->batch;
     92 }
     93 
     94 static void
     95 batch_dword(struct intel_info *info, uint32_t dword)
     96 {
     97 	*info->cur++ = dword;
     98 }
     99 
    100 static int
    101 batch_reloc(struct intel_info *info, struct gralloc_drm_bo_t *bo,
    102 		uint32_t read_domains, uint32_t write_domain)
    103 {
    104 	struct intel_buffer *target = (struct intel_buffer *) bo;
    105 	uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]);
    106 	int ret;
    107 
    108 	ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset,
    109 			target->ibo, 0, read_domains, write_domain);
    110 	if (!ret)
    111 		batch_dword(info, target->ibo->offset);
    112 
    113 	return ret;
    114 }
    115 
    116 static int
    117 batch_flush(struct intel_info *info)
    118 {
    119 	int size, ret;
    120 
    121 	batch_dword(info, MI_BATCH_BUFFER_END);
    122 	size = batch_count(info);
    123 	if (size & 1) {
    124 		batch_dword(info, MI_NOOP);
    125 		size = batch_count(info);
    126 	}
    127 
    128 	size *= sizeof(info->batch[0]);
    129 	ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch);
    130 	if (ret) {
    131 		ALOGE("failed to subdata batch");
    132 		goto fail;
    133 	}
    134 	ret = drm_intel_bo_mrb_exec(info->batch_ibo, size,
    135 		NULL, 0, 0, info->exec_blt);
    136 	if (ret) {
    137 		ALOGE("failed to exec batch");
    138 		goto fail;
    139 	}
    140 
    141 	return batch_next(info);
    142 
    143 fail:
    144 	info->cur = info->batch;
    145 
    146 	return ret;
    147 }
    148 
    149 static int
    150 batch_reserve(struct intel_info *info, int count)
    151 {
    152 	int ret = 0;
    153 
    154 	if (batch_count(info) + count > info->capacity)
    155 		ret = batch_flush(info);
    156 
    157 	return ret;
    158 }
    159 
    160 static void
    161 batch_destroy(struct intel_info *info)
    162 {
    163 	if (info->batch_ibo) {
    164 		drm_intel_bo_unreference(info->batch_ibo);
    165 		info->batch_ibo = NULL;
    166 	}
    167 
    168 	if (info->batch) {
    169 		free(info->batch);
    170 		info->batch = NULL;
    171 	}
    172 }
    173 
    174 static int
    175 batch_init(struct intel_info *info)
    176 {
    177 	int ret;
    178 
    179 	info->capacity = 512;
    180 	info->size = (info->capacity + 16) * sizeof(info->batch[0]);
    181 
    182 	info->batch = malloc(info->size);
    183 	if (!info->batch)
    184 		return -ENOMEM;
    185 
    186 	ret = batch_next(info);
    187 	if (ret) {
    188 		free(info->batch);
    189 		info->batch = NULL;
    190 	}
    191 
    192 	return ret;
    193 }
    194 
    195 static void intel_resolve_format(struct gralloc_drm_drv_t *drv,
    196 		struct gralloc_drm_bo_t *bo,
    197 		uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
    198 {
    199 	/*
    200 	 * TODO - should take account hw specific padding, alignment
    201 	 * for camera, video decoder etc.
    202 	 */
    203 
    204 	struct intel_buffer *ib = (struct intel_buffer *) bo;
    205 
    206 	memset(pitches, 0, 4 * sizeof(uint32_t));
    207 	memset(offsets, 0, 4 * sizeof(uint32_t));
    208 	memset(handles, 0, 4 * sizeof(uint32_t));
    209 
    210 	pitches[0] = ib->base.handle->stride;
    211 	handles[0] = ib->base.fb_handle;
    212 
    213 	switch(ib->base.handle->format) {
    214 		case HAL_PIXEL_FORMAT_YV12:
    215 
    216 			// U and V stride are half of Y plane
    217 			pitches[2] = pitches[0]/2;
    218 			pitches[1] = pitches[0]/2;
    219 
    220 			// like I420 but U and V are in reverse order
    221 			offsets[2] = offsets[0] +
    222 				pitches[0] * ib->base.handle->height;
    223 			offsets[1] = offsets[2] +
    224 				pitches[2] * ib->base.handle->height/2;
    225 
    226 			handles[1] = handles[2] = handles[0];
    227 			break;
    228 
    229 		case HAL_PIXEL_FORMAT_DRM_NV12:
    230 
    231 			// U and V are interleaved in 2nd plane
    232 			pitches[1] = pitches[0];
    233 			offsets[1] = offsets[0] +
    234 				pitches[0] * ib->base.handle->height;
    235 
    236 			handles[1] = handles[0];
    237 			break;
    238 	}
    239 }
    240 
    241 static drm_intel_bo *alloc_ibo(struct intel_info *info,
    242 		const struct gralloc_drm_handle_t *handle,
    243 		uint32_t *tiling, unsigned long *stride)
    244 {
    245 	drm_intel_bo *ibo;
    246 	const char *name;
    247 	int aligned_width, aligned_height, bpp;
    248 	unsigned long flags;
    249 
    250 	flags = 0;
    251 	bpp = gralloc_drm_get_bpp(handle->format);
    252 	if (!bpp) {
    253 		ALOGE("unrecognized format 0x%x", handle->format);
    254 		return NULL;
    255 	}
    256 
    257 	aligned_width = handle->width;
    258 	aligned_height = handle->height;
    259 	gralloc_drm_align_geometry(handle->format,
    260 			&aligned_width, &aligned_height);
    261 
    262 	if (handle->usage & GRALLOC_USAGE_HW_FB) {
    263 		unsigned long max_stride;
    264 
    265 		max_stride = 32 * 1024;
    266 		if (info->gen < 50)
    267 			max_stride /= 2;
    268 		if (info->gen < 40)
    269 			max_stride /= 2;
    270 
    271 		name = "gralloc-fb";
    272 		aligned_width = ALIGN(aligned_width, 64);
    273 		flags = BO_ALLOC_FOR_RENDER;
    274 
    275 		*tiling = I915_TILING_X;
    276 		*stride = aligned_width * bpp;
    277 		if (*stride > max_stride) {
    278 			*tiling = I915_TILING_NONE;
    279 			max_stride = 32 * 1024;
    280 			if (*stride > max_stride)
    281 				return NULL;
    282 		}
    283 
    284 		while (1) {
    285 			ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
    286 					aligned_width, aligned_height,
    287 					bpp, tiling, stride, flags);
    288 			if (!ibo || *stride > max_stride) {
    289 				if (ibo) {
    290 					drm_intel_bo_unreference(ibo);
    291 					ibo = NULL;
    292 				}
    293 
    294 				if (*tiling != I915_TILING_NONE) {
    295 					/* retry */
    296 					*tiling = I915_TILING_NONE;
    297 					max_stride = 32 * 1024;
    298 					continue;
    299 				}
    300 			}
    301 			if (ibo)
    302 				drm_intel_bo_disable_reuse(ibo);
    303 			break;
    304 		}
    305 	}
    306 	else {
    307 		if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN |
    308 				     GRALLOC_USAGE_SW_WRITE_OFTEN))
    309 			*tiling = I915_TILING_NONE;
    310 		else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) ||
    311 			 ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) &&
    312 			  handle->width >= 64))
    313 			*tiling = I915_TILING_X;
    314 		else
    315 			*tiling = I915_TILING_NONE;
    316 
    317 		if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) {
    318 			name = "gralloc-texture";
    319 			/* see 2D texture layout of DRI drivers */
    320 			aligned_width = ALIGN(aligned_width, 4);
    321 			aligned_height = ALIGN(aligned_height, 2);
    322 		}
    323 		else {
    324 			name = "gralloc-buffer";
    325 		}
    326 
    327 		if (handle->usage & GRALLOC_USAGE_HW_RENDER)
    328 			flags = BO_ALLOC_FOR_RENDER;
    329 
    330 		ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
    331 				aligned_width, aligned_height,
    332 				bpp, tiling, stride, flags);
    333 	}
    334 
    335 	return ibo;
    336 }
    337 
    338 static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv,
    339 		struct gralloc_drm_handle_t *handle)
    340 {
    341 	struct intel_info *info = (struct intel_info *) drv;
    342 	struct intel_buffer *ib;
    343 
    344 	ib = calloc(1, sizeof(*ib));
    345 	if (!ib)
    346 		return NULL;
    347 
    348 	if (handle->name) {
    349 		uint32_t dummy;
    350 
    351 		ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr,
    352 				"gralloc-r", handle->name);
    353 		if (!ib->ibo) {
    354 			ALOGE("failed to create ibo from name %u",
    355 					handle->name);
    356 			free(ib);
    357 			return NULL;
    358 		}
    359 
    360 		if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
    361 			ALOGE("failed to get ibo tiling");
    362 			drm_intel_bo_unreference(ib->ibo);
    363 			free(ib);
    364 			return NULL;
    365 		}
    366 	}
    367 	else {
    368 		unsigned long stride;
    369 
    370 		ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride);
    371 		if (!ib->ibo) {
    372 			ALOGE("failed to allocate ibo %dx%d (format %d)",
    373 					handle->width,
    374 					handle->height,
    375 					handle->format);
    376 			free(ib);
    377 			return NULL;
    378 		}
    379 
    380 		handle->stride = stride;
    381 
    382 		if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) {
    383 			ALOGE("failed to flink ibo");
    384 			drm_intel_bo_unreference(ib->ibo);
    385 			free(ib);
    386 			return NULL;
    387 		}
    388 	}
    389 
    390 	ib->base.fb_handle = ib->ibo->handle;
    391 
    392 	ib->base.handle = handle;
    393 
    394 	return &ib->base;
    395 }
    396 
    397 static void intel_free(struct gralloc_drm_drv_t *drv,
    398 		struct gralloc_drm_bo_t *bo)
    399 {
    400 	struct intel_buffer *ib = (struct intel_buffer *) bo;
    401 
    402 	drm_intel_bo_unreference(ib->ibo);
    403 	free(ib);
    404 }
    405 
    406 static int intel_map(struct gralloc_drm_drv_t *drv,
    407 		struct gralloc_drm_bo_t *bo,
    408 		int x, int y, int w, int h,
    409 		int enable_write, void **addr)
    410 {
    411 	struct intel_buffer *ib = (struct intel_buffer *) bo;
    412 	int err;
    413 
    414 	if (ib->tiling != I915_TILING_NONE ||
    415 	    (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
    416 		err = drm_intel_gem_bo_map_gtt(ib->ibo);
    417 	else
    418 		err = drm_intel_bo_map(ib->ibo, enable_write);
    419 	if (!err)
    420 		*addr = ib->ibo->virtual;
    421 
    422 	return err;
    423 }
    424 
    425 static void intel_unmap(struct gralloc_drm_drv_t *drv,
    426 		struct gralloc_drm_bo_t *bo)
    427 {
    428 	struct intel_buffer *ib = (struct intel_buffer *) bo;
    429 
    430 	if (ib->tiling != I915_TILING_NONE ||
    431 	    (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
    432 		drm_intel_gem_bo_unmap_gtt(ib->ibo);
    433 	else
    434 		drm_intel_bo_unmap(ib->ibo);
    435 }
    436 
    437 #include "intel_chipset.h" /* for platform detection macros */
    438 static void gen_init(struct intel_info *info)
    439 {
    440 	struct drm_i915_getparam gp;
    441 	int pageflipping, id, has_blt;
    442 
    443 	memset(&gp, 0, sizeof(gp));
    444 	gp.param = I915_PARAM_CHIPSET_ID;
    445 	gp.value = &id;
    446 	if (drmCommandWriteRead(info->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
    447 		id = 0;
    448 
    449 	memset(&gp, 0, sizeof(gp));
    450 	gp.param = I915_PARAM_HAS_BLT;
    451 	gp.value = &has_blt;
    452 	if (drmCommandWriteRead(info->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
    453 		has_blt = 0;
    454 	info->exec_blt = has_blt ? I915_EXEC_BLT : 0;
    455 
    456 	/* GEN4, G4X, GEN5, GEN6, GEN7 */
    457 	if ((IS_9XX(id) || IS_G4X(id)) && !IS_GEN3(id)) {
    458 		if (IS_GEN7(id))
    459 			info->gen = 70;
    460 		else if (IS_GEN6(id))
    461 			info->gen = 60;
    462 		else if (IS_GEN5(id))
    463 			info->gen = 50;
    464 		else
    465 			info->gen = 40;
    466 	}
    467 	else {
    468 		info->gen = 30;
    469 	}
    470 }
    471 
    472 static void intel_destroy(struct gralloc_drm_drv_t *drv)
    473 {
    474 	struct intel_info *info = (struct intel_info *) drv;
    475 
    476 	batch_destroy(info);
    477 	drm_intel_bufmgr_destroy(info->bufmgr);
    478 	free(info);
    479 }
    480 
    481 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd)
    482 {
    483 	struct intel_info *info;
    484 
    485 	info = calloc(1, sizeof(*info));
    486 	if (!info) {
    487 		ALOGE("failed to allocate driver info");
    488 		return NULL;
    489 	}
    490 
    491 	info->fd = fd;
    492 	info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
    493 	if (!info->bufmgr) {
    494 		ALOGE("failed to create buffer manager");
    495 		free(info);
    496 		return NULL;
    497 	}
    498 
    499 	batch_init(info);
    500 	gen_init(info);
    501 
    502 	info->base.destroy = intel_destroy;
    503 	info->base.alloc = intel_alloc;
    504 	info->base.free = intel_free;
    505 	info->base.map = intel_map;
    506 	info->base.unmap = intel_unmap;
    507 	info->base.resolve_format = intel_resolve_format;
    508 
    509 	return &info->base;
    510 }
    511