xenocara/xserver/present/present_screen.c
2019-07-27 07:57:06 +00:00

322 lines
9.4 KiB
C

/*
* Copyright © 2013 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#include "present_priv.h"
int present_request;
DevPrivateKeyRec present_screen_private_key;
DevPrivateKeyRec present_window_private_key;
/*
* Get a pointer to a present window private, creating if necessary
*/
present_window_priv_ptr
present_get_window_priv(WindowPtr window, Bool create)
{
present_window_priv_ptr window_priv = present_window_priv(window);
if (!create || window_priv != NULL)
return window_priv;
window_priv = calloc (1, sizeof (present_window_priv_rec));
if (!window_priv)
return NULL;
xorg_list_init(&window_priv->vblank);
xorg_list_init(&window_priv->notifies);
xorg_list_init(&window_priv->exec_queue);
xorg_list_init(&window_priv->flip_queue);
xorg_list_init(&window_priv->idle_queue);
window_priv->window = window;
window_priv->crtc = PresentCrtcNeverSet;
dixSetPrivate(&window->devPrivates, &present_window_private_key, window_priv);
return window_priv;
}
/*
* Hook the close screen function to clean up our screen private
*/
static Bool
present_close_screen(ScreenPtr screen)
{
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
screen_priv->flip_destroy(screen);
unwrap(screen_priv, screen, CloseScreen);
(*screen->CloseScreen) (screen);
free(screen_priv);
return TRUE;
}
/*
* Free any queued presentations for this window
*/
static void
present_free_window_vblank(WindowPtr window)
{
ScreenPtr screen = window->drawable.pScreen;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
present_window_priv_ptr window_priv = present_window_priv(window);
present_vblank_ptr vblank, tmp;
xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
screen_priv->abort_vblank(window->drawable.pScreen, window, vblank->crtc, vblank->event_id, vblank->target_msc);
present_vblank_destroy(vblank);
}
}
/*
* Clean up any pending or current flips for this window
*/
static void
present_clear_window_flip(WindowPtr window)
{
ScreenPtr screen = window->drawable.pScreen;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
present_vblank_ptr flip_pending = screen_priv->flip_pending;
if (flip_pending && flip_pending->window == window) {
present_set_abort_flip(screen);
flip_pending->window = NULL;
}
if (screen_priv->flip_window == window) {
present_restore_screen_pixmap(screen);
screen_priv->flip_window = NULL;
}
}
static void
present_wnmd_clear_window_flip(WindowPtr window)
{
present_window_priv_ptr window_priv = present_window_priv(window);
present_vblank_ptr vblank, tmp;
if (window_priv->flip_pending) {
present_wnmd_set_abort_flip(window);
window_priv->flip_pending->window = NULL;
}
xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->idle_queue, event_queue) {
present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
/* The pixmap will be destroyed by freeing the window resources. */
vblank->pixmap = NULL;
present_vblank_destroy(vblank);
}
vblank = window_priv->flip_active;
if (vblank) {
present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
present_vblank_destroy(vblank);
}
window_priv->flip_active = NULL;
}
/*
* Hook the close window function to clean up our window private
*/
static Bool
present_destroy_window(WindowPtr window)
{
Bool ret;
ScreenPtr screen = window->drawable.pScreen;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
present_window_priv_ptr window_priv = present_window_priv(window);
if (window_priv) {
present_clear_window_notifies(window);
present_free_events(window);
present_free_window_vblank(window);
if (screen_priv->wnmd_info)
present_wnmd_clear_window_flip(window);
else
present_clear_window_flip(window);
free(window_priv);
}
unwrap(screen_priv, screen, DestroyWindow);
if (screen->DestroyWindow)
ret = screen->DestroyWindow (window);
else
ret = TRUE;
wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
return ret;
}
/*
* Hook the config notify screen function to deliver present config notify events
*/
static int
present_config_notify(WindowPtr window,
int x, int y, int w, int h, int bw,
WindowPtr sibling)
{
int ret;
ScreenPtr screen = window->drawable.pScreen;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
present_send_config_notify(window, x, y, w, h, bw, sibling);
unwrap(screen_priv, screen, ConfigNotify);
if (screen->ConfigNotify)
ret = screen->ConfigNotify (window, x, y, w, h, bw, sibling);
else
ret = 0;
wrap(screen_priv, screen, ConfigNotify, present_config_notify);
return ret;
}
/*
* Hook the clip notify screen function to un-flip as necessary
*/
static void
present_clip_notify(WindowPtr window, int dx, int dy)
{
ScreenPtr screen = window->drawable.pScreen;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
screen_priv->check_flip_window(window);
unwrap(screen_priv, screen, ClipNotify)
if (screen->ClipNotify)
screen->ClipNotify (window, dx, dy);
wrap(screen_priv, screen, ClipNotify, present_clip_notify);
}
static Bool
present_screen_register_priv_keys(void)
{
if (!dixRegisterPrivateKey(&present_screen_private_key, PRIVATE_SCREEN, 0))
return FALSE;
if (!dixRegisterPrivateKey(&present_window_private_key, PRIVATE_WINDOW, 0))
return FALSE;
return TRUE;
}
static present_screen_priv_ptr
present_screen_priv_init(ScreenPtr screen)
{
present_screen_priv_ptr screen_priv;
screen_priv = calloc(1, sizeof (present_screen_priv_rec));
if (!screen_priv)
return NULL;
wrap(screen_priv, screen, CloseScreen, present_close_screen);
wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
wrap(screen_priv, screen, ConfigNotify, present_config_notify);
wrap(screen_priv, screen, ClipNotify, present_clip_notify);
dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv);
return screen_priv;
}
/*
* Initialize a screen for use with present in window flip mode (wnmd)
*/
int
present_wnmd_screen_init(ScreenPtr screen, present_wnmd_info_ptr info)
{
if (!present_screen_register_priv_keys())
return FALSE;
if (!present_screen_priv(screen)) {
present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
if (!screen_priv)
return FALSE;
screen_priv->wnmd_info = info;
present_wnmd_init_mode_hooks(screen_priv);
}
return TRUE;
}
/*
* Initialize a screen for use with present in default screen flip mode (scmd)
*/
int
present_screen_init(ScreenPtr screen, present_screen_info_ptr info)
{
if (!present_screen_register_priv_keys())
return FALSE;
if (!present_screen_priv(screen)) {
present_screen_priv_ptr screen_priv = present_screen_priv_init(screen);
if (!screen_priv)
return FALSE;
screen_priv->info = info;
present_scmd_init_mode_hooks(screen_priv);
present_fake_screen_init(screen);
}
return TRUE;
}
/*
* Initialize the present extension
*/
void
present_extension_init(void)
{
ExtensionEntry *extension;
int i;
#ifdef PANORAMIX
if (!noPanoramiXExtension)
return;
#endif
extension = AddExtension(PRESENT_NAME, PresentNumberEvents, PresentNumberErrors,
proc_present_dispatch, sproc_present_dispatch,
NULL, StandardMinorOpcode);
if (!extension)
goto bail;
present_request = extension->base;
if (!present_init())
goto bail;
if (!present_event_init())
goto bail;
for (i = 0; i < screenInfo.numScreens; i++) {
if (!present_screen_init(screenInfo.screens[i], NULL))
goto bail;
}
return;
bail:
FatalError("Cannot initialize Present extension");
}