1 /*
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 
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
batch_next(struct intel_info * info)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
batch_count(struct intel_info * info)89 batch_count(struct intel_info *info)
90 {
91 	return info->cur - info->batch;
92 }
93 
94 static void
batch_dword(struct intel_info * info,uint32_t dword)95 batch_dword(struct intel_info *info, uint32_t dword)
96 {
97 	*info->cur++ = dword;
98 }
99 
100 static int
batch_reloc(struct intel_info * info,struct gralloc_drm_bo_t * bo,uint32_t read_domains,uint32_t write_domain)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
batch_flush(struct intel_info * info)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
batch_reserve(struct intel_info * info,int count)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
batch_destroy(struct intel_info * info)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
batch_init(struct intel_info * info)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 
intel_resolve_format(struct gralloc_drm_drv_t * drv,struct gralloc_drm_bo_t * bo,uint32_t * pitches,uint32_t * offsets,uint32_t * handles)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 
alloc_ibo(struct intel_info * info,const struct gralloc_drm_handle_t * handle,uint32_t * tiling,unsigned long * stride)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 
intel_alloc(struct gralloc_drm_drv_t * drv,struct gralloc_drm_handle_t * handle)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 
intel_free(struct gralloc_drm_drv_t * drv,struct gralloc_drm_bo_t * bo)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 
intel_map(struct gralloc_drm_drv_t * drv,struct gralloc_drm_bo_t * bo,int x,int y,int w,int h,int enable_write,void ** addr)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 
intel_unmap(struct gralloc_drm_drv_t * drv,struct gralloc_drm_bo_t * bo)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 */
gen_init(struct intel_info * info)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 
intel_destroy(struct gralloc_drm_drv_t * drv)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 
gralloc_drm_drv_create_for_intel(int fd)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