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 
50 static 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 
F_TO_DW(float val)72 static __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  */
RADEONGetDatatypeBpp(int bpp,uint32_t * type)86 Bool 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 
RADEONPixmapIsColortiled(PixmapPtr pPix)107 static Bool RADEONPixmapIsColortiled(PixmapPtr pPix)
108 {
109     return FALSE;
110 }
111 
RADEONGetOffsetPitch(PixmapPtr pPix,int bpp,uint32_t * pitch_offset,unsigned int offset,unsigned int pitch)112 static 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 
RADEONGetPixmapOffsetPitch(PixmapPtr pPix,uint32_t * pitch_offset)132 Bool 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  */
radeon_transform_is_affine_or_scaled(PictTransformPtr t)151 Bool 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 
RADEONPrepareAccess_CS(PixmapPtr pPix,int index)159 Bool 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 
RADEONFinishAccess_CS(PixmapPtr pPix,int index)224 void 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 
RADEONEXACreatePixmap2(ScreenPtr pScreen,int width,int height,int depth,int usage_hint,int bitsPerPixel,int * new_pitch)238 void *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 
RADEONEXADestroyPixmap(ScreenPtr pScreen,void * driverPriv)272 void 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 
RADEONEXASharePixmapBacking(PixmapPtr ppix,ScreenPtr slave,void ** fd_handle)285 Bool RADEONEXASharePixmapBacking(PixmapPtr ppix, ScreenPtr slave, 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 
RADEONEXASetSharedPixmapBacking(PixmapPtr ppix,void * fd_handle)296 Bool 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 
radeon_get_pixmap_tiling(PixmapPtr pPix)308 uint32_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 
RADEONEXAPixmapIsOffscreen(PixmapPtr pPix)315 Bool 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