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 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 * 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 "nv_m2mf.xml.h" 31 #include "nv_object.xml.h" 32 #include "nv30/nv30_screen.h" 33 #include "nv30/nv30_context.h" 34 #include "nv30/nv30_resource.h" 35 #include "nv30/nv30_transfer.h" 36 37 static inline unsigned 38 layer_offset(struct pipe_resource *pt, unsigned level, unsigned layer) 39 { 40 struct nv30_miptree *mt = nv30_miptree(pt); 41 struct nv30_miptree_level *lvl = &mt->level[level]; 42 43 if (pt->target == PIPE_TEXTURE_CUBE) 44 return (layer * mt->layer_size) + lvl->offset; 45 46 return lvl->offset + (layer * lvl->zslice_size); 47 } 48 49 static boolean 50 nv30_miptree_get_handle(struct pipe_screen *pscreen, 51 struct pipe_resource *pt, 52 struct winsys_handle *handle) 53 { 54 struct nv30_miptree *mt = nv30_miptree(pt); 55 unsigned stride; 56 57 if (!mt || !mt->base.bo) 58 return false; 59 60 stride = mt->level[0].pitch; 61 62 return nouveau_screen_bo_get_handle(pscreen, mt->base.bo, stride, handle); 63 } 64 65 static void 66 nv30_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt) 67 { 68 struct nv30_miptree *mt = nv30_miptree(pt); 69 70 nouveau_bo_ref(NULL, &mt->base.bo); 71 FREE(mt); 72 } 73 74 struct nv30_transfer { 75 struct pipe_transfer base; 76 struct nv30_rect img; 77 struct nv30_rect tmp; 78 unsigned nblocksx; 79 unsigned nblocksy; 80 }; 81 82 static inline struct nv30_transfer * 83 nv30_transfer(struct pipe_transfer *ptx) 84 { 85 return (struct nv30_transfer *)ptx; 86 } 87 88 static inline void 89 define_rect(struct pipe_resource *pt, unsigned level, unsigned z, 90 unsigned x, unsigned y, unsigned w, unsigned h, 91 struct nv30_rect *rect) 92 { 93 struct nv30_miptree *mt = nv30_miptree(pt); 94 struct nv30_miptree_level *lvl = &mt->level[level]; 95 96 rect->w = u_minify(pt->width0, level) << mt->ms_x; 97 rect->w = util_format_get_nblocksx(pt->format, rect->w); 98 rect->h = u_minify(pt->height0, level) << mt->ms_y; 99 rect->h = util_format_get_nblocksy(pt->format, rect->h); 100 rect->d = 1; 101 rect->z = 0; 102 if (mt->swizzled) { 103 if (pt->target == PIPE_TEXTURE_3D) { 104 rect->d = u_minify(pt->depth0, level); 105 rect->z = z; z = 0; 106 } 107 rect->pitch = 0; 108 } else { 109 rect->pitch = lvl->pitch; 110 } 111 112 rect->bo = mt->base.bo; 113 rect->domain = NOUVEAU_BO_VRAM; 114 rect->offset = layer_offset(pt, level, z); 115 rect->cpp = util_format_get_blocksize(pt->format); 116 117 rect->x0 = util_format_get_nblocksx(pt->format, x) << mt->ms_x; 118 rect->y0 = util_format_get_nblocksy(pt->format, y) << mt->ms_y; 119 rect->x1 = rect->x0 + (w << mt->ms_x); 120 rect->y1 = rect->y0 + (h << mt->ms_y); 121 } 122 123 void 124 nv30_resource_copy_region(struct pipe_context *pipe, 125 struct pipe_resource *dstres, unsigned dst_level, 126 unsigned dstx, unsigned dsty, unsigned dstz, 127 struct pipe_resource *srcres, unsigned src_level, 128 const struct pipe_box *src_box) 129 { 130 struct nv30_context *nv30 = nv30_context(pipe); 131 struct nv30_rect src, dst; 132 133 if (dstres->target == PIPE_BUFFER && srcres->target == PIPE_BUFFER) { 134 nouveau_copy_buffer(&nv30->base, 135 nv04_resource(dstres), dstx, 136 nv04_resource(srcres), src_box->x, src_box->width); 137 return; 138 } 139 140 define_rect(srcres, src_level, src_box->z, src_box->x, src_box->y, 141 src_box->width, src_box->height, &src); 142 define_rect(dstres, dst_level, dstz, dstx, dsty, 143 src_box->width, src_box->height, &dst); 144 145 nv30_transfer_rect(nv30, NEAREST, &src, &dst); 146 } 147 148 static void 149 nv30_resource_resolve(struct nv30_context *nv30, 150 const struct pipe_blit_info *info) 151 { 152 struct nv30_miptree *src_mt = nv30_miptree(info->src.resource); 153 struct nv30_rect src, dst; 154 unsigned x, x0, x1, y, y1, w, h; 155 156 define_rect(info->src.resource, 0, info->src.box.z, info->src.box.x, 157 info->src.box.y, info->src.box.width, info->src.box.height, &src); 158 define_rect(info->dst.resource, 0, info->dst.box.z, info->dst.box.x, 159 info->dst.box.y, info->dst.box.width, info->dst.box.height, &dst); 160 161 x0 = src.x0; 162 x1 = src.x1; 163 y1 = src.y1; 164 165 /* On nv3x we must use sifm which is restricted to 1024x1024 tiles */ 166 for (y = src.y0; y < y1; y += h) { 167 h = y1 - y; 168 if (h > 1024) 169 h = 1024; 170 171 src.y0 = 0; 172 src.y1 = h; 173 src.h = h; 174 175 dst.y1 = dst.y0 + (h >> src_mt->ms_y); 176 dst.h = h >> src_mt->ms_y; 177 178 for (x = x0; x < x1; x += w) { 179 w = x1 - x; 180 if (w > 1024) 181 w = 1024; 182 183 src.offset = y * src.pitch + x * src.cpp; 184 src.x0 = 0; 185 src.x1 = w; 186 src.w = w; 187 188 dst.offset = (y >> src_mt->ms_y) * dst.pitch + 189 (x >> src_mt->ms_x) * dst.cpp; 190 dst.x1 = dst.x0 + (w >> src_mt->ms_x); 191 dst.w = w >> src_mt->ms_x; 192 193 nv30_transfer_rect(nv30, BILINEAR, &src, &dst); 194 } 195 } 196 } 197 198 void 199 nv30_blit(struct pipe_context *pipe, 200 const struct pipe_blit_info *blit_info) 201 { 202 struct nv30_context *nv30 = nv30_context(pipe); 203 struct pipe_blit_info info = *blit_info; 204 205 if (info.src.resource->nr_samples > 1 && 206 info.dst.resource->nr_samples <= 1 && 207 !util_format_is_depth_or_stencil(info.src.resource->format) && 208 !util_format_is_pure_integer(info.src.resource->format)) { 209 nv30_resource_resolve(nv30, blit_info); 210 return; 211 } 212 213 if (util_try_blit_via_copy_region(pipe, &info)) { 214 return; /* done */ 215 } 216 217 if (info.mask & PIPE_MASK_S) { 218 debug_printf("nv30: cannot blit stencil, skipping\n"); 219 info.mask &= ~PIPE_MASK_S; 220 } 221 222 if (!util_blitter_is_blit_supported(nv30->blitter, &info)) { 223 debug_printf("nv30: blit unsupported %s -> %s\n", 224 util_format_short_name(info.src.resource->format), 225 util_format_short_name(info.dst.resource->format)); 226 return; 227 } 228 229 /* XXX turn off occlusion queries */ 230 231 util_blitter_save_vertex_buffer_slot(nv30->blitter, nv30->vtxbuf); 232 util_blitter_save_vertex_elements(nv30->blitter, nv30->vertex); 233 util_blitter_save_vertex_shader(nv30->blitter, nv30->vertprog.program); 234 util_blitter_save_rasterizer(nv30->blitter, nv30->rast); 235 util_blitter_save_viewport(nv30->blitter, &nv30->viewport); 236 util_blitter_save_scissor(nv30->blitter, &nv30->scissor); 237 util_blitter_save_fragment_shader(nv30->blitter, nv30->fragprog.program); 238 util_blitter_save_blend(nv30->blitter, nv30->blend); 239 util_blitter_save_depth_stencil_alpha(nv30->blitter, 240 nv30->zsa); 241 util_blitter_save_stencil_ref(nv30->blitter, &nv30->stencil_ref); 242 util_blitter_save_sample_mask(nv30->blitter, nv30->sample_mask); 243 util_blitter_save_framebuffer(nv30->blitter, &nv30->framebuffer); 244 util_blitter_save_fragment_sampler_states(nv30->blitter, 245 nv30->fragprog.num_samplers, 246 (void**)nv30->fragprog.samplers); 247 util_blitter_save_fragment_sampler_views(nv30->blitter, 248 nv30->fragprog.num_textures, nv30->fragprog.textures); 249 util_blitter_save_render_condition(nv30->blitter, nv30->render_cond_query, 250 nv30->render_cond_cond, nv30->render_cond_mode); 251 util_blitter_blit(nv30->blitter, &info); 252 } 253 254 void 255 nv30_flush_resource(struct pipe_context *pipe, 256 struct pipe_resource *resource) 257 { 258 } 259 260 static void * 261 nv30_miptree_transfer_map(struct pipe_context *pipe, struct pipe_resource *pt, 262 unsigned level, unsigned usage, 263 const struct pipe_box *box, 264 struct pipe_transfer **ptransfer) 265 { 266 struct nv30_context *nv30 = nv30_context(pipe); 267 struct nouveau_device *dev = nv30->screen->base.device; 268 struct nv30_transfer *tx; 269 unsigned access = 0; 270 int ret; 271 272 tx = CALLOC_STRUCT(nv30_transfer); 273 if (!tx) 274 return NULL; 275 pipe_resource_reference(&tx->base.resource, pt); 276 tx->base.level = level; 277 tx->base.usage = usage; 278 tx->base.box = *box; 279 tx->base.stride = align(util_format_get_nblocksx(pt->format, box->width) * 280 util_format_get_blocksize(pt->format), 64); 281 tx->base.layer_stride = util_format_get_nblocksy(pt->format, box->height) * 282 tx->base.stride; 283 284 tx->nblocksx = util_format_get_nblocksx(pt->format, box->width); 285 tx->nblocksy = util_format_get_nblocksy(pt->format, box->height); 286 287 define_rect(pt, level, box->z, box->x, box->y, 288 tx->nblocksx, tx->nblocksy, &tx->img); 289 290 ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 291 tx->base.layer_stride, NULL, &tx->tmp.bo); 292 if (ret) { 293 pipe_resource_reference(&tx->base.resource, NULL); 294 FREE(tx); 295 return NULL; 296 } 297 298 tx->tmp.domain = NOUVEAU_BO_GART; 299 tx->tmp.offset = 0; 300 tx->tmp.pitch = tx->base.stride; 301 tx->tmp.cpp = tx->img.cpp; 302 tx->tmp.w = tx->nblocksx; 303 tx->tmp.h = tx->nblocksy; 304 tx->tmp.d = 1; 305 tx->tmp.x0 = 0; 306 tx->tmp.y0 = 0; 307 tx->tmp.x1 = tx->tmp.w; 308 tx->tmp.y1 = tx->tmp.h; 309 tx->tmp.z = 0; 310 311 if (usage & PIPE_TRANSFER_READ) 312 nv30_transfer_rect(nv30, NEAREST, &tx->img, &tx->tmp); 313 314 if (tx->tmp.bo->map) { 315 *ptransfer = &tx->base; 316 return tx->tmp.bo->map; 317 } 318 319 if (usage & PIPE_TRANSFER_READ) 320 access |= NOUVEAU_BO_RD; 321 if (usage & PIPE_TRANSFER_WRITE) 322 access |= NOUVEAU_BO_WR; 323 324 ret = nouveau_bo_map(tx->tmp.bo, access, nv30->base.client); 325 if (ret) { 326 pipe_resource_reference(&tx->base.resource, NULL); 327 FREE(tx); 328 return NULL; 329 } 330 331 *ptransfer = &tx->base; 332 return tx->tmp.bo->map; 333 } 334 335 static void 336 nv30_miptree_transfer_unmap(struct pipe_context *pipe, 337 struct pipe_transfer *ptx) 338 { 339 struct nv30_context *nv30 = nv30_context(pipe); 340 struct nv30_transfer *tx = nv30_transfer(ptx); 341 342 if (ptx->usage & PIPE_TRANSFER_WRITE) { 343 nv30_transfer_rect(nv30, NEAREST, &tx->tmp, &tx->img); 344 345 /* Allow the copies above to finish executing before freeing the source */ 346 nouveau_fence_work(nv30->screen->base.fence.current, 347 nouveau_fence_unref_bo, tx->tmp.bo); 348 } else { 349 nouveau_bo_ref(NULL, &tx->tmp.bo); 350 } 351 pipe_resource_reference(&ptx->resource, NULL); 352 FREE(tx); 353 } 354 355 const struct u_resource_vtbl nv30_miptree_vtbl = { 356 nv30_miptree_get_handle, 357 nv30_miptree_destroy, 358 nv30_miptree_transfer_map, 359 u_default_transfer_flush_region, 360 nv30_miptree_transfer_unmap, 361 }; 362 363 struct pipe_resource * 364 nv30_miptree_create(struct pipe_screen *pscreen, 365 const struct pipe_resource *tmpl) 366 { 367 struct nouveau_device *dev = nouveau_screen(pscreen)->device; 368 struct nv30_miptree *mt = CALLOC_STRUCT(nv30_miptree); 369 struct pipe_resource *pt = &mt->base.base; 370 unsigned blocksz, size; 371 unsigned w, h, d, l; 372 int ret; 373 374 switch (tmpl->nr_samples) { 375 case 4: 376 mt->ms_mode = 0x00004000; 377 mt->ms_x = 1; 378 mt->ms_y = 1; 379 break; 380 case 2: 381 mt->ms_mode = 0x00003000; 382 mt->ms_x = 1; 383 mt->ms_y = 0; 384 break; 385 default: 386 mt->ms_mode = 0x00000000; 387 mt->ms_x = 0; 388 mt->ms_y = 0; 389 break; 390 } 391 392 mt->base.vtbl = &nv30_miptree_vtbl; 393 *pt = *tmpl; 394 pipe_reference_init(&pt->reference, 1); 395 pt->screen = pscreen; 396 397 w = pt->width0 << mt->ms_x; 398 h = pt->height0 << mt->ms_y; 399 d = (pt->target == PIPE_TEXTURE_3D) ? pt->depth0 : 1; 400 blocksz = util_format_get_blocksize(pt->format); 401 402 if ((pt->target == PIPE_TEXTURE_RECT) || 403 (pt->bind & PIPE_BIND_SCANOUT) || 404 !util_is_power_of_two(pt->width0) || 405 !util_is_power_of_two(pt->height0) || 406 !util_is_power_of_two(pt->depth0) || 407 util_format_is_compressed(pt->format) || 408 util_format_is_float(pt->format) || mt->ms_mode) { 409 mt->uniform_pitch = util_format_get_nblocksx(pt->format, w) * blocksz; 410 mt->uniform_pitch = align(mt->uniform_pitch, 64); 411 if (pt->bind & PIPE_BIND_SCANOUT) { 412 struct nv30_screen *screen = nv30_screen(pscreen); 413 int pitch_align = MAX2( 414 screen->eng3d->oclass >= NV40_3D_CLASS ? 1024 : 256, 415 /* round_down_pow2(mt->uniform_pitch / 4) */ 416 1 << (util_last_bit(mt->uniform_pitch / 4) - 1)); 417 mt->uniform_pitch = align(mt->uniform_pitch, pitch_align); 418 } 419 } 420 421 if (!mt->uniform_pitch) 422 mt->swizzled = true; 423 424 size = 0; 425 for (l = 0; l <= pt->last_level; l++) { 426 struct nv30_miptree_level *lvl = &mt->level[l]; 427 unsigned nbx = util_format_get_nblocksx(pt->format, w); 428 unsigned nby = util_format_get_nblocksx(pt->format, h); 429 430 lvl->offset = size; 431 lvl->pitch = mt->uniform_pitch; 432 if (!lvl->pitch) 433 lvl->pitch = nbx * blocksz; 434 435 lvl->zslice_size = lvl->pitch * nby; 436 size += lvl->zslice_size * d; 437 438 w = u_minify(w, 1); 439 h = u_minify(h, 1); 440 d = u_minify(d, 1); 441 } 442 443 mt->layer_size = size; 444 if (pt->target == PIPE_TEXTURE_CUBE) { 445 if (!mt->uniform_pitch) 446 mt->layer_size = align(mt->layer_size, 128); 447 size = mt->layer_size * 6; 448 } 449 450 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 256, size, NULL, &mt->base.bo); 451 if (ret) { 452 FREE(mt); 453 return NULL; 454 } 455 456 mt->base.domain = NOUVEAU_BO_VRAM; 457 return &mt->base.base; 458 } 459 460 struct pipe_resource * 461 nv30_miptree_from_handle(struct pipe_screen *pscreen, 462 const struct pipe_resource *tmpl, 463 struct winsys_handle *handle) 464 { 465 struct nv30_miptree *mt; 466 unsigned stride; 467 468 /* only supports 2D, non-mipmapped textures for the moment */ 469 if ((tmpl->target != PIPE_TEXTURE_2D && 470 tmpl->target != PIPE_TEXTURE_RECT) || 471 tmpl->last_level != 0 || 472 tmpl->depth0 != 1 || 473 tmpl->array_size > 1) 474 return NULL; 475 476 mt = CALLOC_STRUCT(nv30_miptree); 477 if (!mt) 478 return NULL; 479 480 mt->base.bo = nouveau_screen_bo_from_handle(pscreen, handle, &stride); 481 if (mt->base.bo == NULL) { 482 FREE(mt); 483 return NULL; 484 } 485 486 mt->base.base = *tmpl; 487 mt->base.vtbl = &nv30_miptree_vtbl; 488 pipe_reference_init(&mt->base.base.reference, 1); 489 mt->base.base.screen = pscreen; 490 mt->uniform_pitch = stride; 491 mt->level[0].pitch = mt->uniform_pitch; 492 mt->level[0].offset = 0; 493 494 /* no need to adjust bo reference count */ 495 return &mt->base.base; 496 } 497 498 struct pipe_surface * 499 nv30_miptree_surface_new(struct pipe_context *pipe, 500 struct pipe_resource *pt, 501 const struct pipe_surface *tmpl) 502 { 503 struct nv30_miptree *mt = nv30_miptree(pt); /* guaranteed */ 504 struct nv30_surface *ns; 505 struct pipe_surface *ps; 506 struct nv30_miptree_level *lvl = &mt->level[tmpl->u.tex.level]; 507 508 ns = CALLOC_STRUCT(nv30_surface); 509 if (!ns) 510 return NULL; 511 ps = &ns->base; 512 513 pipe_reference_init(&ps->reference, 1); 514 pipe_resource_reference(&ps->texture, pt); 515 ps->context = pipe; 516 ps->format = tmpl->format; 517 ps->u.tex.level = tmpl->u.tex.level; 518 ps->u.tex.first_layer = tmpl->u.tex.first_layer; 519 ps->u.tex.last_layer = tmpl->u.tex.last_layer; 520 521 ns->width = u_minify(pt->width0, ps->u.tex.level); 522 ns->height = u_minify(pt->height0, ps->u.tex.level); 523 ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1; 524 ns->offset = layer_offset(pt, ps->u.tex.level, ps->u.tex.first_layer); 525 if (mt->swizzled) 526 ns->pitch = 4096; /* random, just something the hw won't reject.. */ 527 else 528 ns->pitch = lvl->pitch; 529 530 /* comment says there are going to be removed, but they're used by the st */ 531 ps->width = ns->width; 532 ps->height = ns->height; 533 return ps; 534 } 535 536 void 537 nv30_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps) 538 { 539 struct nv30_surface *ns = nv30_surface(ps); 540 541 pipe_resource_reference(&ps->texture, NULL); 542 FREE(ns); 543 } 544