gralloc_drm_intel.c revision a8f0334ef5706875f2c73a2690a2f1fc3e5fee27
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
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) {
130		ALOGE("failed to subdata batch");
131		goto fail;
132	}
133	ret = drm_intel_bo_exec(info->batch_ibo, size, NULL, 0, 0);
134	if (ret) {
135		ALOGE("failed to exec batch");
136		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_resolve_format(struct gralloc_drm_drv_t *drv,
194		struct gralloc_drm_bo_t *bo,
195		uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
196{
197	/*
198	 * TODO - should take account hw specific padding, alignment
199	 * for camera, video decoder etc.
200	 */
201
202	struct intel_buffer *ib = (struct intel_buffer *) bo;
203
204	memset(pitches, 0, 4 * sizeof(uint32_t));
205	memset(offsets, 0, 4 * sizeof(uint32_t));
206	memset(handles, 0, 4 * sizeof(uint32_t));
207
208	pitches[0] = ib->base.handle->stride;
209	handles[0] = ib->base.fb_handle;
210
211	switch(ib->base.handle->format) {
212		case HAL_PIXEL_FORMAT_YV12:
213
214			// U and V stride are half of Y plane
215			pitches[2] = pitches[0]/2;
216			pitches[1] = pitches[0]/2;
217
218			// like I420 but U and V are in reverse order
219			offsets[2] = offsets[0] +
220				pitches[0] * ib->base.handle->height;
221			offsets[1] = offsets[2] +
222				pitches[2] * ib->base.handle->height/2;
223
224			handles[1] = handles[2] = handles[0];
225			break;
226
227		case HAL_PIXEL_FORMAT_DRM_NV12:
228
229			// U and V are interleaved in 2nd plane
230			pitches[1] = pitches[0];
231			offsets[1] = offsets[0] +
232				pitches[0] * ib->base.handle->height;
233
234			handles[1] = handles[0];
235			break;
236	}
237}
238
239static void intel_copy(struct gralloc_drm_drv_t *drv,
240		struct gralloc_drm_bo_t *dst,
241		struct gralloc_drm_bo_t *src,
242		short x1, short y1, short x2, short y2)
243{
244	struct intel_info *info = (struct intel_info *) drv;
245	struct intel_buffer *dst_ib = (struct intel_buffer *) dst;
246	struct intel_buffer *src_ib = (struct intel_buffer *) src;
247	drm_intel_bo *bo_table[3];
248	uint32_t cmd, br13, dst_pitch, src_pitch;
249
250	if (dst->handle->width != src->handle->width ||
251	    dst->handle->height != src->handle->height ||
252	    dst->handle->stride != src->handle->stride ||
253	    dst->handle->format != src->handle->format) {
254		ALOGE("copy between incompatible buffers");
255		return;
256	}
257
258	if (x1 < 0)
259		x1 = 0;
260	if (y1 < 0)
261		y1 = 0;
262	if (x2 > dst->handle->width)
263		x2 = dst->handle->width;
264	if (y2 > dst->handle->height)
265		y2 = dst->handle->height;
266
267	if (x2 <= x1 || y2 <= y1)
268		return;
269
270	bo_table[0] = info->batch_ibo;
271	bo_table[1] = src_ib->ibo;
272	bo_table[2] = dst_ib->ibo;
273	if (drm_intel_bufmgr_check_aperture_space(bo_table, 3)) {
274		if (batch_flush(info))
275			return;
276		assert(!drm_intel_bufmgr_check_aperture_space(bo_table, 3));
277	}
278
279	cmd = XY_SRC_COPY_BLT_CMD;
280	br13 = 0xcc << 16; /* ROP_S/GXcopy */
281	dst_pitch = dst->handle->stride;
282	src_pitch = src->handle->stride;
283
284	switch (gralloc_drm_get_bpp(dst->handle->format)) {
285	case 1:
286		break;
287	case 2:
288		br13 |= (1 << 24);
289		break;
290	case 4:
291		br13 |= (1 << 24) | (1 << 25);
292		cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
293		break;
294	default:
295		ALOGE("copy with unsupported format");
296		return;
297	}
298
299	if (info->gen >= 40) {
300		if (dst_ib->tiling != I915_TILING_NONE) {
301			assert(dst_pitch % 512 == 0);
302			dst_pitch >>= 2;
303			cmd |= XY_SRC_COPY_BLT_DST_TILED;
304		}
305		if (src_ib->tiling != I915_TILING_NONE) {
306			assert(src_pitch % 512 == 0);
307			src_pitch >>= 2;
308			cmd |= XY_SRC_COPY_BLT_SRC_TILED;
309		}
310	}
311
312	if (batch_reserve(info, 8))
313		return;
314
315	batch_dword(info, cmd);
316	batch_dword(info, br13 | dst_pitch);
317	batch_dword(info, (y1 << 16) | x1);
318	batch_dword(info, (y2 << 16) | x2);
319	batch_reloc(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
320	batch_dword(info, (y1 << 16) | x1);
321	batch_dword(info, src_pitch);
322	batch_reloc(info, src, I915_GEM_DOMAIN_RENDER, 0);
323
324	if (info->gen >= 60) {
325		batch_reserve(info, 4);
326		batch_dword(info, MI_FLUSH_DW | 2);
327		batch_dword(info, 0);
328		batch_dword(info, 0);
329		batch_dword(info, 0);
330	}
331	else {
332		int flags = (info->gen >= 40) ? 0 :
333			MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE;
334
335		batch_reserve(info, 1);
336		batch_dword(info, MI_FLUSH | flags);
337	}
338
339	batch_flush(info);
340}
341
342static drm_intel_bo *alloc_ibo(struct intel_info *info,
343		const struct gralloc_drm_handle_t *handle,
344		uint32_t *tiling, unsigned long *stride)
345{
346	drm_intel_bo *ibo;
347	const char *name;
348	int aligned_width, aligned_height, bpp;
349	unsigned long flags;
350
351	flags = 0;
352	bpp = gralloc_drm_get_bpp(handle->format);
353	if (!bpp) {
354		ALOGE("unrecognized format 0x%x", handle->format);
355		return NULL;
356	}
357
358	aligned_width = handle->width;
359	aligned_height = handle->height;
360	gralloc_drm_align_geometry(handle->format,
361			&aligned_width, &aligned_height);
362
363	if (handle->usage & GRALLOC_USAGE_HW_FB) {
364		unsigned long max_stride;
365
366		max_stride = 32 * 1024;
367		if (info->gen < 50)
368			max_stride /= 2;
369		if (info->gen < 40)
370			max_stride /= 2;
371
372		name = "gralloc-fb";
373		aligned_width = (aligned_width + 63) & ~63;
374		flags = BO_ALLOC_FOR_RENDER;
375
376		*tiling = I915_TILING_X;
377		*stride = aligned_width * bpp;
378		if (*stride > max_stride) {
379			*tiling = I915_TILING_NONE;
380			max_stride = 32 * 1024;
381			if (*stride > max_stride)
382				return NULL;
383		}
384
385		while (1) {
386			ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
387					aligned_width, aligned_height,
388					bpp, tiling, stride, flags);
389			if (!ibo || *stride > max_stride) {
390				if (ibo) {
391					drm_intel_bo_unreference(ibo);
392					ibo = NULL;
393				}
394
395				if (*tiling != I915_TILING_NONE) {
396					/* retry */
397					*tiling = I915_TILING_NONE;
398					max_stride = 32 * 1024;
399					continue;
400				}
401			}
402			if (ibo)
403				drm_intel_bo_disable_reuse(ibo);
404			break;
405		}
406	}
407	else {
408		if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN |
409				     GRALLOC_USAGE_SW_WRITE_OFTEN))
410			*tiling = I915_TILING_NONE;
411		else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) ||
412			 ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) &&
413			  handle->width >= 64))
414			*tiling = I915_TILING_X;
415		else
416			*tiling = I915_TILING_NONE;
417
418		if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) {
419			name = "gralloc-texture";
420			/* see 2D texture layout of DRI drivers */
421			aligned_width = (aligned_width + 3) & ~3;
422			aligned_height = (aligned_height + 1) & ~1;
423		}
424		else {
425			name = "gralloc-buffer";
426		}
427
428		if (handle->usage & GRALLOC_USAGE_HW_RENDER)
429			flags = BO_ALLOC_FOR_RENDER;
430
431		ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name,
432				aligned_width, aligned_height,
433				bpp, tiling, stride, flags);
434	}
435
436	return ibo;
437}
438
439static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv,
440		struct gralloc_drm_handle_t *handle)
441{
442	struct intel_info *info = (struct intel_info *) drv;
443	struct intel_buffer *ib;
444
445	ib = calloc(1, sizeof(*ib));
446	if (!ib)
447		return NULL;
448
449	if (handle->name) {
450		uint32_t dummy;
451
452		ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr,
453				"gralloc-r", handle->name);
454		if (!ib->ibo) {
455			ALOGE("failed to create ibo from name %u",
456					handle->name);
457			free(ib);
458			return NULL;
459		}
460
461		if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) {
462			ALOGE("failed to get ibo tiling");
463			drm_intel_bo_unreference(ib->ibo);
464			free(ib);
465			return NULL;
466		}
467	}
468	else {
469		unsigned long stride;
470
471		ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride);
472		if (!ib->ibo) {
473			ALOGE("failed to allocate ibo %dx%d (format %d)",
474					handle->width,
475					handle->height,
476					handle->format);
477			free(ib);
478			return NULL;
479		}
480
481		handle->stride = stride;
482
483		if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) {
484			ALOGE("failed to flink ibo");
485			drm_intel_bo_unreference(ib->ibo);
486			free(ib);
487			return NULL;
488		}
489	}
490
491	ib->base.fb_handle = ib->ibo->handle;
492
493	ib->base.handle = handle;
494
495	return &ib->base;
496}
497
498static void intel_free(struct gralloc_drm_drv_t *drv,
499		struct gralloc_drm_bo_t *bo)
500{
501	struct intel_buffer *ib = (struct intel_buffer *) bo;
502
503	drm_intel_bo_unreference(ib->ibo);
504	free(ib);
505}
506
507static int intel_map(struct gralloc_drm_drv_t *drv,
508		struct gralloc_drm_bo_t *bo,
509		int x, int y, int w, int h,
510		int enable_write, void **addr)
511{
512	struct intel_buffer *ib = (struct intel_buffer *) bo;
513	int err;
514
515	if (ib->tiling != I915_TILING_NONE ||
516	    (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
517		err = drm_intel_gem_bo_map_gtt(ib->ibo);
518	else
519		err = drm_intel_bo_map(ib->ibo, enable_write);
520	if (!err)
521		*addr = ib->ibo->virtual;
522
523	return err;
524}
525
526static void intel_unmap(struct gralloc_drm_drv_t *drv,
527		struct gralloc_drm_bo_t *bo)
528{
529	struct intel_buffer *ib = (struct intel_buffer *) bo;
530
531	if (ib->tiling != I915_TILING_NONE ||
532	    (ib->base.handle->usage & GRALLOC_USAGE_HW_FB))
533		drm_intel_gem_bo_unmap_gtt(ib->ibo);
534	else
535		drm_intel_bo_unmap(ib->ibo);
536}
537
538#include "intel_chipset.h" /* for platform detection macros */
539static void intel_init_kms_features(struct gralloc_drm_drv_t *drv,
540		struct gralloc_drm_t *drm)
541{
542	struct intel_info *info = (struct intel_info *) drv;
543	struct drm_i915_getparam gp;
544	int pageflipping, id;
545
546	switch (drm->primary.fb_format) {
547	case HAL_PIXEL_FORMAT_BGRA_8888:
548	case HAL_PIXEL_FORMAT_RGB_565:
549		break;
550	default:
551		drm->primary.fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
552		break;
553	}
554
555	drm->mode_quirk_vmwgfx = 0;
556	/* why? */
557	drm->mode_sync_flip = 1;
558
559	memset(&gp, 0, sizeof(gp));
560	gp.param = I915_PARAM_HAS_PAGEFLIPPING;
561	gp.value = &pageflipping;
562	if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
563		pageflipping = 0;
564
565	memset(&gp, 0, sizeof(gp));
566	gp.param = I915_PARAM_CHIPSET_ID;
567	gp.value = &id;
568	if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp)))
569		id = 0;
570
571	/* GEN4, G4X, GEN5, GEN6, GEN7 */
572	if ((IS_9XX(id) || IS_G4X(id)) && !IS_GEN3(id)) {
573		if (IS_GEN7(id))
574			info->gen = 70;
575		else if (IS_GEN6(id))
576			info->gen = 60;
577		else if (IS_GEN5(id))
578			info->gen = 50;
579		else
580			info->gen = 40;
581	}
582	else {
583		info->gen = 30;
584	}
585
586	if (pageflipping && info->gen > 30)
587		drm->swap_mode = DRM_SWAP_FLIP;
588	else if (info->batch && info->gen == 30)
589		drm->swap_mode = DRM_SWAP_COPY;
590	else
591		drm->swap_mode = DRM_SWAP_SETCRTC;
592
593	if (drm->resources) {
594		int pipe;
595
596		pipe = drm_intel_get_pipe_from_crtc_id(info->bufmgr,
597				drm->primary.crtc_id);
598		drm->swap_interval = (pipe >= 0) ? 1 : 0;
599		drm->vblank_secondary = (pipe > 0);
600	}
601	else {
602		drm->swap_interval = 0;
603	}
604}
605
606static void intel_destroy(struct gralloc_drm_drv_t *drv)
607{
608	struct intel_info *info = (struct intel_info *) drv;
609
610	batch_destroy(info);
611	drm_intel_bufmgr_destroy(info->bufmgr);
612	free(info);
613}
614
615struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd)
616{
617	struct intel_info *info;
618
619	info = calloc(1, sizeof(*info));
620	if (!info) {
621		ALOGE("failed to allocate driver info");
622		return NULL;
623	}
624
625	info->fd = fd;
626	info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024);
627	if (!info->bufmgr) {
628		ALOGE("failed to create buffer manager");
629		free(info);
630		return NULL;
631	}
632
633	batch_init(info);
634
635	info->base.destroy = intel_destroy;
636	info->base.init_kms_features = intel_init_kms_features;
637	info->base.alloc = intel_alloc;
638	info->base.free = intel_free;
639	info->base.map = intel_map;
640	info->base.unmap = intel_unmap;
641	info->base.copy = intel_copy;
642	info->base.resolve_format = intel_resolve_format;
643
644	return &info->base;
645}
646