-
Notifications
You must be signed in to change notification settings - Fork 82
Expand file tree
/
Copy pathbacking_store_tuner.c
More file actions
208 lines (182 loc) · 8.2 KB
/
Copy pathbacking_store_tuner.c
File metadata and controls
208 lines (182 loc) · 8.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
* Copyright © 2013 Siarhei Siamashka <siarhei.siamashka@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xorgVersion.h"
#include "xf86.h"
#include "fb.h"
#include "inputstr.h"
#include "fbdev_priv.h"
#include "backing_store_tuner.h"
/*
* This code implements a heuristics, which enables backing store for some
* windows. When backing store is enabled for a window, the window gets a
* backing pixmap (via automatic redirection provided by composite extension).
* It acts a bit similar to ShadowFB, but for individual windows.
*
* The advantage of backing store is that we can avoid "expose event -> redraw"
* animated trail in the exposed area when dragging another window on top of it.
* Dragging windows becomes much smoother and faster.
*
* But the disadvantage of backing store is the same as for ShadowFB. That's a
* loss of precious RAM, extra buffer copy when somebody tries to update window
* content, potentially skip of some frames on fast animation (they just do
* not reach screen). Also hardware accelerated scrolling does not currently
* work for the windows with backing store enabled.
*
* We try to make the best use of backing store by enabling backing store for
* all the windows that are direct children of root, except the one which has
* keyboard focus (either directly or via one of its children). In practice this
* heuristics seems to provide nearly perfect results:
* 1) dragging windows is fast and smooth.
* 2) the top level window with the keyboard focus (typically the application
* that a user is working with) is G2D accelerated and does not suffer from
* any intermediate buffer copy overhead.
*/
static void
xPostValidateTree(WindowPtr pWin, WindowPtr pLayerWin, VTKind kind)
{
ScreenPtr pScreen = pWin ? pWin->drawable.pScreen :
pLayerWin->drawable.pScreen;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
BackingStoreTuner *private = BACKING_STORE_TUNER(pScrn);
WindowPtr curWin, focusWin = NULL;
/*
* Increment and backup the current counter. Because ChangeWindowAttributes
* may trigger nested PostValidateTree calls, we want to detect this
* situation and bail out (assuming that the nested PostValidateTree
* call already did the job)
*/
unsigned int CurrentCount = ++private->PostValidateTreeCount;
/* Call the original PostValidateTree */
if (private->PostValidateTree) {
pScreen->PostValidateTree = private->PostValidateTree;
(*pScreen->PostValidateTree) (pWin, pLayerWin, kind);
private->PostValidateTree = pScreen->PostValidateTree;
pScreen->PostValidateTree = xPostValidateTree;
}
/* Find the window with keyboard focus */
if (inputInfo.keyboard && inputInfo.keyboard->focus)
focusWin = inputInfo.keyboard->focus->win;
if (!pWin || !focusWin || focusWin == NoneWin || focusWin == PointerRootWin)
return;
/* Descend down to the window, which has the root window as a parent */
while (focusWin->parent && focusWin->parent != pScreen->root)
focusWin = focusWin->parent;
if (focusWin->parent != pScreen->root)
return;
/*
* We are a bit paranoid here and want to eliminate any possibility
* of infinite recursion
*/
if (private->PostValidateTreeNestingLevel > 4) {
DebugMsg("Oops, too much nesting for PostValidateTree, bailing out\n");
return;
}
private->PostValidateTreeNestingLevel++;
/* Disable backing store for the focus window */
if (!private->ForceBackingStore && focusWin->backingStore) {
DebugMsg("Disable backing store for the focus window 0x%x\n",
(unsigned int)focusWin->drawable.id);
pScreen->backingStoreSupport = Always;
focusWin->backingStore = NotUseful;
(*pScreen->ChangeWindowAttributes) (focusWin, CWBackingStore);
if (CurrentCount != private->PostValidateTreeCount) {
DebugMsg("Nested PostValidateTree in ChangeWindowAttributes\n");
private->PostValidateTreeNestingLevel--;
return;
}
}
/* And enable backing store for all the other children of root */
curWin = pScreen->root->firstChild;
while (curWin) {
if (!curWin->backingStore && (private->ForceBackingStore ||
curWin != focusWin)) {
DebugMsg("Enable backing store for window 0x%x\n",
(unsigned int)curWin->drawable.id);
pScreen->backingStoreSupport = Always;
curWin->backingStore = WhenMapped;
(*pScreen->ChangeWindowAttributes) (curWin, CWBackingStore);
if (CurrentCount != private->PostValidateTreeCount) {
DebugMsg("Nested PostValidateTree in ChangeWindowAttributes\n");
private->PostValidateTreeNestingLevel--;
return;
}
}
curWin = curWin->nextSib;
}
private->PostValidateTreeNestingLevel--;
}
static void
xReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
BackingStoreTuner *private = BACKING_STORE_TUNER(pScrn);
if (private->ReparentWindow) {
pScreen->ReparentWindow = private->ReparentWindow;
(*pScreen->ReparentWindow) (pWin, pPriorParent);
private->ReparentWindow = pScreen->ReparentWindow;
pScreen->ReparentWindow = xReparentWindow;
}
/* We only want backing store set for direct children of root */
if (pPriorParent == pScreen->root && pWin->backingStore) {
DebugMsg("Reparent window 0x%x from root, disabling backing store\n",
(unsigned int)pWin->drawable.id);
pScreen->backingStoreSupport = Always;
pWin->backingStore = NotUseful;
(*pScreen->ChangeWindowAttributes) (pWin, CWBackingStore);
}
}
/*****************************************************************************/
BackingStoreTuner *BackingStoreTuner_Init(ScreenPtr pScreen, Bool force)
{
BackingStoreTuner *private = calloc(1, sizeof(BackingStoreTuner));
if (!private) {
xf86DrvMsg(pScreen->myNum, X_INFO,
"BackingStoreTuner_Init: calloc failed\n");
return NULL;
}
private->ForceBackingStore = force;
if (private->ForceBackingStore)
xf86DrvMsg(pScreen->myNum, X_INFO,
"automatically forcing backing store for all windows\n");
else
xf86DrvMsg(pScreen->myNum, X_INFO,
"using backing store heuristics\n");
/* Wrap the current PostValidateTree function */
private->PostValidateTree = pScreen->PostValidateTree;
pScreen->PostValidateTree = xPostValidateTree;
/* Wrap the current ReparentWindow function */
private->ReparentWindow = pScreen->ReparentWindow;
pScreen->ReparentWindow = xReparentWindow;
return private;
}
void BackingStoreTuner_Close(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
BackingStoreTuner *private = BACKING_STORE_TUNER(pScrn);
pScreen->PostValidateTree = private->PostValidateTree;
pScreen->ReparentWindow = private->ReparentWindow;
}