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, ¤t_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