present_screen.c revision eee80088
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    present_send_config_notify(window,
97                               window->drawable.x,
98                               window->drawable.y,
99                               window->drawable.width,
100                               window->drawable.height,
101                               window->borderWidth,
102                               window->nextSib,
103                               PresentWindowDestroyed);
104
105    if (window_priv) {
106        present_clear_window_notifies(window);
107        present_free_events(window);
108        present_free_window_vblank(window);
109
110        screen_priv->clear_window_flip(window);
111
112        free(window_priv);
113    }
114    unwrap(screen_priv, screen, DestroyWindow);
115    if (screen->DestroyWindow)
116        ret = screen->DestroyWindow (window);
117    else
118        ret = TRUE;
119    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
120    return ret;
121}
122
123/*
124 * Hook the config notify screen function to deliver present config notify events
125 */
126static int
127present_config_notify(WindowPtr window,
128                   int x, int y, int w, int h, int bw,
129                   WindowPtr sibling)
130{
131    int ret;
132    ScreenPtr screen = window->drawable.pScreen;
133    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
134
135    present_send_config_notify(window, x, y, w, h, bw, sibling, 0);
136
137    unwrap(screen_priv, screen, ConfigNotify);
138    if (screen->ConfigNotify)
139        ret = screen->ConfigNotify (window, x, y, w, h, bw, sibling);
140    else
141        ret = 0;
142    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
143    return ret;
144}
145
146/*
147 * Hook the clip notify screen function to un-flip as necessary
148 */
149
150static void
151present_clip_notify(WindowPtr window, int dx, int dy)
152{
153    ScreenPtr screen = window->drawable.pScreen;
154    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
155
156    screen_priv->check_flip_window(window);
157    unwrap(screen_priv, screen, ClipNotify)
158    if (screen->ClipNotify)
159        screen->ClipNotify (window, dx, dy);
160    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
161}
162
163Bool
164present_screen_register_priv_keys(void)
165{
166    if (!dixRegisterPrivateKey(&present_screen_private_key, PRIVATE_SCREEN, 0))
167        return FALSE;
168
169    if (!dixRegisterPrivateKey(&present_window_private_key, PRIVATE_WINDOW, 0))
170        return FALSE;
171
172    return TRUE;
173}
174
175present_screen_priv_ptr
176present_screen_priv_init(ScreenPtr screen)
177{
178    present_screen_priv_ptr screen_priv;
179
180    screen_priv = calloc(1, sizeof (present_screen_priv_rec));
181    if (!screen_priv)
182        return NULL;
183
184    wrap(screen_priv, screen, CloseScreen, present_close_screen);
185    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
186    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
187    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
188
189    dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv);
190
191    return screen_priv;
192}
193
194/*
195 * Initialize a screen for use with present in default screen flip mode (scmd)
196 */
197int
198present_screen_init(ScreenPtr screen, present_screen_info_ptr info)
199{
200    if (!present_screen_register_priv_keys())
201        return FALSE;
202
203    if (!present_screen_priv(screen)) {
204        present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
205        if (!screen_priv)
206            return FALSE;
207
208        screen_priv->info = info;
209        present_scmd_init_mode_hooks(screen_priv);
210
211        present_fake_screen_init(screen);
212    }
213
214    return TRUE;
215}
216
217/*
218 * Initialize the present extension
219 */
220void
221present_extension_init(void)
222{
223    ExtensionEntry *extension;
224    int i;
225
226#ifdef PANORAMIX
227    if (!noPanoramiXExtension)
228        return;
229#endif
230
231    extension = AddExtension(PRESENT_NAME, PresentNumberEvents, PresentNumberErrors,
232                             proc_present_dispatch, sproc_present_dispatch,
233                             NULL, StandardMinorOpcode);
234    if (!extension)
235        goto bail;
236
237    present_request = extension->base;
238
239    if (!present_init())
240        goto bail;
241
242    if (!present_event_init())
243        goto bail;
244
245    for (i = 0; i < screenInfo.numScreens; i++) {
246        if (!present_screen_init(screenInfo.screens[i], NULL))
247            goto bail;
248    }
249    return;
250
251bail:
252    FatalError("Cannot initialize Present extension");
253}
254