intel_uxa.c revision 42542f5f
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
3442542f5fSchristos#include "xorg-server.h"
3503b705cfSriastradh#include <xf86.h>
3603b705cfSriastradh#include <xf86drm.h>
3703b705cfSriastradh#include <xaarop.h>
3803b705cfSriastradh#include <string.h>
3903b705cfSriastradh#include <errno.h>
4003b705cfSriastradh#include <unistd.h>
4103b705cfSriastradh
4203b705cfSriastradh#include "intel.h"
4303b705cfSriastradh#include "intel_glamor.h"
4403b705cfSriastradh#include "uxa.h"
4503b705cfSriastradh
4603b705cfSriastradh#include "i830_reg.h"
4703b705cfSriastradh#include "i915_drm.h"
4803b705cfSriastradh#include "brw_defines.h"
4903b705cfSriastradh
5003b705cfSriastradhstatic const int I830CopyROP[16] = {
5103b705cfSriastradh	ROP_0,			/* GXclear */
5203b705cfSriastradh	ROP_DSa,		/* GXand */
5303b705cfSriastradh	ROP_SDna,		/* GXandReverse */
5403b705cfSriastradh	ROP_S,			/* GXcopy */
5503b705cfSriastradh	ROP_DSna,		/* GXandInverted */
5603b705cfSriastradh	ROP_D,			/* GXnoop */
5703b705cfSriastradh	ROP_DSx,		/* GXxor */
5803b705cfSriastradh	ROP_DSo,		/* GXor */
5903b705cfSriastradh	ROP_DSon,		/* GXnor */
6003b705cfSriastradh	ROP_DSxn,		/* GXequiv */
6103b705cfSriastradh	ROP_Dn,			/* GXinvert */
6203b705cfSriastradh	ROP_SDno,		/* GXorReverse */
6303b705cfSriastradh	ROP_Sn,			/* GXcopyInverted */
6403b705cfSriastradh	ROP_DSno,		/* GXorInverted */
6503b705cfSriastradh	ROP_DSan,		/* GXnand */
6603b705cfSriastradh	ROP_1			/* GXset */
6703b705cfSriastradh};
6803b705cfSriastradh
6903b705cfSriastradhstatic const int I830PatternROP[16] = {
7003b705cfSriastradh	ROP_0,
7103b705cfSriastradh	ROP_DPa,
7203b705cfSriastradh	ROP_PDna,
7303b705cfSriastradh	ROP_P,
7403b705cfSriastradh	ROP_DPna,
7503b705cfSriastradh	ROP_D,
7603b705cfSriastradh	ROP_DPx,
7703b705cfSriastradh	ROP_DPo,
7803b705cfSriastradh	ROP_DPon,
7903b705cfSriastradh	ROP_PDxn,
8003b705cfSriastradh	ROP_Dn,
8103b705cfSriastradh	ROP_PDno,
8203b705cfSriastradh	ROP_Pn,
8303b705cfSriastradh	ROP_DPno,
8403b705cfSriastradh	ROP_DPan,
8503b705cfSriastradh	ROP_1
8603b705cfSriastradh};
8703b705cfSriastradh
8803b705cfSriastradh#if HAS_DEVPRIVATEKEYREC
8903b705cfSriastradhDevPrivateKeyRec uxa_pixmap_index;
9003b705cfSriastradh#else
9103b705cfSriastradhint uxa_pixmap_index;
9203b705cfSriastradh#endif
9303b705cfSriastradh
9403b705cfSriastradhstatic void
9503b705cfSriastradhgen6_context_switch(intel_screen_private *intel,
9603b705cfSriastradh		    int new_mode)
9703b705cfSriastradh{
9803b705cfSriastradh	intel_batch_submit(intel->scrn);
9903b705cfSriastradh}
10003b705cfSriastradh
10103b705cfSriastradhstatic void
10203b705cfSriastradhgen5_context_switch(intel_screen_private *intel,
10303b705cfSriastradh		    int new_mode)
10403b705cfSriastradh{
10503b705cfSriastradh	/* Ironlake has a limitation that a 3D or Media command can't
10603b705cfSriastradh	 * be the first command after a BLT, unless it's
10703b705cfSriastradh	 * non-pipelined.  Instead of trying to track it and emit a
10803b705cfSriastradh	 * command at the right time, we just emit a dummy
10903b705cfSriastradh	 * non-pipelined 3D instruction after each blit.
11003b705cfSriastradh	 */
11103b705cfSriastradh
11203b705cfSriastradh	if (new_mode == I915_EXEC_BLT) {
11303b705cfSriastradh		OUT_BATCH(MI_FLUSH |
11403b705cfSriastradh			  MI_STATE_INSTRUCTION_CACHE_FLUSH |
11503b705cfSriastradh			  MI_INHIBIT_RENDER_CACHE_FLUSH);
11603b705cfSriastradh	} else {
11703b705cfSriastradh		OUT_BATCH(CMD_POLY_STIPPLE_OFFSET << 16);
11803b705cfSriastradh		OUT_BATCH(0);
11903b705cfSriastradh	}
12003b705cfSriastradh}
12103b705cfSriastradh
12203b705cfSriastradhstatic void
12303b705cfSriastradhgen4_context_switch(intel_screen_private *intel,
12403b705cfSriastradh		    int new_mode)
12503b705cfSriastradh{
12603b705cfSriastradh	if (new_mode == I915_EXEC_BLT) {
12703b705cfSriastradh		OUT_BATCH(MI_FLUSH |
12803b705cfSriastradh			  MI_STATE_INSTRUCTION_CACHE_FLUSH |
12903b705cfSriastradh			  MI_INHIBIT_RENDER_CACHE_FLUSH);
13003b705cfSriastradh	}
13103b705cfSriastradh}
13203b705cfSriastradh
13303b705cfSriastradhBool
13403b705cfSriastradhintel_get_aperture_space(ScrnInfoPtr scrn, drm_intel_bo ** bo_table,
13503b705cfSriastradh			 int num_bos)
13603b705cfSriastradh{
13703b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
13803b705cfSriastradh
13903b705cfSriastradh	if (intel->batch_bo == NULL) {
14003b705cfSriastradh		intel_debug_fallback(scrn, "VT inactive\n");
14103b705cfSriastradh		return FALSE;
14203b705cfSriastradh	}
14303b705cfSriastradh
14403b705cfSriastradh	bo_table[0] = intel->batch_bo;
14503b705cfSriastradh	if (drm_intel_bufmgr_check_aperture_space(bo_table, num_bos) != 0) {
14603b705cfSriastradh		intel_batch_submit(scrn);
14703b705cfSriastradh		bo_table[0] = intel->batch_bo;
14803b705cfSriastradh		if (drm_intel_bufmgr_check_aperture_space(bo_table, num_bos) !=
14903b705cfSriastradh		    0) {
15003b705cfSriastradh			intel_debug_fallback(scrn, "Couldn't get aperture "
15103b705cfSriastradh					    "space for BOs\n");
15203b705cfSriastradh			return FALSE;
15303b705cfSriastradh		}
15403b705cfSriastradh	}
15503b705cfSriastradh	return TRUE;
15603b705cfSriastradh}
15703b705cfSriastradh
15803b705cfSriastradhstatic unsigned int
15942542f5fSchristosintel_uxa_compute_size(struct intel_screen_private *intel,
16042542f5fSchristos		       int w, int h, int bpp, unsigned usage,
16142542f5fSchristos		       uint32_t *tiling, int *stride)
16203b705cfSriastradh{
16303b705cfSriastradh	int pitch, size;
16403b705cfSriastradh
16503b705cfSriastradh	if (*tiling != I915_TILING_NONE) {
16603b705cfSriastradh		/* First check whether tiling is necessary. */
16742542f5fSchristos		pitch = (w * bpp  + 7) / 8;
16803b705cfSriastradh		pitch = ALIGN(pitch, 64);
16903b705cfSriastradh		size = pitch * ALIGN (h, 2);
17003b705cfSriastradh		if (INTEL_INFO(intel)->gen < 040) {
17103b705cfSriastradh			/* Gen 2/3 has a maximum stride for tiling of
17203b705cfSriastradh			 * 8192 bytes.
17303b705cfSriastradh			 */
17403b705cfSriastradh			if (pitch > KB(8))
17503b705cfSriastradh				*tiling = I915_TILING_NONE;
17603b705cfSriastradh
17703b705cfSriastradh			/* Narrower than half a tile? */
17803b705cfSriastradh			if (pitch < 256)
17903b705cfSriastradh				*tiling = I915_TILING_NONE;
18003b705cfSriastradh
18103b705cfSriastradh			/* Older hardware requires fences to be pot size
18203b705cfSriastradh			 * aligned with a minimum of 1 MiB, so causes
18303b705cfSriastradh			 * massive overallocation for small textures.
18403b705cfSriastradh			 */
18503b705cfSriastradh			if (size < 1024*1024/2 && !intel->has_relaxed_fencing)
18603b705cfSriastradh				*tiling = I915_TILING_NONE;
18703b705cfSriastradh		} else if (!(usage & INTEL_CREATE_PIXMAP_DRI2) && size <= 4096) {
18803b705cfSriastradh			/* Disable tiling beneath a page size, we will not see
18903b705cfSriastradh			 * any benefit from reducing TLB misses and instead
19003b705cfSriastradh			 * just incur extra cost when we require a fence.
19103b705cfSriastradh			 */
19203b705cfSriastradh			*tiling = I915_TILING_NONE;
19303b705cfSriastradh		}
19403b705cfSriastradh	}
19503b705cfSriastradh
19642542f5fSchristos	pitch = (w * bpp + 7) / 8;
19703b705cfSriastradh	if (!(usage & INTEL_CREATE_PIXMAP_DRI2) && pitch <= 256)
19803b705cfSriastradh		*tiling = I915_TILING_NONE;
19903b705cfSriastradh
20003b705cfSriastradh	if (*tiling != I915_TILING_NONE) {
20103b705cfSriastradh		int aligned_h, tile_height;
20203b705cfSriastradh
20303b705cfSriastradh		if (IS_GEN2(intel))
20403b705cfSriastradh			tile_height = 16;
20503b705cfSriastradh		else if (*tiling == I915_TILING_X)
20603b705cfSriastradh			tile_height = 8;
20703b705cfSriastradh		else
20803b705cfSriastradh			tile_height = 32;
20903b705cfSriastradh		aligned_h = ALIGN(h, 2*tile_height);
21003b705cfSriastradh
21103b705cfSriastradh		*stride = intel_get_fence_pitch(intel,
21203b705cfSriastradh						ALIGN(pitch, 512),
21303b705cfSriastradh						*tiling);
21403b705cfSriastradh
21503b705cfSriastradh		/* Round the object up to the size of the fence it will live in
21603b705cfSriastradh		 * if necessary.  We could potentially make the kernel allocate
21703b705cfSriastradh		 * a larger aperture space and just bind the subset of pages in,
21803b705cfSriastradh		 * but this is easier and also keeps us out of trouble (as much)
21903b705cfSriastradh		 * with drm_intel_bufmgr_check_aperture().
22003b705cfSriastradh		 */
22103b705cfSriastradh		size = intel_get_fence_size(intel, *stride * aligned_h);
22203b705cfSriastradh
22303b705cfSriastradh		if (size > intel->max_tiling_size)
22403b705cfSriastradh			*tiling = I915_TILING_NONE;
22503b705cfSriastradh	}
22603b705cfSriastradh
22703b705cfSriastradh	if (*tiling == I915_TILING_NONE) {
22803b705cfSriastradh		/* We only require a 64 byte alignment for scanouts, but
22903b705cfSriastradh		 * a 256 byte alignment for sharing with PRIME.
23003b705cfSriastradh		 */
23103b705cfSriastradh		*stride = ALIGN(pitch, 256);
23203b705cfSriastradh		/* Round the height up so that the GPU's access to a 2x2 aligned
23303b705cfSriastradh		 * subspan doesn't address an invalid page offset beyond the
23403b705cfSriastradh		 * end of the GTT.
23503b705cfSriastradh		 */
23603b705cfSriastradh		size = *stride * ALIGN(h, 2);
23703b705cfSriastradh	}
23803b705cfSriastradh
23903b705cfSriastradh	return size;
24003b705cfSriastradh}
24103b705cfSriastradh
24242542f5fSchristosdrm_intel_bo *intel_allocate_framebuffer(ScrnInfoPtr scrn,
24342542f5fSchristos					 int width, int height, int cpp,
24442542f5fSchristos					 int *out_stride,
24542542f5fSchristos					 uint32_t *out_tiling)
24642542f5fSchristos{
24742542f5fSchristos	intel_screen_private *intel = intel_get_screen_private(scrn);
24842542f5fSchristos	uint32_t tiling;
24942542f5fSchristos	int stride, size;
25042542f5fSchristos	drm_intel_bo *bo;
25142542f5fSchristos
25242542f5fSchristos	if (intel->tiling & INTEL_TILING_FB)
25342542f5fSchristos		tiling = I915_TILING_X;
25442542f5fSchristos	else
25542542f5fSchristos		tiling = I915_TILING_NONE;
25642542f5fSchristos
25742542f5fSchristosretry:
25842542f5fSchristos	size = intel_uxa_compute_size(intel,
25942542f5fSchristos				      width, height,
26042542f5fSchristos				      intel->cpp*8, 0,
26142542f5fSchristos				      &tiling, &stride);
26242542f5fSchristos	if (!intel_check_display_stride(scrn, stride, tiling)) {
26342542f5fSchristos		if (tiling != I915_TILING_NONE) {
26442542f5fSchristos			tiling = I915_TILING_NONE;
26542542f5fSchristos			goto retry;
26642542f5fSchristos		}
26742542f5fSchristos
26842542f5fSchristos		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
26942542f5fSchristos			   "Front buffer stride %d kB "
27042542f5fSchristos			   "exceeds display limit\n", stride / 1024);
27142542f5fSchristos		return NULL;
27242542f5fSchristos	}
27342542f5fSchristos
27442542f5fSchristos	bo = drm_intel_bo_alloc(intel->bufmgr, "front buffer", size, 0);
27542542f5fSchristos	if (bo == NULL)
27642542f5fSchristos		return FALSE;
27742542f5fSchristos
27842542f5fSchristos	if (tiling != I915_TILING_NONE)
27942542f5fSchristos		drm_intel_bo_set_tiling(bo, &tiling, stride);
28042542f5fSchristos
28142542f5fSchristos	xf86DrvMsg(scrn->scrnIndex, X_INFO,
28242542f5fSchristos		   "Allocated new frame buffer %dx%d stride %d, %s\n",
28342542f5fSchristos		   width, height, stride,
28442542f5fSchristos		   tiling == I915_TILING_NONE ? "untiled" : "tiled");
28542542f5fSchristos
28642542f5fSchristos	drm_intel_bo_disable_reuse(bo);
28742542f5fSchristos
28842542f5fSchristos	intel_set_gem_max_sizes(scrn);
28942542f5fSchristos	*out_stride = stride;
29042542f5fSchristos	*out_tiling = tiling;
29142542f5fSchristos	return bo;
29242542f5fSchristos}
29342542f5fSchristos
29403b705cfSriastradhstatic Bool
29503b705cfSriastradhintel_uxa_check_solid(DrawablePtr drawable, int alu, Pixel planemask)
29603b705cfSriastradh{
29703b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(drawable->pScreen);
29803b705cfSriastradh
29903b705cfSriastradh	if (!UXA_PM_IS_SOLID(drawable, planemask)) {
30003b705cfSriastradh		intel_debug_fallback(scrn, "planemask is not solid\n");
30103b705cfSriastradh		return FALSE;
30203b705cfSriastradh	}
30303b705cfSriastradh
30403b705cfSriastradh	switch (drawable->bitsPerPixel) {
30503b705cfSriastradh	case 8:
30603b705cfSriastradh	case 16:
30703b705cfSriastradh	case 32:
30803b705cfSriastradh		break;
30903b705cfSriastradh	default:
31003b705cfSriastradh		return FALSE;
31103b705cfSriastradh	}
31203b705cfSriastradh
31303b705cfSriastradh	return TRUE;
31403b705cfSriastradh}
31503b705cfSriastradh
31603b705cfSriastradh/**
31703b705cfSriastradh * Sets up hardware state for a series of solid fills.
31803b705cfSriastradh */
31903b705cfSriastradhstatic Bool
32003b705cfSriastradhintel_uxa_prepare_solid(PixmapPtr pixmap, int alu, Pixel planemask, Pixel fg)
32103b705cfSriastradh{
32203b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
32303b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
32403b705cfSriastradh	drm_intel_bo *bo_table[] = {
32503b705cfSriastradh		NULL,		/* batch_bo */
32603b705cfSriastradh		intel_get_pixmap_bo(pixmap),
32703b705cfSriastradh	};
32803b705cfSriastradh
32903b705cfSriastradh	if (!intel_check_pitch_2d(pixmap))
33003b705cfSriastradh		return FALSE;
33103b705cfSriastradh
33203b705cfSriastradh	if (!intel_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table)))
33303b705cfSriastradh		return FALSE;
33403b705cfSriastradh
33503b705cfSriastradh	intel->BR[13] = (I830PatternROP[alu] & 0xff) << 16;
33603b705cfSriastradh	switch (pixmap->drawable.bitsPerPixel) {
33703b705cfSriastradh	case 8:
33803b705cfSriastradh		break;
33903b705cfSriastradh	case 16:
34003b705cfSriastradh		/* RGB565 */
34103b705cfSriastradh		intel->BR[13] |= (1 << 24);
34203b705cfSriastradh		break;
34303b705cfSriastradh	case 32:
34403b705cfSriastradh		/* RGB8888 */
34503b705cfSriastradh		intel->BR[13] |= ((1 << 24) | (1 << 25));
34603b705cfSriastradh		break;
34703b705cfSriastradh	}
34803b705cfSriastradh	intel->BR[16] = fg;
34903b705cfSriastradh
35003b705cfSriastradh	return TRUE;
35103b705cfSriastradh}
35203b705cfSriastradh
35303b705cfSriastradhstatic void intel_uxa_solid(PixmapPtr pixmap, int x1, int y1, int x2, int y2)
35403b705cfSriastradh{
35503b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
35603b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
35703b705cfSriastradh	unsigned long pitch;
35803b705cfSriastradh	uint32_t cmd;
35903b705cfSriastradh
36003b705cfSriastradh	if (x1 < 0)
36103b705cfSriastradh		x1 = 0;
36203b705cfSriastradh	if (y1 < 0)
36303b705cfSriastradh		y1 = 0;
36403b705cfSriastradh	if (x2 > pixmap->drawable.width)
36503b705cfSriastradh		x2 = pixmap->drawable.width;
36603b705cfSriastradh	if (y2 > pixmap->drawable.height)
36703b705cfSriastradh		y2 = pixmap->drawable.height;
36803b705cfSriastradh
36903b705cfSriastradh	if (x2 <= x1 || y2 <= y1)
37003b705cfSriastradh		return;
37103b705cfSriastradh
37203b705cfSriastradh	pitch = intel_pixmap_pitch(pixmap);
37303b705cfSriastradh
37403b705cfSriastradh	{
37542542f5fSchristos		int len = INTEL_INFO(intel)->gen >= 0100 ? 7 : 6;
37642542f5fSchristos		BEGIN_BATCH_BLT(len);
37703b705cfSriastradh
37842542f5fSchristos		cmd = XY_COLOR_BLT_CMD | (len - 2);
37903b705cfSriastradh
38003b705cfSriastradh		if (pixmap->drawable.bitsPerPixel == 32)
38103b705cfSriastradh			cmd |=
38203b705cfSriastradh			    XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB;
38303b705cfSriastradh
38403b705cfSriastradh		if (INTEL_INFO(intel)->gen >= 040 && intel_pixmap_tiled(pixmap)) {
38503b705cfSriastradh			assert((pitch % 512) == 0);
38603b705cfSriastradh			pitch >>= 2;
38703b705cfSriastradh			cmd |= XY_COLOR_BLT_TILED;
38803b705cfSriastradh		}
38903b705cfSriastradh
39003b705cfSriastradh		OUT_BATCH(cmd);
39103b705cfSriastradh
39203b705cfSriastradh		OUT_BATCH(intel->BR[13] | pitch);
39303b705cfSriastradh		OUT_BATCH((y1 << 16) | (x1 & 0xffff));
39403b705cfSriastradh		OUT_BATCH((y2 << 16) | (x2 & 0xffff));
39503b705cfSriastradh		OUT_RELOC_PIXMAP_FENCED(pixmap, I915_GEM_DOMAIN_RENDER,
39603b705cfSriastradh					I915_GEM_DOMAIN_RENDER, 0);
39703b705cfSriastradh		OUT_BATCH(intel->BR[16]);
39803b705cfSriastradh		ADVANCE_BATCH();
39903b705cfSriastradh	}
40003b705cfSriastradh}
40103b705cfSriastradh
40203b705cfSriastradh/**
40303b705cfSriastradh * TODO:
40403b705cfSriastradh *   - support planemask using FULL_BLT_CMD?
40503b705cfSriastradh */
40603b705cfSriastradhstatic Bool
40703b705cfSriastradhintel_uxa_check_copy(PixmapPtr source, PixmapPtr dest,
40803b705cfSriastradh		    int alu, Pixel planemask)
40903b705cfSriastradh{
41003b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
41103b705cfSriastradh
41203b705cfSriastradh	if (!UXA_PM_IS_SOLID(&source->drawable, planemask)) {
41303b705cfSriastradh		intel_debug_fallback(scrn, "planemask is not solid");
41403b705cfSriastradh		return FALSE;
41503b705cfSriastradh	}
41603b705cfSriastradh
41703b705cfSriastradh	if (source->drawable.bitsPerPixel != dest->drawable.bitsPerPixel) {
41803b705cfSriastradh		intel_debug_fallback(scrn, "mixed bpp copies unsupported\n");
41903b705cfSriastradh		return FALSE;
42003b705cfSriastradh	}
42103b705cfSriastradh	switch (source->drawable.bitsPerPixel) {
42203b705cfSriastradh	case 8:
42303b705cfSriastradh	case 16:
42403b705cfSriastradh	case 32:
42503b705cfSriastradh		break;
42603b705cfSriastradh	default:
42703b705cfSriastradh		return FALSE;
42803b705cfSriastradh	}
42903b705cfSriastradh
43003b705cfSriastradh	if (!intel_check_pitch_2d(source))
43103b705cfSriastradh		return FALSE;
43203b705cfSriastradh	if (!intel_check_pitch_2d(dest))
43303b705cfSriastradh		return FALSE;
43403b705cfSriastradh
43503b705cfSriastradh	return TRUE;
43603b705cfSriastradh}
43703b705cfSriastradh
43803b705cfSriastradhstatic Bool
43903b705cfSriastradhintel_uxa_prepare_copy(PixmapPtr source, PixmapPtr dest, int xdir,
44003b705cfSriastradh		      int ydir, int alu, Pixel planemask)
44103b705cfSriastradh{
44203b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
44303b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
44403b705cfSriastradh	drm_intel_bo *bo_table[] = {
44503b705cfSriastradh		NULL,		/* batch_bo */
44603b705cfSriastradh		intel_get_pixmap_bo(source),
44703b705cfSriastradh		intel_get_pixmap_bo(dest),
44803b705cfSriastradh	};
44903b705cfSriastradh
45003b705cfSriastradh	if (!intel_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table)))
45103b705cfSriastradh		return FALSE;
45203b705cfSriastradh
45303b705cfSriastradh	intel->render_source = source;
45403b705cfSriastradh
45503b705cfSriastradh	intel->BR[13] = I830CopyROP[alu] << 16;
45603b705cfSriastradh	switch (source->drawable.bitsPerPixel) {
45703b705cfSriastradh	case 8:
45803b705cfSriastradh		break;
45903b705cfSriastradh	case 16:
46003b705cfSriastradh		intel->BR[13] |= (1 << 24);
46103b705cfSriastradh		break;
46203b705cfSriastradh	case 32:
46303b705cfSriastradh		intel->BR[13] |= ((1 << 25) | (1 << 24));
46403b705cfSriastradh		break;
46503b705cfSriastradh	}
46603b705cfSriastradh
46703b705cfSriastradh	return TRUE;
46803b705cfSriastradh}
46903b705cfSriastradh
47003b705cfSriastradhstatic void
47103b705cfSriastradhintel_uxa_copy(PixmapPtr dest, int src_x1, int src_y1, int dst_x1,
47203b705cfSriastradh	      int dst_y1, int w, int h)
47303b705cfSriastradh{
47403b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
47503b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
47603b705cfSriastradh	uint32_t cmd;
47703b705cfSriastradh	int dst_x2, dst_y2, src_x2, src_y2;
47803b705cfSriastradh	unsigned int dst_pitch, src_pitch;
47903b705cfSriastradh
48003b705cfSriastradh	dst_x2 = dst_x1 + w;
48103b705cfSriastradh	dst_y2 = dst_y1 + h;
48203b705cfSriastradh
48303b705cfSriastradh	/* XXX Fixup extents as a lamentable workaround for missing
48403b705cfSriastradh	 * source clipping in the upper layers.
48503b705cfSriastradh	 */
48603b705cfSriastradh	if (dst_x1 < 0)
48703b705cfSriastradh		src_x1 -= dst_x1, dst_x1 = 0;
48803b705cfSriastradh	if (dst_y1 < 0)
48903b705cfSriastradh		src_y1 -= dst_y1, dst_y1 = 0;
49003b705cfSriastradh	if (dst_x2 > dest->drawable.width)
49103b705cfSriastradh		dst_x2 = dest->drawable.width;
49203b705cfSriastradh	if (dst_y2 > dest->drawable.height)
49303b705cfSriastradh		dst_y2 = dest->drawable.height;
49403b705cfSriastradh
49503b705cfSriastradh	src_x2 = src_x1 + (dst_x2 - dst_x1);
49603b705cfSriastradh	src_y2 = src_y1 + (dst_y2 - dst_y1);
49703b705cfSriastradh
49803b705cfSriastradh	if (src_x1 < 0)
49903b705cfSriastradh		dst_x1 -= src_x1, src_x1 = 0;
50003b705cfSriastradh	if (src_y1 < 0)
50103b705cfSriastradh		dst_y1 -= src_y1, src_y1 = 0;
50203b705cfSriastradh	if (src_x2 > intel->render_source->drawable.width)
50303b705cfSriastradh		dst_x2 -= src_x2 - intel->render_source->drawable.width;
50403b705cfSriastradh	if (src_y2 > intel->render_source->drawable.height)
50503b705cfSriastradh		dst_y2 -= src_y2 - intel->render_source->drawable.height;
50603b705cfSriastradh
50703b705cfSriastradh	if (dst_x2 <= dst_x1 || dst_y2 <= dst_y1)
50803b705cfSriastradh		return;
50903b705cfSriastradh
51003b705cfSriastradh	dst_pitch = intel_pixmap_pitch(dest);
51103b705cfSriastradh	src_pitch = intel_pixmap_pitch(intel->render_source);
51203b705cfSriastradh
51303b705cfSriastradh	{
51442542f5fSchristos		int len = INTEL_INFO(intel)->gen >= 0100 ? 10 : 8;
51542542f5fSchristos		BEGIN_BATCH_BLT(len);
51603b705cfSriastradh
51742542f5fSchristos		cmd = XY_SRC_COPY_BLT_CMD | (len - 2);
51803b705cfSriastradh
51903b705cfSriastradh		if (dest->drawable.bitsPerPixel == 32)
52003b705cfSriastradh			cmd |=
52103b705cfSriastradh			    XY_SRC_COPY_BLT_WRITE_ALPHA |
52203b705cfSriastradh			    XY_SRC_COPY_BLT_WRITE_RGB;
52303b705cfSriastradh
52403b705cfSriastradh		if (INTEL_INFO(intel)->gen >= 040) {
52503b705cfSriastradh			if (intel_pixmap_tiled(dest)) {
52603b705cfSriastradh				assert((dst_pitch % 512) == 0);
52703b705cfSriastradh				dst_pitch >>= 2;
52803b705cfSriastradh				cmd |= XY_SRC_COPY_BLT_DST_TILED;
52903b705cfSriastradh			}
53003b705cfSriastradh
53103b705cfSriastradh			if (intel_pixmap_tiled(intel->render_source)) {
53203b705cfSriastradh				assert((src_pitch % 512) == 0);
53303b705cfSriastradh				src_pitch >>= 2;
53403b705cfSriastradh				cmd |= XY_SRC_COPY_BLT_SRC_TILED;
53503b705cfSriastradh			}
53603b705cfSriastradh		}
53703b705cfSriastradh
53803b705cfSriastradh		OUT_BATCH(cmd);
53903b705cfSriastradh
54003b705cfSriastradh		OUT_BATCH(intel->BR[13] | dst_pitch);
54103b705cfSriastradh		OUT_BATCH((dst_y1 << 16) | (dst_x1 & 0xffff));
54203b705cfSriastradh		OUT_BATCH((dst_y2 << 16) | (dst_x2 & 0xffff));
54303b705cfSriastradh		OUT_RELOC_PIXMAP_FENCED(dest,
54403b705cfSriastradh					I915_GEM_DOMAIN_RENDER,
54503b705cfSriastradh					I915_GEM_DOMAIN_RENDER,
54603b705cfSriastradh					0);
54703b705cfSriastradh		OUT_BATCH((src_y1 << 16) | (src_x1 & 0xffff));
54803b705cfSriastradh		OUT_BATCH(src_pitch);
54903b705cfSriastradh		OUT_RELOC_PIXMAP_FENCED(intel->render_source,
55003b705cfSriastradh					I915_GEM_DOMAIN_RENDER, 0,
55103b705cfSriastradh					0);
55203b705cfSriastradh
55303b705cfSriastradh		ADVANCE_BATCH();
55403b705cfSriastradh	}
55503b705cfSriastradh}
55603b705cfSriastradh
55703b705cfSriastradhstatic void intel_uxa_done(PixmapPtr pixmap)
55803b705cfSriastradh{
55903b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
56003b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
56103b705cfSriastradh
56242542f5fSchristos	if (INTEL_INFO(intel)->gen >= 060) {
56303b705cfSriastradh		/* workaround a random BLT hang */
56403b705cfSriastradh		BEGIN_BATCH_BLT(3);
56542542f5fSchristos		OUT_BATCH(XY_SETUP_CLIP_BLT_CMD | (3 - 2));
56603b705cfSriastradh		OUT_BATCH(0);
56703b705cfSriastradh		OUT_BATCH(0);
56803b705cfSriastradh		ADVANCE_BATCH();
56903b705cfSriastradh	}
57003b705cfSriastradh
57103b705cfSriastradh	intel_debug_flush(scrn);
57203b705cfSriastradh}
57303b705cfSriastradh
57403b705cfSriastradh/**
57503b705cfSriastradh * Do any cleanup from the Composite operation.
57603b705cfSriastradh *
57703b705cfSriastradh * This is shared between i830 through i965.
57803b705cfSriastradh */
57903b705cfSriastradhstatic void i830_done_composite(PixmapPtr dest)
58003b705cfSriastradh{
58103b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
58203b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
58303b705cfSriastradh
58403b705cfSriastradh	if (intel->vertex_flush)
58503b705cfSriastradh		intel->vertex_flush(intel);
58603b705cfSriastradh
58703b705cfSriastradh	intel_debug_flush(scrn);
58803b705cfSriastradh}
58903b705cfSriastradh
59003b705cfSriastradh#define xFixedToFloat(val) \
59103b705cfSriastradh	((float)xFixedToInt(val) + ((float)xFixedFrac(val) / 65536.0))
59203b705cfSriastradh
59303b705cfSriastradhstatic Bool
59403b705cfSriastradh_intel_transform_point(PictTransformPtr transform,
59503b705cfSriastradh		       float x, float y, float result[3])
59603b705cfSriastradh{
59703b705cfSriastradh	int j;
59803b705cfSriastradh
59903b705cfSriastradh	for (j = 0; j < 3; j++) {
60003b705cfSriastradh		result[j] = (xFixedToFloat(transform->matrix[j][0]) * x +
60103b705cfSriastradh			     xFixedToFloat(transform->matrix[j][1]) * y +
60203b705cfSriastradh			     xFixedToFloat(transform->matrix[j][2]));
60303b705cfSriastradh	}
60403b705cfSriastradh	if (!result[2])
60503b705cfSriastradh		return FALSE;
60603b705cfSriastradh	return TRUE;
60703b705cfSriastradh}
60803b705cfSriastradh
60903b705cfSriastradh/**
61003b705cfSriastradh * Returns the floating-point coordinates transformed by the given transform.
61103b705cfSriastradh *
61203b705cfSriastradh * transform may be null.
61303b705cfSriastradh */
61403b705cfSriastradhBool
61503b705cfSriastradhintel_get_transformed_coordinates(int x, int y, PictTransformPtr transform,
61603b705cfSriastradh				  float *x_out, float *y_out)
61703b705cfSriastradh{
61803b705cfSriastradh	if (transform == NULL) {
61903b705cfSriastradh		*x_out = x;
62003b705cfSriastradh		*y_out = y;
62103b705cfSriastradh	} else {
62203b705cfSriastradh		float result[3];
62303b705cfSriastradh
62403b705cfSriastradh		if (!_intel_transform_point(transform,
62503b705cfSriastradh					    x, y,
62603b705cfSriastradh					    result))
62703b705cfSriastradh			return FALSE;
62803b705cfSriastradh		*x_out = result[0] / result[2];
62903b705cfSriastradh		*y_out = result[1] / result[2];
63003b705cfSriastradh	}
63103b705cfSriastradh	return TRUE;
63203b705cfSriastradh}
63303b705cfSriastradh
63403b705cfSriastradh/**
63503b705cfSriastradh * Returns the un-normalized floating-point coordinates transformed by the given transform.
63603b705cfSriastradh *
63703b705cfSriastradh * transform may be null.
63803b705cfSriastradh */
63903b705cfSriastradhBool
64003b705cfSriastradhintel_get_transformed_coordinates_3d(int x, int y, PictTransformPtr transform,
64103b705cfSriastradh				     float *x_out, float *y_out, float *w_out)
64203b705cfSriastradh{
64303b705cfSriastradh	if (transform == NULL) {
64403b705cfSriastradh		*x_out = x;
64503b705cfSriastradh		*y_out = y;
64603b705cfSriastradh		*w_out = 1;
64703b705cfSriastradh	} else {
64803b705cfSriastradh		float result[3];
64903b705cfSriastradh
65003b705cfSriastradh		if (!_intel_transform_point(transform,
65103b705cfSriastradh					    x, y,
65203b705cfSriastradh					    result))
65303b705cfSriastradh			return FALSE;
65403b705cfSriastradh		*x_out = result[0];
65503b705cfSriastradh		*y_out = result[1];
65603b705cfSriastradh		*w_out = result[2];
65703b705cfSriastradh	}
65803b705cfSriastradh	return TRUE;
65903b705cfSriastradh}
66003b705cfSriastradh
66103b705cfSriastradh/**
66203b705cfSriastradh * Returns whether the provided transform is affine.
66303b705cfSriastradh *
66403b705cfSriastradh * transform may be null.
66503b705cfSriastradh */
66603b705cfSriastradhBool intel_transform_is_affine(PictTransformPtr t)
66703b705cfSriastradh{
66803b705cfSriastradh	if (t == NULL)
66903b705cfSriastradh		return TRUE;
67003b705cfSriastradh	return t->matrix[2][0] == 0 && t->matrix[2][1] == 0;
67103b705cfSriastradh}
67203b705cfSriastradh
67303b705cfSriastradhdri_bo *intel_get_pixmap_bo(PixmapPtr pixmap)
67403b705cfSriastradh{
67503b705cfSriastradh	struct intel_pixmap *intel;
67603b705cfSriastradh
67703b705cfSriastradh	intel = intel_get_pixmap_private(pixmap);
67803b705cfSriastradh	if (intel == NULL)
67903b705cfSriastradh		return NULL;
68003b705cfSriastradh
68103b705cfSriastradh	return intel->bo;
68203b705cfSriastradh}
68303b705cfSriastradh
68442542f5fSchristosstatic unsigned intel_get_tile_width(intel_screen_private *intel, int tiling, int pitch)
68542542f5fSchristos{
68642542f5fSchristos	unsigned long tile_width;
68742542f5fSchristos
68842542f5fSchristos	if (tiling == I915_TILING_NONE)
68942542f5fSchristos		return 4;
69042542f5fSchristos
69142542f5fSchristos	tile_width = (tiling == I915_TILING_Y) ? 128 : 512;
69242542f5fSchristos	if (INTEL_INFO(intel)->gen >= 040)
69342542f5fSchristos		return tile_width;
69442542f5fSchristos
69542542f5fSchristos	while (tile_width < pitch)
69642542f5fSchristos		tile_width <<= 1;
69742542f5fSchristos
69842542f5fSchristos	return tile_width;
69942542f5fSchristos}
70042542f5fSchristos
70103b705cfSriastradhvoid intel_set_pixmap_bo(PixmapPtr pixmap, dri_bo * bo)
70203b705cfSriastradh{
70342542f5fSchristos	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
70442542f5fSchristos	intel_screen_private *intel = intel_get_screen_private(scrn);
70503b705cfSriastradh	struct intel_pixmap *priv;
70603b705cfSriastradh
70703b705cfSriastradh	priv = intel_get_pixmap_private(pixmap);
70803b705cfSriastradh	if (priv == NULL && bo == NULL)
70942542f5fSchristos		return;
71003b705cfSriastradh
71103b705cfSriastradh	if (priv != NULL) {
71203b705cfSriastradh		if (priv->bo == bo)
71303b705cfSriastradh			return;
71403b705cfSriastradh
71542542f5fSchristosfree_priv:
71603b705cfSriastradh		dri_bo_unreference(priv->bo);
71703b705cfSriastradh		list_del(&priv->batch);
71803b705cfSriastradh
71903b705cfSriastradh		free(priv);
72003b705cfSriastradh		priv = NULL;
72103b705cfSriastradh	}
72203b705cfSriastradh
72303b705cfSriastradh	if (bo != NULL) {
72442542f5fSchristos		uint32_t tiling, swizzle_mode;
72542542f5fSchristos		unsigned tile_width;
72642542f5fSchristos		int size, stride;
72703b705cfSriastradh
72803b705cfSriastradh		priv = calloc(1, sizeof (struct intel_pixmap));
72903b705cfSriastradh		if (priv == NULL)
73003b705cfSriastradh			goto BAIL;
73103b705cfSriastradh
73203b705cfSriastradh		list_init(&priv->batch);
73303b705cfSriastradh
73403b705cfSriastradh		dri_bo_reference(bo);
73503b705cfSriastradh		priv->bo = bo;
73603b705cfSriastradh		priv->stride = intel_pixmap_pitch(pixmap);
73703b705cfSriastradh
73842542f5fSchristos		if (drm_intel_bo_get_tiling(bo, &tiling, &swizzle_mode)) {
73942542f5fSchristos			bo = NULL;
74042542f5fSchristos			goto free_priv;
74103b705cfSriastradh		}
74203b705cfSriastradh
74303b705cfSriastradh		priv->tiling = tiling;
74403b705cfSriastradh		priv->busy = -1;
74503b705cfSriastradh		priv->offscreen = 1;
74642542f5fSchristos
74742542f5fSchristos		stride = (pixmap->drawable.width * pixmap->drawable.bitsPerPixel + 7) / 8;
74842542f5fSchristos		tile_width = intel_get_tile_width(intel, tiling, stride);
74942542f5fSchristos		stride = ALIGN(stride, tile_width);
75042542f5fSchristos
75142542f5fSchristos		if (priv->stride < stride ||
75242542f5fSchristos		    priv->stride & (tile_width - 1) ||
75342542f5fSchristos		    priv->stride >= KB(32)) {
75442542f5fSchristos			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
75542542f5fSchristos				   "%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",
75642542f5fSchristos				   __FUNCTION__, priv->stride, stride, KB(32), tile_width);
75742542f5fSchristos			bo = NULL;
75842542f5fSchristos			goto free_priv;
75942542f5fSchristos		}
76042542f5fSchristos
76142542f5fSchristos		if (tiling != I915_TILING_NONE) {
76242542f5fSchristos			int height;
76342542f5fSchristos
76442542f5fSchristos			if (IS_GEN2(intel))
76542542f5fSchristos				height = 16;
76642542f5fSchristos			else if (tiling == I915_TILING_X)
76742542f5fSchristos				height = 8;
76842542f5fSchristos			else
76942542f5fSchristos				height = 32;
77042542f5fSchristos
77142542f5fSchristos			height = ALIGN(pixmap->drawable.height, 2*height);
77242542f5fSchristos			size = intel_get_fence_size(intel, priv->stride * height);
77342542f5fSchristos		} else
77442542f5fSchristos			size = priv->stride * pixmap->drawable.height;
77542542f5fSchristos
77642542f5fSchristos		if (bo->size < size || bo->size > intel->max_bo_size) {
77742542f5fSchristos			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
77842542f5fSchristos				   "%s: size of buffer object does not match constraints: size=%ld, must be greater than %d, but less than %d\n",
77942542f5fSchristos				   __FUNCTION__, (long)bo->size, size, intel->max_bo_size);
78042542f5fSchristos			bo = NULL;
78142542f5fSchristos			goto free_priv;
78242542f5fSchristos		}
78303b705cfSriastradh	}
78403b705cfSriastradh
78503b705cfSriastradh  BAIL:
78603b705cfSriastradh	intel_set_pixmap_private(pixmap, priv);
78703b705cfSriastradh}
78803b705cfSriastradh
78903b705cfSriastradhstatic Bool intel_uxa_pixmap_is_offscreen(PixmapPtr pixmap)
79003b705cfSriastradh{
79103b705cfSriastradh	return intel_pixmap_is_offscreen(pixmap);
79203b705cfSriastradh}
79303b705cfSriastradh
79403b705cfSriastradhstatic Bool intel_uxa_prepare_access(PixmapPtr pixmap, uxa_access_t access)
79503b705cfSriastradh{
79603b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
79703b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
79803b705cfSriastradh	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
79903b705cfSriastradh	dri_bo *bo = priv->bo;
80003b705cfSriastradh	int ret;
80103b705cfSriastradh
80203b705cfSriastradh	/* Transitioning to glamor acceleration, we need to flush all pending
80303b705cfSriastradh	 * usage by UXA. */
80403b705cfSriastradh	if (access == UXA_GLAMOR_ACCESS_RW || access == UXA_GLAMOR_ACCESS_RO) {
80503b705cfSriastradh		if (!list_is_empty(&priv->batch))
80603b705cfSriastradh			intel_batch_submit(scrn);
80703b705cfSriastradh		return TRUE;
80803b705cfSriastradh	}
80903b705cfSriastradh
81003b705cfSriastradh	/* When falling back to swrast, flush all pending operations */
81103b705cfSriastradh	intel_glamor_flush(intel);
81203b705cfSriastradh	if (access == UXA_ACCESS_RW || priv->dirty)
81303b705cfSriastradh		intel_batch_submit(scrn);
81403b705cfSriastradh
81503b705cfSriastradh	assert(bo->size <= intel->max_gtt_map_size);
81603b705cfSriastradh	ret = drm_intel_gem_bo_map_gtt(bo);
81703b705cfSriastradh	if (ret) {
81803b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
81903b705cfSriastradh			   "%s: bo map (use gtt? %d, access %d) failed: %s\n",
82003b705cfSriastradh			   __FUNCTION__,
82103b705cfSriastradh			   priv->tiling || bo->size <= intel->max_gtt_map_size,
82203b705cfSriastradh			   access,
82303b705cfSriastradh			   strerror(-ret));
82403b705cfSriastradh		return FALSE;
82503b705cfSriastradh	}
82603b705cfSriastradh
82703b705cfSriastradh	pixmap->devPrivate.ptr = bo->virtual;
82803b705cfSriastradh	priv->busy = 0;
82903b705cfSriastradh
83003b705cfSriastradh	return TRUE;
83103b705cfSriastradh}
83203b705cfSriastradh
83303b705cfSriastradhstatic void intel_uxa_finish_access(PixmapPtr pixmap, uxa_access_t access)
83403b705cfSriastradh{
83503b705cfSriastradh	struct intel_pixmap *priv;
83603b705cfSriastradh
83703b705cfSriastradh	if (access == UXA_GLAMOR_ACCESS_RW || access == UXA_GLAMOR_ACCESS_RO)
83803b705cfSriastradh		return;
83903b705cfSriastradh
84003b705cfSriastradh	priv = intel_get_pixmap_private(pixmap);
84103b705cfSriastradh	if (priv == NULL)
84203b705cfSriastradh		return;
84303b705cfSriastradh
84403b705cfSriastradh	drm_intel_gem_bo_unmap_gtt(priv->bo);
84503b705cfSriastradh	pixmap->devPrivate.ptr = NULL;
84603b705cfSriastradh}
84703b705cfSriastradh
84803b705cfSriastradhstatic Bool intel_uxa_pixmap_put_image(PixmapPtr pixmap,
84903b705cfSriastradh				       char *src, int src_pitch,
85003b705cfSriastradh				       int x, int y, int w, int h)
85103b705cfSriastradh{
85203b705cfSriastradh	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
85303b705cfSriastradh	int stride = intel_pixmap_pitch(pixmap);
85403b705cfSriastradh	int cpp = pixmap->drawable.bitsPerPixel/8;
85503b705cfSriastradh	int ret = FALSE;
85603b705cfSriastradh
85703b705cfSriastradh	if (priv == NULL || priv->bo == NULL)
85803b705cfSriastradh		return FALSE;
85903b705cfSriastradh
86003b705cfSriastradh	if (priv->tiling == I915_TILING_NONE &&
86103b705cfSriastradh	    (h == 1 || (src_pitch == stride && w == pixmap->drawable.width))) {
86203b705cfSriastradh		return drm_intel_bo_subdata(priv->bo, y*stride + x*cpp, stride*(h-1) + w*cpp, src) == 0;
86303b705cfSriastradh	} else if (drm_intel_gem_bo_map_gtt(priv->bo) == 0) {
86403b705cfSriastradh		char *dst = priv->bo->virtual;
86503b705cfSriastradh		int row_length = w * cpp;
86603b705cfSriastradh		int num_rows = h;
86703b705cfSriastradh		if (row_length == src_pitch && src_pitch == stride)
86803b705cfSriastradh			num_rows = 1, row_length *= h;
86903b705cfSriastradh		dst += y * stride + x * cpp;
87003b705cfSriastradh		do {
87103b705cfSriastradh			memcpy (dst, src, row_length);
87203b705cfSriastradh			src += src_pitch;
87303b705cfSriastradh			dst += stride;
87403b705cfSriastradh		} while (--num_rows);
87503b705cfSriastradh		drm_intel_gem_bo_unmap_gtt(priv->bo);
87603b705cfSriastradh		ret = TRUE;
87703b705cfSriastradh	}
87803b705cfSriastradh
87903b705cfSriastradh	return ret;
88003b705cfSriastradh}
88103b705cfSriastradh
88203b705cfSriastradhstatic Bool intel_uxa_put_image(PixmapPtr pixmap,
88303b705cfSriastradh				int x, int y,
88403b705cfSriastradh				int w, int h,
88503b705cfSriastradh				char *src, int src_pitch)
88603b705cfSriastradh{
88703b705cfSriastradh	struct intel_pixmap *priv;
88803b705cfSriastradh
88903b705cfSriastradh	priv = intel_get_pixmap_private(pixmap);
89003b705cfSriastradh	if (!intel_pixmap_is_busy(priv)) {
89103b705cfSriastradh		/* bo is not busy so can be replaced without a stall, upload in-place. */
89203b705cfSriastradh		return intel_uxa_pixmap_put_image(pixmap, src, src_pitch, x, y, w, h);
89303b705cfSriastradh	} else {
89403b705cfSriastradh		ScreenPtr screen = pixmap->drawable.pScreen;
89503b705cfSriastradh
89603b705cfSriastradh		if (!priv->pinned &&
89703b705cfSriastradh		    x == 0 && y == 0 &&
89803b705cfSriastradh		    w == pixmap->drawable.width &&
89903b705cfSriastradh		    h == pixmap->drawable.height)
90003b705cfSriastradh		{
90103b705cfSriastradh			intel_screen_private *intel = intel_get_screen_private(xf86ScreenToScrn(screen));
90203b705cfSriastradh			uint32_t tiling = priv->tiling;
90303b705cfSriastradh			int size, stride;
90403b705cfSriastradh			dri_bo *bo;
90503b705cfSriastradh
90603b705cfSriastradh			/* Replace busy bo. */
90742542f5fSchristos			size = intel_uxa_compute_size(intel,
90842542f5fSchristos						      w, h,
90942542f5fSchristos						      pixmap->drawable.bitsPerPixel, pixmap->usage_hint,
91042542f5fSchristos						      &tiling, &stride);
91103b705cfSriastradh			if (size > intel->max_gtt_map_size)
91203b705cfSriastradh				return FALSE;
91303b705cfSriastradh
91403b705cfSriastradh			bo = drm_intel_bo_alloc(intel->bufmgr, "pixmap", size, 0);
91503b705cfSriastradh			if (bo == NULL)
91603b705cfSriastradh				return FALSE;
91703b705cfSriastradh
91803b705cfSriastradh			if (tiling != I915_TILING_NONE)
91903b705cfSriastradh				drm_intel_bo_set_tiling(bo, &tiling, stride);
92003b705cfSriastradh			priv->stride = stride;
92103b705cfSriastradh			priv->tiling = tiling;
92203b705cfSriastradh
92303b705cfSriastradh			screen->ModifyPixmapHeader(pixmap,
92403b705cfSriastradh						   w, h,
92503b705cfSriastradh						   0, 0,
92603b705cfSriastradh						   stride, NULL);
92703b705cfSriastradh			intel_set_pixmap_bo(pixmap, bo);
92803b705cfSriastradh			dri_bo_unreference(bo);
92903b705cfSriastradh
93003b705cfSriastradh			return intel_uxa_pixmap_put_image(pixmap, src, src_pitch, 0, 0, w, h);
93103b705cfSriastradh		}
93203b705cfSriastradh		else
93303b705cfSriastradh		{
93403b705cfSriastradh			PixmapPtr scratch;
93503b705cfSriastradh			Bool ret;
93603b705cfSriastradh
93703b705cfSriastradh			/* Upload to a linear buffer and queue a blit.  */
93803b705cfSriastradh			scratch = (*screen->CreatePixmap)(screen, w, h,
93903b705cfSriastradh							  pixmap->drawable.depth,
94003b705cfSriastradh							  UXA_CREATE_PIXMAP_FOR_MAP);
94103b705cfSriastradh			if (!scratch)
94203b705cfSriastradh				return FALSE;
94303b705cfSriastradh
94403b705cfSriastradh			if (!intel_uxa_pixmap_is_offscreen(scratch)) {
94503b705cfSriastradh				screen->DestroyPixmap(scratch);
94603b705cfSriastradh				return FALSE;
94703b705cfSriastradh			}
94803b705cfSriastradh
94903b705cfSriastradh			ret = intel_uxa_pixmap_put_image(scratch, src, src_pitch, 0, 0, w, h);
95003b705cfSriastradh			if (ret) {
95103b705cfSriastradh				GCPtr gc = GetScratchGC(pixmap->drawable.depth, screen);
95203b705cfSriastradh				if (gc) {
95303b705cfSriastradh					ValidateGC(&pixmap->drawable, gc);
95403b705cfSriastradh
95503b705cfSriastradh					(*gc->ops->CopyArea)(&scratch->drawable,
95603b705cfSriastradh							     &pixmap->drawable,
95703b705cfSriastradh							     gc, 0, 0, w, h, x, y);
95803b705cfSriastradh
95903b705cfSriastradh					FreeScratchGC(gc);
96003b705cfSriastradh				} else
96103b705cfSriastradh					ret = FALSE;
96203b705cfSriastradh			}
96303b705cfSriastradh
96403b705cfSriastradh			(*screen->DestroyPixmap)(scratch);
96503b705cfSriastradh			return ret;
96603b705cfSriastradh		}
96703b705cfSriastradh	}
96803b705cfSriastradh}
96903b705cfSriastradh
97003b705cfSriastradhstatic Bool intel_uxa_pixmap_get_image(PixmapPtr pixmap,
97103b705cfSriastradh				       int x, int y, int w, int h,
97203b705cfSriastradh				       char *dst, int dst_pitch)
97303b705cfSriastradh{
97403b705cfSriastradh	struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
97503b705cfSriastradh	int stride = intel_pixmap_pitch(pixmap);
97603b705cfSriastradh	int cpp = pixmap->drawable.bitsPerPixel/8;
97703b705cfSriastradh
97803b705cfSriastradh	/* assert(priv->tiling == I915_TILING_NONE); */
97903b705cfSriastradh	if (h == 1 || (dst_pitch == stride && w == pixmap->drawable.width)) {
98003b705cfSriastradh		return drm_intel_bo_get_subdata(priv->bo, y*stride + x*cpp, (h-1)*stride + w*cpp, dst) == 0;
98103b705cfSriastradh	} else {
98203b705cfSriastradh		char *src;
98303b705cfSriastradh
98403b705cfSriastradh		if (drm_intel_gem_bo_map_gtt(priv->bo))
98503b705cfSriastradh		    return FALSE;
98603b705cfSriastradh
98703b705cfSriastradh		src = (char *) priv->bo->virtual + y * stride + x * cpp;
98803b705cfSriastradh		w *= cpp;
98903b705cfSriastradh		do {
99003b705cfSriastradh			memcpy(dst, src, w);
99103b705cfSriastradh			src += stride;
99203b705cfSriastradh			dst += dst_pitch;
99303b705cfSriastradh		} while (--h);
99403b705cfSriastradh
99503b705cfSriastradh		drm_intel_gem_bo_unmap_gtt(priv->bo);
99603b705cfSriastradh
99703b705cfSriastradh		return TRUE;
99803b705cfSriastradh	}
99903b705cfSriastradh}
100003b705cfSriastradh
100103b705cfSriastradhstatic Bool intel_uxa_get_image(PixmapPtr pixmap,
100203b705cfSriastradh				int x, int y,
100303b705cfSriastradh				int w, int h,
100403b705cfSriastradh				char *dst, int dst_pitch)
100503b705cfSriastradh{
100603b705cfSriastradh	struct intel_pixmap *priv;
100703b705cfSriastradh	PixmapPtr scratch = NULL;
100803b705cfSriastradh	Bool ret;
100903b705cfSriastradh
101003b705cfSriastradh	/* The presumption is that we wish to keep the target hot, so
101103b705cfSriastradh	 * copy to a new bo and move that to the CPU in preference to
101203b705cfSriastradh	 * causing ping-pong of the original.
101303b705cfSriastradh	 *
101403b705cfSriastradh	 * Also the gpu is much faster at detiling.
101503b705cfSriastradh	 */
101603b705cfSriastradh
101703b705cfSriastradh	priv = intel_get_pixmap_private(pixmap);
101803b705cfSriastradh	if (intel_pixmap_is_busy(priv) || priv->tiling != I915_TILING_NONE) {
101903b705cfSriastradh		ScreenPtr screen = pixmap->drawable.pScreen;
102003b705cfSriastradh		GCPtr gc;
102103b705cfSriastradh
102203b705cfSriastradh		/* Copy to a linear buffer and pull.  */
102303b705cfSriastradh		scratch = screen->CreatePixmap(screen, w, h,
102403b705cfSriastradh					       pixmap->drawable.depth,
102503b705cfSriastradh					       INTEL_CREATE_PIXMAP_TILING_NONE);
102603b705cfSriastradh		if (!scratch)
102703b705cfSriastradh			return FALSE;
102803b705cfSriastradh
102903b705cfSriastradh		if (!intel_uxa_pixmap_is_offscreen(scratch)) {
103003b705cfSriastradh			screen->DestroyPixmap(scratch);
103103b705cfSriastradh			return FALSE;
103203b705cfSriastradh		}
103303b705cfSriastradh
103403b705cfSriastradh		gc = GetScratchGC(pixmap->drawable.depth, screen);
103503b705cfSriastradh		if (!gc) {
103603b705cfSriastradh			screen->DestroyPixmap(scratch);
103703b705cfSriastradh			return FALSE;
103803b705cfSriastradh		}
103903b705cfSriastradh
104003b705cfSriastradh		ValidateGC(&pixmap->drawable, gc);
104103b705cfSriastradh
104203b705cfSriastradh		gc->ops->CopyArea(&pixmap->drawable,
104303b705cfSriastradh				  &scratch->drawable,
104403b705cfSriastradh				  gc, x, y, w, h, 0, 0);
104503b705cfSriastradh
104603b705cfSriastradh		FreeScratchGC(gc);
104703b705cfSriastradh
104803b705cfSriastradh		intel_batch_submit(xf86ScreenToScrn(screen));
104903b705cfSriastradh
105003b705cfSriastradh		x = y = 0;
105103b705cfSriastradh		pixmap = scratch;
105203b705cfSriastradh	}
105303b705cfSriastradh
105403b705cfSriastradh	ret = intel_uxa_pixmap_get_image(pixmap, x, y, w, h, dst, dst_pitch);
105503b705cfSriastradh
105603b705cfSriastradh	if (scratch)
105703b705cfSriastradh		scratch->drawable.pScreen->DestroyPixmap(scratch);
105803b705cfSriastradh
105903b705cfSriastradh	return ret;
106003b705cfSriastradh}
106103b705cfSriastradh
106203b705cfSriastradhstatic CARD32 intel_cache_expire(OsTimerPtr timer, CARD32 now, pointer data)
106303b705cfSriastradh{
106403b705cfSriastradh	intel_screen_private *intel = data;
106503b705cfSriastradh
106603b705cfSriastradh	/* We just want to create and destroy a bo as this causes libdrm
106703b705cfSriastradh	 * to reap its caches. However, since we can't remove that buffer
106803b705cfSriastradh	 * from the cache due to its own activity, we want to use something
106903b705cfSriastradh	 * that we know we will reuse later. The most frequently reused buffer
107003b705cfSriastradh	 * we have is the batchbuffer, and the best way to trigger its
107103b705cfSriastradh	 * reallocation is to submit a flush.
107203b705cfSriastradh	 */
107303b705cfSriastradh	intel_batch_emit_flush(intel->scrn);
107403b705cfSriastradh	intel_batch_submit(intel->scrn);
107503b705cfSriastradh
107603b705cfSriastradh	return 0;
107703b705cfSriastradh}
107803b705cfSriastradh
107903b705cfSriastradhstatic void intel_flush_rendering(intel_screen_private *intel)
108003b705cfSriastradh{
108103b705cfSriastradh	if (intel->needs_flush == 0)
108203b705cfSriastradh		return;
108303b705cfSriastradh
108403b705cfSriastradh	if (intel->has_kernel_flush) {
108503b705cfSriastradh		intel_batch_submit(intel->scrn);
108603b705cfSriastradh		drm_intel_bo_busy(intel->front_buffer);
108703b705cfSriastradh	} else {
108803b705cfSriastradh		intel_batch_emit_flush(intel->scrn);
108903b705cfSriastradh		intel_batch_submit(intel->scrn);
109003b705cfSriastradh	}
109103b705cfSriastradh
109203b705cfSriastradh	intel->cache_expire = TimerSet(intel->cache_expire, 0, 3000,
109303b705cfSriastradh				       intel_cache_expire, intel);
109403b705cfSriastradh
109503b705cfSriastradh	intel->needs_flush = 0;
109603b705cfSriastradh}
109703b705cfSriastradh
109803b705cfSriastradhstatic void intel_throttle(intel_screen_private *intel)
109903b705cfSriastradh{
110003b705cfSriastradh	drmCommandNone(intel->drmSubFD, DRM_I915_GEM_THROTTLE);
110103b705cfSriastradh}
110203b705cfSriastradh
110303b705cfSriastradhvoid intel_uxa_block_handler(intel_screen_private *intel)
110403b705cfSriastradh{
110503b705cfSriastradh	/* Emit a flush of the rendering cache, or on the 965
110603b705cfSriastradh	 * and beyond rendering results may not hit the
110703b705cfSriastradh	 * framebuffer until significantly later.
110803b705cfSriastradh	 */
110903b705cfSriastradh	intel_glamor_flush(intel);
111003b705cfSriastradh	intel_flush_rendering(intel);
111103b705cfSriastradh	intel_throttle(intel);
111203b705cfSriastradh}
111303b705cfSriastradh
111403b705cfSriastradhstatic PixmapPtr
111503b705cfSriastradhintel_uxa_create_pixmap(ScreenPtr screen, int w, int h, int depth,
111603b705cfSriastradh			unsigned usage)
111703b705cfSriastradh{
111803b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
111903b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
112003b705cfSriastradh	struct intel_pixmap *priv;
112103b705cfSriastradh	PixmapPtr pixmap, new_pixmap = NULL;
112203b705cfSriastradh
112303b705cfSriastradh	if (!(usage & INTEL_CREATE_PIXMAP_DRI2)) {
112403b705cfSriastradh		pixmap = intel_glamor_create_pixmap(screen, w, h, depth, usage);
112503b705cfSriastradh		if (pixmap)
112603b705cfSriastradh			return pixmap;
112703b705cfSriastradh	}
112803b705cfSriastradh
112903b705cfSriastradh	if (w > 32767 || h > 32767)
113003b705cfSriastradh		return NullPixmap;
113103b705cfSriastradh
113203b705cfSriastradh	if (depth == 1 || intel->force_fallback)
113303b705cfSriastradh		return fbCreatePixmap(screen, w, h, depth, usage);
113403b705cfSriastradh
113503b705cfSriastradh	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32)
113603b705cfSriastradh		return fbCreatePixmap(screen, w, h, depth, usage);
113703b705cfSriastradh
113803b705cfSriastradh	pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
113903b705cfSriastradh	if (pixmap == NullPixmap)
114003b705cfSriastradh		return pixmap;
114103b705cfSriastradh
114203b705cfSriastradh	if (w && h) {
114303b705cfSriastradh		unsigned int size, tiling;
114403b705cfSriastradh		int stride;
114503b705cfSriastradh
114603b705cfSriastradh		/* Always attempt to tile, compute_size() will remove the
114703b705cfSriastradh		 * tiling for pixmaps that are either too large or too small
114803b705cfSriastradh		 * to be effectively tiled.
114903b705cfSriastradh		 */
115003b705cfSriastradh		tiling = I915_TILING_X;
115103b705cfSriastradh		if (usage & INTEL_CREATE_PIXMAP_TILING_Y)
115203b705cfSriastradh			tiling = I915_TILING_Y;
115303b705cfSriastradh		if (usage == UXA_CREATE_PIXMAP_FOR_MAP || usage & INTEL_CREATE_PIXMAP_TILING_NONE)
115403b705cfSriastradh			tiling = I915_TILING_NONE;
115503b705cfSriastradh
115603b705cfSriastradh#ifdef CREATE_PIXMAP_USAGE_SHARED
115703b705cfSriastradh		if (usage == CREATE_PIXMAP_USAGE_SHARED)
115803b705cfSriastradh			tiling = I915_TILING_NONE;
115903b705cfSriastradh#endif
116003b705cfSriastradh		/* if tiling is off force to none */
116103b705cfSriastradh		if (!intel->tiling)
116203b705cfSriastradh			tiling = I915_TILING_NONE;
116303b705cfSriastradh
116403b705cfSriastradh		if (tiling != I915_TILING_NONE && !(usage & INTEL_CREATE_PIXMAP_DRI2)) {
116503b705cfSriastradh		    if (h <= 4)
116603b705cfSriastradh			tiling = I915_TILING_NONE;
116703b705cfSriastradh		    if (h <= 16 && tiling == I915_TILING_Y)
116803b705cfSriastradh			tiling = I915_TILING_X;
116903b705cfSriastradh		}
117042542f5fSchristos		size = intel_uxa_compute_size(intel,
117142542f5fSchristos					      w, h, pixmap->drawable.bitsPerPixel, usage,
117242542f5fSchristos					      &tiling, &stride);
117303b705cfSriastradh
117403b705cfSriastradh		/* Fail very large allocations.  Large BOs will tend to hit SW fallbacks
117503b705cfSriastradh		 * frequently, and also will tend to fail to successfully map when doing
117603b705cfSriastradh		 * SW fallbacks because we overcommit address space for BO access.
117703b705cfSriastradh		 */
117803b705cfSriastradh		if (size > intel->max_bo_size || stride >= KB(32))
117903b705cfSriastradh			goto fallback_pixmap;
118003b705cfSriastradh
118103b705cfSriastradh		priv = calloc(1, sizeof (struct intel_pixmap));
118203b705cfSriastradh		if (priv == NULL)
118303b705cfSriastradh			goto fallback_pixmap;
118403b705cfSriastradh
118503b705cfSriastradh		if (usage == UXA_CREATE_PIXMAP_FOR_MAP) {
118603b705cfSriastradh			priv->busy = 0;
118703b705cfSriastradh			priv->bo = drm_intel_bo_alloc(intel->bufmgr,
118803b705cfSriastradh						      "pixmap", size, 0);
118903b705cfSriastradh		} else {
119003b705cfSriastradh			priv->busy = -1;
119103b705cfSriastradh			priv->bo = drm_intel_bo_alloc_for_render(intel->bufmgr,
119203b705cfSriastradh								 "pixmap",
119303b705cfSriastradh								 size, 0);
119403b705cfSriastradh		}
119503b705cfSriastradh		if (!priv->bo)
119603b705cfSriastradh			goto fallback_priv;
119703b705cfSriastradh
119803b705cfSriastradh		if (tiling != I915_TILING_NONE)
119903b705cfSriastradh			drm_intel_bo_set_tiling(priv->bo, &tiling, stride);
120003b705cfSriastradh		priv->stride = stride;
120103b705cfSriastradh		priv->tiling = tiling;
120203b705cfSriastradh		priv->offscreen = 1;
120303b705cfSriastradh
120403b705cfSriastradh		list_init(&priv->batch);
120503b705cfSriastradh		intel_set_pixmap_private(pixmap, priv);
120603b705cfSriastradh
120703b705cfSriastradh		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL);
120803b705cfSriastradh
120903b705cfSriastradh		if (!intel_glamor_create_textured_pixmap(pixmap))
121003b705cfSriastradh			goto fallback_glamor;
121103b705cfSriastradh	}
121203b705cfSriastradh
121303b705cfSriastradh	return pixmap;
121403b705cfSriastradh
121503b705cfSriastradhfallback_glamor:
121603b705cfSriastradh	if (usage & INTEL_CREATE_PIXMAP_DRI2) {
121703b705cfSriastradh	/* XXX need further work to handle the DRI2 failure case.
121803b705cfSriastradh	 * Glamor don't know how to handle a BO only pixmap. Put
121903b705cfSriastradh	 * a warning indicator here.
122003b705cfSriastradh	 */
122103b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
122203b705cfSriastradh			   "Failed to create textured DRI2 pixmap.");
122303b705cfSriastradh		return pixmap;
122403b705cfSriastradh	}
122503b705cfSriastradh	/* Create textured pixmap failed means glamor failed to
122603b705cfSriastradh	 * create a texture from current BO for some reasons. We turn
122703b705cfSriastradh	 * to create a new glamor pixmap and clean up current one.
122803b705cfSriastradh	 * One thing need to be noted, this new pixmap doesn't
122903b705cfSriastradh	 * has a priv and bo attached to it. It's glamor's responsbility
123003b705cfSriastradh	 * to take care of it. Glamor will mark this new pixmap as a
123103b705cfSriastradh	 * texture only pixmap and will never fallback to DDX layer
123203b705cfSriastradh	 * afterwards.
123303b705cfSriastradh	 */
123403b705cfSriastradh	new_pixmap = intel_glamor_create_pixmap(screen, w, h,
123503b705cfSriastradh						depth, usage);
123603b705cfSriastradh	dri_bo_unreference(priv->bo);
123703b705cfSriastradhfallback_priv:
123803b705cfSriastradh	free(priv);
123903b705cfSriastradhfallback_pixmap:
124003b705cfSriastradh	fbDestroyPixmap(pixmap);
124103b705cfSriastradh	if (new_pixmap)
124203b705cfSriastradh		return new_pixmap;
124303b705cfSriastradh	else
124403b705cfSriastradh		return fbCreatePixmap(screen, w, h, depth, usage);
124503b705cfSriastradh}
124603b705cfSriastradh
124703b705cfSriastradhstatic Bool intel_uxa_destroy_pixmap(PixmapPtr pixmap)
124803b705cfSriastradh{
124903b705cfSriastradh	if (pixmap->refcnt == 1) {
125003b705cfSriastradh		intel_glamor_destroy_pixmap(pixmap);
125103b705cfSriastradh		intel_set_pixmap_bo(pixmap, NULL);
125203b705cfSriastradh	}
125303b705cfSriastradh	fbDestroyPixmap(pixmap);
125403b705cfSriastradh	return TRUE;
125503b705cfSriastradh}
125603b705cfSriastradh
125703b705cfSriastradhBool intel_uxa_create_screen_resources(ScreenPtr screen)
125803b705cfSriastradh{
125903b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
126003b705cfSriastradh	PixmapPtr pixmap;
126103b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
126203b705cfSriastradh	dri_bo *bo = intel->front_buffer;
126342542f5fSchristos	int old_width, old_height, old_pitch;
126403b705cfSriastradh
126503b705cfSriastradh	if (!uxa_resources_init(screen))
126603b705cfSriastradh		return FALSE;
126703b705cfSriastradh
126803b705cfSriastradh	if (drm_intel_gem_bo_map_gtt(bo))
126903b705cfSriastradh		return FALSE;
127003b705cfSriastradh
127103b705cfSriastradh	pixmap = screen->GetScreenPixmap(screen);
127242542f5fSchristos	old_width = pixmap->drawable.width;
127342542f5fSchristos	old_height = pixmap->drawable.height;
127442542f5fSchristos	old_pitch = pixmap->devKind;
127542542f5fSchristos
127642542f5fSchristos	if (!screen->ModifyPixmapHeader(pixmap,
127742542f5fSchristos					scrn->virtualX,
127842542f5fSchristos					scrn->virtualY,
127942542f5fSchristos					-1, -1,
128042542f5fSchristos					intel->front_pitch,
128142542f5fSchristos					NULL))
128242542f5fSchristos		return FALSE;
128342542f5fSchristos
128403b705cfSriastradh	intel_set_pixmap_bo(pixmap, bo);
128542542f5fSchristos	if (intel_get_pixmap_private(pixmap) == NULL)
128642542f5fSchristos		goto err;
128703b705cfSriastradh
128803b705cfSriastradh	if (!intel_glamor_create_screen_resources(screen))
128942542f5fSchristos		goto err;
129042542f5fSchristos
129142542f5fSchristos	intel_get_pixmap_private(pixmap)->pinned |= PIN_SCANOUT;
129242542f5fSchristos	scrn->displayWidth = intel->front_pitch / intel->cpp;
129303b705cfSriastradh
129403b705cfSriastradh	return TRUE;
129542542f5fSchristos
129642542f5fSchristoserr:
129742542f5fSchristos	screen->ModifyPixmapHeader(pixmap,
129842542f5fSchristos				   old_width, old_height, -1, -1, old_pitch, NULL);
129942542f5fSchristos	return FALSE;
130003b705cfSriastradh}
130103b705cfSriastradh
130203b705cfSriastradh#ifdef CREATE_PIXMAP_USAGE_SHARED
130303b705cfSriastradhstatic Bool
130403b705cfSriastradhintel_uxa_share_pixmap_backing(PixmapPtr ppix, ScreenPtr slave, void **fd_handle)
130503b705cfSriastradh{
130603b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(ppix->drawable.pScreen);
130703b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
130803b705cfSriastradh	struct intel_pixmap *priv = intel_get_pixmap_private(ppix);
130903b705cfSriastradh	unsigned int size, tiling, swizzle;
131003b705cfSriastradh	dri_bo *bo = intel_get_pixmap_bo(ppix), *newbo;
131103b705cfSriastradh	int stride;
131203b705cfSriastradh	int handle;
131303b705cfSriastradh
131403b705cfSriastradh	if (drm_intel_bo_references(intel->batch_bo, bo))
131503b705cfSriastradh		intel_batch_submit(intel->scrn);
131603b705cfSriastradh
131703b705cfSriastradh	drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
131803b705cfSriastradh
131903b705cfSriastradh	if (tiling == I915_TILING_X) {
132042542f5fSchristos		if (priv->pinned)
132103b705cfSriastradh			return FALSE;
132203b705cfSriastradh
132303b705cfSriastradh	        tiling = I915_TILING_NONE;
132403b705cfSriastradh
132542542f5fSchristos		size = intel_uxa_compute_size(intel,
132642542f5fSchristos					      ppix->drawable.width, ppix->drawable.height,
132742542f5fSchristos					      ppix->drawable.bitsPerPixel, INTEL_CREATE_PIXMAP_DRI2,
132842542f5fSchristos					      &tiling, &stride);
132903b705cfSriastradh
133003b705cfSriastradh		newbo = drm_intel_bo_alloc_for_render(intel->bufmgr,
133103b705cfSriastradh						      "pixmap",
133203b705cfSriastradh						      size, 0);
133303b705cfSriastradh
133403b705cfSriastradh		if (tiling != I915_TILING_NONE)
133503b705cfSriastradh			drm_intel_bo_set_tiling(newbo, &tiling, stride);
133603b705cfSriastradh		priv->stride = stride;
133703b705cfSriastradh		priv->tiling = tiling;
133803b705cfSriastradh		intel_set_pixmap_bo(ppix, newbo);
133903b705cfSriastradh
134003b705cfSriastradh		ppix->drawable.pScreen->ModifyPixmapHeader(ppix, ppix->drawable.width,
134103b705cfSriastradh					   ppix->drawable.height, 0, 0,
134203b705cfSriastradh					   stride, NULL);
134303b705cfSriastradh		bo = newbo;
134403b705cfSriastradh	}
134503b705cfSriastradh	drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
134603b705cfSriastradh	drm_intel_bo_gem_export_to_prime(bo, &handle);
134742542f5fSchristos	priv->pinned |= PIN_PRIME;
134803b705cfSriastradh
134903b705cfSriastradh	*fd_handle = (void *)(long)handle;
135003b705cfSriastradh	return TRUE;
135103b705cfSriastradh}
135203b705cfSriastradh
135303b705cfSriastradhstatic Bool
135403b705cfSriastradhintel_uxa_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle)
135503b705cfSriastradh{
135603b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(ppix->drawable.pScreen);
135703b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
135803b705cfSriastradh	dri_bo *bo;
135903b705cfSriastradh	int ihandle = (int)(long)fd_handle;
136003b705cfSriastradh
136103b705cfSriastradh	/* force untiled for now */
136203b705cfSriastradh	bo = drm_intel_bo_gem_create_from_prime(intel->bufmgr, ihandle, 0);
136303b705cfSriastradh	if (!bo)
136403b705cfSriastradh		return FALSE;
136503b705cfSriastradh
136603b705cfSriastradh	intel_set_pixmap_bo(ppix, bo);
136703b705cfSriastradh	close(ihandle);
136803b705cfSriastradh	return TRUE;
136903b705cfSriastradh}
137003b705cfSriastradh#endif
137103b705cfSriastradh
137203b705cfSriastradhstatic void
137303b705cfSriastradhintel_limits_init(intel_screen_private *intel)
137403b705cfSriastradh{
137503b705cfSriastradh	/* Limits are described in the BLT engine chapter under Graphics Data Size
137603b705cfSriastradh	 * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO,
137703b705cfSriastradh	 * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO.
137803b705cfSriastradh	 *
137903b705cfSriastradh	 * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768.
138003b705cfSriastradh	 *
138103b705cfSriastradh	 * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled.
138203b705cfSriastradh	 * i965 limits 3D surface to 4kB-aligned offset if tiled.
138303b705cfSriastradh	 * i965 limits 3D surfaces to w,h of ?,8192.
138403b705cfSriastradh	 * i965 limits 3D surface to pitch of 1B - 128kB.
138503b705cfSriastradh	 * i965 limits 3D surface pitch alignment to 1 or 2 times the element size.
138603b705cfSriastradh	 * i965 limits 3D surface pitch alignment to 512B if tiled.
138703b705cfSriastradh	 * i965 limits 3D destination drawing rect to w,h of 8192,8192.
138803b705cfSriastradh	 *
138903b705cfSriastradh	 * i915 limits 3D textures to 4B-aligned offset if un-tiled.
139003b705cfSriastradh	 * i915 limits 3D textures to ~4kB-aligned offset if tiled.
139103b705cfSriastradh	 * i915 limits 3D textures to width,height of 2048,2048.
139203b705cfSriastradh	 * i915 limits 3D textures to pitch of 16B - 8kB, in dwords.
139303b705cfSriastradh	 * i915 limits 3D destination to ~4kB-aligned offset if tiled.
139403b705cfSriastradh	 * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled.
139503b705cfSriastradh	 * i915 limits 3D destination to pitch 64B-aligned if used with depth.
139603b705cfSriastradh	 * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled.
139703b705cfSriastradh	 * i915 limits 3D destination to POT aligned pitch if tiled.
139803b705cfSriastradh	 * i915 limits 3D destination drawing rect to w,h of 2048,2048.
139903b705cfSriastradh	 *
140003b705cfSriastradh	 * i845 limits 3D textures to 4B-aligned offset if un-tiled.
140103b705cfSriastradh	 * i845 limits 3D textures to ~4kB-aligned offset if tiled.
140203b705cfSriastradh	 * i845 limits 3D textures to width,height of 2048,2048.
140303b705cfSriastradh	 * i845 limits 3D textures to pitch of 4B - 8kB, in dwords.
140403b705cfSriastradh	 * i845 limits 3D destination to 4B-aligned offset if un-tiled.
140503b705cfSriastradh	 * i845 limits 3D destination to ~4kB-aligned offset if tiled.
140603b705cfSriastradh	 * i845 limits 3D destination to pitch of 8B - 8kB, in dwords.
140703b705cfSriastradh	 * i845 limits 3D destination drawing rect to w,h of 2048,2048.
140803b705cfSriastradh	 *
140903b705cfSriastradh	 * For the tiled issues, the only tiled buffer we draw to should be
141003b705cfSriastradh	 * the front, which will have an appropriate pitch/offset already set up,
141103b705cfSriastradh	 * so UXA doesn't need to worry.
141203b705cfSriastradh	 */
141303b705cfSriastradh	if (INTEL_INFO(intel)->gen >= 040) {
141403b705cfSriastradh		intel->accel_pixmap_offset_alignment = 4 * 2;
141503b705cfSriastradh		intel->accel_max_x = 8192;
141603b705cfSriastradh		intel->accel_max_y = 8192;
141703b705cfSriastradh	} else {
141803b705cfSriastradh		intel->accel_pixmap_offset_alignment = 4;
141903b705cfSriastradh		intel->accel_max_x = 2048;
142003b705cfSriastradh		intel->accel_max_y = 2048;
142103b705cfSriastradh	}
142203b705cfSriastradh}
142303b705cfSriastradh
142442542f5fSchristosstatic Bool intel_option_accel_none(intel_screen_private *intel)
142542542f5fSchristos{
142642542f5fSchristos	const char *s;
142742542f5fSchristos
142842542f5fSchristos	s = xf86GetOptValString(intel->Options, OPTION_ACCEL_METHOD);
142942542f5fSchristos	if (s == NULL)
143042542f5fSchristos		return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
143142542f5fSchristos
143242542f5fSchristos	return strcasecmp(s, "none") == 0;
143342542f5fSchristos}
143442542f5fSchristos
143503b705cfSriastradhstatic Bool intel_option_accel_blt(intel_screen_private *intel)
143603b705cfSriastradh{
143703b705cfSriastradh	const char *s;
143803b705cfSriastradh
143903b705cfSriastradh	s = xf86GetOptValString(intel->Options, OPTION_ACCEL_METHOD);
144003b705cfSriastradh	if (s == NULL)
144103b705cfSriastradh		return FALSE;
144203b705cfSriastradh
144303b705cfSriastradh	return strcasecmp(s, "blt") == 0;
144403b705cfSriastradh}
144503b705cfSriastradh
144603b705cfSriastradhBool intel_uxa_init(ScreenPtr screen)
144703b705cfSriastradh{
144803b705cfSriastradh	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
144903b705cfSriastradh	intel_screen_private *intel = intel_get_screen_private(scrn);
145003b705cfSriastradh
145103b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY
145203b705cfSriastradh	if (!dixRegisterPrivateKey(&uxa_pixmap_index, PRIVATE_PIXMAP, 0))
145303b705cfSriastradh#else
145403b705cfSriastradh	if (!dixRequestPrivate(&uxa_pixmap_index, 0))
145503b705cfSriastradh#endif
145603b705cfSriastradh		return FALSE;
145703b705cfSriastradh
145803b705cfSriastradh	intel_limits_init(intel);
145903b705cfSriastradh
146003b705cfSriastradh	intel->uxa_driver = uxa_driver_alloc();
146103b705cfSriastradh	if (intel->uxa_driver == NULL)
146203b705cfSriastradh		return FALSE;
146303b705cfSriastradh
146403b705cfSriastradh	memset(intel->uxa_driver, 0, sizeof(*intel->uxa_driver));
146503b705cfSriastradh
146603b705cfSriastradh	intel->uxa_driver->uxa_major = 1;
146703b705cfSriastradh	intel->uxa_driver->uxa_minor = 0;
146803b705cfSriastradh
146903b705cfSriastradh	intel->prim_offset = 0;
147003b705cfSriastradh	intel->vertex_count = 0;
147103b705cfSriastradh	intel->vertex_offset = 0;
147203b705cfSriastradh	intel->vertex_used = 0;
147303b705cfSriastradh	intel->floats_per_vertex = 0;
147403b705cfSriastradh	intel->last_floats_per_vertex = 0;
147503b705cfSriastradh	intel->vertex_bo = NULL;
147603b705cfSriastradh	intel->surface_used = 0;
147703b705cfSriastradh	intel->surface_reloc = 0;
147803b705cfSriastradh
147903b705cfSriastradh	/* Solid fill */
148003b705cfSriastradh	intel->uxa_driver->check_solid = intel_uxa_check_solid;
148103b705cfSriastradh	intel->uxa_driver->prepare_solid = intel_uxa_prepare_solid;
148203b705cfSriastradh	intel->uxa_driver->solid = intel_uxa_solid;
148303b705cfSriastradh	intel->uxa_driver->done_solid = intel_uxa_done;
148403b705cfSriastradh
148503b705cfSriastradh	/* Copy */
148603b705cfSriastradh	intel->uxa_driver->check_copy = intel_uxa_check_copy;
148703b705cfSriastradh	intel->uxa_driver->prepare_copy = intel_uxa_prepare_copy;
148803b705cfSriastradh	intel->uxa_driver->copy = intel_uxa_copy;
148903b705cfSriastradh	intel->uxa_driver->done_copy = intel_uxa_done;
149003b705cfSriastradh
149103b705cfSriastradh	/* Composite */
149203b705cfSriastradh	if (intel_option_accel_blt(intel)) {
149342542f5fSchristos	} else if (INTEL_INFO(intel)->gen < 030) {
149403b705cfSriastradh		intel->uxa_driver->check_composite = i830_check_composite;
149503b705cfSriastradh		intel->uxa_driver->check_composite_target = i830_check_composite_target;
149603b705cfSriastradh		intel->uxa_driver->check_composite_texture = i830_check_composite_texture;
149703b705cfSriastradh		intel->uxa_driver->prepare_composite = i830_prepare_composite;
149803b705cfSriastradh		intel->uxa_driver->composite = i830_composite;
149903b705cfSriastradh		intel->uxa_driver->done_composite = i830_done_composite;
150003b705cfSriastradh
150103b705cfSriastradh		intel->vertex_flush = i830_vertex_flush;
150203b705cfSriastradh		intel->batch_commit_notify = i830_batch_commit_notify;
150342542f5fSchristos	} else if (INTEL_INFO(intel)->gen < 040) {
150403b705cfSriastradh		intel->uxa_driver->check_composite = i915_check_composite;
150503b705cfSriastradh		intel->uxa_driver->check_composite_target = i915_check_composite_target;
150603b705cfSriastradh		intel->uxa_driver->check_composite_texture = i915_check_composite_texture;
150703b705cfSriastradh		intel->uxa_driver->prepare_composite = i915_prepare_composite;
150803b705cfSriastradh		intel->uxa_driver->composite = i915_composite;
150903b705cfSriastradh		intel->uxa_driver->done_composite = i830_done_composite;
151003b705cfSriastradh
151103b705cfSriastradh		intel->vertex_flush = i915_vertex_flush;
151203b705cfSriastradh		intel->batch_commit_notify = i915_batch_commit_notify;
151342542f5fSchristos	} else if (INTEL_INFO(intel)->gen < 0100) {
151403b705cfSriastradh		intel->uxa_driver->check_composite = i965_check_composite;
151503b705cfSriastradh		intel->uxa_driver->check_composite_texture = i965_check_composite_texture;
151603b705cfSriastradh		intel->uxa_driver->prepare_composite = i965_prepare_composite;
151703b705cfSriastradh		intel->uxa_driver->composite = i965_composite;
151803b705cfSriastradh		intel->uxa_driver->done_composite = i830_done_composite;
151903b705cfSriastradh
152003b705cfSriastradh		intel->vertex_flush = i965_vertex_flush;
152103b705cfSriastradh		intel->batch_flush = i965_batch_flush;
152203b705cfSriastradh		intel->batch_commit_notify = i965_batch_commit_notify;
152303b705cfSriastradh
152442542f5fSchristos		if (INTEL_INFO(intel)->gen < 050) {
152503b705cfSriastradh			intel->context_switch = gen4_context_switch;
152642542f5fSchristos		} else if (INTEL_INFO(intel)->gen < 060) {
152703b705cfSriastradh			intel->context_switch = gen5_context_switch;
152803b705cfSriastradh		} else {
152903b705cfSriastradh			intel->context_switch = gen6_context_switch;
153003b705cfSriastradh		}
153103b705cfSriastradh	}
153203b705cfSriastradh
153303b705cfSriastradh	/* PutImage */
153403b705cfSriastradh	intel->uxa_driver->put_image = intel_uxa_put_image;
153503b705cfSriastradh	intel->uxa_driver->get_image = intel_uxa_get_image;
153603b705cfSriastradh
153703b705cfSriastradh	intel->uxa_driver->prepare_access = intel_uxa_prepare_access;
153803b705cfSriastradh	intel->uxa_driver->finish_access = intel_uxa_finish_access;
153903b705cfSriastradh	intel->uxa_driver->pixmap_is_offscreen = intel_uxa_pixmap_is_offscreen;
154003b705cfSriastradh
154103b705cfSriastradh	screen->CreatePixmap = intel_uxa_create_pixmap;
154203b705cfSriastradh	screen->DestroyPixmap = intel_uxa_destroy_pixmap;
154303b705cfSriastradh
154403b705cfSriastradh#ifdef CREATE_PIXMAP_USAGE_SHARED
154503b705cfSriastradh	screen->SharePixmapBacking = intel_uxa_share_pixmap_backing;
154603b705cfSriastradh	screen->SetSharedPixmapBacking = intel_uxa_set_shared_pixmap_backing;
154703b705cfSriastradh#endif
154803b705cfSriastradh
154903b705cfSriastradh	if (!uxa_driver_init(screen, intel->uxa_driver)) {
155003b705cfSriastradh		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
155103b705cfSriastradh			   "UXA initialization failed\n");
155203b705cfSriastradh		free(intel->uxa_driver);
155303b705cfSriastradh		return FALSE;
155403b705cfSriastradh	}
155503b705cfSriastradh
155642542f5fSchristos	if (intel_option_accel_none(intel))
155742542f5fSchristos		intel->force_fallback = 1;
155842542f5fSchristos
155903b705cfSriastradh	uxa_set_fallback_debug(screen, intel->fallback_debug);
156003b705cfSriastradh	uxa_set_force_fallback(screen, intel->force_fallback);
156103b705cfSriastradh
156242542f5fSchristos	intel->flush_rendering = intel_flush_rendering;
156303b705cfSriastradh	return TRUE;
156403b705cfSriastradh}
1565