1de2362d3Smrg/*
2de2362d3Smrg * Copyright 2005 Eric Anholt
3de2362d3Smrg * Copyright 2005 Benjamin Herrenschmidt
4de2362d3Smrg * All Rights Reserved.
5de2362d3Smrg *
6de2362d3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7de2362d3Smrg * copy of this software and associated documentation files (the "Software"),
8de2362d3Smrg * to deal in the Software without restriction, including without limitation
9de2362d3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10de2362d3Smrg * and/or sell copies of the Software, and to permit persons to whom the
11de2362d3Smrg * Software is furnished to do so, subject to the following conditions:
12de2362d3Smrg *
13de2362d3Smrg * The above copyright notice and this permission notice (including the next
14de2362d3Smrg * paragraph) shall be included in all copies or substantial portions of the
15de2362d3Smrg * Software.
16de2362d3Smrg *
17de2362d3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18de2362d3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19de2362d3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20de2362d3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21de2362d3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22de2362d3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23de2362d3Smrg * SOFTWARE.
24de2362d3Smrg *
25de2362d3Smrg * Authors:
26de2362d3Smrg *    Eric Anholt <anholt@FreeBSD.org>
27de2362d3Smrg *    Zack Rusin <zrusin@trolltech.com>
28de2362d3Smrg *    Benjamin Herrenschmidt <benh@kernel.crashing.org>
29de2362d3Smrg *
30de2362d3Smrg */
31de2362d3Smrg
32de2362d3Smrg#ifdef HAVE_CONFIG_H
33de2362d3Smrg#include "config.h"
34de2362d3Smrg#endif
35de2362d3Smrg
36de2362d3Smrg#include "radeon.h"
37de2362d3Smrg#include "radeon_reg.h"
38de2362d3Smrg#include "r600_reg.h"
3918781e08Smrg#include "radeon_bo_helper.h"
40de2362d3Smrg#include "radeon_probe.h"
41de2362d3Smrg#include "radeon_version.h"
42de2362d3Smrg#include "radeon_exa_shared.h"
43de2362d3Smrg#include "xf86.h"
44de2362d3Smrg
45de2362d3Smrg
46de2362d3Smrg/***********************************************************************/
47de2362d3Smrg#define RINFO_FROM_SCREEN(pScr) ScrnInfoPtr pScrn =  xf86ScreenToScrn(pScr); \
48de2362d3Smrg    RADEONInfoPtr info   = RADEONPTR(pScrn)
49de2362d3Smrg
50de2362d3Smrgstatic struct {
51de2362d3Smrg    int rop;
52de2362d3Smrg    int pattern;
53de2362d3Smrg} RADEON_ROP[] = {
54de2362d3Smrg    { RADEON_ROP3_ZERO, RADEON_ROP3_ZERO }, /* GXclear        */
55de2362d3Smrg    { RADEON_ROP3_DSa,  RADEON_ROP3_DPa  }, /* Gxand          */
56de2362d3Smrg    { RADEON_ROP3_SDna, RADEON_ROP3_PDna }, /* GXandReverse   */
57de2362d3Smrg    { RADEON_ROP3_S,    RADEON_ROP3_P    }, /* GXcopy         */
58de2362d3Smrg    { RADEON_ROP3_DSna, RADEON_ROP3_DPna }, /* GXandInverted  */
59de2362d3Smrg    { RADEON_ROP3_D,    RADEON_ROP3_D    }, /* GXnoop         */
60de2362d3Smrg    { RADEON_ROP3_DSx,  RADEON_ROP3_DPx  }, /* GXxor          */
61de2362d3Smrg    { RADEON_ROP3_DSo,  RADEON_ROP3_DPo  }, /* GXor           */
62de2362d3Smrg    { RADEON_ROP3_DSon, RADEON_ROP3_DPon }, /* GXnor          */
63de2362d3Smrg    { RADEON_ROP3_DSxn, RADEON_ROP3_PDxn }, /* GXequiv        */
64de2362d3Smrg    { RADEON_ROP3_Dn,   RADEON_ROP3_Dn   }, /* GXinvert       */
65de2362d3Smrg    { RADEON_ROP3_SDno, RADEON_ROP3_PDno }, /* GXorReverse    */
66de2362d3Smrg    { RADEON_ROP3_Sn,   RADEON_ROP3_Pn   }, /* GXcopyInverted */
67de2362d3Smrg    { RADEON_ROP3_DSno, RADEON_ROP3_DPno }, /* GXorInverted   */
68de2362d3Smrg    { RADEON_ROP3_DSan, RADEON_ROP3_DPan }, /* GXnand         */
69de2362d3Smrg    { RADEON_ROP3_ONE,  RADEON_ROP3_ONE  }  /* GXset          */
70de2362d3Smrg};
71de2362d3Smrg
72de2362d3Smrgstatic __inline__ uint32_t F_TO_DW(float val)
73de2362d3Smrg{
74de2362d3Smrg    union {
75de2362d3Smrg	float f;
76de2362d3Smrg	uint32_t l;
77de2362d3Smrg    } tmp;
78de2362d3Smrg    tmp.f = val;
79de2362d3Smrg    return tmp.l;
80de2362d3Smrg}
81de2362d3Smrg
82de2362d3Smrg
83de2362d3Smrg/* Assumes that depth 15 and 16 can be used as depth 16, which is okay since we
84de2362d3Smrg * require src and dest datatypes to be equal.
85de2362d3Smrg */
86de2362d3SmrgBool RADEONGetDatatypeBpp(int bpp, uint32_t *type)
87de2362d3Smrg{
88de2362d3Smrg	switch (bpp) {
89de2362d3Smrg	case 8:
90de2362d3Smrg		*type = ATI_DATATYPE_CI8;
91de2362d3Smrg		return TRUE;
92de2362d3Smrg	case 16:
93de2362d3Smrg		*type = ATI_DATATYPE_RGB565;
94de2362d3Smrg		return TRUE;
95de2362d3Smrg	case 24:
96de2362d3Smrg		*type = ATI_DATATYPE_CI8;
97de2362d3Smrg		return TRUE;
98de2362d3Smrg	case 32:
99de2362d3Smrg		*type = ATI_DATATYPE_ARGB8888;
100de2362d3Smrg		return TRUE;
101de2362d3Smrg	default:
102de2362d3Smrg		RADEON_FALLBACK(("Unsupported bpp: %d\n", bpp));
103de2362d3Smrg		return FALSE;
104de2362d3Smrg	}
105de2362d3Smrg}
106de2362d3Smrg
107de2362d3Smrgstatic Bool RADEONPixmapIsColortiled(PixmapPtr pPix)
108de2362d3Smrg{
10918781e08Smrg    return FALSE;
110de2362d3Smrg}
111de2362d3Smrg
112de2362d3Smrgstatic Bool RADEONGetOffsetPitch(PixmapPtr pPix, int bpp, uint32_t *pitch_offset,
113de2362d3Smrg				 unsigned int offset, unsigned int pitch)
114de2362d3Smrg{
115de2362d3Smrg	RINFO_FROM_SCREEN(pPix->drawable.pScreen);
116de2362d3Smrg
117de2362d3Smrg	if (pitch > 16320 || pitch % info->accel_state->exa->pixmapPitchAlign != 0)
118de2362d3Smrg		RADEON_FALLBACK(("Bad pitch 0x%08x\n", pitch));
119de2362d3Smrg
120de2362d3Smrg	if (offset % info->accel_state->exa->pixmapOffsetAlign != 0)
121de2362d3Smrg		RADEON_FALLBACK(("Bad offset 0x%08x\n", offset));
122de2362d3Smrg
123de2362d3Smrg	pitch = pitch >> 6;
124de2362d3Smrg	*pitch_offset = (pitch << 22) | (offset >> 10);
125de2362d3Smrg
126de2362d3Smrg	/* If it's the front buffer, we've got to note that it's tiled? */
127de2362d3Smrg	if (RADEONPixmapIsColortiled(pPix))
128de2362d3Smrg		*pitch_offset |= RADEON_DST_TILE_MACRO;
129de2362d3Smrg	return TRUE;
130de2362d3Smrg}
131de2362d3Smrg
132de2362d3SmrgBool RADEONGetPixmapOffsetPitch(PixmapPtr pPix, uint32_t *pitch_offset)
133de2362d3Smrg{
13418781e08Smrg	uint32_t pitch;
135de2362d3Smrg	int bpp;
136de2362d3Smrg
137de2362d3Smrg	bpp = pPix->drawable.bitsPerPixel;
138de2362d3Smrg	if (bpp == 24)
139de2362d3Smrg		bpp = 8;
140de2362d3Smrg
141de2362d3Smrg	pitch = exaGetPixmapPitch(pPix);
142de2362d3Smrg
14318781e08Smrg	return RADEONGetOffsetPitch(pPix, bpp, pitch_offset, 0, pitch);
144de2362d3Smrg}
145de2362d3Smrg
146de2362d3Smrg/**
147de2362d3Smrg * Returns whether the provided transform is affine.
148de2362d3Smrg *
149de2362d3Smrg * transform may be null.
150de2362d3Smrg */
151de2362d3SmrgBool radeon_transform_is_affine_or_scaled(PictTransformPtr t)
152de2362d3Smrg{
15339413783Smrg	if (!t)
154de2362d3Smrg		return TRUE;
155de2362d3Smrg	/* the shaders don't handle scaling either */
156de2362d3Smrg	return t->matrix[2][0] == 0 && t->matrix[2][1] == 0 && t->matrix[2][2] == IntToxFixed(1);
157de2362d3Smrg}
158de2362d3Smrg
159de2362d3SmrgBool RADEONPrepareAccess_CS(PixmapPtr pPix, int index)
160de2362d3Smrg{
161de2362d3Smrg    ScreenPtr pScreen = pPix->drawable.pScreen;
162de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
163de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
164de2362d3Smrg    struct radeon_exa_pixmap_priv *driver_priv;
165de2362d3Smrg    uint32_t possible_domains = ~0U;
166de2362d3Smrg    uint32_t current_domain = 0;
167de2362d3Smrg    Bool can_fail = !(pPix->drawable.bitsPerPixel < 8) &&
16818781e08Smrg	pPix != pScreen->GetScreenPixmap(pScreen);
169de2362d3Smrg    Bool flush = FALSE;
170de2362d3Smrg    int ret;
171de2362d3Smrg
172de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
173de2362d3Smrg    /* May need to handle byte swapping in DownloadFrom/UploadToScreen */
17418781e08Smrg    if (pPix->drawable.bitsPerPixel > 8)
175de2362d3Smrg	return FALSE;
176de2362d3Smrg#endif
177de2362d3Smrg
178de2362d3Smrg    driver_priv = exaGetPixmapDriverPrivate(pPix);
179de2362d3Smrg    if (!driver_priv)
180de2362d3Smrg      return FALSE;
181de2362d3Smrg
182de2362d3Smrg    /* untile in DFS/UTS */
183de2362d3Smrg    if (driver_priv->tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))
184de2362d3Smrg	return FALSE;
185de2362d3Smrg
186de2362d3Smrg    /* if we have more refs than just the BO then flush */
18739413783Smrg    if (radeon_bo_is_referenced_by_cs(driver_priv->bo->bo.radeon, info->cs)) {
188de2362d3Smrg	flush = TRUE;
189de2362d3Smrg
190de2362d3Smrg	if (can_fail) {
19139413783Smrg	    possible_domains = radeon_bo_get_src_domain(driver_priv->bo->bo.radeon);
192de2362d3Smrg	    if (possible_domains == RADEON_GEM_DOMAIN_VRAM)
193de2362d3Smrg		return FALSE; /* use DownloadFromScreen */
194de2362d3Smrg	}
195de2362d3Smrg    }
196de2362d3Smrg
197de2362d3Smrg    /* if the BO might end up in VRAM, prefer DownloadFromScreen */
198de2362d3Smrg    if (can_fail && (possible_domains & RADEON_GEM_DOMAIN_VRAM)) {
19939413783Smrg	radeon_bo_is_busy(driver_priv->bo->bo.radeon, &current_domain);
200de2362d3Smrg
201de2362d3Smrg	if (current_domain & possible_domains) {
202de2362d3Smrg	    if (current_domain == RADEON_GEM_DOMAIN_VRAM)
203de2362d3Smrg		return FALSE;
204de2362d3Smrg	} else if (possible_domains & RADEON_GEM_DOMAIN_VRAM)
205de2362d3Smrg	    return FALSE;
206de2362d3Smrg    }
207de2362d3Smrg
208de2362d3Smrg    if (flush)
209de2362d3Smrg        radeon_cs_flush_indirect(pScrn);
210de2362d3Smrg
211de2362d3Smrg    /* flush IB */
21239413783Smrg    ret = radeon_bo_map(driver_priv->bo->bo.radeon, 1);
213de2362d3Smrg    if (ret) {
214de2362d3Smrg      FatalError("failed to map pixmap %d\n", ret);
215de2362d3Smrg      return FALSE;
216de2362d3Smrg    }
217de2362d3Smrg    driver_priv->bo_mapped = TRUE;
218de2362d3Smrg
21939413783Smrg    pPix->devPrivate.ptr = driver_priv->bo->bo.radeon->ptr;
220de2362d3Smrg
221de2362d3Smrg    return TRUE;
222de2362d3Smrg}
223de2362d3Smrg
224de2362d3Smrgvoid RADEONFinishAccess_CS(PixmapPtr pPix, int index)
225de2362d3Smrg{
226de2362d3Smrg    struct radeon_exa_pixmap_priv *driver_priv;
227de2362d3Smrg
228de2362d3Smrg    driver_priv = exaGetPixmapDriverPrivate(pPix);
229de2362d3Smrg    if (!driver_priv || !driver_priv->bo_mapped)
230de2362d3Smrg        return;
231de2362d3Smrg
23239413783Smrg    radeon_bo_unmap(driver_priv->bo->bo.radeon);
233de2362d3Smrg    driver_priv->bo_mapped = FALSE;
234de2362d3Smrg    pPix->devPrivate.ptr = NULL;
235de2362d3Smrg}
236de2362d3Smrg
237de2362d3Smrg
238de2362d3Smrgvoid *RADEONEXACreatePixmap2(ScreenPtr pScreen, int width, int height,
239de2362d3Smrg			     int depth, int usage_hint, int bitsPerPixel,
240de2362d3Smrg			     int *new_pitch)
241de2362d3Smrg{
242de2362d3Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
243de2362d3Smrg    RADEONInfoPtr info = RADEONPTR(pScrn);
244de2362d3Smrg    struct radeon_exa_pixmap_priv *new_priv;
245de2362d3Smrg
24618781e08Smrg    if (width != 0 && height != 0 && !info->exa_force_create &&
24718781e08Smrg	info->exa_pixmaps == FALSE)
24818781e08Smrg        return NULL;
249de2362d3Smrg
250de2362d3Smrg    new_priv = calloc(1, sizeof(struct radeon_exa_pixmap_priv));
251de2362d3Smrg    if (!new_priv) {
252de2362d3Smrg	return NULL;
253de2362d3Smrg    }
254de2362d3Smrg
25518781e08Smrg    if (width == 0 || height == 0) {
256de2362d3Smrg	return new_priv;
257de2362d3Smrg    }
258de2362d3Smrg
25918781e08Smrg    new_priv->bo = radeon_alloc_pixmap_bo(pScrn, width, height, depth,
26018781e08Smrg					  usage_hint, bitsPerPixel, new_pitch,
26118781e08Smrg					  &new_priv->surface,
26218781e08Smrg					  &new_priv->tiling_flags);
263de2362d3Smrg    if (!new_priv->bo) {
264de2362d3Smrg	free(new_priv);
265de2362d3Smrg	ErrorF("Failed to alloc memory\n");
266de2362d3Smrg	return NULL;
267de2362d3Smrg    }
268de2362d3Smrg
269de2362d3Smrg    return new_priv;
270de2362d3Smrg}
271de2362d3Smrg
272de2362d3Smrgvoid RADEONEXADestroyPixmap(ScreenPtr pScreen, void *driverPriv)
273de2362d3Smrg{
2748bf5c682Smrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(xf86ScreenToScrn(pScreen));
275de2362d3Smrg    struct radeon_exa_pixmap_priv *driver_priv = driverPriv;
276de2362d3Smrg
277de2362d3Smrg    if (!driverPriv)
278de2362d3Smrg      return;
279de2362d3Smrg
28039413783Smrg    radeon_buffer_unref(&driver_priv->bo);
2818bf5c682Smrg    drmmode_fb_reference(pRADEONEnt->fd, &driver_priv->fb, NULL);
282de2362d3Smrg    free(driverPriv);
283de2362d3Smrg}
284de2362d3Smrg
2850a1d3ae0SmrgBool RADEONEXASharePixmapBacking(PixmapPtr ppix, ScreenPtr seconndary, void **fd_handle)
286de2362d3Smrg{
28718781e08Smrg    struct radeon_exa_pixmap_priv *driver_priv = exaGetPixmapDriverPrivate(ppix);
28818781e08Smrg
28939413783Smrg    if (!radeon_share_pixmap_backing(driver_priv->bo->bo.radeon, fd_handle))
29018781e08Smrg	return FALSE;
29118781e08Smrg
29218781e08Smrg    driver_priv->shared = TRUE;
29318781e08Smrg    return TRUE;
294de2362d3Smrg}
295de2362d3Smrg
29618781e08SmrgBool RADEONEXASetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle)
297de2362d3Smrg{
29818781e08Smrg    struct radeon_exa_pixmap_priv *driver_priv = exaGetPixmapDriverPrivate(ppix);
29939413783Smrg    int ihandle = (int)(long)fd_handle;
30018781e08Smrg
30118781e08Smrg    if (!radeon_set_shared_pixmap_backing(ppix, fd_handle, &driver_priv->surface))
30218781e08Smrg	return FALSE;
30318781e08Smrg
30439413783Smrg    driver_priv->shared = ihandle != -1;
30518781e08Smrg    return TRUE;
306de2362d3Smrg}
307de2362d3Smrg
308de2362d3Smrguint32_t radeon_get_pixmap_tiling(PixmapPtr pPix)
309de2362d3Smrg{
310de2362d3Smrg    struct radeon_exa_pixmap_priv *driver_priv;
311de2362d3Smrg    driver_priv = exaGetPixmapDriverPrivate(pPix);
312de2362d3Smrg    return driver_priv->tiling_flags;
313de2362d3Smrg}
314de2362d3Smrg
315de2362d3SmrgBool RADEONEXAPixmapIsOffscreen(PixmapPtr pPix)
316de2362d3Smrg{
317de2362d3Smrg    struct radeon_exa_pixmap_priv *driver_priv;
318de2362d3Smrg
319de2362d3Smrg    driver_priv = exaGetPixmapDriverPrivate(pPix);
320de2362d3Smrg
321de2362d3Smrg    if (!driver_priv)
322de2362d3Smrg       return FALSE;
323de2362d3Smrg    if (driver_priv->bo)
324de2362d3Smrg       return TRUE;
325de2362d3Smrg    return FALSE;
326de2362d3Smrg}
327de2362d3Smrg
328de2362d3Smrg#define ENTER_DRAW(x) TRACE
329de2362d3Smrg#define LEAVE_DRAW(x) TRACE
330de2362d3Smrg/***********************************************************************/
331de2362d3Smrg
332de2362d3Smrg#ifdef RENDER
333de2362d3Smrg#include "radeon_exa_render.c"
334de2362d3Smrg#endif
335de2362d3Smrg#include "radeon_exa_funcs.c"
336de2362d3Smrg
337de2362d3Smrg
338de2362d3Smrg
339