radeon_exa_funcs.c revision 39413783
1/*
2 * Copyright 2005 Eric Anholt
3 * Copyright 2005 Benjamin Herrenschmidt
4 * Copyright 2006 Tungsten Graphics, Inc.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 *
26 * Authors:
27 *    Eric Anholt <anholt@FreeBSD.org>
28 *    Zack Rusin <zrusin@trolltech.com>
29 *    Benjamin Herrenschmidt <benh@kernel.crashing.org>
30 *    Michel Dänzer <michel@daenzer.net>
31 *
32 */
33
34#include <errno.h>
35#include <string.h>
36
37#include "radeon.h"
38
39#include "exa.h"
40
41static int
42RADEONMarkSync(ScreenPtr pScreen)
43{
44    RINFO_FROM_SCREEN(pScreen);
45
46    TRACE;
47
48    return ++info->accel_state->exaSyncMarker;
49}
50
51static void
52RADEONSync(ScreenPtr pScreen, int marker)
53{
54
55}
56
57static void Emit2DState(ScrnInfoPtr pScrn, int op)
58{
59    RADEONInfoPtr info = RADEONPTR(pScrn);
60    int has_src;
61
62    /* don't emit if no operation in progress */
63    if (info->state_2d.op == 0 && op == 0)
64	return;
65
66    has_src = info->state_2d.src_pitch_offset || info->state_2d.src_bo;
67
68    if (has_src) {
69      BEGIN_ACCEL_RELOC(10, 2);
70    } else {
71      BEGIN_ACCEL_RELOC(9, 1);
72    }
73    OUT_RING_REG(RADEON_DEFAULT_SC_BOTTOM_RIGHT, info->state_2d.default_sc_bottom_right);
74    OUT_RING_REG(RADEON_DP_GUI_MASTER_CNTL, info->state_2d.dp_gui_master_cntl);
75    OUT_RING_REG(RADEON_DP_BRUSH_FRGD_CLR, info->state_2d.dp_brush_frgd_clr);
76    OUT_RING_REG(RADEON_DP_BRUSH_BKGD_CLR, info->state_2d.dp_brush_bkgd_clr);
77    OUT_RING_REG(RADEON_DP_SRC_FRGD_CLR,   info->state_2d.dp_src_frgd_clr);
78    OUT_RING_REG(RADEON_DP_SRC_BKGD_CLR,   info->state_2d.dp_src_bkgd_clr);
79    OUT_RING_REG(RADEON_DP_WRITE_MASK, info->state_2d.dp_write_mask);
80    OUT_RING_REG(RADEON_DP_CNTL, info->state_2d.dp_cntl);
81
82    OUT_RING_REG(RADEON_DST_PITCH_OFFSET, info->state_2d.dst_pitch_offset);
83    OUT_RING_RELOC(info->state_2d.dst_bo, 0, info->state_2d.dst_domain);
84
85    if (has_src) {
86	OUT_RING_REG(RADEON_SRC_PITCH_OFFSET, info->state_2d.src_pitch_offset);
87	OUT_RING_RELOC(info->state_2d.src_bo, RADEON_GEM_DOMAIN_GTT|RADEON_GEM_DOMAIN_VRAM, 0);
88    }
89    ADVANCE_RING();
90
91    if (op)
92	info->state_2d.op = op;
93    info->reemit_current2d = Emit2DState;
94}
95
96static void
97RADEONFlush2D(PixmapPtr pPix)
98{
99    RINFO_FROM_SCREEN(pPix->drawable.pScreen);
100
101    TRACE;
102
103    BEGIN_RING(2*2);
104    OUT_RING_REG(RADEON_DSTCACHE_CTLSTAT, RADEON_RB2D_DC_FLUSH_ALL);
105    OUT_RING_REG(RADEON_WAIT_UNTIL,
106                  RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_DMA_GUI_IDLE);
107    ADVANCE_RING();
108}
109
110static void
111RADEONDone2D(PixmapPtr pPix)
112{
113    RINFO_FROM_SCREEN(pPix->drawable.pScreen);
114    info->state_2d.op = 0;
115
116    RADEONFlush2D(pPix);
117}
118
119static Bool
120RADEONPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
121{
122    RINFO_FROM_SCREEN(pPix->drawable.pScreen);
123    uint32_t datatype, dst_pitch_offset;
124    struct radeon_exa_pixmap_priv *driver_priv;
125    int ret;
126
127    TRACE;
128
129    if (pPix->drawable.bitsPerPixel == 24)
130	RADEON_FALLBACK(("24bpp unsupported\n"));
131    if (!RADEONGetDatatypeBpp(pPix->drawable.bitsPerPixel, &datatype))
132	RADEON_FALLBACK(("RADEONGetDatatypeBpp failed\n"));
133    if (!RADEONGetPixmapOffsetPitch(pPix, &dst_pitch_offset))
134	RADEON_FALLBACK(("RADEONGetPixmapOffsetPitch failed\n"));
135
136    RADEON_SWITCH_TO_2D();
137
138    radeon_cs_space_reset_bos(info->cs);
139
140    driver_priv = exaGetPixmapDriverPrivate(pPix);
141    radeon_cs_space_add_persistent_bo(info->cs, driver_priv->bo->bo.radeon, 0,
142				      RADEON_GEM_DOMAIN_VRAM);
143
144    ret = radeon_cs_space_check(info->cs);
145    if (ret)
146	RADEON_FALLBACK(("Not enough RAM to hw accel solid operation\n"));
147
148    driver_priv = exaGetPixmapDriverPrivate(pPix);
149    if (driver_priv) {
150	info->state_2d.dst_bo = driver_priv->bo->bo.radeon;
151 	info->state_2d.dst_domain = driver_priv->shared ? RADEON_GEM_DOMAIN_GTT : RADEON_GEM_DOMAIN_VRAM;
152    }
153
154    info->state_2d.default_sc_bottom_right = (RADEON_DEFAULT_SC_RIGHT_MAX |
155					       RADEON_DEFAULT_SC_BOTTOM_MAX);
156    info->state_2d.dp_brush_bkgd_clr = 0x00000000;
157    info->state_2d.dp_src_frgd_clr = 0xffffffff;
158    info->state_2d.dp_src_bkgd_clr = 0x00000000;
159    info->state_2d.dp_gui_master_cntl = (RADEON_GMC_DST_PITCH_OFFSET_CNTL |
160					  RADEON_GMC_BRUSH_SOLID_COLOR |
161					  (datatype << 8) |
162					  RADEON_GMC_SRC_DATATYPE_COLOR |
163					  RADEON_ROP[alu].pattern |
164					  RADEON_GMC_CLR_CMP_CNTL_DIS);
165    info->state_2d.dp_brush_frgd_clr = fg;
166    info->state_2d.dp_cntl = (RADEON_DST_X_LEFT_TO_RIGHT | RADEON_DST_Y_TOP_TO_BOTTOM);
167    info->state_2d.dp_write_mask = pm;
168    info->state_2d.dst_pitch_offset = dst_pitch_offset;
169    info->state_2d.src_pitch_offset = 0;
170    info->state_2d.src_bo = NULL;
171
172    info->accel_state->dst_pix = pPix;
173
174    Emit2DState(pScrn, RADEON_2D_EXA_SOLID);
175
176    return TRUE;
177}
178
179
180static void
181RADEONSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2)
182{
183    RINFO_FROM_SCREEN(pPix->drawable.pScreen);
184
185    TRACE;
186
187    if (CS_FULL(info->cs)) {
188	RADEONFlush2D(info->accel_state->dst_pix);
189	radeon_cs_flush_indirect(pScrn);
190    }
191
192    if (info->accel_state->vsync)
193	RADEONWaitForVLine(pScrn, pPix,
194			   radeon_pick_best_crtc(pScrn, FALSE, x1, x2, y1, y2),
195			   y1, y2);
196
197    BEGIN_RING(2*2);
198    OUT_RING_REG(RADEON_DST_Y_X, (y1 << 16) | x1);
199    OUT_RING_REG(RADEON_DST_HEIGHT_WIDTH, ((y2 - y1) << 16) | (x2 - x1));
200    ADVANCE_RING();
201}
202
203static void
204RADEONDoPrepareCopy(ScrnInfoPtr pScrn, uint32_t src_pitch_offset,
205		    uint32_t dst_pitch_offset, uint32_t datatype, int rop,
206		    Pixel planemask)
207{
208    RADEONInfoPtr info = RADEONPTR(pScrn);
209
210    /* setup 2D state */
211    info->state_2d.dp_gui_master_cntl = (RADEON_GMC_DST_PITCH_OFFSET_CNTL |
212					  RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
213					  RADEON_GMC_BRUSH_NONE |
214					  (datatype << 8) |
215					  RADEON_GMC_SRC_DATATYPE_COLOR |
216					  RADEON_ROP[rop].rop |
217					  RADEON_DP_SRC_SOURCE_MEMORY |
218					  RADEON_GMC_CLR_CMP_CNTL_DIS);
219    info->state_2d.dp_cntl = ((info->accel_state->xdir >= 0 ? RADEON_DST_X_LEFT_TO_RIGHT : 0) |
220			       (info->accel_state->ydir >= 0 ? RADEON_DST_Y_TOP_TO_BOTTOM : 0));
221    info->state_2d.dp_brush_frgd_clr = 0xffffffff;
222    info->state_2d.dp_brush_bkgd_clr = 0x00000000;
223    info->state_2d.dp_src_frgd_clr = 0xffffffff;
224    info->state_2d.dp_src_bkgd_clr = 0x00000000;
225    info->state_2d.dp_write_mask = planemask;
226    info->state_2d.dst_pitch_offset = dst_pitch_offset;
227    info->state_2d.src_pitch_offset = src_pitch_offset;
228    info->state_2d.default_sc_bottom_right =  (RADEON_DEFAULT_SC_RIGHT_MAX
229						| RADEON_DEFAULT_SC_BOTTOM_MAX);
230
231    Emit2DState(pScrn, RADEON_2D_EXA_COPY);
232}
233
234static Bool
235RADEONPrepareCopy(PixmapPtr pSrc,   PixmapPtr pDst,
236		  int xdir, int ydir,
237		  int rop,
238		  Pixel planemask)
239{
240    RINFO_FROM_SCREEN(pDst->drawable.pScreen);
241    uint32_t datatype, src_pitch_offset, dst_pitch_offset;
242    struct radeon_exa_pixmap_priv *driver_priv;
243    int ret;
244    TRACE;
245
246    if (pDst->drawable.bitsPerPixel == 24)
247	RADEON_FALLBACK(("24bpp unsupported"));
248    if (!RADEONGetDatatypeBpp(pDst->drawable.bitsPerPixel, &datatype))
249	RADEON_FALLBACK(("RADEONGetDatatypeBpp failed\n"));
250    if (!RADEONGetPixmapOffsetPitch(pSrc, &src_pitch_offset))
251	RADEON_FALLBACK(("RADEONGetPixmapOffsetPitch source failed\n"));
252    if (!RADEONGetPixmapOffsetPitch(pDst, &dst_pitch_offset))
253	RADEON_FALLBACK(("RADEONGetPixmapOffsetPitch dest failed\n"));
254
255    RADEON_SWITCH_TO_2D();
256
257    radeon_cs_space_reset_bos(info->cs);
258
259    driver_priv = exaGetPixmapDriverPrivate(pSrc);
260    radeon_cs_space_add_persistent_bo(info->cs, driver_priv->bo->bo.radeon,
261				      RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM, 0);
262    info->state_2d.src_bo = driver_priv->bo->bo.radeon;
263
264    driver_priv = exaGetPixmapDriverPrivate(pDst);
265    info->state_2d.dst_bo = driver_priv->bo->bo.radeon;
266    info->state_2d.dst_domain = driver_priv->shared ? RADEON_GEM_DOMAIN_GTT : RADEON_GEM_DOMAIN_VRAM;
267    radeon_cs_space_add_persistent_bo(info->cs, driver_priv->bo->bo.radeon, 0,
268				      info->state_2d.dst_domain);
269
270    ret = radeon_cs_space_check(info->cs);
271    if (ret)
272	RADEON_FALLBACK(("Not enough RAM to hw accel copy operation\n"));
273
274    info->accel_state->xdir = xdir;
275    info->accel_state->ydir = ydir;
276    info->accel_state->dst_pix = pDst;
277
278    RADEONDoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset,
279			datatype, rop, planemask);
280
281    return TRUE;
282}
283
284static void
285RADEONCopy(PixmapPtr pDst,
286	   int srcX, int srcY,
287	   int dstX, int dstY,
288	   int w, int h)
289{
290    RINFO_FROM_SCREEN(pDst->drawable.pScreen);
291
292    TRACE;
293
294    if (CS_FULL(info->cs)) {
295        RADEONFlush2D(info->accel_state->dst_pix);
296	radeon_cs_flush_indirect(pScrn);
297    }
298
299    if (info->accel_state->xdir < 0) {
300	srcX += w - 1;
301	dstX += w - 1;
302    }
303    if (info->accel_state->ydir < 0) {
304	srcY += h - 1;
305	dstY += h - 1;
306    }
307
308    if (info->accel_state->vsync)
309	RADEONWaitForVLine(pScrn, pDst,
310			   radeon_pick_best_crtc(pScrn, FALSE, dstX, dstX + w, dstY, dstY + h),
311			   dstY, dstY + h);
312
313    BEGIN_RING(2*3);
314
315    OUT_RING_REG(RADEON_SRC_Y_X,	   (srcY << 16) | srcX);
316    OUT_RING_REG(RADEON_DST_Y_X,	   (dstY << 16) | dstX);
317    OUT_RING_REG(RADEON_DST_HEIGHT_WIDTH, (h  << 16) | w);
318
319    ADVANCE_RING();
320}
321
322/* Emit blit with arbitrary source and destination offsets and pitches */
323static void
324RADEONBlitChunk(ScrnInfoPtr pScrn, struct radeon_bo *src_bo,
325                struct radeon_bo *dst_bo, uint32_t datatype,
326                uint32_t src_pitch_offset, uint32_t dst_pitch_offset,
327                int srcX, int srcY, int dstX, int dstY, int w, int h,
328                uint32_t src_domain, uint32_t dst_domain)
329{
330    RADEONInfoPtr info = RADEONPTR(pScrn);
331
332    if (src_bo && dst_bo) {
333        BEGIN_ACCEL_RELOC(6, 2);
334    } else if (src_bo && !dst_bo) {
335        BEGIN_ACCEL_RELOC(6, 1);
336    } else {
337        BEGIN_RING(2*6);
338    }
339    OUT_RING_REG(RADEON_DP_GUI_MASTER_CNTL,
340		  RADEON_GMC_DST_PITCH_OFFSET_CNTL |
341		  RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
342		  RADEON_GMC_BRUSH_NONE |
343		  (datatype << 8) |
344		  RADEON_GMC_SRC_DATATYPE_COLOR |
345		  RADEON_ROP3_S |
346		  RADEON_DP_SRC_SOURCE_MEMORY |
347		  RADEON_GMC_CLR_CMP_CNTL_DIS |
348		  RADEON_GMC_WR_MSK_DIS);
349    OUT_RING_REG(RADEON_SRC_PITCH_OFFSET, src_pitch_offset);
350    if (src_bo) {
351	OUT_RING_RELOC(src_bo, src_domain, 0);
352    }
353    OUT_RING_REG(RADEON_DST_PITCH_OFFSET, dst_pitch_offset);
354    if (dst_bo) {
355	OUT_RING_RELOC(dst_bo, 0, dst_domain);
356    }
357    OUT_RING_REG(RADEON_SRC_Y_X, (srcY << 16) | srcX);
358    OUT_RING_REG(RADEON_DST_Y_X, (dstY << 16) | dstX);
359    OUT_RING_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | w);
360    ADVANCE_RING();
361    BEGIN_RING(2*2);
362    OUT_RING_REG(RADEON_DSTCACHE_CTLSTAT, RADEON_RB2D_DC_FLUSH_ALL);
363    OUT_RING_REG(RADEON_WAIT_UNTIL,
364                  RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_DMA_GUI_IDLE);
365    ADVANCE_RING();
366}
367
368static Bool
369RADEONUploadToScreenCS(PixmapPtr pDst, int x, int y, int w, int h,
370		       char *src, int src_pitch)
371{
372    ScreenPtr pScreen = pDst->drawable.pScreen;
373    RINFO_FROM_SCREEN(pScreen);
374    struct radeon_exa_pixmap_priv *driver_priv;
375    struct radeon_bo *scratch = NULL;
376    struct radeon_bo *copy_dst;
377    unsigned char *dst;
378    unsigned size;
379    uint32_t datatype = 0;
380    uint32_t dst_domain;
381    uint32_t dst_pitch_offset;
382    unsigned bpp = pDst->drawable.bitsPerPixel;
383    uint32_t scratch_pitch = RADEON_ALIGN(w * bpp / 8, 64);
384    uint32_t copy_pitch;
385    uint32_t swap = RADEON_HOST_DATA_SWAP_NONE;
386    int ret;
387    Bool flush = TRUE;
388    Bool r;
389    int i;
390
391    if (bpp < 8)
392	return FALSE;
393
394    driver_priv = exaGetPixmapDriverPrivate(pDst);
395    if (!driver_priv || !driver_priv->bo->bo.radeon)
396	return FALSE;
397
398#if X_BYTE_ORDER == X_BIG_ENDIAN
399    switch (bpp) {
400    case 32:
401	swap = RADEON_HOST_DATA_SWAP_32BIT;
402	break;
403    case 16:
404	swap = RADEON_HOST_DATA_SWAP_16BIT;
405	break;
406    }
407#endif
408
409    /* If we know the BO won't be busy / in VRAM, don't bother with a scratch */
410    copy_dst = driver_priv->bo->bo.radeon;
411    copy_pitch = pDst->devKind;
412    if (!(driver_priv->tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) {
413	if (!radeon_bo_is_referenced_by_cs(driver_priv->bo->bo.radeon, info->cs)) {
414	    flush = FALSE;
415	    if (!radeon_bo_is_busy(driver_priv->bo->bo.radeon, &dst_domain) &&
416		!(dst_domain & RADEON_GEM_DOMAIN_VRAM))
417		goto copy;
418	}
419	/* use cpu copy for fast fb access */
420	if (info->is_fast_fb)
421	    goto copy;
422    }
423
424    size = scratch_pitch * h;
425    scratch = radeon_bo_open(info->bufmgr, 0, size, 0, RADEON_GEM_DOMAIN_GTT, 0);
426    if (!scratch) {
427	goto copy;
428    }
429    radeon_cs_space_reset_bos(info->cs);
430    radeon_add_pixmap(info->cs, pDst, 0, RADEON_GEM_DOMAIN_VRAM);
431    radeon_cs_space_add_persistent_bo(info->cs, scratch, RADEON_GEM_DOMAIN_GTT, 0);
432    ret = radeon_cs_space_check(info->cs);
433    if (ret) {
434	goto copy;
435    }
436    copy_dst = scratch;
437    copy_pitch = scratch_pitch;
438    flush = FALSE;
439
440copy:
441    if (flush)
442	radeon_cs_flush_indirect(pScrn);
443
444    ret = radeon_bo_map(copy_dst, 0);
445    if (ret) {
446        r = FALSE;
447        goto out;
448    }
449    r = TRUE;
450    size = w * bpp / 8;
451    dst = copy_dst->ptr;
452    if (copy_dst == driver_priv->bo->bo.radeon)
453	dst += y * copy_pitch + x * bpp / 8;
454    for (i = 0; i < h; i++) {
455        RADEONCopySwap(dst + i * copy_pitch, (uint8_t*)src, size, swap);
456        src += src_pitch;
457    }
458    radeon_bo_unmap(copy_dst);
459
460    if (copy_dst == scratch) {
461	RADEONGetDatatypeBpp(pDst->drawable.bitsPerPixel, &datatype);
462	RADEONGetPixmapOffsetPitch(pDst, &dst_pitch_offset);
463	RADEON_SWITCH_TO_2D();
464	RADEONBlitChunk(pScrn, scratch, driver_priv->bo->bo.radeon, datatype, scratch_pitch << 16,
465			dst_pitch_offset, 0, 0, x, y, w, h,
466			RADEON_GEM_DOMAIN_GTT, RADEON_GEM_DOMAIN_VRAM);
467    }
468
469out:
470    if (scratch)
471	radeon_bo_unref(scratch);
472    return r;
473}
474
475static Bool
476RADEONDownloadFromScreenCS(PixmapPtr pSrc, int x, int y, int w,
477                           int h, char *dst, int dst_pitch)
478{
479    RINFO_FROM_SCREEN(pSrc->drawable.pScreen);
480    struct radeon_exa_pixmap_priv *driver_priv;
481    struct radeon_bo *scratch = NULL;
482    struct radeon_bo *copy_src;
483    unsigned size;
484    uint32_t datatype = 0;
485    uint32_t src_domain = 0;
486    uint32_t src_pitch_offset;
487    unsigned bpp = pSrc->drawable.bitsPerPixel;
488    uint32_t scratch_pitch = RADEON_ALIGN(w * bpp / 8, 64);
489    uint32_t copy_pitch;
490    uint32_t swap = RADEON_HOST_DATA_SWAP_NONE;
491    int ret;
492    Bool flush = FALSE;
493    Bool r;
494
495    if (bpp < 8)
496	return FALSE;
497
498    driver_priv = exaGetPixmapDriverPrivate(pSrc);
499    if (!driver_priv || !driver_priv->bo->bo.radeon)
500	return FALSE;
501
502#if X_BYTE_ORDER == X_BIG_ENDIAN
503    switch (bpp) {
504    case 32:
505	swap = RADEON_HOST_DATA_SWAP_32BIT;
506	break;
507    case 16:
508	swap = RADEON_HOST_DATA_SWAP_16BIT;
509	break;
510    }
511#endif
512
513    /* If we know the BO won't end up in VRAM anyway, don't bother with a scratch */
514    copy_src = driver_priv->bo->bo.radeon;
515    copy_pitch = pSrc->devKind;
516    if (!(driver_priv->tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) {
517	if (radeon_bo_is_referenced_by_cs(driver_priv->bo->bo.radeon, info->cs)) {
518	    src_domain = radeon_bo_get_src_domain(driver_priv->bo->bo.radeon);
519	    if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
520		(RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
521		src_domain = 0;
522	    else /* A write may be scheduled */
523		flush = TRUE;
524	}
525
526	if (!src_domain)
527	    radeon_bo_is_busy(driver_priv->bo->bo.radeon, &src_domain);
528
529	if (src_domain & ~(uint32_t)RADEON_GEM_DOMAIN_VRAM)
530	    goto copy;
531    }
532    size = scratch_pitch * h;
533    scratch = radeon_bo_open(info->bufmgr, 0, size, 0, RADEON_GEM_DOMAIN_GTT, 0);
534    if (!scratch) {
535	goto copy;
536    }
537    radeon_cs_space_reset_bos(info->cs);
538    radeon_add_pixmap(info->cs, pSrc, RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM, 0);
539    radeon_cs_space_add_persistent_bo(info->cs, scratch, 0, RADEON_GEM_DOMAIN_GTT);
540    ret = radeon_cs_space_check(info->cs);
541    if (ret) {
542	goto copy;
543    }
544    RADEONGetDatatypeBpp(pSrc->drawable.bitsPerPixel, &datatype);
545    RADEONGetPixmapOffsetPitch(pSrc, &src_pitch_offset);
546    RADEON_SWITCH_TO_2D();
547    RADEONBlitChunk(pScrn, driver_priv->bo->bo.radeon, scratch, datatype,
548		    src_pitch_offset, scratch_pitch << 16, x, y, 0, 0, w, h,
549                    RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT,
550                    RADEON_GEM_DOMAIN_GTT);
551    copy_src = scratch;
552    copy_pitch = scratch_pitch;
553    flush = TRUE;
554
555copy:
556    if (flush)
557	FLUSH_RING();
558
559    ret = radeon_bo_map(copy_src, 0);
560    if (ret) {
561	ErrorF("failed to map pixmap: %d\n", ret);
562        r = FALSE;
563        goto out;
564    }
565    r = TRUE;
566    w *= bpp / 8;
567    if (copy_src == driver_priv->bo->bo.radeon)
568	size = y * copy_pitch + x * bpp / 8;
569    else
570	size = 0;
571    while (h--) {
572        RADEONCopySwap((uint8_t*)dst, copy_src->ptr + size, w, swap);
573        size += copy_pitch;
574        dst += dst_pitch;
575    }
576    radeon_bo_unmap(copy_src);
577out:
578    if (scratch)
579	radeon_bo_unref(scratch);
580    return r;
581}
582
583Bool RADEONDrawInit(ScreenPtr pScreen)
584{
585    RINFO_FROM_SCREEN(pScreen);
586
587    if (!info->accel_state->exa) {
588	xf86DrvMsg(pScreen->myNum, X_ERROR, "Memory map not set up\n");
589	return FALSE;
590    }
591
592    info->accel_state->exa->exa_major = EXA_VERSION_MAJOR;
593    info->accel_state->exa->exa_minor = EXA_VERSION_MINOR;
594
595    info->accel_state->exa->PrepareSolid = RADEONPrepareSolid;
596    info->accel_state->exa->Solid = RADEONSolid;
597    info->accel_state->exa->DoneSolid = RADEONDone2D;
598
599    info->accel_state->exa->PrepareCopy = RADEONPrepareCopy;
600    info->accel_state->exa->Copy = RADEONCopy;
601    info->accel_state->exa->DoneCopy = RADEONDone2D;
602
603    info->accel_state->exa->MarkSync = RADEONMarkSync;
604    info->accel_state->exa->WaitMarker = RADEONSync;
605
606    info->accel_state->exa->UploadToScreen = &RADEONUploadToScreenCS;
607    info->accel_state->exa->DownloadFromScreen = &RADEONDownloadFromScreenCS;
608
609    info->accel_state->exa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_SUPPORTS_PREPARE_AUX |
610	EXA_SUPPORTS_OFFSCREEN_OVERLAPS | EXA_HANDLES_PIXMAPS | EXA_MIXED_PIXMAPS;
611    info->accel_state->exa->pixmapOffsetAlign = RADEON_GPU_PAGE_SIZE;
612    info->accel_state->exa->pixmapPitchAlign = 64;
613
614#ifdef RENDER
615    if (info->RenderAccel) {
616	if (IS_R300_3D || IS_R500_3D) {
617		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Render acceleration "
618			       "enabled for R300/R400/R500 type cards.\n");
619		info->accel_state->exa->CheckComposite = R300CheckComposite;
620		info->accel_state->exa->PrepareComposite =
621		    R300PrepareComposite;
622		info->accel_state->exa->Composite = RadeonComposite;
623		info->accel_state->exa->DoneComposite = RadeonDoneComposite;
624	} else if (IS_R200_3D) {
625		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Render acceleration "
626			       "enabled for R200 type cards.\n");
627		info->accel_state->exa->CheckComposite = R200CheckComposite;
628		info->accel_state->exa->PrepareComposite =
629		    R200PrepareComposite;
630		info->accel_state->exa->Composite = RadeonComposite;
631		info->accel_state->exa->DoneComposite = RadeonDoneComposite;
632	} else {
633		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Render acceleration "
634			       "enabled for R100 type cards.\n");
635		info->accel_state->exa->CheckComposite = R100CheckComposite;
636		info->accel_state->exa->PrepareComposite =
637		    R100PrepareComposite;
638		info->accel_state->exa->Composite = RadeonComposite;
639		info->accel_state->exa->DoneComposite = RadeonDoneComposite;
640	}
641    }
642#endif
643
644    info->accel_state->exa->DestroyPixmap = RADEONEXADestroyPixmap;
645    info->accel_state->exa->PixmapIsOffscreen = RADEONEXAPixmapIsOffscreen;
646    info->accel_state->exa->PrepareAccess = RADEONPrepareAccess_CS;
647    info->accel_state->exa->FinishAccess = RADEONFinishAccess_CS;
648    info->accel_state->exa->CreatePixmap2 = RADEONEXACreatePixmap2;
649    info->accel_state->exa->SharePixmapBacking = RADEONEXASharePixmapBacking;
650    info->accel_state->exa->SetSharedPixmapBacking = RADEONEXASetSharedPixmapBacking;
651
652
653    info->accel_state->exa->maxPitchBytes = 16320;
654    info->accel_state->exa->maxX = 8191;
655    info->accel_state->exa->maxY = 8191;
656
657    if (xf86ReturnOptValBool(info->Options, OPTION_EXA_VSYNC, FALSE)) {
658	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EXA VSync enabled\n");
659	info->accel_state->vsync = TRUE;
660    } else
661	info->accel_state->vsync = FALSE;
662
663    RADEONEngineInit(pScrn);
664
665    if (!exaDriverInit(pScreen, info->accel_state->exa)) {
666	free(info->accel_state->exa);
667	return FALSE;
668    }
669    exaMarkSync(pScreen);
670
671    return TRUE;
672}
673
674