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