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
;
39 ExaScreenPriv(pScreen
);
40 ExaPixmapPriv(pPixmap
);
41 int w
= pPixmap
->drawable
.width
, h
= pPixmap
->drawable
.height
;
42 int depth
= pPixmap
->drawable
.depth
, bpp
= pPixmap
->drawable
.bitsPerPixel
;
43 int usage_hint
= pPixmap
->usage_hint
;
44 int paddedWidth
= pExaPixmap
->sys_pitch
;
47 if (pExaPixmap
->driverPriv
)
50 if (exaPixmapIsPinned(pPixmap
))
53 /* Can't accel 1/4 bpp. */
54 if (pExaPixmap
->accel_blocked
|| bpp
< 8)
57 if (pExaScr
->info
->CreatePixmap2
) {
60 pExaPixmap
->driverPriv
=
61 pExaScr
->info
->CreatePixmap2(pScreen
, w
, h
, depth
, usage_hint
, bpp
,
63 paddedWidth
= pExaPixmap
->fb_pitch
= new_pitch
;
66 if (paddedWidth
< pExaPixmap
->fb_pitch
)
67 paddedWidth
= pExaPixmap
->fb_pitch
;
68 pExaPixmap
->driverPriv
=
69 pExaScr
->info
->CreatePixmap(pScreen
, paddedWidth
* h
, 0);
72 if (!pExaPixmap
->driverPriv
)
75 (*pScreen
->ModifyPixmapHeader
) (pPixmap
, w
, h
, 0, 0, paddedWidth
, NULL
);
79 exaDoMigration_mixed(ExaMigrationPtr pixmaps
, int npixmaps
, Bool can_accel
)
83 /* If anything is pinned in system memory, we won't be able to
86 for (i
= 0; i
< npixmaps
; i
++) {
87 if (exaPixmapIsPinned(pixmaps
[i
].pPix
) &&
88 !exaPixmapHasGpuCopy(pixmaps
[i
].pPix
)) {
94 /* We can do nothing. */
98 for (i
= 0; i
< npixmaps
; i
++) {
99 PixmapPtr pPixmap
= pixmaps
[i
].pPix
;
101 ExaPixmapPriv(pPixmap
);
103 if (!pExaPixmap
->driverPriv
)
104 exaCreateDriverPixmap_mixed(pPixmap
);
106 if (pExaPixmap
->pDamage
&& exaPixmapHasGpuCopy(pPixmap
)) {
107 ExaScreenPriv(pPixmap
->drawable
.pScreen
);
109 /* This pitch is needed for proper acceleration. For some reason
110 * there are pixmaps without pDamage and a bad fb_pitch value.
111 * So setting devKind when only exaPixmapHasGpuCopy() is true
112 * causes corruption. Pixmaps without pDamage are not migrated
113 * and should have a valid devKind at all times, so that's why this
114 * isn't causing problems. Pixmaps have their gpu pitch set the
115 * first time in the MPH call from exaCreateDriverPixmap_mixed().
117 pPixmap
->devKind
= pExaPixmap
->fb_pitch
;
118 exaCopyDirtyToFb(pixmaps
+ i
);
120 if (pExaScr
->deferred_mixed_pixmap
== pPixmap
&&
121 !pixmaps
[i
].as_dst
&& !pixmaps
[i
].pReg
)
122 pExaScr
->deferred_mixed_pixmap
= NULL
;
125 pExaPixmap
->use_gpu_copy
= exaPixmapHasGpuCopy(pPixmap
);
130 exaMoveInPixmap_mixed(PixmapPtr pPixmap
)
132 ExaMigrationRec pixmaps
[1];
134 pixmaps
[0].as_dst
= FALSE
;
135 pixmaps
[0].as_src
= TRUE
;
136 pixmaps
[0].pPix
= pPixmap
;
137 pixmaps
[0].pReg
= NULL
;
139 exaDoMigration(pixmaps
, 1, TRUE
);
143 exaDamageReport_mixed(DamagePtr pDamage
, RegionPtr pRegion
, void *closure
)
145 PixmapPtr pPixmap
= closure
;
147 ExaPixmapPriv(pPixmap
);
149 /* Move back results of software rendering on system memory copy of mixed driver
150 * pixmap (see exaPrepareAccessReg_mixed).
152 * Defer moving the destination back into the driver pixmap, to try and save
153 * overhead on multiple subsequent software fallbacks.
155 if (!pExaPixmap
->use_gpu_copy
&& exaPixmapHasGpuCopy(pPixmap
)) {
156 ExaScreenPriv(pPixmap
->drawable
.pScreen
);
158 if (pExaScr
->deferred_mixed_pixmap
&&
159 pExaScr
->deferred_mixed_pixmap
!= pPixmap
)
160 exaMoveInPixmap_mixed(pExaScr
->deferred_mixed_pixmap
);
161 pExaScr
->deferred_mixed_pixmap
= pPixmap
;
165 /* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
166 * use the DownloadFromScreen hook to retrieve contents to a copy in system
167 * memory, perform software rendering on that and move back the results with the
168 * UploadToScreen hook (see exaDamageReport_mixed).
171 exaPrepareAccessReg_mixed(PixmapPtr pPixmap
, int index
, RegionPtr pReg
)
173 ExaPixmapPriv(pPixmap
);
174 Bool has_gpu_copy
= exaPixmapHasGpuCopy(pPixmap
);
177 success
= ExaDoPrepareAccess(pPixmap
, index
);
179 if (success
&& has_gpu_copy
&& pExaPixmap
->pDamage
) {
180 /* You cannot do accelerated operations while a buffer is mapped. */
181 exaFinishAccess(&pPixmap
->drawable
, index
);
182 /* Update the gpu view of both deferred destination pixmaps and of
183 * source pixmaps that were migrated with a bounding region.
185 exaMoveInPixmap_mixed(pPixmap
);
186 success
= ExaDoPrepareAccess(pPixmap
, index
);
189 /* We have a gpu pixmap that can be accessed, we don't need the cpu
190 * copy anymore. Drivers that prefer DFS, should fail prepare
193 DamageDestroy(pExaPixmap
->pDamage
);
194 pExaPixmap
->pDamage
= NULL
;
196 free(pExaPixmap
->sys_ptr
);
197 pExaPixmap
->sys_ptr
= NULL
;
204 ExaMigrationRec pixmaps
[1];
206 /* Do we need to allocate our system buffer? */
207 if (!pExaPixmap
->sys_ptr
) {
208 pExaPixmap
->sys_ptr
= malloc(pExaPixmap
->sys_pitch
*
209 pPixmap
->drawable
.height
);
210 if (!pExaPixmap
->sys_ptr
)
211 FatalError("EXA: malloc failed for size %d bytes\n",
212 pExaPixmap
->sys_pitch
* pPixmap
->drawable
.height
);
215 if (index
== EXA_PREPARE_DEST
|| index
== EXA_PREPARE_AUX_DEST
) {
216 pixmaps
[0].as_dst
= TRUE
;
217 pixmaps
[0].as_src
= FALSE
;
220 pixmaps
[0].as_dst
= FALSE
;
221 pixmaps
[0].as_src
= TRUE
;
223 pixmaps
[0].pPix
= pPixmap
;
224 pixmaps
[0].pReg
= pReg
;
226 if (!pExaPixmap
->pDamage
&&
227 (has_gpu_copy
|| !exaPixmapIsPinned(pPixmap
))) {
228 Bool as_dst
= pixmaps
[0].as_dst
;
230 /* Set up damage tracking */
231 pExaPixmap
->pDamage
= DamageCreate(exaDamageReport_mixed
, NULL
,
232 DamageReportNonEmpty
, TRUE
,
233 pPixmap
->drawable
.pScreen
,
236 if (pExaPixmap
->pDamage
) {
237 DamageRegister(&pPixmap
->drawable
, pExaPixmap
->pDamage
);
238 /* This ensures that pending damage reflects the current
239 * operation. This is used by exa to optimize migration.
241 DamageSetReportAfterOp(pExaPixmap
->pDamage
, TRUE
);
245 exaPixmapDirty(pPixmap
, 0, 0, pPixmap
->drawable
.width
,
246 pPixmap
->drawable
.height
);
248 /* We don't know which region of the destination will be damaged,
249 * have to assume all of it
252 pixmaps
[0].as_dst
= FALSE
;
253 pixmaps
[0].as_src
= TRUE
;
254 pixmaps
[0].pReg
= NULL
;
256 exaCopyDirtyToSys(pixmaps
);
260 exaPixmapDirty(pPixmap
, 0, 0, pPixmap
->drawable
.width
,
261 pPixmap
->drawable
.height
);
263 else if (has_gpu_copy
)
264 exaCopyDirtyToSys(pixmaps
);
266 pPixmap
->devPrivate
.ptr
= pExaPixmap
->sys_ptr
;
267 pPixmap
->devKind
= pExaPixmap
->sys_pitch
;
268 pExaPixmap
->use_gpu_copy
= FALSE
;