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#include <gcstruct.h> 25 26uint32_t 27present_query_capabilities(RRCrtcPtr crtc) 28{ 29 present_screen_priv_ptr screen_priv; 30 31 if (!crtc) 32 return 0; 33 34 screen_priv = present_screen_priv(crtc->pScreen); 35 36 if (!screen_priv) 37 return 0; 38 39 return screen_priv->query_capabilities(screen_priv); 40} 41 42RRCrtcPtr 43present_get_crtc(WindowPtr window) 44{ 45 ScreenPtr screen = window->drawable.pScreen; 46 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 47 RRCrtcPtr crtc = NULL; 48 49 if (!screen_priv) 50 return NULL; 51 52 crtc = screen_priv->get_crtc(screen_priv, window); 53 if (crtc && !present_screen_priv(crtc->pScreen)) { 54 crtc = RRFirstEnabledCrtc(screen); 55 } 56 if (crtc && !present_screen_priv(crtc->pScreen)) { 57 crtc = NULL; 58 } 59 return crtc; 60} 61 62/* 63 * Copies the update region from a pixmap to the target drawable 64 */ 65void 66present_copy_region(DrawablePtr drawable, 67 PixmapPtr pixmap, 68 RegionPtr update, 69 int16_t x_off, 70 int16_t y_off) 71{ 72 ScreenPtr screen = drawable->pScreen; 73 GCPtr gc; 74 75 gc = GetScratchGC(drawable->depth, screen); 76 if (update) { 77 ChangeGCVal changes[2]; 78 79 changes[0].val = x_off; 80 changes[1].val = y_off; 81 ChangeGC(serverClient, gc, 82 GCClipXOrigin|GCClipYOrigin, 83 changes); 84 (*gc->funcs->ChangeClip)(gc, CT_REGION, update, 0); 85 } 86 ValidateGC(drawable, gc); 87 (*gc->ops->CopyArea)(&pixmap->drawable, 88 drawable, 89 gc, 90 0, 0, 91 pixmap->drawable.width, pixmap->drawable.height, 92 x_off, y_off); 93 if (update) 94 (*gc->funcs->ChangeClip)(gc, CT_NONE, NULL, 0); 95 FreeScratchGC(gc); 96} 97 98void 99present_pixmap_idle(PixmapPtr pixmap, WindowPtr window, CARD32 serial, struct present_fence *present_fence) 100{ 101 if (present_fence) 102 present_fence_set_triggered(present_fence); 103 if (window) { 104 DebugPresent(("\ti %08" PRIx32 "\n", pixmap ? pixmap->drawable.id : 0)); 105 present_send_idle_notify(window, serial, pixmap, present_fence); 106 } 107} 108 109struct pixmap_visit { 110 PixmapPtr old; 111 PixmapPtr new; 112}; 113 114static int 115present_set_tree_pixmap_visit(WindowPtr window, void *data) 116{ 117 struct pixmap_visit *visit = data; 118 ScreenPtr screen = window->drawable.pScreen; 119 120 if ((*screen->GetWindowPixmap)(window) != visit->old) 121 return WT_DONTWALKCHILDREN; 122 (*screen->SetWindowPixmap)(window, visit->new); 123 return WT_WALKCHILDREN; 124} 125 126void 127present_set_tree_pixmap(WindowPtr window, 128 PixmapPtr expected, 129 PixmapPtr pixmap) 130{ 131 struct pixmap_visit visit; 132 ScreenPtr screen = window->drawable.pScreen; 133 134 visit.old = (*screen->GetWindowPixmap)(window); 135 if (expected && visit.old != expected) 136 return; 137 138 visit.new = pixmap; 139 if (visit.old == visit.new) 140 return; 141 TraverseTree(window, present_set_tree_pixmap_visit, &visit); 142} 143 144Bool 145present_can_window_flip(WindowPtr window) 146{ 147 ScreenPtr screen = window->drawable.pScreen; 148 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 149 150 return screen_priv->can_window_flip(window); 151} 152 153uint64_t 154present_get_target_msc(uint64_t target_msc_arg, 155 uint64_t crtc_msc, 156 uint64_t divisor, 157 uint64_t remainder, 158 uint32_t options) 159{ 160 const Bool synced_flip = !(options & PresentOptionAsync); 161 uint64_t target_msc; 162 163 /* If the specified target-msc lies in the future, then this 164 * defines the target-msc according to Present protocol. 165 */ 166 if (msc_is_after(target_msc_arg, crtc_msc)) 167 return target_msc_arg; 168 169 /* If no divisor is specified, the modulo is undefined 170 * and we do present instead asap. 171 */ 172 if (divisor == 0) { 173 target_msc = crtc_msc; 174 175 /* When no async presentation is forced, by default we sync the 176 * presentation with vblank. But in this case we can't target 177 * the current crtc-msc, which already has begun, but must aim 178 * for the upcoming one. 179 */ 180 if (synced_flip) 181 target_msc++; 182 183 return target_msc; 184 } 185 186 /* Calculate target-msc by the specified modulo parameters. According 187 * to Present protocol this is after the next field with: 188 * 189 * field-msc % divisor == remainder. 190 * 191 * The following formula calculates a target_msc solving above equation 192 * and with |target_msc - crtc_msc| < divisor. 193 * 194 * Example with crtc_msc = 10, divisor = 4 and remainder = 3, 2, 1, 0: 195 * 11 = 10 - 2 + 3 = 10 - (10 % 4) + 3, 196 * 10 = 10 - 2 + 2 = 10 - (10 % 4) + 2, 197 * 9 = 10 - 2 + 1 = 10 - (10 % 4) + 1, 198 * 8 = 10 - 2 + 0 = 10 - (10 % 4) + 0. 199 */ 200 target_msc = crtc_msc - (crtc_msc % divisor) + remainder; 201 202 /* Here we already found the correct field-msc. */ 203 if (msc_is_after(target_msc, crtc_msc)) 204 return target_msc; 205 /* 206 * Here either: 207 * a) target_msc == crtc_msc, i.e. crtc_msc actually solved 208 * above equation with crtc_msc % divisor == remainder. 209 * 210 * => This means we want to present at target_msc + divisor for a synced 211 * flip or directly now for an async flip. 212 * 213 * b) target_msc < crtc_msc with target_msc + divisor > crtc_msc. 214 * 215 * => This means in any case we want to present at target_msc + divisor. 216 */ 217 if (synced_flip || msc_is_after(crtc_msc, target_msc)) 218 target_msc += divisor; 219 return target_msc; 220} 221 222int 223present_pixmap(WindowPtr window, 224 PixmapPtr pixmap, 225 CARD32 serial, 226 RegionPtr valid, 227 RegionPtr update, 228 int16_t x_off, 229 int16_t y_off, 230 RRCrtcPtr target_crtc, 231 SyncFence *wait_fence, 232 SyncFence *idle_fence, 233 uint32_t options, 234 uint64_t window_msc, 235 uint64_t divisor, 236 uint64_t remainder, 237 present_notify_ptr notifies, 238 int num_notifies) 239{ 240 ScreenPtr screen = window->drawable.pScreen; 241 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 242 243 return screen_priv->present_pixmap(window, 244 pixmap, 245 serial, 246 valid, 247 update, 248 x_off, 249 y_off, 250 target_crtc, 251 wait_fence, 252 idle_fence, 253 options, 254 window_msc, 255 divisor, 256 remainder, 257 notifies, 258 num_notifies); 259} 260 261int 262present_notify_msc(WindowPtr window, 263 CARD32 serial, 264 uint64_t target_msc, 265 uint64_t divisor, 266 uint64_t remainder) 267{ 268 return present_pixmap(window, 269 NULL, 270 serial, 271 NULL, NULL, 272 0, 0, 273 NULL, 274 NULL, NULL, 275 divisor == 0 ? PresentOptionAsync : 0, 276 target_msc, divisor, remainder, NULL, 0); 277} 278