radeon_exa_funcs.c revision 8bf5c682
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, 0, RADEON_GEM_DOMAIN_VRAM);
142
143    ret = radeon_cs_space_check(info->cs);
144    if (ret)
145	RADEON_FALLBACK(("Not enough RAM to hw accel solid operation\n"));
146
147    driver_priv = exaGetPixmapDriverPrivate(pPix);
148    if (driver_priv) {
149	info->state_2d.dst_bo = driver_priv->bo;
150 	info->state_2d.dst_domain = driver_priv->shared ? RADEON_GEM_DOMAIN_GTT : RADEON_GEM_DOMAIN_VRAM;
151    }
152
153    info->state_2d.default_sc_bottom_right = (RADEON_DEFAULT_SC_RIGHT_MAX |
154					       RADEON_DEFAULT_SC_BOTTOM_MAX);
155    info->state_2d.dp_brush_bkgd_clr = 0x00000000;
156    info->state_2d.dp_src_frgd_clr = 0xffffffff;
157    info->state_2d.dp_src_bkgd_clr = 0x00000000;
158    info->state_2d.dp_gui_master_cntl = (RADEON_GMC_DST_PITCH_OFFSET_CNTL |
159					  RADEON_GMC_BRUSH_SOLID_COLOR |
160					  (datatype << 8) |
161					  RADEON_GMC_SRC_DATATYPE_COLOR |
162					  RADEON_ROP[alu].pattern |
163					  RADEON_GMC_CLR_CMP_CNTL_DIS);
164    info->state_2d.dp_brush_frgd_clr = fg;
165    info->state_2d.dp_cntl = (RADEON_DST_X_LEFT_TO_RIGHT | RADEON_DST_Y_TOP_TO_BOTTOM);
166    info->state_2d.dp_write_mask = pm;
167    info->state_2d.dst_pitch_offset = dst_pitch_offset;
168    info->state_2d.src_pitch_offset = 0;
169    info->state_2d.src_bo = NULL;
170
171    info->accel_state->dst_pix = pPix;
172
173    Emit2DState(pScrn, RADEON_2D_EXA_SOLID);
174
175    return TRUE;
176}
177
178
179static void
180RADEONSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2)
181{
182    RINFO_FROM_SCREEN(pPix->drawable.pScreen);
183
184    TRACE;
185
186    if (CS_FULL(info->cs)) {
187	RADEONFlush2D(info->accel_state->dst_pix);
188	radeon_cs_flush_indirect(pScrn);
189    }
190
191    if (info->accel_state->vsync)
192	RADEONWaitForVLine(pScrn, pPix,
193			   radeon_pick_best_crtc(pScrn, FALSE, x1, x2, y1, y2),
194			   y1, y2);
195
196    BEGIN_RING(2*2);
197    OUT_RING_REG(RADEON_DST_Y_X, (y1 << 16) | x1);
198    OUT_RING_REG(RADEON_DST_HEIGHT_WIDTH, ((y2 - y1) << 16) | (x2 - x1));
199    ADVANCE_RING();
200}
201
202static void
203RADEONDoPrepareCopy(ScrnInfoPtr pScrn, uint32_t src_pitch_offset,
204		    uint32_t dst_pitch_offset, uint32_t datatype, int rop,
205		    Pixel planemask)
206{
207    RADEONInfoPtr info = RADEONPTR(pScrn);
208
209    /* setup 2D state */
210    info->state_2d.dp_gui_master_cntl = (RADEON_GMC_DST_PITCH_OFFSET_CNTL |
211					  RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
212					  RADEON_GMC_BRUSH_NONE |
213					  (datatype << 8) |
214					  RADEON_GMC_SRC_DATATYPE_COLOR |
215					  RADEON_ROP[rop].rop |
216					  RADEON_DP_SRC_SOURCE_MEMORY |
217					  RADEON_GMC_CLR_CMP_CNTL_DIS);
218    info->state_2d.dp_cntl = ((info->accel_state->xdir >= 0 ? RADEON_DST_X_LEFT_TO_RIGHT : 0) |
219			       (info->accel_state->ydir >= 0 ? RADEON_DST_Y_TOP_TO_BOTTOM : 0));
220    info->state_2d.dp_brush_frgd_clr = 0xffffffff;
221    info->state_2d.dp_brush_bkgd_clr = 0x00000000;
222    info->state_2d.dp_src_frgd_clr = 0xffffffff;
223    info->state_2d.dp_src_bkgd_clr = 0x00000000;
224    info->state_2d.dp_write_mask = planemask;
225    info->state_2d.dst_pitch_offset = dst_pitch_offset;
226    info->state_2d.src_pitch_offset = src_pitch_offset;
227    info->state_2d.default_sc_bottom_right =  (RADEON_DEFAULT_SC_RIGHT_MAX
228						| RADEON_DEFAULT_SC_BOTTOM_MAX);
229
230    Emit2DState(pScrn, RADEON_2D_EXA_COPY);
231}
232
233static Bool
234RADEONPrepareCopy(PixmapPtr pSrc,   PixmapPtr pDst,
235		  int xdir, int ydir,
236		  int rop,
237		  Pixel planemask)
238{
239    RINFO_FROM_SCREEN(pDst->drawable.pScreen);
240    uint32_t datatype, src_pitch_offset, dst_pitch_offset;
241    struct radeon_exa_pixmap_priv *driver_priv;
242    int ret;
243    TRACE;
244
245    if (pDst->drawable.bitsPerPixel == 24)
246	RADEON_FALLBACK(("24bpp unsupported"));
247    if (!RADEONGetDatatypeBpp(pDst->drawable.bitsPerPixel, &datatype))
248	RADEON_FALLBACK(("RADEONGetDatatypeBpp failed\n"));
249    if (!RADEONGetPixmapOffsetPitch(pSrc, &src_pitch_offset))
250	RADEON_FALLBACK(("RADEONGetPixmapOffsetPitch source failed\n"));
251    if (!RADEONGetPixmapOffsetPitch(pDst, &dst_pitch_offset))
252	RADEON_FALLBACK(("RADEONGetPixmapOffsetPitch dest failed\n"));
253
254    RADEON_SWITCH_TO_2D();
255
256    radeon_cs_space_reset_bos(info->cs);
257
258    driver_priv = exaGetPixmapDriverPrivate(pSrc);
259    radeon_cs_space_add_persistent_bo(info->cs, driver_priv->bo, RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM, 0);
260    info->state_2d.src_bo = driver_priv->bo;
261
262    driver_priv = exaGetPixmapDriverPrivate(pDst);
263    info->state_2d.dst_bo = driver_priv->bo;
264    info->state_2d.dst_domain = driver_priv->shared ? RADEON_GEM_DOMAIN_GTT : RADEON_GEM_DOMAIN_VRAM;
265    radeon_cs_space_add_persistent_bo(info->cs, driver_priv->bo, 0, info->state_2d.dst_domain);
266
267    ret = radeon_cs_space_check(info->cs);
268    if (ret)
269	RADEON_FALLBACK(("Not enough RAM to hw accel copy operation\n"));
270
271    info->accel_state->xdir = xdir;
272    info->accel_state->ydir = ydir;
273    info->accel_state->dst_pix = pDst;
274
275    RADEONDoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset,
276			datatype, rop, planemask);
277
278    return TRUE;
279}
280
281static void
282RADEONCopy(PixmapPtr pDst,
283	   int srcX, int srcY,
284	   int dstX, int dstY,
285	   int w, int h)
286{
287    RINFO_FROM_SCREEN(pDst->drawable.pScreen);
288
289    TRACE;
290
291    if (CS_FULL(info->cs)) {
292        RADEONFlush2D(info->accel_state->dst_pix);
293	radeon_cs_flush_indirect(pScrn);
294    }
295
296    if (info->accel_state->xdir < 0) {
297	srcX += w - 1;
298	dstX += w - 1;
299    }
300    if (info->accel_state->ydir < 0) {
301	srcY += h - 1;
302	dstY += h - 1;
303    }
304
305    if (info->accel_state->vsync)
306	RADEONWaitForVLine(pScrn, pDst,
307			   radeon_pick_best_crtc(pScrn, FALSE, dstX, dstX + w, dstY, dstY + h),
308			   dstY, dstY + h);
309
310    BEGIN_RING(2*3);
311
312    OUT_RING_REG(RADEON_SRC_Y_X,	   (srcY << 16) | srcX);
313    OUT_RING_REG(RADEON_DST_Y_X,	   (dstY << 16) | dstX);
314    OUT_RING_REG(RADEON_DST_HEIGHT_WIDTH, (h  << 16) | w);
315
316    ADVANCE_RING();
317}
318
319/* Emit blit with arbitrary source and destination offsets and pitches */
320static void
321RADEONBlitChunk(ScrnInfoPtr pScrn, struct radeon_bo *src_bo,
322                struct radeon_bo *dst_bo, uint32_t datatype,
323                uint32_t src_pitch_offset, uint32_t dst_pitch_offset,
324                int srcX, int srcY, int dstX, int dstY, int w, int h,
325                uint32_t src_domain, uint32_t dst_domain)
326{
327    RADEONInfoPtr info = RADEONPTR(pScrn);
328
329    if (src_bo && dst_bo) {
330        BEGIN_ACCEL_RELOC(6, 2);
331    } else if (src_bo && dst_bo == NULL) {
332        BEGIN_ACCEL_RELOC(6, 1);
333    } else {
334        BEGIN_RING(2*6);
335    }
336    OUT_RING_REG(RADEON_DP_GUI_MASTER_CNTL,
337		  RADEON_GMC_DST_PITCH_OFFSET_CNTL |
338		  RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
339		  RADEON_GMC_BRUSH_NONE |
340		  (datatype << 8) |
341		  RADEON_GMC_SRC_DATATYPE_COLOR |
342		  RADEON_ROP3_S |
343		  RADEON_DP_SRC_SOURCE_MEMORY |
344		  RADEON_GMC_CLR_CMP_CNTL_DIS |
345		  RADEON_GMC_WR_MSK_DIS);
346    OUT_RING_REG(RADEON_SRC_PITCH_OFFSET, src_pitch_offset);
347    if (src_bo) {
348	OUT_RING_RELOC(src_bo, src_domain, 0);
349    }
350    OUT_RING_REG(RADEON_DST_PITCH_OFFSET, dst_pitch_offset);
351    if (dst_bo) {
352	OUT_RING_RELOC(dst_bo, 0, dst_domain);
353    }
354    OUT_RING_REG(RADEON_SRC_Y_X, (srcY << 16) | srcX);
355    OUT_RING_REG(RADEON_DST_Y_X, (dstY << 16) | dstX);
356    OUT_RING_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | w);
357    ADVANCE_RING();
358    BEGIN_RING(2*2);
359    OUT_RING_REG(RADEON_DSTCACHE_CTLSTAT, RADEON_RB2D_DC_FLUSH_ALL);
360    OUT_RING_REG(RADEON_WAIT_UNTIL,
361                  RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_DMA_GUI_IDLE);
362    ADVANCE_RING();
363}
364
365static Bool
366RADEONUploadToScreenCS(PixmapPtr pDst, int x, int y, int w, int h,
367		       char *src, int src_pitch)
368{
369    ScreenPtr pScreen = pDst->drawable.pScreen;
370    RINFO_FROM_SCREEN(pScreen);
371    struct radeon_exa_pixmap_priv *driver_priv;
372    struct radeon_bo *scratch = NULL;
373    struct radeon_bo *copy_dst;
374    unsigned char *dst;
375    unsigned size;
376    uint32_t datatype = 0;
377    uint32_t dst_domain;
378    uint32_t dst_pitch_offset;
379    unsigned bpp = pDst->drawable.bitsPerPixel;
380    uint32_t scratch_pitch = RADEON_ALIGN(w * bpp / 8, 64);
381    uint32_t copy_pitch;
382    uint32_t swap = RADEON_HOST_DATA_SWAP_NONE;
383    int ret;
384    Bool flush = TRUE;
385    Bool r;
386    int i;
387
388    if (bpp < 8)
389	return FALSE;
390
391    driver_priv = exaGetPixmapDriverPrivate(pDst);
392    if (!driver_priv || !driver_priv->bo)
393	return FALSE;
394
395#if X_BYTE_ORDER == X_BIG_ENDIAN
396    switch (bpp) {
397    case 32:
398	swap = RADEON_HOST_DATA_SWAP_32BIT;
399	break;
400    case 16:
401	swap = RADEON_HOST_DATA_SWAP_16BIT;
402	break;
403    }
404#endif
405
406    /* If we know the BO won't be busy / in VRAM, don't bother with a scratch */
407    copy_dst = driver_priv->bo;
408    copy_pitch = pDst->devKind;
409    if (!(driver_priv->tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) {
410	if (!radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
411	    flush = FALSE;
412	    if (!radeon_bo_is_busy(driver_priv->bo, &dst_domain) &&
413		!(dst_domain & RADEON_GEM_DOMAIN_VRAM))
414		goto copy;
415	}
416	/* use cpu copy for fast fb access */
417	if (info->is_fast_fb)
418	    goto copy;
419    }
420
421    size = scratch_pitch * h;
422    scratch = radeon_bo_open(info->bufmgr, 0, size, 0, RADEON_GEM_DOMAIN_GTT, 0);
423    if (scratch == NULL) {
424	goto copy;
425    }
426    radeon_cs_space_reset_bos(info->cs);
427    radeon_add_pixmap(info->cs, pDst, 0, RADEON_GEM_DOMAIN_VRAM);
428    radeon_cs_space_add_persistent_bo(info->cs, scratch, RADEON_GEM_DOMAIN_GTT, 0);
429    ret = radeon_cs_space_check(info->cs);
430    if (ret) {
431	goto copy;
432    }
433    copy_dst = scratch;
434    copy_pitch = scratch_pitch;
435    flush = FALSE;
436
437copy:
438    if (flush)
439	radeon_cs_flush_indirect(pScrn);
440
441    ret = radeon_bo_map(copy_dst, 0);
442    if (ret) {
443        r = FALSE;
444        goto out;
445    }
446    r = TRUE;
447    size = w * bpp / 8;
448    dst = copy_dst->ptr;
449    if (copy_dst == driver_priv->bo)
450	dst += y * copy_pitch + x * bpp / 8;
451    for (i = 0; i < h; i++) {
452        RADEONCopySwap(dst + i * copy_pitch, (uint8_t*)src, size, swap);
453        src += src_pitch;
454    }
455    radeon_bo_unmap(copy_dst);
456
457    if (copy_dst == scratch) {
458	RADEONGetDatatypeBpp(pDst->drawable.bitsPerPixel, &datatype);
459	RADEONGetPixmapOffsetPitch(pDst, &dst_pitch_offset);
460	RADEON_SWITCH_TO_2D();
461	RADEONBlitChunk(pScrn, scratch, driver_priv->bo, datatype, scratch_pitch << 16,
462			dst_pitch_offset, 0, 0, x, y, w, h,
463			RADEON_GEM_DOMAIN_GTT, RADEON_GEM_DOMAIN_VRAM);
464    }
465
466out:
467    if (scratch)
468	radeon_bo_unref(scratch);
469    return r;
470}
471
472static Bool
473RADEONDownloadFromScreenCS(PixmapPtr pSrc, int x, int y, int w,
474                           int h, char *dst, int dst_pitch)
475{
476    RINFO_FROM_SCREEN(pSrc->drawable.pScreen);
477    struct radeon_exa_pixmap_priv *driver_priv;
478    struct radeon_bo *scratch = NULL;
479    struct radeon_bo *copy_src;
480    unsigned size;
481    uint32_t datatype = 0;
482    uint32_t src_domain = 0;
483    uint32_t src_pitch_offset;
484    unsigned bpp = pSrc->drawable.bitsPerPixel;
485    uint32_t scratch_pitch = RADEON_ALIGN(w * bpp / 8, 64);
486    uint32_t copy_pitch;
487    uint32_t swap = RADEON_HOST_DATA_SWAP_NONE;
488    int ret;
489    Bool flush = FALSE;
490    Bool r;
491
492    if (bpp < 8)
493	return FALSE;
494
495    driver_priv = exaGetPixmapDriverPrivate(pSrc);
496    if (!driver_priv || !driver_priv->bo)
497	return FALSE;
498
499#if X_BYTE_ORDER == X_BIG_ENDIAN
500    switch (bpp) {
501    case 32:
502	swap = RADEON_HOST_DATA_SWAP_32BIT;
503	break;
504    case 16:
505	swap = RADEON_HOST_DATA_SWAP_16BIT;
506	break;
507    }
508#endif
509
510    /* If we know the BO won't end up in VRAM anyway, don't bother with a scratch */
511    copy_src = driver_priv->bo;
512    copy_pitch = pSrc->devKind;
513    if (!(driver_priv->tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) {
514	if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
515	    src_domain = radeon_bo_get_src_domain(driver_priv->bo);
516	    if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
517		(RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
518		src_domain = 0;
519	    else /* A write may be scheduled */
520		flush = TRUE;
521	}
522
523	if (!src_domain)
524	    radeon_bo_is_busy(driver_priv->bo, &src_domain);
525
526	if (src_domain & ~(uint32_t)RADEON_GEM_DOMAIN_VRAM)
527	    goto copy;
528    }
529    size = scratch_pitch * h;
530    scratch = radeon_bo_open(info->bufmgr, 0, size, 0, RADEON_GEM_DOMAIN_GTT, 0);
531    if (scratch == NULL) {
532	goto copy;
533    }
534    radeon_cs_space_reset_bos(info->cs);
535    radeon_add_pixmap(info->cs, pSrc, RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM, 0);
536    radeon_cs_space_add_persistent_bo(info->cs, scratch, 0, RADEON_GEM_DOMAIN_GTT);
537    ret = radeon_cs_space_check(info->cs);
538    if (ret) {
539	goto copy;
540    }
541    RADEONGetDatatypeBpp(pSrc->drawable.bitsPerPixel, &datatype);
542    RADEONGetPixmapOffsetPitch(pSrc, &src_pitch_offset);
543    RADEON_SWITCH_TO_2D();
544    RADEONBlitChunk(pScrn, driver_priv->bo, scratch, datatype, src_pitch_offset,
545                    scratch_pitch << 16, x, y, 0, 0, w, h,
546                    RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT,
547                    RADEON_GEM_DOMAIN_GTT);
548    copy_src = scratch;
549    copy_pitch = scratch_pitch;
550    flush = TRUE;
551
552copy:
553    if (flush)
554	FLUSH_RING();
555
556    ret = radeon_bo_map(copy_src, 0);
557    if (ret) {
558	ErrorF("failed to map pixmap: %d\n", ret);
559        r = FALSE;
560        goto out;
561    }
562    r = TRUE;
563    w *= bpp / 8;
564    if (copy_src == driver_priv->bo)
565	size = y * copy_pitch + x * bpp / 8;
566    else
567	size = 0;
568    while (h--) {
569        RADEONCopySwap((uint8_t*)dst, copy_src->ptr + size, w, swap);
570        size += copy_pitch;
571        dst += dst_pitch;
572    }
573    radeon_bo_unmap(copy_src);
574out:
575    if (scratch)
576	radeon_bo_unref(scratch);
577    return r;
578}
579
580Bool RADEONDrawInit(ScreenPtr pScreen)
581{
582    RINFO_FROM_SCREEN(pScreen);
583
584    if (info->accel_state->exa == NULL) {
585	xf86DrvMsg(pScreen->myNum, X_ERROR, "Memory map not set up\n");
586	return FALSE;
587    }
588
589    info->accel_state->exa->exa_major = EXA_VERSION_MAJOR;
590    info->accel_state->exa->exa_minor = EXA_VERSION_MINOR;
591
592    info->accel_state->exa->PrepareSolid = RADEONPrepareSolid;
593    info->accel_state->exa->Solid = RADEONSolid;
594    info->accel_state->exa->DoneSolid = RADEONDone2D;
595
596    info->accel_state->exa->PrepareCopy = RADEONPrepareCopy;
597    info->accel_state->exa->Copy = RADEONCopy;
598    info->accel_state->exa->DoneCopy = RADEONDone2D;
599
600    info->accel_state->exa->MarkSync = RADEONMarkSync;
601    info->accel_state->exa->WaitMarker = RADEONSync;
602
603    info->accel_state->exa->UploadToScreen = &RADEONUploadToScreenCS;
604    info->accel_state->exa->DownloadFromScreen = &RADEONDownloadFromScreenCS;
605
606    info->accel_state->exa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_SUPPORTS_PREPARE_AUX |
607	EXA_SUPPORTS_OFFSCREEN_OVERLAPS | EXA_HANDLES_PIXMAPS | EXA_MIXED_PIXMAPS;
608    info->accel_state->exa->pixmapOffsetAlign = RADEON_GPU_PAGE_SIZE;
609    info->accel_state->exa->pixmapPitchAlign = 64;
610
611#ifdef RENDER
612    if (info->RenderAccel) {
613	if (IS_R300_3D || IS_R500_3D) {
614		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Render acceleration "
615			       "enabled for R300/R400/R500 type cards.\n");
616		info->accel_state->exa->CheckComposite = R300CheckComposite;
617		info->accel_state->exa->PrepareComposite =
618		    R300PrepareComposite;
619		info->accel_state->exa->Composite = RadeonComposite;
620		info->accel_state->exa->DoneComposite = RadeonDoneComposite;
621	} else if (IS_R200_3D) {
622		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Render acceleration "
623			       "enabled for R200 type cards.\n");
624		info->accel_state->exa->CheckComposite = R200CheckComposite;
625		info->accel_state->exa->PrepareComposite =
626		    R200PrepareComposite;
627		info->accel_state->exa->Composite = RadeonComposite;
628		info->accel_state->exa->DoneComposite = RadeonDoneComposite;
629	} else {
630		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Render acceleration "
631			       "enabled for R100 type cards.\n");
632		info->accel_state->exa->CheckComposite = R100CheckComposite;
633		info->accel_state->exa->PrepareComposite =
634		    R100PrepareComposite;
635		info->accel_state->exa->Composite = RadeonComposite;
636		info->accel_state->exa->DoneComposite = RadeonDoneComposite;
637	}
638    }
639#endif
640
641    info->accel_state->exa->CreatePixmap = RADEONEXACreatePixmap;
642    info->accel_state->exa->DestroyPixmap = RADEONEXADestroyPixmap;
643    info->accel_state->exa->PixmapIsOffscreen = RADEONEXAPixmapIsOffscreen;
644    info->accel_state->exa->PrepareAccess = RADEONPrepareAccess_CS;
645    info->accel_state->exa->FinishAccess = RADEONFinishAccess_CS;
646    info->accel_state->exa->CreatePixmap2 = RADEONEXACreatePixmap2;
647    info->accel_state->exa->SharePixmapBacking = RADEONEXASharePixmapBacking;
648    info->accel_state->exa->SetSharedPixmapBacking = RADEONEXASetSharedPixmapBacking;
649
650
651    info->accel_state->exa->maxPitchBytes = 16320;
652    info->accel_state->exa->maxX = 8191;
653    info->accel_state->exa->maxY = 8191;
654
655    if (xf86ReturnOptValBool(info->Options, OPTION_EXA_VSYNC, FALSE)) {
656	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EXA VSync enabled\n");
657	info->accel_state->vsync = TRUE;
658    } else
659	info->accel_state->vsync = FALSE;
660
661    RADEONEngineInit(pScrn);
662
663    if (!exaDriverInit(pScreen, info->accel_state->exa)) {
664	free(info->accel_state->exa);
665	return FALSE;
666    }
667    exaMarkSync(pScreen);
668
669    return TRUE;
670}
671
672