xref: /OK3568_Linux_fs/external/xserver/present/present_screen.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright © 2013 Keith Packard
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22 
23 #ifdef HAVE_XORG_CONFIG_H
24 #include <xorg-config.h>
25 #endif
26 
27 #include "present_priv.h"
28 
29 int present_request;
30 DevPrivateKeyRec present_screen_private_key;
31 DevPrivateKeyRec present_window_private_key;
32 
33 /*
34  * Get a pointer to a present window private, creating if necessary
35  */
36 present_window_priv_ptr
present_get_window_priv(WindowPtr window,Bool create)37 present_get_window_priv(WindowPtr window, Bool create)
38 {
39     present_window_priv_ptr window_priv = present_window_priv(window);
40 
41     if (!create || window_priv != NULL)
42         return window_priv;
43     window_priv = calloc (1, sizeof (present_window_priv_rec));
44     if (!window_priv)
45         return NULL;
46     xorg_list_init(&window_priv->vblank);
47     xorg_list_init(&window_priv->notifies);
48 
49     xorg_list_init(&window_priv->exec_queue);
50     xorg_list_init(&window_priv->flip_queue);
51     xorg_list_init(&window_priv->idle_queue);
52 
53     window_priv->window = window;
54     window_priv->crtc = PresentCrtcNeverSet;
55     dixSetPrivate(&window->devPrivates, &present_window_private_key, window_priv);
56     return window_priv;
57 }
58 
59 /*
60  * Hook the close screen function to clean up our screen private
61  */
62 static Bool
present_close_screen(ScreenPtr screen)63 present_close_screen(ScreenPtr screen)
64 {
65     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
66 
67     screen_priv->flip_destroy(screen);
68 
69     unwrap(screen_priv, screen, CloseScreen);
70     (*screen->CloseScreen) (screen);
71     free(screen_priv);
72     return TRUE;
73 }
74 
75 /*
76  * Free any queued presentations for this window
77  */
78 static void
present_free_window_vblank(WindowPtr window)79 present_free_window_vblank(WindowPtr window)
80 {
81     ScreenPtr                   screen = window->drawable.pScreen;
82     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
83     present_window_priv_ptr     window_priv = present_window_priv(window);
84     present_vblank_ptr          vblank, tmp;
85 
86     xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
87         screen_priv->abort_vblank(window->drawable.pScreen, window, vblank->crtc, vblank->event_id, vblank->target_msc);
88         present_vblank_destroy(vblank);
89     }
90 }
91 
92 /*
93  * Clean up any pending or current flips for this window
94  */
95 static void
present_clear_window_flip(WindowPtr window)96 present_clear_window_flip(WindowPtr window)
97 {
98     ScreenPtr                   screen = window->drawable.pScreen;
99     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
100     present_vblank_ptr          flip_pending = screen_priv->flip_pending;
101 
102     if (flip_pending && flip_pending->window == window) {
103         present_set_abort_flip(screen);
104         flip_pending->window = NULL;
105     }
106     if (screen_priv->flip_window == window) {
107         present_restore_screen_pixmap(screen);
108         screen_priv->flip_window = NULL;
109     }
110 }
111 
112 static void
present_wnmd_clear_window_flip(WindowPtr window)113 present_wnmd_clear_window_flip(WindowPtr window)
114 {
115     present_window_priv_ptr     window_priv = present_window_priv(window);
116     present_vblank_ptr          vblank, tmp;
117 
118     xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->flip_queue, event_queue) {
119         present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
120         present_vblank_destroy(vblank);
121     }
122 
123     xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->idle_queue, event_queue) {
124         present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
125         present_vblank_destroy(vblank);
126     }
127 
128     vblank = window_priv->flip_active;
129     if (vblank) {
130         present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
131         present_vblank_destroy(vblank);
132     }
133     window_priv->flip_active = NULL;
134 }
135 
136 /*
137  * Hook the close window function to clean up our window private
138  */
139 static Bool
present_destroy_window(WindowPtr window)140 present_destroy_window(WindowPtr window)
141 {
142     Bool ret;
143     ScreenPtr screen = window->drawable.pScreen;
144     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
145     present_window_priv_ptr window_priv = present_window_priv(window);
146 
147     if (window_priv) {
148         present_clear_window_notifies(window);
149         present_free_events(window);
150         present_free_window_vblank(window);
151 
152         if (screen_priv->wnmd_info)
153             present_wnmd_clear_window_flip(window);
154         else
155             present_clear_window_flip(window);
156 
157         free(window_priv);
158     }
159     unwrap(screen_priv, screen, DestroyWindow);
160     if (screen->DestroyWindow)
161         ret = screen->DestroyWindow (window);
162     else
163         ret = TRUE;
164     wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
165     return ret;
166 }
167 
168 /*
169  * Hook the config notify screen function to deliver present config notify events
170  */
171 static int
present_config_notify(WindowPtr window,int x,int y,int w,int h,int bw,WindowPtr sibling)172 present_config_notify(WindowPtr window,
173                    int x, int y, int w, int h, int bw,
174                    WindowPtr sibling)
175 {
176     int ret;
177     ScreenPtr screen = window->drawable.pScreen;
178     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
179 
180     present_send_config_notify(window, x, y, w, h, bw, sibling);
181 
182     unwrap(screen_priv, screen, ConfigNotify);
183     if (screen->ConfigNotify)
184         ret = screen->ConfigNotify (window, x, y, w, h, bw, sibling);
185     else
186         ret = 0;
187     wrap(screen_priv, screen, ConfigNotify, present_config_notify);
188     return ret;
189 }
190 
191 /*
192  * Hook the clip notify screen function to un-flip as necessary
193  */
194 
195 static void
present_clip_notify(WindowPtr window,int dx,int dy)196 present_clip_notify(WindowPtr window, int dx, int dy)
197 {
198     ScreenPtr screen = window->drawable.pScreen;
199     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
200 
201     screen_priv->check_flip_window(window);
202     unwrap(screen_priv, screen, ClipNotify)
203     if (screen->ClipNotify)
204         screen->ClipNotify (window, dx, dy);
205     wrap(screen_priv, screen, ClipNotify, present_clip_notify);
206 }
207 
208 static Bool
present_screen_register_priv_keys(void)209 present_screen_register_priv_keys(void)
210 {
211     if (!dixRegisterPrivateKey(&present_screen_private_key, PRIVATE_SCREEN, 0))
212         return FALSE;
213 
214     if (!dixRegisterPrivateKey(&present_window_private_key, PRIVATE_WINDOW, 0))
215         return FALSE;
216 
217     return TRUE;
218 }
219 
220 static present_screen_priv_ptr
present_screen_priv_init(ScreenPtr screen)221 present_screen_priv_init(ScreenPtr screen)
222 {
223     present_screen_priv_ptr screen_priv;
224 
225     screen_priv = calloc(1, sizeof (present_screen_priv_rec));
226     if (!screen_priv)
227         return NULL;
228 
229     wrap(screen_priv, screen, CloseScreen, present_close_screen);
230     wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
231     wrap(screen_priv, screen, ConfigNotify, present_config_notify);
232     wrap(screen_priv, screen, ClipNotify, present_clip_notify);
233 
234     dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv);
235 
236     return screen_priv;
237 }
238 
239 /*
240  * Initialize a screen for use with present in window flip mode (wnmd)
241  */
242 int
present_wnmd_screen_init(ScreenPtr screen,present_wnmd_info_ptr info)243 present_wnmd_screen_init(ScreenPtr screen, present_wnmd_info_ptr info)
244 {
245     if (!present_screen_register_priv_keys())
246         return FALSE;
247 
248     if (!present_screen_priv(screen)) {
249         present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
250         if (!screen_priv)
251             return FALSE;
252 
253         screen_priv->wnmd_info = info;
254         present_wnmd_init_mode_hooks(screen_priv);
255     }
256 
257     return TRUE;
258 }
259 
260 /*
261  * Initialize a screen for use with present in default screen flip mode (scmd)
262  */
263 int
present_screen_init(ScreenPtr screen,present_screen_info_ptr info)264 present_screen_init(ScreenPtr screen, present_screen_info_ptr info)
265 {
266     if (!present_screen_register_priv_keys())
267         return FALSE;
268 
269     if (!present_screen_priv(screen)) {
270         present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
271         if (!screen_priv)
272             return FALSE;
273 
274         screen_priv->info = info;
275         present_scmd_init_mode_hooks(screen_priv);
276 
277         present_fake_screen_init(screen);
278     }
279 
280     return TRUE;
281 }
282 
283 /*
284  * Initialize the present extension
285  */
286 void
present_extension_init(void)287 present_extension_init(void)
288 {
289     ExtensionEntry *extension;
290     int i;
291 
292 #ifdef PANORAMIX
293     if (!noPanoramiXExtension)
294         return;
295 #endif
296 
297     extension = AddExtension(PRESENT_NAME, PresentNumberEvents, PresentNumberErrors,
298                              proc_present_dispatch, sproc_present_dispatch,
299                              NULL, StandardMinorOpcode);
300     if (!extension)
301         goto bail;
302 
303     present_request = extension->base;
304 
305     if (!present_init())
306         goto bail;
307 
308     if (!present_event_init())
309         goto bail;
310 
311     for (i = 0; i < screenInfo.numScreens; i++) {
312         if (!present_screen_init(screenInfo.screens[i], NULL))
313             goto bail;
314     }
315     return;
316 
317 bail:
318     FatalError("Cannot initialize Present extension");
319 }
320