Home | History | Annotate | Line # | Download | only in src
      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