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