1/*
2 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
19 * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Except as contained in this notice, the name(s) of the above
25 * copyright holders shall not be used in advertising or otherwise to
26 * promote the sale, use or other dealings in this Software without
27 * prior written authorization.
28 */
29
30#ifdef HAVE_DIX_CONFIG_H
31#include <dix-config.h>
32#endif
33
34#include <stddef.h>
35#include "mi.h"
36#include "scrnintstr.h"
37#include "gcstruct.h"
38#include "pixmapstr.h"
39#include "windowstr.h"
40#include "dixfontstr.h"
41#include "mivalidate.h"
42#include "driWrap.h"
43#include "dri.h"
44
45#include <OpenGL/OpenGL.h>
46
47typedef struct {
48    GCOps const *originalOps;
49} DRIGCRec;
50
51typedef struct {
52    GCOps *originalOps;
53    CreateGCProcPtr CreateGC;
54} DRIWrapScreenRec;
55
56typedef struct {
57    Bool didSave;
58    int devKind;
59    DevUnion devPrivate;
60} DRISavedDrawableState;
61
62static DevPrivateKeyRec driGCKeyRec;
63#define driGCKey (&driGCKeyRec)
64
65static DevPrivateKeyRec driWrapScreenKeyRec;
66#define driWrapScreenKey (&driWrapScreenKeyRec)
67
68static GCOps driGCOps;
69
70#define wrap(priv, real, member, func) { \
71        priv->member = real->member; \
72        real->member = func; \
73}
74
75#define unwrap(priv, real, member)     { \
76        real->member = priv->member; \
77}
78
79static DRIGCRec *
80DRIGetGCPriv(GCPtr pGC)
81{
82    return dixLookupPrivate(&pGC->devPrivates, driGCKey);
83}
84
85static void
86DRIUnwrapGC(GCPtr pGC)
87{
88    DRIGCRec *pGCPriv = DRIGetGCPriv(pGC);
89
90    pGC->ops = pGCPriv->originalOps;
91}
92
93static void
94DRIWrapGC(GCPtr pGC)
95{
96    pGC->ops = &driGCOps;
97}
98
99static void
100DRISurfaceSetDrawable(DrawablePtr pDraw,
101                      DRISavedDrawableState *saved)
102{
103    saved->didSave = FALSE;
104
105    if (pDraw->type == DRAWABLE_PIXMAP) {
106        int pitch, width, height, bpp;
107        void *buffer;
108
109        if (DRIGetPixmapData(pDraw, &width, &height, &pitch, &bpp,
110                             &buffer)) {
111            PixmapPtr pPix = (PixmapPtr)pDraw;
112
113            saved->devKind = pPix->devKind;
114            saved->devPrivate.ptr = pPix->devPrivate.ptr;
115            saved->didSave = TRUE;
116
117            pPix->devKind = pitch;
118            pPix->devPrivate.ptr = buffer;
119        }
120    }
121}
122
123static void
124DRISurfaceRestoreDrawable(DrawablePtr pDraw,
125                          DRISavedDrawableState *saved)
126{
127    PixmapPtr pPix = (PixmapPtr)pDraw;
128
129    if (!saved->didSave)
130        return;
131
132    pPix->devKind = saved->devKind;
133    pPix->devPrivate.ptr = saved->devPrivate.ptr;
134}
135
136static void
137DRIFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
138             DDXPointPtr pptInit, int *pwidthInit,
139             int sorted)
140{
141    DRISavedDrawableState saved;
142
143    DRISurfaceSetDrawable(dst, &saved);
144
145    DRIUnwrapGC(pGC);
146
147    pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
148
149    DRIWrapGC(pGC);
150
151    DRISurfaceRestoreDrawable(dst, &saved);
152}
153
154static void
155DRISetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
156            DDXPointPtr pptInit, int *pwidthInit,
157            int nspans, int sorted)
158{
159    DRISavedDrawableState saved;
160
161    DRISurfaceSetDrawable(dst, &saved);
162
163    DRIUnwrapGC(pGC);
164
165    pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted);
166
167    DRIWrapGC(pGC);
168
169    DRISurfaceRestoreDrawable(dst, &saved);
170}
171
172static void
173DRIPutImage(DrawablePtr dst, GCPtr pGC,
174            int depth, int x, int y, int w, int h,
175            int leftPad, int format, char *pBits)
176{
177    DRISavedDrawableState saved;
178
179    DRISurfaceSetDrawable(dst, &saved);
180
181    DRIUnwrapGC(pGC);
182
183    pGC->ops->PutImage(dst, pGC, depth, x, y, w, h, leftPad, format, pBits);
184
185    DRIWrapGC(pGC);
186
187    DRISurfaceRestoreDrawable(dst, &saved);
188}
189
190static RegionPtr
191DRICopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
192            int srcx, int srcy, int w, int h,
193            int dstx, int dsty)
194{
195    RegionPtr pReg;
196    DRISavedDrawableState pSrcSaved, dstSaved;
197
198    DRISurfaceSetDrawable(pSrc, &pSrcSaved);
199    DRISurfaceSetDrawable(dst, &dstSaved);
200
201    DRIUnwrapGC(pGC);
202
203    pReg = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty);
204
205    DRIWrapGC(pGC);
206
207    DRISurfaceRestoreDrawable(pSrc, &pSrcSaved);
208    DRISurfaceRestoreDrawable(dst, &dstSaved);
209
210    return pReg;
211}
212
213static RegionPtr
214DRICopyPlane(DrawablePtr pSrc, DrawablePtr dst,
215             GCPtr pGC, int srcx, int srcy,
216             int w, int h, int dstx, int dsty,
217             unsigned long plane)
218{
219    RegionPtr pReg;
220    DRISavedDrawableState pSrcSaved, dstSaved;
221
222    DRISurfaceSetDrawable(pSrc, &pSrcSaved);
223    DRISurfaceSetDrawable(dst, &dstSaved);
224
225    DRIUnwrapGC(pGC);
226
227    pReg = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty,
228                               plane);
229
230    DRIWrapGC(pGC);
231
232    DRISurfaceRestoreDrawable(pSrc, &pSrcSaved);
233    DRISurfaceRestoreDrawable(dst, &dstSaved);
234
235    return pReg;
236}
237
238static void
239DRIPolyPoint(DrawablePtr dst, GCPtr pGC,
240             int mode, int npt, DDXPointPtr pptInit)
241{
242    DRISavedDrawableState saved;
243
244    DRISurfaceSetDrawable(dst, &saved);
245
246    DRIUnwrapGC(pGC);
247
248    pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit);
249
250    DRIWrapGC(pGC);
251
252    DRISurfaceRestoreDrawable(dst, &saved);
253}
254
255static void
256DRIPolylines(DrawablePtr dst, GCPtr pGC,
257             int mode, int npt, DDXPointPtr pptInit)
258{
259    DRISavedDrawableState saved;
260
261    DRISurfaceSetDrawable(dst, &saved);
262
263    DRIUnwrapGC(pGC);
264
265    pGC->ops->Polylines(dst, pGC, mode, npt, pptInit);
266
267    DRIWrapGC(pGC);
268
269    DRISurfaceRestoreDrawable(dst, &saved);
270}
271
272static void
273DRIPolySegment(DrawablePtr dst, GCPtr pGC,
274               int nseg, xSegment *pSeg)
275{
276    DRISavedDrawableState saved;
277
278    DRISurfaceSetDrawable(dst, &saved);
279
280    DRIUnwrapGC(pGC);
281
282    pGC->ops->PolySegment(dst, pGC, nseg, pSeg);
283
284    DRIWrapGC(pGC);
285
286    DRISurfaceRestoreDrawable(dst, &saved);
287}
288
289static void
290DRIPolyRectangle(DrawablePtr dst, GCPtr pGC,
291                 int nRects, xRectangle *pRects)
292{
293    DRISavedDrawableState saved;
294
295    DRISurfaceSetDrawable(dst, &saved);
296
297    DRIUnwrapGC(pGC);
298
299    pGC->ops->PolyRectangle(dst, pGC, nRects, pRects);
300
301    DRIWrapGC(pGC);
302
303    DRISurfaceRestoreDrawable(dst, &saved);
304}
305static void
306DRIPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs)
307{
308    DRISavedDrawableState saved;
309
310    DRISurfaceSetDrawable(dst, &saved);
311
312    DRIUnwrapGC(pGC);
313
314    pGC->ops->PolyArc(dst, pGC, narcs, parcs);
315
316    DRIWrapGC(pGC);
317
318    DRISurfaceRestoreDrawable(dst, &saved);
319}
320
321static void
322DRIFillPolygon(DrawablePtr dst, GCPtr pGC,
323               int shape, int mode, int count,
324               DDXPointPtr pptInit)
325{
326    DRISavedDrawableState saved;
327
328    DRISurfaceSetDrawable(dst, &saved);
329
330    DRIUnwrapGC(pGC);
331
332    pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
333
334    DRIWrapGC(pGC);
335
336    DRISurfaceRestoreDrawable(dst, &saved);
337}
338
339static void
340DRIPolyFillRect(DrawablePtr dst, GCPtr pGC,
341                int nRectsInit, xRectangle *pRectsInit)
342{
343    DRISavedDrawableState saved;
344
345    DRISurfaceSetDrawable(dst, &saved);
346
347    DRIUnwrapGC(pGC);
348
349    pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
350
351    DRIWrapGC(pGC);
352
353    DRISurfaceRestoreDrawable(dst, &saved);
354}
355
356static void
357DRIPolyFillArc(DrawablePtr dst, GCPtr pGC,
358               int narcsInit, xArc *parcsInit)
359{
360    DRISavedDrawableState saved;
361
362    DRISurfaceSetDrawable(dst, &saved);
363
364    DRIUnwrapGC(pGC);
365
366    pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
367
368    DRIWrapGC(pGC);
369
370    DRISurfaceRestoreDrawable(dst, &saved);
371}
372
373static int
374DRIPolyText8(DrawablePtr dst, GCPtr pGC,
375             int x, int y, int count, char *chars)
376{
377    int ret;
378    DRISavedDrawableState saved;
379
380    DRISurfaceSetDrawable(dst, &saved);
381
382    DRIUnwrapGC(pGC);
383
384    ret = pGC->ops->PolyText8(dst, pGC, x, y, count, chars);
385
386    DRIWrapGC(pGC);
387
388    DRISurfaceRestoreDrawable(dst, &saved);
389
390    return ret;
391}
392
393static int
394DRIPolyText16(DrawablePtr dst, GCPtr pGC,
395              int x, int y, int count, unsigned short *chars)
396{
397    int ret;
398    DRISavedDrawableState saved;
399
400    DRISurfaceSetDrawable(dst, &saved);
401
402    DRIUnwrapGC(pGC);
403
404    ret = pGC->ops->PolyText16(dst, pGC, x, y, count, chars);
405
406    DRIWrapGC(pGC);
407
408    DRISurfaceRestoreDrawable(dst, &saved);
409
410    return ret;
411}
412
413static void
414DRIImageText8(DrawablePtr dst, GCPtr pGC,
415              int x, int y, int count, char *chars)
416{
417    DRISavedDrawableState saved;
418
419    DRISurfaceSetDrawable(dst, &saved);
420
421    DRIUnwrapGC(pGC);
422
423    pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
424
425    DRIWrapGC(pGC);
426
427    DRISurfaceRestoreDrawable(dst, &saved);
428}
429
430static void
431DRIImageText16(DrawablePtr dst, GCPtr pGC,
432               int x, int y, int count, unsigned short *chars)
433{
434    DRISavedDrawableState saved;
435
436    DRISurfaceSetDrawable(dst, &saved);
437
438    DRIUnwrapGC(pGC);
439
440    pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
441
442    DRIWrapGC(pGC);
443
444    DRISurfaceRestoreDrawable(dst, &saved);
445}
446
447static void
448DRIImageGlyphBlt(DrawablePtr dst, GCPtr pGC,
449                 int x, int y, unsigned int nglyphInit,
450                 CharInfoPtr *ppciInit, void *unused)
451{
452    DRISavedDrawableState saved;
453
454    DRISurfaceSetDrawable(dst, &saved);
455
456    DRIUnwrapGC(pGC);
457
458    pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
459
460    DRIWrapGC(pGC);
461
462    DRISurfaceRestoreDrawable(dst, &saved);
463}
464
465static void
466DRIPolyGlyphBlt(DrawablePtr dst, GCPtr pGC,
467                int x, int y, unsigned int nglyph,
468                CharInfoPtr *ppci, void *pglyphBase)
469{
470    DRISavedDrawableState saved;
471
472    DRISurfaceSetDrawable(dst, &saved);
473
474    DRIUnwrapGC(pGC);
475
476    pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase);
477
478    DRIWrapGC(pGC);
479
480    DRISurfaceRestoreDrawable(dst, &saved);
481}
482
483static void
484DRIPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
485              int dx, int dy, int xOrg, int yOrg)
486{
487    DRISavedDrawableState bitMapSaved, dstSaved;
488
489    DRISurfaceSetDrawable(&pBitMap->drawable, &bitMapSaved);
490    DRISurfaceSetDrawable(dst, &dstSaved);
491
492    DRIUnwrapGC(pGC);
493
494    pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg);
495
496    DRIWrapGC(pGC);
497
498    DRISurfaceRestoreDrawable(&pBitMap->drawable, &bitMapSaved);
499    DRISurfaceRestoreDrawable(dst, &dstSaved);
500}
501
502static GCOps driGCOps = {
503    DRIFillSpans,
504    DRISetSpans,
505    DRIPutImage,
506    DRICopyArea,
507    DRICopyPlane,
508    DRIPolyPoint,
509    DRIPolylines,
510    DRIPolySegment,
511    DRIPolyRectangle,
512    DRIPolyArc,
513    DRIFillPolygon,
514    DRIPolyFillRect,
515    DRIPolyFillArc,
516    DRIPolyText8,
517    DRIPolyText16,
518    DRIImageText8,
519    DRIImageText16,
520    DRIImageGlyphBlt,
521    DRIPolyGlyphBlt,
522    DRIPushPixels
523};
524
525static Bool
526DRICreateGC(GCPtr pGC)
527{
528    ScreenPtr pScreen = pGC->pScreen;
529    DRIWrapScreenRec *pScreenPriv;
530    DRIGCRec *pGCPriv;
531    Bool ret;
532
533    pScreenPriv = dixLookupPrivate(&pScreen->devPrivates, driWrapScreenKey);
534
535    pGCPriv = DRIGetGCPriv(pGC);
536
537    unwrap(pScreenPriv, pScreen, CreateGC);
538    ret = pScreen->CreateGC(pGC);
539
540    if (ret) {
541        pGCPriv->originalOps = pGC->ops;
542        pGC->ops = &driGCOps;
543    }
544
545    wrap(pScreenPriv, pScreen, CreateGC, DRICreateGC);
546
547    return ret;
548}
549
550/* Return false if an error occurred. */
551Bool
552DRIWrapInit(ScreenPtr pScreen)
553{
554    DRIWrapScreenRec *pScreenPriv;
555
556    if (!dixRegisterPrivateKey(&driGCKeyRec, PRIVATE_GC, sizeof(DRIGCRec)))
557        return FALSE;
558
559    if (!dixRegisterPrivateKey(&driWrapScreenKeyRec, PRIVATE_SCREEN,
560                               sizeof(DRIWrapScreenRec)))
561        return FALSE;
562
563    pScreenPriv = dixGetPrivateAddr(&pScreen->devPrivates,
564                                    &driWrapScreenKeyRec);
565    pScreenPriv->CreateGC = pScreen->CreateGC;
566    pScreen->CreateGC = DRICreateGC;
567
568    return TRUE;
569}
570