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