intel_uxa.c revision 42542f5f
1/**************************************************************************
2
3Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4All Rights Reserved.
5Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org>
6  Based on code from i830_xaa.c.
7
8Permission is hereby granted, free of charge, to any person obtaining a
9copy of this software and associated documentation files (the
10"Software"), to deal in the Software without restriction, including
11without limitation the rights to use, copy, modify, merge, publish,
12distribute, sub license, and/or sell copies of the Software, and to
13permit persons to whom the Software is furnished to do so, subject to
14the following conditions:
15
16The above copyright notice and this permission notice (including the
17next paragraph) shall be included in all copies or substantial portions
18of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
24ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28**************************************************************************/
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include "xorg-server.h"
35#include <xf86.h>
36#include <xf86drm.h>
37#include <xaarop.h>
38#include <string.h>
39#include <errno.h>
40#include <unistd.h>
41
42#include "intel.h"
43#include "intel_glamor.h"
44#include "uxa.h"
45
46#include "i830_reg.h"
47#include "i915_drm.h"
48#include "brw_defines.h"
49
50static const int I830CopyROP[16] = {
51	ROP_0,			/* GXclear */
52	ROP_DSa,		/* GXand */
53	ROP_SDna,		/* GXandReverse */
54	ROP_S,			/* GXcopy */
55	ROP_DSna,		/* GXandInverted */
56	ROP_D,			/* GXnoop */
57	ROP_DSx,		/* GXxor */
58	ROP_DSo,		/* GXor */
59	ROP_DSon,		/* GXnor */
60	ROP_DSxn,		/* GXequiv */
61	ROP_Dn,			/* GXinvert */
62	ROP_SDno,		/* GXorReverse */
63	ROP_Sn,			/* GXcopyInverted */
64	ROP_DSno,		/* GXorInverted */
65	ROP_DSan,		/* GXnand */
66	ROP_1			/* GXset */
67};
68
69static const int I830PatternROP[16] = {
70	ROP_0,
71	ROP_DPa,
72	ROP_PDna,
73	ROP_P,
74	ROP_DPna,
75	ROP_D,
76	ROP_DPx,
77	ROP_DPo,
78	ROP_DPon,
79	ROP_PDxn,
80	ROP_Dn,
81	ROP_PDno,
82	ROP_Pn,
83	ROP_DPno,
84	ROP_DPan,
85	ROP_1
86};
87
88#if HAS_DEVPRIVATEKEYREC
89DevPrivateKeyRec uxa_pixmap_index;
90#else
91int uxa_pixmap_index;
92#endif
93
94static void
95gen6_context_switch(intel_screen_private *intel,
96		    int new_mode)
97{
98	intel_batch_submit(intel->scrn);
99}
100
101static void
102gen5_context_switch(intel_screen_private *intel,
103		    int new_mode)
104{
105	/* Ironlake has a limitation that a 3D or Media command can't
106	 * be the first command after a BLT, unless it's
107	 * non-pipelined.  Instead of trying to track it and emit a
108	 * command at the right time, we just emit a dummy
109	 * non-pipelined 3D instruction after each blit.
110	 */
111
112	if (new_mode == I915_EXEC_BLT) {
113		OUT_BATCH(MI_FLUSH |
114			  MI_STATE_INSTRUCTION_CACHE_FLUSH |
115			  MI_INHIBIT_RENDER_CACHE_FLUSH);
116	} else {
117		OUT_BATCH(CMD_POLY_STIPPLE_OFFSET << 16);
118		OUT_BATCH(0);
119	}
120}
121
122static void
123gen4_context_switch(intel_screen_private *intel,
124		    int new_mode)
125{
126	if (new_mode == I915_EXEC_BLT) {
127		OUT_BATCH(MI_FLUSH |
128			  MI_STATE_INSTRUCTION_CACHE_FLUSH |
129			  MI_INHIBIT_RENDER_CACHE_FLUSH);
130	}
131}
132
133Bool
134intel_get_aperture_space(ScrnInfoPtr scrn, drm_intel_bo ** bo_table,
135			 int num_bos)
136{
137	intel_screen_private *intel = intel_get_screen_private(scrn);
138
139	if (intel->batch_bo == NULL) {
140		intel_debug_fallback(scrn, "VT inactive\n");
141		return FALSE;
142	}
143
144	bo_table[0] = intel->batch_bo;
145	if (drm_intel_bufmgr_check_aperture_space(bo_table, num_bos) != 0) {
146		intel_batch_submit(scrn);
147		bo_table[0] = intel->batch_bo;
148		if (drm_intel_bufmgr_check_aperture_space(bo_table, num_bos) !=
149		    0) {
150			intel_debug_fallback(scrn, "Couldn't get aperture "
151					    "space for BOs\n");
152			return FALSE;
153		}
154	}
155	return TRUE;
156}
157
158static unsigned int
159intel_uxa_compute_size(struct intel_screen_private *intel,
160		       int w, int h, int bpp, unsigned usage,
161		       uint32_t *tiling, int *stride)
162{
163	int pitch, size;
164
165	if (*tiling != I915_TILING_NONE) {
166		/* First check whether tiling is necessary. */
167		pitch = (w * bpp  + 7) / 8;
168		pitch = ALIGN(pitch, 64);
169		size = pitch * ALIGN (h, 2);
170		if (INTEL_INFO(intel)->gen < 040) {
171			/* Gen 2/3 has a maximum stride for tiling of
172			 * 8192 bytes.
173			 */
174			if (pitch > KB(8))
175				*tiling = I915_TILING_NONE;
176
177			/* Narrower than half a tile? */
178			if (pitch < 256)
179				*tiling = I915_TILING_NONE;
180
181			/* Older hardware requires fences to be pot size
182			 * aligned with a minimum of 1 MiB, so causes
183			 * massive overallocation for small textures.
184			 */
185			if (size < 1024*1024/2 && !intel->has_relaxed_fencing)
186				*tiling = I915_TILING_NONE;
187		} else if (!(usage & INTEL_CREATE_PIXMAP_DRI2) && size <= 4096) {
188			/* Disable tiling beneath a page size, we will not see
189			 * any benefit from reducing TLB misses and instead
190			 * just incur extra cost when we require a fence.
191			 */
192			*tiling = I915_TILING_NONE;
193		}
194	}
195
196	pitch = (w * bpp + 7) / 8;
197	if (!(usage & INTEL_CREATE_PIXMAP_DRI2) && pitch <= 256)
198		*tiling = I915_TILING_NONE;
199
200	if (*tiling != I915_TILING_NONE) {
201		int aligned_h, tile_height;
202
203		if (IS_GEN2(intel))
204			tile_height = 16;
205		else if (*tiling == I915_TILING_X)
206			tile_height = 8;
207		else
208			tile_height = 32;
209		aligned_h = ALIGN(h, 2*tile_height);
210
211		*stride = intel_get_fence_pitch(intel,
212						ALIGN(pitch, 512),
213						*tiling);
214
215		/* Round the object up to the size of the fence it will live in
216		 * if necessary.  We could potentially make the kernel allocate
217		 * a larger aperture space and just bind the subset of pages in,
218		 * but this is easier and also keeps us out of trouble (as much)
219		 * with drm_intel_bufmgr_check_aperture().
220		 */
221		size = intel_get_fence_size(intel, *stride * aligned_h);
222
223		if (size > intel->max_tiling_size)
224			*tiling = I915_TILING_NONE;
225	}
226
227	if (*tiling == I915_TILING_NONE) {
228		/* We only require a 64 byte alignment for scanouts, but
229		 * a 256 byte alignment for sharing with PRIME.
230		 */
231		*stride = ALIGN(pitch, 256);
232		/* Round the height up so that the GPU's access to a 2x2 aligned
233		 * subspan doesn't address an invalid page offset beyond the
234		 * end of the GTT.
235		 */
236		size = *stride * ALIGN(h, 2);
237	}
238
239	return size;
240}
241
242drm_intel_bo *intel_allocate_framebuffer(ScrnInfoPtr scrn,
243					 int width, int height, int cpp,
244					 int *out_stride,
245					 uint32_t *out_tiling)
246{
247	intel_screen_private *intel = intel_get_screen_private(scrn);
248	uint32_t tiling;
249	int stride, size;
250	drm_intel_bo *bo;
251
252	if (intel->tiling & INTEL_TILING_FB)
253		tiling = I915_TILING_X;
254	else
255		tiling = I915_TILING_NONE;
256
257retry:
258	size = intel_uxa_compute_size(intel,
259				      width, height,
260				      intel->cpp*8, 0,
261				      &tiling, &stride);
262	if (!intel_check_display_stride(scrn, stride, tiling)) {
263		if (tiling != I915_TILING_NONE) {
264			tiling = I915_TILING_NONE;
265			goto retry;
266		}
267
268		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
269			   "Front buffer stride %d kB "
270			   "exceeds display limit\n", stride / 1024);
271		return NULL;
272	}
273
274	bo = drm_intel_bo_alloc(intel->bufmgr, "front buffer", size, 0);
275	if (bo == NULL)
276		return FALSE;
277
278	if (tiling != I915_TILING_NONE)
279		drm_intel_bo_set_tiling(bo, &tiling, stride);
280
281	xf86DrvMsg(scrn->scrnIndex, X_INFO,
282		   "Allocated new frame buffer %dx%d stride %d, %s\n",
283		   width, height, stride,
284		   tiling == I915_TILING_NONE ? "untiled" : "tiled");
285
286	drm_intel_bo_disable_reuse(bo);
287
288	intel_set_gem_max_sizes(scrn);
289	*out_stride = stride;
290	*out_tiling = tiling;
291	return bo;
292}
293
294static Bool
295intel_uxa_check_solid(DrawablePtr drawable, int alu, Pixel planemask)
296{
297	ScrnInfoPtr scrn = xf86ScreenToScrn(drawable->pScreen);
298
299	if (!UXA_PM_IS_SOLID(drawable, planemask)) {
300		intel_debug_fallback(scrn, "planemask is not solid\n");
301		return FALSE;
302	}
303
304	switch (drawable->bitsPerPixel) {
305	case 8:
306	case 16:
307	case 32:
308		break;
309	default:
310		return FALSE;
311	}
312
313	return TRUE;
314}
315
316/**
317 * Sets up hardware state for a series of solid fills.
318 */
319static Bool
320intel_uxa_prepare_solid(PixmapPtr pixmap, int alu, Pixel planemask, Pixel fg)
321{
322	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
323	intel_screen_private *intel = intel_get_screen_private(scrn);
324	drm_intel_bo *bo_table[] = {
325		NULL,		/* batch_bo */
326		intel_get_pixmap_bo(pixmap),
327	};
328
329	if (!intel_check_pitch_2d(pixmap))
330		return FALSE;
331
332	if (!intel_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table)))
333		return FALSE;
334
335	intel->BR[13] = (I830PatternROP[alu] & 0xff) << 16;
336	switch (pixmap->drawable.bitsPerPixel) {
337	case 8:
338		break;
339	case 16:
340		/* RGB565 */
341		intel->BR[13] |= (1 << 24);
342		break;
343	case 32:
344		/* RGB8888 */
345		intel->BR[13] |= ((1 << 24) | (1 << 25));
346		break;
347	}
348	intel->BR[16] = fg;
349
350	return TRUE;
351}
352
353static void intel_uxa_solid(PixmapPtr pixmap, int x1, int y1, int x2, int y2)
354{
355	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
356	intel_screen_private *intel = intel_get_screen_private(scrn);
357	unsigned long pitch;
358	uint32_t cmd;
359
360	if (x1 < 0)
361		x1 = 0;
362	if (y1 < 0)
363		y1 = 0;
364	if (x2 > pixmap->drawable.width)
365		x2 = pixmap->drawable.width;
366	if (y2 > pixmap->drawable.height)
367		y2 = pixmap->drawable.height;
368
369	if (x2 <= x1 || y2 <= y1)
370		return;
371
372	pitch = intel_pixmap_pitch(pixmap);
373
374	{
375		int len = INTEL_INFO(intel)->gen >= 0100 ? 7 : 6;
376		BEGIN_BATCH_BLT(len);
377
378		cmd = XY_COLOR_BLT_CMD | (len - 2);
379
380		if (pixmap->drawable.bitsPerPixel == 32)
381			cmd |=
382			    XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB;
383
384		if (INTEL_INFO(intel)->gen >= 040 && intel_pixmap_tiled(pixmap)) {
385			assert((pitch % 512) == 0);
386			pitch >>= 2;
387			cmd |= XY_COLOR_BLT_TILED;
388		}
389
390		OUT_BATCH(cmd);
391
392		OUT_BATCH(intel->BR[13] | pitch);
393		OUT_BATCH((y1 << 16) | (x1 & 0xffff));
394		OUT_BATCH((y2 << 16) | (x2 & 0xffff));
395		OUT_RELOC_PIXMAP_FENCED(pixmap, I915_GEM_DOMAIN_RENDER,
396					I915_GEM_DOMAIN_RENDER, 0);
397		OUT_BATCH(intel->BR[16]);
398		ADVANCE_BATCH();
399	}
400}
401
402/**
403 * TODO:
404 *   - support planemask using FULL_BLT_CMD?
405 */
406static Bool
407intel_uxa_check_copy(PixmapPtr source, PixmapPtr dest,
408		    int alu, Pixel planemask)
409{
410	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
411
412	if (!UXA_PM_IS_SOLID(&source->drawable, planemask)) {
413		intel_debug_fallback(scrn, "planemask is not solid");
414		return FALSE;
415	}
416
417	if (source->drawable.bitsPerPixel != dest->drawable.bitsPerPixel) {
418		intel_debug_fallback(scrn, "mixed bpp copies unsupported\n");
419		return FALSE;
420	}
421	switch (source->drawable.bitsPerPixel) {
422	case 8:
423	case 16:
424	case 32:
425		break;
426	default:
427		return FALSE;
428	}
429
430	if (!intel_check_pitch_2d(source))
431		return FALSE;
432	if (!intel_check_pitch_2d(dest))
433		return FALSE;
434
435	return TRUE;
436}
437
438static Bool
439intel_uxa_prepare_copy(PixmapPtr source, PixmapPtr dest, int xdir,
440		      int ydir, int alu, Pixel planemask)
441{
442	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
443	intel_screen_private *intel = intel_get_screen_private(scrn);
444	drm_intel_bo *bo_table[] = {
445		NULL,		/* batch_bo */
446		intel_get_pixmap_bo(source),
447		intel_get_pixmap_bo(dest),
448	};
449
450	if (!intel_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table)))
451		return FALSE;
452
453	intel->render_source = source;
454
455	intel->BR[13] = I830CopyROP[alu] << 16;
456	switch (source->drawable.bitsPerPixel) {
457	case 8:
458		break;
459	case 16:
460		intel->BR[13] |= (1 << 24);
461		break;
462	case 32:
463		intel->BR[13] |= ((1 << 25) | (1 << 24));
464		break;
465	}
466
467	return TRUE;
468}
469
470static void
471intel_uxa_copy(PixmapPtr dest, int src_x1, int src_y1, int dst_x1,
472	      int dst_y1, int w, int h)
473{
474	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
475	intel_screen_private *intel = intel_get_screen_private(scrn);
476	uint32_t cmd;
477	int dst_x2, dst_y2, src_x2, src_y2;
478	unsigned int dst_pitch, src_pitch;
479
480	dst_x2 = dst_x1 + w;
481	dst_y2 = dst_y1 + h;
482
483	/* XXX Fixup extents as a lamentable workaround for missing
484	 * source clipping in the upper layers.
485	 */
486	if (dst_x1 < 0)
487		src_x1 -= dst_x1, dst_x1 = 0;
488	if (dst_y1 < 0)
489		src_y1 -= dst_y1, dst_y1 = 0;
490	if (dst_x2 > dest->drawable.width)
491		dst_x2 = dest->drawable.width;
492	if (dst_y2 > dest->drawable.height)
493		dst_y2 = dest->drawable.height;
494
495	src_x2 = src_x1 + (dst_x2 - dst_x1);
496	src_y2 = src_y1 + (dst_y2 - dst_y1);
497
498	if (src_x1 < 0)
499		dst_x1 -= src_x1, src_x1 = 0;
500	if (src_y1 < 0)
501		dst_y1 -= src_y1, src_y1 = 0;
502	if (src_x2 > intel->render_source->drawable.width)
503		dst_x2 -= src_x2 - intel->render_source->drawable.width;
504	if (src_y2 > intel->render_source->drawable.height)
505		dst_y2 -= src_y2 - intel->render_source->drawable.height;
506
507	if (dst_x2 <= dst_x1 || dst_y2 <= dst_y1)
508		return;
509
510	dst_pitch = intel_pixmap_pitch(dest);
511	src_pitch = intel_pixmap_pitch(intel->render_source);
512
513	{
514		int len = INTEL_INFO(intel)->gen >= 0100 ? 10 : 8;
515		BEGIN_BATCH_BLT(len);
516
517		cmd = XY_SRC_COPY_BLT_CMD | (len - 2);
518
519		if (dest->drawable.bitsPerPixel == 32)
520			cmd |=
521			    XY_SRC_COPY_BLT_WRITE_ALPHA |
522			    XY_SRC_COPY_BLT_WRITE_RGB;
523
524		if (INTEL_INFO(intel)->gen >= 040) {
525			if (intel_pixmap_tiled(dest)) {
526				assert((dst_pitch % 512) == 0);
527				dst_pitch >>= 2;
528				cmd |= XY_SRC_COPY_BLT_DST_TILED;
529			}
530
531			if (intel_pixmap_tiled(intel->render_source)) {
532				assert((src_pitch % 512) == 0);
533				src_pitch >>= 2;
534				cmd |= XY_SRC_COPY_BLT_SRC_TILED;
535			}
536		}
537
538		OUT_BATCH(cmd);
539
540		OUT_BATCH(intel->BR[13] | dst_pitch);
541		OUT_BATCH((dst_y1 << 16) | (dst_x1 & 0xffff));
542		OUT_BATCH((dst_y2 << 16) | (dst_x2 & 0xffff));
543		OUT_RELOC_PIXMAP_FENCED(dest,
544					I915_GEM_DOMAIN_RENDER,
545					I915_GEM_DOMAIN_RENDER,
546					0);
547		OUT_BATCH((src_y1 << 16) | (src_x1 & 0xffff));
548		OUT_BATCH(src_pitch);
549		OUT_RELOC_PIXMAP_FENCED(intel->render_source,
550					I915_GEM_DOMAIN_RENDER, 0,
551					0);
552
553		ADVANCE_BATCH();
554	}
555}
556
557static void intel_uxa_done(PixmapPtr pixmap)
558{
559	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
560	intel_screen_private *intel = intel_get_screen_private(scrn);
561
562	if (INTEL_INFO(intel)->gen >= 060) {
563		/* workaround a random BLT hang */
564		BEGIN_BATCH_BLT(3);
565		OUT_BATCH(XY_SETUP_CLIP_BLT_CMD | (3 - 2));
566		OUT_BATCH(0);
567		OUT_BATCH(0);
568		ADVANCE_BATCH();
569	}
570
571	intel_debug_flush(scrn);
572}
573
574/**
575 * Do any cleanup from the Composite operation.
576 *
577 * This is shared between i830 through i965.
578 */
579static void i830_done_composite(PixmapPtr dest)
580{
581	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
582	intel_screen_private *intel = intel_get_screen_private(scrn);
583
584	if (intel->vertex_flush)
585		intel->vertex_flush(intel);
586
587	intel_debug_flush(scrn);
588}
589
590#define xFixedToFloat(val) \
591	((float)xFixedToInt(val) + ((float)xFixedFrac(val) / 65536.0))
592
593static Bool
594_intel_transform_point(PictTransformPtr transform,
595		       float x, float y, float result[3])
596{
597	int j;
598
599	for (j = 0; j < 3; j++) {
600		result[j] = (xFixedToFloat(transform->matrix[j][0]) * x +
601			     xFixedToFloat(transform->matrix[j][1]) * y +
602			     xFixedToFloat(transform->matrix[j][2]));
603	}
604	if (!result[2])
605		return FALSE;
606	return TRUE;
607}
608
609/**
610 * Returns the floating-point coordinates transformed by the given transform.
611 *
612 * transform may be null.
613 */
614Bool
615intel_get_transformed_coordinates(int x, int y, PictTransformPtr transform,
616				  float *x_out, float *y_out)
617{
618	if (transform == NULL) {
619		*x_out = x;
620		*y_out = y;
621	} else {
622		float result[3];
623
624		if (!_intel_transform_point(transform,
625					    x, y,
626					    result))
627			return FALSE;
628		*x_out = result[0] / result[2];
629		*y_out = result[1] / result[2];
630	}
631	return TRUE;
632}
633
634/**
635 * Returns the un-normalized floating-point coordinates transformed by the given transform.
636 *
637 * transform may be null.
638 */
639Bool
640intel_get_transformed_coordinates_3d(int x, int y, PictTransformPtr transform,
641				     float *x_out, float *y_out, float *w_out)
642{
643	if (transform == NULL) {
644		*x_out = x;
645		*y_out = y;
646		*w_out = 1;
647	} else {
648		float result[3];
649
650		if (!_intel_transform_point(transform,
651					    x, y,
652					    result))
653			return FALSE;
654		*x_out = result[0];
655		*y_out = result[1];
656		*w_out = result[2];
657	}
658	return TRUE;
659}
660
661/**
662 * Returns whether the provided transform is affine.
663 *
664 * transform may be null.
665 */
666Bool intel_transform_is_affine(PictTransformPtr t)
667{
668	if (t == NULL)
669		return TRUE;
670	return t->matrix[2][0] == 0 && t->matrix[2][1] == 0;
671}
672
673dri_bo *intel_get_pixmap_bo(PixmapPtr pixmap)
674{
675	struct intel_pixmap *intel;
676
677	intel = intel_get_pixmap_private(pixmap);
678	if (intel == NULL)
679		return NULL;
680
681	return intel->bo;
682}
683
684static unsigned intel_get_tile_width(intel_screen_private *intel, int tiling, int pitch)
685{
686	unsigned long tile_width;
687
688	if (tiling == I915_TILING_NONE)
689		return 4;
690
691	tile_width = (tiling == I915_TILING_Y) ? 128 : 512;
692	if (INTEL_INFO(intel)->gen >= 040)
693		return tile_width;
694
695	while (tile_width < pitch)
696		tile_width <<= 1;
697
698	return tile_width;
699}
700
701void intel_set_pixmap_bo(PixmapPtr pixmap, dri_bo * bo)
702{
703	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
704	intel_screen_private *intel = intel_get_screen_private(scrn);
705	struct intel_pixmap *priv;
706
707	priv = intel_get_pixmap_private(pixmap);
708	if (priv == NULL && bo == NULL)
709		return;
710
711	if (priv != NULL) {
712		if (priv->bo == bo)
713			return;
714
715free_priv:
716		dri_bo_unreference(priv->bo);
717		list_del(&priv->batch);
718
719		free(priv);
720		priv = NULL;
721	}
722
723	if (bo != NULL) {
724		uint32_t tiling, swizzle_mode;
725		unsigned tile_width;
726		int size, stride;
727
728		priv = calloc(1, sizeof (struct intel_pixmap));
729		if (priv == NULL)
730			goto BAIL;
731
732		list_init(&priv->batch);
733
734		dri_bo_reference(bo);
735		priv->bo = bo;
736		priv->stride = intel_pixmap_pitch(pixmap);
737
738		if (drm_intel_bo_get_tiling(bo, &tiling, &swizzle_mode)) {
739			bo = NULL;
740			goto free_priv;
741		}
742
743		priv->tiling = tiling;
744		priv->busy = -1;
745		priv->offscreen = 1;
746
747		stride = (pixmap->drawable.width * pixmap->drawable.bitsPerPixel + 7) / 8;
748		tile_width = intel_get_tile_width(intel, tiling, stride);
749		stride = ALIGN(stride, tile_width);
750
751		if (priv->stride < stride ||
752		    priv->stride & (tile_width - 1) ||
753		    priv->stride >= KB(32)) {
754			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
755				   "%s: stride on buffer object does not match constraints: stride=%d, must be greater than %d, but less than %d, and have alignment at least %d\n",
756				   __FUNCTION__, priv->stride, stride, KB(32), tile_width);
757			bo = NULL;
758			goto free_priv;
759		}
760
761		if (tiling != I915_TILING_NONE) {
762			int height;
763
764			if (IS_GEN2(intel))
765				height = 16;
766			else if (tiling == I915_TILING_X)
767				height = 8;
768			else
769				height = 32;
770
771			height = ALIGN(pixmap->drawable.height, 2*height);
772			size = intel_get_fence_size(intel, priv->stride * height);
773		} else
774			size = priv->stride * pixmap->drawable.height;
775
776		if (bo->size < size || bo->size > intel->max_bo_size) {
777			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
778				   "%s: size of buffer object does not match constraints: size=%ld, must be greater than %d, but less than %d\n",
779				   __FUNCTION__, (long)bo->size, size, intel->max_bo_size);
780			bo = NULL;
781			goto free_priv;
782		}
783	}
784
785  BAIL:
786	intel_set_pixmap_private(pixmap, priv);
787}
788
789static Bool intel_uxa_pixmap_is_offscreen(PixmapPtr pixmap)
790{
791	return intel_pixmap_is_offscreen(pixmap);
792}
793
794static Bool intel_uxa_prepare_access(PixmapPtr pixmap, uxa_access_t access)
795{
796	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
797	intel_screen_private *intel = intel_get_screen_private(scrn);
798	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
799	dri_bo *bo = priv->bo;
800	int ret;
801
802	/* Transitioning to glamor acceleration, we need to flush all pending
803	 * usage by UXA. */
804	if (access == UXA_GLAMOR_ACCESS_RW || access == UXA_GLAMOR_ACCESS_RO) {
805		if (!list_is_empty(&priv->batch))
806			intel_batch_submit(scrn);
807		return TRUE;
808	}
809
810	/* When falling back to swrast, flush all pending operations */
811	intel_glamor_flush(intel);
812	if (access == UXA_ACCESS_RW || priv->dirty)
813		intel_batch_submit(scrn);
814
815	assert(bo->size <= intel->max_gtt_map_size);
816	ret = drm_intel_gem_bo_map_gtt(bo);
817	if (ret) {
818		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
819			   "%s: bo map (use gtt? %d, access %d) failed: %s\n",
820			   __FUNCTION__,
821			   priv->tiling || bo->size <= intel->max_gtt_map_size,
822			   access,
823			   strerror(-ret));
824		return FALSE;
825	}
826
827	pixmap->devPrivate.ptr = bo->virtual;
828	priv->busy = 0;
829
830	return TRUE;
831}
832
833static void intel_uxa_finish_access(PixmapPtr pixmap, uxa_access_t access)
834{
835	struct intel_pixmap *priv;
836
837	if (access == UXA_GLAMOR_ACCESS_RW || access == UXA_GLAMOR_ACCESS_RO)
838		return;
839
840	priv = intel_get_pixmap_private(pixmap);
841	if (priv == NULL)
842		return;
843
844	drm_intel_gem_bo_unmap_gtt(priv->bo);
845	pixmap->devPrivate.ptr = NULL;
846}
847
848static Bool intel_uxa_pixmap_put_image(PixmapPtr pixmap,
849				       char *src, int src_pitch,
850				       int x, int y, int w, int h)
851{
852	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
853	int stride = intel_pixmap_pitch(pixmap);
854	int cpp = pixmap->drawable.bitsPerPixel/8;
855	int ret = FALSE;
856
857	if (priv == NULL || priv->bo == NULL)
858		return FALSE;
859
860	if (priv->tiling == I915_TILING_NONE &&
861	    (h == 1 || (src_pitch == stride && w == pixmap->drawable.width))) {
862		return drm_intel_bo_subdata(priv->bo, y*stride + x*cpp, stride*(h-1) + w*cpp, src) == 0;
863	} else if (drm_intel_gem_bo_map_gtt(priv->bo) == 0) {
864		char *dst = priv->bo->virtual;
865		int row_length = w * cpp;
866		int num_rows = h;
867		if (row_length == src_pitch && src_pitch == stride)
868			num_rows = 1, row_length *= h;
869		dst += y * stride + x * cpp;
870		do {
871			memcpy (dst, src, row_length);
872			src += src_pitch;
873			dst += stride;
874		} while (--num_rows);
875		drm_intel_gem_bo_unmap_gtt(priv->bo);
876		ret = TRUE;
877	}
878
879	return ret;
880}
881
882static Bool intel_uxa_put_image(PixmapPtr pixmap,
883				int x, int y,
884				int w, int h,
885				char *src, int src_pitch)
886{
887	struct intel_pixmap *priv;
888
889	priv = intel_get_pixmap_private(pixmap);
890	if (!intel_pixmap_is_busy(priv)) {
891		/* bo is not busy so can be replaced without a stall, upload in-place. */
892		return intel_uxa_pixmap_put_image(pixmap, src, src_pitch, x, y, w, h);
893	} else {
894		ScreenPtr screen = pixmap->drawable.pScreen;
895
896		if (!priv->pinned &&
897		    x == 0 && y == 0 &&
898		    w == pixmap->drawable.width &&
899		    h == pixmap->drawable.height)
900		{
901			intel_screen_private *intel = intel_get_screen_private(xf86ScreenToScrn(screen));
902			uint32_t tiling = priv->tiling;
903			int size, stride;
904			dri_bo *bo;
905
906			/* Replace busy bo. */
907			size = intel_uxa_compute_size(intel,
908						      w, h,
909						      pixmap->drawable.bitsPerPixel, pixmap->usage_hint,
910						      &tiling, &stride);
911			if (size > intel->max_gtt_map_size)
912				return FALSE;
913
914			bo = drm_intel_bo_alloc(intel->bufmgr, "pixmap", size, 0);
915			if (bo == NULL)
916				return FALSE;
917
918			if (tiling != I915_TILING_NONE)
919				drm_intel_bo_set_tiling(bo, &tiling, stride);
920			priv->stride = stride;
921			priv->tiling = tiling;
922
923			screen->ModifyPixmapHeader(pixmap,
924						   w, h,
925						   0, 0,
926						   stride, NULL);
927			intel_set_pixmap_bo(pixmap, bo);
928			dri_bo_unreference(bo);
929
930			return intel_uxa_pixmap_put_image(pixmap, src, src_pitch, 0, 0, w, h);
931		}
932		else
933		{
934			PixmapPtr scratch;
935			Bool ret;
936
937			/* Upload to a linear buffer and queue a blit.  */
938			scratch = (*screen->CreatePixmap)(screen, w, h,
939							  pixmap->drawable.depth,
940							  UXA_CREATE_PIXMAP_FOR_MAP);
941			if (!scratch)
942				return FALSE;
943
944			if (!intel_uxa_pixmap_is_offscreen(scratch)) {
945				screen->DestroyPixmap(scratch);
946				return FALSE;
947			}
948
949			ret = intel_uxa_pixmap_put_image(scratch, src, src_pitch, 0, 0, w, h);
950			if (ret) {
951				GCPtr gc = GetScratchGC(pixmap->drawable.depth, screen);
952				if (gc) {
953					ValidateGC(&pixmap->drawable, gc);
954
955					(*gc->ops->CopyArea)(&scratch->drawable,
956							     &pixmap->drawable,
957							     gc, 0, 0, w, h, x, y);
958
959					FreeScratchGC(gc);
960				} else
961					ret = FALSE;
962			}
963
964			(*screen->DestroyPixmap)(scratch);
965			return ret;
966		}
967	}
968}
969
970static Bool intel_uxa_pixmap_get_image(PixmapPtr pixmap,
971				       int x, int y, int w, int h,
972				       char *dst, int dst_pitch)
973{
974	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
975	int stride = intel_pixmap_pitch(pixmap);
976	int cpp = pixmap->drawable.bitsPerPixel/8;
977
978	/* assert(priv->tiling == I915_TILING_NONE); */
979	if (h == 1 || (dst_pitch == stride && w == pixmap->drawable.width)) {
980		return drm_intel_bo_get_subdata(priv->bo, y*stride + x*cpp, (h-1)*stride + w*cpp, dst) == 0;
981	} else {
982		char *src;
983
984		if (drm_intel_gem_bo_map_gtt(priv->bo))
985		    return FALSE;
986
987		src = (char *) priv->bo->virtual + y * stride + x * cpp;
988		w *= cpp;
989		do {
990			memcpy(dst, src, w);
991			src += stride;
992			dst += dst_pitch;
993		} while (--h);
994
995		drm_intel_gem_bo_unmap_gtt(priv->bo);
996
997		return TRUE;
998	}
999}
1000
1001static Bool intel_uxa_get_image(PixmapPtr pixmap,
1002				int x, int y,
1003				int w, int h,
1004				char *dst, int dst_pitch)
1005{
1006	struct intel_pixmap *priv;
1007	PixmapPtr scratch = NULL;
1008	Bool ret;
1009
1010	/* The presumption is that we wish to keep the target hot, so
1011	 * copy to a new bo and move that to the CPU in preference to
1012	 * causing ping-pong of the original.
1013	 *
1014	 * Also the gpu is much faster at detiling.
1015	 */
1016
1017	priv = intel_get_pixmap_private(pixmap);
1018	if (intel_pixmap_is_busy(priv) || priv->tiling != I915_TILING_NONE) {
1019		ScreenPtr screen = pixmap->drawable.pScreen;
1020		GCPtr gc;
1021
1022		/* Copy to a linear buffer and pull.  */
1023		scratch = screen->CreatePixmap(screen, w, h,
1024					       pixmap->drawable.depth,
1025					       INTEL_CREATE_PIXMAP_TILING_NONE);
1026		if (!scratch)
1027			return FALSE;
1028
1029		if (!intel_uxa_pixmap_is_offscreen(scratch)) {
1030			screen->DestroyPixmap(scratch);
1031			return FALSE;
1032		}
1033
1034		gc = GetScratchGC(pixmap->drawable.depth, screen);
1035		if (!gc) {
1036			screen->DestroyPixmap(scratch);
1037			return FALSE;
1038		}
1039
1040		ValidateGC(&pixmap->drawable, gc);
1041
1042		gc->ops->CopyArea(&pixmap->drawable,
1043				  &scratch->drawable,
1044				  gc, x, y, w, h, 0, 0);
1045
1046		FreeScratchGC(gc);
1047
1048		intel_batch_submit(xf86ScreenToScrn(screen));
1049
1050		x = y = 0;
1051		pixmap = scratch;
1052	}
1053
1054	ret = intel_uxa_pixmap_get_image(pixmap, x, y, w, h, dst, dst_pitch);
1055
1056	if (scratch)
1057		scratch->drawable.pScreen->DestroyPixmap(scratch);
1058
1059	return ret;
1060}
1061
1062static CARD32 intel_cache_expire(OsTimerPtr timer, CARD32 now, pointer data)
1063{
1064	intel_screen_private *intel = data;
1065
1066	/* We just want to create and destroy a bo as this causes libdrm
1067	 * to reap its caches. However, since we can't remove that buffer
1068	 * from the cache due to its own activity, we want to use something
1069	 * that we know we will reuse later. The most frequently reused buffer
1070	 * we have is the batchbuffer, and the best way to trigger its
1071	 * reallocation is to submit a flush.
1072	 */
1073	intel_batch_emit_flush(intel->scrn);
1074	intel_batch_submit(intel->scrn);
1075
1076	return 0;
1077}
1078
1079static void intel_flush_rendering(intel_screen_private *intel)
1080{
1081	if (intel->needs_flush == 0)
1082		return;
1083
1084	if (intel->has_kernel_flush) {
1085		intel_batch_submit(intel->scrn);
1086		drm_intel_bo_busy(intel->front_buffer);
1087	} else {
1088		intel_batch_emit_flush(intel->scrn);
1089		intel_batch_submit(intel->scrn);
1090	}
1091
1092	intel->cache_expire = TimerSet(intel->cache_expire, 0, 3000,
1093				       intel_cache_expire, intel);
1094
1095	intel->needs_flush = 0;
1096}
1097
1098static void intel_throttle(intel_screen_private *intel)
1099{
1100	drmCommandNone(intel->drmSubFD, DRM_I915_GEM_THROTTLE);
1101}
1102
1103void intel_uxa_block_handler(intel_screen_private *intel)
1104{
1105	/* Emit a flush of the rendering cache, or on the 965
1106	 * and beyond rendering results may not hit the
1107	 * framebuffer until significantly later.
1108	 */
1109	intel_glamor_flush(intel);
1110	intel_flush_rendering(intel);
1111	intel_throttle(intel);
1112}
1113
1114static PixmapPtr
1115intel_uxa_create_pixmap(ScreenPtr screen, int w, int h, int depth,
1116			unsigned usage)
1117{
1118	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1119	intel_screen_private *intel = intel_get_screen_private(scrn);
1120	struct intel_pixmap *priv;
1121	PixmapPtr pixmap, new_pixmap = NULL;
1122
1123	if (!(usage & INTEL_CREATE_PIXMAP_DRI2)) {
1124		pixmap = intel_glamor_create_pixmap(screen, w, h, depth, usage);
1125		if (pixmap)
1126			return pixmap;
1127	}
1128
1129	if (w > 32767 || h > 32767)
1130		return NullPixmap;
1131
1132	if (depth == 1 || intel->force_fallback)
1133		return fbCreatePixmap(screen, w, h, depth, usage);
1134
1135	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32)
1136		return fbCreatePixmap(screen, w, h, depth, usage);
1137
1138	pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
1139	if (pixmap == NullPixmap)
1140		return pixmap;
1141
1142	if (w && h) {
1143		unsigned int size, tiling;
1144		int stride;
1145
1146		/* Always attempt to tile, compute_size() will remove the
1147		 * tiling for pixmaps that are either too large or too small
1148		 * to be effectively tiled.
1149		 */
1150		tiling = I915_TILING_X;
1151		if (usage & INTEL_CREATE_PIXMAP_TILING_Y)
1152			tiling = I915_TILING_Y;
1153		if (usage == UXA_CREATE_PIXMAP_FOR_MAP || usage & INTEL_CREATE_PIXMAP_TILING_NONE)
1154			tiling = I915_TILING_NONE;
1155
1156#ifdef CREATE_PIXMAP_USAGE_SHARED
1157		if (usage == CREATE_PIXMAP_USAGE_SHARED)
1158			tiling = I915_TILING_NONE;
1159#endif
1160		/* if tiling is off force to none */
1161		if (!intel->tiling)
1162			tiling = I915_TILING_NONE;
1163
1164		if (tiling != I915_TILING_NONE && !(usage & INTEL_CREATE_PIXMAP_DRI2)) {
1165		    if (h <= 4)
1166			tiling = I915_TILING_NONE;
1167		    if (h <= 16 && tiling == I915_TILING_Y)
1168			tiling = I915_TILING_X;
1169		}
1170		size = intel_uxa_compute_size(intel,
1171					      w, h, pixmap->drawable.bitsPerPixel, usage,
1172					      &tiling, &stride);
1173
1174		/* Fail very large allocations.  Large BOs will tend to hit SW fallbacks
1175		 * frequently, and also will tend to fail to successfully map when doing
1176		 * SW fallbacks because we overcommit address space for BO access.
1177		 */
1178		if (size > intel->max_bo_size || stride >= KB(32))
1179			goto fallback_pixmap;
1180
1181		priv = calloc(1, sizeof (struct intel_pixmap));
1182		if (priv == NULL)
1183			goto fallback_pixmap;
1184
1185		if (usage == UXA_CREATE_PIXMAP_FOR_MAP) {
1186			priv->busy = 0;
1187			priv->bo = drm_intel_bo_alloc(intel->bufmgr,
1188						      "pixmap", size, 0);
1189		} else {
1190			priv->busy = -1;
1191			priv->bo = drm_intel_bo_alloc_for_render(intel->bufmgr,
1192								 "pixmap",
1193								 size, 0);
1194		}
1195		if (!priv->bo)
1196			goto fallback_priv;
1197
1198		if (tiling != I915_TILING_NONE)
1199			drm_intel_bo_set_tiling(priv->bo, &tiling, stride);
1200		priv->stride = stride;
1201		priv->tiling = tiling;
1202		priv->offscreen = 1;
1203
1204		list_init(&priv->batch);
1205		intel_set_pixmap_private(pixmap, priv);
1206
1207		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL);
1208
1209		if (!intel_glamor_create_textured_pixmap(pixmap))
1210			goto fallback_glamor;
1211	}
1212
1213	return pixmap;
1214
1215fallback_glamor:
1216	if (usage & INTEL_CREATE_PIXMAP_DRI2) {
1217	/* XXX need further work to handle the DRI2 failure case.
1218	 * Glamor don't know how to handle a BO only pixmap. Put
1219	 * a warning indicator here.
1220	 */
1221		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1222			   "Failed to create textured DRI2 pixmap.");
1223		return pixmap;
1224	}
1225	/* Create textured pixmap failed means glamor failed to
1226	 * create a texture from current BO for some reasons. We turn
1227	 * to create a new glamor pixmap and clean up current one.
1228	 * One thing need to be noted, this new pixmap doesn't
1229	 * has a priv and bo attached to it. It's glamor's responsbility
1230	 * to take care of it. Glamor will mark this new pixmap as a
1231	 * texture only pixmap and will never fallback to DDX layer
1232	 * afterwards.
1233	 */
1234	new_pixmap = intel_glamor_create_pixmap(screen, w, h,
1235						depth, usage);
1236	dri_bo_unreference(priv->bo);
1237fallback_priv:
1238	free(priv);
1239fallback_pixmap:
1240	fbDestroyPixmap(pixmap);
1241	if (new_pixmap)
1242		return new_pixmap;
1243	else
1244		return fbCreatePixmap(screen, w, h, depth, usage);
1245}
1246
1247static Bool intel_uxa_destroy_pixmap(PixmapPtr pixmap)
1248{
1249	if (pixmap->refcnt == 1) {
1250		intel_glamor_destroy_pixmap(pixmap);
1251		intel_set_pixmap_bo(pixmap, NULL);
1252	}
1253	fbDestroyPixmap(pixmap);
1254	return TRUE;
1255}
1256
1257Bool intel_uxa_create_screen_resources(ScreenPtr screen)
1258{
1259	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1260	PixmapPtr pixmap;
1261	intel_screen_private *intel = intel_get_screen_private(scrn);
1262	dri_bo *bo = intel->front_buffer;
1263	int old_width, old_height, old_pitch;
1264
1265	if (!uxa_resources_init(screen))
1266		return FALSE;
1267
1268	if (drm_intel_gem_bo_map_gtt(bo))
1269		return FALSE;
1270
1271	pixmap = screen->GetScreenPixmap(screen);
1272	old_width = pixmap->drawable.width;
1273	old_height = pixmap->drawable.height;
1274	old_pitch = pixmap->devKind;
1275
1276	if (!screen->ModifyPixmapHeader(pixmap,
1277					scrn->virtualX,
1278					scrn->virtualY,
1279					-1, -1,
1280					intel->front_pitch,
1281					NULL))
1282		return FALSE;
1283
1284	intel_set_pixmap_bo(pixmap, bo);
1285	if (intel_get_pixmap_private(pixmap) == NULL)
1286		goto err;
1287
1288	if (!intel_glamor_create_screen_resources(screen))
1289		goto err;
1290
1291	intel_get_pixmap_private(pixmap)->pinned |= PIN_SCANOUT;
1292	scrn->displayWidth = intel->front_pitch / intel->cpp;
1293
1294	return TRUE;
1295
1296err:
1297	screen->ModifyPixmapHeader(pixmap,
1298				   old_width, old_height, -1, -1, old_pitch, NULL);
1299	return FALSE;
1300}
1301
1302#ifdef CREATE_PIXMAP_USAGE_SHARED
1303static Bool
1304intel_uxa_share_pixmap_backing(PixmapPtr ppix, ScreenPtr slave, void **fd_handle)
1305{
1306	ScrnInfoPtr scrn = xf86ScreenToScrn(ppix->drawable.pScreen);
1307	intel_screen_private *intel = intel_get_screen_private(scrn);
1308	struct intel_pixmap *priv = intel_get_pixmap_private(ppix);
1309	unsigned int size, tiling, swizzle;
1310	dri_bo *bo = intel_get_pixmap_bo(ppix), *newbo;
1311	int stride;
1312	int handle;
1313
1314	if (drm_intel_bo_references(intel->batch_bo, bo))
1315		intel_batch_submit(intel->scrn);
1316
1317	drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
1318
1319	if (tiling == I915_TILING_X) {
1320		if (priv->pinned)
1321			return FALSE;
1322
1323	        tiling = I915_TILING_NONE;
1324
1325		size = intel_uxa_compute_size(intel,
1326					      ppix->drawable.width, ppix->drawable.height,
1327					      ppix->drawable.bitsPerPixel, INTEL_CREATE_PIXMAP_DRI2,
1328					      &tiling, &stride);
1329
1330		newbo = drm_intel_bo_alloc_for_render(intel->bufmgr,
1331						      "pixmap",
1332						      size, 0);
1333
1334		if (tiling != I915_TILING_NONE)
1335			drm_intel_bo_set_tiling(newbo, &tiling, stride);
1336		priv->stride = stride;
1337		priv->tiling = tiling;
1338		intel_set_pixmap_bo(ppix, newbo);
1339
1340		ppix->drawable.pScreen->ModifyPixmapHeader(ppix, ppix->drawable.width,
1341					   ppix->drawable.height, 0, 0,
1342					   stride, NULL);
1343		bo = newbo;
1344	}
1345	drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
1346	drm_intel_bo_gem_export_to_prime(bo, &handle);
1347	priv->pinned |= PIN_PRIME;
1348
1349	*fd_handle = (void *)(long)handle;
1350	return TRUE;
1351}
1352
1353static Bool
1354intel_uxa_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle)
1355{
1356	ScrnInfoPtr scrn = xf86ScreenToScrn(ppix->drawable.pScreen);
1357	intel_screen_private *intel = intel_get_screen_private(scrn);
1358	dri_bo *bo;
1359	int ihandle = (int)(long)fd_handle;
1360
1361	/* force untiled for now */
1362	bo = drm_intel_bo_gem_create_from_prime(intel->bufmgr, ihandle, 0);
1363	if (!bo)
1364		return FALSE;
1365
1366	intel_set_pixmap_bo(ppix, bo);
1367	close(ihandle);
1368	return TRUE;
1369}
1370#endif
1371
1372static void
1373intel_limits_init(intel_screen_private *intel)
1374{
1375	/* Limits are described in the BLT engine chapter under Graphics Data Size
1376	 * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO,
1377	 * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO.
1378	 *
1379	 * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768.
1380	 *
1381	 * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled.
1382	 * i965 limits 3D surface to 4kB-aligned offset if tiled.
1383	 * i965 limits 3D surfaces to w,h of ?,8192.
1384	 * i965 limits 3D surface to pitch of 1B - 128kB.
1385	 * i965 limits 3D surface pitch alignment to 1 or 2 times the element size.
1386	 * i965 limits 3D surface pitch alignment to 512B if tiled.
1387	 * i965 limits 3D destination drawing rect to w,h of 8192,8192.
1388	 *
1389	 * i915 limits 3D textures to 4B-aligned offset if un-tiled.
1390	 * i915 limits 3D textures to ~4kB-aligned offset if tiled.
1391	 * i915 limits 3D textures to width,height of 2048,2048.
1392	 * i915 limits 3D textures to pitch of 16B - 8kB, in dwords.
1393	 * i915 limits 3D destination to ~4kB-aligned offset if tiled.
1394	 * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled.
1395	 * i915 limits 3D destination to pitch 64B-aligned if used with depth.
1396	 * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled.
1397	 * i915 limits 3D destination to POT aligned pitch if tiled.
1398	 * i915 limits 3D destination drawing rect to w,h of 2048,2048.
1399	 *
1400	 * i845 limits 3D textures to 4B-aligned offset if un-tiled.
1401	 * i845 limits 3D textures to ~4kB-aligned offset if tiled.
1402	 * i845 limits 3D textures to width,height of 2048,2048.
1403	 * i845 limits 3D textures to pitch of 4B - 8kB, in dwords.
1404	 * i845 limits 3D destination to 4B-aligned offset if un-tiled.
1405	 * i845 limits 3D destination to ~4kB-aligned offset if tiled.
1406	 * i845 limits 3D destination to pitch of 8B - 8kB, in dwords.
1407	 * i845 limits 3D destination drawing rect to w,h of 2048,2048.
1408	 *
1409	 * For the tiled issues, the only tiled buffer we draw to should be
1410	 * the front, which will have an appropriate pitch/offset already set up,
1411	 * so UXA doesn't need to worry.
1412	 */
1413	if (INTEL_INFO(intel)->gen >= 040) {
1414		intel->accel_pixmap_offset_alignment = 4 * 2;
1415		intel->accel_max_x = 8192;
1416		intel->accel_max_y = 8192;
1417	} else {
1418		intel->accel_pixmap_offset_alignment = 4;
1419		intel->accel_max_x = 2048;
1420		intel->accel_max_y = 2048;
1421	}
1422}
1423
1424static Bool intel_option_accel_none(intel_screen_private *intel)
1425{
1426	const char *s;
1427
1428	s = xf86GetOptValString(intel->Options, OPTION_ACCEL_METHOD);
1429	if (s == NULL)
1430		return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
1431
1432	return strcasecmp(s, "none") == 0;
1433}
1434
1435static Bool intel_option_accel_blt(intel_screen_private *intel)
1436{
1437	const char *s;
1438
1439	s = xf86GetOptValString(intel->Options, OPTION_ACCEL_METHOD);
1440	if (s == NULL)
1441		return FALSE;
1442
1443	return strcasecmp(s, "blt") == 0;
1444}
1445
1446Bool intel_uxa_init(ScreenPtr screen)
1447{
1448	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1449	intel_screen_private *intel = intel_get_screen_private(scrn);
1450
1451#if HAS_DIXREGISTERPRIVATEKEY
1452	if (!dixRegisterPrivateKey(&uxa_pixmap_index, PRIVATE_PIXMAP, 0))
1453#else
1454	if (!dixRequestPrivate(&uxa_pixmap_index, 0))
1455#endif
1456		return FALSE;
1457
1458	intel_limits_init(intel);
1459
1460	intel->uxa_driver = uxa_driver_alloc();
1461	if (intel->uxa_driver == NULL)
1462		return FALSE;
1463
1464	memset(intel->uxa_driver, 0, sizeof(*intel->uxa_driver));
1465
1466	intel->uxa_driver->uxa_major = 1;
1467	intel->uxa_driver->uxa_minor = 0;
1468
1469	intel->prim_offset = 0;
1470	intel->vertex_count = 0;
1471	intel->vertex_offset = 0;
1472	intel->vertex_used = 0;
1473	intel->floats_per_vertex = 0;
1474	intel->last_floats_per_vertex = 0;
1475	intel->vertex_bo = NULL;
1476	intel->surface_used = 0;
1477	intel->surface_reloc = 0;
1478
1479	/* Solid fill */
1480	intel->uxa_driver->check_solid = intel_uxa_check_solid;
1481	intel->uxa_driver->prepare_solid = intel_uxa_prepare_solid;
1482	intel->uxa_driver->solid = intel_uxa_solid;
1483	intel->uxa_driver->done_solid = intel_uxa_done;
1484
1485	/* Copy */
1486	intel->uxa_driver->check_copy = intel_uxa_check_copy;
1487	intel->uxa_driver->prepare_copy = intel_uxa_prepare_copy;
1488	intel->uxa_driver->copy = intel_uxa_copy;
1489	intel->uxa_driver->done_copy = intel_uxa_done;
1490
1491	/* Composite */
1492	if (intel_option_accel_blt(intel)) {
1493	} else if (INTEL_INFO(intel)->gen < 030) {
1494		intel->uxa_driver->check_composite = i830_check_composite;
1495		intel->uxa_driver->check_composite_target = i830_check_composite_target;
1496		intel->uxa_driver->check_composite_texture = i830_check_composite_texture;
1497		intel->uxa_driver->prepare_composite = i830_prepare_composite;
1498		intel->uxa_driver->composite = i830_composite;
1499		intel->uxa_driver->done_composite = i830_done_composite;
1500
1501		intel->vertex_flush = i830_vertex_flush;
1502		intel->batch_commit_notify = i830_batch_commit_notify;
1503	} else if (INTEL_INFO(intel)->gen < 040) {
1504		intel->uxa_driver->check_composite = i915_check_composite;
1505		intel->uxa_driver->check_composite_target = i915_check_composite_target;
1506		intel->uxa_driver->check_composite_texture = i915_check_composite_texture;
1507		intel->uxa_driver->prepare_composite = i915_prepare_composite;
1508		intel->uxa_driver->composite = i915_composite;
1509		intel->uxa_driver->done_composite = i830_done_composite;
1510
1511		intel->vertex_flush = i915_vertex_flush;
1512		intel->batch_commit_notify = i915_batch_commit_notify;
1513	} else if (INTEL_INFO(intel)->gen < 0100) {
1514		intel->uxa_driver->check_composite = i965_check_composite;
1515		intel->uxa_driver->check_composite_texture = i965_check_composite_texture;
1516		intel->uxa_driver->prepare_composite = i965_prepare_composite;
1517		intel->uxa_driver->composite = i965_composite;
1518		intel->uxa_driver->done_composite = i830_done_composite;
1519
1520		intel->vertex_flush = i965_vertex_flush;
1521		intel->batch_flush = i965_batch_flush;
1522		intel->batch_commit_notify = i965_batch_commit_notify;
1523
1524		if (INTEL_INFO(intel)->gen < 050) {
1525			intel->context_switch = gen4_context_switch;
1526		} else if (INTEL_INFO(intel)->gen < 060) {
1527			intel->context_switch = gen5_context_switch;
1528		} else {
1529			intel->context_switch = gen6_context_switch;
1530		}
1531	}
1532
1533	/* PutImage */
1534	intel->uxa_driver->put_image = intel_uxa_put_image;
1535	intel->uxa_driver->get_image = intel_uxa_get_image;
1536
1537	intel->uxa_driver->prepare_access = intel_uxa_prepare_access;
1538	intel->uxa_driver->finish_access = intel_uxa_finish_access;
1539	intel->uxa_driver->pixmap_is_offscreen = intel_uxa_pixmap_is_offscreen;
1540
1541	screen->CreatePixmap = intel_uxa_create_pixmap;
1542	screen->DestroyPixmap = intel_uxa_destroy_pixmap;
1543
1544#ifdef CREATE_PIXMAP_USAGE_SHARED
1545	screen->SharePixmapBacking = intel_uxa_share_pixmap_backing;
1546	screen->SetSharedPixmapBacking = intel_uxa_set_shared_pixmap_backing;
1547#endif
1548
1549	if (!uxa_driver_init(screen, intel->uxa_driver)) {
1550		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1551			   "UXA initialization failed\n");
1552		free(intel->uxa_driver);
1553		return FALSE;
1554	}
1555
1556	if (intel_option_accel_none(intel))
1557		intel->force_fallback = 1;
1558
1559	uxa_set_fallback_debug(screen, intel->fallback_debug);
1560	uxa_set_force_fallback(screen, intel->force_fallback);
1561
1562	intel->flush_rendering = intel_flush_rendering;
1563	return TRUE;
1564}
1565