present_screen.c revision 1b5d61b8
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
29int present_request;
30DevPrivateKeyRec present_screen_private_key;
31DevPrivateKeyRec present_window_private_key;
32
33/*
34 * Get a pointer to a present window private, creating if necessary
35 */
36present_window_priv_ptr
37present_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 */
62static Bool
63present_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 */
78static void
79present_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 */
95static void
96present_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
112static void
113present_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    if (window_priv->flip_pending) {
119        present_wnmd_set_abort_flip(window);
120        window_priv->flip_pending->window = NULL;
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        /* The pixmap will be destroyed by freeing the window resources. */
126        vblank->pixmap = NULL;
127        present_vblank_destroy(vblank);
128    }
129
130    vblank = window_priv->flip_active;
131    if (vblank) {
132        present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
133        present_vblank_destroy(vblank);
134    }
135    window_priv->flip_active = NULL;
136}
137
138/*
139 * Hook the close window function to clean up our window private
140 */
141static Bool
142present_destroy_window(WindowPtr window)
143{
144    Bool ret;
145    ScreenPtr screen = window->drawable.pScreen;
146    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
147    present_window_priv_ptr window_priv = present_window_priv(window);
148
149    if (window_priv) {
150        present_clear_window_notifies(window);
151        present_free_events(window);
152        present_free_window_vblank(window);
153
154        if (screen_priv->wnmd_info)
155            present_wnmd_clear_window_flip(window);
156        else
157            present_clear_window_flip(window);
158
159        free(window_priv);
160    }
161    unwrap(screen_priv, screen, DestroyWindow);
162    if (screen->DestroyWindow)
163        ret = screen->DestroyWindow (window);
164    else
165        ret = TRUE;
166    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
167    return ret;
168}
169
170/*
171 * Hook the config notify screen function to deliver present config notify events
172 */
173static int
174present_config_notify(WindowPtr window,
175                   int x, int y, int w, int h, int bw,
176                   WindowPtr sibling)
177{
178    int ret;
179    ScreenPtr screen = window->drawable.pScreen;
180    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
181
182    present_send_config_notify(window, x, y, w, h, bw, sibling);
183
184    unwrap(screen_priv, screen, ConfigNotify);
185    if (screen->ConfigNotify)
186        ret = screen->ConfigNotify (window, x, y, w, h, bw, sibling);
187    else
188        ret = 0;
189    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
190    return ret;
191}
192
193/*
194 * Hook the clip notify screen function to un-flip as necessary
195 */
196
197static void
198present_clip_notify(WindowPtr window, int dx, int dy)
199{
200    ScreenPtr screen = window->drawable.pScreen;
201    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
202
203    screen_priv->check_flip_window(window);
204    unwrap(screen_priv, screen, ClipNotify)
205    if (screen->ClipNotify)
206        screen->ClipNotify (window, dx, dy);
207    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
208}
209
210static Bool
211present_screen_register_priv_keys(void)
212{
213    if (!dixRegisterPrivateKey(&present_screen_private_key, PRIVATE_SCREEN, 0))
214        return FALSE;
215
216    if (!dixRegisterPrivateKey(&present_window_private_key, PRIVATE_WINDOW, 0))
217        return FALSE;
218
219    return TRUE;
220}
221
222static present_screen_priv_ptr
223present_screen_priv_init(ScreenPtr screen)
224{
225    present_screen_priv_ptr screen_priv;
226
227    screen_priv = calloc(1, sizeof (present_screen_priv_rec));
228    if (!screen_priv)
229        return NULL;
230
231    wrap(screen_priv, screen, CloseScreen, present_close_screen);
232    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
233    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
234    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
235
236    dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv);
237
238    return screen_priv;
239}
240
241/*
242 * Initialize a screen for use with present in window flip mode (wnmd)
243 */
244int
245present_wnmd_screen_init(ScreenPtr screen, present_wnmd_info_ptr info)
246{
247    if (!present_screen_register_priv_keys())
248        return FALSE;
249
250    if (!present_screen_priv(screen)) {
251        present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
252        if (!screen_priv)
253            return FALSE;
254
255        screen_priv->wnmd_info = info;
256        present_wnmd_init_mode_hooks(screen_priv);
257    }
258
259    return TRUE;
260}
261
262/*
263 * Initialize a screen for use with present in default screen flip mode (scmd)
264 */
265int
266present_screen_init(ScreenPtr screen, present_screen_info_ptr info)
267{
268    if (!present_screen_register_priv_keys())
269        return FALSE;
270
271    if (!present_screen_priv(screen)) {
272        present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
273        if (!screen_priv)
274            return FALSE;
275
276        screen_priv->info = info;
277        present_scmd_init_mode_hooks(screen_priv);
278
279        present_fake_screen_init(screen);
280    }
281
282    return TRUE;
283}
284
285/*
286 * Initialize the present extension
287 */
288void
289present_extension_init(void)
290{
291    ExtensionEntry *extension;
292    int i;
293
294#ifdef PANORAMIX
295    if (!noPanoramiXExtension)
296        return;
297#endif
298
299    extension = AddExtension(PRESENT_NAME, PresentNumberEvents, PresentNumberErrors,
300                             proc_present_dispatch, sproc_present_dispatch,
301                             NULL, StandardMinorOpcode);
302    if (!extension)
303        goto bail;
304
305    present_request = extension->base;
306
307    if (!present_init())
308        goto bail;
309
310    if (!present_event_init())
311        goto bail;
312
313    for (i = 0; i < screenInfo.numScreens; i++) {
314        if (!present_screen_init(screenInfo.screens[i], NULL))
315            goto bail;
316    }
317    return;
318
319bail:
320    FatalError("Cannot initialize Present extension");
321}
322