1706f2543Smrg/* 2706f2543Smrg * Copyright � 2009 Maarten Maathuis 3706f2543Smrg * 4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5706f2543Smrg * copy of this software and associated documentation files (the "Software"), 6706f2543Smrg * to deal in the Software without restriction, including without limitation 7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the 9706f2543Smrg * Software is furnished to do so, subject to the following conditions: 10706f2543Smrg * 11706f2543Smrg * The above copyright notice and this permission notice (including the next 12706f2543Smrg * paragraph) shall be included in all copies or substantial portions of the 13706f2543Smrg * Software. 14706f2543Smrg * 15706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18706f2543Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19706f2543Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20706f2543Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21706f2543Smrg * SOFTWARE. 22706f2543Smrg * 23706f2543Smrg */ 24706f2543Smrg 25706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 26706f2543Smrg#include <dix-config.h> 27706f2543Smrg#endif 28706f2543Smrg 29706f2543Smrg#include <string.h> 30706f2543Smrg 31706f2543Smrg#include "exa_priv.h" 32706f2543Smrg#include "exa.h" 33706f2543Smrg 34706f2543Smrgvoid 35706f2543SmrgexaCreateDriverPixmap_mixed(PixmapPtr pPixmap) 36706f2543Smrg{ 37706f2543Smrg ScreenPtr pScreen = pPixmap->drawable.pScreen; 38706f2543Smrg ExaScreenPriv(pScreen); 39706f2543Smrg ExaPixmapPriv(pPixmap); 40706f2543Smrg int w = pPixmap->drawable.width, h = pPixmap->drawable.height; 41706f2543Smrg int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel; 42706f2543Smrg int usage_hint = pPixmap->usage_hint; 43706f2543Smrg int paddedWidth = pExaPixmap->sys_pitch; 44706f2543Smrg 45706f2543Smrg /* Already done. */ 46706f2543Smrg if (pExaPixmap->driverPriv) 47706f2543Smrg return; 48706f2543Smrg 49706f2543Smrg if (exaPixmapIsPinned(pPixmap)) 50706f2543Smrg return; 51706f2543Smrg 52706f2543Smrg /* Can't accel 1/4 bpp. */ 53706f2543Smrg if (pExaPixmap->accel_blocked || bpp < 8) 54706f2543Smrg return; 55706f2543Smrg 56706f2543Smrg if (pExaScr->info->CreatePixmap2) { 57706f2543Smrg int new_pitch = 0; 58706f2543Smrg pExaPixmap->driverPriv = pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp, &new_pitch); 59706f2543Smrg paddedWidth = pExaPixmap->fb_pitch = new_pitch; 60706f2543Smrg } else { 61706f2543Smrg if (paddedWidth < pExaPixmap->fb_pitch) 62706f2543Smrg paddedWidth = pExaPixmap->fb_pitch; 63706f2543Smrg pExaPixmap->driverPriv = pExaScr->info->CreatePixmap(pScreen, paddedWidth*h, 0); 64706f2543Smrg } 65706f2543Smrg 66706f2543Smrg if (!pExaPixmap->driverPriv) 67706f2543Smrg return; 68706f2543Smrg 69706f2543Smrg (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, 70706f2543Smrg paddedWidth, NULL); 71706f2543Smrg} 72706f2543Smrg 73706f2543Smrgvoid 74706f2543SmrgexaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) 75706f2543Smrg{ 76706f2543Smrg int i; 77706f2543Smrg 78706f2543Smrg /* If anything is pinned in system memory, we won't be able to 79706f2543Smrg * accelerate. 80706f2543Smrg */ 81706f2543Smrg for (i = 0; i < npixmaps; i++) { 82706f2543Smrg if (exaPixmapIsPinned (pixmaps[i].pPix) && 83706f2543Smrg !exaPixmapHasGpuCopy (pixmaps[i].pPix)) 84706f2543Smrg { 85706f2543Smrg can_accel = FALSE; 86706f2543Smrg break; 87706f2543Smrg } 88706f2543Smrg } 89706f2543Smrg 90706f2543Smrg /* We can do nothing. */ 91706f2543Smrg if (!can_accel) 92706f2543Smrg return; 93706f2543Smrg 94706f2543Smrg for (i = 0; i < npixmaps; i++) { 95706f2543Smrg PixmapPtr pPixmap = pixmaps[i].pPix; 96706f2543Smrg ExaPixmapPriv(pPixmap); 97706f2543Smrg 98706f2543Smrg if (!pExaPixmap->driverPriv) 99706f2543Smrg exaCreateDriverPixmap_mixed(pPixmap); 100706f2543Smrg 101706f2543Smrg if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) { 102706f2543Smrg ExaScreenPriv(pPixmap->drawable.pScreen); 103706f2543Smrg 104706f2543Smrg /* This pitch is needed for proper acceleration. For some reason 105706f2543Smrg * there are pixmaps without pDamage and a bad fb_pitch value. 106706f2543Smrg * So setting devKind when only exaPixmapHasGpuCopy() is true 107706f2543Smrg * causes corruption. Pixmaps without pDamage are not migrated 108706f2543Smrg * and should have a valid devKind at all times, so that's why this 109706f2543Smrg * isn't causing problems. Pixmaps have their gpu pitch set the 110706f2543Smrg * first time in the MPH call from exaCreateDriverPixmap_mixed(). 111706f2543Smrg */ 112706f2543Smrg pPixmap->devKind = pExaPixmap->fb_pitch; 113706f2543Smrg exaCopyDirtyToFb(pixmaps + i); 114706f2543Smrg 115706f2543Smrg if (pExaScr->deferred_mixed_pixmap == pPixmap && 116706f2543Smrg !pixmaps[i].as_dst && !pixmaps[i].pReg) 117706f2543Smrg pExaScr->deferred_mixed_pixmap = NULL; 118706f2543Smrg } 119706f2543Smrg 120706f2543Smrg pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap); 121706f2543Smrg } 122706f2543Smrg} 123706f2543Smrg 124706f2543Smrgvoid 125706f2543SmrgexaMoveInPixmap_mixed(PixmapPtr pPixmap) 126706f2543Smrg{ 127706f2543Smrg ExaMigrationRec pixmaps[1]; 128706f2543Smrg 129706f2543Smrg pixmaps[0].as_dst = FALSE; 130706f2543Smrg pixmaps[0].as_src = TRUE; 131706f2543Smrg pixmaps[0].pPix = pPixmap; 132706f2543Smrg pixmaps[0].pReg = NULL; 133706f2543Smrg 134706f2543Smrg exaDoMigration(pixmaps, 1, TRUE); 135706f2543Smrg} 136706f2543Smrg 137706f2543Smrgvoid 138706f2543SmrgexaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure) 139706f2543Smrg{ 140706f2543Smrg PixmapPtr pPixmap = closure; 141706f2543Smrg ExaPixmapPriv(pPixmap); 142706f2543Smrg 143706f2543Smrg /* Move back results of software rendering on system memory copy of mixed driver 144706f2543Smrg * pixmap (see exaPrepareAccessReg_mixed). 145706f2543Smrg * 146706f2543Smrg * Defer moving the destination back into the driver pixmap, to try and save 147706f2543Smrg * overhead on multiple subsequent software fallbacks. 148706f2543Smrg */ 149706f2543Smrg if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) { 150706f2543Smrg ExaScreenPriv(pPixmap->drawable.pScreen); 151706f2543Smrg 152706f2543Smrg if (pExaScr->deferred_mixed_pixmap && 153706f2543Smrg pExaScr->deferred_mixed_pixmap != pPixmap) 154706f2543Smrg exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap); 155706f2543Smrg pExaScr->deferred_mixed_pixmap = pPixmap; 156706f2543Smrg } 157706f2543Smrg} 158706f2543Smrg 159706f2543Smrg/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we 160706f2543Smrg * use the DownloadFromScreen hook to retrieve contents to a copy in system 161706f2543Smrg * memory, perform software rendering on that and move back the results with the 162706f2543Smrg * UploadToScreen hook (see exaDamageReport_mixed). 163706f2543Smrg */ 164706f2543Smrgvoid 165706f2543SmrgexaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg) 166706f2543Smrg{ 167706f2543Smrg ExaPixmapPriv(pPixmap); 168706f2543Smrg Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); 169706f2543Smrg Bool success; 170706f2543Smrg 171706f2543Smrg success = ExaDoPrepareAccess(pPixmap, index); 172706f2543Smrg 173706f2543Smrg if (success && has_gpu_copy && pExaPixmap->pDamage) { 174706f2543Smrg /* You cannot do accelerated operations while a buffer is mapped. */ 175706f2543Smrg exaFinishAccess(&pPixmap->drawable, index); 176706f2543Smrg /* Update the gpu view of both deferred destination pixmaps and of 177706f2543Smrg * source pixmaps that were migrated with a bounding region. 178706f2543Smrg */ 179706f2543Smrg exaMoveInPixmap_mixed(pPixmap); 180706f2543Smrg success = ExaDoPrepareAccess(pPixmap, index); 181706f2543Smrg 182706f2543Smrg if (success) { 183706f2543Smrg /* We have a gpu pixmap that can be accessed, we don't need the cpu 184706f2543Smrg * copy anymore. Drivers that prefer DFS, should fail prepare 185706f2543Smrg * access. 186706f2543Smrg */ 187706f2543Smrg DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); 188706f2543Smrg DamageDestroy(pExaPixmap->pDamage); 189706f2543Smrg pExaPixmap->pDamage = NULL; 190706f2543Smrg 191706f2543Smrg free(pExaPixmap->sys_ptr); 192706f2543Smrg pExaPixmap->sys_ptr = NULL; 193706f2543Smrg 194706f2543Smrg return; 195706f2543Smrg } 196706f2543Smrg } 197706f2543Smrg 198706f2543Smrg if (!success) { 199706f2543Smrg ExaMigrationRec pixmaps[1]; 200706f2543Smrg 201706f2543Smrg /* Do we need to allocate our system buffer? */ 202706f2543Smrg if (!pExaPixmap->sys_ptr) { 203706f2543Smrg pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch * 204706f2543Smrg pPixmap->drawable.height); 205706f2543Smrg if (!pExaPixmap->sys_ptr) 206706f2543Smrg FatalError("EXA: malloc failed for size %d bytes\n", 207706f2543Smrg pExaPixmap->sys_pitch * pPixmap->drawable.height); 208706f2543Smrg } 209706f2543Smrg 210706f2543Smrg if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { 211706f2543Smrg pixmaps[0].as_dst = TRUE; 212706f2543Smrg pixmaps[0].as_src = FALSE; 213706f2543Smrg } else { 214706f2543Smrg pixmaps[0].as_dst = FALSE; 215706f2543Smrg pixmaps[0].as_src = TRUE; 216706f2543Smrg } 217706f2543Smrg pixmaps[0].pPix = pPixmap; 218706f2543Smrg pixmaps[0].pReg = pReg; 219706f2543Smrg 220706f2543Smrg if (!pExaPixmap->pDamage && 221706f2543Smrg (has_gpu_copy || !exaPixmapIsPinned(pPixmap))) { 222706f2543Smrg Bool as_dst = pixmaps[0].as_dst; 223706f2543Smrg 224706f2543Smrg /* Set up damage tracking */ 225706f2543Smrg pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, 226706f2543Smrg DamageReportNonEmpty, TRUE, 227706f2543Smrg pPixmap->drawable.pScreen, 228706f2543Smrg pPixmap); 229706f2543Smrg 230706f2543Smrg DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); 231706f2543Smrg /* This ensures that pending damage reflects the current operation. */ 232706f2543Smrg /* This is used by exa to optimize migration. */ 233706f2543Smrg DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); 234706f2543Smrg 235706f2543Smrg if (has_gpu_copy) { 236706f2543Smrg exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, 237706f2543Smrg pPixmap->drawable.height); 238706f2543Smrg 239706f2543Smrg /* We don't know which region of the destination will be damaged, 240706f2543Smrg * have to assume all of it 241706f2543Smrg */ 242706f2543Smrg if (as_dst) { 243706f2543Smrg pixmaps[0].as_dst = FALSE; 244706f2543Smrg pixmaps[0].as_src = TRUE; 245706f2543Smrg pixmaps[0].pReg = NULL; 246706f2543Smrg } 247706f2543Smrg exaCopyDirtyToSys(pixmaps); 248706f2543Smrg } 249706f2543Smrg 250706f2543Smrg if (as_dst) 251706f2543Smrg exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, 252706f2543Smrg pPixmap->drawable.height); 253706f2543Smrg } else if (has_gpu_copy) 254706f2543Smrg exaCopyDirtyToSys(pixmaps); 255706f2543Smrg 256706f2543Smrg pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; 257706f2543Smrg pPixmap->devKind = pExaPixmap->sys_pitch; 258706f2543Smrg pExaPixmap->use_gpu_copy = FALSE; 259706f2543Smrg } 260706f2543Smrg} 261706f2543Smrg 262