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