intel_uxa.c revision 03b705cf
103b705cfSriastradh/**************************************************************************
203b705cfSriastradh
303b705cfSriastradhCopyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
403b705cfSriastradhAll Rights Reserved.
503b705cfSriastradhCopyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org>
603b705cfSriastradh  Based on code from i830_xaa.c.
703b705cfSriastradh
803b705cfSriastradhPermission is hereby granted, free of charge, to any person obtaining a
903b705cfSriastradhcopy of this software and associated documentation files (the
1003b705cfSriastradh"Software"), to deal in the Software without restriction, including
1103b705cfSriastradhwithout limitation the rights to use, copy, modify, merge, publish,
1203b705cfSriastradhdistribute, sub license, and/or sell copies of the Software, and to
1303b705cfSriastradhpermit persons to whom the Software is furnished to do so, subject to
1403b705cfSriastradhthe following conditions:
1503b705cfSriastradh
1603b705cfSriastradhThe above copyright notice and this permission notice (including the
1703b705cfSriastradhnext paragraph) shall be included in all copies or substantial portions
1803b705cfSriastradhof the Software.
1903b705cfSriastradh
2003b705cfSriastradhTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2103b705cfSriastradhOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2203b705cfSriastradhMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
2303b705cfSriastradhIN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
2403b705cfSriastradhANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2503b705cfSriastradhTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2603b705cfSriastradhSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2703b705cfSriastradh
2803b705cfSriastradh**************************************************************************/
2903b705cfSriastradh
3003b705cfSriastradh#ifdef HAVE_CONFIG_H
3103b705cfSriastradh#include "config.h"
3203b705cfSriastradh#endif
3303b705cfSriastradh
3403b705cfSriastradh#include <xf86.h>
3503b705cfSriastradh#include <xf86drm.h>
3603b705cfSriastradh#include <xaarop.h>
3703b705cfSriastradh#include <string.h>
3803b705cfSriastradh#include <errno.h>
3903b705cfSriastradh#include <unistd.h>
4003b705cfSriastradh
4103b705cfSriastradh#include "intel.h"
4203b705cfSriastradh#include "intel_glamor.h"
4303b705cfSriastradh#include "uxa.h"
4403b705cfSriastradh
4503b705cfSriastradh#include "i830_reg.h"
4603b705cfSriastradh#include "i915_drm.h"
4703b705cfSriastradh#include "brw_defines.h"
4803b705cfSriastradh
4903b705cfSriastradhstatic const int I830CopyROP[16] = {
5003b705cfSriastradh	ROP_0,			/* GXclear */
5103b705cfSriastradh	ROP_DSa,		/* GXand */
5203b705cfSriastradh	ROP_SDna,		/* GXandReverse */
5303b705cfSriastradh	ROP_S,			/* GXcopy */
5403b705cfSriastradh	ROP_DSna,		/* GXandInverted */
5503b705cfSriastradh	ROP_D,			/* GXnoop */
5603b705cfSriastradh	ROP_DSx,		/* GXxor */
5703b705cfSriastradh	ROP_DSo,		/* GXor */
5803b705cfSriastradh	ROP_DSon,		/* GXnor */
5903b705cfSriastradh	ROP_DSxn,		/* GXequiv */
6003b705cfSriastradh	ROP_Dn,			/* GXinvert */
6103b705cfSriastradh	ROP_SDno,		/* GXorReverse */
6203b705cfSriastradh	ROP_Sn,			/* GXcopyInverted */
6303b705cfSriastradh	ROP_DSno,		/* GXorInverted */
6403b705cfSriastradh	ROP_DSan,		/* GXnand */
6503b705cfSriastradh	ROP_1			/* GXset */
6603b705cfSriastradh};
6703b705cfSriastradh
6803b705cfSriastradhstatic const int I830PatternROP[16] = {
6903b705cfSriastradh	ROP_0,
7003b705cfSriastradh	ROP_DPa,
7103b705cfSriastradh	ROP_PDna,
7203b705cfSriastradh	ROP_P,
7303b705cfSriastradh	ROP_DPna,
7403b705cfSriastradh	ROP_D,
7503b705cfSriastradh	ROP_DPx,
7603b705cfSriastradh	ROP_DPo,
7703b705cfSriastradh	ROP_DPon,
7803b705cfSriastradh	ROP_PDxn,
7903b705cfSriastradh	ROP_Dn,
8003b705cfSriastradh	ROP_PDno,
8103b705cfSriastradh	ROP_Pn,
8203b705cfSriastradh	ROP_DPno,
8303b705cfSriastradh	ROP_DPan,
8403b705cfSriastradh	ROP_1
8503b705cfSriastradh};
8603b705cfSriastradh
8703b705cfSriastradh#if HAS_DEVPRIVATEKEYREC
8803b705cfSriastradhDevPrivateKeyRec uxa_pixmap_index;
8903b705cfSriastradh#else
9003b705cfSriastradhint uxa_pixmap_index;
9103b705cfSriastradh#endif
9203b705cfSriastradh
9303b705cfSriastradhstatic void
9403b705cfSriastradhgen6_context_switch(intel_screen_private *intel,
9503b705cfSriastradh		    int new_mode)
9603b705cfSriastradh{
9703b705cfSriastradh	intel_batch_submit(intel->scrn);
9803b705cfSriastradh}
9903b705cfSriastradh
10003b705cfSriastradhstatic void
10103b705cfSriastradhgen5_context_switch(intel_screen_private *intel,
10203b705cfSriastradh		    int new_mode)
10303b705cfSriastradh{
10403b705cfSriastradh	/* Ironlake has a limitation that a 3D or Media command can't
10503b705cfSriastradh	 * be the first command after a BLT, unless it's
10603b705cfSriastradh	 * non-pipelined.  Instead of trying to track it and emit a
10703b705cfSriastradh	 * command at the right time, we just emit a dummy
10803b705cfSriastradh	 * non-pipelined 3D instruction after each blit.
10903b705cfSriastradh	 */
11003b705cfSriastradh
11103b705cfSriastradh	if (new_mode == I915_EXEC_BLT) {
11203b705cfSriastradh		OUT_BATCH(MI_FLUSH |
11303b705cfSriastradh			  MI_STATE_INSTRUCTION_CACHE_FLUSH |
11403b705cfSriastradh			  MI_INHIBIT_RENDER_CACHE_FLUSH);
11503b705cfSriastradh	} else {
11603b705cfSriastradh		OUT_BATCH(CMD_POLY_STIPPLE_OFFSET << 16);
11703b705cfSriastradh		OUT_BATCH(0);
11803b705cfSriastradh	}
11903b705cfSriastradh}
12003b705cfSriastradh
12103b705cfSriastradhstatic void
12203b705cfSriastradhgen4_context_switch(intel_screen_private *intel,
12303b705cfSriastradh		    int new_mode)
12403b705cfSriastradh{
12503b705cfSriastradh	if (new_mode == I915_EXEC_BLT) {
12603b705cfSriastradh		OUT_BATCH(MI_FLUSH |
12703b705cfSriastradh			  MI_STATE_INSTRUCTION_CACHE_FLUSH |
12803b705cfSriastradh			  MI_INHIBIT_RENDER_CACHE_FLUSH);
12903b705cfSriastradh	}
13003b705cfSriastradh}
13103b705cfSriastradh
13203b705cfSriastradhBool
13303b705cfSriastradhintel_get_aperture_space(ScrnInfoPtr scrn, drm_intel_bo ** bo_table,
13403b705cfSriastradh			 int num_bos)
13503b705cfSriastradh{
13603b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
13703b705cfSriastradh
13803b705cfSriastradh	if (intel->batch_bo == NULL) {
13903b705cfSriastradh		intel_debug_fallback(scrn, "VT inactive\n");
14003b705cfSriastradh		return FALSE;
14103b705cfSriastradh	}
14203b705cfSriastradh
14303b705cfSriastradh	bo_table[0] = intel->batch_bo;
14403b705cfSriastradh	if (drm_intel_bufmgr_check_aperture_space(bo_table, num_bos) != 0) {
14503b705cfSriastradh		intel_batch_submit(scrn);
14603b705cfSriastradh		bo_table[0] = intel->batch_bo;
14703b705cfSriastradh		if (drm_intel_bufmgr_check_aperture_space(bo_table, num_bos) !=
14803b705cfSriastradh		    0) {
14903b705cfSriastradh			intel_debug_fallback(scrn, "Couldn't get aperture "
15003b705cfSriastradh					    "space for BOs\n");
15103b705cfSriastradh			return FALSE;
15203b705cfSriastradh		}
15303b705cfSriastradh	}
15403b705cfSriastradh	return TRUE;
15503b705cfSriastradh}
15603b705cfSriastradh
15703b705cfSriastradhstatic unsigned int
15803b705cfSriastradhintel_uxa_pixmap_compute_size(PixmapPtr pixmap,
15903b705cfSriastradh			      int w, int h,
16003b705cfSriastradh			      uint32_t *tiling,
16103b705cfSriastradh			      int *stride,
16203b705cfSriastradh			      unsigned usage)
16303b705cfSriastradh{
16403b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
16503b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
16603b705cfSriastradh	int pitch, size;
16703b705cfSriastradh
16803b705cfSriastradh	if (*tiling != I915_TILING_NONE) {
16903b705cfSriastradh		/* First check whether tiling is necessary. */
17003b705cfSriastradh		pitch = (w * pixmap->drawable.bitsPerPixel + 7) / 8;
17103b705cfSriastradh		pitch = ALIGN(pitch, 64);
17203b705cfSriastradh		size = pitch * ALIGN (h, 2);
17303b705cfSriastradh		if (INTEL_INFO(intel)->gen < 040) {
17403b705cfSriastradh			/* Gen 2/3 has a maximum stride for tiling of
17503b705cfSriastradh			 * 8192 bytes.
17603b705cfSriastradh			 */
17703b705cfSriastradh			if (pitch > KB(8))
17803b705cfSriastradh				*tiling = I915_TILING_NONE;
17903b705cfSriastradh
18003b705cfSriastradh			/* Narrower than half a tile? */
18103b705cfSriastradh			if (pitch < 256)
18203b705cfSriastradh				*tiling = I915_TILING_NONE;
18303b705cfSriastradh
18403b705cfSriastradh			/* Older hardware requires fences to be pot size
18503b705cfSriastradh			 * aligned with a minimum of 1 MiB, so causes
18603b705cfSriastradh			 * massive overallocation for small textures.
18703b705cfSriastradh			 */
18803b705cfSriastradh			if (size < 1024*1024/2 && !intel->has_relaxed_fencing)
18903b705cfSriastradh				*tiling = I915_TILING_NONE;
19003b705cfSriastradh		} else if (!(usage & INTEL_CREATE_PIXMAP_DRI2) && size <= 4096) {
19103b705cfSriastradh			/* Disable tiling beneath a page size, we will not see
19203b705cfSriastradh			 * any benefit from reducing TLB misses and instead
19303b705cfSriastradh			 * just incur extra cost when we require a fence.
19403b705cfSriastradh			 */
19503b705cfSriastradh			*tiling = I915_TILING_NONE;
19603b705cfSriastradh		}
19703b705cfSriastradh	}
19803b705cfSriastradh
19903b705cfSriastradh	pitch = (w * pixmap->drawable.bitsPerPixel + 7) / 8;
20003b705cfSriastradh	if (!(usage & INTEL_CREATE_PIXMAP_DRI2) && pitch <= 256)
20103b705cfSriastradh		*tiling = I915_TILING_NONE;
20203b705cfSriastradh
20303b705cfSriastradh	if (*tiling != I915_TILING_NONE) {
20403b705cfSriastradh		int aligned_h, tile_height;
20503b705cfSriastradh
20603b705cfSriastradh		if (IS_GEN2(intel))
20703b705cfSriastradh			tile_height = 16;
20803b705cfSriastradh		else if (*tiling == I915_TILING_X)
20903b705cfSriastradh			tile_height = 8;
21003b705cfSriastradh		else
21103b705cfSriastradh			tile_height = 32;
21203b705cfSriastradh		aligned_h = ALIGN(h, 2*tile_height);
21303b705cfSriastradh
21403b705cfSriastradh		*stride = intel_get_fence_pitch(intel,
21503b705cfSriastradh						ALIGN(pitch, 512),
21603b705cfSriastradh						*tiling);
21703b705cfSriastradh
21803b705cfSriastradh		/* Round the object up to the size of the fence it will live in
21903b705cfSriastradh		 * if necessary.  We could potentially make the kernel allocate
22003b705cfSriastradh		 * a larger aperture space and just bind the subset of pages in,
22103b705cfSriastradh		 * but this is easier and also keeps us out of trouble (as much)
22203b705cfSriastradh		 * with drm_intel_bufmgr_check_aperture().
22303b705cfSriastradh		 */
22403b705cfSriastradh		size = intel_get_fence_size(intel, *stride * aligned_h);
22503b705cfSriastradh
22603b705cfSriastradh		if (size > intel->max_tiling_size)
22703b705cfSriastradh			*tiling = I915_TILING_NONE;
22803b705cfSriastradh	}
22903b705cfSriastradh
23003b705cfSriastradh	if (*tiling == I915_TILING_NONE) {
23103b705cfSriastradh		/* We only require a 64 byte alignment for scanouts, but
23203b705cfSriastradh		 * a 256 byte alignment for sharing with PRIME.
23303b705cfSriastradh		 */
23403b705cfSriastradh		*stride = ALIGN(pitch, 256);
23503b705cfSriastradh		/* Round the height up so that the GPU's access to a 2x2 aligned
23603b705cfSriastradh		 * subspan doesn't address an invalid page offset beyond the
23703b705cfSriastradh		 * end of the GTT.
23803b705cfSriastradh		 */
23903b705cfSriastradh		size = *stride * ALIGN(h, 2);
24003b705cfSriastradh	}
24103b705cfSriastradh
24203b705cfSriastradh	return size;
24303b705cfSriastradh}
24403b705cfSriastradh
24503b705cfSriastradhstatic Bool
24603b705cfSriastradhintel_uxa_check_solid(DrawablePtr drawable, int alu, Pixel planemask)
24703b705cfSriastradh{
24803b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(drawable->pScreen);
24903b705cfSriastradh
25003b705cfSriastradh	if (!UXA_PM_IS_SOLID(drawable, planemask)) {
25103b705cfSriastradh		intel_debug_fallback(scrn, "planemask is not solid\n");
25203b705cfSriastradh		return FALSE;
25303b705cfSriastradh	}
25403b705cfSriastradh
25503b705cfSriastradh	switch (drawable->bitsPerPixel) {
25603b705cfSriastradh	case 8:
25703b705cfSriastradh	case 16:
25803b705cfSriastradh	case 32:
25903b705cfSriastradh		break;
26003b705cfSriastradh	default:
26103b705cfSriastradh		return FALSE;
26203b705cfSriastradh	}
26303b705cfSriastradh
26403b705cfSriastradh	return TRUE;
26503b705cfSriastradh}
26603b705cfSriastradh
26703b705cfSriastradh/**
26803b705cfSriastradh * Sets up hardware state for a series of solid fills.
26903b705cfSriastradh */
27003b705cfSriastradhstatic Bool
27103b705cfSriastradhintel_uxa_prepare_solid(PixmapPtr pixmap, int alu, Pixel planemask, Pixel fg)
27203b705cfSriastradh{
27303b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
27403b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
27503b705cfSriastradh	drm_intel_bo *bo_table[] = {
27603b705cfSriastradh		NULL,		/* batch_bo */
27703b705cfSriastradh		intel_get_pixmap_bo(pixmap),
27803b705cfSriastradh	};
27903b705cfSriastradh
28003b705cfSriastradh	if (!intel_check_pitch_2d(pixmap))
28103b705cfSriastradh		return FALSE;
28203b705cfSriastradh
28303b705cfSriastradh	if (!intel_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table)))
28403b705cfSriastradh		return FALSE;
28503b705cfSriastradh
28603b705cfSriastradh	intel->BR[13] = (I830PatternROP[alu] & 0xff) << 16;
28703b705cfSriastradh	switch (pixmap->drawable.bitsPerPixel) {
28803b705cfSriastradh	case 8:
28903b705cfSriastradh		break;
29003b705cfSriastradh	case 16:
29103b705cfSriastradh		/* RGB565 */
29203b705cfSriastradh		intel->BR[13] |= (1 << 24);
29303b705cfSriastradh		break;
29403b705cfSriastradh	case 32:
29503b705cfSriastradh		/* RGB8888 */
29603b705cfSriastradh		intel->BR[13] |= ((1 << 24) | (1 << 25));
29703b705cfSriastradh		break;
29803b705cfSriastradh	}
29903b705cfSriastradh	intel->BR[16] = fg;
30003b705cfSriastradh
30103b705cfSriastradh	return TRUE;
30203b705cfSriastradh}
30303b705cfSriastradh
30403b705cfSriastradhstatic void intel_uxa_solid(PixmapPtr pixmap, int x1, int y1, int x2, int y2)
30503b705cfSriastradh{
30603b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
30703b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
30803b705cfSriastradh	unsigned long pitch;
30903b705cfSriastradh	uint32_t cmd;
31003b705cfSriastradh
31103b705cfSriastradh	if (x1 < 0)
31203b705cfSriastradh		x1 = 0;
31303b705cfSriastradh	if (y1 < 0)
31403b705cfSriastradh		y1 = 0;
31503b705cfSriastradh	if (x2 > pixmap->drawable.width)
31603b705cfSriastradh		x2 = pixmap->drawable.width;
31703b705cfSriastradh	if (y2 > pixmap->drawable.height)
31803b705cfSriastradh		y2 = pixmap->drawable.height;
31903b705cfSriastradh
32003b705cfSriastradh	if (x2 <= x1 || y2 <= y1)
32103b705cfSriastradh		return;
32203b705cfSriastradh
32303b705cfSriastradh	pitch = intel_pixmap_pitch(pixmap);
32403b705cfSriastradh
32503b705cfSriastradh	{
32603b705cfSriastradh		BEGIN_BATCH_BLT(6);
32703b705cfSriastradh
32803b705cfSriastradh		cmd = XY_COLOR_BLT_CMD;
32903b705cfSriastradh
33003b705cfSriastradh		if (pixmap->drawable.bitsPerPixel == 32)
33103b705cfSriastradh			cmd |=
33203b705cfSriastradh			    XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB;
33303b705cfSriastradh
33403b705cfSriastradh		if (INTEL_INFO(intel)->gen >= 040 && intel_pixmap_tiled(pixmap)) {
33503b705cfSriastradh			assert((pitch % 512) == 0);
33603b705cfSriastradh			pitch >>= 2;
33703b705cfSriastradh			cmd |= XY_COLOR_BLT_TILED;
33803b705cfSriastradh		}
33903b705cfSriastradh
34003b705cfSriastradh		OUT_BATCH(cmd);
34103b705cfSriastradh
34203b705cfSriastradh		OUT_BATCH(intel->BR[13] | pitch);
34303b705cfSriastradh		OUT_BATCH((y1 << 16) | (x1 & 0xffff));
34403b705cfSriastradh		OUT_BATCH((y2 << 16) | (x2 & 0xffff));
34503b705cfSriastradh		OUT_RELOC_PIXMAP_FENCED(pixmap, I915_GEM_DOMAIN_RENDER,
34603b705cfSriastradh					I915_GEM_DOMAIN_RENDER, 0);
34703b705cfSriastradh		OUT_BATCH(intel->BR[16]);
34803b705cfSriastradh		ADVANCE_BATCH();
34903b705cfSriastradh	}
35003b705cfSriastradh}
35103b705cfSriastradh
35203b705cfSriastradh/**
35303b705cfSriastradh * TODO:
35403b705cfSriastradh *   - support planemask using FULL_BLT_CMD?
35503b705cfSriastradh */
35603b705cfSriastradhstatic Bool
35703b705cfSriastradhintel_uxa_check_copy(PixmapPtr source, PixmapPtr dest,
35803b705cfSriastradh		    int alu, Pixel planemask)
35903b705cfSriastradh{
36003b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
36103b705cfSriastradh
36203b705cfSriastradh	if (!UXA_PM_IS_SOLID(&source->drawable, planemask)) {
36303b705cfSriastradh		intel_debug_fallback(scrn, "planemask is not solid");
36403b705cfSriastradh		return FALSE;
36503b705cfSriastradh	}
36603b705cfSriastradh
36703b705cfSriastradh	if (source->drawable.bitsPerPixel != dest->drawable.bitsPerPixel) {
36803b705cfSriastradh		intel_debug_fallback(scrn, "mixed bpp copies unsupported\n");
36903b705cfSriastradh		return FALSE;
37003b705cfSriastradh	}
37103b705cfSriastradh	switch (source->drawable.bitsPerPixel) {
37203b705cfSriastradh	case 8:
37303b705cfSriastradh	case 16:
37403b705cfSriastradh	case 32:
37503b705cfSriastradh		break;
37603b705cfSriastradh	default:
37703b705cfSriastradh		return FALSE;
37803b705cfSriastradh	}
37903b705cfSriastradh
38003b705cfSriastradh	if (!intel_check_pitch_2d(source))
38103b705cfSriastradh		return FALSE;
38203b705cfSriastradh	if (!intel_check_pitch_2d(dest))
38303b705cfSriastradh		return FALSE;
38403b705cfSriastradh
38503b705cfSriastradh	return TRUE;
38603b705cfSriastradh}
38703b705cfSriastradh
38803b705cfSriastradhstatic Bool
38903b705cfSriastradhintel_uxa_prepare_copy(PixmapPtr source, PixmapPtr dest, int xdir,
39003b705cfSriastradh		      int ydir, int alu, Pixel planemask)
39103b705cfSriastradh{
39203b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
39303b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
39403b705cfSriastradh	drm_intel_bo *bo_table[] = {
39503b705cfSriastradh		NULL,		/* batch_bo */
39603b705cfSriastradh		intel_get_pixmap_bo(source),
39703b705cfSriastradh		intel_get_pixmap_bo(dest),
39803b705cfSriastradh	};
39903b705cfSriastradh
40003b705cfSriastradh	if (!intel_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table)))
40103b705cfSriastradh		return FALSE;
40203b705cfSriastradh
40303b705cfSriastradh	intel->render_source = source;
40403b705cfSriastradh
40503b705cfSriastradh	intel->BR[13] = I830CopyROP[alu] << 16;
40603b705cfSriastradh	switch (source->drawable.bitsPerPixel) {
40703b705cfSriastradh	case 8:
40803b705cfSriastradh		break;
40903b705cfSriastradh	case 16:
41003b705cfSriastradh		intel->BR[13] |= (1 << 24);
41103b705cfSriastradh		break;
41203b705cfSriastradh	case 32:
41303b705cfSriastradh		intel->BR[13] |= ((1 << 25) | (1 << 24));
41403b705cfSriastradh		break;
41503b705cfSriastradh	}
41603b705cfSriastradh
41703b705cfSriastradh	return TRUE;
41803b705cfSriastradh}
41903b705cfSriastradh
42003b705cfSriastradhstatic void
42103b705cfSriastradhintel_uxa_copy(PixmapPtr dest, int src_x1, int src_y1, int dst_x1,
42203b705cfSriastradh	      int dst_y1, int w, int h)
42303b705cfSriastradh{
42403b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
42503b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
42603b705cfSriastradh	uint32_t cmd;
42703b705cfSriastradh	int dst_x2, dst_y2, src_x2, src_y2;
42803b705cfSriastradh	unsigned int dst_pitch, src_pitch;
42903b705cfSriastradh
43003b705cfSriastradh	dst_x2 = dst_x1 + w;
43103b705cfSriastradh	dst_y2 = dst_y1 + h;
43203b705cfSriastradh
43303b705cfSriastradh	/* XXX Fixup extents as a lamentable workaround for missing
43403b705cfSriastradh	 * source clipping in the upper layers.
43503b705cfSriastradh	 */
43603b705cfSriastradh	if (dst_x1 < 0)
43703b705cfSriastradh		src_x1 -= dst_x1, dst_x1 = 0;
43803b705cfSriastradh	if (dst_y1 < 0)
43903b705cfSriastradh		src_y1 -= dst_y1, dst_y1 = 0;
44003b705cfSriastradh	if (dst_x2 > dest->drawable.width)
44103b705cfSriastradh		dst_x2 = dest->drawable.width;
44203b705cfSriastradh	if (dst_y2 > dest->drawable.height)
44303b705cfSriastradh		dst_y2 = dest->drawable.height;
44403b705cfSriastradh
44503b705cfSriastradh	src_x2 = src_x1 + (dst_x2 - dst_x1);
44603b705cfSriastradh	src_y2 = src_y1 + (dst_y2 - dst_y1);
44703b705cfSriastradh
44803b705cfSriastradh	if (src_x1 < 0)
44903b705cfSriastradh		dst_x1 -= src_x1, src_x1 = 0;
45003b705cfSriastradh	if (src_y1 < 0)
45103b705cfSriastradh		dst_y1 -= src_y1, src_y1 = 0;
45203b705cfSriastradh	if (src_x2 > intel->render_source->drawable.width)
45303b705cfSriastradh		dst_x2 -= src_x2 - intel->render_source->drawable.width;
45403b705cfSriastradh	if (src_y2 > intel->render_source->drawable.height)
45503b705cfSriastradh		dst_y2 -= src_y2 - intel->render_source->drawable.height;
45603b705cfSriastradh
45703b705cfSriastradh	if (dst_x2 <= dst_x1 || dst_y2 <= dst_y1)
45803b705cfSriastradh		return;
45903b705cfSriastradh
46003b705cfSriastradh	dst_pitch = intel_pixmap_pitch(dest);
46103b705cfSriastradh	src_pitch = intel_pixmap_pitch(intel->render_source);
46203b705cfSriastradh
46303b705cfSriastradh	{
46403b705cfSriastradh		BEGIN_BATCH_BLT(8);
46503b705cfSriastradh
46603b705cfSriastradh		cmd = XY_SRC_COPY_BLT_CMD;
46703b705cfSriastradh
46803b705cfSriastradh		if (dest->drawable.bitsPerPixel == 32)
46903b705cfSriastradh			cmd |=
47003b705cfSriastradh			    XY_SRC_COPY_BLT_WRITE_ALPHA |
47103b705cfSriastradh			    XY_SRC_COPY_BLT_WRITE_RGB;
47203b705cfSriastradh
47303b705cfSriastradh		if (INTEL_INFO(intel)->gen >= 040) {
47403b705cfSriastradh			if (intel_pixmap_tiled(dest)) {
47503b705cfSriastradh				assert((dst_pitch % 512) == 0);
47603b705cfSriastradh				dst_pitch >>= 2;
47703b705cfSriastradh				cmd |= XY_SRC_COPY_BLT_DST_TILED;
47803b705cfSriastradh			}
47903b705cfSriastradh
48003b705cfSriastradh			if (intel_pixmap_tiled(intel->render_source)) {
48103b705cfSriastradh				assert((src_pitch % 512) == 0);
48203b705cfSriastradh				src_pitch >>= 2;
48303b705cfSriastradh				cmd |= XY_SRC_COPY_BLT_SRC_TILED;
48403b705cfSriastradh			}
48503b705cfSriastradh		}
48603b705cfSriastradh
48703b705cfSriastradh		OUT_BATCH(cmd);
48803b705cfSriastradh
48903b705cfSriastradh		OUT_BATCH(intel->BR[13] | dst_pitch);
49003b705cfSriastradh		OUT_BATCH((dst_y1 << 16) | (dst_x1 & 0xffff));
49103b705cfSriastradh		OUT_BATCH((dst_y2 << 16) | (dst_x2 & 0xffff));
49203b705cfSriastradh		OUT_RELOC_PIXMAP_FENCED(dest,
49303b705cfSriastradh					I915_GEM_DOMAIN_RENDER,
49403b705cfSriastradh					I915_GEM_DOMAIN_RENDER,
49503b705cfSriastradh					0);
49603b705cfSriastradh		OUT_BATCH((src_y1 << 16) | (src_x1 & 0xffff));
49703b705cfSriastradh		OUT_BATCH(src_pitch);
49803b705cfSriastradh		OUT_RELOC_PIXMAP_FENCED(intel->render_source,
49903b705cfSriastradh					I915_GEM_DOMAIN_RENDER, 0,
50003b705cfSriastradh					0);
50103b705cfSriastradh
50203b705cfSriastradh		ADVANCE_BATCH();
50303b705cfSriastradh	}
50403b705cfSriastradh}
50503b705cfSriastradh
50603b705cfSriastradhstatic void intel_uxa_done(PixmapPtr pixmap)
50703b705cfSriastradh{
50803b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
50903b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
51003b705cfSriastradh
51103b705cfSriastradh	if (IS_GEN6(intel) || IS_GEN7(intel)) {
51203b705cfSriastradh		/* workaround a random BLT hang */
51303b705cfSriastradh		BEGIN_BATCH_BLT(3);
51403b705cfSriastradh		OUT_BATCH(XY_SETUP_CLIP_BLT_CMD);
51503b705cfSriastradh		OUT_BATCH(0);
51603b705cfSriastradh		OUT_BATCH(0);
51703b705cfSriastradh		ADVANCE_BATCH();
51803b705cfSriastradh	}
51903b705cfSriastradh
52003b705cfSriastradh	intel_debug_flush(scrn);
52103b705cfSriastradh}
52203b705cfSriastradh
52303b705cfSriastradh/**
52403b705cfSriastradh * Do any cleanup from the Composite operation.
52503b705cfSriastradh *
52603b705cfSriastradh * This is shared between i830 through i965.
52703b705cfSriastradh */
52803b705cfSriastradhstatic void i830_done_composite(PixmapPtr dest)
52903b705cfSriastradh{
53003b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
53103b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
53203b705cfSriastradh
53303b705cfSriastradh	if (intel->vertex_flush)
53403b705cfSriastradh		intel->vertex_flush(intel);
53503b705cfSriastradh
53603b705cfSriastradh	intel_debug_flush(scrn);
53703b705cfSriastradh}
53803b705cfSriastradh
53903b705cfSriastradh#define xFixedToFloat(val) \
54003b705cfSriastradh	((float)xFixedToInt(val) + ((float)xFixedFrac(val) / 65536.0))
54103b705cfSriastradh
54203b705cfSriastradhstatic Bool
54303b705cfSriastradh_intel_transform_point(PictTransformPtr transform,
54403b705cfSriastradh		       float x, float y, float result[3])
54503b705cfSriastradh{
54603b705cfSriastradh	int j;
54703b705cfSriastradh
54803b705cfSriastradh	for (j = 0; j < 3; j++) {
54903b705cfSriastradh		result[j] = (xFixedToFloat(transform->matrix[j][0]) * x +
55003b705cfSriastradh			     xFixedToFloat(transform->matrix[j][1]) * y +
55103b705cfSriastradh			     xFixedToFloat(transform->matrix[j][2]));
55203b705cfSriastradh	}
55303b705cfSriastradh	if (!result[2])
55403b705cfSriastradh		return FALSE;
55503b705cfSriastradh	return TRUE;
55603b705cfSriastradh}
55703b705cfSriastradh
55803b705cfSriastradh/**
55903b705cfSriastradh * Returns the floating-point coordinates transformed by the given transform.
56003b705cfSriastradh *
56103b705cfSriastradh * transform may be null.
56203b705cfSriastradh */
56303b705cfSriastradhBool
56403b705cfSriastradhintel_get_transformed_coordinates(int x, int y, PictTransformPtr transform,
56503b705cfSriastradh				  float *x_out, float *y_out)
56603b705cfSriastradh{
56703b705cfSriastradh	if (transform == NULL) {
56803b705cfSriastradh		*x_out = x;
56903b705cfSriastradh		*y_out = y;
57003b705cfSriastradh	} else {
57103b705cfSriastradh		float result[3];
57203b705cfSriastradh
57303b705cfSriastradh		if (!_intel_transform_point(transform,
57403b705cfSriastradh					    x, y,
57503b705cfSriastradh					    result))
57603b705cfSriastradh			return FALSE;
57703b705cfSriastradh		*x_out = result[0] / result[2];
57803b705cfSriastradh		*y_out = result[1] / result[2];
57903b705cfSriastradh	}
58003b705cfSriastradh	return TRUE;
58103b705cfSriastradh}
58203b705cfSriastradh
58303b705cfSriastradh/**
58403b705cfSriastradh * Returns the un-normalized floating-point coordinates transformed by the given transform.
58503b705cfSriastradh *
58603b705cfSriastradh * transform may be null.
58703b705cfSriastradh */
58803b705cfSriastradhBool
58903b705cfSriastradhintel_get_transformed_coordinates_3d(int x, int y, PictTransformPtr transform,
59003b705cfSriastradh				     float *x_out, float *y_out, float *w_out)
59103b705cfSriastradh{
59203b705cfSriastradh	if (transform == NULL) {
59303b705cfSriastradh		*x_out = x;
59403b705cfSriastradh		*y_out = y;
59503b705cfSriastradh		*w_out = 1;
59603b705cfSriastradh	} else {
59703b705cfSriastradh		float result[3];
59803b705cfSriastradh
59903b705cfSriastradh		if (!_intel_transform_point(transform,
60003b705cfSriastradh					    x, y,
60103b705cfSriastradh					    result))
60203b705cfSriastradh			return FALSE;
60303b705cfSriastradh		*x_out = result[0];
60403b705cfSriastradh		*y_out = result[1];
60503b705cfSriastradh		*w_out = result[2];
60603b705cfSriastradh	}
60703b705cfSriastradh	return TRUE;
60803b705cfSriastradh}
60903b705cfSriastradh
61003b705cfSriastradh/**
61103b705cfSriastradh * Returns whether the provided transform is affine.
61203b705cfSriastradh *
61303b705cfSriastradh * transform may be null.
61403b705cfSriastradh */
61503b705cfSriastradhBool intel_transform_is_affine(PictTransformPtr t)
61603b705cfSriastradh{
61703b705cfSriastradh	if (t == NULL)
61803b705cfSriastradh		return TRUE;
61903b705cfSriastradh	return t->matrix[2][0] == 0 && t->matrix[2][1] == 0;
62003b705cfSriastradh}
62103b705cfSriastradh
62203b705cfSriastradhdri_bo *intel_get_pixmap_bo(PixmapPtr pixmap)
62303b705cfSriastradh{
62403b705cfSriastradh	struct intel_pixmap *intel;
62503b705cfSriastradh
62603b705cfSriastradh	intel = intel_get_pixmap_private(pixmap);
62703b705cfSriastradh	if (intel == NULL)
62803b705cfSriastradh		return NULL;
62903b705cfSriastradh
63003b705cfSriastradh	return intel->bo;
63103b705cfSriastradh}
63203b705cfSriastradh
63303b705cfSriastradhvoid intel_set_pixmap_bo(PixmapPtr pixmap, dri_bo * bo)
63403b705cfSriastradh{
63503b705cfSriastradh	struct intel_pixmap *priv;
63603b705cfSriastradh
63703b705cfSriastradh	priv = intel_get_pixmap_private(pixmap);
63803b705cfSriastradh	if (priv == NULL && bo == NULL)
63903b705cfSriastradh	    return;
64003b705cfSriastradh
64103b705cfSriastradh	if (priv != NULL) {
64203b705cfSriastradh		if (priv->bo == bo)
64303b705cfSriastradh			return;
64403b705cfSriastradh
64503b705cfSriastradh		dri_bo_unreference(priv->bo);
64603b705cfSriastradh		list_del(&priv->batch);
64703b705cfSriastradh
64803b705cfSriastradh		free(priv);
64903b705cfSriastradh		priv = NULL;
65003b705cfSriastradh	}
65103b705cfSriastradh
65203b705cfSriastradh	if (bo != NULL) {
65303b705cfSriastradh		uint32_t tiling;
65403b705cfSriastradh		uint32_t swizzle_mode;
65503b705cfSriastradh		int ret;
65603b705cfSriastradh
65703b705cfSriastradh		priv = calloc(1, sizeof (struct intel_pixmap));
65803b705cfSriastradh		if (priv == NULL)
65903b705cfSriastradh			goto BAIL;
66003b705cfSriastradh
66103b705cfSriastradh		list_init(&priv->batch);
66203b705cfSriastradh
66303b705cfSriastradh		dri_bo_reference(bo);
66403b705cfSriastradh		priv->bo = bo;
66503b705cfSriastradh		priv->stride = intel_pixmap_pitch(pixmap);
66603b705cfSriastradh
66703b705cfSriastradh		ret = drm_intel_bo_get_tiling(bo, &tiling, &swizzle_mode);
66803b705cfSriastradh		if (ret != 0) {
66903b705cfSriastradh			FatalError("Couldn't get tiling on bo %p: %s\n",
67003b705cfSriastradh				   bo, strerror(-ret));
67103b705cfSriastradh		}
67203b705cfSriastradh
67303b705cfSriastradh		priv->tiling = tiling;
67403b705cfSriastradh		priv->busy = -1;
67503b705cfSriastradh		priv->offscreen = 1;
67603b705cfSriastradh	}
67703b705cfSriastradh
67803b705cfSriastradh  BAIL:
67903b705cfSriastradh	intel_set_pixmap_private(pixmap, priv);
68003b705cfSriastradh}
68103b705cfSriastradh
68203b705cfSriastradhstatic Bool intel_uxa_pixmap_is_offscreen(PixmapPtr pixmap)
68303b705cfSriastradh{
68403b705cfSriastradh	return intel_pixmap_is_offscreen(pixmap);
68503b705cfSriastradh}
68603b705cfSriastradh
68703b705cfSriastradhstatic Bool intel_uxa_prepare_access(PixmapPtr pixmap, uxa_access_t access)
68803b705cfSriastradh{
68903b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
69003b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
69103b705cfSriastradh	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
69203b705cfSriastradh	dri_bo *bo = priv->bo;
69303b705cfSriastradh	int ret;
69403b705cfSriastradh
69503b705cfSriastradh	/* Transitioning to glamor acceleration, we need to flush all pending
69603b705cfSriastradh	 * usage by UXA. */
69703b705cfSriastradh	if (access == UXA_GLAMOR_ACCESS_RW || access == UXA_GLAMOR_ACCESS_RO) {
69803b705cfSriastradh		if (!list_is_empty(&priv->batch))
69903b705cfSriastradh			intel_batch_submit(scrn);
70003b705cfSriastradh		return TRUE;
70103b705cfSriastradh	}
70203b705cfSriastradh
70303b705cfSriastradh	/* When falling back to swrast, flush all pending operations */
70403b705cfSriastradh	intel_glamor_flush(intel);
70503b705cfSriastradh	if (access == UXA_ACCESS_RW || priv->dirty)
70603b705cfSriastradh		intel_batch_submit(scrn);
70703b705cfSriastradh
70803b705cfSriastradh	assert(bo->size <= intel->max_gtt_map_size);
70903b705cfSriastradh	ret = drm_intel_gem_bo_map_gtt(bo);
71003b705cfSriastradh	if (ret) {
71103b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
71203b705cfSriastradh			   "%s: bo map (use gtt? %d, access %d) failed: %s\n",
71303b705cfSriastradh			   __FUNCTION__,
71403b705cfSriastradh			   priv->tiling || bo->size <= intel->max_gtt_map_size,
71503b705cfSriastradh			   access,
71603b705cfSriastradh			   strerror(-ret));
71703b705cfSriastradh		return FALSE;
71803b705cfSriastradh	}
71903b705cfSriastradh
72003b705cfSriastradh	pixmap->devPrivate.ptr = bo->virtual;
72103b705cfSriastradh	priv->busy = 0;
72203b705cfSriastradh
72303b705cfSriastradh	return TRUE;
72403b705cfSriastradh}
72503b705cfSriastradh
72603b705cfSriastradhstatic void intel_uxa_finish_access(PixmapPtr pixmap, uxa_access_t access)
72703b705cfSriastradh{
72803b705cfSriastradh	struct intel_pixmap *priv;
72903b705cfSriastradh
73003b705cfSriastradh	if (access == UXA_GLAMOR_ACCESS_RW || access == UXA_GLAMOR_ACCESS_RO)
73103b705cfSriastradh		return;
73203b705cfSriastradh
73303b705cfSriastradh	priv = intel_get_pixmap_private(pixmap);
73403b705cfSriastradh	if (priv == NULL)
73503b705cfSriastradh		return;
73603b705cfSriastradh
73703b705cfSriastradh	drm_intel_gem_bo_unmap_gtt(priv->bo);
73803b705cfSriastradh	pixmap->devPrivate.ptr = NULL;
73903b705cfSriastradh}
74003b705cfSriastradh
74103b705cfSriastradhstatic Bool intel_uxa_pixmap_put_image(PixmapPtr pixmap,
74203b705cfSriastradh				       char *src, int src_pitch,
74303b705cfSriastradh				       int x, int y, int w, int h)
74403b705cfSriastradh{
74503b705cfSriastradh	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
74603b705cfSriastradh	int stride = intel_pixmap_pitch(pixmap);
74703b705cfSriastradh	int cpp = pixmap->drawable.bitsPerPixel/8;
74803b705cfSriastradh	int ret = FALSE;
74903b705cfSriastradh
75003b705cfSriastradh	if (priv == NULL || priv->bo == NULL)
75103b705cfSriastradh		return FALSE;
75203b705cfSriastradh
75303b705cfSriastradh	if (priv->tiling == I915_TILING_NONE &&
75403b705cfSriastradh	    (h == 1 || (src_pitch == stride && w == pixmap->drawable.width))) {
75503b705cfSriastradh		return drm_intel_bo_subdata(priv->bo, y*stride + x*cpp, stride*(h-1) + w*cpp, src) == 0;
75603b705cfSriastradh	} else if (drm_intel_gem_bo_map_gtt(priv->bo) == 0) {
75703b705cfSriastradh		char *dst = priv->bo->virtual;
75803b705cfSriastradh		int row_length = w * cpp;
75903b705cfSriastradh		int num_rows = h;
76003b705cfSriastradh		if (row_length == src_pitch && src_pitch == stride)
76103b705cfSriastradh			num_rows = 1, row_length *= h;
76203b705cfSriastradh		dst += y * stride + x * cpp;
76303b705cfSriastradh		do {
76403b705cfSriastradh			memcpy (dst, src, row_length);
76503b705cfSriastradh			src += src_pitch;
76603b705cfSriastradh			dst += stride;
76703b705cfSriastradh		} while (--num_rows);
76803b705cfSriastradh		drm_intel_gem_bo_unmap_gtt(priv->bo);
76903b705cfSriastradh		ret = TRUE;
77003b705cfSriastradh	}
77103b705cfSriastradh
77203b705cfSriastradh	return ret;
77303b705cfSriastradh}
77403b705cfSriastradh
77503b705cfSriastradhstatic Bool intel_uxa_put_image(PixmapPtr pixmap,
77603b705cfSriastradh				int x, int y,
77703b705cfSriastradh				int w, int h,
77803b705cfSriastradh				char *src, int src_pitch)
77903b705cfSriastradh{
78003b705cfSriastradh	struct intel_pixmap *priv;
78103b705cfSriastradh
78203b705cfSriastradh	priv = intel_get_pixmap_private(pixmap);
78303b705cfSriastradh	if (!intel_pixmap_is_busy(priv)) {
78403b705cfSriastradh		/* bo is not busy so can be replaced without a stall, upload in-place. */
78503b705cfSriastradh		return intel_uxa_pixmap_put_image(pixmap, src, src_pitch, x, y, w, h);
78603b705cfSriastradh	} else {
78703b705cfSriastradh		ScreenPtr screen = pixmap->drawable.pScreen;
78803b705cfSriastradh
78903b705cfSriastradh		if (!priv->pinned &&
79003b705cfSriastradh		    x == 0 && y == 0 &&
79103b705cfSriastradh		    w == pixmap->drawable.width &&
79203b705cfSriastradh		    h == pixmap->drawable.height)
79303b705cfSriastradh		{
79403b705cfSriastradh			intel_screen_private *intel = intel_get_screen_private(xf86ScreenToScrn(screen));
79503b705cfSriastradh			uint32_t tiling = priv->tiling;
79603b705cfSriastradh			int size, stride;
79703b705cfSriastradh			dri_bo *bo;
79803b705cfSriastradh
79903b705cfSriastradh			/* Replace busy bo. */
80003b705cfSriastradh			size = intel_uxa_pixmap_compute_size (pixmap, w, h,
80103b705cfSriastradh							      &tiling, &stride, 0);
80203b705cfSriastradh			if (size > intel->max_gtt_map_size)
80303b705cfSriastradh				return FALSE;
80403b705cfSriastradh
80503b705cfSriastradh			bo = drm_intel_bo_alloc(intel->bufmgr, "pixmap", size, 0);
80603b705cfSriastradh			if (bo == NULL)
80703b705cfSriastradh				return FALSE;
80803b705cfSriastradh
80903b705cfSriastradh			if (tiling != I915_TILING_NONE)
81003b705cfSriastradh				drm_intel_bo_set_tiling(bo, &tiling, stride);
81103b705cfSriastradh			priv->stride = stride;
81203b705cfSriastradh			priv->tiling = tiling;
81303b705cfSriastradh
81403b705cfSriastradh			screen->ModifyPixmapHeader(pixmap,
81503b705cfSriastradh						   w, h,
81603b705cfSriastradh						   0, 0,
81703b705cfSriastradh						   stride, NULL);
81803b705cfSriastradh			intel_set_pixmap_bo(pixmap, bo);
81903b705cfSriastradh			dri_bo_unreference(bo);
82003b705cfSriastradh
82103b705cfSriastradh			return intel_uxa_pixmap_put_image(pixmap, src, src_pitch, 0, 0, w, h);
82203b705cfSriastradh		}
82303b705cfSriastradh		else
82403b705cfSriastradh		{
82503b705cfSriastradh			PixmapPtr scratch;
82603b705cfSriastradh			Bool ret;
82703b705cfSriastradh
82803b705cfSriastradh			/* Upload to a linear buffer and queue a blit.  */
82903b705cfSriastradh			scratch = (*screen->CreatePixmap)(screen, w, h,
83003b705cfSriastradh							  pixmap->drawable.depth,
83103b705cfSriastradh							  UXA_CREATE_PIXMAP_FOR_MAP);
83203b705cfSriastradh			if (!scratch)
83303b705cfSriastradh				return FALSE;
83403b705cfSriastradh
83503b705cfSriastradh			if (!intel_uxa_pixmap_is_offscreen(scratch)) {
83603b705cfSriastradh				screen->DestroyPixmap(scratch);
83703b705cfSriastradh				return FALSE;
83803b705cfSriastradh			}
83903b705cfSriastradh
84003b705cfSriastradh			ret = intel_uxa_pixmap_put_image(scratch, src, src_pitch, 0, 0, w, h);
84103b705cfSriastradh			if (ret) {
84203b705cfSriastradh				GCPtr gc = GetScratchGC(pixmap->drawable.depth, screen);
84303b705cfSriastradh				if (gc) {
84403b705cfSriastradh					ValidateGC(&pixmap->drawable, gc);
84503b705cfSriastradh
84603b705cfSriastradh					(*gc->ops->CopyArea)(&scratch->drawable,
84703b705cfSriastradh							     &pixmap->drawable,
84803b705cfSriastradh							     gc, 0, 0, w, h, x, y);
84903b705cfSriastradh
85003b705cfSriastradh					FreeScratchGC(gc);
85103b705cfSriastradh				} else
85203b705cfSriastradh					ret = FALSE;
85303b705cfSriastradh			}
85403b705cfSriastradh
85503b705cfSriastradh			(*screen->DestroyPixmap)(scratch);
85603b705cfSriastradh			return ret;
85703b705cfSriastradh		}
85803b705cfSriastradh	}
85903b705cfSriastradh}
86003b705cfSriastradh
86103b705cfSriastradhstatic Bool intel_uxa_pixmap_get_image(PixmapPtr pixmap,
86203b705cfSriastradh				       int x, int y, int w, int h,
86303b705cfSriastradh				       char *dst, int dst_pitch)
86403b705cfSriastradh{
86503b705cfSriastradh	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
86603b705cfSriastradh	int stride = intel_pixmap_pitch(pixmap);
86703b705cfSriastradh	int cpp = pixmap->drawable.bitsPerPixel/8;
86803b705cfSriastradh
86903b705cfSriastradh	/* assert(priv->tiling == I915_TILING_NONE); */
87003b705cfSriastradh	if (h == 1 || (dst_pitch == stride && w == pixmap->drawable.width)) {
87103b705cfSriastradh		return drm_intel_bo_get_subdata(priv->bo, y*stride + x*cpp, (h-1)*stride + w*cpp, dst) == 0;
87203b705cfSriastradh	} else {
87303b705cfSriastradh		char *src;
87403b705cfSriastradh
87503b705cfSriastradh		if (drm_intel_gem_bo_map_gtt(priv->bo))
87603b705cfSriastradh		    return FALSE;
87703b705cfSriastradh
87803b705cfSriastradh		src = (char *) priv->bo->virtual + y * stride + x * cpp;
87903b705cfSriastradh		w *= cpp;
88003b705cfSriastradh		do {
88103b705cfSriastradh			memcpy(dst, src, w);
88203b705cfSriastradh			src += stride;
88303b705cfSriastradh			dst += dst_pitch;
88403b705cfSriastradh		} while (--h);
88503b705cfSriastradh
88603b705cfSriastradh		drm_intel_gem_bo_unmap_gtt(priv->bo);
88703b705cfSriastradh
88803b705cfSriastradh		return TRUE;
88903b705cfSriastradh	}
89003b705cfSriastradh}
89103b705cfSriastradh
89203b705cfSriastradhstatic Bool intel_uxa_get_image(PixmapPtr pixmap,
89303b705cfSriastradh				int x, int y,
89403b705cfSriastradh				int w, int h,
89503b705cfSriastradh				char *dst, int dst_pitch)
89603b705cfSriastradh{
89703b705cfSriastradh	struct intel_pixmap *priv;
89803b705cfSriastradh	PixmapPtr scratch = NULL;
89903b705cfSriastradh	Bool ret;
90003b705cfSriastradh
90103b705cfSriastradh	/* The presumption is that we wish to keep the target hot, so
90203b705cfSriastradh	 * copy to a new bo and move that to the CPU in preference to
90303b705cfSriastradh	 * causing ping-pong of the original.
90403b705cfSriastradh	 *
90503b705cfSriastradh	 * Also the gpu is much faster at detiling.
90603b705cfSriastradh	 */
90703b705cfSriastradh
90803b705cfSriastradh	priv = intel_get_pixmap_private(pixmap);
90903b705cfSriastradh	if (intel_pixmap_is_busy(priv) || priv->tiling != I915_TILING_NONE) {
91003b705cfSriastradh		ScreenPtr screen = pixmap->drawable.pScreen;
91103b705cfSriastradh		GCPtr gc;
91203b705cfSriastradh
91303b705cfSriastradh		/* Copy to a linear buffer and pull.  */
91403b705cfSriastradh		scratch = screen->CreatePixmap(screen, w, h,
91503b705cfSriastradh					       pixmap->drawable.depth,
91603b705cfSriastradh					       INTEL_CREATE_PIXMAP_TILING_NONE);
91703b705cfSriastradh		if (!scratch)
91803b705cfSriastradh			return FALSE;
91903b705cfSriastradh
92003b705cfSriastradh		if (!intel_uxa_pixmap_is_offscreen(scratch)) {
92103b705cfSriastradh			screen->DestroyPixmap(scratch);
92203b705cfSriastradh			return FALSE;
92303b705cfSriastradh		}
92403b705cfSriastradh
92503b705cfSriastradh		gc = GetScratchGC(pixmap->drawable.depth, screen);
92603b705cfSriastradh		if (!gc) {
92703b705cfSriastradh			screen->DestroyPixmap(scratch);
92803b705cfSriastradh			return FALSE;
92903b705cfSriastradh		}
93003b705cfSriastradh
93103b705cfSriastradh		ValidateGC(&pixmap->drawable, gc);
93203b705cfSriastradh
93303b705cfSriastradh		gc->ops->CopyArea(&pixmap->drawable,
93403b705cfSriastradh				  &scratch->drawable,
93503b705cfSriastradh				  gc, x, y, w, h, 0, 0);
93603b705cfSriastradh
93703b705cfSriastradh		FreeScratchGC(gc);
93803b705cfSriastradh
93903b705cfSriastradh		intel_batch_submit(xf86ScreenToScrn(screen));
94003b705cfSriastradh
94103b705cfSriastradh		x = y = 0;
94203b705cfSriastradh		pixmap = scratch;
94303b705cfSriastradh	}
94403b705cfSriastradh
94503b705cfSriastradh	ret = intel_uxa_pixmap_get_image(pixmap, x, y, w, h, dst, dst_pitch);
94603b705cfSriastradh
94703b705cfSriastradh	if (scratch)
94803b705cfSriastradh		scratch->drawable.pScreen->DestroyPixmap(scratch);
94903b705cfSriastradh
95003b705cfSriastradh	return ret;
95103b705cfSriastradh}
95203b705cfSriastradh
95303b705cfSriastradhstatic CARD32 intel_cache_expire(OsTimerPtr timer, CARD32 now, pointer data)
95403b705cfSriastradh{
95503b705cfSriastradh	intel_screen_private *intel = data;
95603b705cfSriastradh
95703b705cfSriastradh	/* We just want to create and destroy a bo as this causes libdrm
95803b705cfSriastradh	 * to reap its caches. However, since we can't remove that buffer
95903b705cfSriastradh	 * from the cache due to its own activity, we want to use something
96003b705cfSriastradh	 * that we know we will reuse later. The most frequently reused buffer
96103b705cfSriastradh	 * we have is the batchbuffer, and the best way to trigger its
96203b705cfSriastradh	 * reallocation is to submit a flush.
96303b705cfSriastradh	 */
96403b705cfSriastradh	intel_batch_emit_flush(intel->scrn);
96503b705cfSriastradh	intel_batch_submit(intel->scrn);
96603b705cfSriastradh
96703b705cfSriastradh	return 0;
96803b705cfSriastradh}
96903b705cfSriastradh
97003b705cfSriastradhstatic void intel_flush_rendering(intel_screen_private *intel)
97103b705cfSriastradh{
97203b705cfSriastradh	if (intel->needs_flush == 0)
97303b705cfSriastradh		return;
97403b705cfSriastradh
97503b705cfSriastradh	if (intel->has_kernel_flush) {
97603b705cfSriastradh		intel_batch_submit(intel->scrn);
97703b705cfSriastradh		drm_intel_bo_busy(intel->front_buffer);
97803b705cfSriastradh	} else {
97903b705cfSriastradh		intel_batch_emit_flush(intel->scrn);
98003b705cfSriastradh		intel_batch_submit(intel->scrn);
98103b705cfSriastradh	}
98203b705cfSriastradh
98303b705cfSriastradh	intel->cache_expire = TimerSet(intel->cache_expire, 0, 3000,
98403b705cfSriastradh				       intel_cache_expire, intel);
98503b705cfSriastradh
98603b705cfSriastradh	intel->needs_flush = 0;
98703b705cfSriastradh}
98803b705cfSriastradh
98903b705cfSriastradhstatic void intel_throttle(intel_screen_private *intel)
99003b705cfSriastradh{
99103b705cfSriastradh	drmCommandNone(intel->drmSubFD, DRM_I915_GEM_THROTTLE);
99203b705cfSriastradh}
99303b705cfSriastradh
99403b705cfSriastradhvoid intel_uxa_block_handler(intel_screen_private *intel)
99503b705cfSriastradh{
99603b705cfSriastradh	/* Emit a flush of the rendering cache, or on the 965
99703b705cfSriastradh	 * and beyond rendering results may not hit the
99803b705cfSriastradh	 * framebuffer until significantly later.
99903b705cfSriastradh	 */
100003b705cfSriastradh	intel_glamor_flush(intel);
100103b705cfSriastradh	intel_flush_rendering(intel);
100203b705cfSriastradh	intel_throttle(intel);
100303b705cfSriastradh}
100403b705cfSriastradh
100503b705cfSriastradhstatic PixmapPtr
100603b705cfSriastradhintel_uxa_create_pixmap(ScreenPtr screen, int w, int h, int depth,
100703b705cfSriastradh			unsigned usage)
100803b705cfSriastradh{
100903b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
101003b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
101103b705cfSriastradh	struct intel_pixmap *priv;
101203b705cfSriastradh	PixmapPtr pixmap, new_pixmap = NULL;
101303b705cfSriastradh
101403b705cfSriastradh	if (!(usage & INTEL_CREATE_PIXMAP_DRI2)) {
101503b705cfSriastradh		pixmap = intel_glamor_create_pixmap(screen, w, h, depth, usage);
101603b705cfSriastradh		if (pixmap)
101703b705cfSriastradh			return pixmap;
101803b705cfSriastradh	}
101903b705cfSriastradh
102003b705cfSriastradh	if (w > 32767 || h > 32767)
102103b705cfSriastradh		return NullPixmap;
102203b705cfSriastradh
102303b705cfSriastradh	if (depth == 1 || intel->force_fallback)
102403b705cfSriastradh		return fbCreatePixmap(screen, w, h, depth, usage);
102503b705cfSriastradh
102603b705cfSriastradh	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32)
102703b705cfSriastradh		return fbCreatePixmap(screen, w, h, depth, usage);
102803b705cfSriastradh
102903b705cfSriastradh	pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
103003b705cfSriastradh	if (pixmap == NullPixmap)
103103b705cfSriastradh		return pixmap;
103203b705cfSriastradh
103303b705cfSriastradh	if (w && h) {
103403b705cfSriastradh		unsigned int size, tiling;
103503b705cfSriastradh		int stride;
103603b705cfSriastradh
103703b705cfSriastradh		/* Always attempt to tile, compute_size() will remove the
103803b705cfSriastradh		 * tiling for pixmaps that are either too large or too small
103903b705cfSriastradh		 * to be effectively tiled.
104003b705cfSriastradh		 */
104103b705cfSriastradh		tiling = I915_TILING_X;
104203b705cfSriastradh		if (usage & INTEL_CREATE_PIXMAP_TILING_Y)
104303b705cfSriastradh			tiling = I915_TILING_Y;
104403b705cfSriastradh		if (usage == UXA_CREATE_PIXMAP_FOR_MAP || usage & INTEL_CREATE_PIXMAP_TILING_NONE)
104503b705cfSriastradh			tiling = I915_TILING_NONE;
104603b705cfSriastradh
104703b705cfSriastradh#ifdef CREATE_PIXMAP_USAGE_SHARED
104803b705cfSriastradh		if (usage == CREATE_PIXMAP_USAGE_SHARED)
104903b705cfSriastradh			tiling = I915_TILING_NONE;
105003b705cfSriastradh#endif
105103b705cfSriastradh		/* if tiling is off force to none */
105203b705cfSriastradh		if (!intel->tiling)
105303b705cfSriastradh			tiling = I915_TILING_NONE;
105403b705cfSriastradh
105503b705cfSriastradh		if (tiling != I915_TILING_NONE && !(usage & INTEL_CREATE_PIXMAP_DRI2)) {
105603b705cfSriastradh		    if (h <= 4)
105703b705cfSriastradh			tiling = I915_TILING_NONE;
105803b705cfSriastradh		    if (h <= 16 && tiling == I915_TILING_Y)
105903b705cfSriastradh			tiling = I915_TILING_X;
106003b705cfSriastradh		}
106103b705cfSriastradh		size = intel_uxa_pixmap_compute_size(pixmap, w, h, &tiling, &stride, usage);
106203b705cfSriastradh
106303b705cfSriastradh		/* Fail very large allocations.  Large BOs will tend to hit SW fallbacks
106403b705cfSriastradh		 * frequently, and also will tend to fail to successfully map when doing
106503b705cfSriastradh		 * SW fallbacks because we overcommit address space for BO access.
106603b705cfSriastradh		 */
106703b705cfSriastradh		if (size > intel->max_bo_size || stride >= KB(32))
106803b705cfSriastradh			goto fallback_pixmap;
106903b705cfSriastradh
107003b705cfSriastradh		priv = calloc(1, sizeof (struct intel_pixmap));
107103b705cfSriastradh		if (priv == NULL)
107203b705cfSriastradh			goto fallback_pixmap;
107303b705cfSriastradh
107403b705cfSriastradh		if (usage == UXA_CREATE_PIXMAP_FOR_MAP) {
107503b705cfSriastradh			priv->busy = 0;
107603b705cfSriastradh			priv->bo = drm_intel_bo_alloc(intel->bufmgr,
107703b705cfSriastradh						      "pixmap", size, 0);
107803b705cfSriastradh		} else {
107903b705cfSriastradh			priv->busy = -1;
108003b705cfSriastradh			priv->bo = drm_intel_bo_alloc_for_render(intel->bufmgr,
108103b705cfSriastradh								 "pixmap",
108203b705cfSriastradh								 size, 0);
108303b705cfSriastradh		}
108403b705cfSriastradh		if (!priv->bo)
108503b705cfSriastradh			goto fallback_priv;
108603b705cfSriastradh
108703b705cfSriastradh		if (tiling != I915_TILING_NONE)
108803b705cfSriastradh			drm_intel_bo_set_tiling(priv->bo, &tiling, stride);
108903b705cfSriastradh		priv->stride = stride;
109003b705cfSriastradh		priv->tiling = tiling;
109103b705cfSriastradh		priv->offscreen = 1;
109203b705cfSriastradh
109303b705cfSriastradh		list_init(&priv->batch);
109403b705cfSriastradh		intel_set_pixmap_private(pixmap, priv);
109503b705cfSriastradh
109603b705cfSriastradh		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL);
109703b705cfSriastradh
109803b705cfSriastradh		if (!intel_glamor_create_textured_pixmap(pixmap))
109903b705cfSriastradh			goto fallback_glamor;
110003b705cfSriastradh	}
110103b705cfSriastradh
110203b705cfSriastradh	return pixmap;
110303b705cfSriastradh
110403b705cfSriastradhfallback_glamor:
110503b705cfSriastradh	if (usage & INTEL_CREATE_PIXMAP_DRI2) {
110603b705cfSriastradh	/* XXX need further work to handle the DRI2 failure case.
110703b705cfSriastradh	 * Glamor don't know how to handle a BO only pixmap. Put
110803b705cfSriastradh	 * a warning indicator here.
110903b705cfSriastradh	 */
111003b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
111103b705cfSriastradh			   "Failed to create textured DRI2 pixmap.");
111203b705cfSriastradh		return pixmap;
111303b705cfSriastradh	}
111403b705cfSriastradh	/* Create textured pixmap failed means glamor failed to
111503b705cfSriastradh	 * create a texture from current BO for some reasons. We turn
111603b705cfSriastradh	 * to create a new glamor pixmap and clean up current one.
111703b705cfSriastradh	 * One thing need to be noted, this new pixmap doesn't
111803b705cfSriastradh	 * has a priv and bo attached to it. It's glamor's responsbility
111903b705cfSriastradh	 * to take care of it. Glamor will mark this new pixmap as a
112003b705cfSriastradh	 * texture only pixmap and will never fallback to DDX layer
112103b705cfSriastradh	 * afterwards.
112203b705cfSriastradh	 */
112303b705cfSriastradh	new_pixmap = intel_glamor_create_pixmap(screen, w, h,
112403b705cfSriastradh						depth, usage);
112503b705cfSriastradh	dri_bo_unreference(priv->bo);
112603b705cfSriastradhfallback_priv:
112703b705cfSriastradh	free(priv);
112803b705cfSriastradhfallback_pixmap:
112903b705cfSriastradh	fbDestroyPixmap(pixmap);
113003b705cfSriastradh	if (new_pixmap)
113103b705cfSriastradh		return new_pixmap;
113203b705cfSriastradh	else
113303b705cfSriastradh		return fbCreatePixmap(screen, w, h, depth, usage);
113403b705cfSriastradh}
113503b705cfSriastradh
113603b705cfSriastradhstatic Bool intel_uxa_destroy_pixmap(PixmapPtr pixmap)
113703b705cfSriastradh{
113803b705cfSriastradh	if (pixmap->refcnt == 1) {
113903b705cfSriastradh		intel_glamor_destroy_pixmap(pixmap);
114003b705cfSriastradh		intel_set_pixmap_bo(pixmap, NULL);
114103b705cfSriastradh	}
114203b705cfSriastradh	fbDestroyPixmap(pixmap);
114303b705cfSriastradh	return TRUE;
114403b705cfSriastradh}
114503b705cfSriastradh
114603b705cfSriastradhBool intel_uxa_create_screen_resources(ScreenPtr screen)
114703b705cfSriastradh{
114803b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
114903b705cfSriastradh	PixmapPtr pixmap;
115003b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
115103b705cfSriastradh	dri_bo *bo = intel->front_buffer;
115203b705cfSriastradh
115303b705cfSriastradh	if (!uxa_resources_init(screen))
115403b705cfSriastradh		return FALSE;
115503b705cfSriastradh
115603b705cfSriastradh	if (drm_intel_gem_bo_map_gtt(bo))
115703b705cfSriastradh		return FALSE;
115803b705cfSriastradh
115903b705cfSriastradh	pixmap = screen->GetScreenPixmap(screen);
116003b705cfSriastradh	intel_set_pixmap_bo(pixmap, bo);
116103b705cfSriastradh	intel_get_pixmap_private(pixmap)->pinned |= PIN_SCANOUT;
116203b705cfSriastradh	screen->ModifyPixmapHeader(pixmap,
116303b705cfSriastradh				   scrn->virtualX,
116403b705cfSriastradh				   scrn->virtualY,
116503b705cfSriastradh				   -1, -1,
116603b705cfSriastradh				   intel->front_pitch,
116703b705cfSriastradh				   NULL);
116803b705cfSriastradh	scrn->displayWidth = intel->front_pitch / intel->cpp;
116903b705cfSriastradh
117003b705cfSriastradh	if (!intel_glamor_create_screen_resources(screen))
117103b705cfSriastradh		return FALSE;
117203b705cfSriastradh
117303b705cfSriastradh	return TRUE;
117403b705cfSriastradh}
117503b705cfSriastradh
117603b705cfSriastradh#ifdef CREATE_PIXMAP_USAGE_SHARED
117703b705cfSriastradhstatic Bool
117803b705cfSriastradhintel_uxa_share_pixmap_backing(PixmapPtr ppix, ScreenPtr slave, void **fd_handle)
117903b705cfSriastradh{
118003b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(ppix->drawable.pScreen);
118103b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
118203b705cfSriastradh	struct intel_pixmap *priv = intel_get_pixmap_private(ppix);
118303b705cfSriastradh	unsigned int size, tiling, swizzle;
118403b705cfSriastradh	dri_bo *bo = intel_get_pixmap_bo(ppix), *newbo;
118503b705cfSriastradh	int stride;
118603b705cfSriastradh	int handle;
118703b705cfSriastradh
118803b705cfSriastradh	if (drm_intel_bo_references(intel->batch_bo, bo))
118903b705cfSriastradh		intel_batch_submit(intel->scrn);
119003b705cfSriastradh
119103b705cfSriastradh	drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
119203b705cfSriastradh
119303b705cfSriastradh	if (tiling == I915_TILING_X) {
119403b705cfSriastradh		if (priv->pinned & ~PIN_DRI)
119503b705cfSriastradh			return FALSE;
119603b705cfSriastradh
119703b705cfSriastradh	        tiling = I915_TILING_NONE;
119803b705cfSriastradh
119903b705cfSriastradh		size = intel_uxa_pixmap_compute_size(ppix, ppix->drawable.width, ppix->drawable.height, &tiling, &stride, INTEL_CREATE_PIXMAP_DRI2);
120003b705cfSriastradh
120103b705cfSriastradh		newbo = drm_intel_bo_alloc_for_render(intel->bufmgr,
120203b705cfSriastradh						      "pixmap",
120303b705cfSriastradh						      size, 0);
120403b705cfSriastradh
120503b705cfSriastradh		if (tiling != I915_TILING_NONE)
120603b705cfSriastradh			drm_intel_bo_set_tiling(newbo, &tiling, stride);
120703b705cfSriastradh		priv->stride = stride;
120803b705cfSriastradh		priv->tiling = tiling;
120903b705cfSriastradh		intel_set_pixmap_bo(ppix, newbo);
121003b705cfSriastradh
121103b705cfSriastradh		ppix->drawable.pScreen->ModifyPixmapHeader(ppix, ppix->drawable.width,
121203b705cfSriastradh					   ppix->drawable.height, 0, 0,
121303b705cfSriastradh					   stride, NULL);
121403b705cfSriastradh		bo = newbo;
121503b705cfSriastradh	}
121603b705cfSriastradh	drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
121703b705cfSriastradh	drm_intel_bo_gem_export_to_prime(bo, &handle);
121803b705cfSriastradh	priv->pinned |= PIN_DRI;
121903b705cfSriastradh
122003b705cfSriastradh	*fd_handle = (void *)(long)handle;
122103b705cfSriastradh	return TRUE;
122203b705cfSriastradh}
122303b705cfSriastradh
122403b705cfSriastradhstatic Bool
122503b705cfSriastradhintel_uxa_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle)
122603b705cfSriastradh{
122703b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(ppix->drawable.pScreen);
122803b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
122903b705cfSriastradh	dri_bo *bo;
123003b705cfSriastradh	int ihandle = (int)(long)fd_handle;
123103b705cfSriastradh
123203b705cfSriastradh	/* force untiled for now */
123303b705cfSriastradh	bo = drm_intel_bo_gem_create_from_prime(intel->bufmgr, ihandle, 0);
123403b705cfSriastradh	if (!bo)
123503b705cfSriastradh		return FALSE;
123603b705cfSriastradh
123703b705cfSriastradh	intel_set_pixmap_bo(ppix, bo);
123803b705cfSriastradh	close(ihandle);
123903b705cfSriastradh	return TRUE;
124003b705cfSriastradh}
124103b705cfSriastradh#endif
124203b705cfSriastradh
124303b705cfSriastradhstatic void
124403b705cfSriastradhintel_limits_init(intel_screen_private *intel)
124503b705cfSriastradh{
124603b705cfSriastradh	/* Limits are described in the BLT engine chapter under Graphics Data Size
124703b705cfSriastradh	 * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO,
124803b705cfSriastradh	 * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO.
124903b705cfSriastradh	 *
125003b705cfSriastradh	 * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768.
125103b705cfSriastradh	 *
125203b705cfSriastradh	 * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled.
125303b705cfSriastradh	 * i965 limits 3D surface to 4kB-aligned offset if tiled.
125403b705cfSriastradh	 * i965 limits 3D surfaces to w,h of ?,8192.
125503b705cfSriastradh	 * i965 limits 3D surface to pitch of 1B - 128kB.
125603b705cfSriastradh	 * i965 limits 3D surface pitch alignment to 1 or 2 times the element size.
125703b705cfSriastradh	 * i965 limits 3D surface pitch alignment to 512B if tiled.
125803b705cfSriastradh	 * i965 limits 3D destination drawing rect to w,h of 8192,8192.
125903b705cfSriastradh	 *
126003b705cfSriastradh	 * i915 limits 3D textures to 4B-aligned offset if un-tiled.
126103b705cfSriastradh	 * i915 limits 3D textures to ~4kB-aligned offset if tiled.
126203b705cfSriastradh	 * i915 limits 3D textures to width,height of 2048,2048.
126303b705cfSriastradh	 * i915 limits 3D textures to pitch of 16B - 8kB, in dwords.
126403b705cfSriastradh	 * i915 limits 3D destination to ~4kB-aligned offset if tiled.
126503b705cfSriastradh	 * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled.
126603b705cfSriastradh	 * i915 limits 3D destination to pitch 64B-aligned if used with depth.
126703b705cfSriastradh	 * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled.
126803b705cfSriastradh	 * i915 limits 3D destination to POT aligned pitch if tiled.
126903b705cfSriastradh	 * i915 limits 3D destination drawing rect to w,h of 2048,2048.
127003b705cfSriastradh	 *
127103b705cfSriastradh	 * i845 limits 3D textures to 4B-aligned offset if un-tiled.
127203b705cfSriastradh	 * i845 limits 3D textures to ~4kB-aligned offset if tiled.
127303b705cfSriastradh	 * i845 limits 3D textures to width,height of 2048,2048.
127403b705cfSriastradh	 * i845 limits 3D textures to pitch of 4B - 8kB, in dwords.
127503b705cfSriastradh	 * i845 limits 3D destination to 4B-aligned offset if un-tiled.
127603b705cfSriastradh	 * i845 limits 3D destination to ~4kB-aligned offset if tiled.
127703b705cfSriastradh	 * i845 limits 3D destination to pitch of 8B - 8kB, in dwords.
127803b705cfSriastradh	 * i845 limits 3D destination drawing rect to w,h of 2048,2048.
127903b705cfSriastradh	 *
128003b705cfSriastradh	 * For the tiled issues, the only tiled buffer we draw to should be
128103b705cfSriastradh	 * the front, which will have an appropriate pitch/offset already set up,
128203b705cfSriastradh	 * so UXA doesn't need to worry.
128303b705cfSriastradh	 */
128403b705cfSriastradh	if (INTEL_INFO(intel)->gen >= 040) {
128503b705cfSriastradh		intel->accel_pixmap_offset_alignment = 4 * 2;
128603b705cfSriastradh		intel->accel_max_x = 8192;
128703b705cfSriastradh		intel->accel_max_y = 8192;
128803b705cfSriastradh	} else {
128903b705cfSriastradh		intel->accel_pixmap_offset_alignment = 4;
129003b705cfSriastradh		intel->accel_max_x = 2048;
129103b705cfSriastradh		intel->accel_max_y = 2048;
129203b705cfSriastradh	}
129303b705cfSriastradh}
129403b705cfSriastradh
129503b705cfSriastradhstatic Bool intel_option_accel_blt(intel_screen_private *intel)
129603b705cfSriastradh{
129703b705cfSriastradh	const char *s;
129803b705cfSriastradh
129903b705cfSriastradh	s = xf86GetOptValString(intel->Options, OPTION_ACCEL_METHOD);
130003b705cfSriastradh	if (s == NULL)
130103b705cfSriastradh		return FALSE;
130203b705cfSriastradh
130303b705cfSriastradh	return strcasecmp(s, "blt") == 0;
130403b705cfSriastradh}
130503b705cfSriastradh
130603b705cfSriastradhBool intel_uxa_init(ScreenPtr screen)
130703b705cfSriastradh{
130803b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
130903b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
131003b705cfSriastradh
131103b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY
131203b705cfSriastradh	if (!dixRegisterPrivateKey(&uxa_pixmap_index, PRIVATE_PIXMAP, 0))
131303b705cfSriastradh#else
131403b705cfSriastradh	if (!dixRequestPrivate(&uxa_pixmap_index, 0))
131503b705cfSriastradh#endif
131603b705cfSriastradh		return FALSE;
131703b705cfSriastradh
131803b705cfSriastradh	intel_limits_init(intel);
131903b705cfSriastradh
132003b705cfSriastradh	intel->uxa_driver = uxa_driver_alloc();
132103b705cfSriastradh	if (intel->uxa_driver == NULL)
132203b705cfSriastradh		return FALSE;
132303b705cfSriastradh
132403b705cfSriastradh	memset(intel->uxa_driver, 0, sizeof(*intel->uxa_driver));
132503b705cfSriastradh
132603b705cfSriastradh	intel->uxa_driver->uxa_major = 1;
132703b705cfSriastradh	intel->uxa_driver->uxa_minor = 0;
132803b705cfSriastradh
132903b705cfSriastradh	intel->prim_offset = 0;
133003b705cfSriastradh	intel->vertex_count = 0;
133103b705cfSriastradh	intel->vertex_offset = 0;
133203b705cfSriastradh	intel->vertex_used = 0;
133303b705cfSriastradh	intel->floats_per_vertex = 0;
133403b705cfSriastradh	intel->last_floats_per_vertex = 0;
133503b705cfSriastradh	intel->vertex_bo = NULL;
133603b705cfSriastradh	intel->surface_used = 0;
133703b705cfSriastradh	intel->surface_reloc = 0;
133803b705cfSriastradh
133903b705cfSriastradh	/* Solid fill */
134003b705cfSriastradh	intel->uxa_driver->check_solid = intel_uxa_check_solid;
134103b705cfSriastradh	intel->uxa_driver->prepare_solid = intel_uxa_prepare_solid;
134203b705cfSriastradh	intel->uxa_driver->solid = intel_uxa_solid;
134303b705cfSriastradh	intel->uxa_driver->done_solid = intel_uxa_done;
134403b705cfSriastradh
134503b705cfSriastradh	/* Copy */
134603b705cfSriastradh	intel->uxa_driver->check_copy = intel_uxa_check_copy;
134703b705cfSriastradh	intel->uxa_driver->prepare_copy = intel_uxa_prepare_copy;
134803b705cfSriastradh	intel->uxa_driver->copy = intel_uxa_copy;
134903b705cfSriastradh	intel->uxa_driver->done_copy = intel_uxa_done;
135003b705cfSriastradh
135103b705cfSriastradh	/* Composite */
135203b705cfSriastradh	if (intel_option_accel_blt(intel)) {
135303b705cfSriastradh	} else if (IS_GEN2(intel)) {
135403b705cfSriastradh		intel->uxa_driver->check_composite = i830_check_composite;
135503b705cfSriastradh		intel->uxa_driver->check_composite_target = i830_check_composite_target;
135603b705cfSriastradh		intel->uxa_driver->check_composite_texture = i830_check_composite_texture;
135703b705cfSriastradh		intel->uxa_driver->prepare_composite = i830_prepare_composite;
135803b705cfSriastradh		intel->uxa_driver->composite = i830_composite;
135903b705cfSriastradh		intel->uxa_driver->done_composite = i830_done_composite;
136003b705cfSriastradh
136103b705cfSriastradh		intel->vertex_flush = i830_vertex_flush;
136203b705cfSriastradh		intel->batch_commit_notify = i830_batch_commit_notify;
136303b705cfSriastradh	} else if (IS_GEN3(intel)) {
136403b705cfSriastradh		intel->uxa_driver->check_composite = i915_check_composite;
136503b705cfSriastradh		intel->uxa_driver->check_composite_target = i915_check_composite_target;
136603b705cfSriastradh		intel->uxa_driver->check_composite_texture = i915_check_composite_texture;
136703b705cfSriastradh		intel->uxa_driver->prepare_composite = i915_prepare_composite;
136803b705cfSriastradh		intel->uxa_driver->composite = i915_composite;
136903b705cfSriastradh		intel->uxa_driver->done_composite = i830_done_composite;
137003b705cfSriastradh
137103b705cfSriastradh		intel->vertex_flush = i915_vertex_flush;
137203b705cfSriastradh		intel->batch_commit_notify = i915_batch_commit_notify;
137303b705cfSriastradh	} else {
137403b705cfSriastradh		intel->uxa_driver->check_composite = i965_check_composite;
137503b705cfSriastradh		intel->uxa_driver->check_composite_texture = i965_check_composite_texture;
137603b705cfSriastradh		intel->uxa_driver->prepare_composite = i965_prepare_composite;
137703b705cfSriastradh		intel->uxa_driver->composite = i965_composite;
137803b705cfSriastradh		intel->uxa_driver->done_composite = i830_done_composite;
137903b705cfSriastradh
138003b705cfSriastradh		intel->vertex_flush = i965_vertex_flush;
138103b705cfSriastradh		intel->batch_flush = i965_batch_flush;
138203b705cfSriastradh		intel->batch_commit_notify = i965_batch_commit_notify;
138303b705cfSriastradh
138403b705cfSriastradh		if (IS_GEN4(intel)) {
138503b705cfSriastradh			intel->context_switch = gen4_context_switch;
138603b705cfSriastradh		} else if (IS_GEN5(intel)) {
138703b705cfSriastradh			intel->context_switch = gen5_context_switch;
138803b705cfSriastradh		} else {
138903b705cfSriastradh			intel->context_switch = gen6_context_switch;
139003b705cfSriastradh		}
139103b705cfSriastradh	}
139203b705cfSriastradh
139303b705cfSriastradh	/* PutImage */
139403b705cfSriastradh	intel->uxa_driver->put_image = intel_uxa_put_image;
139503b705cfSriastradh	intel->uxa_driver->get_image = intel_uxa_get_image;
139603b705cfSriastradh
139703b705cfSriastradh	intel->uxa_driver->prepare_access = intel_uxa_prepare_access;
139803b705cfSriastradh	intel->uxa_driver->finish_access = intel_uxa_finish_access;
139903b705cfSriastradh	intel->uxa_driver->pixmap_is_offscreen = intel_uxa_pixmap_is_offscreen;
140003b705cfSriastradh
140103b705cfSriastradh	screen->CreatePixmap = intel_uxa_create_pixmap;
140203b705cfSriastradh	screen->DestroyPixmap = intel_uxa_destroy_pixmap;
140303b705cfSriastradh
140403b705cfSriastradh#ifdef CREATE_PIXMAP_USAGE_SHARED
140503b705cfSriastradh	screen->SharePixmapBacking = intel_uxa_share_pixmap_backing;
140603b705cfSriastradh	screen->SetSharedPixmapBacking = intel_uxa_set_shared_pixmap_backing;
140703b705cfSriastradh#endif
140803b705cfSriastradh
140903b705cfSriastradh	if (!uxa_driver_init(screen, intel->uxa_driver)) {
141003b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
141103b705cfSriastradh			   "UXA initialization failed\n");
141203b705cfSriastradh		free(intel->uxa_driver);
141303b705cfSriastradh		return FALSE;
141403b705cfSriastradh	}
141503b705cfSriastradh
141603b705cfSriastradh	uxa_set_fallback_debug(screen, intel->fallback_debug);
141703b705cfSriastradh	uxa_set_force_fallback(screen, intel->force_fallback);
141803b705cfSriastradh
141903b705cfSriastradh	return TRUE;
142003b705cfSriastradh}
1421