present_screen.c revision ed6184df
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#include "present_priv.h"
24
25int present_request;
26DevPrivateKeyRec present_screen_private_key;
27DevPrivateKeyRec present_window_private_key;
28
29/*
30 * Get a pointer to a present window private, creating if necessary
31 */
32present_window_priv_ptr
33present_get_window_priv(WindowPtr window, Bool create)
34{
35    present_window_priv_ptr window_priv = present_window_priv(window);
36
37    if (!create || window_priv != NULL)
38        return window_priv;
39    window_priv = calloc (1, sizeof (present_window_priv_rec));
40    if (!window_priv)
41        return NULL;
42    xorg_list_init(&window_priv->vblank);
43    xorg_list_init(&window_priv->notifies);
44
45    window_priv->window = window;
46    window_priv->crtc = PresentCrtcNeverSet;
47    dixSetPrivate(&window->devPrivates, &present_window_private_key, window_priv);
48    return window_priv;
49}
50
51/*
52 * Hook the close screen function to clean up our screen private
53 */
54static Bool
55present_close_screen(ScreenPtr screen)
56{
57    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
58
59    if (screen_priv->flip_destroy)
60        screen_priv->flip_destroy(screen);
61
62    unwrap(screen_priv, screen, CloseScreen);
63    (*screen->CloseScreen) (screen);
64    free(screen_priv);
65    return TRUE;
66}
67
68/*
69 * Free any queued presentations for this window
70 */
71static void
72present_free_window_vblank(WindowPtr window)
73{
74    ScreenPtr                   screen = window->drawable.pScreen;
75    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
76    present_window_priv_ptr     window_priv = present_window_priv(window);
77    present_vblank_ptr          vblank, tmp;
78
79    xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
80        screen_priv->abort_vblank(window->drawable.pScreen, window, vblank->crtc, vblank->event_id, vblank->target_msc);
81        present_vblank_destroy(vblank);
82    }
83}
84
85/*
86 * Hook the close window function to clean up our window private
87 */
88static Bool
89present_destroy_window(WindowPtr window)
90{
91    Bool ret;
92    ScreenPtr screen = window->drawable.pScreen;
93    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
94    present_window_priv_ptr window_priv = present_window_priv(window);
95
96    if (window_priv) {
97        present_clear_window_notifies(window);
98        present_free_events(window);
99        present_free_window_vblank(window);
100
101        screen_priv->clear_window_flip(window);
102
103        free(window_priv);
104    }
105    unwrap(screen_priv, screen, DestroyWindow);
106    if (screen->DestroyWindow)
107        ret = screen->DestroyWindow (window);
108    else
109        ret = TRUE;
110    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
111    return ret;
112}
113
114/*
115 * Hook the config notify screen function to deliver present config notify events
116 */
117static int
118present_config_notify(WindowPtr window,
119                   int x, int y, int w, int h, int bw,
120                   WindowPtr sibling)
121{
122    int ret;
123    ScreenPtr screen = window->drawable.pScreen;
124    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
125
126    present_send_config_notify(window, x, y, w, h, bw, sibling);
127
128    unwrap(screen_priv, screen, ConfigNotify);
129    if (screen->ConfigNotify)
130        ret = screen->ConfigNotify (window, x, y, w, h, bw, sibling);
131    else
132        ret = 0;
133    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
134    return ret;
135}
136
137/*
138 * Hook the clip notify screen function to un-flip as necessary
139 */
140
141static void
142present_clip_notify(WindowPtr window, int dx, int dy)
143{
144    ScreenPtr screen = window->drawable.pScreen;
145    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
146
147    screen_priv->check_flip_window(window);
148    unwrap(screen_priv, screen, ClipNotify)
149    if (screen->ClipNotify)
150        screen->ClipNotify (window, dx, dy);
151    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
152}
153
154Bool
155present_screen_register_priv_keys(void)
156{
157    if (!dixRegisterPrivateKey(&present_screen_private_key, PRIVATE_SCREEN, 0))
158        return FALSE;
159
160    if (!dixRegisterPrivateKey(&present_window_private_key, PRIVATE_WINDOW, 0))
161        return FALSE;
162
163    return TRUE;
164}
165
166present_screen_priv_ptr
167present_screen_priv_init(ScreenPtr screen)
168{
169    present_screen_priv_ptr screen_priv;
170
171    screen_priv = calloc(1, sizeof (present_screen_priv_rec));
172    if (!screen_priv)
173        return NULL;
174
175    wrap(screen_priv, screen, CloseScreen, present_close_screen);
176    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
177    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
178    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
179
180    dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv);
181
182    return screen_priv;
183}
184
185/*
186 * Initialize a screen for use with present in default screen flip mode (scmd)
187 */
188int
189present_screen_init(ScreenPtr screen, present_screen_info_ptr info)
190{
191    if (!present_screen_register_priv_keys())
192        return FALSE;
193
194    if (!present_screen_priv(screen)) {
195        present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
196        if (!screen_priv)
197            return FALSE;
198
199        screen_priv->info = info;
200        present_scmd_init_mode_hooks(screen_priv);
201
202        present_fake_screen_init(screen);
203    }
204
205    return TRUE;
206}
207
208/*
209 * Initialize the present extension
210 */
211void
212present_extension_init(void)
213{
214    ExtensionEntry *extension;
215    int i;
216
217#ifdef PANORAMIX
218    if (!noPanoramiXExtension)
219        return;
220#endif
221
222    extension = AddExtension(PRESENT_NAME, PresentNumberEvents, PresentNumberErrors,
223                             proc_present_dispatch, sproc_present_dispatch,
224                             NULL, StandardMinorOpcode);
225    if (!extension)
226        goto bail;
227
228    present_request = extension->base;
229
230    if (!present_init())
231        goto bail;
232
233    if (!present_event_init())
234        goto bail;
235
236    for (i = 0; i < screenInfo.numScreens; i++) {
237        if (!present_screen_init(screenInfo.screens[i], NULL))
238            goto bail;
239    }
240    return;
241
242bail:
243    FatalError("Cannot initialize Present extension");
244}
245