xserver/present/present.c
Łukasz Spintzyk b03d7184b7 present: fallback get_crtc to return crtc belonging to screen with present extension
Since crtc can belong to secondary output that may not have present
extension enabled we should fallback to first enabled crtc or fake crtc.

Fix for issue xorg/xserver#1195

(cherry picked from commit d6c02ffd9c)
2021-07-29 11:55:38 +02:00

250 lines
7.7 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"
#include <gcstruct.h>
/*
* Returns:
* TRUE if the first MSC value is equal to or after the second one
* FALSE if the first MSC value is before the second one
*/
static Bool
msc_is_equal_or_after(uint64_t test, uint64_t reference)
{
return (int64_t)(test - reference) >= 0;
}
uint32_t
present_query_capabilities(RRCrtcPtr crtc)
{
present_screen_priv_ptr screen_priv;
if (!crtc)
return 0;
screen_priv = present_screen_priv(crtc->pScreen);
if (!screen_priv)
return 0;
return screen_priv->query_capabilities(screen_priv);
}
RRCrtcPtr
present_get_crtc(WindowPtr window)
{
ScreenPtr screen = window->drawable.pScreen;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
RRCrtcPtr crtc = NULL;
if (!screen_priv)
return NULL;
crtc = screen_priv->get_crtc(screen_priv, window);
if (crtc && !present_screen_priv(crtc->pScreen)) {
crtc = RRFirstEnabledCrtc(screen);
}
if (crtc && !present_screen_priv(crtc->pScreen)) {
crtc = NULL;
}
return crtc;
}
/*
* Copies the update region from a pixmap to the target drawable
*/
void
present_copy_region(DrawablePtr drawable,
PixmapPtr pixmap,
RegionPtr update,
int16_t x_off,
int16_t y_off)
{
ScreenPtr screen = drawable->pScreen;
GCPtr gc;
gc = GetScratchGC(drawable->depth, screen);
if (update) {
ChangeGCVal changes[2];
changes[0].val = x_off;
changes[1].val = y_off;
ChangeGC(serverClient, gc,
GCClipXOrigin|GCClipYOrigin,
changes);
(*gc->funcs->ChangeClip)(gc, CT_REGION, update, 0);
}
ValidateGC(drawable, gc);
(*gc->ops->CopyArea)(&pixmap->drawable,
drawable,
gc,
0, 0,
pixmap->drawable.width, pixmap->drawable.height,
x_off, y_off);
if (update)
(*gc->funcs->ChangeClip)(gc, CT_NONE, NULL, 0);
FreeScratchGC(gc);
}
void
present_pixmap_idle(PixmapPtr pixmap, WindowPtr window, CARD32 serial, struct present_fence *present_fence)
{
if (present_fence)
present_fence_set_triggered(present_fence);
if (window) {
DebugPresent(("\ti %08" PRIx32 "\n", pixmap ? pixmap->drawable.id : 0));
present_send_idle_notify(window, serial, pixmap, present_fence);
}
}
struct pixmap_visit {
PixmapPtr old;
PixmapPtr new;
};
static int
present_set_tree_pixmap_visit(WindowPtr window, void *data)
{
struct pixmap_visit *visit = data;
ScreenPtr screen = window->drawable.pScreen;
if ((*screen->GetWindowPixmap)(window) != visit->old)
return WT_DONTWALKCHILDREN;
(*screen->SetWindowPixmap)(window, visit->new);
return WT_WALKCHILDREN;
}
void
present_set_tree_pixmap(WindowPtr window,
PixmapPtr expected,
PixmapPtr pixmap)
{
struct pixmap_visit visit;
ScreenPtr screen = window->drawable.pScreen;
visit.old = (*screen->GetWindowPixmap)(window);
if (expected && visit.old != expected)
return;
visit.new = pixmap;
if (visit.old == visit.new)
return;
TraverseTree(window, present_set_tree_pixmap_visit, &visit);
}
Bool
present_can_window_flip(WindowPtr window)
{
ScreenPtr screen = window->drawable.pScreen;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
return screen_priv->can_window_flip(window);
}
void
present_adjust_timings(uint32_t options,
uint64_t *crtc_msc,
uint64_t *target_msc,
uint64_t divisor,
uint64_t remainder)
{
/* Adjust target_msc to match modulus
*/
if (msc_is_equal_or_after(*crtc_msc, *target_msc)) {
if (divisor != 0) {
*target_msc = *crtc_msc - (*crtc_msc % divisor) + remainder;
if (options & PresentOptionAsync) {
if (msc_is_after(*crtc_msc, *target_msc))
*target_msc += divisor;
} else {
if (msc_is_equal_or_after(*crtc_msc, *target_msc))
*target_msc += divisor;
}
} else {
*target_msc = *crtc_msc;
if (!(options & PresentOptionAsync))
(*target_msc)++;
}
}
}
int
present_pixmap(WindowPtr window,
PixmapPtr pixmap,
CARD32 serial,
RegionPtr valid,
RegionPtr update,
int16_t x_off,
int16_t y_off,
RRCrtcPtr target_crtc,
SyncFence *wait_fence,
SyncFence *idle_fence,
uint32_t options,
uint64_t window_msc,
uint64_t divisor,
uint64_t remainder,
present_notify_ptr notifies,
int num_notifies)
{
ScreenPtr screen = window->drawable.pScreen;
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
return screen_priv->present_pixmap(window,
pixmap,
serial,
valid,
update,
x_off,
y_off,
target_crtc,
wait_fence,
idle_fence,
options,
window_msc,
divisor,
remainder,
notifies,
num_notifies);
}
int
present_notify_msc(WindowPtr window,
CARD32 serial,
uint64_t target_msc,
uint64_t divisor,
uint64_t remainder)
{
return present_pixmap(window,
NULL,
serial,
NULL, NULL,
0, 0,
NULL,
NULL, NULL,
divisor == 0 ? PresentOptionAsync : 0,
target_msc, divisor, remainder, NULL, 0);
}