Imported Upstream version 1.15.1
[deb_xorg-server.git] / exa / exa_migration_mixed.c
CommitLineData
a09e091a
JB
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
34void
35exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
36{
37 ScreenPtr pScreen = pPixmap->drawable.pScreen;
38
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;
45
46 /* Already done. */
47 if (pExaPixmap->driverPriv)
48 return;
49
50 if (exaPixmapIsPinned(pPixmap))
51 return;
52
53 /* Can't accel 1/4 bpp. */
54 if (pExaPixmap->accel_blocked || bpp < 8)
55 return;
56
57 if (pExaScr->info->CreatePixmap2) {
58 int new_pitch = 0;
59
60 pExaPixmap->driverPriv =
61 pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp,
62 &new_pitch);
63 paddedWidth = pExaPixmap->fb_pitch = new_pitch;
64 }
65 else {
66 if (paddedWidth < pExaPixmap->fb_pitch)
67 paddedWidth = pExaPixmap->fb_pitch;
68 pExaPixmap->driverPriv =
69 pExaScr->info->CreatePixmap(pScreen, paddedWidth * h, 0);
70 }
71
72 if (!pExaPixmap->driverPriv)
73 return;
74
75 (*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
76}
77
78void
79exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
80{
81 int i;
82
83 /* If anything is pinned in system memory, we won't be able to
84 * accelerate.
85 */
86 for (i = 0; i < npixmaps; i++) {
87 if (exaPixmapIsPinned(pixmaps[i].pPix) &&
88 !exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
89 can_accel = FALSE;
90 break;
91 }
92 }
93
94 /* We can do nothing. */
95 if (!can_accel)
96 return;
97
98 for (i = 0; i < npixmaps; i++) {
99 PixmapPtr pPixmap = pixmaps[i].pPix;
100
101 ExaPixmapPriv(pPixmap);
102
103 if (!pExaPixmap->driverPriv)
104 exaCreateDriverPixmap_mixed(pPixmap);
105
106 if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) {
107 ExaScreenPriv(pPixmap->drawable.pScreen);
108
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().
116 */
117 pPixmap->devKind = pExaPixmap->fb_pitch;
118 exaCopyDirtyToFb(pixmaps + i);
119
120 if (pExaScr->deferred_mixed_pixmap == pPixmap &&
121 !pixmaps[i].as_dst && !pixmaps[i].pReg)
122 pExaScr->deferred_mixed_pixmap = NULL;
123 }
124
125 pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
126 }
127}
128
129void
130exaMoveInPixmap_mixed(PixmapPtr pPixmap)
131{
132 ExaMigrationRec pixmaps[1];
133
134 pixmaps[0].as_dst = FALSE;
135 pixmaps[0].as_src = TRUE;
136 pixmaps[0].pPix = pPixmap;
137 pixmaps[0].pReg = NULL;
138
139 exaDoMigration(pixmaps, 1, TRUE);
140}
141
142void
143exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure)
144{
145 PixmapPtr pPixmap = closure;
146
147 ExaPixmapPriv(pPixmap);
148
149 /* Move back results of software rendering on system memory copy of mixed driver
150 * pixmap (see exaPrepareAccessReg_mixed).
151 *
152 * Defer moving the destination back into the driver pixmap, to try and save
153 * overhead on multiple subsequent software fallbacks.
154 */
155 if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) {
156 ExaScreenPriv(pPixmap->drawable.pScreen);
157
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;
162 }
163}
164
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).
169 */
170void
171exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
172{
173 ExaPixmapPriv(pPixmap);
174 Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
175 Bool success;
176
177 success = ExaDoPrepareAccess(pPixmap, index);
178
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.
184 */
185 exaMoveInPixmap_mixed(pPixmap);
186 success = ExaDoPrepareAccess(pPixmap, index);
187
188 if (success) {
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
191 * access.
192 */
193 DamageDestroy(pExaPixmap->pDamage);
194 pExaPixmap->pDamage = NULL;
195
196 free(pExaPixmap->sys_ptr);
197 pExaPixmap->sys_ptr = NULL;
198
199 return;
200 }
201 }
202
203 if (!success) {
204 ExaMigrationRec pixmaps[1];
205
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);
213 }
214
215 if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
216 pixmaps[0].as_dst = TRUE;
217 pixmaps[0].as_src = FALSE;
218 }
219 else {
220 pixmaps[0].as_dst = FALSE;
221 pixmaps[0].as_src = TRUE;
222 }
223 pixmaps[0].pPix = pPixmap;
224 pixmaps[0].pReg = pReg;
225
226 if (!pExaPixmap->pDamage &&
227 (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) {
228 Bool as_dst = pixmaps[0].as_dst;
229
230 /* Set up damage tracking */
231 pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
232 DamageReportNonEmpty, TRUE,
233 pPixmap->drawable.pScreen,
234 pPixmap);
235
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.
240 */
241 DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
242 }
243
244 if (has_gpu_copy) {
245 exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
246 pPixmap->drawable.height);
247
248 /* We don't know which region of the destination will be damaged,
249 * have to assume all of it
250 */
251 if (as_dst) {
252 pixmaps[0].as_dst = FALSE;
253 pixmaps[0].as_src = TRUE;
254 pixmaps[0].pReg = NULL;
255 }
256 exaCopyDirtyToSys(pixmaps);
257 }
258
259 if (as_dst)
260 exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
261 pPixmap->drawable.height);
262 }
263 else if (has_gpu_copy)
264 exaCopyDirtyToSys(pixmaps);
265
266 pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
267 pPixmap->devKind = pExaPixmap->sys_pitch;
268 pExaPixmap->use_gpu_copy = FALSE;
269 }
270}