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