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 #ifdef HAVE_XORG_CONFIG_H
24 #include <xorg-config.h>
25 #endif
26
27 #include "present_priv.h"
28 #include <gcstruct.h>
29
30 /*
31 * Returns:
32 * TRUE if the first MSC value is equal to or after the second one
33 * FALSE if the first MSC value is before the second one
34 */
35 static Bool
msc_is_equal_or_after(uint64_t test,uint64_t reference)36 msc_is_equal_or_after(uint64_t test, uint64_t reference)
37 {
38 return (int64_t)(test - reference) >= 0;
39 }
40
41 uint32_t
present_query_capabilities(RRCrtcPtr crtc)42 present_query_capabilities(RRCrtcPtr crtc)
43 {
44 present_screen_priv_ptr screen_priv;
45
46 if (!crtc)
47 return 0;
48
49 screen_priv = present_screen_priv(crtc->pScreen);
50
51 if (!screen_priv)
52 return 0;
53
54 return screen_priv->query_capabilities(screen_priv);
55 }
56
57 RRCrtcPtr
present_get_crtc(WindowPtr window)58 present_get_crtc(WindowPtr window)
59 {
60 ScreenPtr screen = window->drawable.pScreen;
61 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
62
63 if (!screen_priv)
64 return NULL;
65
66 return screen_priv->get_crtc(screen_priv, window);
67 }
68
69 /*
70 * Copies the update region from a pixmap to the target drawable
71 */
72 void
present_copy_region(DrawablePtr drawable,PixmapPtr pixmap,RegionPtr update,int16_t x_off,int16_t y_off)73 present_copy_region(DrawablePtr drawable,
74 PixmapPtr pixmap,
75 RegionPtr update,
76 int16_t x_off,
77 int16_t y_off)
78 {
79 ScreenPtr screen = drawable->pScreen;
80 GCPtr gc;
81
82 gc = GetScratchGC(drawable->depth, screen);
83 if (update) {
84 ChangeGCVal changes[2];
85
86 changes[0].val = x_off;
87 changes[1].val = y_off;
88 ChangeGC(serverClient, gc,
89 GCClipXOrigin|GCClipYOrigin,
90 changes);
91 (*gc->funcs->ChangeClip)(gc, CT_REGION, update, 0);
92 }
93 ValidateGC(drawable, gc);
94 (*gc->ops->CopyArea)(&pixmap->drawable,
95 drawable,
96 gc,
97 0, 0,
98 pixmap->drawable.width, pixmap->drawable.height,
99 x_off, y_off);
100 if (update)
101 (*gc->funcs->ChangeClip)(gc, CT_NONE, NULL, 0);
102 FreeScratchGC(gc);
103 }
104
105 void
present_pixmap_idle(PixmapPtr pixmap,WindowPtr window,CARD32 serial,struct present_fence * present_fence)106 present_pixmap_idle(PixmapPtr pixmap, WindowPtr window, CARD32 serial, struct present_fence *present_fence)
107 {
108 if (present_fence)
109 present_fence_set_triggered(present_fence);
110 if (window) {
111 DebugPresent(("\ti %08" PRIx32 "\n", pixmap ? pixmap->drawable.id : 0));
112 present_send_idle_notify(window, serial, pixmap, present_fence);
113 }
114 }
115
116 struct pixmap_visit {
117 PixmapPtr old;
118 PixmapPtr new;
119 };
120
121 static int
present_set_tree_pixmap_visit(WindowPtr window,void * data)122 present_set_tree_pixmap_visit(WindowPtr window, void *data)
123 {
124 struct pixmap_visit *visit = data;
125 ScreenPtr screen = window->drawable.pScreen;
126
127 if ((*screen->GetWindowPixmap)(window) != visit->old)
128 return WT_DONTWALKCHILDREN;
129 (*screen->SetWindowPixmap)(window, visit->new);
130 return WT_WALKCHILDREN;
131 }
132
133 void
present_set_tree_pixmap(WindowPtr window,PixmapPtr expected,PixmapPtr pixmap)134 present_set_tree_pixmap(WindowPtr window,
135 PixmapPtr expected,
136 PixmapPtr pixmap)
137 {
138 struct pixmap_visit visit;
139 ScreenPtr screen = window->drawable.pScreen;
140
141 visit.old = (*screen->GetWindowPixmap)(window);
142 if (expected && visit.old != expected)
143 return;
144
145 visit.new = pixmap;
146 if (visit.old == visit.new)
147 return;
148 TraverseTree(window, present_set_tree_pixmap_visit, &visit);
149 }
150
151 Bool
present_can_window_flip(WindowPtr window)152 present_can_window_flip(WindowPtr window)
153 {
154 ScreenPtr screen = window->drawable.pScreen;
155 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
156
157 return screen_priv->can_window_flip(window);
158 }
159
160 void
present_adjust_timings(uint32_t options,uint64_t * crtc_msc,uint64_t * target_msc,uint64_t divisor,uint64_t remainder)161 present_adjust_timings(uint32_t options,
162 uint64_t *crtc_msc,
163 uint64_t *target_msc,
164 uint64_t divisor,
165 uint64_t remainder)
166 {
167 /* Adjust target_msc to match modulus
168 */
169 if (msc_is_equal_or_after(*crtc_msc, *target_msc)) {
170 if (divisor != 0) {
171 *target_msc = *crtc_msc - (*crtc_msc % divisor) + remainder;
172 if (options & PresentOptionAsync) {
173 if (msc_is_after(*crtc_msc, *target_msc))
174 *target_msc += divisor;
175 } else {
176 if (msc_is_equal_or_after(*crtc_msc, *target_msc))
177 *target_msc += divisor;
178 }
179 } else {
180 *target_msc = *crtc_msc;
181 if (!(options & PresentOptionAsync))
182 (*target_msc)++;
183 }
184 }
185 }
186
187 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)188 present_pixmap(WindowPtr window,
189 PixmapPtr pixmap,
190 CARD32 serial,
191 RegionPtr valid,
192 RegionPtr update,
193 int16_t x_off,
194 int16_t y_off,
195 RRCrtcPtr target_crtc,
196 SyncFence *wait_fence,
197 SyncFence *idle_fence,
198 uint32_t options,
199 uint64_t window_msc,
200 uint64_t divisor,
201 uint64_t remainder,
202 present_notify_ptr notifies,
203 int num_notifies)
204 {
205 ScreenPtr screen = window->drawable.pScreen;
206 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
207
208 return screen_priv->present_pixmap(window,
209 pixmap,
210 serial,
211 valid,
212 update,
213 x_off,
214 y_off,
215 target_crtc,
216 wait_fence,
217 idle_fence,
218 options,
219 window_msc,
220 divisor,
221 remainder,
222 notifies,
223 num_notifies);
224 }
225
226 int
present_notify_msc(WindowPtr window,CARD32 serial,uint64_t target_msc,uint64_t divisor,uint64_t remainder)227 present_notify_msc(WindowPtr window,
228 CARD32 serial,
229 uint64_t target_msc,
230 uint64_t divisor,
231 uint64_t remainder)
232 {
233 return present_pixmap(window,
234 NULL,
235 serial,
236 NULL, NULL,
237 0, 0,
238 NULL,
239 NULL, NULL,
240 divisor == 0 ? PresentOptionAsync : 0,
241 target_msc, divisor, remainder, NULL, 0);
242 }
243