Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / kdrive / ephyr / ephyr_draw.c
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 */
55 static void
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
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
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
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
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
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
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
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
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
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 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 */
277 static void
278 ephyrComposite(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
291 static void
292 ephyrDoneComposite(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 */
308 static Bool
309 ephyrDownloadFromScreen(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 */
345 static Bool
346 ephyrUploadToScreen(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
379 static Bool
380 ephyrPrepareAccess(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 */
395 static int
396 ephyrMarkSync(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 */
415 static void
416 ephyrWaitMarker(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 */
431 Bool
432 ephyrDrawInit(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
504 void
505 ephyrDrawEnable(ScreenPtr pScreen)
506 {
507 }
508
509 void
510 ephyrDrawDisable(ScreenPtr pScreen)
511 {
512 }
513
514 void
515 ephyrDrawFini(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 */
524 void
525 exaDDXDriverInit(ScreenPtr pScreen)
526 {
527 ExaScreenPriv(pScreen);
528
529 pExaScr->migration = ExaMigrationSmart;
530 pExaScr->checkDirtyCorrectness = TRUE;
531 }