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