etnaviv_resource.c revision b8e80941
1/* 2 * Copyright (c) 2012-2015 Etnaviv Project 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, sub license, 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 (including the 12 * next paragraph) shall be included in all copies or substantial portions 13 * of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: 24 * Wladimir J. van der Laan <laanwj@gmail.com> 25 */ 26 27#include "etnaviv_resource.h" 28 29#include "hw/common.xml.h" 30 31#include "etnaviv_context.h" 32#include "etnaviv_debug.h" 33#include "etnaviv_screen.h" 34#include "etnaviv_translate.h" 35 36#include "util/hash_table.h" 37#include "util/u_inlines.h" 38#include "util/u_memory.h" 39 40#include "drm-uapi/drm_fourcc.h" 41 42static enum etna_surface_layout modifier_to_layout(uint64_t modifier) 43{ 44 switch (modifier) { 45 case DRM_FORMAT_MOD_VIVANTE_TILED: 46 return ETNA_LAYOUT_TILED; 47 case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: 48 return ETNA_LAYOUT_SUPER_TILED; 49 case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED: 50 return ETNA_LAYOUT_MULTI_TILED; 51 case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED: 52 return ETNA_LAYOUT_MULTI_SUPERTILED; 53 case DRM_FORMAT_MOD_LINEAR: 54 default: 55 return ETNA_LAYOUT_LINEAR; 56 } 57} 58 59static uint64_t layout_to_modifier(enum etna_surface_layout layout) 60{ 61 switch (layout) { 62 case ETNA_LAYOUT_TILED: 63 return DRM_FORMAT_MOD_VIVANTE_TILED; 64 case ETNA_LAYOUT_SUPER_TILED: 65 return DRM_FORMAT_MOD_VIVANTE_SUPER_TILED; 66 case ETNA_LAYOUT_MULTI_TILED: 67 return DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED; 68 case ETNA_LAYOUT_MULTI_SUPERTILED: 69 return DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED; 70 case ETNA_LAYOUT_LINEAR: 71 return DRM_FORMAT_MOD_LINEAR; 72 default: 73 return DRM_FORMAT_MOD_INVALID; 74 } 75} 76 77/* A tile is 4x4 pixels, having 'screen->specs.bits_per_tile' of tile status. 78 * So, in a buffer of N pixels, there are N / (4 * 4) tiles. 79 * We need N * screen->specs.bits_per_tile / (4 * 4) bits of tile status, or 80 * N * screen->specs.bits_per_tile / (4 * 4 * 8) bytes. 81 */ 82bool 83etna_screen_resource_alloc_ts(struct pipe_screen *pscreen, 84 struct etna_resource *rsc) 85{ 86 struct etna_screen *screen = etna_screen(pscreen); 87 size_t rt_ts_size, ts_layer_stride, pixels; 88 89 assert(!rsc->ts_bo); 90 91 /* TS only for level 0 -- XXX is this formula correct? */ 92 pixels = rsc->levels[0].layer_stride / util_format_get_blocksize(rsc->base.format); 93 ts_layer_stride = align(pixels * screen->specs.bits_per_tile / 0x80, 94 0x100 * screen->specs.pixel_pipes); 95 rt_ts_size = ts_layer_stride * rsc->base.array_size; 96 if (rt_ts_size == 0) 97 return true; 98 99 DBG_F(ETNA_DBG_RESOURCE_MSGS, "%p: Allocating tile status of size %zu", 100 rsc, rt_ts_size); 101 102 struct etna_bo *rt_ts; 103 rt_ts = etna_bo_new(screen->dev, rt_ts_size, DRM_ETNA_GEM_CACHE_WC); 104 105 if (unlikely(!rt_ts)) { 106 BUG("Problem allocating tile status for resource"); 107 return false; 108 } 109 110 rsc->ts_bo = rt_ts; 111 rsc->levels[0].ts_offset = 0; 112 rsc->levels[0].ts_layer_stride = ts_layer_stride; 113 rsc->levels[0].ts_size = rt_ts_size; 114 115 /* It is important to initialize the TS, as random pattern 116 * can result in crashes. Do this on the CPU as this only happens once 117 * per surface anyway and it's a small area, so it may not be worth 118 * queuing this to the GPU. */ 119 void *ts_map = etna_bo_map(rt_ts); 120 memset(ts_map, screen->specs.ts_clear_value, rt_ts_size); 121 122 return true; 123} 124 125static boolean 126etna_screen_can_create_resource(struct pipe_screen *pscreen, 127 const struct pipe_resource *templat) 128{ 129 struct etna_screen *screen = etna_screen(pscreen); 130 if (!translate_samples_to_xyscale(templat->nr_samples, NULL, NULL, NULL)) 131 return false; 132 133 /* templat->bind is not set here, so we must use the minimum sizes */ 134 uint max_size = 135 MIN2(screen->specs.max_rendertarget_size, screen->specs.max_texture_size); 136 137 if (templat->width0 > max_size || templat->height0 > max_size) 138 return false; 139 140 return true; 141} 142 143static unsigned 144setup_miptree(struct etna_resource *rsc, unsigned paddingX, unsigned paddingY, 145 unsigned msaa_xscale, unsigned msaa_yscale) 146{ 147 struct pipe_resource *prsc = &rsc->base; 148 unsigned level, size = 0; 149 unsigned width = prsc->width0; 150 unsigned height = prsc->height0; 151 unsigned depth = prsc->depth0; 152 153 for (level = 0; level <= prsc->last_level; level++) { 154 struct etna_resource_level *mip = &rsc->levels[level]; 155 156 mip->width = width; 157 mip->height = height; 158 mip->padded_width = align(width * msaa_xscale, paddingX); 159 mip->padded_height = align(height * msaa_yscale, paddingY); 160 mip->stride = util_format_get_stride(prsc->format, mip->padded_width); 161 mip->offset = size; 162 mip->layer_stride = mip->stride * util_format_get_nblocksy(prsc->format, mip->padded_height); 163 mip->size = prsc->array_size * mip->layer_stride; 164 165 /* align levels to 64 bytes to be able to render to them */ 166 size += align(mip->size, ETNA_PE_ALIGNMENT) * depth; 167 168 width = u_minify(width, 1); 169 height = u_minify(height, 1); 170 depth = u_minify(depth, 1); 171 } 172 173 return size; 174} 175 176/* Is rs alignment needed? */ 177static bool is_rs_align(struct etna_screen *screen, 178 const struct pipe_resource *tmpl) 179{ 180 return screen->specs.use_blt ? false : ( 181 VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN) || 182 !etna_resource_sampler_only(tmpl)); 183} 184 185/* Create a new resource object, using the given template info */ 186struct pipe_resource * 187etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, 188 enum etna_resource_addressing_mode mode, uint64_t modifier, 189 const struct pipe_resource *templat) 190{ 191 struct etna_screen *screen = etna_screen(pscreen); 192 struct etna_resource *rsc; 193 unsigned size; 194 195 DBG_F(ETNA_DBG_RESOURCE_MSGS, 196 "target=%d, format=%s, %ux%ux%u, array_size=%u, " 197 "last_level=%u, nr_samples=%u, usage=%u, bind=%x, flags=%x", 198 templat->target, util_format_name(templat->format), templat->width0, 199 templat->height0, templat->depth0, templat->array_size, 200 templat->last_level, templat->nr_samples, templat->usage, 201 templat->bind, templat->flags); 202 203 /* Determine scaling for antialiasing, allow override using debug flag */ 204 int nr_samples = templat->nr_samples; 205 if ((templat->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL)) && 206 !(templat->bind & PIPE_BIND_SAMPLER_VIEW)) { 207 if (DBG_ENABLED(ETNA_DBG_MSAA_2X)) 208 nr_samples = 2; 209 if (DBG_ENABLED(ETNA_DBG_MSAA_4X)) 210 nr_samples = 4; 211 } 212 213 int msaa_xscale = 1, msaa_yscale = 1; 214 if (!translate_samples_to_xyscale(nr_samples, &msaa_xscale, &msaa_yscale, NULL)) { 215 /* Number of samples not supported */ 216 return NULL; 217 } 218 219 /* Determine needed padding (alignment of height/width) */ 220 unsigned paddingX = 0, paddingY = 0; 221 unsigned halign = TEXTURE_HALIGN_FOUR; 222 if (!util_format_is_compressed(templat->format)) { 223 /* If we have the TEXTURE_HALIGN feature, we can always align to the 224 * resolve engine's width. If not, we must not align resources used 225 * only for textures. If this GPU uses the BLT engine, never do RS align. 226 */ 227 etna_layout_multiple(layout, screen->specs.pixel_pipes, 228 is_rs_align (screen, templat), 229 &paddingX, &paddingY, &halign); 230 assert(paddingX && paddingY); 231 } else { 232 /* Compressed textures are padded to their block size, but we don't have 233 * to do anything special for that. */ 234 paddingX = 1; 235 paddingY = 1; 236 } 237 238 if (!screen->specs.use_blt && templat->target != PIPE_BUFFER) 239 etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY); 240 241 if (templat->bind & PIPE_BIND_SCANOUT && screen->ro->kms_fd >= 0) { 242 struct pipe_resource scanout_templat = *templat; 243 struct renderonly_scanout *scanout; 244 struct winsys_handle handle; 245 246 /* pad scanout buffer size to be compatible with the RS */ 247 if (!screen->specs.use_blt && modifier == DRM_FORMAT_MOD_LINEAR) 248 etna_adjust_rs_align(screen->specs.pixel_pipes, &paddingX, &paddingY); 249 250 scanout_templat.width0 = align(scanout_templat.width0, paddingX); 251 scanout_templat.height0 = align(scanout_templat.height0, paddingY); 252 253 scanout = renderonly_scanout_for_resource(&scanout_templat, 254 screen->ro, &handle); 255 if (!scanout) 256 return NULL; 257 258 assert(handle.type == WINSYS_HANDLE_TYPE_FD); 259 handle.modifier = modifier; 260 rsc = etna_resource(pscreen->resource_from_handle(pscreen, templat, 261 &handle, 262 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE)); 263 close(handle.handle); 264 if (!rsc) 265 return NULL; 266 267 rsc->scanout = scanout; 268 269 return &rsc->base; 270 } 271 272 rsc = CALLOC_STRUCT(etna_resource); 273 if (!rsc) 274 return NULL; 275 276 rsc->base = *templat; 277 rsc->base.screen = pscreen; 278 rsc->base.nr_samples = nr_samples; 279 rsc->layout = layout; 280 rsc->halign = halign; 281 rsc->addressing_mode = mode; 282 283 pipe_reference_init(&rsc->base.reference, 1); 284 285 size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale); 286 287 uint32_t flags = DRM_ETNA_GEM_CACHE_WC; 288 if (templat->bind & PIPE_BIND_VERTEX_BUFFER) 289 flags |= DRM_ETNA_GEM_FORCE_MMU; 290 struct etna_bo *bo = etna_bo_new(screen->dev, size, flags); 291 if (unlikely(bo == NULL)) { 292 BUG("Problem allocating video memory for resource"); 293 goto free_rsc; 294 } 295 296 rsc->bo = bo; 297 rsc->ts_bo = 0; /* TS is only created when first bound to surface */ 298 299 if (DBG_ENABLED(ETNA_DBG_ZERO)) { 300 void *map = etna_bo_map(bo); 301 memset(map, 0, size); 302 } 303 304 rsc->pending_ctx = _mesa_set_create(NULL, _mesa_hash_pointer, 305 _mesa_key_pointer_equal); 306 if (!rsc->pending_ctx) 307 goto free_rsc; 308 309 return &rsc->base; 310 311free_rsc: 312 FREE(rsc); 313 return NULL; 314} 315 316static struct pipe_resource * 317etna_resource_create(struct pipe_screen *pscreen, 318 const struct pipe_resource *templat) 319{ 320 struct etna_screen *screen = etna_screen(pscreen); 321 322 /* Figure out what tiling and address mode to use -- for now, assume that 323 * texture cannot be linear. there is a capability LINEAR_TEXTURE_SUPPORT 324 * (supported on gc880 and gc2000 at least), but not sure how it works. 325 * Buffers always have LINEAR layout. 326 */ 327 unsigned layout = ETNA_LAYOUT_LINEAR; 328 enum etna_resource_addressing_mode mode = ETNA_ADDRESSING_MODE_TILED; 329 330 if (etna_resource_sampler_only(templat)) { 331 /* The buffer is only used for texturing, so create something 332 * directly compatible with the sampler. Such a buffer can 333 * never be rendered to. */ 334 layout = ETNA_LAYOUT_TILED; 335 336 if (util_format_is_compressed(templat->format)) 337 layout = ETNA_LAYOUT_LINEAR; 338 } else if (templat->target != PIPE_BUFFER) { 339 bool want_multitiled = false; 340 bool want_supertiled = screen->specs.can_supertile; 341 342 /* When this GPU supports single-buffer rendering, don't ever enable 343 * multi-tiling. This replicates the blob behavior on GC3000. 344 */ 345 if (!screen->specs.single_buffer) 346 want_multitiled = screen->specs.pixel_pipes > 1; 347 348 /* Keep single byte blocksized resources as tiled, since we 349 * are unable to use the RS blit to de-tile them. However, 350 * if they're used as a render target or depth/stencil, they 351 * must be multi-tiled for GPUs with multiple pixel pipes. 352 * Ignore depth/stencil here, but it is an error for a render 353 * target. 354 */ 355 if (util_format_get_blocksize(templat->format) == 1 && 356 !(templat->bind & PIPE_BIND_DEPTH_STENCIL)) { 357 assert(!(templat->bind & PIPE_BIND_RENDER_TARGET && want_multitiled)); 358 want_multitiled = want_supertiled = false; 359 } 360 361 layout = ETNA_LAYOUT_BIT_TILE; 362 if (want_multitiled) 363 layout |= ETNA_LAYOUT_BIT_MULTI; 364 if (want_supertiled) 365 layout |= ETNA_LAYOUT_BIT_SUPER; 366 } 367 368 if (templat->target == PIPE_TEXTURE_3D) 369 layout = ETNA_LAYOUT_LINEAR; 370 371 /* modifier is only used for scanout surfaces, so safe to use LINEAR here */ 372 return etna_resource_alloc(pscreen, layout, mode, DRM_FORMAT_MOD_LINEAR, templat); 373} 374 375enum modifier_priority { 376 MODIFIER_PRIORITY_INVALID = 0, 377 MODIFIER_PRIORITY_LINEAR, 378 MODIFIER_PRIORITY_SPLIT_TILED, 379 MODIFIER_PRIORITY_SPLIT_SUPER_TILED, 380 MODIFIER_PRIORITY_TILED, 381 MODIFIER_PRIORITY_SUPER_TILED, 382}; 383 384const uint64_t priority_to_modifier[] = { 385 [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID, 386 [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR, 387 [MODIFIER_PRIORITY_SPLIT_TILED] = DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED, 388 [MODIFIER_PRIORITY_SPLIT_SUPER_TILED] = DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED, 389 [MODIFIER_PRIORITY_TILED] = DRM_FORMAT_MOD_VIVANTE_TILED, 390 [MODIFIER_PRIORITY_SUPER_TILED] = DRM_FORMAT_MOD_VIVANTE_SUPER_TILED, 391}; 392 393static uint64_t 394select_best_modifier(const struct etna_screen * screen, 395 const uint64_t *modifiers, const unsigned count) 396{ 397 enum modifier_priority prio = MODIFIER_PRIORITY_INVALID; 398 399 for (int i = 0; i < count; i++) { 400 switch (modifiers[i]) { 401 case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: 402 if ((screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer) || 403 !screen->specs.can_supertile) 404 break; 405 prio = MAX2(prio, MODIFIER_PRIORITY_SUPER_TILED); 406 break; 407 case DRM_FORMAT_MOD_VIVANTE_TILED: 408 if (screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer) 409 break; 410 prio = MAX2(prio, MODIFIER_PRIORITY_TILED); 411 break; 412 case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED: 413 if ((screen->specs.pixel_pipes < 2) || !screen->specs.can_supertile) 414 break; 415 prio = MAX2(prio, MODIFIER_PRIORITY_SPLIT_SUPER_TILED); 416 break; 417 case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED: 418 if (screen->specs.pixel_pipes < 2) 419 break; 420 prio = MAX2(prio, MODIFIER_PRIORITY_SPLIT_TILED); 421 break; 422 case DRM_FORMAT_MOD_LINEAR: 423 prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR); 424 break; 425 case DRM_FORMAT_MOD_INVALID: 426 default: 427 break; 428 } 429 } 430 431 return priority_to_modifier[prio]; 432} 433 434static struct pipe_resource * 435etna_resource_create_modifiers(struct pipe_screen *pscreen, 436 const struct pipe_resource *templat, 437 const uint64_t *modifiers, int count) 438{ 439 struct etna_screen *screen = etna_screen(pscreen); 440 struct pipe_resource tmpl = *templat; 441 uint64_t modifier = select_best_modifier(screen, modifiers, count); 442 443 if (modifier == DRM_FORMAT_MOD_INVALID) 444 return NULL; 445 446 /* 447 * We currently assume that all buffers allocated through this interface 448 * should be scanout enabled. 449 */ 450 tmpl.bind |= PIPE_BIND_SCANOUT; 451 452 return etna_resource_alloc(pscreen, modifier_to_layout(modifier), 453 ETNA_ADDRESSING_MODE_TILED, modifier, &tmpl); 454} 455 456static void 457etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc) 458{ 459 struct etna_resource *res = etna_resource(prsc); 460 461 if (res->external) 462 etna_resource(res->external)->seqno++; 463 else 464 res->seqno++; 465} 466 467static void 468etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) 469{ 470 struct etna_screen *screen = etna_screen(pscreen); 471 struct etna_resource *rsc = etna_resource(prsc); 472 473 mtx_lock(&screen->lock); 474 _mesa_set_remove_key(screen->used_resources, rsc); 475 _mesa_set_destroy(rsc->pending_ctx, NULL); 476 mtx_unlock(&screen->lock); 477 478 if (rsc->bo) 479 etna_bo_del(rsc->bo); 480 481 if (rsc->ts_bo) 482 etna_bo_del(rsc->ts_bo); 483 484 if (rsc->scanout) 485 renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro); 486 487 pipe_resource_reference(&rsc->texture, NULL); 488 pipe_resource_reference(&rsc->external, NULL); 489 490 for (unsigned i = 0; i < ETNA_NUM_LOD; i++) 491 FREE(rsc->levels[i].patch_offsets); 492 493 FREE(rsc); 494} 495 496static struct pipe_resource * 497etna_resource_from_handle(struct pipe_screen *pscreen, 498 const struct pipe_resource *tmpl, 499 struct winsys_handle *handle, unsigned usage) 500{ 501 struct etna_screen *screen = etna_screen(pscreen); 502 struct etna_resource *rsc; 503 struct etna_resource_level *level; 504 struct pipe_resource *prsc; 505 struct pipe_resource *ptiled = NULL; 506 507 DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, " 508 "nr_samples=%u, usage=%u, bind=%x, flags=%x", 509 tmpl->target, util_format_name(tmpl->format), tmpl->width0, 510 tmpl->height0, tmpl->depth0, tmpl->array_size, tmpl->last_level, 511 tmpl->nr_samples, tmpl->usage, tmpl->bind, tmpl->flags); 512 513 rsc = CALLOC_STRUCT(etna_resource); 514 if (!rsc) 515 return NULL; 516 517 level = &rsc->levels[0]; 518 prsc = &rsc->base; 519 520 *prsc = *tmpl; 521 522 pipe_reference_init(&prsc->reference, 1); 523 prsc->screen = pscreen; 524 525 rsc->bo = etna_screen_bo_from_handle(pscreen, handle, &level->stride); 526 if (!rsc->bo) 527 goto fail; 528 529 rsc->seqno = 1; 530 rsc->layout = modifier_to_layout(handle->modifier); 531 rsc->halign = TEXTURE_HALIGN_FOUR; 532 rsc->addressing_mode = ETNA_ADDRESSING_MODE_TILED; 533 534 535 level->width = tmpl->width0; 536 level->height = tmpl->height0; 537 538 /* Determine padding of the imported resource. */ 539 unsigned paddingX = 0, paddingY = 0; 540 etna_layout_multiple(rsc->layout, screen->specs.pixel_pipes, 541 is_rs_align(screen, tmpl), 542 &paddingX, &paddingY, &rsc->halign); 543 544 if (!screen->specs.use_blt) 545 etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY); 546 level->padded_width = align(level->width, paddingX); 547 level->padded_height = align(level->height, paddingY); 548 549 level->layer_stride = level->stride * util_format_get_nblocksy(prsc->format, 550 level->padded_height); 551 level->size = level->layer_stride; 552 553 /* The DDX must give us a BO which conforms to our padding size. 554 * The stride of the BO must be greater or equal to our padded 555 * stride. The size of the BO must accomodate the padded height. */ 556 if (level->stride < util_format_get_stride(tmpl->format, level->padded_width)) { 557 BUG("BO stride %u is too small for RS engine width padding (%zu, format %s)", 558 level->stride, util_format_get_stride(tmpl->format, level->padded_width), 559 util_format_name(tmpl->format)); 560 goto fail; 561 } 562 if (etna_bo_size(rsc->bo) < level->stride * level->padded_height) { 563 BUG("BO size %u is too small for RS engine height padding (%u, format %s)", 564 etna_bo_size(rsc->bo), level->stride * level->padded_height, 565 util_format_name(tmpl->format)); 566 goto fail; 567 } 568 569 rsc->pending_ctx = _mesa_set_create(NULL, _mesa_hash_pointer, 570 _mesa_key_pointer_equal); 571 if (!rsc->pending_ctx) 572 goto fail; 573 574 if (rsc->layout == ETNA_LAYOUT_LINEAR) { 575 /* 576 * Both sampler and pixel pipes can't handle linear, create a compatible 577 * base resource, where we can attach the imported buffer as an external 578 * resource. 579 */ 580 struct pipe_resource tiled_templat = *tmpl; 581 582 /* 583 * Remove BIND_SCANOUT to avoid recursion, as etna_resource_create uses 584 * this function to import the scanout buffer and get a tiled resource. 585 */ 586 tiled_templat.bind &= ~PIPE_BIND_SCANOUT; 587 588 ptiled = etna_resource_create(pscreen, &tiled_templat); 589 if (!ptiled) 590 goto fail; 591 592 etna_resource(ptiled)->external = prsc; 593 594 return ptiled; 595 } 596 597 return prsc; 598 599fail: 600 etna_resource_destroy(pscreen, prsc); 601 if (ptiled) 602 etna_resource_destroy(pscreen, ptiled); 603 604 return NULL; 605} 606 607static boolean 608etna_resource_get_handle(struct pipe_screen *pscreen, 609 struct pipe_context *pctx, 610 struct pipe_resource *prsc, 611 struct winsys_handle *handle, unsigned usage) 612{ 613 struct etna_resource *rsc = etna_resource(prsc); 614 /* Scanout is always attached to the base resource */ 615 struct renderonly_scanout *scanout = rsc->scanout; 616 617 /* 618 * External resources are preferred, so a import->export chain of 619 * render/sampler incompatible buffers yield the same handle. 620 */ 621 if (rsc->external) 622 rsc = etna_resource(rsc->external); 623 624 handle->stride = rsc->levels[0].stride; 625 handle->offset = rsc->levels[0].offset; 626 handle->modifier = layout_to_modifier(rsc->layout); 627 628 if (handle->type == WINSYS_HANDLE_TYPE_SHARED) { 629 return etna_bo_get_name(rsc->bo, &handle->handle) == 0; 630 } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) { 631 if (renderonly_get_handle(scanout, handle)) { 632 return TRUE; 633 } else { 634 handle->handle = etna_bo_handle(rsc->bo); 635 return TRUE; 636 } 637 } else if (handle->type == WINSYS_HANDLE_TYPE_FD) { 638 handle->handle = etna_bo_dmabuf(rsc->bo); 639 return TRUE; 640 } else { 641 return FALSE; 642 } 643} 644 645void 646etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc, 647 enum etna_resource_status status) 648{ 649 struct etna_screen *screen = ctx->screen; 650 struct etna_resource *rsc; 651 652 if (!prsc) 653 return; 654 655 rsc = etna_resource(prsc); 656 657 mtx_lock(&screen->lock); 658 659 /* 660 * if we are pending read or write by any other context or 661 * if reading a resource pending a write, then 662 * flush all the contexts to maintain coherency 663 */ 664 if (((status & ETNA_PENDING_WRITE) && rsc->status) || 665 ((status & ETNA_PENDING_READ) && (rsc->status & ETNA_PENDING_WRITE))) { 666 set_foreach(rsc->pending_ctx, entry) { 667 struct etna_context *extctx = (struct etna_context *)entry->key; 668 struct pipe_context *pctx = &extctx->base; 669 670 if (extctx == ctx) 671 continue; 672 673 pctx->flush(pctx, NULL, 0); 674 /* It's safe to clear the status here. If we need to flush it means 675 * either another context had the resource in exclusive (write) use, 676 * or we transition the resource to exclusive use in our context. 677 * In both cases the new status accurately reflects the resource use 678 * after the flush. 679 */ 680 rsc->status = 0; 681 } 682 } 683 684 rsc->status |= status; 685 686 _mesa_set_add(screen->used_resources, rsc); 687 _mesa_set_add(rsc->pending_ctx, ctx); 688 689 mtx_unlock(&screen->lock); 690} 691 692bool 693etna_resource_has_valid_ts(struct etna_resource *rsc) 694{ 695 if (!rsc->ts_bo) 696 return false; 697 698 for (int level = 0; level <= rsc->base.last_level; level++) 699 if (rsc->levels[level].ts_valid) 700 return true; 701 702 return false; 703} 704 705void 706etna_resource_screen_init(struct pipe_screen *pscreen) 707{ 708 pscreen->can_create_resource = etna_screen_can_create_resource; 709 pscreen->resource_create = etna_resource_create; 710 pscreen->resource_create_with_modifiers = etna_resource_create_modifiers; 711 pscreen->resource_from_handle = etna_resource_from_handle; 712 pscreen->resource_get_handle = etna_resource_get_handle; 713 pscreen->resource_changed = etna_resource_changed; 714 pscreen->resource_destroy = etna_resource_destroy; 715} 716