nv50_miptree.c revision 32cd1a0345eaf1f4da8a60a4ac2145ff51383d59
1/* 2 * Copyright 2008 Ben Skeggs 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 shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#include "pipe/p_state.h" 24#include "pipe/p_defines.h" 25#include "pipe/p_inlines.h" 26 27#include "nv50_context.h" 28 29static struct pipe_texture * 30nv50_miptree_create(struct pipe_screen *pscreen, const struct pipe_texture *tmp) 31{ 32 struct pipe_winsys *ws = pscreen->winsys; 33 struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree); 34 struct pipe_texture *pt = &mt->base; 35 unsigned usage, width = tmp->width[0], height = tmp->height[0]; 36 unsigned depth = tmp->depth[0]; 37 int i, l; 38 39 mt->base = *tmp; 40 mt->base.refcount = 1; 41 mt->base.screen = pscreen; 42 43 usage = PIPE_BUFFER_USAGE_PIXEL; 44 switch (pt->format) { 45 case PIPE_FORMAT_Z24S8_UNORM: 46 case PIPE_FORMAT_Z16_UNORM: 47 usage |= NOUVEAU_BUFFER_USAGE_ZETA; 48 break; 49 default: 50 break; 51 } 52 53 switch (pt->target) { 54 case PIPE_TEXTURE_3D: 55 mt->image_nr = pt->depth[0]; 56 break; 57 case PIPE_TEXTURE_CUBE: 58 mt->image_nr = 6; 59 break; 60 default: 61 mt->image_nr = 1; 62 break; 63 } 64 65 for (l = 0; l <= pt->last_level; l++) { 66 struct nv50_miptree_level *lvl = &mt->level[l]; 67 68 pt->width[l] = width; 69 pt->height[l] = height; 70 pt->depth[l] = depth; 71 pt->nblocksx[l] = pf_get_nblocksx(&pt->block, width); 72 pt->nblocksy[l] = pf_get_nblocksy(&pt->block, height); 73 74 lvl->image_offset = CALLOC(mt->image_nr, sizeof(int)); 75 lvl->image = CALLOC(mt->image_nr, sizeof(struct pipe_buffer *)); 76 77 width = MAX2(1, width >> 1); 78 height = MAX2(1, height >> 1); 79 depth = MAX2(1, depth >> 1); 80 } 81 82 for (i = 0; i < mt->image_nr; i++) { 83 for (l = 0; l <= pt->last_level; l++) { 84 struct nv50_miptree_level *lvl = &mt->level[l]; 85 int size; 86 87 size = align(pt->width[l], 8) * pt->block.size; 88 size = align(size, 64); 89 size *= align(pt->height[l], 8) * pt->block.size; 90 91 lvl->image[i] = ws->buffer_create(ws, 256, 0, size); 92 lvl->image_offset[i] = mt->total_size; 93 94 mt->total_size += size; 95 } 96 } 97 98 mt->buffer = ws->buffer_create(ws, 256, usage, mt->total_size); 99 if (!mt->buffer) { 100 FREE(mt); 101 return NULL; 102 } 103 104 return &mt->base; 105} 106 107static struct pipe_texture * 108nv50_miptree_blanket(struct pipe_screen *pscreen, const struct pipe_texture *pt, 109 const unsigned *stride, struct pipe_buffer *pb) 110{ 111 struct nv50_miptree *mt; 112 113 /* Only supports 2D, non-mipmapped textures for the moment */ 114 if (pt->target != PIPE_TEXTURE_2D || pt->last_level != 0 || 115 pt->depth[0] != 1) 116 return NULL; 117 118 mt = CALLOC_STRUCT(nv50_miptree); 119 if (!mt) 120 return NULL; 121 122 mt->base = *pt; 123 mt->base.refcount = 1; 124 mt->base.screen = pscreen; 125 mt->image_nr = 1; 126 mt->level[0].image_offset = CALLOC(1, sizeof(unsigned)); 127 128 pipe_buffer_reference(pscreen, &mt->buffer, pb); 129 return &mt->base; 130} 131 132static INLINE void 133mark_dirty(uint32_t *flags, unsigned image) 134{ 135 flags[image / 32] |= (1 << (image % 32)); 136} 137 138static INLINE void 139mark_clean(uint32_t *flags, unsigned image) 140{ 141 flags[image / 32] &= ~(1 << (image % 32)); 142} 143 144static INLINE int 145is_dirty(uint32_t *flags, unsigned image) 146{ 147 return !!(flags[image / 32] & (1 << (image % 32))); 148} 149 150static void 151nv50_miptree_release(struct pipe_screen *pscreen, struct pipe_texture **ppt) 152{ 153 struct pipe_texture *pt = *ppt; 154 155 *ppt = NULL; 156 157 if (--pt->refcount <= 0) { 158 struct nv50_miptree *mt = nv50_miptree(pt); 159 160 pipe_buffer_reference(pscreen, &mt->buffer, NULL); 161 FREE(mt); 162 } 163} 164 165void 166nv50_miptree_sync(struct pipe_screen *pscreen, struct nv50_miptree *mt, 167 unsigned level, unsigned image) 168{ 169 struct nv50_screen *nvscreen = nv50_screen(pscreen); 170 struct nv50_miptree_level *lvl = &mt->level[level]; 171 struct pipe_surface *dst, *src; 172 unsigned face = 0, zslice = 0; 173 174 if (!is_dirty(lvl->image_dirty_cpu, image)) 175 return; 176 177 if (mt->base.target == PIPE_TEXTURE_CUBE) 178 face = image; 179 else 180 if (mt->base.target == PIPE_TEXTURE_3D) 181 zslice = image; 182 183 /* Mark as clean already - so we don't continually call this function 184 * trying to get a GPU_WRITE pipe_surface! 185 */ 186 mark_clean(lvl->image_dirty_cpu, image); 187 188 /* Pretend we're doing CPU access so we get the backing pipe_surface 189 * and not a view into the larger miptree. 190 */ 191 src = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice, 192 PIPE_BUFFER_USAGE_CPU_READ); 193 194 /* Pretend we're only reading with the GPU so surface doesn't get marked 195 * as dirtied by the GPU. 196 */ 197 dst = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice, 198 PIPE_BUFFER_USAGE_GPU_READ); 199 200 nv50_surface_do_copy(nvscreen, dst, 0, 0, src, 0, 0, dst->width, dst->height); 201 202 pscreen->tex_surface_release(pscreen, &dst); 203 pscreen->tex_surface_release(pscreen, &src); 204} 205 206/* The reverse of the above */ 207static void 208nv50_miptree_sync_cpu(struct pipe_screen *pscreen, struct nv50_miptree *mt, 209 unsigned level, unsigned image) 210{ 211 struct nv50_screen *nvscreen = nv50_screen(pscreen); 212 struct nv50_miptree_level *lvl = &mt->level[level]; 213 struct pipe_surface *dst, *src; 214 unsigned face = 0, zslice = 0; 215 216 if (!is_dirty(lvl->image_dirty_gpu, image)) 217 return; 218 219 if (mt->base.target == PIPE_TEXTURE_CUBE) 220 face = image; 221 else 222 if (mt->base.target == PIPE_TEXTURE_3D) 223 zslice = image; 224 225 mark_clean(lvl->image_dirty_gpu, image); 226 227 src = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice, 228 PIPE_BUFFER_USAGE_GPU_READ); 229 dst = pscreen->get_tex_surface(pscreen, &mt->base, face, level, zslice, 230 PIPE_BUFFER_USAGE_CPU_READ); 231 232 nv50_surface_do_copy(nvscreen, dst, 0, 0, src, 0, 0, dst->width, dst->height); 233 234 pscreen->tex_surface_release(pscreen, &dst); 235 pscreen->tex_surface_release(pscreen, &src); 236} 237 238static struct pipe_surface * 239nv50_miptree_surface_new(struct pipe_screen *pscreen, struct pipe_texture *pt, 240 unsigned face, unsigned level, unsigned zslice, 241 unsigned flags) 242{ 243 struct nv50_miptree *mt = nv50_miptree(pt); 244 struct nv50_miptree_level *lvl = &mt->level[level]; 245 struct pipe_surface *ps; 246 int img; 247 248 if (pt->target == PIPE_TEXTURE_CUBE) 249 img = face; 250 else 251 if (pt->target == PIPE_TEXTURE_3D) 252 img = zslice; 253 else 254 img = 0; 255 256 ps = CALLOC_STRUCT(pipe_surface); 257 if (!ps) 258 return NULL; 259 pipe_texture_reference(&ps->texture, pt); 260 ps->format = pt->format; 261 ps->width = pt->width[level]; 262 ps->height = pt->height[level]; 263 ps->block = pt->block; 264 ps->nblocksx = pt->nblocksx[level]; 265 ps->nblocksy = pt->nblocksy[level]; 266 ps->stride = ps->width * ps->block.size; 267 ps->usage = flags; 268 ps->status = PIPE_SURFACE_STATUS_DEFINED; 269 ps->refcount = 1; 270 ps->face = face; 271 ps->level = level; 272 ps->zslice = zslice; 273 274 if (flags & PIPE_BUFFER_USAGE_CPU_READ_WRITE) { 275 assert(!(flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE)); 276 nv50_miptree_sync_cpu(pscreen, mt, level, img); 277 278 ps->offset = 0; 279 pipe_texture_reference(&ps->texture, pt); 280 281 if (flags & PIPE_BUFFER_USAGE_CPU_WRITE) 282 mark_dirty(lvl->image_dirty_cpu, img); 283 } else { 284 nv50_miptree_sync(pscreen, mt, level, img); 285 286 ps->offset = lvl->image_offset[img]; 287 pipe_texture_reference(&ps->texture, pt); 288 289 if (flags & PIPE_BUFFER_USAGE_GPU_WRITE) 290 mark_dirty(lvl->image_dirty_gpu, img); 291 } 292 293 return ps; 294} 295 296static void 297nv50_miptree_surface_del(struct pipe_screen *pscreen, 298 struct pipe_surface **psurface) 299{ 300 struct pipe_surface *ps = *psurface; 301 struct nv50_surface *s = nv50_surface(ps); 302 303 *psurface = NULL; 304 305 if (--ps->refcount <= 0) { 306 pipe_texture_reference(&ps->texture, NULL); 307 FREE(s); 308 } 309} 310 311void 312nv50_screen_init_miptree_functions(struct pipe_screen *pscreen) 313{ 314 pscreen->texture_create = nv50_miptree_create; 315 pscreen->texture_blanket = nv50_miptree_blanket; 316 pscreen->texture_release = nv50_miptree_release; 317 pscreen->get_tex_surface = nv50_miptree_surface_new; 318 pscreen->tex_surface_release = nv50_miptree_surface_del; 319} 320 321