Initial commit
[xorg_rtime.git] / xorg-server-1.4 / hw / kdrive / ephyr / ephyr_draw.c
blob84faecc00f8a5be0a93bc93750c54d34bc9dde4f
1 /*
2 * Copyright © 2006 Intel Corporation
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:
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.
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.
23 * Authors:
24 * Eric Anholt <eric@anholt.net>
28 #ifdef HAVE_CONFIG_H
29 #include <kdrive-config.h>
30 #endif
31 #undef NDEBUG /* No, really. The whole point of this module is to crash. */
33 #include "ephyr.h"
34 #include "exa_priv.h"
35 #include "fbpict.h"
37 #define EPHYR_TRACE_DRAW 0
39 #if EPHYR_TRACE_DRAW
40 #define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__);
41 #else
42 #define TRACE_DRAW() do { } while (0)
43 #endif
45 /* Use some oddball alignments, to expose issues in alignment handling in EXA. */
46 #define EPHYR_OFFSET_ALIGN 24
47 #define EPHYR_PITCH_ALIGN 24
49 #define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024)
50 #define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024)
52 /**
53 * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to
54 * fb functions.
56 static void
57 ephyrPreparePipelinedAccess(PixmapPtr pPix, int index)
59 KdScreenPriv(pPix->drawable.pScreen);
60 KdScreenInfo *screen = pScreenPriv->screen;
61 EphyrScrPriv *scrpriv = screen->driver;
62 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
64 assert(fakexa->saved_ptrs[index] == NULL);
65 fakexa->saved_ptrs[index] = pPix->devPrivate.ptr;
67 if (pPix->devPrivate.ptr != NULL)
68 return;
70 pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix);
73 /**
74 * Restores the original devPrivate.ptr of the pixmap from before we messed with
75 * it.
77 static void
78 ephyrFinishPipelinedAccess(PixmapPtr pPix, int index)
80 KdScreenPriv(pPix->drawable.pScreen);
81 KdScreenInfo *screen = pScreenPriv->screen;
82 EphyrScrPriv *scrpriv = screen->driver;
83 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
85 pPix->devPrivate.ptr = fakexa->saved_ptrs[index];
86 fakexa->saved_ptrs[index] = NULL;
89 /**
90 * Sets up a scratch GC for fbFill, and saves other parameters for the
91 * ephyrSolid implementation.
93 static Bool
94 ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
96 ScreenPtr pScreen = pPix->drawable.pScreen;
97 KdScreenPriv(pScreen);
98 KdScreenInfo *screen = pScreenPriv->screen;
99 EphyrScrPriv *scrpriv = screen->driver;
100 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
101 CARD32 tmpval[3];
103 ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST);
105 fakexa->pDst = pPix;
106 fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen);
108 tmpval[0] = alu;
109 tmpval[1] = pm;
110 tmpval[2] = fg;
111 ChangeGC(fakexa->pGC, GCFunction | GCPlaneMask | GCForeground,
112 tmpval);
114 ValidateGC(&pPix->drawable, fakexa->pGC);
116 TRACE_DRAW();
118 return TRUE;
122 * Does an fbFill of the rectangle to be drawn.
124 static void
125 ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2)
127 ScreenPtr pScreen = pPix->drawable.pScreen;
128 KdScreenPriv(pScreen);
129 KdScreenInfo *screen = pScreenPriv->screen;
130 EphyrScrPriv *scrpriv = screen->driver;
131 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
133 fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1);
137 * Cleans up the scratch GC created in ephyrPrepareSolid.
139 static void
140 ephyrDoneSolid(PixmapPtr pPix)
142 ScreenPtr pScreen = pPix->drawable.pScreen;
143 KdScreenPriv(pScreen);
144 KdScreenInfo *screen = pScreenPriv->screen;
145 EphyrScrPriv *scrpriv = screen->driver;
146 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
148 FreeScratchGC(fakexa->pGC);
150 ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST);
154 * Sets up a scratch GC for fbCopyArea, and saves other parameters for the
155 * ephyrCopy implementation.
157 static Bool
158 ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu,
159 Pixel pm)
161 ScreenPtr pScreen = pDst->drawable.pScreen;
162 KdScreenPriv(pScreen);
163 KdScreenInfo *screen = pScreenPriv->screen;
164 EphyrScrPriv *scrpriv = screen->driver;
165 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
166 CARD32 tmpval[2];
168 ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
169 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
171 fakexa->pSrc = pSrc;
172 fakexa->pDst = pDst;
173 fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen);
175 tmpval[0] = alu;
176 tmpval[1] = pm;
177 ChangeGC (fakexa->pGC, GCFunction | GCPlaneMask, tmpval);
179 ValidateGC(&pDst->drawable, fakexa->pGC);
181 TRACE_DRAW();
183 return TRUE;
187 * Does an fbCopyArea to take care of the requested copy.
189 static void
190 ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h)
192 ScreenPtr pScreen = pDst->drawable.pScreen;
193 KdScreenPriv(pScreen);
194 KdScreenInfo *screen = pScreenPriv->screen;
195 EphyrScrPriv *scrpriv = screen->driver;
196 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
198 fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC,
199 srcX, srcY, w, h, dstX, dstY);
203 * Cleans up the scratch GC created in ephyrPrepareCopy.
205 static void
206 ephyrDoneCopy(PixmapPtr pDst)
208 ScreenPtr pScreen = pDst->drawable.pScreen;
209 KdScreenPriv(pScreen);
210 KdScreenInfo *screen = pScreenPriv->screen;
211 EphyrScrPriv *scrpriv = screen->driver;
212 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
214 FreeScratchGC (fakexa->pGC);
216 ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
217 ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
221 * Reports that we can always accelerate the given operation. This may not be
222 * desirable from an EXA testing standpoint -- testing the fallback paths would
223 * be useful, too.
225 static Bool
226 ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
227 PicturePtr pDstPicture)
229 /* Exercise the component alpha helper, so fail on this case like a normal
230 * driver
232 if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver)
233 return FALSE;
235 return TRUE;
239 * Saves off the parameters for ephyrComposite.
241 static Bool
242 ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
243 PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask,
244 PixmapPtr pDst)
246 KdScreenPriv(pDst->drawable.pScreen);
247 KdScreenInfo *screen = pScreenPriv->screen;
248 EphyrScrPriv *scrpriv = screen->driver;
249 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
251 ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
252 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
253 if (pMask != NULL)
254 ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK);
256 fakexa->op = op;
257 fakexa->pSrcPicture = pSrcPicture;
258 fakexa->pMaskPicture = pMaskPicture;
259 fakexa->pDstPicture = pDstPicture;
260 fakexa->pSrc = pSrc;
261 fakexa->pMask = pMask;
262 fakexa->pDst = pDst;
264 TRACE_DRAW();
266 return TRUE;
270 * Does an fbComposite to complete the requested drawing operation.
272 static void
273 ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
274 int dstX, int dstY, int w, int h)
276 KdScreenPriv(pDst->drawable.pScreen);
277 KdScreenInfo *screen = pScreenPriv->screen;
278 EphyrScrPriv *scrpriv = screen->driver;
279 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
281 fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture,
282 fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY,
283 w, h);
286 static void
287 ephyrDoneComposite(PixmapPtr pDst)
289 KdScreenPriv(pDst->drawable.pScreen);
290 KdScreenInfo *screen = pScreenPriv->screen;
291 EphyrScrPriv *scrpriv = screen->driver;
292 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
294 if (fakexa->pMask != NULL)
295 ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK);
296 ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
297 ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
301 * Does fake acceleration of DownloadFromScren using memcpy.
303 static Bool
304 ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst,
305 int dst_pitch)
307 KdScreenPriv(pSrc->drawable.pScreen);
308 KdScreenInfo *screen = pScreenPriv->screen;
309 EphyrScrPriv *scrpriv = screen->driver;
310 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
311 char *src;
312 int src_pitch, cpp;
314 if (pSrc->drawable.bitsPerPixel < 8)
315 return FALSE;
317 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
319 cpp = pSrc->drawable.bitsPerPixel / 8;
320 src_pitch = exaGetPixmapPitch(pSrc);
321 src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc);
322 src += y * src_pitch + x * cpp;
324 for (; h > 0; h--) {
325 memcpy(dst, src, w * cpp);
326 dst += dst_pitch;
327 src += src_pitch;
330 exaMarkSync(pSrc->drawable.pScreen);
332 ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC);
334 return TRUE;
338 * Does fake acceleration of UploadToScreen using memcpy.
340 static Bool
341 ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
342 int src_pitch)
344 KdScreenPriv(pDst->drawable.pScreen);
345 KdScreenInfo *screen = pScreenPriv->screen;
346 EphyrScrPriv *scrpriv = screen->driver;
347 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
348 char *dst;
349 int dst_pitch, cpp;
351 if (pDst->drawable.bitsPerPixel < 8)
352 return FALSE;
354 ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
356 cpp = pDst->drawable.bitsPerPixel / 8;
357 dst_pitch = exaGetPixmapPitch(pDst);
358 dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst);
359 dst += y * dst_pitch + x * cpp;
361 for (; h > 0; h--) {
362 memcpy(dst, src, w * cpp);
363 dst += dst_pitch;
364 src += src_pitch;
367 exaMarkSync(pDst->drawable.pScreen);
369 ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST);
371 return TRUE;
374 static Bool
375 ephyrPrepareAccess(PixmapPtr pPix, int index)
377 /* Make sure we don't somehow end up with a pointer that is in framebuffer
378 * and hasn't been readied for us.
380 assert(pPix->devPrivate.ptr != NULL);
382 return TRUE;
386 * In fakexa, we currently only track whether we have synced to the latest
387 * "accelerated" drawing that has happened or not. It's not used for anything
388 * yet.
390 static int
391 ephyrMarkSync(ScreenPtr pScreen)
393 KdScreenPriv(pScreen);
394 KdScreenInfo *screen = pScreenPriv->screen;
395 EphyrScrPriv *scrpriv = screen->driver;
396 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
398 fakexa->is_synced = FALSE;
400 return 0;
404 * Assumes that we're waiting on the latest marker. When EXA gets smarter and
405 * starts using markers in a fine-grained way (for example, waiting on drawing
406 * to required pixmaps to complete, rather than waiting for all drawing to
407 * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker
408 * implementation fine-grained as well.
410 static void
411 ephyrWaitMarker(ScreenPtr pScreen, int marker)
413 KdScreenPriv(pScreen);
414 KdScreenInfo *screen = pScreenPriv->screen;
415 EphyrScrPriv *scrpriv = screen->driver;
416 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
418 fakexa->is_synced = TRUE;
422 * This function initializes EXA to use the fake acceleration implementation
423 * which just falls through to software. The purpose is to have a reliable,
424 * correct driver with which to test changes to the EXA core.
426 Bool
427 ephyrDrawInit(ScreenPtr pScreen)
429 KdScreenPriv(pScreen);
430 KdScreenInfo *screen = pScreenPriv->screen;
431 EphyrScrPriv *scrpriv = screen->driver;
432 EphyrFakexaPriv *fakexa;
433 Bool success;
435 fakexa = xcalloc(1, sizeof(*fakexa));
436 if (fakexa == NULL)
437 return FALSE;
439 fakexa->exa = exaDriverAlloc();
440 if (fakexa->exa == NULL) {
441 xfree(fakexa);
442 return FALSE;
445 fakexa->exa->memoryBase = screen->memory_base;
446 fakexa->exa->memorySize = screen->memory_size;
447 fakexa->exa->offScreenBase = screen->off_screen_base;
449 /* Since we statically link against EXA, we shouldn't have to be smart about
450 * versioning.
452 fakexa->exa->exa_major = 2;
453 fakexa->exa->exa_minor = 0;
455 fakexa->exa->PrepareSolid = ephyrPrepareSolid;
456 fakexa->exa->Solid = ephyrSolid;
457 fakexa->exa->DoneSolid = ephyrDoneSolid;
459 fakexa->exa->PrepareCopy = ephyrPrepareCopy;
460 fakexa->exa->Copy = ephyrCopy;
461 fakexa->exa->DoneCopy = ephyrDoneCopy;
463 fakexa->exa->CheckComposite = ephyrCheckComposite;
464 fakexa->exa->PrepareComposite = ephyrPrepareComposite;
465 fakexa->exa->Composite = ephyrComposite;
466 fakexa->exa->DoneComposite = ephyrDoneComposite;
468 fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen;
469 fakexa->exa->UploadToScreen = ephyrUploadToScreen;
471 fakexa->exa->MarkSync = ephyrMarkSync;
472 fakexa->exa->WaitMarker = ephyrWaitMarker;
474 fakexa->exa->PrepareAccess = ephyrPrepareAccess;
476 fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN;
477 fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN;
479 fakexa->exa->maxX = 1023;
480 fakexa->exa->maxY = 1023;
482 fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS;
484 success = exaDriverInit(pScreen, fakexa->exa);
485 if (success) {
486 ErrorF("Initialized fake EXA acceleration\n");
487 scrpriv->fakexa = fakexa;
488 } else {
489 ErrorF("Failed to initialize EXA\n");
490 xfree(fakexa->exa);
491 xfree(fakexa);
494 return success;
497 void
498 ephyrDrawEnable(ScreenPtr pScreen)
502 void
503 ephyrDrawDisable(ScreenPtr pScreen)
507 void
508 ephyrDrawFini(ScreenPtr pScreen)
513 * exaDDXDriverInit is required by the top-level EXA module, and is used by
514 * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since
515 * we won't be enabling/disabling the FB.
517 void
518 exaDDXDriverInit(ScreenPtr pScreen)
520 ExaScreenPriv(pScreen);
522 pExaScr->migration = ExaMigrationSmart;
523 pExaScr->hideOffscreenPixmapData = TRUE;
524 pExaScr->checkDirtyCorrectness = TRUE;