xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/shadowfb/shadowfb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2    Copyright (C) 1999.  The XFree86 Project Inc.
3    Copyright 2014 Red Hat, Inc.
4 
5    Written by Mark Vojkovich (mvojkovi@ucsd.edu)
6    Pre-fb-write callbacks and RENDER support - Nolan Leake (nolan@vmware.com)
7 */
8 
9 #ifdef HAVE_XORG_CONFIG_H
10 #include <xorg-config.h>
11 #endif
12 
13 #include <X11/X.h>
14 #include <X11/Xproto.h>
15 #include "misc.h"
16 #include "pixmapstr.h"
17 #include "input.h"
18 #include <X11/fonts/font.h>
19 #include "mi.h"
20 #include "scrnintstr.h"
21 #include "windowstr.h"
22 #include "gcstruct.h"
23 #include "dixfontstr.h"
24 #include <X11/fonts/fontstruct.h>
25 #include "xf86.h"
26 #include "xf86str.h"
27 #include "shadowfb.h"
28 
29 #include "picturestr.h"
30 
31 static Bool ShadowCloseScreen(ScreenPtr pScreen);
32 static Bool ShadowCreateRootWindow(WindowPtr pWin);
33 
34 typedef struct {
35     ScrnInfoPtr pScrn;
36     RefreshAreaFuncPtr preRefresh;
37     RefreshAreaFuncPtr postRefresh;
38     CloseScreenProcPtr CloseScreen;
39     CreateWindowProcPtr CreateWindow;
40 } ShadowScreenRec, *ShadowScreenPtr;
41 
42 static DevPrivateKeyRec ShadowScreenKeyRec;
43 
44 static ShadowScreenPtr
shadowfbGetScreenPrivate(ScreenPtr pScreen)45 shadowfbGetScreenPrivate(ScreenPtr pScreen)
46 {
47     return dixLookupPrivate(&(pScreen)->devPrivates, &ShadowScreenKeyRec);
48 }
49 
50 Bool
ShadowFBInit2(ScreenPtr pScreen,RefreshAreaFuncPtr preRefreshArea,RefreshAreaFuncPtr postRefreshArea)51 ShadowFBInit2(ScreenPtr pScreen,
52               RefreshAreaFuncPtr preRefreshArea,
53               RefreshAreaFuncPtr postRefreshArea)
54 {
55     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
56     ShadowScreenPtr pPriv;
57 
58     if (!preRefreshArea && !postRefreshArea)
59         return FALSE;
60 
61     if (!dixRegisterPrivateKey(&ShadowScreenKeyRec, PRIVATE_SCREEN, 0))
62         return FALSE;
63 
64     if (!(pPriv = (ShadowScreenPtr) malloc(sizeof(ShadowScreenRec))))
65         return FALSE;
66 
67     dixSetPrivate(&pScreen->devPrivates, &ShadowScreenKeyRec, pPriv);
68 
69     pPriv->pScrn = pScrn;
70     pPriv->preRefresh = preRefreshArea;
71     pPriv->postRefresh = postRefreshArea;
72 
73     pPriv->CloseScreen = pScreen->CloseScreen;
74     pPriv->CreateWindow = pScreen->CreateWindow;
75 
76     pScreen->CloseScreen = ShadowCloseScreen;
77     pScreen->CreateWindow = ShadowCreateRootWindow;
78 
79     return TRUE;
80 }
81 
82 Bool
ShadowFBInit(ScreenPtr pScreen,RefreshAreaFuncPtr refreshArea)83 ShadowFBInit(ScreenPtr pScreen, RefreshAreaFuncPtr refreshArea)
84 {
85     return ShadowFBInit2(pScreen, NULL, refreshArea);
86 }
87 
88 /*
89  * Note that we don't do DamageEmpty, or indeed look at the region inside the
90  * DamagePtr at all.  This is an optimization, believe it or not.  The
91  * incoming RegionPtr is the new damage, and if we were to empty the region
92  * miext/damage would just have to waste time reallocating and re-unioning
93  * it every time, whereas if we leave it around the union gets fast-pathed
94  * away.
95  */
96 
97 static void
shadowfbReportPre(DamagePtr damage,RegionPtr reg,void * closure)98 shadowfbReportPre(DamagePtr damage, RegionPtr reg, void *closure)
99 {
100     ShadowScreenPtr pPriv = closure;
101 
102     if (!pPriv->pScrn->vtSema)
103         return;
104 
105     pPriv->preRefresh(pPriv->pScrn, RegionNumRects(reg), RegionRects(reg));
106 }
107 
108 static void
shadowfbReportPost(DamagePtr damage,RegionPtr reg,void * closure)109 shadowfbReportPost(DamagePtr damage, RegionPtr reg, void *closure)
110 {
111     ShadowScreenPtr pPriv = closure;
112 
113     if (!pPriv->pScrn->vtSema)
114         return;
115 
116     pPriv->postRefresh(pPriv->pScrn, RegionNumRects(reg), RegionRects(reg));
117 }
118 
119 static Bool
ShadowCreateRootWindow(WindowPtr pWin)120 ShadowCreateRootWindow(WindowPtr pWin)
121 {
122     Bool ret;
123     ScreenPtr pScreen = pWin->drawable.pScreen;
124     ShadowScreenPtr pPriv = shadowfbGetScreenPrivate(pScreen);
125 
126     /* paranoia */
127     if (pWin != pScreen->root)
128         ErrorF("ShadowCreateRootWindow called unexpectedly\n");
129 
130     /* call down, but don't hook ourselves back in; we know the first time
131      * we're called it's for the root window.
132      */
133     pScreen->CreateWindow = pPriv->CreateWindow;
134     ret = pScreen->CreateWindow(pWin);
135 
136     /* this might look like it leaks, but the damage code reaps listeners
137      * when their drawable disappears.
138      */
139     if (ret) {
140         DamagePtr damage;
141 
142         if (pPriv->preRefresh) {
143             damage = DamageCreate(shadowfbReportPre, NULL,
144                                   DamageReportRawRegion,
145                                   TRUE, pScreen, pPriv);
146             DamageRegister(&pWin->drawable, damage);
147         }
148 
149         if (pPriv->postRefresh) {
150             damage = DamageCreate(shadowfbReportPost, NULL,
151                                   DamageReportRawRegion,
152                                   TRUE, pScreen, pPriv);
153             DamageSetReportAfterOp(damage, TRUE);
154             DamageRegister(&pWin->drawable, damage);
155         }
156     }
157 
158     return ret;
159 }
160 
161 static Bool
ShadowCloseScreen(ScreenPtr pScreen)162 ShadowCloseScreen(ScreenPtr pScreen)
163 {
164     ShadowScreenPtr pPriv = shadowfbGetScreenPrivate(pScreen);
165 
166     pScreen->CloseScreen = pPriv->CloseScreen;
167 
168     free(pPriv);
169 
170     return (*pScreen->CloseScreen) (pScreen);
171 }
172