exa_migration_mixed.c revision 35c4bbdf
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 = xallocarray(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} 271