1 /*
2  * Copyright © 2009 Maarten Maathuis
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  *
23  */
24 
25 #ifdef HAVE_DIX_CONFIG_H
26 #include <dix-config.h>
27 #endif
28 
29 #include <string.h>
30 
31 #include "exa_priv.h"
32 #include "exa.h"
33 
34 /* This file holds the driver allocated pixmaps + better initial placement code.
35  */
36 
37 static _X_INLINE void *
ExaGetPixmapAddress(PixmapPtr p)38 ExaGetPixmapAddress(PixmapPtr p)
39 {
40     ExaPixmapPriv(p);
41 
42     return pExaPixmap->sys_ptr;
43 }
44 
45 /**
46  * exaCreatePixmap() creates a new pixmap.
47  */
48 PixmapPtr
exaCreatePixmap_mixed(ScreenPtr pScreen,int w,int h,int depth,unsigned usage_hint)49 exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
50                       unsigned usage_hint)
51 {
52     PixmapPtr pPixmap;
53     ExaPixmapPrivPtr pExaPixmap;
54     int bpp;
55     size_t paddedWidth;
56 
57     ExaScreenPriv(pScreen);
58 
59     if (w > 32767 || h > 32767)
60         return NullPixmap;
61 
62     swap(pExaScr, pScreen, CreatePixmap);
63     pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
64     swap(pExaScr, pScreen, CreatePixmap);
65 
66     if (!pPixmap)
67         return NULL;
68 
69     pExaPixmap = ExaGetPixmapPriv(pPixmap);
70     pExaPixmap->driverPriv = NULL;
71 
72     bpp = pPixmap->drawable.bitsPerPixel;
73 
74     paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
75     if (paddedWidth / 4 > 32767 || h > 32767)
76         return NullPixmap;
77 
78     /* We will allocate the system pixmap later if needed. */
79     pPixmap->devPrivate.ptr = NULL;
80     pExaPixmap->sys_ptr = NULL;
81     pExaPixmap->sys_pitch = paddedWidth;
82 
83     pExaPixmap->area = NULL;
84     pExaPixmap->fb_ptr = NULL;
85     pExaPixmap->pDamage = NULL;
86 
87     exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
88     exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
89 
90     (*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
91 
92     /* A scratch pixmap will become a driver pixmap right away. */
93     if (!w || !h) {
94         exaCreateDriverPixmap_mixed(pPixmap);
95         pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
96     }
97     else {
98         pExaPixmap->use_gpu_copy = FALSE;
99 
100         if (w == 1 && h == 1) {
101             pExaPixmap->sys_ptr = malloc(paddedWidth);
102 
103             /* Set up damage tracking */
104             pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
105                                                DamageReportNonEmpty, TRUE,
106                                                pPixmap->drawable.pScreen,
107                                                pPixmap);
108 
109             if (pExaPixmap->pDamage) {
110                 DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
111                 /* This ensures that pending damage reflects the current
112                  * operation. This is used by exa to optimize migration.
113                  */
114                 DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
115             }
116         }
117     }
118 
119     /* During a fallback we must prepare access. */
120     if (pExaScr->fallback_counter)
121         exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
122 
123     return pPixmap;
124 }
125 
126 Bool
exaModifyPixmapHeader_mixed(PixmapPtr pPixmap,int width,int height,int depth,int bitsPerPixel,int devKind,void * pPixData)127 exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
128                             int bitsPerPixel, int devKind, void *pPixData)
129 {
130     ScreenPtr pScreen;
131     ExaScreenPrivPtr pExaScr;
132     ExaPixmapPrivPtr pExaPixmap;
133     Bool ret, has_gpu_copy;
134 
135     if (!pPixmap)
136         return FALSE;
137 
138     pScreen = pPixmap->drawable.pScreen;
139     pExaScr = ExaGetScreenPriv(pScreen);
140     pExaPixmap = ExaGetPixmapPriv(pPixmap);
141 
142     if (pPixData) {
143         if (pExaPixmap->driverPriv) {
144             if (pExaPixmap->pDamage) {
145                 DamageDestroy(pExaPixmap->pDamage);
146                 pExaPixmap->pDamage = NULL;
147             }
148 
149             pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
150             pExaPixmap->driverPriv = NULL;
151         }
152 
153         pExaPixmap->use_gpu_copy = FALSE;
154         pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
155     }
156 
157     has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
158 
159     if (width <= 0)
160         width = pPixmap->drawable.width;
161 
162     if (height <= 0)
163         height = pPixmap->drawable.height;
164 
165     if (bitsPerPixel <= 0) {
166         if (depth <= 0)
167             bitsPerPixel = pPixmap->drawable.bitsPerPixel;
168         else
169             bitsPerPixel = BitsPerPixel(depth);
170     }
171 
172     if (depth <= 0)
173         depth = pPixmap->drawable.depth;
174 
175     if (width != pPixmap->drawable.width ||
176         height != pPixmap->drawable.height ||
177         depth != pPixmap->drawable.depth ||
178         bitsPerPixel != pPixmap->drawable.bitsPerPixel) {
179         if (pExaPixmap->driverPriv) {
180             if (devKind > 0)
181                 pExaPixmap->fb_pitch = devKind;
182             else
183                 exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
184 
185             exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
186             RegionEmpty(&pExaPixmap->validFB);
187         }
188 
189         /* Need to re-create system copy if there's also a GPU copy */
190         if (has_gpu_copy) {
191             if (pExaPixmap->sys_ptr) {
192                 free(pExaPixmap->sys_ptr);
193                 pExaPixmap->sys_ptr = NULL;
194                 DamageDestroy(pExaPixmap->pDamage);
195                 pExaPixmap->pDamage = NULL;
196                 RegionEmpty(&pExaPixmap->validSys);
197 
198                 if (pExaScr->deferred_mixed_pixmap == pPixmap)
199                     pExaScr->deferred_mixed_pixmap = NULL;
200             }
201 
202             pExaPixmap->sys_pitch = PixmapBytePad(width, depth);
203         }
204     }
205 
206     if (has_gpu_copy) {
207         pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
208         pPixmap->devKind = pExaPixmap->fb_pitch;
209     }
210     else {
211         pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
212         pPixmap->devKind = pExaPixmap->sys_pitch;
213     }
214 
215     /* Only pass driver pixmaps to the driver. */
216     if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) {
217         ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
218                                                 bitsPerPixel, devKind,
219                                                 pPixData);
220         if (ret == TRUE)
221             goto out;
222     }
223 
224     swap(pExaScr, pScreen, ModifyPixmapHeader);
225     ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
226                                       bitsPerPixel, devKind, pPixData);
227     swap(pExaScr, pScreen, ModifyPixmapHeader);
228 
229  out:
230     if (has_gpu_copy) {
231         pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr;
232         pExaPixmap->fb_pitch = pPixmap->devKind;
233     }
234     else {
235         pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
236         pExaPixmap->sys_pitch = pPixmap->devKind;
237     }
238     /* Always NULL this, we don't want lingering pointers. */
239     pPixmap->devPrivate.ptr = NULL;
240 
241     return ret;
242 }
243 
244 Bool
exaDestroyPixmap_mixed(PixmapPtr pPixmap)245 exaDestroyPixmap_mixed(PixmapPtr pPixmap)
246 {
247     ScreenPtr pScreen = pPixmap->drawable.pScreen;
248 
249     ExaScreenPriv(pScreen);
250     Bool ret;
251 
252     if (pPixmap->refcnt == 1) {
253         ExaPixmapPriv(pPixmap);
254 
255         exaDestroyPixmap(pPixmap);
256 
257         if (pExaScr->deferred_mixed_pixmap == pPixmap)
258             pExaScr->deferred_mixed_pixmap = NULL;
259 
260         if (pExaPixmap->driverPriv)
261             pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
262         pExaPixmap->driverPriv = NULL;
263 
264         if (pExaPixmap->pDamage) {
265             free(pExaPixmap->sys_ptr);
266             pExaPixmap->sys_ptr = NULL;
267             pExaPixmap->pDamage = NULL;
268         }
269     }
270 
271     swap(pExaScr, pScreen, DestroyPixmap);
272     ret = pScreen->DestroyPixmap(pPixmap);
273     swap(pExaScr, pScreen, DestroyPixmap);
274 
275     return ret;
276 }
277 
278 Bool
exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap)279 exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap)
280 {
281     ScreenPtr pScreen = pPixmap->drawable.pScreen;
282 
283     ExaScreenPriv(pScreen);
284     ExaPixmapPriv(pPixmap);
285     void *saved_ptr;
286     Bool ret;
287 
288     if (!pExaPixmap->driverPriv)
289         return FALSE;
290 
291     saved_ptr = pPixmap->devPrivate.ptr;
292     pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
293     ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
294     pPixmap->devPrivate.ptr = saved_ptr;
295 
296     return ret;
297 }
298 
299 Bool
exaSharePixmapBacking_mixed(PixmapPtr pPixmap,ScreenPtr slave,void ** handle_p)300 exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr slave, void **handle_p)
301 {
302     ScreenPtr pScreen = pPixmap->drawable.pScreen;
303     ExaScreenPriv(pScreen);
304     Bool ret = FALSE;
305 
306     exaMoveInPixmap(pPixmap);
307     /* get the driver to give us a handle */
308     if (pExaScr->info->SharePixmapBacking)
309         ret = pExaScr->info->SharePixmapBacking(pPixmap, slave, handle_p);
310 
311     return ret;
312 }
313 
314 Bool
exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap,void * handle)315 exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle)
316 {
317     ScreenPtr pScreen = pPixmap->drawable.pScreen;
318     ExaScreenPriv(pScreen);
319     Bool ret = FALSE;
320 
321     if (pExaScr->info->SetSharedPixmapBacking)
322         ret = pExaScr->info->SetSharedPixmapBacking(pPixmap, handle);
323 
324     if (ret == TRUE)
325         exaMoveInPixmap(pPixmap);
326 
327     return ret;
328 }
329 
330 
331