radeon_exa.c revision 68105dcb
1/*
2 * Copyright 2005 Eric Anholt
3 * Copyright 2005 Benjamin Herrenschmidt
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Authors:
26 *    Eric Anholt <anholt@FreeBSD.org>
27 *    Zack Rusin <zrusin@trolltech.com>
28 *    Benjamin Herrenschmidt <benh@kernel.crashing.org>
29 *
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include "radeon.h"
37#include "radeon_reg.h"
38#include "r600_reg.h"
39#ifdef XF86DRI
40#include "radeon_drm.h"
41#endif
42#include "radeon_macros.h"
43#include "radeon_probe.h"
44#include "radeon_version.h"
45#include "radeon_exa_shared.h"
46
47#include "xf86.h"
48
49
50/***********************************************************************/
51#define RINFO_FROM_SCREEN(pScr) ScrnInfoPtr pScrn =  xf86ScreenToScrn(pScr); \
52    RADEONInfoPtr info   = RADEONPTR(pScrn)
53
54static struct {
55    int rop;
56    int pattern;
57} RADEON_ROP[] = {
58    { RADEON_ROP3_ZERO, RADEON_ROP3_ZERO }, /* GXclear        */
59    { RADEON_ROP3_DSa,  RADEON_ROP3_DPa  }, /* Gxand          */
60    { RADEON_ROP3_SDna, RADEON_ROP3_PDna }, /* GXandReverse   */
61    { RADEON_ROP3_S,    RADEON_ROP3_P    }, /* GXcopy         */
62    { RADEON_ROP3_DSna, RADEON_ROP3_DPna }, /* GXandInverted  */
63    { RADEON_ROP3_D,    RADEON_ROP3_D    }, /* GXnoop         */
64    { RADEON_ROP3_DSx,  RADEON_ROP3_DPx  }, /* GXxor          */
65    { RADEON_ROP3_DSo,  RADEON_ROP3_DPo  }, /* GXor           */
66    { RADEON_ROP3_DSon, RADEON_ROP3_DPon }, /* GXnor          */
67    { RADEON_ROP3_DSxn, RADEON_ROP3_PDxn }, /* GXequiv        */
68    { RADEON_ROP3_Dn,   RADEON_ROP3_Dn   }, /* GXinvert       */
69    { RADEON_ROP3_SDno, RADEON_ROP3_PDno }, /* GXorReverse    */
70    { RADEON_ROP3_Sn,   RADEON_ROP3_Pn   }, /* GXcopyInverted */
71    { RADEON_ROP3_DSno, RADEON_ROP3_DPno }, /* GXorInverted   */
72    { RADEON_ROP3_DSan, RADEON_ROP3_DPan }, /* GXnand         */
73    { RADEON_ROP3_ONE,  RADEON_ROP3_ONE  }  /* GXset          */
74};
75
76/* Compute log base 2 of val. */
77static __inline__ int
78RADEONLog2(int val)
79{
80	int bits;
81#if (defined __i386__ || defined __x86_64__) && (defined __GNUC__)
82	__asm volatile("bsrl	%1, %0"
83		: "=r" (bits)
84		: "c" (val)
85	);
86	return bits;
87#else
88	for (bits = 0; val != 0; val >>= 1, ++bits)
89		;
90	return bits - 1;
91#endif
92}
93
94static __inline__ uint32_t F_TO_DW(float val)
95{
96    union {
97	float f;
98	uint32_t l;
99    } tmp;
100    tmp.f = val;
101    return tmp.l;
102}
103
104
105/* Assumes that depth 15 and 16 can be used as depth 16, which is okay since we
106 * require src and dest datatypes to be equal.
107 */
108Bool RADEONGetDatatypeBpp(int bpp, uint32_t *type)
109{
110	switch (bpp) {
111	case 8:
112		*type = ATI_DATATYPE_CI8;
113		return TRUE;
114	case 16:
115		*type = ATI_DATATYPE_RGB565;
116		return TRUE;
117	case 24:
118		*type = ATI_DATATYPE_CI8;
119		return TRUE;
120	case 32:
121		*type = ATI_DATATYPE_ARGB8888;
122		return TRUE;
123	default:
124		RADEON_FALLBACK(("Unsupported bpp: %d\n", bpp));
125		return FALSE;
126	}
127}
128
129static Bool RADEONPixmapIsColortiled(PixmapPtr pPix)
130{
131    RINFO_FROM_SCREEN(pPix->drawable.pScreen);
132
133#ifdef XF86DRM_MODE
134    if (info->cs) {
135	/* Taken care of by the kernel relocation handling */
136	return FALSE;
137    }
138#endif
139
140    /* This doesn't account for the back buffer, which we may want to wrap in
141     * a pixmap at some point for the purposes of DRI buffer moves.
142     */
143    if (info->tilingEnabled && exaGetPixmapOffset(pPix) == 0)
144	return TRUE;
145    else
146	return FALSE;
147}
148
149static Bool RADEONGetOffsetPitch(PixmapPtr pPix, int bpp, uint32_t *pitch_offset,
150				 unsigned int offset, unsigned int pitch)
151{
152	RINFO_FROM_SCREEN(pPix->drawable.pScreen);
153
154	if (pitch > 16320 || pitch % info->accel_state->exa->pixmapPitchAlign != 0)
155		RADEON_FALLBACK(("Bad pitch 0x%08x\n", pitch));
156
157	if (offset % info->accel_state->exa->pixmapOffsetAlign != 0)
158		RADEON_FALLBACK(("Bad offset 0x%08x\n", offset));
159
160	pitch = pitch >> 6;
161	*pitch_offset = (pitch << 22) | (offset >> 10);
162
163	/* If it's the front buffer, we've got to note that it's tiled? */
164	if (RADEONPixmapIsColortiled(pPix))
165		*pitch_offset |= RADEON_DST_TILE_MACRO;
166	return TRUE;
167}
168
169Bool RADEONGetPixmapOffsetPitch(PixmapPtr pPix, uint32_t *pitch_offset)
170{
171	uint32_t pitch, offset;
172	int bpp;
173
174	bpp = pPix->drawable.bitsPerPixel;
175	if (bpp == 24)
176		bpp = 8;
177
178	offset = radeonGetPixmapOffset(pPix);
179	pitch = exaGetPixmapPitch(pPix);
180
181	return RADEONGetOffsetPitch(pPix, bpp, pitch_offset, offset, pitch);
182}
183
184/**
185 * Returns whether the provided transform is affine.
186 *
187 * transform may be null.
188 */
189Bool radeon_transform_is_affine_or_scaled(PictTransformPtr t)
190{
191	if (t == NULL)
192		return TRUE;
193	/* the shaders don't handle scaling either */
194	return t->matrix[2][0] == 0 && t->matrix[2][1] == 0 && t->matrix[2][2] == IntToxFixed(1);
195}
196
197#if X_BYTE_ORDER == X_BIG_ENDIAN
198
199static unsigned long swapper_surfaces[6];
200
201static Bool RADEONPrepareAccess_BE(PixmapPtr pPix, int index)
202{
203    RINFO_FROM_SCREEN(pPix->drawable.pScreen);
204    unsigned char *RADEONMMIO = info->MMIO;
205    uint32_t offset = exaGetPixmapOffset(pPix);
206    int bpp, soff;
207    uint32_t size, flags;
208
209    /* Front buffer is always set with proper swappers */
210    if (offset == 0)
211        return TRUE;
212
213    /* If same bpp as front buffer, just do nothing as the main
214     * swappers will apply
215     */
216    bpp = pPix->drawable.bitsPerPixel;
217    if (bpp == pScrn->bitsPerPixel)
218        return TRUE;
219
220    /* We need to setup a separate swapper, let's request a
221     * surface. We need to align the size first
222     */
223    size = exaGetPixmapSize(pPix);
224    size = RADEON_ALIGN(size, RADEON_GPU_PAGE_SIZE);
225
226    /* Set surface to tiling disabled with appropriate swapper */
227    switch (bpp) {
228    case 16:
229        flags = RADEON_SURF_AP0_SWP_16BPP | RADEON_SURF_AP1_SWP_16BPP;
230	break;
231    case 32:
232        flags = RADEON_SURF_AP0_SWP_32BPP | RADEON_SURF_AP1_SWP_32BPP;
233	break;
234    default:
235        flags = 0;
236    }
237#if defined(XF86DRI)
238    if (info->directRenderingEnabled && info->allowColorTiling) {
239	struct drm_radeon_surface_alloc drmsurfalloc;
240	int rc;
241
242        drmsurfalloc.address = offset;
243        drmsurfalloc.size = size;
244	drmsurfalloc.flags = flags | 1; /* bogus pitch to please DRM */
245
246        rc = drmCommandWrite(info->dri->drmFD, DRM_RADEON_SURF_ALLOC,
247			     &drmsurfalloc, sizeof(drmsurfalloc));
248	if (rc < 0) {
249	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
250		       "drm: could not allocate surface for access"
251		       " swapper, err: %d!\n", rc);
252	    return FALSE;
253	}
254	swapper_surfaces[index] = offset;
255
256	return TRUE;
257    }
258#endif
259    soff = (index + 1) * 0x10;
260    OUTREG(RADEON_SURFACE0_INFO + soff, flags);
261    OUTREG(RADEON_SURFACE0_LOWER_BOUND + soff, offset);
262    OUTREG(RADEON_SURFACE0_UPPER_BOUND + soff, offset + size - 1);
263    swapper_surfaces[index] = offset;
264    return TRUE;
265}
266
267static void RADEONFinishAccess_BE(PixmapPtr pPix, int index)
268{
269    RINFO_FROM_SCREEN(pPix->drawable.pScreen);
270    unsigned char *RADEONMMIO = info->MMIO;
271    uint32_t offset = exaGetPixmapOffset(pPix);
272    int soff;
273
274    /* Front buffer is always set with proper swappers */
275    if (offset == 0)
276        return;
277
278    if (swapper_surfaces[index] == 0)
279        return;
280#if defined(XF86DRI)
281    if (info->directRenderingEnabled && info->allowColorTiling) {
282	struct drm_radeon_surface_free drmsurffree;
283
284	drmsurffree.address = offset;
285	drmCommandWrite(info->dri->drmFD, DRM_RADEON_SURF_FREE,
286			&drmsurffree, sizeof(drmsurffree));
287	swapper_surfaces[index] = 0;
288	return;
289    }
290#endif
291    soff = (index + 1) * 0x10;
292    OUTREG(RADEON_SURFACE0_INFO + soff, 0);
293    OUTREG(RADEON_SURFACE0_LOWER_BOUND + soff, 0);
294    OUTREG(RADEON_SURFACE0_UPPER_BOUND + soff, 0);
295    swapper_surfaces[index] = 0;
296}
297
298#endif /* X_BYTE_ORDER == X_BIG_ENDIAN */
299
300#ifdef XF86DRM_MODE
301Bool RADEONPrepareAccess_CS(PixmapPtr pPix, int index)
302{
303    ScreenPtr pScreen = pPix->drawable.pScreen;
304    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
305    RADEONInfoPtr info = RADEONPTR(pScrn);
306    struct radeon_exa_pixmap_priv *driver_priv;
307    uint32_t possible_domains = ~0U;
308    uint32_t current_domain = 0;
309#ifdef EXA_MIXED_PIXMAPS
310    Bool can_fail = !(pPix->drawable.bitsPerPixel < 8) &&
311	pPix != pScreen->GetScreenPixmap(pScreen) &&
312        (info->accel_state->exa->flags & EXA_MIXED_PIXMAPS);
313#else
314    Bool can_fail = FALSE;
315#endif
316    Bool flush = FALSE;
317    int ret;
318
319#if X_BYTE_ORDER == X_BIG_ENDIAN
320    /* May need to handle byte swapping in DownloadFrom/UploadToScreen */
321    if (can_fail && pPix->drawable.bitsPerPixel > 8)
322	return FALSE;
323#endif
324
325    driver_priv = exaGetPixmapDriverPrivate(pPix);
326    if (!driver_priv)
327      return FALSE;
328
329    /* untile in DFS/UTS */
330    if (driver_priv->tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))
331	return FALSE;
332
333    /* if we have more refs than just the BO then flush */
334    if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
335	flush = TRUE;
336
337	if (can_fail) {
338	    possible_domains = radeon_bo_get_src_domain(driver_priv->bo);
339	    if (possible_domains == RADEON_GEM_DOMAIN_VRAM)
340		return FALSE; /* use DownloadFromScreen */
341	}
342    }
343
344    /* if the BO might end up in VRAM, prefer DownloadFromScreen */
345    if (can_fail && (possible_domains & RADEON_GEM_DOMAIN_VRAM)) {
346	radeon_bo_is_busy(driver_priv->bo, &current_domain);
347
348	if (current_domain & possible_domains) {
349	    if (current_domain == RADEON_GEM_DOMAIN_VRAM)
350		return FALSE;
351	} else if (possible_domains & RADEON_GEM_DOMAIN_VRAM)
352	    return FALSE;
353    }
354
355    if (flush)
356        radeon_cs_flush_indirect(pScrn);
357
358    /* flush IB */
359    ret = radeon_bo_map(driver_priv->bo, 1);
360    if (ret) {
361      FatalError("failed to map pixmap %d\n", ret);
362      return FALSE;
363    }
364    driver_priv->bo_mapped = TRUE;
365
366    pPix->devPrivate.ptr = driver_priv->bo->ptr;
367
368    return TRUE;
369}
370
371void RADEONFinishAccess_CS(PixmapPtr pPix, int index)
372{
373    struct radeon_exa_pixmap_priv *driver_priv;
374
375    driver_priv = exaGetPixmapDriverPrivate(pPix);
376    if (!driver_priv || !driver_priv->bo_mapped)
377        return;
378
379    radeon_bo_unmap(driver_priv->bo);
380    driver_priv->bo_mapped = FALSE;
381    pPix->devPrivate.ptr = NULL;
382}
383
384
385void *RADEONEXACreatePixmap(ScreenPtr pScreen, int size, int align)
386{
387    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
388    RADEONInfoPtr info = RADEONPTR(pScrn);
389    struct radeon_exa_pixmap_priv *new_priv;
390
391#ifdef EXA_MIXED_PIXMAPS
392    if (info->accel_state->exa->flags & EXA_MIXED_PIXMAPS) {
393        if (size != 0 && !info->exa_force_create &&
394	    info->exa_pixmaps == FALSE)
395            return NULL;
396    }
397#endif
398
399    new_priv = calloc(1, sizeof(struct radeon_exa_pixmap_priv));
400    if (!new_priv)
401	return NULL;
402
403    if (size == 0)
404	return new_priv;
405
406    new_priv->bo = radeon_bo_open(info->bufmgr, 0, size, align,
407				  RADEON_GEM_DOMAIN_VRAM, 0);
408    if (!new_priv->bo) {
409	free(new_priv);
410	ErrorF("Failed to alloc memory\n");
411	return NULL;
412    }
413
414    return new_priv;
415
416}
417
418static const unsigned MicroBlockTable[5][3][2] = {
419    /*linear  tiled   square-tiled */
420    {{32, 1}, {8, 4}, {0, 0}}, /*   8 bits per pixel */
421    {{16, 1}, {8, 2}, {4, 4}}, /*  16 bits per pixel */
422    {{ 8, 1}, {4, 2}, {0, 0}}, /*  32 bits per pixel */
423    {{ 4, 1}, {0, 0}, {2, 2}}, /*  64 bits per pixel */
424    {{ 2, 1}, {0, 0}, {0, 0}}  /* 128 bits per pixel */
425};
426
427/* Return true if macrotiling can be enabled */
428static Bool RADEONMacroSwitch(int width, int height, int bpp,
429                              uint32_t flags, Bool rv350_mode)
430{
431    unsigned tilew, tileh, microtiled, logbpp;
432
433    logbpp = RADEONLog2(bpp / 8);
434    if (logbpp > 4)
435        return 0;
436
437    microtiled = !!(flags & RADEON_TILING_MICRO);
438    tilew = MicroBlockTable[logbpp][microtiled][0] * 8;
439    tileh = MicroBlockTable[logbpp][microtiled][1] * 8;
440
441    /* See TX_FILTER1_n.MACRO_SWITCH. */
442    if (rv350_mode) {
443        return width >= tilew && height >= tileh;
444    } else {
445        return width > tilew && height > tileh;
446    }
447}
448
449void *RADEONEXACreatePixmap2(ScreenPtr pScreen, int width, int height,
450			     int depth, int usage_hint, int bitsPerPixel,
451			     int *new_pitch)
452{
453    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
454    RADEONInfoPtr info = RADEONPTR(pScrn);
455    struct radeon_exa_pixmap_priv *new_priv;
456    int pitch, base_align;
457    uint32_t size, heighta;
458    uint32_t tiling = 0;
459    int cpp = bitsPerPixel / 8;
460#ifdef XF86DRM_MODE
461    struct radeon_surface surface;
462#endif
463
464#ifdef EXA_MIXED_PIXMAPS
465    if (info->accel_state->exa->flags & EXA_MIXED_PIXMAPS) {
466	if (width != 0 && height != 0 && !info->exa_force_create &&
467	    info->exa_pixmaps == FALSE)
468            return NULL;
469    }
470#endif
471
472    if (usage_hint) {
473	if (info->allowColorTiling) {
474    	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MACRO)
475 	   	tiling |= RADEON_TILING_MACRO;
476    	    if (usage_hint & RADEON_CREATE_PIXMAP_TILING_MICRO)
477                tiling |= RADEON_TILING_MICRO;
478	}
479	if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH)
480 	   	tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO;
481
482    }
483
484    /* Small pixmaps must not be macrotiled on R300, hw cannot sample them
485     * correctly because samplers automatically switch to macrolinear. */
486    if (info->ChipFamily >= CHIP_FAMILY_R300 &&
487        info->ChipFamily <= CHIP_FAMILY_RS740 &&
488        (tiling & RADEON_TILING_MACRO) &&
489        !RADEONMacroSwitch(width, height, bitsPerPixel, tiling,
490                           info->ChipFamily >= CHIP_FAMILY_RV350)) {
491        tiling &= ~RADEON_TILING_MACRO;
492    }
493
494    heighta = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, tiling));
495    pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, cpp, tiling)) * cpp;
496    base_align = drmmode_get_base_align(pScrn, cpp, tiling);
497    size = RADEON_ALIGN(heighta * pitch, RADEON_GPU_PAGE_SIZE);
498    memset(&surface, 0, sizeof(struct radeon_surface));
499
500#ifdef XF86DRM_MODE
501    if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
502		if (width) {
503			surface.npix_x = width;
504			/* need to align height to 8 for old kernel */
505			surface.npix_y = RADEON_ALIGN(height, 8);
506			surface.npix_z = 1;
507			surface.blk_w = 1;
508			surface.blk_h = 1;
509			surface.blk_d = 1;
510			surface.array_size = 1;
511			surface.last_level = 0;
512			surface.bpe = cpp;
513			surface.nsamples = 1;
514			if (height < 64) {
515				/* disable 2d tiling for small surface to work around
516				 * the fact that ddx align height to 8 pixel for old
517				 * obscure reason i can't remember
518				 */
519				tiling &= ~RADEON_TILING_MACRO;
520			}
521			surface.flags = RADEON_SURF_SCANOUT;
522			surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
523			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE);
524			if ((tiling & RADEON_TILING_MICRO)) {
525				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
526				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
527			}
528			if ((tiling & RADEON_TILING_MACRO)) {
529				surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
530				surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
531			}
532			if (usage_hint & RADEON_CREATE_PIXMAP_SZBUFFER) {
533				surface.flags |= RADEON_SURF_ZBUFFER;
534				surface.flags |= RADEON_SURF_SBUFFER;
535			}
536			if (radeon_surface_best(info->surf_man, &surface)) {
537				return NULL;
538			}
539			if (radeon_surface_init(info->surf_man, &surface)) {
540				return NULL;
541			}
542			size = surface.bo_size;
543			base_align = surface.bo_alignment;
544			pitch = surface.level[0].pitch_bytes;
545			tiling = 0;
546			switch (surface.level[0].mode) {
547			case RADEON_SURF_MODE_2D:
548				tiling |= RADEON_TILING_MACRO;
549				tiling |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT;
550				tiling |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT;
551				tiling |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT;
552				tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT;
553				tiling |= eg_tile_split(surface.stencil_tile_split) << RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT;
554				break;
555			case RADEON_SURF_MODE_1D:
556				tiling |= RADEON_TILING_MICRO;
557				break;
558			default:
559				break;
560			}
561		}
562	}
563#endif
564
565    new_priv = calloc(1, sizeof(struct radeon_exa_pixmap_priv));
566    if (!new_priv) {
567	return NULL;
568    }
569
570    if (size == 0) {
571	return new_priv;
572    }
573
574    *new_pitch = pitch;
575
576    new_priv->bo = radeon_bo_open(info->bufmgr, 0, size, base_align,
577				  RADEON_GEM_DOMAIN_VRAM, 0);
578    if (!new_priv->bo) {
579	free(new_priv);
580	ErrorF("Failed to alloc memory\n");
581	return NULL;
582    }
583
584    if (tiling && !radeon_bo_set_tiling(new_priv->bo, tiling, *new_pitch))
585	new_priv->tiling_flags = tiling;
586
587    new_priv->surface = surface;
588    return new_priv;
589}
590
591void RADEONEXADestroyPixmap(ScreenPtr pScreen, void *driverPriv)
592{
593    struct radeon_exa_pixmap_priv *driver_priv = driverPriv;
594
595    if (!driverPriv)
596      return;
597
598    if (driver_priv->bo)
599	radeon_bo_unref(driver_priv->bo);
600    free(driverPriv);
601}
602
603struct radeon_bo *radeon_get_pixmap_bo(PixmapPtr pPix)
604{
605    struct radeon_exa_pixmap_priv *driver_priv;
606    driver_priv = exaGetPixmapDriverPrivate(pPix);
607    return driver_priv->bo;
608}
609
610#if defined(XF86DRM_MODE)
611struct radeon_surface *radeon_get_pixmap_surface(PixmapPtr pPix)
612{
613    struct radeon_exa_pixmap_priv *driver_priv;
614    driver_priv = exaGetPixmapDriverPrivate(pPix);
615    return &driver_priv->surface;
616}
617#endif
618
619uint32_t radeon_get_pixmap_tiling(PixmapPtr pPix)
620{
621    struct radeon_exa_pixmap_priv *driver_priv;
622    driver_priv = exaGetPixmapDriverPrivate(pPix);
623    return driver_priv->tiling_flags;
624}
625
626void radeon_set_pixmap_bo(PixmapPtr pPix, struct radeon_bo *bo)
627{
628    struct radeon_exa_pixmap_priv *driver_priv;
629
630    driver_priv = exaGetPixmapDriverPrivate(pPix);
631    if (driver_priv) {
632	uint32_t pitch;
633
634	if (driver_priv->bo)
635	    radeon_bo_unref(driver_priv->bo);
636
637	radeon_bo_ref(bo);
638	driver_priv->bo = bo;
639
640	radeon_bo_get_tiling(bo, &driver_priv->tiling_flags, &pitch);
641    }
642}
643
644Bool RADEONEXAPixmapIsOffscreen(PixmapPtr pPix)
645{
646    struct radeon_exa_pixmap_priv *driver_priv;
647
648    driver_priv = exaGetPixmapDriverPrivate(pPix);
649
650    if (!driver_priv)
651       return FALSE;
652    if (driver_priv->bo)
653       return TRUE;
654    return FALSE;
655}
656#endif
657
658#define ENTER_DRAW(x) TRACE
659#define LEAVE_DRAW(x) TRACE
660/***********************************************************************/
661
662#define ACCEL_MMIO
663#define ACCEL_PREAMBLE()	unsigned char *RADEONMMIO = info->MMIO
664#define BEGIN_ACCEL(n)		RADEONWaitForFifo(pScrn, (n))
665#define OUT_ACCEL_REG(reg, val)	OUTREG(reg, val)
666#define OUT_ACCEL_REG_F(reg, val) OUTREG(reg, F_TO_DW(val))
667#define OUT_RELOC(x, read, write)            do {} while(0)
668#define FINISH_ACCEL()
669
670#ifdef RENDER
671#include "radeon_exa_render.c"
672#endif
673#include "radeon_exa_funcs.c"
674
675#undef ACCEL_MMIO
676#undef ACCEL_PREAMBLE
677#undef BEGIN_ACCEL
678#undef OUT_ACCEL_REG
679#undef OUT_ACCEL_REG_F
680#undef FINISH_ACCEL
681#undef OUT_RELOC
682
683#ifdef XF86DRI
684
685#define ACCEL_CP
686#define ACCEL_PREAMBLE()						\
687    RING_LOCALS;							\
688    RADEONCP_REFRESH(pScrn, info)
689#define BEGIN_ACCEL(n)		BEGIN_RING(2*(n))
690#define OUT_ACCEL_REG(reg, val)	OUT_RING_REG(reg, val)
691#define FINISH_ACCEL()		ADVANCE_RING()
692#define OUT_RELOC(x, read, write) OUT_RING_RELOC(x, read, write)
693
694#define OUT_RING_F(x) OUT_RING(F_TO_DW(x))
695
696#ifdef RENDER
697#include "radeon_exa_render.c"
698#endif
699#include "radeon_exa_funcs.c"
700
701#undef ACCEL_CP
702#undef ACCEL_PREAMBLE
703#undef BEGIN_ACCEL
704#undef OUT_ACCEL_REG
705#undef FINISH_ACCEL
706#undef OUT_RING_F
707
708#endif /* XF86DRI */
709
710/*
711 * Once screen->off_screen_base is set, this function
712 * allocates the remaining memory appropriately
713 */
714Bool RADEONSetupMemEXA (ScreenPtr pScreen)
715{
716    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
717    RADEONInfoPtr info = RADEONPTR(pScrn);
718    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
719    int cpp = info->CurrentLayout.pixel_bytes;
720    int screen_size;
721    int byteStride = pScrn->displayWidth * cpp;
722
723    if (info->accel_state->exa != NULL) {
724	xf86DrvMsg(pScreen->myNum, X_ERROR, "Memory map already initialized\n");
725	return FALSE;
726    }
727    info->accel_state->exa = exaDriverAlloc();
728    if (info->accel_state->exa == NULL)
729	return FALSE;
730
731    /* Need to adjust screen size for 16 line tiles, and then make it align to.
732     * the buffer alignment requirement.
733     */
734    if (info->allowColorTiling)
735	screen_size = RADEON_ALIGN(pScrn->virtualY, 16) * byteStride;
736    else
737	screen_size = pScrn->virtualY * byteStride;
738
739    info->accel_state->exa->memoryBase = info->FB;
740    info->accel_state->exa->memorySize = info->FbMapSize - info->FbSecureSize;
741    info->accel_state->exa->offScreenBase = screen_size;
742
743    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Allocating from a screen of %ld kb\n",
744	       info->accel_state->exa->memorySize / 1024);
745
746    /* Reserve static area for hardware cursor */
747    if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
748        int cursor_size = 64 * 4 * 64;
749        int align = IS_AVIVO_VARIANT ? 4096 : 256;
750        int c;
751
752        for (c = 0; c < xf86_config->num_crtc; c++) {
753            xf86CrtcPtr crtc = xf86_config->crtc[c];
754            RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
755
756            radeon_crtc->cursor_offset =
757                RADEON_ALIGN(info->accel_state->exa->offScreenBase, align);
758            info->accel_state->exa->offScreenBase = radeon_crtc->cursor_offset + cursor_size;
759
760            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
761                       "Will use %d kb for hardware cursor %d at offset 0x%08x\n",
762                       (cursor_size * xf86_config->num_crtc) / 1024,
763                       c,
764                       (unsigned int)radeon_crtc->cursor_offset);
765        }
766    }
767
768#if defined(XF86DRI)
769    if (info->directRenderingEnabled) {
770	int depthCpp = (info->dri->depthBits - 8) / 4, l, next, depth_size;
771
772	info->dri->frontOffset = 0;
773	info->dri->frontPitch = pScrn->displayWidth;
774
775        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
776	       "Will use %d kb for front buffer at offset 0x%08x\n",
777	       screen_size / 1024, info->dri->frontOffset);
778	RADEONDRIAllocatePCIGARTTable(pScreen);
779
780	if (info->cardType==CARD_PCIE)
781	  xf86DrvMsg(pScrn->scrnIndex, X_INFO,
782		     "Will use %d kb for PCI GART at offset 0x%08x\n",
783		     info->dri->pciGartSize / 1024,
784		     (int)info->dri->pciGartOffset);
785
786	/* Reserve a static area for the back buffer the same size as the
787	 * visible screen.  XXX: This would be better initialized in ati_dri.c
788	 * when GLX is set up, but the offscreen memory manager's allocations
789	 * don't last through VT switches, while the kernel's understanding of
790	 * offscreen locations does.
791	 */
792	info->dri->backPitch = pScrn->displayWidth;
793	next = RADEON_ALIGN(info->accel_state->exa->offScreenBase, RADEON_GPU_PAGE_SIZE);
794	if (!info->dri->noBackBuffer &&
795	    next + screen_size <= info->accel_state->exa->memorySize)
796	{
797	    info->dri->backOffset = next;
798	    info->accel_state->exa->offScreenBase = next + screen_size;
799	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
800		       "Will use %d kb for back buffer at offset 0x%08x\n",
801		       screen_size / 1024, info->dri->backOffset);
802	}
803
804	/* Reserve the static depth buffer, and adjust pitch and height to
805	 * handle tiling.
806	 */
807	info->dri->depthPitch = RADEON_ALIGN(pScrn->displayWidth, 32);
808	depth_size = RADEON_ALIGN(pScrn->virtualY, 16) * info->dri->depthPitch * depthCpp;
809	next = RADEON_ALIGN(info->accel_state->exa->offScreenBase, RADEON_GPU_PAGE_SIZE);
810	if (next + depth_size <= info->accel_state->exa->memorySize)
811	{
812	    info->dri->depthOffset = next;
813	    info->accel_state->exa->offScreenBase = next + depth_size;
814	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
815		       "Will use %d kb for depth buffer at offset 0x%08x\n",
816		       depth_size / 1024, info->dri->depthOffset);
817	}
818
819	info->dri->textureSize *= (info->accel_state->exa->memorySize -
820				   info->accel_state->exa->offScreenBase) / 100;
821
822	l = RADEONLog2(info->dri->textureSize / RADEON_NR_TEX_REGIONS);
823	if (l < RADEON_LOG_TEX_GRANULARITY)
824	    l = RADEON_LOG_TEX_GRANULARITY;
825	info->dri->textureSize = (info->dri->textureSize >> l) << l;
826	if (info->dri->textureSize >= 512 * 1024) {
827	    info->dri->textureOffset = info->accel_state->exa->offScreenBase;
828	    info->accel_state->exa->offScreenBase += info->dri->textureSize;
829	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
830		       "Will use %d kb for textures at offset 0x%08x\n",
831		       info->dri->textureSize / 1024, info->dri->textureOffset);
832	} else {
833	    /* Minimum texture size is for 2 256x256x32bpp textures */
834	    info->dri->textureSize = 0;
835	}
836    } else
837#endif /* XF86DRI */
838    	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
839		       "Will use %d kb for front buffer at offset 0x%08x\n",
840		       screen_size / 1024, 0);
841
842    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
843	       "Will use %ld kb for X Server offscreen at offset 0x%08lx\n",
844	       (info->accel_state->exa->memorySize - info->accel_state->exa->offScreenBase) /
845	       1024, info->accel_state->exa->offScreenBase);
846
847    return TRUE;
848}
849
850#ifdef XF86DRI
851
852#ifndef ExaOffscreenMarkUsed
853extern void ExaOffscreenMarkUsed(PixmapPtr);
854#endif
855
856unsigned long long
857RADEONTexOffsetStart(PixmapPtr pPix)
858{
859    RINFO_FROM_SCREEN(pPix->drawable.pScreen);
860    unsigned long long offset;
861
862    if (exaGetPixmapDriverPrivate(pPix))
863	return -1;
864
865    exaMoveInPixmap(pPix);
866    ExaOffscreenMarkUsed(pPix);
867
868    offset = exaGetPixmapOffset(pPix);
869
870    if (offset > info->FbMapSize)
871	return ~0ULL;
872    else
873	return info->fbLocation + offset;
874}
875#endif
876