freedreno_resource.c revision 14dfd8cc4344a1bb15a63179b497d14eaec9cc0d
1/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ 2 3/* 4 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Authors: 26 * Rob Clark <robclark@freedesktop.org> 27 */ 28 29#include "util/u_format.h" 30#include "util/u_inlines.h" 31#include "util/u_transfer.h" 32#include "util/u_string.h" 33#include "util/u_surface.h" 34 35#include "freedreno_resource.h" 36#include "freedreno_screen.h" 37#include "freedreno_surface.h" 38#include "freedreno_context.h" 39#include "freedreno_query_hw.h" 40#include "freedreno_util.h" 41 42#include <errno.h> 43 44static void 45fd_invalidate_resource(struct fd_context *ctx, struct pipe_resource *prsc) 46{ 47 int i; 48 49 /* Go through the entire state and see if the resource is bound 50 * anywhere. If it is, mark the relevant state as dirty. This is called on 51 * realloc_bo. 52 */ 53 54 /* Constbufs */ 55 for (i = 1; i < PIPE_MAX_CONSTANT_BUFFERS && !(ctx->dirty & FD_DIRTY_CONSTBUF); i++) { 56 if (ctx->constbuf[PIPE_SHADER_VERTEX].cb[i].buffer == prsc) 57 ctx->dirty |= FD_DIRTY_CONSTBUF; 58 if (ctx->constbuf[PIPE_SHADER_FRAGMENT].cb[i].buffer == prsc) 59 ctx->dirty |= FD_DIRTY_CONSTBUF; 60 } 61 62 /* VBOs */ 63 for (i = 0; i < ctx->vtx.vertexbuf.count && !(ctx->dirty & FD_DIRTY_VTXBUF); i++) { 64 if (ctx->vtx.vertexbuf.vb[i].buffer == prsc) 65 ctx->dirty |= FD_DIRTY_VTXBUF; 66 } 67 68 /* Index buffer */ 69 if (ctx->indexbuf.buffer == prsc) 70 ctx->dirty |= FD_DIRTY_INDEXBUF; 71 72 /* Textures */ 73 for (i = 0; i < ctx->verttex.num_textures && !(ctx->dirty & FD_DIRTY_VERTTEX); i++) { 74 if (ctx->verttex.textures[i]->texture == prsc) 75 ctx->dirty |= FD_DIRTY_VERTTEX; 76 } 77 for (i = 0; i < ctx->fragtex.num_textures && !(ctx->dirty & FD_DIRTY_FRAGTEX); i++) { 78 if (ctx->fragtex.textures[i]->texture == prsc) 79 ctx->dirty |= FD_DIRTY_FRAGTEX; 80 } 81} 82 83static void 84realloc_bo(struct fd_resource *rsc, uint32_t size) 85{ 86 struct fd_screen *screen = fd_screen(rsc->base.b.screen); 87 uint32_t flags = DRM_FREEDRENO_GEM_CACHE_WCOMBINE | 88 DRM_FREEDRENO_GEM_TYPE_KMEM; /* TODO */ 89 90 /* if we start using things other than write-combine, 91 * be sure to check for PIPE_RESOURCE_FLAG_MAP_COHERENT 92 */ 93 94 if (rsc->bo) 95 fd_bo_del(rsc->bo); 96 97 rsc->bo = fd_bo_new(screen->dev, size, flags); 98 rsc->timestamp = 0; 99 rsc->dirty = rsc->reading = false; 100 list_delinit(&rsc->list); 101 util_range_set_empty(&rsc->valid_buffer_range); 102} 103 104static void fd_resource_transfer_flush_region(struct pipe_context *pctx, 105 struct pipe_transfer *ptrans, 106 const struct pipe_box *box) 107{ 108 struct fd_resource *rsc = fd_resource(ptrans->resource); 109 110 if (ptrans->resource->target == PIPE_BUFFER) 111 util_range_add(&rsc->valid_buffer_range, 112 ptrans->box.x + box->x, 113 ptrans->box.x + box->x + box->width); 114} 115 116static void 117fd_resource_transfer_unmap(struct pipe_context *pctx, 118 struct pipe_transfer *ptrans) 119{ 120 struct fd_context *ctx = fd_context(pctx); 121 struct fd_resource *rsc = fd_resource(ptrans->resource); 122 if (!(ptrans->usage & PIPE_TRANSFER_UNSYNCHRONIZED)) 123 fd_bo_cpu_fini(rsc->bo); 124 125 util_range_add(&rsc->valid_buffer_range, 126 ptrans->box.x, 127 ptrans->box.x + ptrans->box.width); 128 129 pipe_resource_reference(&ptrans->resource, NULL); 130 util_slab_free(&ctx->transfer_pool, ptrans); 131} 132 133static void * 134fd_resource_transfer_map(struct pipe_context *pctx, 135 struct pipe_resource *prsc, 136 unsigned level, unsigned usage, 137 const struct pipe_box *box, 138 struct pipe_transfer **pptrans) 139{ 140 struct fd_context *ctx = fd_context(pctx); 141 struct fd_resource *rsc = fd_resource(prsc); 142 struct fd_resource_slice *slice = fd_resource_slice(rsc, level); 143 struct pipe_transfer *ptrans; 144 enum pipe_format format = prsc->format; 145 uint32_t op = 0; 146 uint32_t offset; 147 char *buf; 148 int ret = 0; 149 150 DBG("prsc=%p, level=%u, usage=%x", prsc, level, usage); 151 152 ptrans = util_slab_alloc(&ctx->transfer_pool); 153 if (!ptrans) 154 return NULL; 155 156 /* util_slab_alloc() doesn't zero: */ 157 memset(ptrans, 0, sizeof(*ptrans)); 158 159 pipe_resource_reference(&ptrans->resource, prsc); 160 ptrans->level = level; 161 ptrans->usage = usage; 162 ptrans->box = *box; 163 ptrans->stride = slice->pitch * rsc->cpp; 164 ptrans->layer_stride = slice->size0; 165 166 if (usage & PIPE_TRANSFER_READ) 167 op |= DRM_FREEDRENO_PREP_READ; 168 169 if (usage & PIPE_TRANSFER_WRITE) 170 op |= DRM_FREEDRENO_PREP_WRITE; 171 172 if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { 173 realloc_bo(rsc, fd_bo_size(rsc->bo)); 174 fd_invalidate_resource(ctx, prsc); 175 } else if ((usage & PIPE_TRANSFER_WRITE) && 176 prsc->target == PIPE_BUFFER && 177 !util_ranges_intersect(&rsc->valid_buffer_range, 178 box->x, box->x + box->width)) { 179 /* We are trying to write to a previously uninitialized range. No need 180 * to wait. 181 */ 182 } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { 183 /* If the GPU is writing to the resource, or if it is reading from the 184 * resource and we're trying to write to it, flush the renders. 185 */ 186 if (rsc->dirty || 187 ((ptrans->usage & PIPE_TRANSFER_WRITE) && rsc->reading)) 188 fd_context_render(pctx); 189 190 /* The GPU keeps track of how the various bo's are being used, and 191 * will wait if necessary for the proper operation to have 192 * completed. 193 */ 194 ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op); 195 if (ret) 196 goto fail; 197 } 198 199 buf = fd_bo_map(rsc->bo); 200 if (!buf) { 201 fd_resource_transfer_unmap(pctx, ptrans); 202 return NULL; 203 } 204 205 *pptrans = ptrans; 206 207 if (rsc->layer_first) { 208 offset = slice->offset + 209 box->y / util_format_get_blockheight(format) * ptrans->stride + 210 box->x / util_format_get_blockwidth(format) * rsc->cpp + 211 box->z * rsc->layer_size; 212 } else { 213 offset = slice->offset + 214 box->y / util_format_get_blockheight(format) * ptrans->stride + 215 box->x / util_format_get_blockwidth(format) * rsc->cpp + 216 box->z * slice->size0; 217 } 218 219 return buf + offset; 220 221fail: 222 fd_resource_transfer_unmap(pctx, ptrans); 223 return NULL; 224} 225 226static void 227fd_resource_destroy(struct pipe_screen *pscreen, 228 struct pipe_resource *prsc) 229{ 230 struct fd_resource *rsc = fd_resource(prsc); 231 if (rsc->bo) 232 fd_bo_del(rsc->bo); 233 list_delinit(&rsc->list); 234 util_range_destroy(&rsc->valid_buffer_range); 235 FREE(rsc); 236} 237 238static boolean 239fd_resource_get_handle(struct pipe_screen *pscreen, 240 struct pipe_resource *prsc, 241 struct winsys_handle *handle) 242{ 243 struct fd_resource *rsc = fd_resource(prsc); 244 245 return fd_screen_bo_get_handle(pscreen, rsc->bo, 246 rsc->slices[0].pitch * rsc->cpp, handle); 247} 248 249 250static const struct u_resource_vtbl fd_resource_vtbl = { 251 .resource_get_handle = fd_resource_get_handle, 252 .resource_destroy = fd_resource_destroy, 253 .transfer_map = fd_resource_transfer_map, 254 .transfer_flush_region = fd_resource_transfer_flush_region, 255 .transfer_unmap = fd_resource_transfer_unmap, 256 .transfer_inline_write = u_default_transfer_inline_write, 257}; 258 259static uint32_t 260setup_slices(struct fd_resource *rsc, uint32_t alignment) 261{ 262 struct pipe_resource *prsc = &rsc->base.b; 263 uint32_t level, size = 0; 264 uint32_t width = prsc->width0; 265 uint32_t height = prsc->height0; 266 uint32_t depth = prsc->depth0; 267 /* in layer_first layout, the level (slice) contains just one 268 * layer (since in fact the layer contains the slices) 269 */ 270 uint32_t layers_in_level = rsc->layer_first ? 1 : prsc->array_size; 271 272 for (level = 0; level <= prsc->last_level; level++) { 273 struct fd_resource_slice *slice = fd_resource_slice(rsc, level); 274 275 slice->pitch = width = align(width, 32); 276 slice->offset = size; 277 /* 1d array and 2d array textures must all have the same layer size 278 * for each miplevel on a3xx. 3d textures can have different layer 279 * sizes for high levels, but the hw auto-sizer is buggy (or at least 280 * different than what this code does), so as soon as the layer size 281 * range gets into range, we stop reducing it. 282 */ 283 if (prsc->target == PIPE_TEXTURE_3D && ( 284 level == 1 || 285 (level > 1 && rsc->slices[level - 1].size0 > 0xf000))) 286 slice->size0 = align(slice->pitch * height * rsc->cpp, alignment); 287 else if (level == 0 || rsc->layer_first || alignment == 1) 288 slice->size0 = align(slice->pitch * height * rsc->cpp, alignment); 289 else 290 slice->size0 = rsc->slices[level - 1].size0; 291 292 size += slice->size0 * depth * layers_in_level; 293 294 width = u_minify(width, 1); 295 height = u_minify(height, 1); 296 depth = u_minify(depth, 1); 297 } 298 299 return size; 300} 301 302static uint32_t 303slice_alignment(struct pipe_screen *pscreen, const struct pipe_resource *tmpl) 304{ 305 /* on a3xx, 2d array and 3d textures seem to want their 306 * layers aligned to page boundaries: 307 */ 308 switch (tmpl->target) { 309 case PIPE_TEXTURE_3D: 310 case PIPE_TEXTURE_1D_ARRAY: 311 case PIPE_TEXTURE_2D_ARRAY: 312 return 4096; 313 default: 314 return 1; 315 } 316} 317 318/** 319 * Create a new texture object, using the given template info. 320 */ 321static struct pipe_resource * 322fd_resource_create(struct pipe_screen *pscreen, 323 const struct pipe_resource *tmpl) 324{ 325 struct fd_resource *rsc = CALLOC_STRUCT(fd_resource); 326 struct pipe_resource *prsc = &rsc->base.b; 327 uint32_t size; 328 329 DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, " 330 "nr_samples=%u, usage=%u, bind=%x, flags=%x", 331 tmpl->target, util_format_name(tmpl->format), 332 tmpl->width0, tmpl->height0, tmpl->depth0, 333 tmpl->array_size, tmpl->last_level, tmpl->nr_samples, 334 tmpl->usage, tmpl->bind, tmpl->flags); 335 336 if (!rsc) 337 return NULL; 338 339 *prsc = *tmpl; 340 341 pipe_reference_init(&prsc->reference, 1); 342 list_inithead(&rsc->list); 343 prsc->screen = pscreen; 344 345 util_range_init(&rsc->valid_buffer_range); 346 347 rsc->base.vtbl = &fd_resource_vtbl; 348 rsc->cpp = util_format_get_blocksize(tmpl->format); 349 350 assert(rsc->cpp); 351 352 if (is_a4xx(fd_screen(pscreen))) { 353 switch (tmpl->target) { 354 case PIPE_TEXTURE_3D: 355 /* TODO 3D_ARRAY? */ 356 rsc->layer_first = false; 357 break; 358 default: 359 rsc->layer_first = true; 360 break; 361 } 362 } 363 364 size = setup_slices(rsc, slice_alignment(pscreen, tmpl)); 365 366 if (rsc->layer_first) { 367 rsc->layer_size = align(size, 4096); 368 size = rsc->layer_size * prsc->array_size; 369 } 370 371 realloc_bo(rsc, size); 372 if (!rsc->bo) 373 goto fail; 374 375 return prsc; 376fail: 377 fd_resource_destroy(pscreen, prsc); 378 return NULL; 379} 380 381/** 382 * Create a texture from a winsys_handle. The handle is often created in 383 * another process by first creating a pipe texture and then calling 384 * resource_get_handle. 385 */ 386static struct pipe_resource * 387fd_resource_from_handle(struct pipe_screen *pscreen, 388 const struct pipe_resource *tmpl, 389 struct winsys_handle *handle) 390{ 391 struct fd_resource *rsc = CALLOC_STRUCT(fd_resource); 392 struct fd_resource_slice *slice = &rsc->slices[0]; 393 struct pipe_resource *prsc = &rsc->base.b; 394 395 DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, " 396 "nr_samples=%u, usage=%u, bind=%x, flags=%x", 397 tmpl->target, util_format_name(tmpl->format), 398 tmpl->width0, tmpl->height0, tmpl->depth0, 399 tmpl->array_size, tmpl->last_level, tmpl->nr_samples, 400 tmpl->usage, tmpl->bind, tmpl->flags); 401 402 if (!rsc) 403 return NULL; 404 405 *prsc = *tmpl; 406 407 pipe_reference_init(&prsc->reference, 1); 408 list_inithead(&rsc->list); 409 prsc->screen = pscreen; 410 411 util_range_init(&rsc->valid_buffer_range); 412 413 rsc->bo = fd_screen_bo_from_handle(pscreen, handle, &slice->pitch); 414 if (!rsc->bo) 415 goto fail; 416 417 rsc->base.vtbl = &fd_resource_vtbl; 418 rsc->cpp = util_format_get_blocksize(tmpl->format); 419 slice->pitch /= rsc->cpp; 420 421 assert(rsc->cpp); 422 423 return prsc; 424 425fail: 426 fd_resource_destroy(pscreen, prsc); 427 return NULL; 428} 429 430static void fd_blitter_pipe_begin(struct fd_context *ctx); 431static void fd_blitter_pipe_end(struct fd_context *ctx); 432 433/** 434 * _copy_region using pipe (3d engine) 435 */ 436static bool 437fd_blitter_pipe_copy_region(struct fd_context *ctx, 438 struct pipe_resource *dst, 439 unsigned dst_level, 440 unsigned dstx, unsigned dsty, unsigned dstz, 441 struct pipe_resource *src, 442 unsigned src_level, 443 const struct pipe_box *src_box) 444{ 445 /* not until we allow rendertargets to be buffers */ 446 if (dst->target == PIPE_BUFFER || src->target == PIPE_BUFFER) 447 return false; 448 449 if (!util_blitter_is_copy_supported(ctx->blitter, dst, src)) 450 return false; 451 452 fd_blitter_pipe_begin(ctx); 453 util_blitter_copy_texture(ctx->blitter, 454 dst, dst_level, dstx, dsty, dstz, 455 src, src_level, src_box); 456 fd_blitter_pipe_end(ctx); 457 458 return true; 459} 460 461/** 462 * Copy a block of pixels from one resource to another. 463 * The resource must be of the same format. 464 * Resources with nr_samples > 1 are not allowed. 465 */ 466static void 467fd_resource_copy_region(struct pipe_context *pctx, 468 struct pipe_resource *dst, 469 unsigned dst_level, 470 unsigned dstx, unsigned dsty, unsigned dstz, 471 struct pipe_resource *src, 472 unsigned src_level, 473 const struct pipe_box *src_box) 474{ 475 struct fd_context *ctx = fd_context(pctx); 476 477 /* TODO if we have 2d core, or other DMA engine that could be used 478 * for simple copies and reasonably easily synchronized with the 3d 479 * core, this is where we'd plug it in.. 480 */ 481 482 /* try blit on 3d pipe: */ 483 if (fd_blitter_pipe_copy_region(ctx, 484 dst, dst_level, dstx, dsty, dstz, 485 src, src_level, src_box)) 486 return; 487 488 /* else fallback to pure sw: */ 489 util_resource_copy_region(pctx, 490 dst, dst_level, dstx, dsty, dstz, 491 src, src_level, src_box); 492} 493 494/** 495 * Optimal hardware path for blitting pixels. 496 * Scaling, format conversion, up- and downsampling (resolve) are allowed. 497 */ 498static void 499fd_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) 500{ 501 struct fd_context *ctx = fd_context(pctx); 502 struct pipe_blit_info info = *blit_info; 503 504 if (info.src.resource->nr_samples > 1 && 505 info.dst.resource->nr_samples <= 1 && 506 !util_format_is_depth_or_stencil(info.src.resource->format) && 507 !util_format_is_pure_integer(info.src.resource->format)) { 508 DBG("color resolve unimplemented"); 509 return; 510 } 511 512 if (util_try_blit_via_copy_region(pctx, &info)) { 513 return; /* done */ 514 } 515 516 if (info.mask & PIPE_MASK_S) { 517 DBG("cannot blit stencil, skipping"); 518 info.mask &= ~PIPE_MASK_S; 519 } 520 521 if (!util_blitter_is_blit_supported(ctx->blitter, &info)) { 522 DBG("blit unsupported %s -> %s", 523 util_format_short_name(info.src.resource->format), 524 util_format_short_name(info.dst.resource->format)); 525 return; 526 } 527 528 fd_blitter_pipe_begin(ctx); 529 util_blitter_blit(ctx->blitter, &info); 530 fd_blitter_pipe_end(ctx); 531} 532 533static void 534fd_blitter_pipe_begin(struct fd_context *ctx) 535{ 536 util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vtx.vertexbuf.vb); 537 util_blitter_save_vertex_elements(ctx->blitter, ctx->vtx.vtx); 538 util_blitter_save_vertex_shader(ctx->blitter, ctx->prog.vp); 539 util_blitter_save_rasterizer(ctx->blitter, ctx->rasterizer); 540 util_blitter_save_viewport(ctx->blitter, &ctx->viewport); 541 util_blitter_save_scissor(ctx->blitter, &ctx->scissor); 542 util_blitter_save_fragment_shader(ctx->blitter, ctx->prog.fp); 543 util_blitter_save_blend(ctx->blitter, ctx->blend); 544 util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->zsa); 545 util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref); 546 util_blitter_save_sample_mask(ctx->blitter, ctx->sample_mask); 547 util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer); 548 util_blitter_save_fragment_sampler_states(ctx->blitter, 549 ctx->fragtex.num_samplers, 550 (void **)ctx->fragtex.samplers); 551 util_blitter_save_fragment_sampler_views(ctx->blitter, 552 ctx->fragtex.num_textures, ctx->fragtex.textures); 553 554 fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_BLIT); 555} 556 557static void 558fd_blitter_pipe_end(struct fd_context *ctx) 559{ 560 fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_NULL); 561} 562 563static void 564fd_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) 565{ 566 struct fd_resource *rsc = fd_resource(prsc); 567 568 if (rsc->dirty) 569 fd_context_render(pctx); 570} 571 572void 573fd_resource_screen_init(struct pipe_screen *pscreen) 574{ 575 pscreen->resource_create = fd_resource_create; 576 pscreen->resource_from_handle = fd_resource_from_handle; 577 pscreen->resource_get_handle = u_resource_get_handle_vtbl; 578 pscreen->resource_destroy = u_resource_destroy_vtbl; 579} 580 581void 582fd_resource_context_init(struct pipe_context *pctx) 583{ 584 pctx->transfer_map = u_transfer_map_vtbl; 585 pctx->transfer_flush_region = u_transfer_flush_region_vtbl; 586 pctx->transfer_unmap = u_transfer_unmap_vtbl; 587 pctx->transfer_inline_write = u_transfer_inline_write_vtbl; 588 pctx->create_surface = fd_create_surface; 589 pctx->surface_destroy = fd_surface_destroy; 590 pctx->resource_copy_region = fd_resource_copy_region; 591 pctx->blit = fd_blit; 592 pctx->flush_resource = fd_flush_resource; 593} 594