1 /* 2 * Copyright 2009 Red Hat, Inc. 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 /* Authors: 25 * Ben Skeggs <bskeggs (at) redhat.com> 26 */ 27 28 #include "nv_include.h" 29 30 struct wfb_pixmap { 31 PixmapPtr ppix; 32 unsigned long base; 33 unsigned long end; 34 unsigned pitch; 35 unsigned tile_height; 36 unsigned horiz_tiles; 37 uint64_t multiply_factor; 38 }; 39 40 static struct wfb_pixmap wfb_pixmap[6]; 41 42 static inline FbBits 43 nouveau_wfb_rd_linear(const void *src, int size) 44 { 45 FbBits bits = 0; 46 47 memcpy(&bits, src, size); 48 return bits; 49 } 50 51 static inline void 52 nouveau_wfb_wr_linear(void *dst, FbBits value, int size) 53 { 54 memcpy(dst, &value, size); 55 } 56 57 #define TP 6 58 #define TH wfb->tile_height 59 #define TPM ((1 << TP) - 1) 60 #define THM ((1 << TH) - 1) 61 62 static FbBits 63 nouveau_wfb_rd_tiled(const void *ptr, int size) { 64 unsigned long offset = (unsigned long)ptr; 65 struct wfb_pixmap *wfb = NULL; 66 FbBits bits = 0; 67 int x, y, i; 68 69 for (i = 0; i < 6; i++) { 70 if (offset >= wfb_pixmap[i].base && 71 offset < wfb_pixmap[i].end) { 72 wfb = &wfb_pixmap[i]; 73 break; 74 } 75 } 76 77 if (!wfb || !wfb->pitch) 78 return nouveau_wfb_rd_linear(ptr, size); 79 80 offset -= wfb->base; 81 82 y = (offset * wfb->multiply_factor) >> 36; 83 x = offset - y * wfb->pitch; 84 85 offset = (x >> TP) + ((y >> TH) * wfb->horiz_tiles); 86 offset *= (1 << (TH + TP)); 87 offset += ((y & THM) * (1 << TP)) + (x & TPM); 88 89 memcpy(&bits, (void *)wfb->base + offset, size); 90 return bits; 91 } 92 93 static void 94 nouveau_wfb_wr_tiled(void *ptr, FbBits value, int size) { 95 unsigned long offset = (unsigned long)ptr; 96 struct wfb_pixmap *wfb = NULL; 97 int x, y, i; 98 99 for (i = 0; i < 6; i++) { 100 if (offset >= wfb_pixmap[i].base && 101 offset < wfb_pixmap[i].end) { 102 wfb = &wfb_pixmap[i]; 103 break; 104 } 105 } 106 107 if (!wfb || !wfb->pitch) { 108 nouveau_wfb_wr_linear(ptr, value, size); 109 return; 110 } 111 112 offset -= wfb->base; 113 114 y = (offset * wfb->multiply_factor) >> 36; 115 x = offset - y * wfb->pitch; 116 117 offset = (x >> TP) + ((y >> TH) * wfb->horiz_tiles); 118 offset *= (1 << (TH + TP)); 119 offset += ((y & THM) * (1 << TP)) + (x & TPM); 120 121 memcpy((void *)wfb->base + offset, &value, size); 122 } 123 124 void 125 nouveau_wfb_setup_wrap(ReadMemoryProcPtr *pRead, WriteMemoryProcPtr *pWrite, 126 DrawablePtr pDraw) 127 { 128 struct nouveau_bo *bo = NULL; 129 struct wfb_pixmap *wfb; 130 PixmapPtr ppix = NULL; 131 int i, j, have_tiled = 0; 132 133 if (!pRead || !pWrite) 134 return; 135 136 ppix = NVGetDrawablePixmap(pDraw); 137 if (ppix) { 138 struct nouveau_pixmap *priv = nouveau_pixmap(ppix); 139 bo = priv ? priv->bo : NULL; 140 } 141 142 if (!ppix || !bo) { 143 for (i = 0; i < 6; i++) 144 if (wfb_pixmap[i].ppix && wfb_pixmap[i].pitch) 145 have_tiled = 1; 146 147 if (have_tiled) { 148 *pRead = nouveau_wfb_rd_tiled; 149 *pWrite = nouveau_wfb_wr_tiled; 150 } else { 151 *pRead = nouveau_wfb_rd_linear; 152 *pWrite = nouveau_wfb_wr_linear; 153 } 154 return; 155 } 156 157 j = -1; 158 for (i = 0; i < 6; i++) { 159 if (!wfb_pixmap[i].ppix && j < 0) 160 j = i; 161 162 if (wfb_pixmap[i].ppix && wfb_pixmap[i].pitch) 163 have_tiled = 1; 164 } 165 166 if (j == -1) { 167 ErrorF("We ran out of wfb indices, this is not good.\n"); 168 goto out; 169 } 170 171 wfb = &wfb_pixmap[j]; 172 173 wfb->ppix = ppix; 174 wfb->base = (unsigned long)ppix->devPrivate.ptr; 175 wfb->end = wfb->base + bo->size; 176 if (!nv50_style_tiled_pixmap(ppix)) { 177 wfb->pitch = 0; 178 } else { 179 wfb->pitch = ppix->devKind; 180 /* 8192x8192x4 is 28 bits max, 64 - 28 == 36. */ 181 wfb->multiply_factor = (((1ULL << 36) - 1) / wfb->pitch) + 1; 182 if (bo->device->chipset < 0xc0) 183 wfb->tile_height = (bo->config.nv50.tile_mode >> 4) + 2; 184 else 185 wfb->tile_height = (bo->config.nv50.tile_mode >> 4) + 3; 186 wfb->horiz_tiles = wfb->pitch / 64; 187 have_tiled = 1; 188 } 189 190 out: 191 if (have_tiled) { 192 *pRead = nouveau_wfb_rd_tiled; 193 *pWrite = nouveau_wfb_wr_tiled; 194 } else { 195 *pRead = nouveau_wfb_rd_linear; 196 *pWrite = nouveau_wfb_wr_linear; 197 } 198 } 199 200 void 201 nouveau_wfb_finish_wrap(DrawablePtr pDraw) 202 { 203 PixmapPtr ppix; 204 int i; 205 206 ppix = NVGetDrawablePixmap(pDraw); 207 if (!ppix) 208 return; 209 210 for (i = 0; i < 6; i++) { 211 if (wfb_pixmap[i].ppix == ppix) { 212 wfb_pixmap[i].ppix = NULL; 213 wfb_pixmap[i].base = ~0UL; 214 break; 215 } 216 } 217 } 218 219