Home | History | Annotate | Line # | Download | only in present
      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 
     25 int present_request;
     26 DevPrivateKeyRec present_screen_private_key;
     27 DevPrivateKeyRec present_window_private_key;
     28 
     29 /*
     30  * Get a pointer to a present window private, creating if necessary
     31  */
     32 present_window_priv_ptr
     33 present_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  */
     54 static Bool
     55 present_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  */
     71 static void
     72 present_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  */
     88 static Bool
     89 present_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  */
    126 static int
    127 present_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 
    150 static void
    151 present_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 
    163 Bool
    164 present_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 
    175 present_screen_priv_ptr
    176 present_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  */
    197 int
    198 present_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  */
    220 void
    221 present_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 
    251 bail:
    252     FatalError("Cannot initialize Present extension");
    253 }
    254