present_screen.c revision 1b5d61b8
135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2013 Keith Packard
335c4bbdfSmrg *
435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its
535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that
635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright
735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and
835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or
935c4bbdfSmrg * publicity pertaining to distribution of the software without specific,
1035c4bbdfSmrg * written prior permission.  The copyright holders make no representations
1135c4bbdfSmrg * about the suitability of this software for any purpose.  It is provided "as
1235c4bbdfSmrg * is" without express or implied warranty.
1335c4bbdfSmrg *
1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2035c4bbdfSmrg * OF THIS SOFTWARE.
2135c4bbdfSmrg */
2235c4bbdfSmrg
2335c4bbdfSmrg#ifdef HAVE_XORG_CONFIG_H
2435c4bbdfSmrg#include <xorg-config.h>
2535c4bbdfSmrg#endif
2635c4bbdfSmrg
2735c4bbdfSmrg#include "present_priv.h"
2835c4bbdfSmrg
2935c4bbdfSmrgint present_request;
3035c4bbdfSmrgDevPrivateKeyRec present_screen_private_key;
3135c4bbdfSmrgDevPrivateKeyRec present_window_private_key;
3235c4bbdfSmrg
3335c4bbdfSmrg/*
3435c4bbdfSmrg * Get a pointer to a present window private, creating if necessary
3535c4bbdfSmrg */
3635c4bbdfSmrgpresent_window_priv_ptr
3735c4bbdfSmrgpresent_get_window_priv(WindowPtr window, Bool create)
3835c4bbdfSmrg{
3935c4bbdfSmrg    present_window_priv_ptr window_priv = present_window_priv(window);
4035c4bbdfSmrg
4135c4bbdfSmrg    if (!create || window_priv != NULL)
4235c4bbdfSmrg        return window_priv;
4335c4bbdfSmrg    window_priv = calloc (1, sizeof (present_window_priv_rec));
4435c4bbdfSmrg    if (!window_priv)
4535c4bbdfSmrg        return NULL;
4635c4bbdfSmrg    xorg_list_init(&window_priv->vblank);
4735c4bbdfSmrg    xorg_list_init(&window_priv->notifies);
481b5d61b8Smrg
491b5d61b8Smrg    xorg_list_init(&window_priv->exec_queue);
501b5d61b8Smrg    xorg_list_init(&window_priv->flip_queue);
511b5d61b8Smrg    xorg_list_init(&window_priv->idle_queue);
521b5d61b8Smrg
531b5d61b8Smrg    window_priv->window = window;
5435c4bbdfSmrg    window_priv->crtc = PresentCrtcNeverSet;
5535c4bbdfSmrg    dixSetPrivate(&window->devPrivates, &present_window_private_key, window_priv);
5635c4bbdfSmrg    return window_priv;
5735c4bbdfSmrg}
5835c4bbdfSmrg
5935c4bbdfSmrg/*
6035c4bbdfSmrg * Hook the close screen function to clean up our screen private
6135c4bbdfSmrg */
6235c4bbdfSmrgstatic Bool
6335c4bbdfSmrgpresent_close_screen(ScreenPtr screen)
6435c4bbdfSmrg{
6535c4bbdfSmrg    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
6635c4bbdfSmrg
671b5d61b8Smrg    screen_priv->flip_destroy(screen);
6835c4bbdfSmrg
6935c4bbdfSmrg    unwrap(screen_priv, screen, CloseScreen);
7035c4bbdfSmrg    (*screen->CloseScreen) (screen);
7135c4bbdfSmrg    free(screen_priv);
7235c4bbdfSmrg    return TRUE;
7335c4bbdfSmrg}
7435c4bbdfSmrg
7535c4bbdfSmrg/*
7635c4bbdfSmrg * Free any queued presentations for this window
7735c4bbdfSmrg */
7835c4bbdfSmrgstatic void
7935c4bbdfSmrgpresent_free_window_vblank(WindowPtr window)
8035c4bbdfSmrg{
811b5d61b8Smrg    ScreenPtr                   screen = window->drawable.pScreen;
821b5d61b8Smrg    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
8335c4bbdfSmrg    present_window_priv_ptr     window_priv = present_window_priv(window);
8435c4bbdfSmrg    present_vblank_ptr          vblank, tmp;
8535c4bbdfSmrg
8635c4bbdfSmrg    xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
871b5d61b8Smrg        screen_priv->abort_vblank(window->drawable.pScreen, window, vblank->crtc, vblank->event_id, vblank->target_msc);
8835c4bbdfSmrg        present_vblank_destroy(vblank);
8935c4bbdfSmrg    }
9035c4bbdfSmrg}
9135c4bbdfSmrg
9235c4bbdfSmrg/*
9335c4bbdfSmrg * Clean up any pending or current flips for this window
9435c4bbdfSmrg */
9535c4bbdfSmrgstatic void
9635c4bbdfSmrgpresent_clear_window_flip(WindowPtr window)
9735c4bbdfSmrg{
9835c4bbdfSmrg    ScreenPtr                   screen = window->drawable.pScreen;
9935c4bbdfSmrg    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
10035c4bbdfSmrg    present_vblank_ptr          flip_pending = screen_priv->flip_pending;
10135c4bbdfSmrg
10235c4bbdfSmrg    if (flip_pending && flip_pending->window == window) {
1031b5d61b8Smrg        present_set_abort_flip(screen);
10435c4bbdfSmrg        flip_pending->window = NULL;
10535c4bbdfSmrg    }
1061b5d61b8Smrg    if (screen_priv->flip_window == window) {
1071b5d61b8Smrg        present_restore_screen_pixmap(screen);
10835c4bbdfSmrg        screen_priv->flip_window = NULL;
1091b5d61b8Smrg    }
1101b5d61b8Smrg}
1111b5d61b8Smrg
1121b5d61b8Smrgstatic void
1131b5d61b8Smrgpresent_wnmd_clear_window_flip(WindowPtr window)
1141b5d61b8Smrg{
1151b5d61b8Smrg    present_window_priv_ptr     window_priv = present_window_priv(window);
1161b5d61b8Smrg    present_vblank_ptr          vblank, tmp;
1171b5d61b8Smrg
1181b5d61b8Smrg    if (window_priv->flip_pending) {
1191b5d61b8Smrg        present_wnmd_set_abort_flip(window);
1201b5d61b8Smrg        window_priv->flip_pending->window = NULL;
1211b5d61b8Smrg    }
1221b5d61b8Smrg
1231b5d61b8Smrg    xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->idle_queue, event_queue) {
1241b5d61b8Smrg        present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
1251b5d61b8Smrg        /* The pixmap will be destroyed by freeing the window resources. */
1261b5d61b8Smrg        vblank->pixmap = NULL;
1271b5d61b8Smrg        present_vblank_destroy(vblank);
1281b5d61b8Smrg    }
1291b5d61b8Smrg
1301b5d61b8Smrg    vblank = window_priv->flip_active;
1311b5d61b8Smrg    if (vblank) {
1321b5d61b8Smrg        present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
1331b5d61b8Smrg        present_vblank_destroy(vblank);
1341b5d61b8Smrg    }
1351b5d61b8Smrg    window_priv->flip_active = NULL;
13635c4bbdfSmrg}
13735c4bbdfSmrg
13835c4bbdfSmrg/*
13935c4bbdfSmrg * Hook the close window function to clean up our window private
14035c4bbdfSmrg */
14135c4bbdfSmrgstatic Bool
14235c4bbdfSmrgpresent_destroy_window(WindowPtr window)
14335c4bbdfSmrg{
14435c4bbdfSmrg    Bool ret;
14535c4bbdfSmrg    ScreenPtr screen = window->drawable.pScreen;
14635c4bbdfSmrg    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
14735c4bbdfSmrg    present_window_priv_ptr window_priv = present_window_priv(window);
14835c4bbdfSmrg
14935c4bbdfSmrg    if (window_priv) {
15035c4bbdfSmrg        present_clear_window_notifies(window);
15135c4bbdfSmrg        present_free_events(window);
15235c4bbdfSmrg        present_free_window_vblank(window);
1531b5d61b8Smrg
1541b5d61b8Smrg        if (screen_priv->wnmd_info)
1551b5d61b8Smrg            present_wnmd_clear_window_flip(window);
1561b5d61b8Smrg        else
1571b5d61b8Smrg            present_clear_window_flip(window);
1581b5d61b8Smrg
15935c4bbdfSmrg        free(window_priv);
16035c4bbdfSmrg    }
16135c4bbdfSmrg    unwrap(screen_priv, screen, DestroyWindow);
16235c4bbdfSmrg    if (screen->DestroyWindow)
16335c4bbdfSmrg        ret = screen->DestroyWindow (window);
16435c4bbdfSmrg    else
16535c4bbdfSmrg        ret = TRUE;
16635c4bbdfSmrg    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
16735c4bbdfSmrg    return ret;
16835c4bbdfSmrg}
16935c4bbdfSmrg
17035c4bbdfSmrg/*
17135c4bbdfSmrg * Hook the config notify screen function to deliver present config notify events
17235c4bbdfSmrg */
17335c4bbdfSmrgstatic int
17435c4bbdfSmrgpresent_config_notify(WindowPtr window,
17535c4bbdfSmrg                   int x, int y, int w, int h, int bw,
17635c4bbdfSmrg                   WindowPtr sibling)
17735c4bbdfSmrg{
17835c4bbdfSmrg    int ret;
17935c4bbdfSmrg    ScreenPtr screen = window->drawable.pScreen;
18035c4bbdfSmrg    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
18135c4bbdfSmrg
18235c4bbdfSmrg    present_send_config_notify(window, x, y, w, h, bw, sibling);
18335c4bbdfSmrg
18435c4bbdfSmrg    unwrap(screen_priv, screen, ConfigNotify);
18535c4bbdfSmrg    if (screen->ConfigNotify)
18635c4bbdfSmrg        ret = screen->ConfigNotify (window, x, y, w, h, bw, sibling);
18735c4bbdfSmrg    else
18835c4bbdfSmrg        ret = 0;
18935c4bbdfSmrg    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
19035c4bbdfSmrg    return ret;
19135c4bbdfSmrg}
19235c4bbdfSmrg
19335c4bbdfSmrg/*
19435c4bbdfSmrg * Hook the clip notify screen function to un-flip as necessary
19535c4bbdfSmrg */
19635c4bbdfSmrg
19735c4bbdfSmrgstatic void
19835c4bbdfSmrgpresent_clip_notify(WindowPtr window, int dx, int dy)
19935c4bbdfSmrg{
20035c4bbdfSmrg    ScreenPtr screen = window->drawable.pScreen;
20135c4bbdfSmrg    present_screen_priv_ptr screen_priv = present_screen_priv(screen);
20235c4bbdfSmrg
2031b5d61b8Smrg    screen_priv->check_flip_window(window);
20435c4bbdfSmrg    unwrap(screen_priv, screen, ClipNotify)
20535c4bbdfSmrg    if (screen->ClipNotify)
20635c4bbdfSmrg        screen->ClipNotify (window, dx, dy);
20735c4bbdfSmrg    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
20835c4bbdfSmrg}
20935c4bbdfSmrg
2101b5d61b8Smrgstatic Bool
2111b5d61b8Smrgpresent_screen_register_priv_keys(void)
21235c4bbdfSmrg{
21335c4bbdfSmrg    if (!dixRegisterPrivateKey(&present_screen_private_key, PRIVATE_SCREEN, 0))
21435c4bbdfSmrg        return FALSE;
21535c4bbdfSmrg
21635c4bbdfSmrg    if (!dixRegisterPrivateKey(&present_window_private_key, PRIVATE_WINDOW, 0))
21735c4bbdfSmrg        return FALSE;
21835c4bbdfSmrg
2191b5d61b8Smrg    return TRUE;
2201b5d61b8Smrg}
2211b5d61b8Smrg
2221b5d61b8Smrgstatic present_screen_priv_ptr
2231b5d61b8Smrgpresent_screen_priv_init(ScreenPtr screen)
2241b5d61b8Smrg{
2251b5d61b8Smrg    present_screen_priv_ptr screen_priv;
2261b5d61b8Smrg
2271b5d61b8Smrg    screen_priv = calloc(1, sizeof (present_screen_priv_rec));
2281b5d61b8Smrg    if (!screen_priv)
2291b5d61b8Smrg        return NULL;
2301b5d61b8Smrg
2311b5d61b8Smrg    wrap(screen_priv, screen, CloseScreen, present_close_screen);
2321b5d61b8Smrg    wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
2331b5d61b8Smrg    wrap(screen_priv, screen, ConfigNotify, present_config_notify);
2341b5d61b8Smrg    wrap(screen_priv, screen, ClipNotify, present_clip_notify);
2351b5d61b8Smrg
2361b5d61b8Smrg    dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv);
2371b5d61b8Smrg
2381b5d61b8Smrg    return screen_priv;
2391b5d61b8Smrg}
2401b5d61b8Smrg
2411b5d61b8Smrg/*
2421b5d61b8Smrg * Initialize a screen for use with present in window flip mode (wnmd)
2431b5d61b8Smrg */
2441b5d61b8Smrgint
2451b5d61b8Smrgpresent_wnmd_screen_init(ScreenPtr screen, present_wnmd_info_ptr info)
2461b5d61b8Smrg{
2471b5d61b8Smrg    if (!present_screen_register_priv_keys())
2481b5d61b8Smrg        return FALSE;
2491b5d61b8Smrg
25035c4bbdfSmrg    if (!present_screen_priv(screen)) {
2511b5d61b8Smrg        present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
25235c4bbdfSmrg        if (!screen_priv)
25335c4bbdfSmrg            return FALSE;
25435c4bbdfSmrg
2551b5d61b8Smrg        screen_priv->wnmd_info = info;
2561b5d61b8Smrg        present_wnmd_init_mode_hooks(screen_priv);
2571b5d61b8Smrg    }
25835c4bbdfSmrg
2591b5d61b8Smrg    return TRUE;
2601b5d61b8Smrg}
26135c4bbdfSmrg
2621b5d61b8Smrg/*
2631b5d61b8Smrg * Initialize a screen for use with present in default screen flip mode (scmd)
2641b5d61b8Smrg */
2651b5d61b8Smrgint
2661b5d61b8Smrgpresent_screen_init(ScreenPtr screen, present_screen_info_ptr info)
2671b5d61b8Smrg{
2681b5d61b8Smrg    if (!present_screen_register_priv_keys())
2691b5d61b8Smrg        return FALSE;
2701b5d61b8Smrg
2711b5d61b8Smrg    if (!present_screen_priv(screen)) {
2721b5d61b8Smrg        present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
2731b5d61b8Smrg        if (!screen_priv)
2741b5d61b8Smrg            return FALSE;
2751b5d61b8Smrg
2761b5d61b8Smrg        screen_priv->info = info;
2771b5d61b8Smrg        present_scmd_init_mode_hooks(screen_priv);
27835c4bbdfSmrg
27935c4bbdfSmrg        present_fake_screen_init(screen);
28035c4bbdfSmrg    }
28135c4bbdfSmrg
28235c4bbdfSmrg    return TRUE;
28335c4bbdfSmrg}
28435c4bbdfSmrg
28535c4bbdfSmrg/*
28635c4bbdfSmrg * Initialize the present extension
28735c4bbdfSmrg */
28835c4bbdfSmrgvoid
28935c4bbdfSmrgpresent_extension_init(void)
29035c4bbdfSmrg{
29135c4bbdfSmrg    ExtensionEntry *extension;
29235c4bbdfSmrg    int i;
29335c4bbdfSmrg
29435c4bbdfSmrg#ifdef PANORAMIX
29535c4bbdfSmrg    if (!noPanoramiXExtension)
29635c4bbdfSmrg        return;
29735c4bbdfSmrg#endif
29835c4bbdfSmrg
29935c4bbdfSmrg    extension = AddExtension(PRESENT_NAME, PresentNumberEvents, PresentNumberErrors,
30035c4bbdfSmrg                             proc_present_dispatch, sproc_present_dispatch,
30135c4bbdfSmrg                             NULL, StandardMinorOpcode);
30235c4bbdfSmrg    if (!extension)
30335c4bbdfSmrg        goto bail;
30435c4bbdfSmrg
30535c4bbdfSmrg    present_request = extension->base;
30635c4bbdfSmrg
30735c4bbdfSmrg    if (!present_init())
30835c4bbdfSmrg        goto bail;
30935c4bbdfSmrg
31035c4bbdfSmrg    if (!present_event_init())
31135c4bbdfSmrg        goto bail;
31235c4bbdfSmrg
31335c4bbdfSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
31435c4bbdfSmrg        if (!present_screen_init(screenInfo.screens[i], NULL))
31535c4bbdfSmrg            goto bail;
31635c4bbdfSmrg    }
31735c4bbdfSmrg    return;
31835c4bbdfSmrg
31935c4bbdfSmrgbail:
32035c4bbdfSmrg    FatalError("Cannot initialize Present extension");
32135c4bbdfSmrg}
322