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#include "radeon_bo_helper.h"
40#include "radeon_probe.h"
41#include "radeon_version.h"
42#include "radeon_exa_shared.h"
43#include "xf86.h"
44
45
46/***********************************************************************/
47#define RINFO_FROM_SCREEN(pScr) ScrnInfoPtr pScrn =  xf86ScreenToScrn(pScr); \
48    RADEONInfoPtr info   = RADEONPTR(pScrn)
49
50static struct {
51    int rop;
52    int pattern;
53} RADEON_ROP[] = {
54    { RADEON_ROP3_ZERO, RADEON_ROP3_ZERO }, /* GXclear        */
55    { RADEON_ROP3_DSa,  RADEON_ROP3_DPa  }, /* Gxand          */
56    { RADEON_ROP3_SDna, RADEON_ROP3_PDna }, /* GXandReverse   */
57    { RADEON_ROP3_S,    RADEON_ROP3_P    }, /* GXcopy         */
58    { RADEON_ROP3_DSna, RADEON_ROP3_DPna }, /* GXandInverted  */
59    { RADEON_ROP3_D,    RADEON_ROP3_D    }, /* GXnoop         */
60    { RADEON_ROP3_DSx,  RADEON_ROP3_DPx  }, /* GXxor          */
61    { RADEON_ROP3_DSo,  RADEON_ROP3_DPo  }, /* GXor           */
62    { RADEON_ROP3_DSon, RADEON_ROP3_DPon }, /* GXnor          */
63    { RADEON_ROP3_DSxn, RADEON_ROP3_PDxn }, /* GXequiv        */
64    { RADEON_ROP3_Dn,   RADEON_ROP3_Dn   }, /* GXinvert       */
65    { RADEON_ROP3_SDno, RADEON_ROP3_PDno }, /* GXorReverse    */
66    { RADEON_ROP3_Sn,   RADEON_ROP3_Pn   }, /* GXcopyInverted */
67    { RADEON_ROP3_DSno, RADEON_ROP3_DPno }, /* GXorInverted   */
68    { RADEON_ROP3_DSan, RADEON_ROP3_DPan }, /* GXnand         */
69    { RADEON_ROP3_ONE,  RADEON_ROP3_ONE  }  /* GXset          */
70};
71
72static __inline__ uint32_t F_TO_DW(float val)
73{
74    union {
75	float f;
76	uint32_t l;
77    } tmp;
78    tmp.f = val;
79    return tmp.l;
80}
81
82
83/* Assumes that depth 15 and 16 can be used as depth 16, which is okay since we
84 * require src and dest datatypes to be equal.
85 */
86Bool RADEONGetDatatypeBpp(int bpp, uint32_t *type)
87{
88	switch (bpp) {
89	case 8:
90		*type = ATI_DATATYPE_CI8;
91		return TRUE;
92	case 16:
93		*type = ATI_DATATYPE_RGB565;
94		return TRUE;
95	case 24:
96		*type = ATI_DATATYPE_CI8;
97		return TRUE;
98	case 32:
99		*type = ATI_DATATYPE_ARGB8888;
100		return TRUE;
101	default:
102		RADEON_FALLBACK(("Unsupported bpp: %d\n", bpp));
103		return FALSE;
104	}
105}
106
107static Bool RADEONPixmapIsColortiled(PixmapPtr pPix)
108{
109    return FALSE;
110}
111
112static Bool RADEONGetOffsetPitch(PixmapPtr pPix, int bpp, uint32_t *pitch_offset,
113				 unsigned int offset, unsigned int pitch)
114{
115	RINFO_FROM_SCREEN(pPix->drawable.pScreen);
116
117	if (pitch > 16320 || pitch % info->accel_state->exa->pixmapPitchAlign != 0)
118		RADEON_FALLBACK(("Bad pitch 0x%08x\n", pitch));
119
120	if (offset % info->accel_state->exa->pixmapOffsetAlign != 0)
121		RADEON_FALLBACK(("Bad offset 0x%08x\n", offset));
122
123	pitch = pitch >> 6;
124	*pitch_offset = (pitch << 22) | (offset >> 10);
125
126	/* If it's the front buffer, we've got to note that it's tiled? */
127	if (RADEONPixmapIsColortiled(pPix))
128		*pitch_offset |= RADEON_DST_TILE_MACRO;
129	return TRUE;
130}
131
132Bool RADEONGetPixmapOffsetPitch(PixmapPtr pPix, uint32_t *pitch_offset)
133{
134	uint32_t pitch;
135	int bpp;
136
137	bpp = pPix->drawable.bitsPerPixel;
138	if (bpp == 24)
139		bpp = 8;
140
141	pitch = exaGetPixmapPitch(pPix);
142
143	return RADEONGetOffsetPitch(pPix, bpp, pitch_offset, 0, pitch);
144}
145
146/**
147 * Returns whether the provided transform is affine.
148 *
149 * transform may be null.
150 */
151Bool radeon_transform_is_affine_or_scaled(PictTransformPtr t)
152{
153	if (!t)
154		return TRUE;
155	/* the shaders don't handle scaling either */
156	return t->matrix[2][0] == 0 && t->matrix[2][1] == 0 && t->matrix[2][2] == IntToxFixed(1);
157}
158
159Bool RADEONPrepareAccess_CS(PixmapPtr pPix, int index)
160{
161    ScreenPtr pScreen = pPix->drawable.pScreen;
162    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
163    RADEONInfoPtr info = RADEONPTR(pScrn);
164    struct radeon_exa_pixmap_priv *driver_priv;
165    uint32_t possible_domains = ~0U;
166    uint32_t current_domain = 0;
167    Bool can_fail = !(pPix->drawable.bitsPerPixel < 8) &&
168	pPix != pScreen->GetScreenPixmap(pScreen);
169    Bool flush = FALSE;
170    int ret;
171
172#if X_BYTE_ORDER == X_BIG_ENDIAN
173    /* May need to handle byte swapping in DownloadFrom/UploadToScreen */
174    if (pPix->drawable.bitsPerPixel > 8)
175	return FALSE;
176#endif
177
178    driver_priv = exaGetPixmapDriverPrivate(pPix);
179    if (!driver_priv)
180      return FALSE;
181
182    /* untile in DFS/UTS */
183    if (driver_priv->tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))
184	return FALSE;
185
186    /* if we have more refs than just the BO then flush */
187    if (radeon_bo_is_referenced_by_cs(driver_priv->bo->bo.radeon, info->cs)) {
188	flush = TRUE;
189
190	if (can_fail) {
191	    possible_domains = radeon_bo_get_src_domain(driver_priv->bo->bo.radeon);
192	    if (possible_domains == RADEON_GEM_DOMAIN_VRAM)
193		return FALSE; /* use DownloadFromScreen */
194	}
195    }
196
197    /* if the BO might end up in VRAM, prefer DownloadFromScreen */
198    if (can_fail && (possible_domains & RADEON_GEM_DOMAIN_VRAM)) {
199	radeon_bo_is_busy(driver_priv->bo->bo.radeon, &current_domain);
200
201	if (current_domain & possible_domains) {
202	    if (current_domain == RADEON_GEM_DOMAIN_VRAM)
203		return FALSE;
204	} else if (possible_domains & RADEON_GEM_DOMAIN_VRAM)
205	    return FALSE;
206    }
207
208    if (flush)
209        radeon_cs_flush_indirect(pScrn);
210
211    /* flush IB */
212    ret = radeon_bo_map(driver_priv->bo->bo.radeon, 1);
213    if (ret) {
214      FatalError("failed to map pixmap %d\n", ret);
215      return FALSE;
216    }
217    driver_priv->bo_mapped = TRUE;
218
219    pPix->devPrivate.ptr = driver_priv->bo->bo.radeon->ptr;
220
221    return TRUE;
222}
223
224void RADEONFinishAccess_CS(PixmapPtr pPix, int index)
225{
226    struct radeon_exa_pixmap_priv *driver_priv;
227
228    driver_priv = exaGetPixmapDriverPrivate(pPix);
229    if (!driver_priv || !driver_priv->bo_mapped)
230        return;
231
232    radeon_bo_unmap(driver_priv->bo->bo.radeon);
233    driver_priv->bo_mapped = FALSE;
234    pPix->devPrivate.ptr = NULL;
235}
236
237
238void *RADEONEXACreatePixmap2(ScreenPtr pScreen, int width, int height,
239			     int depth, int usage_hint, int bitsPerPixel,
240			     int *new_pitch)
241{
242    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
243    RADEONInfoPtr info = RADEONPTR(pScrn);
244    struct radeon_exa_pixmap_priv *new_priv;
245
246    if (width != 0 && height != 0 && !info->exa_force_create &&
247	info->exa_pixmaps == FALSE)
248        return NULL;
249
250    new_priv = calloc(1, sizeof(struct radeon_exa_pixmap_priv));
251    if (!new_priv) {
252	return NULL;
253    }
254
255    if (width == 0 || height == 0) {
256	return new_priv;
257    }
258
259    new_priv->bo = radeon_alloc_pixmap_bo(pScrn, width, height, depth,
260					  usage_hint, bitsPerPixel, new_pitch,
261					  &new_priv->surface,
262					  &new_priv->tiling_flags);
263    if (!new_priv->bo) {
264	free(new_priv);
265	ErrorF("Failed to alloc memory\n");
266	return NULL;
267    }
268
269    return new_priv;
270}
271
272void RADEONEXADestroyPixmap(ScreenPtr pScreen, void *driverPriv)
273{
274    RADEONEntPtr pRADEONEnt = RADEONEntPriv(xf86ScreenToScrn(pScreen));
275    struct radeon_exa_pixmap_priv *driver_priv = driverPriv;
276
277    if (!driverPriv)
278      return;
279
280    radeon_buffer_unref(&driver_priv->bo);
281    drmmode_fb_reference(pRADEONEnt->fd, &driver_priv->fb, NULL);
282    free(driverPriv);
283}
284
285Bool RADEONEXASharePixmapBacking(PixmapPtr ppix, ScreenPtr seconndary, void **fd_handle)
286{
287    struct radeon_exa_pixmap_priv *driver_priv = exaGetPixmapDriverPrivate(ppix);
288
289    if (!radeon_share_pixmap_backing(driver_priv->bo->bo.radeon, fd_handle))
290	return FALSE;
291
292    driver_priv->shared = TRUE;
293    return TRUE;
294}
295
296Bool RADEONEXASetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle)
297{
298    struct radeon_exa_pixmap_priv *driver_priv = exaGetPixmapDriverPrivate(ppix);
299    int ihandle = (int)(long)fd_handle;
300
301    if (!radeon_set_shared_pixmap_backing(ppix, fd_handle, &driver_priv->surface))
302	return FALSE;
303
304    driver_priv->shared = ihandle != -1;
305    return TRUE;
306}
307
308uint32_t radeon_get_pixmap_tiling(PixmapPtr pPix)
309{
310    struct radeon_exa_pixmap_priv *driver_priv;
311    driver_priv = exaGetPixmapDriverPrivate(pPix);
312    return driver_priv->tiling_flags;
313}
314
315Bool RADEONEXAPixmapIsOffscreen(PixmapPtr pPix)
316{
317    struct radeon_exa_pixmap_priv *driver_priv;
318
319    driver_priv = exaGetPixmapDriverPrivate(pPix);
320
321    if (!driver_priv)
322       return FALSE;
323    if (driver_priv->bo)
324       return TRUE;
325    return FALSE;
326}
327
328#define ENTER_DRAW(x) TRACE
329#define LEAVE_DRAW(x) TRACE
330/***********************************************************************/
331
332#ifdef RENDER
333#include "radeon_exa_render.c"
334#endif
335#include "radeon_exa_funcs.c"
336
337
338
339