shadowfb.c revision 1b5d61b8
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
31static Bool ShadowCloseScreen(ScreenPtr pScreen);
32static Bool ShadowCreateRootWindow(WindowPtr pWin);
33
34typedef struct {
35    ScrnInfoPtr pScrn;
36    RefreshAreaFuncPtr preRefresh;
37    RefreshAreaFuncPtr postRefresh;
38    CloseScreenProcPtr CloseScreen;
39    CreateWindowProcPtr CreateWindow;
40} ShadowScreenRec, *ShadowScreenPtr;
41
42static DevPrivateKeyRec ShadowScreenKeyRec;
43
44static ShadowScreenPtr
45shadowfbGetScreenPrivate(ScreenPtr pScreen)
46{
47    return dixLookupPrivate(&(pScreen)->devPrivates, &ShadowScreenKeyRec);
48}
49
50Bool
51ShadowFBInit2(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
82Bool
83ShadowFBInit(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
97static void
98shadowfbReportPre(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
108static void
109shadowfbReportPost(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
119static Bool
120ShadowCreateRootWindow(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
161static Bool
162ShadowCloseScreen(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