xref: /OK3568_Linux_fs/external/xserver/hw/kdrive/ephyr/ephyr_draw.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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