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 34/* This file holds the driver allocated pixmaps + better initial placement code. 35 */ 36 37static _X_INLINE void * 38ExaGetPixmapAddress(PixmapPtr p) 39{ 40 ExaPixmapPriv(p); 41 42 return pExaPixmap->sys_ptr; 43} 44 45/** 46 * exaCreatePixmap() creates a new pixmap. 47 */ 48PixmapPtr 49exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, 50 unsigned usage_hint) 51{ 52 PixmapPtr pPixmap; 53 ExaPixmapPrivPtr pExaPixmap; 54 int bpp; 55 size_t paddedWidth; 56 57 ExaScreenPriv(pScreen); 58 59 if (w > 32767 || h > 32767) 60 return NullPixmap; 61 62 swap(pExaScr, pScreen, CreatePixmap); 63 pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint); 64 swap(pExaScr, pScreen, CreatePixmap); 65 66 if (!pPixmap) 67 return NULL; 68 69 pExaPixmap = ExaGetPixmapPriv(pPixmap); 70 pExaPixmap->driverPriv = NULL; 71 72 bpp = pPixmap->drawable.bitsPerPixel; 73 74 paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); 75 if (paddedWidth / 4 > 32767 || h > 32767) 76 return NullPixmap; 77 78 /* We will allocate the system pixmap later if needed. */ 79 pPixmap->devPrivate.ptr = NULL; 80 pExaPixmap->sys_ptr = NULL; 81 pExaPixmap->sys_pitch = paddedWidth; 82 83 pExaPixmap->area = NULL; 84 pExaPixmap->fb_ptr = NULL; 85 pExaPixmap->pDamage = NULL; 86 87 exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp); 88 exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp); 89 90 (*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL); 91 92 /* A scratch pixmap will become a driver pixmap right away. */ 93 if (!w || !h) { 94 exaCreateDriverPixmap_mixed(pPixmap); 95 pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap); 96 } 97 else { 98 pExaPixmap->use_gpu_copy = FALSE; 99 100 if (w == 1 && h == 1) { 101 pExaPixmap->sys_ptr = malloc(paddedWidth); 102 103 /* Set up damage tracking */ 104 pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, 105 DamageReportNonEmpty, TRUE, 106 pPixmap->drawable.pScreen, 107 pPixmap); 108 109 if (pExaPixmap->pDamage) { 110 DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); 111 /* This ensures that pending damage reflects the current 112 * operation. This is used by exa to optimize migration. 113 */ 114 DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); 115 } 116 } 117 } 118 119 /* During a fallback we must prepare access. */ 120 if (pExaScr->fallback_counter) 121 exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); 122 123 return pPixmap; 124} 125 126Bool 127exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, 128 int bitsPerPixel, int devKind, void *pPixData) 129{ 130 ScreenPtr pScreen; 131 ExaScreenPrivPtr pExaScr; 132 ExaPixmapPrivPtr pExaPixmap; 133 Bool ret, has_gpu_copy; 134 135 if (!pPixmap) 136 return FALSE; 137 138 pScreen = pPixmap->drawable.pScreen; 139 pExaScr = ExaGetScreenPriv(pScreen); 140 pExaPixmap = ExaGetPixmapPriv(pPixmap); 141 142 if (pPixData) { 143 if (pExaPixmap->driverPriv) { 144 if (pExaPixmap->pDamage) { 145 DamageDestroy(pExaPixmap->pDamage); 146 pExaPixmap->pDamage = NULL; 147 } 148 149 pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); 150 pExaPixmap->driverPriv = NULL; 151 } 152 153 pExaPixmap->use_gpu_copy = FALSE; 154 pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; 155 } 156 157 has_gpu_copy = exaPixmapHasGpuCopy(pPixmap); 158 159 if (width <= 0) 160 width = pPixmap->drawable.width; 161 162 if (height <= 0) 163 height = pPixmap->drawable.height; 164 165 if (bitsPerPixel <= 0) { 166 if (depth <= 0) 167 bitsPerPixel = pPixmap->drawable.bitsPerPixel; 168 else 169 bitsPerPixel = BitsPerPixel(depth); 170 } 171 172 if (depth <= 0) 173 depth = pPixmap->drawable.depth; 174 175 if (width != pPixmap->drawable.width || 176 height != pPixmap->drawable.height || 177 depth != pPixmap->drawable.depth || 178 bitsPerPixel != pPixmap->drawable.bitsPerPixel) { 179 if (pExaPixmap->driverPriv) { 180 if (devKind > 0) 181 pExaPixmap->fb_pitch = devKind; 182 else 183 exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel); 184 185 exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel); 186 RegionEmpty(&pExaPixmap->validFB); 187 } 188 189 /* Need to re-create system copy if there's also a GPU copy */ 190 if (has_gpu_copy) { 191 if (pExaPixmap->sys_ptr) { 192 free(pExaPixmap->sys_ptr); 193 pExaPixmap->sys_ptr = NULL; 194 DamageDestroy(pExaPixmap->pDamage); 195 pExaPixmap->pDamage = NULL; 196 RegionEmpty(&pExaPixmap->validSys); 197 198 if (pExaScr->deferred_mixed_pixmap == pPixmap) 199 pExaScr->deferred_mixed_pixmap = NULL; 200 } 201 202 pExaPixmap->sys_pitch = PixmapBytePad(width, depth); 203 } 204 } 205 206 if (has_gpu_copy) { 207 pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; 208 pPixmap->devKind = pExaPixmap->fb_pitch; 209 } 210 else { 211 pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; 212 pPixmap->devKind = pExaPixmap->sys_pitch; 213 } 214 215 /* Only pass driver pixmaps to the driver. */ 216 if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) { 217 ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth, 218 bitsPerPixel, devKind, 219 pPixData); 220 if (ret == TRUE) 221 goto out; 222 } 223 224 swap(pExaScr, pScreen, ModifyPixmapHeader); 225 ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth, 226 bitsPerPixel, devKind, pPixData); 227 swap(pExaScr, pScreen, ModifyPixmapHeader); 228 229 out: 230 if (has_gpu_copy) { 231 pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr; 232 pExaPixmap->fb_pitch = pPixmap->devKind; 233 } 234 else { 235 pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; 236 pExaPixmap->sys_pitch = pPixmap->devKind; 237 } 238 /* Always NULL this, we don't want lingering pointers. */ 239 pPixmap->devPrivate.ptr = NULL; 240 241 return ret; 242} 243 244Bool 245exaDestroyPixmap_mixed(PixmapPtr pPixmap) 246{ 247 ScreenPtr pScreen = pPixmap->drawable.pScreen; 248 249 ExaScreenPriv(pScreen); 250 Bool ret; 251 252 if (pPixmap->refcnt == 1) { 253 ExaPixmapPriv(pPixmap); 254 255 exaDestroyPixmap(pPixmap); 256 257 if (pExaScr->deferred_mixed_pixmap == pPixmap) 258 pExaScr->deferred_mixed_pixmap = NULL; 259 260 if (pExaPixmap->driverPriv) 261 pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); 262 pExaPixmap->driverPriv = NULL; 263 264 if (pExaPixmap->pDamage) { 265 free(pExaPixmap->sys_ptr); 266 pExaPixmap->sys_ptr = NULL; 267 pExaPixmap->pDamage = NULL; 268 } 269 } 270 271 swap(pExaScr, pScreen, DestroyPixmap); 272 ret = pScreen->DestroyPixmap(pPixmap); 273 swap(pExaScr, pScreen, DestroyPixmap); 274 275 return ret; 276} 277 278Bool 279exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap) 280{ 281 ScreenPtr pScreen = pPixmap->drawable.pScreen; 282 283 ExaScreenPriv(pScreen); 284 ExaPixmapPriv(pPixmap); 285 void *saved_ptr; 286 Bool ret; 287 288 if (!pExaPixmap->driverPriv) 289 return FALSE; 290 291 saved_ptr = pPixmap->devPrivate.ptr; 292 pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap); 293 ret = pExaScr->info->PixmapIsOffscreen(pPixmap); 294 pPixmap->devPrivate.ptr = saved_ptr; 295 296 return ret; 297} 298 299Bool 300exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p) 301{ 302 ScreenPtr pScreen = pPixmap->drawable.pScreen; 303 ExaScreenPriv(pScreen); 304 Bool ret = FALSE; 305 306 exaMoveInPixmap(pPixmap); 307 /* get the driver to give us a handle */ 308 if (pExaScr->info->SharePixmapBacking) 309 ret = pExaScr->info->SharePixmapBacking(pPixmap, secondary, handle_p); 310 311 return ret; 312} 313 314Bool 315exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle) 316{ 317 ScreenPtr pScreen = pPixmap->drawable.pScreen; 318 ExaScreenPriv(pScreen); 319 Bool ret = FALSE; 320 321 if (pExaScr->info->SetSharedPixmapBacking) 322 ret = pExaScr->info->SetSharedPixmapBacking(pPixmap, handle); 323 324 if (ret == TRUE) 325 exaMoveInPixmap(pPixmap); 326 327 return ret; 328} 329 330 331