2 * Copyright © 2009 Maarten Maathuis
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:
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
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
25 #ifdef HAVE_DIX_CONFIG_H
26 #include <dix-config.h>
35 exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
37 ScreenPtr pScreen = pPixmap->drawable.pScreen;
38 ExaScreenPriv(pScreen);
39 ExaPixmapPriv(pPixmap);
40 int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
41 int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
42 int usage_hint = pPixmap->usage_hint;
43 int paddedWidth = pExaPixmap->sys_pitch;
46 if (pExaPixmap->driverPriv)
49 if (exaPixmapIsPinned(pPixmap))
52 /* Can't accel 1/4 bpp. */
53 if (pExaPixmap->accel_blocked || bpp < 8)
56 if (pExaScr->info->CreatePixmap2) {
58 pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch);
59 paddedWidth = pExaPixmap->fb_pitch = new_pitch;
61 if (paddedWidth < pExaPixmap->fb_pitch)
62 paddedWidth = pExaPixmap->fb_pitch;
63 pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, paddedWidth*h, 0);
66 if (!pExaPixmap->driverPriv)
69 (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
74 exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
78 /* If anything is pinned in system memory, we won't be able to
81 for (i = 0; i < npixmaps; i++) {
82 if (exaPixmapIsPinned (pixmaps[i].pPix) &&
83 !exaPixmapHasGpuCopy (pixmaps[i].pPix))
90 /* We can do nothing. */
94 for (i = 0; i < npixmaps; i++) {
95 PixmapPtr pPixmap = pixmaps[i].pPix;
96 ExaPixmapPriv(pPixmap);
98 if (!pExaPixmap->driverPriv)
99 exaCreateDriverPixmap_mixed(pPixmap);
101 if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) {
102 ExaScreenPriv(pPixmap->drawable.pScreen);
104 /* This pitch is needed for proper acceleration. For some reason
105 * there are pixmaps without pDamage and a bad fb_pitch value.
106 * So setting devKind when only exaPixmapHasGpuCopy() is true
107 * causes corruption. Pixmaps without pDamage are not migrated
108 * and should have a valid devKind at all times, so that's why this
109 * isn't causing problems. Pixmaps have their gpu pitch set the
110 * first time in the MPH call from exaCreateDriverPixmap_mixed().
112 pPixmap->devKind = pExaPixmap->fb_pitch;
113 exaCopyDirtyToFb(pixmaps + i);
115 if (pExaScr->deferred_mixed_pixmap == pPixmap &&
116 !pixmaps[i].as_dst && !pixmaps[i].pReg)
117 pExaScr->deferred_mixed_pixmap = NULL;
120 pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
125 exaMoveInPixmap_mixed(PixmapPtr pPixmap)
127 ExaMigrationRec pixmaps[1];
129 pixmaps[0].as_dst = FALSE;
130 pixmaps[0].as_src = TRUE;
131 pixmaps[0].pPix = pPixmap;
132 pixmaps[0].pReg = NULL;
134 exaDoMigration(pixmaps, 1, TRUE);
138 exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure)
140 PixmapPtr pPixmap = closure;
141 ExaPixmapPriv(pPixmap);
143 /* Move back results of software rendering on system memory copy of mixed driver
144 * pixmap (see exaPrepareAccessReg_mixed).
146 * Defer moving the destination back into the driver pixmap, to try and save
147 * overhead on multiple subsequent software fallbacks.
149 if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) {
150 ExaScreenPriv(pPixmap->drawable.pScreen);
152 if (pExaScr->deferred_mixed_pixmap &&
153 pExaScr->deferred_mixed_pixmap != pPixmap)
154 exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
155 pExaScr->deferred_mixed_pixmap = pPixmap;
159 /* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
160 * use the DownloadFromScreen hook to retrieve contents to a copy in system
161 * memory, perform software rendering on that and move back the results with the
162 * UploadToScreen hook (see exaDamageReport_mixed).
165 exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
167 ExaPixmapPriv(pPixmap);
168 Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
171 success = ExaDoPrepareAccess(pPixmap, index);
173 if (success && has_gpu_copy && pExaPixmap->pDamage) {
174 /* You cannot do accelerated operations while a buffer is mapped. */
175 exaFinishAccess(&pPixmap->drawable, index);
176 /* Update the gpu view of both deferred destination pixmaps and of
177 * source pixmaps that were migrated with a bounding region.
179 exaMoveInPixmap_mixed(pPixmap);
180 success = ExaDoPrepareAccess(pPixmap, index);
183 /* We have a gpu pixmap that can be accessed, we don't need the cpu
184 * copy anymore. Drivers that prefer DFS, should fail prepare
187 DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
188 DamageDestroy(pExaPixmap->pDamage);
189 pExaPixmap->pDamage = NULL;
191 free(pExaPixmap->sys_ptr);
192 pExaPixmap->sys_ptr = NULL;
199 ExaMigrationRec pixmaps[1];
201 /* Do we need to allocate our system buffer? */
202 if (!pExaPixmap->sys_ptr) {
203 pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch *
204 pPixmap->drawable.height);
205 if (!pExaPixmap->sys_ptr)
206 FatalError("EXA: malloc failed for size %d bytes\n",
207 pExaPixmap->sys_pitch * pPixmap->drawable.height);
210 if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
211 pixmaps[0].as_dst = TRUE;
212 pixmaps[0].as_src = FALSE;
214 pixmaps[0].as_dst = FALSE;
215 pixmaps[0].as_src = TRUE;
217 pixmaps[0].pPix = pPixmap;
218 pixmaps[0].pReg = pReg;
220 if (!pExaPixmap->pDamage &&
221 (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) {
222 Bool as_dst = pixmaps[0].as_dst;
224 /* Set up damage tracking */
225 pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
226 DamageReportNonEmpty, TRUE,
227 pPixmap->drawable.pScreen,
230 DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
231 /* This ensures that pending damage reflects the current operation. */
232 /* This is used by exa to optimize migration. */
233 DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
236 exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
237 pPixmap->drawable.height);
239 /* We don't know which region of the destination will be damaged,
240 * have to assume all of it
243 pixmaps[0].as_dst = FALSE;
244 pixmaps[0].as_src = TRUE;
245 pixmaps[0].pReg = NULL;
247 exaCopyDirtyToSys(pixmaps);
251 exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
252 pPixmap->drawable.height);
253 } else if (has_gpu_copy)
254 exaCopyDirtyToSys(pixmaps);
256 pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
257 pPixmap->devKind = pExaPixmap->sys_pitch;
258 pExaPixmap->use_gpu_copy = FALSE;