Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / kdrive / ephyr / ephyr_draw.c
CommitLineData
a09e091a
JB
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_CONFIG_H
29#include <kdrive-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 */
55static void
56ephyrPreparePipelinedAccess(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 */
76static void
77ephyrFinishPipelinedAccess(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 */
92static Bool
93ephyrPrepareSolid(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 */
124static void
125ephyrSolid(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 */
140static void
141ephyrDoneSolid(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 */
159static Bool
160ephyrPrepareCopy(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 */
192static void
193ephyrCopy(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 */
209static void
210ephyrDoneCopy(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 */
230static Bool
231ephyrCheckComposite(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 */
246static Bool
247ephyrPrepareComposite(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 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
258 if (pMask != NULL)
259 ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK);
260
261 fakexa->op = op;
262 fakexa->pSrcPicture = pSrcPicture;
263 fakexa->pMaskPicture = pMaskPicture;
264 fakexa->pDstPicture = pDstPicture;
265 fakexa->pSrc = pSrc;
266 fakexa->pMask = pMask;
267 fakexa->pDst = pDst;
268
269 TRACE_DRAW();
270
271 return TRUE;
272}
273
274/**
275 * Does an fbComposite to complete the requested drawing operation.
276 */
277static void
278ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
279 int dstX, int dstY, int w, int h)
280{
281 KdScreenPriv(pDst->drawable.pScreen);
282 KdScreenInfo *screen = pScreenPriv->screen;
283 EphyrScrPriv *scrpriv = screen->driver;
284 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
285
286 fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture,
287 fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY,
288 w, h);
289}
290
291static void
292ephyrDoneComposite(PixmapPtr pDst)
293{
294 KdScreenPriv(pDst->drawable.pScreen);
295 KdScreenInfo *screen = pScreenPriv->screen;
296 EphyrScrPriv *scrpriv = screen->driver;
297 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
298
299 if (fakexa->pMask != NULL)
300 ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK);
301 ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC);
302 ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST);
303}
304
305/**
306 * Does fake acceleration of DownloadFromScren using memcpy.
307 */
308static Bool
309ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst,
310 int dst_pitch)
311{
312 KdScreenPriv(pSrc->drawable.pScreen);
313 KdScreenInfo *screen = pScreenPriv->screen;
314 EphyrScrPriv *scrpriv = screen->driver;
315 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
316 unsigned char *src;
317 int src_pitch, cpp;
318
319 if (pSrc->drawable.bitsPerPixel < 8)
320 return FALSE;
321
322 ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC);
323
324 cpp = pSrc->drawable.bitsPerPixel / 8;
325 src_pitch = exaGetPixmapPitch(pSrc);
326 src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc);
327 src += y * src_pitch + x * cpp;
328
329 for (; h > 0; h--) {
330 memcpy(dst, src, w * cpp);
331 dst += dst_pitch;
332 src += src_pitch;
333 }
334
335 exaMarkSync(pSrc->drawable.pScreen);
336
337 ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC);
338
339 return TRUE;
340}
341
342/**
343 * Does fake acceleration of UploadToScreen using memcpy.
344 */
345static Bool
346ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
347 int src_pitch)
348{
349 KdScreenPriv(pDst->drawable.pScreen);
350 KdScreenInfo *screen = pScreenPriv->screen;
351 EphyrScrPriv *scrpriv = screen->driver;
352 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
353 unsigned char *dst;
354 int dst_pitch, cpp;
355
356 if (pDst->drawable.bitsPerPixel < 8)
357 return FALSE;
358
359 ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST);
360
361 cpp = pDst->drawable.bitsPerPixel / 8;
362 dst_pitch = exaGetPixmapPitch(pDst);
363 dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst);
364 dst += y * dst_pitch + x * cpp;
365
366 for (; h > 0; h--) {
367 memcpy(dst, src, w * cpp);
368 dst += dst_pitch;
369 src += src_pitch;
370 }
371
372 exaMarkSync(pDst->drawable.pScreen);
373
374 ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST);
375
376 return TRUE;
377}
378
379static Bool
380ephyrPrepareAccess(PixmapPtr pPix, int index)
381{
382 /* Make sure we don't somehow end up with a pointer that is in framebuffer
383 * and hasn't been readied for us.
384 */
385 assert(pPix->devPrivate.ptr != NULL);
386
387 return TRUE;
388}
389
390/**
391 * In fakexa, we currently only track whether we have synced to the latest
392 * "accelerated" drawing that has happened or not. It's not used for anything
393 * yet.
394 */
395static int
396ephyrMarkSync(ScreenPtr pScreen)
397{
398 KdScreenPriv(pScreen);
399 KdScreenInfo *screen = pScreenPriv->screen;
400 EphyrScrPriv *scrpriv = screen->driver;
401 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
402
403 fakexa->is_synced = FALSE;
404
405 return 0;
406}
407
408/**
409 * Assumes that we're waiting on the latest marker. When EXA gets smarter and
410 * starts using markers in a fine-grained way (for example, waiting on drawing
411 * to required pixmaps to complete, rather than waiting for all drawing to
412 * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker
413 * implementation fine-grained as well.
414 */
415static void
416ephyrWaitMarker(ScreenPtr pScreen, int marker)
417{
418 KdScreenPriv(pScreen);
419 KdScreenInfo *screen = pScreenPriv->screen;
420 EphyrScrPriv *scrpriv = screen->driver;
421 EphyrFakexaPriv *fakexa = scrpriv->fakexa;
422
423 fakexa->is_synced = TRUE;
424}
425
426/**
427 * This function initializes EXA to use the fake acceleration implementation
428 * which just falls through to software. The purpose is to have a reliable,
429 * correct driver with which to test changes to the EXA core.
430 */
431Bool
432ephyrDrawInit(ScreenPtr pScreen)
433{
434 KdScreenPriv(pScreen);
435 KdScreenInfo *screen = pScreenPriv->screen;
436 EphyrScrPriv *scrpriv = screen->driver;
437 EphyrPriv *priv = screen->card->driver;
438 EphyrFakexaPriv *fakexa;
439 Bool success;
440
441 fakexa = calloc(1, sizeof(*fakexa));
442 if (fakexa == NULL)
443 return FALSE;
444
445 fakexa->exa = exaDriverAlloc();
446 if (fakexa->exa == NULL) {
447 free(fakexa);
448 return FALSE;
449 }
450
451 fakexa->exa->memoryBase = (CARD8 *) (priv->base);
452 fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen);
453 fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height;
454
455 /* Since we statically link against EXA, we shouldn't have to be smart about
456 * versioning.
457 */
458 fakexa->exa->exa_major = 2;
459 fakexa->exa->exa_minor = 0;
460
461 fakexa->exa->PrepareSolid = ephyrPrepareSolid;
462 fakexa->exa->Solid = ephyrSolid;
463 fakexa->exa->DoneSolid = ephyrDoneSolid;
464
465 fakexa->exa->PrepareCopy = ephyrPrepareCopy;
466 fakexa->exa->Copy = ephyrCopy;
467 fakexa->exa->DoneCopy = ephyrDoneCopy;
468
469 fakexa->exa->CheckComposite = ephyrCheckComposite;
470 fakexa->exa->PrepareComposite = ephyrPrepareComposite;
471 fakexa->exa->Composite = ephyrComposite;
472 fakexa->exa->DoneComposite = ephyrDoneComposite;
473
474 fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen;
475 fakexa->exa->UploadToScreen = ephyrUploadToScreen;
476
477 fakexa->exa->MarkSync = ephyrMarkSync;
478 fakexa->exa->WaitMarker = ephyrWaitMarker;
479
480 fakexa->exa->PrepareAccess = ephyrPrepareAccess;
481
482 fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN;
483 fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN;
484
485 fakexa->exa->maxX = 1023;
486 fakexa->exa->maxY = 1023;
487
488 fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS;
489
490 success = exaDriverInit(pScreen, fakexa->exa);
491 if (success) {
492 ErrorF("Initialized fake EXA acceleration\n");
493 scrpriv->fakexa = fakexa;
494 }
495 else {
496 ErrorF("Failed to initialize EXA\n");
497 free(fakexa->exa);
498 free(fakexa);
499 }
500
501 return success;
502}
503
504void
505ephyrDrawEnable(ScreenPtr pScreen)
506{
507}
508
509void
510ephyrDrawDisable(ScreenPtr pScreen)
511{
512}
513
514void
515ephyrDrawFini(ScreenPtr pScreen)
516{
517}
518
519/**
520 * exaDDXDriverInit is required by the top-level EXA module, and is used by
521 * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since
522 * we won't be enabling/disabling the FB.
523 */
524void
525exaDDXDriverInit(ScreenPtr pScreen)
526{
527 ExaScreenPriv(pScreen);
528
529 pExaScr->migration = ExaMigrationSmart;
530 pExaScr->checkDirtyCorrectness = TRUE;
531}