1 /* 2 * Copyright 2012 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 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 * Authors: Ben Skeggs 23 * 24 */ 25 26 #include "util/u_format.h" 27 #include "util/u_inlines.h" 28 #include "util/u_surface.h" 29 30 #include "nouveau/nv_m2mf.xml.h" 31 #include "nv30_screen.h" 32 #include "nv30_context.h" 33 #include "nv30_resource.h" 34 #include "nv30_transfer.h" 35 36 static INLINE unsigned 37 layer_offset(struct pipe_resource *pt, unsigned level, unsigned layer) 38 { 39 struct nv30_miptree *mt = nv30_miptree(pt); 40 struct nv30_miptree_level *lvl = &mt->level[level]; 41 42 if (pt->target == PIPE_TEXTURE_CUBE) 43 return (layer * mt->layer_size) + lvl->offset; 44 45 return lvl->offset + (layer * lvl->zslice_size); 46 } 47 48 static boolean 49 nv30_miptree_get_handle(struct pipe_screen *pscreen, 50 struct pipe_resource *pt, 51 struct winsys_handle *handle) 52 { 53 struct nv30_miptree *mt = nv30_miptree(pt); 54 unsigned stride; 55 56 if (!mt || !mt->base.bo) 57 return FALSE; 58 59 stride = mt->level[0].pitch; 60 61 return nouveau_screen_bo_get_handle(pscreen, mt->base.bo, stride, handle); 62 } 63 64 static void 65 nv30_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt) 66 { 67 struct nv30_miptree *mt = nv30_miptree(pt); 68 69 nouveau_bo_ref(NULL, &mt->base.bo); 70 FREE(mt); 71 } 72 73 struct nv30_transfer { 74 struct pipe_transfer base; 75 struct nv30_rect img; 76 struct nv30_rect tmp; 77 unsigned nblocksx; 78 unsigned nblocksy; 79 }; 80 81 static INLINE struct nv30_transfer * 82 nv30_transfer(struct pipe_transfer *ptx) 83 { 84 return (struct nv30_transfer *)ptx; 85 } 86 87 static INLINE void 88 define_rect(struct pipe_resource *pt, unsigned level, unsigned z, 89 unsigned x, unsigned y, unsigned w, unsigned h, 90 struct nv30_rect *rect) 91 { 92 struct nv30_miptree *mt = nv30_miptree(pt); 93 struct nv30_miptree_level *lvl = &mt->level[level]; 94 95 rect->w = u_minify(pt->width0, level) << mt->ms_x; 96 rect->w = util_format_get_nblocksx(pt->format, rect->w); 97 rect->h = u_minify(pt->height0, level) << mt->ms_y; 98 rect->h = util_format_get_nblocksy(pt->format, rect->h); 99 rect->d = 1; 100 rect->z = 0; 101 if (mt->swizzled) { 102 if (pt->target == PIPE_TEXTURE_3D) { 103 rect->d = u_minify(pt->depth0, level); 104 rect->z = z; z = 0; 105 } 106 rect->pitch = 0; 107 } else { 108 rect->pitch = lvl->pitch; 109 } 110 111 rect->bo = mt->base.bo; 112 rect->domain = NOUVEAU_BO_VRAM; 113 rect->offset = layer_offset(pt, level, z); 114 rect->cpp = util_format_get_blocksize(pt->format); 115 116 rect->x0 = util_format_get_nblocksx(pt->format, x) << mt->ms_x; 117 rect->y0 = util_format_get_nblocksy(pt->format, y) << mt->ms_y; 118 rect->x1 = rect->x0 + (w << mt->ms_x); 119 rect->y1 = rect->y0 + (h << mt->ms_y); 120 } 121 122 void 123 nv30_resource_copy_region(struct pipe_context *pipe, 124 struct pipe_resource *dstres, unsigned dst_level, 125 unsigned dstx, unsigned dsty, unsigned dstz, 126 struct pipe_resource *srcres, unsigned src_level, 127 const struct pipe_box *src_box) 128 { 129 struct nv30_context *nv30 = nv30_context(pipe); 130 struct nv30_rect src, dst; 131 132 if (dstres->target == PIPE_BUFFER && srcres->target == PIPE_BUFFER) { 133 util_resource_copy_region(pipe, dstres, dst_level, dstx, dsty, dstz, 134 srcres, src_level, src_box); 135 return; 136 } 137 138 define_rect(srcres, src_level, src_box->z, src_box->x, src_box->y, 139 src_box->width, src_box->height, &src); 140 define_rect(dstres, dst_level, dstz, dstx, dsty, 141 src_box->width, src_box->height, &dst); 142 143 nv30_transfer_rect(nv30, NEAREST, &src, &dst); 144 } 145 146 void 147 nv30_resource_resolve(struct pipe_context *pipe, 148 const struct pipe_resolve_info *info) 149 { 150 struct nv30_context *nv30 = nv30_context(pipe); 151 struct nv30_rect src, dst; 152 153 define_rect(info->src.res, 0, 0, info->src.x0, info->src.y0, 154 info->src.x1 - info->src.x0, info->src.y1 - info->src.y0, &src); 155 define_rect(info->dst.res, info->dst.level, 0, info->dst.x0, info->dst.y0, 156 info->dst.x1 - info->dst.x0, info->dst.y1 - info->dst.y0, &dst); 157 158 nv30_transfer_rect(nv30, BILINEAR, &src, &dst); 159 } 160 161 static struct pipe_transfer * 162 nv30_miptree_transfer_new(struct pipe_context *pipe, struct pipe_resource *pt, 163 unsigned level, unsigned usage, 164 const struct pipe_box *box) 165 { 166 struct nv30_context *nv30 = nv30_context(pipe); 167 struct nouveau_device *dev = nv30->screen->base.device; 168 struct nv30_transfer *tx; 169 int ret; 170 171 tx = CALLOC_STRUCT(nv30_transfer); 172 if (!tx) 173 return NULL; 174 pipe_resource_reference(&tx->base.resource, pt); 175 tx->base.level = level; 176 tx->base.usage = usage; 177 tx->base.box = *box; 178 tx->base.stride = util_format_get_nblocksx(pt->format, box->width) * 179 util_format_get_blocksize(pt->format); 180 tx->base.layer_stride = util_format_get_nblocksy(pt->format, box->height) * 181 tx->base.stride; 182 183 tx->nblocksx = util_format_get_nblocksx(pt->format, box->width); 184 tx->nblocksy = util_format_get_nblocksy(pt->format, box->height); 185 186 define_rect(pt, level, box->z, box->x, box->y, 187 tx->nblocksx, tx->nblocksy, &tx->img); 188 189 ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 190 tx->base.layer_stride, NULL, &tx->tmp.bo); 191 if (ret) { 192 pipe_resource_reference(&tx->base.resource, NULL); 193 FREE(tx); 194 return NULL; 195 } 196 197 tx->tmp.domain = NOUVEAU_BO_GART; 198 tx->tmp.offset = 0; 199 tx->tmp.pitch = tx->base.stride; 200 tx->tmp.cpp = tx->img.cpp; 201 tx->tmp.w = tx->nblocksx; 202 tx->tmp.h = tx->nblocksy; 203 tx->tmp.d = 1; 204 tx->tmp.x0 = 0; 205 tx->tmp.y0 = 0; 206 tx->tmp.x1 = tx->tmp.w; 207 tx->tmp.y1 = tx->tmp.h; 208 tx->tmp.z = 0; 209 210 if (usage & PIPE_TRANSFER_READ) 211 nv30_transfer_rect(nv30, NEAREST, &tx->img, &tx->tmp); 212 213 return &tx->base; 214 } 215 216 static void 217 nv30_miptree_transfer_del(struct pipe_context *pipe, struct pipe_transfer *ptx) 218 { 219 struct nv30_context *nv30 = nv30_context(pipe); 220 struct nv30_transfer *tx = nv30_transfer(ptx); 221 222 if (ptx->usage & PIPE_TRANSFER_WRITE) 223 nv30_transfer_rect(nv30, NEAREST, &tx->tmp, &tx->img); 224 225 nouveau_bo_ref(NULL, &tx->tmp.bo); 226 pipe_resource_reference(&ptx->resource, NULL); 227 FREE(tx); 228 } 229 230 static void * 231 nv30_miptree_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx) 232 { 233 struct nv30_context *nv30 = nv30_context(pipe); 234 struct nv30_transfer *tx = nv30_transfer(ptx); 235 unsigned access = 0; 236 int ret; 237 238 if (tx->tmp.bo->map) 239 return tx->tmp.bo->map; 240 241 if (ptx->usage & PIPE_TRANSFER_READ) 242 access |= NOUVEAU_BO_RD; 243 if (ptx->usage & PIPE_TRANSFER_WRITE) 244 access |= NOUVEAU_BO_WR; 245 246 ret = nouveau_bo_map(tx->tmp.bo, access, nv30->base.client); 247 if (ret) 248 return NULL; 249 return tx->tmp.bo->map; 250 } 251 252 static void 253 nv30_miptree_transfer_unmap(struct pipe_context *pipe, 254 struct pipe_transfer *ptx) 255 { 256 } 257 258 const struct u_resource_vtbl nv30_miptree_vtbl = { 259 nv30_miptree_get_handle, 260 nv30_miptree_destroy, 261 nv30_miptree_transfer_new, 262 nv30_miptree_transfer_del, 263 nv30_miptree_transfer_map, 264 u_default_transfer_flush_region, 265 nv30_miptree_transfer_unmap, 266 u_default_transfer_inline_write 267 }; 268 269 struct pipe_resource * 270 nv30_miptree_create(struct pipe_screen *pscreen, 271 const struct pipe_resource *tmpl) 272 { 273 struct nouveau_device *dev = nouveau_screen(pscreen)->device; 274 struct nv30_miptree *mt = CALLOC_STRUCT(nv30_miptree); 275 struct pipe_resource *pt = &mt->base.base; 276 unsigned blocksz, size; 277 unsigned w, h, d, l; 278 int ret; 279 280 switch (tmpl->nr_samples) { 281 case 4: 282 mt->ms_mode = 0x00004000; 283 mt->ms_x = 1; 284 mt->ms_y = 1; 285 break; 286 case 2: 287 mt->ms_mode = 0x00003000; 288 mt->ms_x = 1; 289 mt->ms_y = 0; 290 break; 291 default: 292 mt->ms_mode = 0x00000000; 293 mt->ms_x = 0; 294 mt->ms_y = 0; 295 break; 296 } 297 298 mt->base.vtbl = &nv30_miptree_vtbl; 299 *pt = *tmpl; 300 pipe_reference_init(&pt->reference, 1); 301 pt->screen = pscreen; 302 303 w = pt->width0 << mt->ms_x; 304 h = pt->height0 << mt->ms_y; 305 d = (pt->target == PIPE_TEXTURE_3D) ? pt->depth0 : 1; 306 blocksz = util_format_get_blocksize(pt->format); 307 308 if ((pt->target == PIPE_TEXTURE_RECT) || 309 !util_is_power_of_two(pt->width0) || 310 !util_is_power_of_two(pt->height0) || 311 !util_is_power_of_two(pt->depth0) || 312 util_format_is_compressed(pt->format) || 313 util_format_is_float(pt->format) || mt->ms_mode) { 314 mt->uniform_pitch = util_format_get_nblocksx(pt->format, w) * blocksz; 315 mt->uniform_pitch = align(mt->uniform_pitch, 64); 316 } 317 318 if (!mt->uniform_pitch) 319 mt->swizzled = TRUE; 320 321 size = 0; 322 for (l = 0; l <= pt->last_level; l++) { 323 struct nv30_miptree_level *lvl = &mt->level[l]; 324 unsigned nbx = util_format_get_nblocksx(pt->format, w); 325 unsigned nby = util_format_get_nblocksx(pt->format, h); 326 327 lvl->offset = size; 328 lvl->pitch = mt->uniform_pitch; 329 if (!lvl->pitch) 330 lvl->pitch = nbx * blocksz; 331 332 lvl->zslice_size = lvl->pitch * nby; 333 size += lvl->zslice_size * d; 334 335 w = u_minify(w, 1); 336 h = u_minify(h, 1); 337 d = u_minify(d, 1); 338 } 339 340 mt->layer_size = size; 341 if (pt->target == PIPE_TEXTURE_CUBE) { 342 if (!mt->uniform_pitch) 343 mt->layer_size = align(mt->layer_size, 128); 344 size = mt->layer_size * 6; 345 } 346 347 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 256, size, NULL, &mt->base.bo); 348 if (ret) { 349 FREE(mt); 350 return NULL; 351 } 352 353 mt->base.domain = NOUVEAU_BO_VRAM; 354 return &mt->base.base; 355 } 356 357 struct pipe_resource * 358 nv30_miptree_from_handle(struct pipe_screen *pscreen, 359 const struct pipe_resource *tmpl, 360 struct winsys_handle *handle) 361 { 362 struct nv30_miptree *mt; 363 unsigned stride; 364 365 /* only supports 2D, non-mipmapped textures for the moment */ 366 if ((tmpl->target != PIPE_TEXTURE_2D && 367 tmpl->target != PIPE_TEXTURE_RECT) || 368 tmpl->last_level != 0 || 369 tmpl->depth0 != 1 || 370 tmpl->array_size > 1) 371 return NULL; 372 373 mt = CALLOC_STRUCT(nv30_miptree); 374 if (!mt) 375 return NULL; 376 377 mt->base.bo = nouveau_screen_bo_from_handle(pscreen, handle, &stride); 378 if (mt->base.bo == NULL) { 379 FREE(mt); 380 return NULL; 381 } 382 383 mt->base.base = *tmpl; 384 mt->base.vtbl = &nv30_miptree_vtbl; 385 pipe_reference_init(&mt->base.base.reference, 1); 386 mt->base.base.screen = pscreen; 387 mt->uniform_pitch = stride; 388 mt->level[0].pitch = mt->uniform_pitch; 389 mt->level[0].offset = 0; 390 391 /* no need to adjust bo reference count */ 392 return &mt->base.base; 393 } 394 395 struct pipe_surface * 396 nv30_miptree_surface_new(struct pipe_context *pipe, 397 struct pipe_resource *pt, 398 const struct pipe_surface *tmpl) 399 { 400 struct nv30_miptree *mt = nv30_miptree(pt); /* guaranteed */ 401 struct nv30_surface *ns; 402 struct pipe_surface *ps; 403 struct nv30_miptree_level *lvl = &mt->level[tmpl->u.tex.level]; 404 405 ns = CALLOC_STRUCT(nv30_surface); 406 if (!ns) 407 return NULL; 408 ps = &ns->base; 409 410 pipe_reference_init(&ps->reference, 1); 411 pipe_resource_reference(&ps->texture, pt); 412 ps->context = pipe; 413 ps->format = tmpl->format; 414 ps->usage = tmpl->usage; 415 ps->u.tex.level = tmpl->u.tex.level; 416 ps->u.tex.first_layer = tmpl->u.tex.first_layer; 417 ps->u.tex.last_layer = tmpl->u.tex.last_layer; 418 419 ns->width = u_minify(pt->width0, ps->u.tex.level); 420 ns->height = u_minify(pt->height0, ps->u.tex.level); 421 ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1; 422 ns->offset = layer_offset(pt, ps->u.tex.level, ps->u.tex.first_layer); 423 if (mt->swizzled) 424 ns->pitch = 4096; /* random, just something the hw won't reject.. */ 425 else 426 ns->pitch = lvl->pitch; 427 428 /* comment says there are going to be removed, but they're used by the st */ 429 ps->width = ns->width; 430 ps->height = ns->height; 431 return ps; 432 } 433 434 void 435 nv30_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps) 436 { 437 struct nv30_surface *ns = nv30_surface(ps); 438 439 pipe_resource_reference(&ps->texture, NULL); 440 FREE(ns); 441 } 442