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 "util/u_inlines.h" 26#include "util/u_format.h" 27 28#include "nvc0_context.h" 29#include "nvc0_resource.h" 30 31uint32_t 32nvc0_tex_choose_tile_dims(unsigned nx, unsigned ny, unsigned nz) 33{ 34 uint32_t tile_mode = 0x000; 35 36 if (ny > 64) tile_mode = 0x040; /* height 128 tiles */ 37 else 38 if (ny > 32) tile_mode = 0x030; /* height 64 tiles */ 39 else 40 if (ny > 16) tile_mode = 0x020; /* height 32 tiles */ 41 else 42 if (ny > 8) tile_mode = 0x010; /* height 16 tiles */ 43 44 if (nz == 1) 45 return tile_mode; 46 else 47 if (tile_mode > 0x020) 48 tile_mode = 0x020; 49 50 if (nz > 16 && tile_mode < 0x020) 51 return tile_mode | 0x500; /* depth 32 tiles */ 52 if (nz > 8) return tile_mode | 0x400; /* depth 16 tiles */ 53 if (nz > 4) return tile_mode | 0x300; /* depth 8 tiles */ 54 if (nz > 2) return tile_mode | 0x200; /* depth 4 tiles */ 55 56 return tile_mode | 0x100; 57} 58 59static uint32_t 60nvc0_mt_choose_storage_type(struct nv50_miptree *mt, boolean compressed) 61{ 62 const unsigned ms = util_logbase2(mt->base.base.nr_samples); 63 64 uint32_t tile_flags; 65 66 compressed = FALSE; /* not yet supported */ 67 68 if (unlikely(mt->base.base.bind & PIPE_BIND_CURSOR)) 69 return 0; 70 if (unlikely(mt->base.base.flags & NOUVEAU_RESOURCE_FLAG_LINEAR)) 71 return 0; 72 73 switch (mt->base.base.format) { 74 case PIPE_FORMAT_Z16_UNORM: 75 if (compressed) 76 tile_flags = 0x02 + ms; 77 else 78 tile_flags = 0x01; 79 break; 80 case PIPE_FORMAT_S8_UINT_Z24_UNORM: 81 if (compressed) 82 tile_flags = 0x51 + ms; 83 else 84 tile_flags = 0x46; 85 break; 86 case PIPE_FORMAT_Z24X8_UNORM: 87 case PIPE_FORMAT_Z24_UNORM_S8_UINT: 88 if (compressed) 89 tile_flags = 0x17 + ms; 90 else 91 tile_flags = 0x11; 92 break; 93 case PIPE_FORMAT_Z32_FLOAT: 94 if (compressed) 95 tile_flags = 0x86 + ms; 96 else 97 tile_flags = 0x7b; 98 break; 99 case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: 100 if (compressed) 101 tile_flags = 0xce + ms; 102 else 103 tile_flags = 0xc3; 104 break; 105 default: 106 switch (util_format_get_blocksizebits(mt->base.base.format)) { 107 case 128: 108 if (compressed) 109 tile_flags = 0xf4 + ms; 110 else 111 tile_flags = 0xfe; 112 break; 113 case 64: 114 if (compressed) { 115 switch (ms) { 116 case 0: tile_flags = 0xe6; break; 117 case 1: tile_flags = 0xeb; break; 118 case 2: tile_flags = 0xed; break; 119 case 3: tile_flags = 0xf2; break; 120 default: 121 return 0; 122 } 123 } else { 124 tile_flags = 0xfe; 125 } 126 break; 127 case 32: 128 if (compressed) { 129 switch (ms) { 130 case 0: tile_flags = 0xdb; break; 131 case 1: tile_flags = 0xdd; break; 132 case 2: tile_flags = 0xdf; break; 133 case 3: tile_flags = 0xe4; break; 134 default: 135 return 0; 136 } 137 } else { 138 tile_flags = 0xfe; 139 } 140 break; 141 case 16: 142 case 8: 143 tile_flags = 0xfe; 144 break; 145 default: 146 return 0; 147 } 148 break; 149 } 150 151 return tile_flags; 152} 153 154static INLINE boolean 155nvc0_miptree_init_ms_mode(struct nv50_miptree *mt) 156{ 157 switch (mt->base.base.nr_samples) { 158 case 8: 159 mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS8; 160 mt->ms_x = 2; 161 mt->ms_y = 1; 162 break; 163 case 4: 164 mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS4; 165 mt->ms_x = 1; 166 mt->ms_y = 1; 167 break; 168 case 2: 169 mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS2; 170 mt->ms_x = 1; 171 break; 172 case 1: 173 case 0: 174 mt->ms_mode = NVC0_3D_MULTISAMPLE_MODE_MS1; 175 break; 176 default: 177 NOUVEAU_ERR("invalid nr_samples: %u\n", mt->base.base.nr_samples); 178 return FALSE; 179 } 180 return TRUE; 181} 182 183boolean 184nv50_miptree_init_layout_linear(struct nv50_miptree *); 185 186static void 187nvc0_miptree_init_layout_video(struct nv50_miptree *mt) 188{ 189 const struct pipe_resource *pt = &mt->base.base; 190 const unsigned blocksize = util_format_get_blocksize(pt->format); 191 192 unsigned nbx = util_format_get_nblocksx(pt->format, pt->width0); 193 unsigned nby = util_format_get_nblocksy(pt->format, pt->height0); 194 195 assert(pt->last_level == 0); 196 assert(mt->ms_x == 0 && 197 mt->ms_y == 0); 198 assert(!util_format_is_compressed(pt->format)); 199 200 assert(nby > 8); 201 mt->level[0].tile_mode = 0x10; 202 mt->level[0].pitch = align(nbx * blocksize, 64); 203 mt->total_size = align(nby, 16) * mt->level[0].pitch; 204 205 if (pt->array_size > 1) { 206 mt->layer_stride = align(mt->total_size, NVC0_TILE_SIZE(0x10)); 207 mt->total_size = mt->layer_stride * pt->array_size; 208 } 209} 210 211static void 212nvc0_miptree_init_layout_tiled(struct nv50_miptree *mt) 213{ 214 struct pipe_resource *pt = &mt->base.base; 215 unsigned w, h, d, l; 216 const unsigned blocksize = util_format_get_blocksize(pt->format); 217 218 mt->layout_3d = pt->target == PIPE_TEXTURE_3D; 219 220 w = pt->width0 << mt->ms_x; 221 h = pt->height0 << mt->ms_y; 222 223 /* For 3D textures, a mipmap is spanned by all the layers, for array 224 * textures and cube maps, each layer contains its own mipmaps. 225 */ 226 d = mt->layout_3d ? pt->depth0 : 1; 227 228 for (l = 0; l <= pt->last_level; ++l) { 229 struct nv50_miptree_level *lvl = &mt->level[l]; 230 unsigned tsx, tsy, tsz; 231 unsigned nbx = util_format_get_nblocksx(pt->format, w); 232 unsigned nby = util_format_get_nblocksy(pt->format, h); 233 234 lvl->offset = mt->total_size; 235 236 lvl->tile_mode = nvc0_tex_choose_tile_dims(nbx, nby, d); 237 238 tsx = NVC0_TILE_SIZE_X(lvl->tile_mode); /* x is tile row pitch in bytes */ 239 tsy = NVC0_TILE_SIZE_Y(lvl->tile_mode); 240 tsz = NVC0_TILE_SIZE_Z(lvl->tile_mode); 241 242 lvl->pitch = align(nbx * blocksize, tsx); 243 244 mt->total_size += lvl->pitch * align(nby, tsy) * align(d, tsz); 245 246 w = u_minify(w, 1); 247 h = u_minify(h, 1); 248 d = u_minify(d, 1); 249 } 250 251 if (pt->array_size > 1) { 252 mt->layer_stride = align(mt->total_size, 253 NVC0_TILE_SIZE(mt->level[0].tile_mode)); 254 mt->total_size = mt->layer_stride * pt->array_size; 255 } 256} 257 258const struct u_resource_vtbl nvc0_miptree_vtbl = 259{ 260 nv50_miptree_get_handle, /* get_handle */ 261 nv50_miptree_destroy, /* resource_destroy */ 262 nvc0_miptree_transfer_new, /* get_transfer */ 263 nvc0_miptree_transfer_del, /* transfer_destroy */ 264 nvc0_miptree_transfer_map, /* transfer_map */ 265 u_default_transfer_flush_region, /* transfer_flush_region */ 266 nvc0_miptree_transfer_unmap, /* transfer_unmap */ 267 u_default_transfer_inline_write /* transfer_inline_write */ 268}; 269 270struct pipe_resource * 271nvc0_miptree_create(struct pipe_screen *pscreen, 272 const struct pipe_resource *templ) 273{ 274 struct nouveau_device *dev = nouveau_screen(pscreen)->device; 275 struct nv50_miptree *mt = CALLOC_STRUCT(nv50_miptree); 276 struct pipe_resource *pt = &mt->base.base; 277 int ret; 278 union nouveau_bo_config bo_config; 279 uint32_t bo_flags; 280 281 if (!mt) 282 return NULL; 283 284 mt->base.vtbl = &nvc0_miptree_vtbl; 285 *pt = *templ; 286 pipe_reference_init(&pt->reference, 1); 287 pt->screen = pscreen; 288 289 bo_config.nvc0.memtype = nvc0_mt_choose_storage_type(mt, TRUE); 290 291 if (!nvc0_miptree_init_ms_mode(mt)) { 292 FREE(mt); 293 return NULL; 294 } 295 296 if (unlikely(pt->flags & NVC0_RESOURCE_FLAG_VIDEO)) { 297 nvc0_miptree_init_layout_video(mt); 298 } else 299 if (likely(bo_config.nvc0.memtype)) { 300 nvc0_miptree_init_layout_tiled(mt); 301 } else 302 if (!nv50_miptree_init_layout_linear(mt)) { 303 FREE(mt); 304 return NULL; 305 } 306 bo_config.nvc0.tile_mode = mt->level[0].tile_mode; 307 308 mt->base.domain = NOUVEAU_BO_VRAM; 309 310 bo_flags = mt->base.domain | NOUVEAU_BO_NOSNOOP; 311 312 if (mt->base.base.bind & (PIPE_BIND_CURSOR | PIPE_BIND_DISPLAY_TARGET)) 313 bo_flags |= NOUVEAU_BO_CONTIG; 314 315 ret = nouveau_bo_new(dev, bo_flags, 4096, mt->total_size, &bo_config, 316 &mt->base.bo); 317 if (ret) { 318 FREE(mt); 319 return NULL; 320 } 321 mt->base.address = mt->base.bo->offset; 322 323 return pt; 324} 325 326/* Offset of zslice @z from start of level @l. */ 327INLINE unsigned 328nvc0_mt_zslice_offset(const struct nv50_miptree *mt, unsigned l, unsigned z) 329{ 330 const struct pipe_resource *pt = &mt->base.base; 331 332 unsigned tds = NVC0_TILE_SHIFT_Z(mt->level[l].tile_mode); 333 unsigned ths = NVC0_TILE_SHIFT_Y(mt->level[l].tile_mode); 334 335 unsigned nby = util_format_get_nblocksy(pt->format, 336 u_minify(pt->height0, l)); 337 338 /* to next 2D tile slice within a 3D tile */ 339 unsigned stride_2d = NVC0_TILE_SIZE_2D(mt->level[l].tile_mode); 340 341 /* to slice in the next (in z direction) 3D tile */ 342 unsigned stride_3d = (align(nby, (1 << ths)) * mt->level[l].pitch) << tds; 343 344 return (z & (1 << (tds - 1))) * stride_2d + (z >> tds) * stride_3d; 345} 346 347/* Surface functions. 348 */ 349 350struct pipe_surface * 351nvc0_miptree_surface_new(struct pipe_context *pipe, 352 struct pipe_resource *pt, 353 const struct pipe_surface *templ) 354{ 355 struct nv50_surface *ns = nv50_surface_from_miptree(nv50_miptree(pt), templ); 356 if (!ns) 357 return NULL; 358 ns->base.context = pipe; 359 return &ns->base; 360} 361