xref: /OK3568_Linux_fs/external/xserver/present/present.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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