1428d7b3dSmrg/**************************************************************************
2428d7b3dSmrg
3428d7b3dSmrgCopyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4428d7b3dSmrgAll Rights Reserved.
5428d7b3dSmrgCopyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org>
6428d7b3dSmrg  Based on code from i830_xaa.c.
7428d7b3dSmrg
8428d7b3dSmrgPermission is hereby granted, free of charge, to any person obtaining a
9428d7b3dSmrgcopy of this software and associated documentation files (the
10428d7b3dSmrg"Software"), to deal in the Software without restriction, including
11428d7b3dSmrgwithout limitation the rights to use, copy, modify, merge, publish,
12428d7b3dSmrgdistribute, sub license, and/or sell copies of the Software, and to
13428d7b3dSmrgpermit persons to whom the Software is furnished to do so, subject to
14428d7b3dSmrgthe following conditions:
15428d7b3dSmrg
16428d7b3dSmrgThe above copyright notice and this permission notice (including the
17428d7b3dSmrgnext paragraph) shall be included in all copies or substantial portions
18428d7b3dSmrgof the Software.
19428d7b3dSmrg
20428d7b3dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21428d7b3dSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22428d7b3dSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23428d7b3dSmrgIN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
24428d7b3dSmrgANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25428d7b3dSmrgTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26428d7b3dSmrgSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27428d7b3dSmrg
28428d7b3dSmrg**************************************************************************/
29428d7b3dSmrg
30428d7b3dSmrg#ifdef HAVE_CONFIG_H
31428d7b3dSmrg#include "config.h"
32428d7b3dSmrg#endif
33428d7b3dSmrg
34428d7b3dSmrg#include "xorg-server.h"
35428d7b3dSmrg#include <xf86.h>
36428d7b3dSmrg#include <xf86drm.h>
37428d7b3dSmrg#include <xaarop.h>
38428d7b3dSmrg#include <string.h>
39428d7b3dSmrg#include <errno.h>
40428d7b3dSmrg#include <unistd.h>
41428d7b3dSmrg
42428d7b3dSmrg#include "intel.h"
43428d7b3dSmrg#include "intel_uxa.h"
44428d7b3dSmrg
45428d7b3dSmrg#include "i830_reg.h"
46428d7b3dSmrg#include "i915_drm.h"
47428d7b3dSmrg#include "brw_defines.h"
48428d7b3dSmrg
49428d7b3dSmrgstatic const int I830CopyROP[16] = {
50428d7b3dSmrg	ROP_0,			/* GXclear */
51428d7b3dSmrg	ROP_DSa,		/* GXand */
52428d7b3dSmrg	ROP_SDna,		/* GXandReverse */
53428d7b3dSmrg	ROP_S,			/* GXcopy */
54428d7b3dSmrg	ROP_DSna,		/* GXandInverted */
55428d7b3dSmrg	ROP_D,			/* GXnoop */
56428d7b3dSmrg	ROP_DSx,		/* GXxor */
57428d7b3dSmrg	ROP_DSo,		/* GXor */
58428d7b3dSmrg	ROP_DSon,		/* GXnor */
59428d7b3dSmrg	ROP_DSxn,		/* GXequiv */
60428d7b3dSmrg	ROP_Dn,			/* GXinvert */
61428d7b3dSmrg	ROP_SDno,		/* GXorReverse */
62428d7b3dSmrg	ROP_Sn,			/* GXcopyInverted */
63428d7b3dSmrg	ROP_DSno,		/* GXorInverted */
64428d7b3dSmrg	ROP_DSan,		/* GXnand */
65428d7b3dSmrg	ROP_1			/* GXset */
66428d7b3dSmrg};
67428d7b3dSmrg
68428d7b3dSmrgstatic const int I830PatternROP[16] = {
69428d7b3dSmrg	ROP_0,
70428d7b3dSmrg	ROP_DPa,
71428d7b3dSmrg	ROP_PDna,
72428d7b3dSmrg	ROP_P,
73428d7b3dSmrg	ROP_DPna,
74428d7b3dSmrg	ROP_D,
75428d7b3dSmrg	ROP_DPx,
76428d7b3dSmrg	ROP_DPo,
77428d7b3dSmrg	ROP_DPon,
78428d7b3dSmrg	ROP_PDxn,
79428d7b3dSmrg	ROP_Dn,
80428d7b3dSmrg	ROP_PDno,
81428d7b3dSmrg	ROP_Pn,
82428d7b3dSmrg	ROP_DPno,
83428d7b3dSmrg	ROP_DPan,
84428d7b3dSmrg	ROP_1
85428d7b3dSmrg};
86428d7b3dSmrg
87428d7b3dSmrg#if HAS_DEVPRIVATEKEYREC
88428d7b3dSmrgDevPrivateKeyRec uxa_pixmap_index;
89428d7b3dSmrg#else
90428d7b3dSmrgint uxa_pixmap_index;
91428d7b3dSmrg#endif
92428d7b3dSmrg
93428d7b3dSmrgstatic void
94428d7b3dSmrggen6_context_switch(intel_screen_private *intel,
95428d7b3dSmrg		    int new_mode)
96428d7b3dSmrg{
97428d7b3dSmrg	intel_batch_submit(intel->scrn);
98428d7b3dSmrg}
99428d7b3dSmrg
100428d7b3dSmrgstatic void
101428d7b3dSmrggen5_context_switch(intel_screen_private *intel,
102428d7b3dSmrg		    int new_mode)
103428d7b3dSmrg{
104428d7b3dSmrg	/* Ironlake has a limitation that a 3D or Media command can't
105428d7b3dSmrg	 * be the first command after a BLT, unless it's
106428d7b3dSmrg	 * non-pipelined.  Instead of trying to track it and emit a
107428d7b3dSmrg	 * command at the right time, we just emit a dummy
108428d7b3dSmrg	 * non-pipelined 3D instruction after each blit.
109428d7b3dSmrg	 */
110428d7b3dSmrg
111428d7b3dSmrg	if (new_mode == I915_EXEC_BLT) {
112428d7b3dSmrg		OUT_BATCH(MI_FLUSH |
113428d7b3dSmrg			  MI_STATE_INSTRUCTION_CACHE_FLUSH |
114428d7b3dSmrg			  MI_INHIBIT_RENDER_CACHE_FLUSH);
115428d7b3dSmrg	} else {
116428d7b3dSmrg		OUT_BATCH(CMD_POLY_STIPPLE_OFFSET << 16);
117428d7b3dSmrg		OUT_BATCH(0);
118428d7b3dSmrg	}
119428d7b3dSmrg}
120428d7b3dSmrg
121428d7b3dSmrgstatic void
122428d7b3dSmrggen4_context_switch(intel_screen_private *intel,
123428d7b3dSmrg		    int new_mode)
124428d7b3dSmrg{
125428d7b3dSmrg	if (new_mode == I915_EXEC_BLT) {
126428d7b3dSmrg		OUT_BATCH(MI_FLUSH |
127428d7b3dSmrg			  MI_STATE_INSTRUCTION_CACHE_FLUSH |
128428d7b3dSmrg			  MI_INHIBIT_RENDER_CACHE_FLUSH);
129428d7b3dSmrg	}
130428d7b3dSmrg}
131428d7b3dSmrg
132428d7b3dSmrgBool
133428d7b3dSmrgintel_uxa_get_aperture_space(ScrnInfoPtr scrn, drm_intel_bo ** bo_table,
134428d7b3dSmrg			 int num_bos)
135428d7b3dSmrg{
136428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
137428d7b3dSmrg
138428d7b3dSmrg	if (intel->batch_bo == NULL) {
139428d7b3dSmrg		intel_uxa_debug_fallback(scrn, "VT inactive\n");
140428d7b3dSmrg		return FALSE;
141428d7b3dSmrg	}
142428d7b3dSmrg
143428d7b3dSmrg	bo_table[0] = intel->batch_bo;
144428d7b3dSmrg	if (drm_intel_bufmgr_check_aperture_space(bo_table, num_bos) != 0) {
145428d7b3dSmrg		intel_batch_submit(scrn);
146428d7b3dSmrg		bo_table[0] = intel->batch_bo;
147428d7b3dSmrg		if (drm_intel_bufmgr_check_aperture_space(bo_table, num_bos) !=
148428d7b3dSmrg		    0) {
149428d7b3dSmrg			intel_uxa_debug_fallback(scrn, "Couldn't get aperture "
150428d7b3dSmrg					    "space for BOs\n");
151428d7b3dSmrg			return FALSE;
152428d7b3dSmrg		}
153428d7b3dSmrg	}
154428d7b3dSmrg	return TRUE;
155428d7b3dSmrg}
156428d7b3dSmrg
157428d7b3dSmrgstatic Bool
158428d7b3dSmrgintel_uxa_check_solid(DrawablePtr drawable, int alu, Pixel planemask)
159428d7b3dSmrg{
160428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(drawable->pScreen);
161428d7b3dSmrg
162428d7b3dSmrg	if (!UXA_PM_IS_SOLID(drawable, planemask)) {
163428d7b3dSmrg		intel_uxa_debug_fallback(scrn, "planemask is not solid\n");
164428d7b3dSmrg		return FALSE;
165428d7b3dSmrg	}
166428d7b3dSmrg
167428d7b3dSmrg	switch (drawable->bitsPerPixel) {
168428d7b3dSmrg	case 8:
169428d7b3dSmrg	case 16:
170428d7b3dSmrg	case 32:
171428d7b3dSmrg		break;
172428d7b3dSmrg	default:
173428d7b3dSmrg		return FALSE;
174428d7b3dSmrg	}
175428d7b3dSmrg
176428d7b3dSmrg	return TRUE;
177428d7b3dSmrg}
178428d7b3dSmrg
179428d7b3dSmrg/**
180428d7b3dSmrg * Sets up hardware state for a series of solid fills.
181428d7b3dSmrg */
182428d7b3dSmrgstatic Bool
183428d7b3dSmrgintel_uxa_prepare_solid(PixmapPtr pixmap, int alu, Pixel planemask, Pixel fg)
184428d7b3dSmrg{
185428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
186428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
187428d7b3dSmrg	drm_intel_bo *bo_table[] = {
188428d7b3dSmrg		NULL,		/* batch_bo */
189428d7b3dSmrg		intel_uxa_get_pixmap_bo(pixmap),
190428d7b3dSmrg	};
191428d7b3dSmrg
192428d7b3dSmrg	if (!intel_uxa_check_pitch_2d(pixmap))
193428d7b3dSmrg		return FALSE;
194428d7b3dSmrg
195428d7b3dSmrg	if (!intel_uxa_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table)))
196428d7b3dSmrg		return FALSE;
197428d7b3dSmrg
198428d7b3dSmrg	intel->BR[13] = (I830PatternROP[alu] & 0xff) << 16;
199428d7b3dSmrg	switch (pixmap->drawable.bitsPerPixel) {
200428d7b3dSmrg	case 8:
201428d7b3dSmrg		break;
202428d7b3dSmrg	case 16:
203428d7b3dSmrg		/* RGB565 */
204428d7b3dSmrg		intel->BR[13] |= (1 << 24);
205428d7b3dSmrg		break;
206428d7b3dSmrg	case 32:
207428d7b3dSmrg		/* RGB8888 */
208428d7b3dSmrg		intel->BR[13] |= ((1 << 24) | (1 << 25));
209428d7b3dSmrg		break;
210428d7b3dSmrg	}
211428d7b3dSmrg	intel->BR[16] = fg;
212428d7b3dSmrg
213428d7b3dSmrg	return TRUE;
214428d7b3dSmrg}
215428d7b3dSmrg
216428d7b3dSmrgstatic void intel_uxa_solid(PixmapPtr pixmap, int x1, int y1, int x2, int y2)
217428d7b3dSmrg{
218428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
219428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
220428d7b3dSmrg	unsigned long pitch;
221428d7b3dSmrg	uint32_t cmd;
222428d7b3dSmrg
223428d7b3dSmrg	if (x1 < 0)
224428d7b3dSmrg		x1 = 0;
225428d7b3dSmrg	if (y1 < 0)
226428d7b3dSmrg		y1 = 0;
227428d7b3dSmrg	if (x2 > pixmap->drawable.width)
228428d7b3dSmrg		x2 = pixmap->drawable.width;
229428d7b3dSmrg	if (y2 > pixmap->drawable.height)
230428d7b3dSmrg		y2 = pixmap->drawable.height;
231428d7b3dSmrg
232428d7b3dSmrg	if (x2 <= x1 || y2 <= y1)
233428d7b3dSmrg		return;
234428d7b3dSmrg
235428d7b3dSmrg	pitch = intel_pixmap_pitch(pixmap);
236428d7b3dSmrg
237428d7b3dSmrg	{
238428d7b3dSmrg		int len = INTEL_INFO(intel)->gen >= 0100 ? 7 : 6;
239428d7b3dSmrg		BEGIN_BATCH_BLT(len);
240428d7b3dSmrg
241428d7b3dSmrg		cmd = XY_COLOR_BLT_CMD | (len - 2);
242428d7b3dSmrg
243428d7b3dSmrg		if (pixmap->drawable.bitsPerPixel == 32)
244428d7b3dSmrg			cmd |=
245428d7b3dSmrg			    XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB;
246428d7b3dSmrg
247428d7b3dSmrg		if (INTEL_INFO(intel)->gen >= 040 && intel_uxa_pixmap_tiled(pixmap)) {
248428d7b3dSmrg			assert((pitch % 512) == 0);
249428d7b3dSmrg			pitch >>= 2;
250428d7b3dSmrg			cmd |= XY_COLOR_BLT_TILED;
251428d7b3dSmrg		}
252428d7b3dSmrg
253428d7b3dSmrg		OUT_BATCH(cmd);
254428d7b3dSmrg
255428d7b3dSmrg		OUT_BATCH(intel->BR[13] | pitch);
256428d7b3dSmrg		OUT_BATCH((y1 << 16) | (x1 & 0xffff));
257428d7b3dSmrg		OUT_BATCH((y2 << 16) | (x2 & 0xffff));
258428d7b3dSmrg		OUT_RELOC_PIXMAP_FENCED(pixmap, I915_GEM_DOMAIN_RENDER,
259428d7b3dSmrg					I915_GEM_DOMAIN_RENDER, 0);
260428d7b3dSmrg		OUT_BATCH(intel->BR[16]);
261428d7b3dSmrg		ADVANCE_BATCH();
262428d7b3dSmrg	}
263428d7b3dSmrg}
264428d7b3dSmrg
265428d7b3dSmrg/**
266428d7b3dSmrg * TODO:
267428d7b3dSmrg *   - support planemask using FULL_BLT_CMD?
268428d7b3dSmrg */
269428d7b3dSmrgstatic Bool
270428d7b3dSmrgintel_uxa_check_copy(PixmapPtr source, PixmapPtr dest,
271428d7b3dSmrg		    int alu, Pixel planemask)
272428d7b3dSmrg{
273428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
274428d7b3dSmrg
275428d7b3dSmrg	if (!UXA_PM_IS_SOLID(&source->drawable, planemask)) {
276428d7b3dSmrg		intel_uxa_debug_fallback(scrn, "planemask is not solid");
277428d7b3dSmrg		return FALSE;
278428d7b3dSmrg	}
279428d7b3dSmrg
280428d7b3dSmrg	if (source->drawable.bitsPerPixel != dest->drawable.bitsPerPixel) {
281428d7b3dSmrg		intel_uxa_debug_fallback(scrn, "mixed bpp copies unsupported\n");
282428d7b3dSmrg		return FALSE;
283428d7b3dSmrg	}
284428d7b3dSmrg	switch (source->drawable.bitsPerPixel) {
285428d7b3dSmrg	case 8:
286428d7b3dSmrg	case 16:
287428d7b3dSmrg	case 32:
288428d7b3dSmrg		break;
289428d7b3dSmrg	default:
290428d7b3dSmrg		return FALSE;
291428d7b3dSmrg	}
292428d7b3dSmrg
293428d7b3dSmrg	if (!intel_uxa_check_pitch_2d(source))
294428d7b3dSmrg		return FALSE;
295428d7b3dSmrg	if (!intel_uxa_check_pitch_2d(dest))
296428d7b3dSmrg		return FALSE;
297428d7b3dSmrg
298428d7b3dSmrg	return TRUE;
299428d7b3dSmrg}
300428d7b3dSmrg
301428d7b3dSmrgstatic Bool
302428d7b3dSmrgintel_uxa_prepare_copy(PixmapPtr source, PixmapPtr dest, int xdir,
303428d7b3dSmrg		      int ydir, int alu, Pixel planemask)
304428d7b3dSmrg{
305428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
306428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
307428d7b3dSmrg	drm_intel_bo *bo_table[] = {
308428d7b3dSmrg		NULL,		/* batch_bo */
309428d7b3dSmrg		intel_uxa_get_pixmap_bo(source),
310428d7b3dSmrg		intel_uxa_get_pixmap_bo(dest),
311428d7b3dSmrg	};
312428d7b3dSmrg
313428d7b3dSmrg	if (!intel_uxa_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table)))
314428d7b3dSmrg		return FALSE;
315428d7b3dSmrg
316428d7b3dSmrg	intel->render_source = source;
317428d7b3dSmrg
318428d7b3dSmrg	intel->BR[13] = I830CopyROP[alu] << 16;
319428d7b3dSmrg	switch (source->drawable.bitsPerPixel) {
320428d7b3dSmrg	case 8:
321428d7b3dSmrg		break;
322428d7b3dSmrg	case 16:
323428d7b3dSmrg		intel->BR[13] |= (1 << 24);
324428d7b3dSmrg		break;
325428d7b3dSmrg	case 32:
326428d7b3dSmrg		intel->BR[13] |= ((1 << 25) | (1 << 24));
327428d7b3dSmrg		break;
328428d7b3dSmrg	}
329428d7b3dSmrg
330428d7b3dSmrg	return TRUE;
331428d7b3dSmrg}
332428d7b3dSmrg
333428d7b3dSmrgstatic void
334428d7b3dSmrgintel_uxa_copy(PixmapPtr dest, int src_x1, int src_y1, int dst_x1,
335428d7b3dSmrg	      int dst_y1, int w, int h)
336428d7b3dSmrg{
337428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
338428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
339428d7b3dSmrg	uint32_t cmd;
340428d7b3dSmrg	int dst_x2, dst_y2, src_x2, src_y2;
341428d7b3dSmrg	unsigned int dst_pitch, src_pitch;
342428d7b3dSmrg
343428d7b3dSmrg	dst_x2 = dst_x1 + w;
344428d7b3dSmrg	dst_y2 = dst_y1 + h;
345428d7b3dSmrg
346428d7b3dSmrg	/* XXX Fixup extents as a lamentable workaround for missing
347428d7b3dSmrg	 * source clipping in the upper layers.
348428d7b3dSmrg	 */
349428d7b3dSmrg	if (dst_x1 < 0)
350428d7b3dSmrg		src_x1 -= dst_x1, dst_x1 = 0;
351428d7b3dSmrg	if (dst_y1 < 0)
352428d7b3dSmrg		src_y1 -= dst_y1, dst_y1 = 0;
353428d7b3dSmrg	if (dst_x2 > dest->drawable.width)
354428d7b3dSmrg		dst_x2 = dest->drawable.width;
355428d7b3dSmrg	if (dst_y2 > dest->drawable.height)
356428d7b3dSmrg		dst_y2 = dest->drawable.height;
357428d7b3dSmrg
358428d7b3dSmrg	src_x2 = src_x1 + (dst_x2 - dst_x1);
359428d7b3dSmrg	src_y2 = src_y1 + (dst_y2 - dst_y1);
360428d7b3dSmrg
361428d7b3dSmrg	if (src_x1 < 0)
362428d7b3dSmrg		dst_x1 -= src_x1, src_x1 = 0;
363428d7b3dSmrg	if (src_y1 < 0)
364428d7b3dSmrg		dst_y1 -= src_y1, src_y1 = 0;
365428d7b3dSmrg	if (src_x2 > intel->render_source->drawable.width)
366428d7b3dSmrg		dst_x2 -= src_x2 - intel->render_source->drawable.width;
367428d7b3dSmrg	if (src_y2 > intel->render_source->drawable.height)
368428d7b3dSmrg		dst_y2 -= src_y2 - intel->render_source->drawable.height;
369428d7b3dSmrg
370428d7b3dSmrg	if (dst_x2 <= dst_x1 || dst_y2 <= dst_y1)
371428d7b3dSmrg		return;
372428d7b3dSmrg
373428d7b3dSmrg	dst_pitch = intel_pixmap_pitch(dest);
374428d7b3dSmrg	src_pitch = intel_pixmap_pitch(intel->render_source);
375428d7b3dSmrg
376428d7b3dSmrg	{
377428d7b3dSmrg		int len = INTEL_INFO(intel)->gen >= 0100 ? 10 : 8;
378428d7b3dSmrg		BEGIN_BATCH_BLT(len);
379428d7b3dSmrg
380428d7b3dSmrg		cmd = XY_SRC_COPY_BLT_CMD | (len - 2);
381428d7b3dSmrg
382428d7b3dSmrg		if (dest->drawable.bitsPerPixel == 32)
383428d7b3dSmrg			cmd |=
384428d7b3dSmrg			    XY_SRC_COPY_BLT_WRITE_ALPHA |
385428d7b3dSmrg			    XY_SRC_COPY_BLT_WRITE_RGB;
386428d7b3dSmrg
387428d7b3dSmrg		if (INTEL_INFO(intel)->gen >= 040) {
388428d7b3dSmrg			if (intel_uxa_pixmap_tiled(dest)) {
389428d7b3dSmrg				assert((dst_pitch % 512) == 0);
390428d7b3dSmrg				dst_pitch >>= 2;
391428d7b3dSmrg				cmd |= XY_SRC_COPY_BLT_DST_TILED;
392428d7b3dSmrg			}
393428d7b3dSmrg
394428d7b3dSmrg			if (intel_uxa_pixmap_tiled(intel->render_source)) {
395428d7b3dSmrg				assert((src_pitch % 512) == 0);
396428d7b3dSmrg				src_pitch >>= 2;
397428d7b3dSmrg				cmd |= XY_SRC_COPY_BLT_SRC_TILED;
398428d7b3dSmrg			}
399428d7b3dSmrg		}
400428d7b3dSmrg
401428d7b3dSmrg		OUT_BATCH(cmd);
402428d7b3dSmrg
403428d7b3dSmrg		OUT_BATCH(intel->BR[13] | dst_pitch);
404428d7b3dSmrg		OUT_BATCH((dst_y1 << 16) | (dst_x1 & 0xffff));
405428d7b3dSmrg		OUT_BATCH((dst_y2 << 16) | (dst_x2 & 0xffff));
406428d7b3dSmrg		OUT_RELOC_PIXMAP_FENCED(dest,
407428d7b3dSmrg					I915_GEM_DOMAIN_RENDER,
408428d7b3dSmrg					I915_GEM_DOMAIN_RENDER,
409428d7b3dSmrg					0);
410428d7b3dSmrg		OUT_BATCH((src_y1 << 16) | (src_x1 & 0xffff));
411428d7b3dSmrg		OUT_BATCH(src_pitch);
412428d7b3dSmrg		OUT_RELOC_PIXMAP_FENCED(intel->render_source,
413428d7b3dSmrg					I915_GEM_DOMAIN_RENDER, 0,
414428d7b3dSmrg					0);
415428d7b3dSmrg
416428d7b3dSmrg		ADVANCE_BATCH();
417428d7b3dSmrg	}
418428d7b3dSmrg}
419428d7b3dSmrg
420428d7b3dSmrgstatic void intel_uxa_done(PixmapPtr pixmap)
421428d7b3dSmrg{
422428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
423428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
424428d7b3dSmrg
425428d7b3dSmrg	if (INTEL_INFO(intel)->gen >= 060) {
426428d7b3dSmrg		/* workaround a random BLT hang */
427428d7b3dSmrg		BEGIN_BATCH_BLT(3);
428428d7b3dSmrg		OUT_BATCH(XY_SETUP_CLIP_BLT_CMD | (3 - 2));
429428d7b3dSmrg		OUT_BATCH(0);
430428d7b3dSmrg		OUT_BATCH(0);
431428d7b3dSmrg		ADVANCE_BATCH();
432428d7b3dSmrg	}
433428d7b3dSmrg
434428d7b3dSmrg	intel_uxa_debug_flush(scrn);
435428d7b3dSmrg}
436428d7b3dSmrg
437428d7b3dSmrg/**
438428d7b3dSmrg * Do any cleanup from the Composite operation.
439428d7b3dSmrg *
440428d7b3dSmrg * This is shared between i830 through i965.
441428d7b3dSmrg */
442428d7b3dSmrgstatic void i830_done_composite(PixmapPtr dest)
443428d7b3dSmrg{
444428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(dest->drawable.pScreen);
445428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
446428d7b3dSmrg
447428d7b3dSmrg	if (intel->vertex_flush)
448428d7b3dSmrg		intel->vertex_flush(intel);
449428d7b3dSmrg
450428d7b3dSmrg	intel_uxa_debug_flush(scrn);
451428d7b3dSmrg}
452428d7b3dSmrg
453428d7b3dSmrg#define xFixedToFloat(val) \
454428d7b3dSmrg	((float)xFixedToInt(val) + ((float)xFixedFrac(val) / 65536.0))
455428d7b3dSmrg
456428d7b3dSmrgstatic Bool
457428d7b3dSmrg_intel_transform_point(PictTransformPtr transform,
458428d7b3dSmrg		       float x, float y, float result[3])
459428d7b3dSmrg{
460428d7b3dSmrg	int j;
461428d7b3dSmrg
462428d7b3dSmrg	for (j = 0; j < 3; j++) {
463428d7b3dSmrg		result[j] = (xFixedToFloat(transform->matrix[j][0]) * x +
464428d7b3dSmrg			     xFixedToFloat(transform->matrix[j][1]) * y +
465428d7b3dSmrg			     xFixedToFloat(transform->matrix[j][2]));
466428d7b3dSmrg	}
467428d7b3dSmrg	if (!result[2])
468428d7b3dSmrg		return FALSE;
469428d7b3dSmrg	return TRUE;
470428d7b3dSmrg}
471428d7b3dSmrg
472428d7b3dSmrg/**
473428d7b3dSmrg * Returns the floating-point coordinates transformed by the given transform.
474428d7b3dSmrg *
475428d7b3dSmrg * transform may be null.
476428d7b3dSmrg */
477428d7b3dSmrgBool
478428d7b3dSmrgintel_uxa_get_transformed_coordinates(int x, int y, PictTransformPtr transform,
479428d7b3dSmrg				  float *x_out, float *y_out)
480428d7b3dSmrg{
481428d7b3dSmrg	if (transform == NULL) {
482428d7b3dSmrg		*x_out = x;
483428d7b3dSmrg		*y_out = y;
484428d7b3dSmrg	} else {
485428d7b3dSmrg		float result[3];
486428d7b3dSmrg
487428d7b3dSmrg		if (!_intel_transform_point(transform,
488428d7b3dSmrg					    x, y,
489428d7b3dSmrg					    result))
490428d7b3dSmrg			return FALSE;
491428d7b3dSmrg		*x_out = result[0] / result[2];
492428d7b3dSmrg		*y_out = result[1] / result[2];
493428d7b3dSmrg	}
494428d7b3dSmrg	return TRUE;
495428d7b3dSmrg}
496428d7b3dSmrg
497428d7b3dSmrg/**
498428d7b3dSmrg * Returns the un-normalized floating-point coordinates transformed by the given transform.
499428d7b3dSmrg *
500428d7b3dSmrg * transform may be null.
501428d7b3dSmrg */
502428d7b3dSmrgBool
503428d7b3dSmrgintel_uxa_get_transformed_coordinates_3d(int x, int y, PictTransformPtr transform,
504428d7b3dSmrg				     float *x_out, float *y_out, float *w_out)
505428d7b3dSmrg{
506428d7b3dSmrg	if (transform == NULL) {
507428d7b3dSmrg		*x_out = x;
508428d7b3dSmrg		*y_out = y;
509428d7b3dSmrg		*w_out = 1;
510428d7b3dSmrg	} else {
511428d7b3dSmrg		float result[3];
512428d7b3dSmrg
513428d7b3dSmrg		if (!_intel_transform_point(transform,
514428d7b3dSmrg					    x, y,
515428d7b3dSmrg					    result))
516428d7b3dSmrg			return FALSE;
517428d7b3dSmrg		*x_out = result[0];
518428d7b3dSmrg		*y_out = result[1];
519428d7b3dSmrg		*w_out = result[2];
520428d7b3dSmrg	}
521428d7b3dSmrg	return TRUE;
522428d7b3dSmrg}
523428d7b3dSmrg
524428d7b3dSmrg/**
525428d7b3dSmrg * Returns whether the provided transform is affine.
526428d7b3dSmrg *
527428d7b3dSmrg * transform may be null.
528428d7b3dSmrg */
529428d7b3dSmrgBool intel_uxa_transform_is_affine(PictTransformPtr t)
530428d7b3dSmrg{
531428d7b3dSmrg	if (t == NULL)
532428d7b3dSmrg		return TRUE;
533428d7b3dSmrg	return t->matrix[2][0] == 0 && t->matrix[2][1] == 0;
534428d7b3dSmrg}
535428d7b3dSmrg
536428d7b3dSmrgdri_bo *intel_uxa_get_pixmap_bo(PixmapPtr pixmap)
537428d7b3dSmrg{
538428d7b3dSmrg	struct intel_uxa_pixmap *intel;
539428d7b3dSmrg
540428d7b3dSmrg	intel = intel_uxa_get_pixmap_private(pixmap);
541428d7b3dSmrg	if (intel == NULL)
542428d7b3dSmrg		return NULL;
543428d7b3dSmrg
544428d7b3dSmrg	return intel->bo;
545428d7b3dSmrg}
546428d7b3dSmrg
547428d7b3dSmrgstatic unsigned intel_get_tile_width(intel_screen_private *intel, int tiling, int pitch)
548428d7b3dSmrg{
549428d7b3dSmrg	unsigned long tile_width;
550428d7b3dSmrg
551428d7b3dSmrg	if (tiling == I915_TILING_NONE)
552428d7b3dSmrg		return 4;
553428d7b3dSmrg
554428d7b3dSmrg	tile_width = (tiling == I915_TILING_Y) ? 128 : 512;
555428d7b3dSmrg	if (INTEL_INFO(intel)->gen >= 040)
556428d7b3dSmrg		return tile_width;
557428d7b3dSmrg
558428d7b3dSmrg	while (tile_width < pitch)
559428d7b3dSmrg		tile_width <<= 1;
560428d7b3dSmrg
561428d7b3dSmrg	return tile_width;
562428d7b3dSmrg}
563428d7b3dSmrg
564428d7b3dSmrgvoid intel_uxa_set_pixmap_bo(PixmapPtr pixmap, dri_bo * bo)
565428d7b3dSmrg{
566428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
567428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
568428d7b3dSmrg	struct intel_uxa_pixmap *priv;
569428d7b3dSmrg
570428d7b3dSmrg	priv = intel_uxa_get_pixmap_private(pixmap);
571428d7b3dSmrg	if (priv == NULL && bo == NULL)
572428d7b3dSmrg		return;
573428d7b3dSmrg
574428d7b3dSmrg	if (priv != NULL) {
575428d7b3dSmrg		if (priv->bo == bo)
576428d7b3dSmrg			return;
577428d7b3dSmrg
578428d7b3dSmrgfree_priv:
579428d7b3dSmrg		dri_bo_unreference(priv->bo);
580428d7b3dSmrg		list_del(&priv->batch);
581428d7b3dSmrg
582428d7b3dSmrg		free(priv);
583428d7b3dSmrg		priv = NULL;
584428d7b3dSmrg	}
585428d7b3dSmrg
586428d7b3dSmrg	if (bo != NULL) {
587428d7b3dSmrg		uint32_t tiling, swizzle_mode;
588428d7b3dSmrg		unsigned tile_width;
589428d7b3dSmrg		int size, stride;
590428d7b3dSmrg
591428d7b3dSmrg		priv = calloc(1, sizeof (struct intel_uxa_pixmap));
592428d7b3dSmrg		if (priv == NULL)
593428d7b3dSmrg			goto BAIL;
594428d7b3dSmrg
595428d7b3dSmrg		list_init(&priv->batch);
596428d7b3dSmrg
597428d7b3dSmrg		dri_bo_reference(bo);
598428d7b3dSmrg		priv->bo = bo;
599428d7b3dSmrg
600428d7b3dSmrg		if (drm_intel_bo_get_tiling(bo, &tiling, &swizzle_mode)) {
601428d7b3dSmrg			bo = NULL;
602428d7b3dSmrg			goto free_priv;
603428d7b3dSmrg		}
604428d7b3dSmrg
605428d7b3dSmrg		priv->tiling = tiling;
606428d7b3dSmrg		priv->busy = -1;
607428d7b3dSmrg		priv->offscreen = 1;
608428d7b3dSmrg
609428d7b3dSmrg		stride = (pixmap->drawable.width * pixmap->drawable.bitsPerPixel + 7) / 8;
610428d7b3dSmrg		tile_width = intel_get_tile_width(intel, tiling, stride);
611428d7b3dSmrg		stride = ALIGN(stride, tile_width);
612428d7b3dSmrg
613428d7b3dSmrg		if (intel_pixmap_pitch(pixmap) < stride ||
614428d7b3dSmrg		    intel_pixmap_pitch(pixmap) & (tile_width - 1) ||
615428d7b3dSmrg		    intel_pixmap_pitch(pixmap) >= KB(32)) {
616428d7b3dSmrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
617428d7b3dSmrg				   "%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",
618428d7b3dSmrg				   __FUNCTION__, intel_pixmap_pitch(pixmap), stride, KB(32), tile_width);
619428d7b3dSmrg			bo = NULL;
620428d7b3dSmrg			goto free_priv;
621428d7b3dSmrg		}
622428d7b3dSmrg
623428d7b3dSmrg		if (tiling != I915_TILING_NONE) {
624428d7b3dSmrg			int height;
625428d7b3dSmrg
626428d7b3dSmrg			if (IS_GEN2(intel))
627428d7b3dSmrg				height = 16;
628428d7b3dSmrg			else if (tiling == I915_TILING_X)
629428d7b3dSmrg				height = 8;
630428d7b3dSmrg			else
631428d7b3dSmrg				height = 32;
632428d7b3dSmrg
633428d7b3dSmrg			height = ALIGN(pixmap->drawable.height, height);
634428d7b3dSmrg			size = intel_get_fence_size(intel, intel_pixmap_pitch(pixmap) * height);
635428d7b3dSmrg		} else
636428d7b3dSmrg			size = intel_pixmap_pitch(pixmap) * pixmap->drawable.height;
637428d7b3dSmrg
638428d7b3dSmrg		if (bo->size < size || bo->size > intel->max_bo_size) {
639428d7b3dSmrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
640428d7b3dSmrg				   "%s: size of buffer object does not match constraints: size=%ld, must be greater than %d, but less than %d\n",
641428d7b3dSmrg				   __FUNCTION__, (long)bo->size, size, intel->max_bo_size);
642428d7b3dSmrg			bo = NULL;
643428d7b3dSmrg			goto free_priv;
644428d7b3dSmrg		}
645428d7b3dSmrg	}
646428d7b3dSmrg
647428d7b3dSmrg  BAIL:
648428d7b3dSmrg	intel_uxa_set_pixmap_private(pixmap, priv);
649428d7b3dSmrg}
650428d7b3dSmrg
651428d7b3dSmrgstatic Bool intel_uxa_prepare_access(PixmapPtr pixmap, uxa_access_t access)
652428d7b3dSmrg{
653428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
654428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
655428d7b3dSmrg	struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap);
656428d7b3dSmrg	dri_bo *bo = priv->bo;
657428d7b3dSmrg	int ret;
658428d7b3dSmrg
659428d7b3dSmrg	/* When falling back to swrast, flush all pending operations */
660428d7b3dSmrg	if (access == UXA_ACCESS_RW || priv->dirty)
661428d7b3dSmrg		intel_batch_submit(scrn);
662428d7b3dSmrg
663428d7b3dSmrg	assert(bo->size <= intel->max_gtt_map_size);
664428d7b3dSmrg	ret = drm_intel_gem_bo_map_gtt(bo);
665428d7b3dSmrg	if (ret) {
666428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
667428d7b3dSmrg			   "%s: bo map (use gtt? %d, access %d) failed: %s\n",
668428d7b3dSmrg			   __FUNCTION__,
669428d7b3dSmrg			   priv->tiling || bo->size <= intel->max_gtt_map_size,
670428d7b3dSmrg			   access,
671428d7b3dSmrg			   strerror(-ret));
672428d7b3dSmrg		return FALSE;
673428d7b3dSmrg	}
674428d7b3dSmrg
675428d7b3dSmrg	pixmap->devPrivate.ptr = bo->virtual;
676428d7b3dSmrg	priv->busy = 0;
677428d7b3dSmrg
678428d7b3dSmrg	return TRUE;
679428d7b3dSmrg}
680428d7b3dSmrg
681428d7b3dSmrgstatic void intel_uxa_finish_access(PixmapPtr pixmap, uxa_access_t access)
682428d7b3dSmrg{
683428d7b3dSmrg	struct intel_uxa_pixmap *priv;
684428d7b3dSmrg
685428d7b3dSmrg	priv = intel_uxa_get_pixmap_private(pixmap);
686428d7b3dSmrg	if (priv == NULL)
687428d7b3dSmrg		return;
688428d7b3dSmrg
689428d7b3dSmrg	drm_intel_gem_bo_unmap_gtt(priv->bo);
690428d7b3dSmrg	pixmap->devPrivate.ptr = NULL;
691428d7b3dSmrg}
692428d7b3dSmrg
693428d7b3dSmrgstatic Bool intel_uxa_pixmap_put_image(PixmapPtr pixmap,
694428d7b3dSmrg				       char *src, int src_pitch,
695428d7b3dSmrg				       int x, int y, int w, int h)
696428d7b3dSmrg{
697428d7b3dSmrg	struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap);
698428d7b3dSmrg	int stride = intel_pixmap_pitch(pixmap);
699428d7b3dSmrg	int cpp = pixmap->drawable.bitsPerPixel/8;
700428d7b3dSmrg	int ret = FALSE;
701428d7b3dSmrg
702428d7b3dSmrg	if (priv == NULL || priv->bo == NULL)
703428d7b3dSmrg		return FALSE;
704428d7b3dSmrg
705428d7b3dSmrg	if (priv->tiling == I915_TILING_NONE &&
706428d7b3dSmrg	    (h == 1 || (src_pitch == stride && w == pixmap->drawable.width))) {
707428d7b3dSmrg		return drm_intel_bo_subdata(priv->bo, y*stride + x*cpp, stride*(h-1) + w*cpp, src) == 0;
708428d7b3dSmrg	} else if (drm_intel_gem_bo_map_gtt(priv->bo) == 0) {
709428d7b3dSmrg		char *dst = priv->bo->virtual;
710428d7b3dSmrg		int row_length = w * cpp;
711428d7b3dSmrg		int num_rows = h;
712428d7b3dSmrg		if (row_length == src_pitch && src_pitch == stride)
713428d7b3dSmrg			num_rows = 1, row_length *= h;
714428d7b3dSmrg		dst += y * stride + x * cpp;
715428d7b3dSmrg		do {
716428d7b3dSmrg			memcpy (dst, src, row_length);
717428d7b3dSmrg			src += src_pitch;
718428d7b3dSmrg			dst += stride;
719428d7b3dSmrg		} while (--num_rows);
720428d7b3dSmrg		drm_intel_gem_bo_unmap_gtt(priv->bo);
721428d7b3dSmrg		ret = TRUE;
722428d7b3dSmrg	}
723428d7b3dSmrg
724428d7b3dSmrg	return ret;
725428d7b3dSmrg}
726428d7b3dSmrg
727428d7b3dSmrgstatic Bool intel_uxa_put_image(PixmapPtr pixmap,
728428d7b3dSmrg				int x, int y,
729428d7b3dSmrg				int w, int h,
730428d7b3dSmrg				char *src, int src_pitch)
731428d7b3dSmrg{
732428d7b3dSmrg	struct intel_uxa_pixmap *priv;
733428d7b3dSmrg
734428d7b3dSmrg	priv = intel_uxa_get_pixmap_private(pixmap);
735428d7b3dSmrg	if (!intel_uxa_pixmap_is_busy(priv)) {
736428d7b3dSmrg		/* bo is not busy so can be replaced without a stall, upload in-place. */
737428d7b3dSmrg		return intel_uxa_pixmap_put_image(pixmap, src, src_pitch, x, y, w, h);
738428d7b3dSmrg	} else {
739428d7b3dSmrg		ScreenPtr screen = pixmap->drawable.pScreen;
740428d7b3dSmrg
741428d7b3dSmrg		if (!priv->pinned &&
742428d7b3dSmrg		    x == 0 && y == 0 &&
743428d7b3dSmrg		    w == pixmap->drawable.width &&
744428d7b3dSmrg		    h == pixmap->drawable.height)
745428d7b3dSmrg		{
746428d7b3dSmrg			intel_screen_private *intel = intel_get_screen_private(xf86ScreenToScrn(screen));
747428d7b3dSmrg			uint32_t tiling = priv->tiling;
748428d7b3dSmrg			int size, stride;
749428d7b3dSmrg			dri_bo *bo;
750428d7b3dSmrg
751428d7b3dSmrg			/* Replace busy bo. */
752428d7b3dSmrg			size = intel_compute_size(intel,
753428d7b3dSmrg                                                  w, h,
754428d7b3dSmrg                                                  pixmap->drawable.bitsPerPixel, pixmap->usage_hint,
755428d7b3dSmrg                                                  &tiling, &stride);
756428d7b3dSmrg			if (size > intel->max_gtt_map_size)
757428d7b3dSmrg				return FALSE;
758428d7b3dSmrg
759428d7b3dSmrg			bo = drm_intel_bo_alloc(intel->bufmgr, "pixmap", size, 0);
760428d7b3dSmrg			if (bo == NULL)
761428d7b3dSmrg				return FALSE;
762428d7b3dSmrg
763428d7b3dSmrg			if (tiling != I915_TILING_NONE)
764428d7b3dSmrg				drm_intel_bo_set_tiling(bo, &tiling, stride);
765428d7b3dSmrg			priv->tiling = tiling;
766428d7b3dSmrg
767428d7b3dSmrg			screen->ModifyPixmapHeader(pixmap,
768428d7b3dSmrg						   w, h,
769428d7b3dSmrg						   0, 0,
770428d7b3dSmrg						   stride, NULL);
771428d7b3dSmrg			intel_uxa_set_pixmap_bo(pixmap, bo);
772428d7b3dSmrg			dri_bo_unreference(bo);
773428d7b3dSmrg
774428d7b3dSmrg			return intel_uxa_pixmap_put_image(pixmap, src, src_pitch, 0, 0, w, h);
775428d7b3dSmrg		}
776428d7b3dSmrg		else
777428d7b3dSmrg		{
778428d7b3dSmrg			PixmapPtr scratch;
779428d7b3dSmrg			Bool ret;
780428d7b3dSmrg
781428d7b3dSmrg			/* Upload to a linear buffer and queue a blit.  */
782428d7b3dSmrg			scratch = (*screen->CreatePixmap)(screen, w, h,
783428d7b3dSmrg							  pixmap->drawable.depth,
784428d7b3dSmrg							  UXA_CREATE_PIXMAP_FOR_MAP);
785428d7b3dSmrg			if (!scratch)
786428d7b3dSmrg				return FALSE;
787428d7b3dSmrg
788428d7b3dSmrg			if (!intel_uxa_pixmap_is_offscreen(scratch)) {
789428d7b3dSmrg				screen->DestroyPixmap(scratch);
790428d7b3dSmrg				return FALSE;
791428d7b3dSmrg			}
792428d7b3dSmrg
793428d7b3dSmrg			ret = intel_uxa_pixmap_put_image(scratch, src, src_pitch, 0, 0, w, h);
794428d7b3dSmrg			if (ret) {
795428d7b3dSmrg				GCPtr gc = GetScratchGC(pixmap->drawable.depth, screen);
796428d7b3dSmrg				if (gc) {
797428d7b3dSmrg					ValidateGC(&pixmap->drawable, gc);
798428d7b3dSmrg
799428d7b3dSmrg					(*gc->ops->CopyArea)(&scratch->drawable,
800428d7b3dSmrg							     &pixmap->drawable,
801428d7b3dSmrg							     gc, 0, 0, w, h, x, y);
802428d7b3dSmrg
803428d7b3dSmrg					FreeScratchGC(gc);
804428d7b3dSmrg				} else
805428d7b3dSmrg					ret = FALSE;
806428d7b3dSmrg			}
807428d7b3dSmrg
808428d7b3dSmrg			(*screen->DestroyPixmap)(scratch);
809428d7b3dSmrg			return ret;
810428d7b3dSmrg		}
811428d7b3dSmrg	}
812428d7b3dSmrg}
813428d7b3dSmrg
814428d7b3dSmrgstatic Bool intel_uxa_pixmap_get_image(PixmapPtr pixmap,
815428d7b3dSmrg				       int x, int y, int w, int h,
816428d7b3dSmrg				       char *dst, int dst_pitch)
817428d7b3dSmrg{
818428d7b3dSmrg	struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap);
819428d7b3dSmrg	int stride = intel_pixmap_pitch(pixmap);
820428d7b3dSmrg	int cpp = pixmap->drawable.bitsPerPixel/8;
821428d7b3dSmrg
822428d7b3dSmrg	/* assert(priv->tiling == I915_TILING_NONE); */
823428d7b3dSmrg	if (h == 1 || (dst_pitch == stride && w == pixmap->drawable.width)) {
824428d7b3dSmrg		return drm_intel_bo_get_subdata(priv->bo, y*stride + x*cpp, (h-1)*stride + w*cpp, dst) == 0;
825428d7b3dSmrg	} else {
826428d7b3dSmrg		char *src;
827428d7b3dSmrg
828428d7b3dSmrg		if (drm_intel_gem_bo_map_gtt(priv->bo))
829428d7b3dSmrg		    return FALSE;
830428d7b3dSmrg
831428d7b3dSmrg		src = (char *) priv->bo->virtual + y * stride + x * cpp;
832428d7b3dSmrg		w *= cpp;
833428d7b3dSmrg		do {
834428d7b3dSmrg			memcpy(dst, src, w);
835428d7b3dSmrg			src += stride;
836428d7b3dSmrg			dst += dst_pitch;
837428d7b3dSmrg		} while (--h);
838428d7b3dSmrg
839428d7b3dSmrg		drm_intel_gem_bo_unmap_gtt(priv->bo);
840428d7b3dSmrg
841428d7b3dSmrg		return TRUE;
842428d7b3dSmrg	}
843428d7b3dSmrg}
844428d7b3dSmrg
845428d7b3dSmrgstatic Bool intel_uxa_get_image(PixmapPtr pixmap,
846428d7b3dSmrg				int x, int y,
847428d7b3dSmrg				int w, int h,
848428d7b3dSmrg				char *dst, int dst_pitch)
849428d7b3dSmrg{
850428d7b3dSmrg	struct intel_uxa_pixmap *priv;
851428d7b3dSmrg	PixmapPtr scratch = NULL;
852428d7b3dSmrg	Bool ret;
853428d7b3dSmrg
854428d7b3dSmrg	/* The presumption is that we wish to keep the target hot, so
855428d7b3dSmrg	 * copy to a new bo and move that to the CPU in preference to
856428d7b3dSmrg	 * causing ping-pong of the original.
857428d7b3dSmrg	 *
858428d7b3dSmrg	 * Also the gpu is much faster at detiling.
859428d7b3dSmrg	 */
860428d7b3dSmrg
861428d7b3dSmrg	priv = intel_uxa_get_pixmap_private(pixmap);
862428d7b3dSmrg	if (intel_uxa_pixmap_is_busy(priv) || priv->tiling != I915_TILING_NONE) {
863428d7b3dSmrg		ScreenPtr screen = pixmap->drawable.pScreen;
864428d7b3dSmrg		GCPtr gc;
865428d7b3dSmrg
866428d7b3dSmrg		/* Copy to a linear buffer and pull.  */
867428d7b3dSmrg		scratch = screen->CreatePixmap(screen, w, h,
868428d7b3dSmrg					       pixmap->drawable.depth,
869428d7b3dSmrg					       INTEL_CREATE_PIXMAP_TILING_NONE);
870428d7b3dSmrg		if (!scratch)
871428d7b3dSmrg			return FALSE;
872428d7b3dSmrg
873428d7b3dSmrg		if (!intel_uxa_pixmap_is_offscreen(scratch)) {
874428d7b3dSmrg			screen->DestroyPixmap(scratch);
875428d7b3dSmrg			return FALSE;
876428d7b3dSmrg		}
877428d7b3dSmrg
878428d7b3dSmrg		gc = GetScratchGC(pixmap->drawable.depth, screen);
879428d7b3dSmrg		if (!gc) {
880428d7b3dSmrg			screen->DestroyPixmap(scratch);
881428d7b3dSmrg			return FALSE;
882428d7b3dSmrg		}
883428d7b3dSmrg
884428d7b3dSmrg		ValidateGC(&pixmap->drawable, gc);
885428d7b3dSmrg
886428d7b3dSmrg		gc->ops->CopyArea(&pixmap->drawable,
887428d7b3dSmrg				  &scratch->drawable,
888428d7b3dSmrg				  gc, x, y, w, h, 0, 0);
889428d7b3dSmrg
890428d7b3dSmrg		FreeScratchGC(gc);
891428d7b3dSmrg
892428d7b3dSmrg		intel_batch_submit(xf86ScreenToScrn(screen));
893428d7b3dSmrg
894428d7b3dSmrg		x = y = 0;
895428d7b3dSmrg		pixmap = scratch;
896428d7b3dSmrg	}
897428d7b3dSmrg
898428d7b3dSmrg	ret = intel_uxa_pixmap_get_image(pixmap, x, y, w, h, dst, dst_pitch);
899428d7b3dSmrg
900428d7b3dSmrg	if (scratch)
901428d7b3dSmrg		scratch->drawable.pScreen->DestroyPixmap(scratch);
902428d7b3dSmrg
903428d7b3dSmrg	return ret;
904428d7b3dSmrg}
905428d7b3dSmrg
906428d7b3dSmrgstatic CARD32 intel_cache_expire(OsTimerPtr timer, CARD32 now, pointer data)
907428d7b3dSmrg{
908428d7b3dSmrg	intel_screen_private *intel = data;
909428d7b3dSmrg
910428d7b3dSmrg	/* We just want to create and destroy a bo as this causes libdrm
911428d7b3dSmrg	 * to reap its caches. However, since we can't remove that buffer
912428d7b3dSmrg	 * from the cache due to its own activity, we want to use something
913428d7b3dSmrg	 * that we know we will reuse later. The most frequently reused buffer
914428d7b3dSmrg	 * we have is the batchbuffer, and the best way to trigger its
915428d7b3dSmrg	 * reallocation is to submit a flush.
916428d7b3dSmrg	 */
917428d7b3dSmrg	intel_batch_emit_flush(intel->scrn);
918428d7b3dSmrg	intel_batch_submit(intel->scrn);
919428d7b3dSmrg
920428d7b3dSmrg	return 0;
921428d7b3dSmrg}
922428d7b3dSmrg
923428d7b3dSmrgstatic void intel_flush_rendering(intel_screen_private *intel)
924428d7b3dSmrg{
925428d7b3dSmrg	if (intel->needs_flush == 0)
926428d7b3dSmrg		return;
927428d7b3dSmrg
928428d7b3dSmrg	if (intel->has_kernel_flush) {
929428d7b3dSmrg		intel_batch_submit(intel->scrn);
930428d7b3dSmrg		drm_intel_bo_busy(intel->front_buffer);
931428d7b3dSmrg	} else {
932428d7b3dSmrg		intel_batch_emit_flush(intel->scrn);
933428d7b3dSmrg		intel_batch_submit(intel->scrn);
934428d7b3dSmrg	}
935428d7b3dSmrg
936428d7b3dSmrg	intel->cache_expire = TimerSet(intel->cache_expire, 0, 3000,
937428d7b3dSmrg				       intel_cache_expire, intel);
938428d7b3dSmrg
939428d7b3dSmrg	intel->needs_flush = 0;
940428d7b3dSmrg}
941428d7b3dSmrg
942428d7b3dSmrgstatic void intel_throttle(intel_screen_private *intel)
943428d7b3dSmrg{
944428d7b3dSmrg	drmCommandNone(intel->drmSubFD, DRM_I915_GEM_THROTTLE);
945428d7b3dSmrg}
946428d7b3dSmrg
947428d7b3dSmrgvoid intel_uxa_block_handler(intel_screen_private *intel)
948428d7b3dSmrg{
949428d7b3dSmrg	/* Emit a flush of the rendering cache, or on the 965
950428d7b3dSmrg	 * and beyond rendering results may not hit the
951428d7b3dSmrg	 * framebuffer until significantly later.
952428d7b3dSmrg	 */
953428d7b3dSmrg	intel_flush_rendering(intel);
954428d7b3dSmrg	intel_throttle(intel);
955428d7b3dSmrg}
956428d7b3dSmrg
957428d7b3dSmrgstatic PixmapPtr
958428d7b3dSmrgintel_uxa_create_pixmap(ScreenPtr screen, int w, int h, int depth,
959428d7b3dSmrg			unsigned usage)
960428d7b3dSmrg{
961428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
962428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
963428d7b3dSmrg	struct intel_uxa_pixmap *priv;
964428d7b3dSmrg	PixmapPtr pixmap, new_pixmap = NULL;
965428d7b3dSmrg
966428d7b3dSmrg	if (w > 32767 || h > 32767)
967428d7b3dSmrg		return NullPixmap;
968428d7b3dSmrg
969428d7b3dSmrg	if (depth == 1 || intel->force_fallback)
970428d7b3dSmrg		return fbCreatePixmap(screen, w, h, depth, usage);
971428d7b3dSmrg
972428d7b3dSmrg	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32)
973428d7b3dSmrg		return fbCreatePixmap(screen, w, h, depth, usage);
974428d7b3dSmrg
975428d7b3dSmrg	pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
976428d7b3dSmrg	if (pixmap == NullPixmap)
977428d7b3dSmrg		return pixmap;
978428d7b3dSmrg
979428d7b3dSmrg	if (w && h) {
980428d7b3dSmrg		unsigned int size, tiling;
981428d7b3dSmrg		int stride;
982428d7b3dSmrg
983428d7b3dSmrg		/* Always attempt to tile, compute_size() will remove the
984428d7b3dSmrg		 * tiling for pixmaps that are either too large or too small
985428d7b3dSmrg		 * to be effectively tiled.
986428d7b3dSmrg		 */
987428d7b3dSmrg		tiling = I915_TILING_X;
988428d7b3dSmrg		if (usage & INTEL_CREATE_PIXMAP_TILING_Y)
989428d7b3dSmrg			tiling = I915_TILING_Y;
990428d7b3dSmrg		if (usage == UXA_CREATE_PIXMAP_FOR_MAP || usage & INTEL_CREATE_PIXMAP_TILING_NONE)
991428d7b3dSmrg			tiling = I915_TILING_NONE;
992428d7b3dSmrg
993428d7b3dSmrg#ifdef CREATE_PIXMAP_USAGE_SHARED
994428d7b3dSmrg		if (usage == CREATE_PIXMAP_USAGE_SHARED)
995428d7b3dSmrg			tiling = I915_TILING_NONE;
996428d7b3dSmrg#endif
997428d7b3dSmrg		/* if tiling is off force to none */
998428d7b3dSmrg		if (!intel->tiling)
999428d7b3dSmrg			tiling = I915_TILING_NONE;
1000428d7b3dSmrg
1001428d7b3dSmrg		if (tiling != I915_TILING_NONE && !(usage & INTEL_CREATE_PIXMAP_DRI2)) {
1002428d7b3dSmrg		    if (h <= 4)
1003428d7b3dSmrg			tiling = I915_TILING_NONE;
1004428d7b3dSmrg		    if (h <= 16 && tiling == I915_TILING_Y)
1005428d7b3dSmrg			tiling = I915_TILING_X;
1006428d7b3dSmrg		}
1007428d7b3dSmrg		size = intel_compute_size(intel,
1008428d7b3dSmrg                                          w, h, pixmap->drawable.bitsPerPixel, usage,
1009428d7b3dSmrg                                          &tiling, &stride);
1010428d7b3dSmrg
1011428d7b3dSmrg		/* Fail very large allocations.  Large BOs will tend to hit SW fallbacks
1012428d7b3dSmrg		 * frequently, and also will tend to fail to successfully map when doing
1013428d7b3dSmrg		 * SW fallbacks because we overcommit address space for BO access.
1014428d7b3dSmrg		 */
1015428d7b3dSmrg		if (size > intel->max_bo_size || stride >= KB(32))
1016428d7b3dSmrg			goto fallback_pixmap;
1017428d7b3dSmrg
1018428d7b3dSmrg		priv = calloc(1, sizeof (struct intel_uxa_pixmap));
1019428d7b3dSmrg		if (priv == NULL)
1020428d7b3dSmrg			goto fallback_pixmap;
1021428d7b3dSmrg
1022428d7b3dSmrg		if (usage == UXA_CREATE_PIXMAP_FOR_MAP) {
1023428d7b3dSmrg			priv->busy = 0;
1024428d7b3dSmrg			priv->bo = drm_intel_bo_alloc(intel->bufmgr,
1025428d7b3dSmrg						      "pixmap", size, 0);
1026428d7b3dSmrg		} else {
1027428d7b3dSmrg			priv->busy = -1;
1028428d7b3dSmrg			priv->bo = drm_intel_bo_alloc_for_render(intel->bufmgr,
1029428d7b3dSmrg								 "pixmap",
1030428d7b3dSmrg								 size, 0);
1031428d7b3dSmrg		}
1032428d7b3dSmrg		if (!priv->bo)
1033428d7b3dSmrg			goto fallback_priv;
1034428d7b3dSmrg
1035428d7b3dSmrg		if (tiling != I915_TILING_NONE)
1036428d7b3dSmrg			drm_intel_bo_set_tiling(priv->bo, &tiling, stride);
1037428d7b3dSmrg		priv->tiling = tiling;
1038428d7b3dSmrg		priv->offscreen = 1;
1039428d7b3dSmrg
1040428d7b3dSmrg		list_init(&priv->batch);
1041428d7b3dSmrg		intel_uxa_set_pixmap_private(pixmap, priv);
1042428d7b3dSmrg
1043428d7b3dSmrg		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL);
1044428d7b3dSmrg	}
1045428d7b3dSmrg
1046428d7b3dSmrg	return pixmap;
1047428d7b3dSmrg
1048428d7b3dSmrgfallback_priv:
1049428d7b3dSmrg	free(priv);
1050428d7b3dSmrgfallback_pixmap:
1051428d7b3dSmrg	fbDestroyPixmap(pixmap);
1052428d7b3dSmrg	if (new_pixmap)
1053428d7b3dSmrg		return new_pixmap;
1054428d7b3dSmrg	else
1055428d7b3dSmrg		return fbCreatePixmap(screen, w, h, depth, usage);
1056428d7b3dSmrg}
1057428d7b3dSmrg
1058428d7b3dSmrgstatic Bool intel_uxa_destroy_pixmap(PixmapPtr pixmap)
1059428d7b3dSmrg{
1060428d7b3dSmrg	if (pixmap->refcnt == 1)
1061428d7b3dSmrg		intel_uxa_set_pixmap_bo(pixmap, NULL);
1062428d7b3dSmrg	fbDestroyPixmap(pixmap);
1063428d7b3dSmrg	return TRUE;
1064428d7b3dSmrg}
1065428d7b3dSmrg
1066428d7b3dSmrgBool intel_uxa_create_screen_resources(ScreenPtr screen)
1067428d7b3dSmrg{
1068428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1069428d7b3dSmrg	PixmapPtr pixmap;
1070428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
1071428d7b3dSmrg	dri_bo *bo = intel->front_buffer;
1072428d7b3dSmrg	int old_width, old_height, old_pitch;
1073428d7b3dSmrg
1074428d7b3dSmrg	if (!uxa_resources_init(screen))
1075428d7b3dSmrg		return FALSE;
1076428d7b3dSmrg
1077428d7b3dSmrg	if (drm_intel_gem_bo_map_gtt(bo))
1078428d7b3dSmrg		return FALSE;
1079428d7b3dSmrg
1080428d7b3dSmrg	pixmap = screen->GetScreenPixmap(screen);
1081428d7b3dSmrg	old_width = pixmap->drawable.width;
1082428d7b3dSmrg	old_height = pixmap->drawable.height;
1083428d7b3dSmrg	old_pitch = pixmap->devKind;
1084428d7b3dSmrg
1085428d7b3dSmrg	if (!screen->ModifyPixmapHeader(pixmap,
1086428d7b3dSmrg					scrn->virtualX,
1087428d7b3dSmrg					scrn->virtualY,
1088428d7b3dSmrg					-1, -1,
1089428d7b3dSmrg					intel->front_pitch,
1090428d7b3dSmrg					NULL))
1091428d7b3dSmrg		return FALSE;
1092428d7b3dSmrg
1093428d7b3dSmrg	intel_uxa_set_pixmap_bo(pixmap, bo);
1094428d7b3dSmrg	if (intel_uxa_get_pixmap_private(pixmap) == NULL)
1095428d7b3dSmrg		goto err;
1096428d7b3dSmrg
1097428d7b3dSmrg	intel_uxa_get_pixmap_private(pixmap)->pinned |= PIN_SCANOUT;
1098428d7b3dSmrg	scrn->displayWidth = intel->front_pitch / intel->cpp;
1099428d7b3dSmrg
1100428d7b3dSmrg	return TRUE;
1101428d7b3dSmrg
1102428d7b3dSmrgerr:
1103428d7b3dSmrg	screen->ModifyPixmapHeader(pixmap,
1104428d7b3dSmrg				   old_width, old_height, -1, -1, old_pitch, NULL);
1105428d7b3dSmrg	return FALSE;
1106428d7b3dSmrg}
1107428d7b3dSmrg
1108428d7b3dSmrg#ifdef CREATE_PIXMAP_USAGE_SHARED
1109428d7b3dSmrgstatic Bool
1110428d7b3dSmrgintel_uxa_share_pixmap_backing(PixmapPtr ppix, ScreenPtr slave, void **fd_handle)
1111428d7b3dSmrg{
1112428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(ppix->drawable.pScreen);
1113428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
1114428d7b3dSmrg	struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(ppix);
1115428d7b3dSmrg	unsigned int size, tiling, swizzle;
1116428d7b3dSmrg	dri_bo *bo = intel_uxa_get_pixmap_bo(ppix), *newbo;
1117428d7b3dSmrg	int stride;
1118428d7b3dSmrg	int handle;
1119428d7b3dSmrg
1120428d7b3dSmrg	if (drm_intel_bo_references(intel->batch_bo, bo))
1121428d7b3dSmrg		intel_batch_submit(intel->scrn);
1122428d7b3dSmrg
1123428d7b3dSmrg	drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
1124428d7b3dSmrg
1125428d7b3dSmrg	if (tiling == I915_TILING_X) {
1126428d7b3dSmrg		if (priv->pinned)
1127428d7b3dSmrg			return FALSE;
1128428d7b3dSmrg
1129428d7b3dSmrg	        tiling = I915_TILING_NONE;
1130428d7b3dSmrg
1131428d7b3dSmrg		size = intel_compute_size(intel,
1132428d7b3dSmrg                                          ppix->drawable.width, ppix->drawable.height,
1133428d7b3dSmrg                                          ppix->drawable.bitsPerPixel, INTEL_CREATE_PIXMAP_DRI2,
1134428d7b3dSmrg                                          &tiling, &stride);
1135428d7b3dSmrg
1136428d7b3dSmrg		newbo = drm_intel_bo_alloc_for_render(intel->bufmgr,
1137428d7b3dSmrg						      "pixmap",
1138428d7b3dSmrg						      size, 0);
1139428d7b3dSmrg
1140428d7b3dSmrg		if (tiling != I915_TILING_NONE)
1141428d7b3dSmrg			drm_intel_bo_set_tiling(newbo, &tiling, stride);
1142428d7b3dSmrg		priv->tiling = tiling;
1143428d7b3dSmrg		intel_uxa_set_pixmap_bo(ppix, newbo);
1144428d7b3dSmrg
1145428d7b3dSmrg		ppix->drawable.pScreen->ModifyPixmapHeader(ppix, ppix->drawable.width,
1146428d7b3dSmrg					   ppix->drawable.height, 0, 0,
1147428d7b3dSmrg					   stride, NULL);
1148428d7b3dSmrg		bo = newbo;
1149428d7b3dSmrg	}
1150428d7b3dSmrg	drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
1151428d7b3dSmrg	drm_intel_bo_gem_export_to_prime(bo, &handle);
1152428d7b3dSmrg	priv->pinned |= PIN_PRIME;
1153428d7b3dSmrg
1154428d7b3dSmrg	*fd_handle = (void *)(long)handle;
1155428d7b3dSmrg	return TRUE;
1156428d7b3dSmrg}
1157428d7b3dSmrg
1158428d7b3dSmrgstatic Bool
1159428d7b3dSmrgintel_uxa_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle)
1160428d7b3dSmrg{
1161428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(ppix->drawable.pScreen);
1162428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
1163428d7b3dSmrg	dri_bo *bo;
1164428d7b3dSmrg	int ihandle = (int)(long)fd_handle;
1165428d7b3dSmrg
1166428d7b3dSmrg	/* force untiled for now */
1167428d7b3dSmrg	bo = drm_intel_bo_gem_create_from_prime(intel->bufmgr, ihandle, 0);
1168428d7b3dSmrg	if (!bo)
1169428d7b3dSmrg		return FALSE;
1170428d7b3dSmrg
1171428d7b3dSmrg	intel_uxa_set_pixmap_bo(ppix, bo);
1172428d7b3dSmrg	close(ihandle);
1173428d7b3dSmrg	return TRUE;
1174428d7b3dSmrg}
1175428d7b3dSmrg#endif
1176428d7b3dSmrg
1177428d7b3dSmrgstatic void
1178428d7b3dSmrgintel_limits_init(intel_screen_private *intel)
1179428d7b3dSmrg{
1180428d7b3dSmrg	/* Limits are described in the BLT engine chapter under Graphics Data Size
1181428d7b3dSmrg	 * Limitations, and the descriptions of SURFACE_STATE, 3DSTATE_BUFFER_INFO,
1182428d7b3dSmrg	 * 3DSTATE_DRAWING_RECTANGLE, 3DSTATE_MAP_INFO, and 3DSTATE_MAP_INFO.
1183428d7b3dSmrg	 *
1184428d7b3dSmrg	 * i845 through i965 limits 2D rendering to 65536 lines and pitch of 32768.
1185428d7b3dSmrg	 *
1186428d7b3dSmrg	 * i965 limits 3D surface to (2*element size)-aligned offset if un-tiled.
1187428d7b3dSmrg	 * i965 limits 3D surface to 4kB-aligned offset if tiled.
1188428d7b3dSmrg	 * i965 limits 3D surfaces to w,h of ?,8192.
1189428d7b3dSmrg	 * i965 limits 3D surface to pitch of 1B - 128kB.
1190428d7b3dSmrg	 * i965 limits 3D surface pitch alignment to 1 or 2 times the element size.
1191428d7b3dSmrg	 * i965 limits 3D surface pitch alignment to 512B if tiled.
1192428d7b3dSmrg	 * i965 limits 3D destination drawing rect to w,h of 8192,8192.
1193428d7b3dSmrg	 *
1194428d7b3dSmrg	 * i915 limits 3D textures to 4B-aligned offset if un-tiled.
1195428d7b3dSmrg	 * i915 limits 3D textures to ~4kB-aligned offset if tiled.
1196428d7b3dSmrg	 * i915 limits 3D textures to width,height of 2048,2048.
1197428d7b3dSmrg	 * i915 limits 3D textures to pitch of 16B - 8kB, in dwords.
1198428d7b3dSmrg	 * i915 limits 3D destination to ~4kB-aligned offset if tiled.
1199428d7b3dSmrg	 * i915 limits 3D destination to pitch of 16B - 8kB, in dwords, if un-tiled.
1200428d7b3dSmrg	 * i915 limits 3D destination to pitch 64B-aligned if used with depth.
1201428d7b3dSmrg	 * i915 limits 3D destination to pitch of 512B - 8kB, in tiles, if tiled.
1202428d7b3dSmrg	 * i915 limits 3D destination to POT aligned pitch if tiled.
1203428d7b3dSmrg	 * i915 limits 3D destination drawing rect to w,h of 2048,2048.
1204428d7b3dSmrg	 *
1205428d7b3dSmrg	 * i845 limits 3D textures to 4B-aligned offset if un-tiled.
1206428d7b3dSmrg	 * i845 limits 3D textures to ~4kB-aligned offset if tiled.
1207428d7b3dSmrg	 * i845 limits 3D textures to width,height of 2048,2048.
1208428d7b3dSmrg	 * i845 limits 3D textures to pitch of 4B - 8kB, in dwords.
1209428d7b3dSmrg	 * i845 limits 3D destination to 4B-aligned offset if un-tiled.
1210428d7b3dSmrg	 * i845 limits 3D destination to ~4kB-aligned offset if tiled.
1211428d7b3dSmrg	 * i845 limits 3D destination to pitch of 8B - 8kB, in dwords.
1212428d7b3dSmrg	 * i845 limits 3D destination drawing rect to w,h of 2048,2048.
1213428d7b3dSmrg	 *
1214428d7b3dSmrg	 * For the tiled issues, the only tiled buffer we draw to should be
1215428d7b3dSmrg	 * the front, which will have an appropriate pitch/offset already set up,
1216428d7b3dSmrg	 * so UXA doesn't need to worry.
1217428d7b3dSmrg	 */
1218428d7b3dSmrg	if (INTEL_INFO(intel)->gen >= 040) {
1219428d7b3dSmrg		intel->accel_pixmap_offset_alignment = 4 * 2;
1220428d7b3dSmrg		intel->accel_max_x = 8192;
1221428d7b3dSmrg		intel->accel_max_y = 8192;
1222428d7b3dSmrg	} else {
1223428d7b3dSmrg		intel->accel_pixmap_offset_alignment = 4;
1224428d7b3dSmrg		intel->accel_max_x = 2048;
1225428d7b3dSmrg		intel->accel_max_y = 2048;
1226428d7b3dSmrg	}
1227428d7b3dSmrg}
1228428d7b3dSmrg
1229428d7b3dSmrgstatic Bool intel_option_accel_none(intel_screen_private *intel)
1230428d7b3dSmrg{
1231428d7b3dSmrg	const char *s;
1232428d7b3dSmrg
1233428d7b3dSmrg	s = xf86GetOptValString(intel->Options, OPTION_ACCEL_METHOD);
1234428d7b3dSmrg	if (s == NULL)
1235428d7b3dSmrg		return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
1236428d7b3dSmrg
1237428d7b3dSmrg	return strcasecmp(s, "none") == 0;
1238428d7b3dSmrg}
1239428d7b3dSmrg
1240428d7b3dSmrgstatic Bool intel_option_accel_blt(intel_screen_private *intel)
1241428d7b3dSmrg{
1242428d7b3dSmrg	const char *s;
1243428d7b3dSmrg
1244428d7b3dSmrg	s = xf86GetOptValString(intel->Options, OPTION_ACCEL_METHOD);
1245428d7b3dSmrg	if (s == NULL)
1246428d7b3dSmrg		return FALSE;
1247428d7b3dSmrg
1248428d7b3dSmrg	return strcasecmp(s, "blt") == 0;
1249428d7b3dSmrg}
1250428d7b3dSmrg
1251428d7b3dSmrg/**
1252428d7b3dSmrg * Intialiazes the hardware for the 3D pipeline use in the 2D driver.
1253428d7b3dSmrg *
1254428d7b3dSmrg * Some state caching is performed to avoid redundant state emits.  This
1255428d7b3dSmrg * function is also responsible for marking the state as clobbered for DRI
1256428d7b3dSmrg * clients.
1257428d7b3dSmrg */
1258428d7b3dSmrgvoid IntelEmitInvarientState(ScrnInfoPtr scrn)
1259428d7b3dSmrg{
1260428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
1261428d7b3dSmrg
1262428d7b3dSmrg	/* If we've emitted our state since the last clobber by another client,
1263428d7b3dSmrg	 * skip it.
1264428d7b3dSmrg	 */
1265428d7b3dSmrg	if (intel->last_3d != LAST_3D_OTHER)
1266428d7b3dSmrg		return;
1267428d7b3dSmrg
1268428d7b3dSmrg	if (IS_GEN2(intel))
1269428d7b3dSmrg		I830EmitInvarientState(scrn);
1270428d7b3dSmrg	else if IS_GEN3(intel)
1271428d7b3dSmrg		I915EmitInvarientState(scrn);
1272428d7b3dSmrg}
1273428d7b3dSmrg
1274428d7b3dSmrgBool intel_uxa_init(ScreenPtr screen)
1275428d7b3dSmrg{
1276428d7b3dSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1277428d7b3dSmrg	intel_screen_private *intel = intel_get_screen_private(scrn);
1278428d7b3dSmrg
1279428d7b3dSmrg	intel_batch_init(scrn);
1280428d7b3dSmrg
1281428d7b3dSmrg	if (INTEL_INFO(intel)->gen >= 040 && INTEL_INFO(intel)->gen < 0100)
1282428d7b3dSmrg		gen4_render_state_init(scrn);
1283428d7b3dSmrg
1284428d7b3dSmrg#if HAS_DIXREGISTERPRIVATEKEY
1285428d7b3dSmrg	if (!dixRegisterPrivateKey(&uxa_pixmap_index, PRIVATE_PIXMAP, 0))
1286428d7b3dSmrg#else
1287428d7b3dSmrg	if (!dixRequestPrivate(&uxa_pixmap_index, 0))
1288428d7b3dSmrg#endif
1289428d7b3dSmrg		return FALSE;
1290428d7b3dSmrg
1291428d7b3dSmrg	intel_limits_init(intel);
1292428d7b3dSmrg
1293428d7b3dSmrg	intel->uxa_driver = uxa_driver_alloc();
1294428d7b3dSmrg	if (intel->uxa_driver == NULL)
1295428d7b3dSmrg		return FALSE;
1296428d7b3dSmrg
1297428d7b3dSmrg	memset(intel->uxa_driver, 0, sizeof(*intel->uxa_driver));
1298428d7b3dSmrg
1299428d7b3dSmrg	intel->uxa_driver->uxa_major = 1;
1300428d7b3dSmrg	intel->uxa_driver->uxa_minor = 0;
1301428d7b3dSmrg
1302428d7b3dSmrg	intel->prim_offset = 0;
1303428d7b3dSmrg	intel->vertex_count = 0;
1304428d7b3dSmrg	intel->vertex_offset = 0;
1305428d7b3dSmrg	intel->vertex_used = 0;
1306428d7b3dSmrg	intel->floats_per_vertex = 0;
1307428d7b3dSmrg	intel->last_floats_per_vertex = 0;
1308428d7b3dSmrg	intel->vertex_bo = NULL;
1309428d7b3dSmrg	intel->surface_used = 0;
1310428d7b3dSmrg	intel->surface_reloc = 0;
1311428d7b3dSmrg
1312428d7b3dSmrg	/* Solid fill */
1313428d7b3dSmrg	intel->uxa_driver->check_solid = intel_uxa_check_solid;
1314428d7b3dSmrg	intel->uxa_driver->prepare_solid = intel_uxa_prepare_solid;
1315428d7b3dSmrg	intel->uxa_driver->solid = intel_uxa_solid;
1316428d7b3dSmrg	intel->uxa_driver->done_solid = intel_uxa_done;
1317428d7b3dSmrg
1318428d7b3dSmrg	/* Copy */
1319428d7b3dSmrg	intel->uxa_driver->check_copy = intel_uxa_check_copy;
1320428d7b3dSmrg	intel->uxa_driver->prepare_copy = intel_uxa_prepare_copy;
1321428d7b3dSmrg	intel->uxa_driver->copy = intel_uxa_copy;
1322428d7b3dSmrg	intel->uxa_driver->done_copy = intel_uxa_done;
1323428d7b3dSmrg
1324428d7b3dSmrg	/* Composite */
1325428d7b3dSmrg	if (intel_option_accel_blt(intel)) {
1326428d7b3dSmrg	} else if (INTEL_INFO(intel)->gen < 030) {
1327428d7b3dSmrg		intel->uxa_driver->check_composite = i830_check_composite;
1328428d7b3dSmrg		intel->uxa_driver->check_composite_target = i830_check_composite_target;
1329428d7b3dSmrg		intel->uxa_driver->check_composite_texture = i830_check_composite_texture;
1330428d7b3dSmrg		intel->uxa_driver->prepare_composite = i830_prepare_composite;
1331428d7b3dSmrg		intel->uxa_driver->composite = i830_composite;
1332428d7b3dSmrg		intel->uxa_driver->done_composite = i830_done_composite;
1333428d7b3dSmrg
1334428d7b3dSmrg		intel->vertex_flush = i830_vertex_flush;
1335428d7b3dSmrg		intel->batch_commit_notify = i830_batch_commit_notify;
1336428d7b3dSmrg	} else if (INTEL_INFO(intel)->gen < 040) {
1337428d7b3dSmrg		intel->uxa_driver->check_composite = i915_check_composite;
1338428d7b3dSmrg		intel->uxa_driver->check_composite_target = i915_check_composite_target;
1339428d7b3dSmrg		intel->uxa_driver->check_composite_texture = i915_check_composite_texture;
1340428d7b3dSmrg		intel->uxa_driver->prepare_composite = i915_prepare_composite;
1341428d7b3dSmrg		intel->uxa_driver->composite = i915_composite;
1342428d7b3dSmrg		intel->uxa_driver->done_composite = i830_done_composite;
1343428d7b3dSmrg
1344428d7b3dSmrg		intel->vertex_flush = i915_vertex_flush;
1345428d7b3dSmrg		intel->batch_commit_notify = i915_batch_commit_notify;
1346428d7b3dSmrg	} else if (INTEL_INFO(intel)->gen < 0100) {
1347428d7b3dSmrg		intel->uxa_driver->check_composite = i965_check_composite;
1348428d7b3dSmrg		intel->uxa_driver->check_composite_texture = i965_check_composite_texture;
1349428d7b3dSmrg		intel->uxa_driver->prepare_composite = i965_prepare_composite;
1350428d7b3dSmrg		intel->uxa_driver->composite = i965_composite;
1351428d7b3dSmrg		intel->uxa_driver->done_composite = i830_done_composite;
1352428d7b3dSmrg
1353428d7b3dSmrg		intel->vertex_flush = i965_vertex_flush;
1354428d7b3dSmrg		intel->batch_flush = i965_batch_flush;
1355428d7b3dSmrg		intel->batch_commit_notify = i965_batch_commit_notify;
1356428d7b3dSmrg
1357428d7b3dSmrg		if (INTEL_INFO(intel)->gen < 050) {
1358428d7b3dSmrg			intel->context_switch = gen4_context_switch;
1359428d7b3dSmrg		} else if (INTEL_INFO(intel)->gen < 060) {
1360428d7b3dSmrg			intel->context_switch = gen5_context_switch;
1361428d7b3dSmrg		} else {
1362428d7b3dSmrg			intel->context_switch = gen6_context_switch;
1363428d7b3dSmrg		}
1364428d7b3dSmrg	}
1365428d7b3dSmrg
1366428d7b3dSmrg	/* PutImage */
1367428d7b3dSmrg	intel->uxa_driver->put_image = intel_uxa_put_image;
1368428d7b3dSmrg	intel->uxa_driver->get_image = intel_uxa_get_image;
1369428d7b3dSmrg
1370428d7b3dSmrg	intel->uxa_driver->prepare_access = intel_uxa_prepare_access;
1371428d7b3dSmrg	intel->uxa_driver->finish_access = intel_uxa_finish_access;
1372428d7b3dSmrg	intel->uxa_driver->pixmap_is_offscreen = intel_uxa_pixmap_is_offscreen;
1373428d7b3dSmrg
1374428d7b3dSmrg	screen->CreatePixmap = intel_uxa_create_pixmap;
1375428d7b3dSmrg	screen->DestroyPixmap = intel_uxa_destroy_pixmap;
1376428d7b3dSmrg
1377428d7b3dSmrg#ifdef CREATE_PIXMAP_USAGE_SHARED
1378428d7b3dSmrg	screen->SharePixmapBacking = intel_uxa_share_pixmap_backing;
1379428d7b3dSmrg	screen->SetSharedPixmapBacking = intel_uxa_set_shared_pixmap_backing;
1380428d7b3dSmrg#endif
1381428d7b3dSmrg
1382428d7b3dSmrg	if (!uxa_driver_init(screen, intel->uxa_driver)) {
1383428d7b3dSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1384428d7b3dSmrg			   "UXA initialization failed\n");
1385428d7b3dSmrg		free(intel->uxa_driver);
1386428d7b3dSmrg		return FALSE;
1387428d7b3dSmrg	}
1388428d7b3dSmrg
1389428d7b3dSmrg	if (intel_option_accel_none(intel))
1390428d7b3dSmrg		intel->force_fallback = 1;
1391428d7b3dSmrg
1392428d7b3dSmrg	uxa_set_fallback_debug(screen, intel->fallback_debug);
1393428d7b3dSmrg	uxa_set_force_fallback(screen, intel->force_fallback);
1394428d7b3dSmrg
1395428d7b3dSmrg	intel->flush_rendering = intel_flush_rendering;
1396428d7b3dSmrg	return TRUE;
1397428d7b3dSmrg}
1398