1 /*
2 * Copyright © 2006 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Eric Anholt <eric@anholt.net>
25 *
26 */
27
28 #ifdef HAVE_DIX_CONFIG_H
29 #include <dix-config.h>
30 #endif
31
32 #include "ephyr.h"
33 #include "exa_priv.h"
34 #include "fbpict.h"
35
36 #define EPHYR_TRACE_DRAW 0
37
38 #if EPHYR_TRACE_DRAW
39 #define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__);
40 #else
41 #define TRACE_DRAW() do { } while (0)
42 #endif
43
44 /* Use some oddball alignments, to expose issues in alignment handling in EXA. */
45 #define EPHYR_OFFSET_ALIGN 24
46 #define EPHYR_PITCH_ALIGN 24
47
48 #define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024)
49 #define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024)
50
51 /**
52 * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to
53 * fb functions.
54 */
55 static void
ephyrPreparePipelinedAccess(PixmapPtr pPix,int index)56 ephyrPreparePipelinedAccess(PixmapPtr pPix, int index)
57 {
58 KdScreenPriv(pPix->drawable.pScreen);
59 KdScreenInfo *screen = pScreenPriv->screen;
60 EphyrScrPriv *scrpriv = screen->driver;
61 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
62
63 assert(fakexa->saved_ptrs[index] == NULL);
64 fakexa->saved_ptrs[index] = pPix->devPrivate.ptr;
65
66 if (pPix->devPrivate.ptr != NULL)
67 return;
68
69 pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix);
70 }
71
72 /**
73 * Restores the original devPrivate.ptr of the pixmap from before we messed with
74 * it.
75 */
76 static void
ephyrFinishPipelinedAccess(PixmapPtr pPix,int index)77 ephyrFinishPipelinedAccess(PixmapPtr pPix, int index)
78 {
79 KdScreenPriv(pPix->drawable.pScreen);
80 KdScreenInfo *screen = pScreenPriv->screen;
81 EphyrScrPriv *scrpriv = screen->driver;
82 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
83
84 pPix->devPrivate.ptr = fakexa->saved_ptrs[index];
85 fakexa->saved_ptrs[index] = NULL;
86 }
87
88 /**
89 * Sets up a scratch GC for fbFill, and saves other parameters for the
90 * ephyrSolid implementation.
91 */
92 static Bool
ephyrPrepareSolid(PixmapPtr pPix,int alu,Pixel pm,Pixel fg)93 ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
94 {
95 ScreenPtr pScreen = pPix->drawable.pScreen;
96
97 KdScreenPriv(pScreen);
98 KdScreenInfo *screen = pScreenPriv->screen;
99 EphyrScrPriv *scrpriv = screen->driver;
100 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
101 ChangeGCVal tmpval[3];
102
103 ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST);
104
105 fakexa->pDst = pPix;
106 fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen);
107
108 tmpval[0].val = alu;
109 tmpval[1].val = pm;
110 tmpval[2].val = fg;
111 ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask | GCForeground,
112 tmpval);
113
114 ValidateGC(&pPix->drawable, fakexa->pGC);
115
116 TRACE_DRAW();
117
118 return TRUE;
119 }
120
121 /**
122 * Does an fbFill of the rectangle to be drawn.
123 */
124 static void
ephyrSolid(PixmapPtr pPix,int x1,int y1,int x2,int y2)125 ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2)
126 {
127 ScreenPtr pScreen = pPix->drawable.pScreen;
128
129 KdScreenPriv(pScreen);
130 KdScreenInfo *screen = pScreenPriv->screen;
131 EphyrScrPriv *scrpriv = screen->driver;
132 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
133
134 fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1);
135 }
136
137 /**
138 * Cleans up the scratch GC created in ephyrPrepareSolid.
139 */
140 static void
ephyrDoneSolid(PixmapPtr pPix)141 ephyrDoneSolid(PixmapPtr pPix)
142 {
143 ScreenPtr pScreen = pPix->drawable.pScreen;
144
145 KdScreenPriv(pScreen);
146 KdScreenInfo *screen = pScreenPriv->screen;
147 EphyrScrPriv *scrpriv = screen->driver;
148 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
149
150 FreeScratchGC(fakexa->pGC);
151
152 ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST);
153 }
154
155 /**
156 * Sets up a scratch GC for fbCopyArea, and saves other parameters for the
157 * ephyrCopy implementation.
158 */
159 static Bool
ephyrPrepareCopy(PixmapPtr pSrc,PixmapPtr pDst,int dx,int dy,int alu,Pixel pm)160 ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu,
161 Pixel pm)
162 {
163 ScreenPtr pScreen = pDst->drawable.pScreen;
164
165 KdScreenPriv(pScreen);
166 KdScreenInfo *screen = pScreenPriv->screen;
167 EphyrScrPriv *scrpriv = screen->driver;
168 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
169 ChangeGCVal tmpval[2];
170
171 ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
172 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
173
174 fakexa->pSrc = pSrc;
175 fakexa->pDst = pDst;
176 fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen);
177
178 tmpval[0].val = alu;
179 tmpval[1].val = pm;
180 ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask, tmpval);
181
182 ValidateGC(&pDst->drawable, fakexa->pGC);
183
184 TRACE_DRAW();
185
186 return TRUE;
187 }
188
189 /**
190 * Does an fbCopyArea to take care of the requested copy.
191 */
192 static void
ephyrCopy(PixmapPtr pDst,int srcX,int srcY,int dstX,int dstY,int w,int h)193 ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h)
194 {
195 ScreenPtr pScreen = pDst->drawable.pScreen;
196
197 KdScreenPriv(pScreen);
198 KdScreenInfo *screen = pScreenPriv->screen;
199 EphyrScrPriv *scrpriv = screen->driver;
200 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
201
202 fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC,
203 srcX, srcY, w, h, dstX, dstY);
204 }
205
206 /**
207 * Cleans up the scratch GC created in ephyrPrepareCopy.
208 */
209 static void
ephyrDoneCopy(PixmapPtr pDst)210 ephyrDoneCopy(PixmapPtr pDst)
211 {
212 ScreenPtr pScreen = pDst->drawable.pScreen;
213
214 KdScreenPriv(pScreen);
215 KdScreenInfo *screen = pScreenPriv->screen;
216 EphyrScrPriv *scrpriv = screen->driver;
217 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
218
219 FreeScratchGC(fakexa->pGC);
220
221 ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
222 ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
223 }
224
225 /**
226 * Reports that we can always accelerate the given operation. This may not be
227 * desirable from an EXA testing standpoint -- testing the fallback paths would
228 * be useful, too.
229 */
230 static Bool
ephyrCheckComposite(int op,PicturePtr pSrcPicture,PicturePtr pMaskPicture,PicturePtr pDstPicture)231 ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
232 PicturePtr pDstPicture)
233 {
234 /* Exercise the component alpha helper, so fail on this case like a normal
235 * driver
236 */
237 if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver)
238 return FALSE;
239
240 return TRUE;
241 }
242
243 /**
244 * Saves off the parameters for ephyrComposite.
245 */
246 static Bool
ephyrPrepareComposite(int op,PicturePtr pSrcPicture,PicturePtr pMaskPicture,PicturePtr pDstPicture,PixmapPtr pSrc,PixmapPtr pMask,PixmapPtr pDst)247 ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
248 PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask,
249 PixmapPtr pDst)
250 {
251 KdScreenPriv(pDst->drawable.pScreen);
252 KdScreenInfo *screen = pScreenPriv->screen;
253 EphyrScrPriv *scrpriv = screen->driver;
254 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
255
256 ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
257 if (pSrc != NULL)
258 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
259 if (pMask != NULL)
260 ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK);
261
262 fakexa->op = op;
263 fakexa->pSrcPicture = pSrcPicture;
264 fakexa->pMaskPicture = pMaskPicture;
265 fakexa->pDstPicture = pDstPicture;
266 fakexa->pSrc = pSrc;
267 fakexa->pMask = pMask;
268 fakexa->pDst = pDst;
269
270 TRACE_DRAW();
271
272 return TRUE;
273 }
274
275 /**
276 * Does an fbComposite to complete the requested drawing operation.
277 */
278 static void
ephyrComposite(PixmapPtr pDst,int srcX,int srcY,int maskX,int maskY,int dstX,int dstY,int w,int h)279 ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
280 int dstX, int dstY, int w, int h)
281 {
282 KdScreenPriv(pDst->drawable.pScreen);
283 KdScreenInfo *screen = pScreenPriv->screen;
284 EphyrScrPriv *scrpriv = screen->driver;
285 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
286
287 fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture,
288 fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY,
289 w, h);
290 }
291
292 static void
ephyrDoneComposite(PixmapPtr pDst)293 ephyrDoneComposite(PixmapPtr pDst)
294 {
295 KdScreenPriv(pDst->drawable.pScreen);
296 KdScreenInfo *screen = pScreenPriv->screen;
297 EphyrScrPriv *scrpriv = screen->driver;
298 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
299
300 if (fakexa->pMask != NULL)
301 ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK);
302 if (fakexa->pSrc != NULL)
303 ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
304 ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
305 }
306
307 /**
308 * Does fake acceleration of DownloadFromScren using memcpy.
309 */
310 static Bool
ephyrDownloadFromScreen(PixmapPtr pSrc,int x,int y,int w,int h,char * dst,int dst_pitch)311 ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst,
312 int dst_pitch)
313 {
314 KdScreenPriv(pSrc->drawable.pScreen);
315 KdScreenInfo *screen = pScreenPriv->screen;
316 EphyrScrPriv *scrpriv = screen->driver;
317 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
318 unsigned char *src;
319 int src_pitch, cpp;
320
321 if (pSrc->drawable.bitsPerPixel < 8)
322 return FALSE;
323
324 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
325
326 cpp = pSrc->drawable.bitsPerPixel / 8;
327 src_pitch = exaGetPixmapPitch(pSrc);
328 src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc);
329 src += y * src_pitch + x * cpp;
330
331 for (; h > 0; h--) {
332 memcpy(dst, src, w * cpp);
333 dst += dst_pitch;
334 src += src_pitch;
335 }
336
337 exaMarkSync(pSrc->drawable.pScreen);
338
339 ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC);
340
341 return TRUE;
342 }
343
344 /**
345 * Does fake acceleration of UploadToScreen using memcpy.
346 */
347 static Bool
ephyrUploadToScreen(PixmapPtr pDst,int x,int y,int w,int h,char * src,int src_pitch)348 ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
349 int src_pitch)
350 {
351 KdScreenPriv(pDst->drawable.pScreen);
352 KdScreenInfo *screen = pScreenPriv->screen;
353 EphyrScrPriv *scrpriv = screen->driver;
354 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
355 unsigned char *dst;
356 int dst_pitch, cpp;
357
358 if (pDst->drawable.bitsPerPixel < 8)
359 return FALSE;
360
361 ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
362
363 cpp = pDst->drawable.bitsPerPixel / 8;
364 dst_pitch = exaGetPixmapPitch(pDst);
365 dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst);
366 dst += y * dst_pitch + x * cpp;
367
368 for (; h > 0; h--) {
369 memcpy(dst, src, w * cpp);
370 dst += dst_pitch;
371 src += src_pitch;
372 }
373
374 exaMarkSync(pDst->drawable.pScreen);
375
376 ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST);
377
378 return TRUE;
379 }
380
381 static Bool
ephyrPrepareAccess(PixmapPtr pPix,int index)382 ephyrPrepareAccess(PixmapPtr pPix, int index)
383 {
384 /* Make sure we don't somehow end up with a pointer that is in framebuffer
385 * and hasn't been readied for us.
386 */
387 assert(pPix->devPrivate.ptr != NULL);
388
389 return TRUE;
390 }
391
392 /**
393 * In fakexa, we currently only track whether we have synced to the latest
394 * "accelerated" drawing that has happened or not. It's not used for anything
395 * yet.
396 */
397 static int
ephyrMarkSync(ScreenPtr pScreen)398 ephyrMarkSync(ScreenPtr pScreen)
399 {
400 KdScreenPriv(pScreen);
401 KdScreenInfo *screen = pScreenPriv->screen;
402 EphyrScrPriv *scrpriv = screen->driver;
403 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
404
405 fakexa->is_synced = FALSE;
406
407 return 0;
408 }
409
410 /**
411 * Assumes that we're waiting on the latest marker. When EXA gets smarter and
412 * starts using markers in a fine-grained way (for example, waiting on drawing
413 * to required pixmaps to complete, rather than waiting for all drawing to
414 * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker
415 * implementation fine-grained as well.
416 */
417 static void
ephyrWaitMarker(ScreenPtr pScreen,int marker)418 ephyrWaitMarker(ScreenPtr pScreen, int marker)
419 {
420 KdScreenPriv(pScreen);
421 KdScreenInfo *screen = pScreenPriv->screen;
422 EphyrScrPriv *scrpriv = screen->driver;
423 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
424
425 fakexa->is_synced = TRUE;
426 }
427
428 /**
429 * This function initializes EXA to use the fake acceleration implementation
430 * which just falls through to software. The purpose is to have a reliable,
431 * correct driver with which to test changes to the EXA core.
432 */
433 Bool
ephyrDrawInit(ScreenPtr pScreen)434 ephyrDrawInit(ScreenPtr pScreen)
435 {
436 KdScreenPriv(pScreen);
437 KdScreenInfo *screen = pScreenPriv->screen;
438 EphyrScrPriv *scrpriv = screen->driver;
439 EphyrPriv *priv = screen->card->driver;
440 EphyrFakexaPriv *fakexa;
441 Bool success;
442
443 fakexa = calloc(1, sizeof(*fakexa));
444 if (fakexa == NULL)
445 return FALSE;
446
447 fakexa->exa = exaDriverAlloc();
448 if (fakexa->exa == NULL) {
449 free(fakexa);
450 return FALSE;
451 }
452
453 fakexa->exa->memoryBase = (CARD8 *) (priv->base);
454 fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen);
455 fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height;
456
457 /* Since we statically link against EXA, we shouldn't have to be smart about
458 * versioning.
459 */
460 fakexa->exa->exa_major = 2;
461 fakexa->exa->exa_minor = 0;
462
463 fakexa->exa->PrepareSolid = ephyrPrepareSolid;
464 fakexa->exa->Solid = ephyrSolid;
465 fakexa->exa->DoneSolid = ephyrDoneSolid;
466
467 fakexa->exa->PrepareCopy = ephyrPrepareCopy;
468 fakexa->exa->Copy = ephyrCopy;
469 fakexa->exa->DoneCopy = ephyrDoneCopy;
470
471 fakexa->exa->CheckComposite = ephyrCheckComposite;
472 fakexa->exa->PrepareComposite = ephyrPrepareComposite;
473 fakexa->exa->Composite = ephyrComposite;
474 fakexa->exa->DoneComposite = ephyrDoneComposite;
475
476 fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen;
477 fakexa->exa->UploadToScreen = ephyrUploadToScreen;
478
479 fakexa->exa->MarkSync = ephyrMarkSync;
480 fakexa->exa->WaitMarker = ephyrWaitMarker;
481
482 fakexa->exa->PrepareAccess = ephyrPrepareAccess;
483
484 fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN;
485 fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN;
486
487 fakexa->exa->maxX = 1023;
488 fakexa->exa->maxY = 1023;
489
490 fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS;
491
492 success = exaDriverInit(pScreen, fakexa->exa);
493 if (success) {
494 ErrorF("Initialized fake EXA acceleration\n");
495 scrpriv->fakexa = fakexa;
496 }
497 else {
498 ErrorF("Failed to initialize EXA\n");
499 free(fakexa->exa);
500 free(fakexa);
501 }
502
503 return success;
504 }
505
506 void
ephyrDrawEnable(ScreenPtr pScreen)507 ephyrDrawEnable(ScreenPtr pScreen)
508 {
509 }
510
511 void
ephyrDrawDisable(ScreenPtr pScreen)512 ephyrDrawDisable(ScreenPtr pScreen)
513 {
514 }
515
516 void
ephyrDrawFini(ScreenPtr pScreen)517 ephyrDrawFini(ScreenPtr pScreen)
518 {
519 }
520
521 /**
522 * exaDDXDriverInit is required by the top-level EXA module, and is used by
523 * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since
524 * we won't be enabling/disabling the FB.
525 */
526 void
exaDDXDriverInit(ScreenPtr pScreen)527 exaDDXDriverInit(ScreenPtr pScreen)
528 {
529 ExaScreenPriv(pScreen);
530
531 pExaScr->migration = ExaMigrationSmart;
532 pExaScr->checkDirtyCorrectness = TRUE;
533 }
534