1/* 2 * Copyright © 2017 Intel Corporation 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 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR 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 OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23/** 24 * @file iris_resource.c 25 * 26 * Resources are images, buffers, and other objects used by the GPU. 27 * 28 * XXX: explain resources 29 */ 30 31#include <stdio.h> 32#include <errno.h> 33#include "pipe/p_defines.h" 34#include "pipe/p_state.h" 35#include "pipe/p_context.h" 36#include "pipe/p_screen.h" 37#include "util/os_memory.h" 38#include "util/u_cpu_detect.h" 39#include "util/u_inlines.h" 40#include "util/format/u_format.h" 41#include "util/u_memory.h" 42#include "util/u_threaded_context.h" 43#include "util/u_transfer.h" 44#include "util/u_transfer_helper.h" 45#include "util/u_upload_mgr.h" 46#include "util/ralloc.h" 47#include "iris_batch.h" 48#include "iris_context.h" 49#include "iris_resource.h" 50#include "iris_screen.h" 51#include "intel/common/intel_aux_map.h" 52#include "intel/dev/intel_debug.h" 53#include "isl/isl.h" 54#include "drm-uapi/drm_fourcc.h" 55#include "drm-uapi/i915_drm.h" 56 57enum modifier_priority { 58 MODIFIER_PRIORITY_INVALID = 0, 59 MODIFIER_PRIORITY_LINEAR, 60 MODIFIER_PRIORITY_X, 61 MODIFIER_PRIORITY_Y, 62 MODIFIER_PRIORITY_Y_CCS, 63 MODIFIER_PRIORITY_Y_GFX12_RC_CCS, 64 MODIFIER_PRIORITY_Y_GFX12_RC_CCS_CC, 65}; 66 67static const uint64_t priority_to_modifier[] = { 68 [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID, 69 [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR, 70 [MODIFIER_PRIORITY_X] = I915_FORMAT_MOD_X_TILED, 71 [MODIFIER_PRIORITY_Y] = I915_FORMAT_MOD_Y_TILED, 72 [MODIFIER_PRIORITY_Y_CCS] = I915_FORMAT_MOD_Y_TILED_CCS, 73 [MODIFIER_PRIORITY_Y_GFX12_RC_CCS] = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, 74 [MODIFIER_PRIORITY_Y_GFX12_RC_CCS_CC] = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, 75}; 76 77static bool 78modifier_is_supported(const struct intel_device_info *devinfo, 79 enum pipe_format pfmt, unsigned bind, 80 uint64_t modifier) 81{ 82 /* Check for basic device support. */ 83 switch (modifier) { 84 case DRM_FORMAT_MOD_LINEAR: 85 case I915_FORMAT_MOD_X_TILED: 86 break; 87 case I915_FORMAT_MOD_Y_TILED: 88 if (devinfo->ver <= 8 && (bind & PIPE_BIND_SCANOUT)) 89 return false; 90 if (devinfo->verx10 >= 125) 91 return false; 92 break; 93 case I915_FORMAT_MOD_Y_TILED_CCS: 94 if (devinfo->ver <= 8 || devinfo->ver >= 12) 95 return false; 96 break; 97 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 98 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 99 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 100 if (devinfo->verx10 != 120) 101 return false; 102 break; 103 case DRM_FORMAT_MOD_INVALID: 104 default: 105 return false; 106 } 107 108 /* Check remaining requirements. */ 109 switch (modifier) { 110 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 111 if (pfmt != PIPE_FORMAT_BGRA8888_UNORM && 112 pfmt != PIPE_FORMAT_RGBA8888_UNORM && 113 pfmt != PIPE_FORMAT_BGRX8888_UNORM && 114 pfmt != PIPE_FORMAT_RGBX8888_UNORM && 115 pfmt != PIPE_FORMAT_NV12 && 116 pfmt != PIPE_FORMAT_P010 && 117 pfmt != PIPE_FORMAT_P012 && 118 pfmt != PIPE_FORMAT_P016 && 119 pfmt != PIPE_FORMAT_YUYV && 120 pfmt != PIPE_FORMAT_UYVY) { 121 return false; 122 } 123 break; 124 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 125 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 126 case I915_FORMAT_MOD_Y_TILED_CCS: { 127 if (INTEL_DEBUG(DEBUG_NO_RBC)) 128 return false; 129 130 enum isl_format rt_format = 131 iris_format_for_usage(devinfo, pfmt, 132 ISL_SURF_USAGE_RENDER_TARGET_BIT).fmt; 133 134 if (rt_format == ISL_FORMAT_UNSUPPORTED || 135 !isl_format_supports_ccs_e(devinfo, rt_format)) 136 return false; 137 break; 138 } 139 default: 140 break; 141 } 142 143 return true; 144} 145 146static uint64_t 147select_best_modifier(struct intel_device_info *devinfo, 148 const struct pipe_resource *templ, 149 const uint64_t *modifiers, 150 int count) 151{ 152 enum modifier_priority prio = MODIFIER_PRIORITY_INVALID; 153 154 for (int i = 0; i < count; i++) { 155 if (!modifier_is_supported(devinfo, templ->format, templ->bind, 156 modifiers[i])) 157 continue; 158 159 switch (modifiers[i]) { 160 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 161 prio = MAX2(prio, MODIFIER_PRIORITY_Y_GFX12_RC_CCS_CC); 162 break; 163 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 164 prio = MAX2(prio, MODIFIER_PRIORITY_Y_GFX12_RC_CCS); 165 break; 166 case I915_FORMAT_MOD_Y_TILED_CCS: 167 prio = MAX2(prio, MODIFIER_PRIORITY_Y_CCS); 168 break; 169 case I915_FORMAT_MOD_Y_TILED: 170 prio = MAX2(prio, MODIFIER_PRIORITY_Y); 171 break; 172 case I915_FORMAT_MOD_X_TILED: 173 prio = MAX2(prio, MODIFIER_PRIORITY_X); 174 break; 175 case DRM_FORMAT_MOD_LINEAR: 176 prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR); 177 break; 178 case DRM_FORMAT_MOD_INVALID: 179 default: 180 break; 181 } 182 } 183 184 return priority_to_modifier[prio]; 185} 186 187static inline bool is_modifier_external_only(enum pipe_format pfmt, 188 uint64_t modifier) 189{ 190 /* Only allow external usage for the following cases: YUV formats 191 * and the media-compression modifier. The render engine lacks 192 * support for rendering to a media-compressed surface if the 193 * compression ratio is large enough. By requiring external usage 194 * of media-compressed surfaces, resolves are avoided. 195 */ 196 return util_format_is_yuv(pfmt) || 197 modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; 198} 199 200static void 201iris_query_dmabuf_modifiers(struct pipe_screen *pscreen, 202 enum pipe_format pfmt, 203 int max, 204 uint64_t *modifiers, 205 unsigned int *external_only, 206 int *count) 207{ 208 struct iris_screen *screen = (void *) pscreen; 209 const struct intel_device_info *devinfo = &screen->devinfo; 210 211 uint64_t all_modifiers[] = { 212 DRM_FORMAT_MOD_LINEAR, 213 I915_FORMAT_MOD_X_TILED, 214 I915_FORMAT_MOD_Y_TILED, 215 I915_FORMAT_MOD_Y_TILED_CCS, 216 I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, 217 I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS, 218 I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, 219 }; 220 221 int supported_mods = 0; 222 223 for (int i = 0; i < ARRAY_SIZE(all_modifiers); i++) { 224 if (!modifier_is_supported(devinfo, pfmt, 0, all_modifiers[i])) 225 continue; 226 227 if (supported_mods < max) { 228 if (modifiers) 229 modifiers[supported_mods] = all_modifiers[i]; 230 231 if (external_only) { 232 external_only[supported_mods] = 233 is_modifier_external_only(pfmt, all_modifiers[i]); 234 } 235 } 236 237 supported_mods++; 238 } 239 240 *count = supported_mods; 241} 242 243static bool 244iris_is_dmabuf_modifier_supported(struct pipe_screen *pscreen, 245 uint64_t modifier, enum pipe_format pfmt, 246 bool *external_only) 247{ 248 struct iris_screen *screen = (void *) pscreen; 249 const struct intel_device_info *devinfo = &screen->devinfo; 250 251 if (modifier_is_supported(devinfo, pfmt, 0, modifier)) { 252 if (external_only) 253 *external_only = is_modifier_external_only(pfmt, modifier); 254 255 return true; 256 } 257 258 return false; 259} 260 261static unsigned int 262iris_get_dmabuf_modifier_planes(struct pipe_screen *pscreen, uint64_t modifier, 263 enum pipe_format format) 264{ 265 unsigned int planes = util_format_get_num_planes(format); 266 267 switch (modifier) { 268 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 269 return 3; 270 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 271 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 272 case I915_FORMAT_MOD_Y_TILED_CCS: 273 return 2 * planes; 274 default: 275 return planes; 276 } 277} 278 279enum isl_format 280iris_image_view_get_format(struct iris_context *ice, 281 const struct pipe_image_view *img) 282{ 283 struct iris_screen *screen = (struct iris_screen *)ice->ctx.screen; 284 const struct intel_device_info *devinfo = &screen->devinfo; 285 286 isl_surf_usage_flags_t usage = ISL_SURF_USAGE_STORAGE_BIT; 287 enum isl_format isl_fmt = 288 iris_format_for_usage(devinfo, img->format, usage).fmt; 289 290 if (img->shader_access & PIPE_IMAGE_ACCESS_READ) { 291 /* On Gfx8, try to use typed surfaces reads (which support a 292 * limited number of formats), and if not possible, fall back 293 * to untyped reads. 294 */ 295 if (devinfo->ver == 8 && 296 !isl_has_matching_typed_storage_image_format(devinfo, isl_fmt)) 297 return ISL_FORMAT_RAW; 298 else 299 return isl_lower_storage_image_format(devinfo, isl_fmt); 300 } 301 302 return isl_fmt; 303} 304 305static struct pipe_memory_object * 306iris_memobj_create_from_handle(struct pipe_screen *pscreen, 307 struct winsys_handle *whandle, 308 bool dedicated) 309{ 310 struct iris_screen *screen = (struct iris_screen *)pscreen; 311 struct iris_memory_object *memobj = CALLOC_STRUCT(iris_memory_object); 312 struct iris_bo *bo; 313 314 if (!memobj) 315 return NULL; 316 317 switch (whandle->type) { 318 case WINSYS_HANDLE_TYPE_SHARED: 319 bo = iris_bo_gem_create_from_name(screen->bufmgr, "winsys image", 320 whandle->handle); 321 break; 322 case WINSYS_HANDLE_TYPE_FD: 323 bo = iris_bo_import_dmabuf(screen->bufmgr, whandle->handle); 324 break; 325 default: 326 unreachable("invalid winsys handle type"); 327 } 328 329 if (!bo) { 330 free(memobj); 331 return NULL; 332 } 333 334 memobj->b.dedicated = dedicated; 335 memobj->bo = bo; 336 memobj->format = whandle->format; 337 memobj->stride = whandle->stride; 338 339 return &memobj->b; 340} 341 342static void 343iris_memobj_destroy(struct pipe_screen *pscreen, 344 struct pipe_memory_object *pmemobj) 345{ 346 struct iris_memory_object *memobj = (struct iris_memory_object *)pmemobj; 347 348 iris_bo_unreference(memobj->bo); 349 free(memobj); 350} 351 352struct pipe_resource * 353iris_resource_get_separate_stencil(struct pipe_resource *p_res) 354{ 355 /* For packed depth-stencil, we treat depth as the primary resource 356 * and store S8 as the "second plane" resource. 357 */ 358 if (p_res->next && p_res->next->format == PIPE_FORMAT_S8_UINT) 359 return p_res->next; 360 361 return NULL; 362 363} 364 365static void 366iris_resource_set_separate_stencil(struct pipe_resource *p_res, 367 struct pipe_resource *stencil) 368{ 369 assert(util_format_has_depth(util_format_description(p_res->format))); 370 pipe_resource_reference(&p_res->next, stencil); 371} 372 373void 374iris_get_depth_stencil_resources(struct pipe_resource *res, 375 struct iris_resource **out_z, 376 struct iris_resource **out_s) 377{ 378 if (!res) { 379 *out_z = NULL; 380 *out_s = NULL; 381 return; 382 } 383 384 if (res->format != PIPE_FORMAT_S8_UINT) { 385 *out_z = (void *) res; 386 *out_s = (void *) iris_resource_get_separate_stencil(res); 387 } else { 388 *out_z = NULL; 389 *out_s = (void *) res; 390 } 391} 392 393void 394iris_resource_disable_aux(struct iris_resource *res) 395{ 396 iris_bo_unreference(res->aux.bo); 397 iris_bo_unreference(res->aux.clear_color_bo); 398 free(res->aux.state); 399 400 res->aux.usage = ISL_AUX_USAGE_NONE; 401 res->aux.possible_usages = 1 << ISL_AUX_USAGE_NONE; 402 res->aux.sampler_usages = 1 << ISL_AUX_USAGE_NONE; 403 res->aux.surf.size_B = 0; 404 res->aux.bo = NULL; 405 res->aux.extra_aux.surf.size_B = 0; 406 res->aux.clear_color_bo = NULL; 407 res->aux.state = NULL; 408} 409 410static uint32_t 411iris_resource_alloc_flags(const struct iris_screen *screen, 412 const struct pipe_resource *templ) 413{ 414 if (templ->flags & IRIS_RESOURCE_FLAG_DEVICE_MEM) 415 return 0; 416 417 uint32_t flags = 0; 418 419 switch (templ->usage) { 420 case PIPE_USAGE_STAGING: 421 flags |= BO_ALLOC_SMEM | BO_ALLOC_COHERENT; 422 break; 423 case PIPE_USAGE_STREAM: 424 flags |= BO_ALLOC_SMEM; 425 break; 426 case PIPE_USAGE_DYNAMIC: 427 case PIPE_USAGE_DEFAULT: 428 case PIPE_USAGE_IMMUTABLE: 429 /* Use LMEM for these if possible */ 430 break; 431 } 432 433 /* Scanout and shared buffers need to be WC (shared because they might be 434 * used for scanout) 435 */ 436 if (templ->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_SHARED)) 437 flags |= BO_ALLOC_SCANOUT; 438 439 if (templ->flags & (PIPE_RESOURCE_FLAG_MAP_COHERENT | 440 PIPE_RESOURCE_FLAG_MAP_PERSISTENT)) 441 flags |= BO_ALLOC_SMEM; 442 443 if ((templ->bind & PIPE_BIND_SHARED) || 444 util_format_get_num_planes(templ->format) > 1) 445 flags |= BO_ALLOC_NO_SUBALLOC; 446 447 return flags; 448} 449 450static void 451iris_resource_destroy(struct pipe_screen *screen, 452 struct pipe_resource *p_res) 453{ 454 struct iris_resource *res = (struct iris_resource *) p_res; 455 456 if (p_res->target == PIPE_BUFFER) 457 util_range_destroy(&res->valid_buffer_range); 458 459 iris_resource_disable_aux(res); 460 461 threaded_resource_deinit(p_res); 462 iris_bo_unreference(res->bo); 463 iris_pscreen_unref(res->orig_screen); 464 465 free(res); 466} 467 468static struct iris_resource * 469iris_alloc_resource(struct pipe_screen *pscreen, 470 const struct pipe_resource *templ) 471{ 472 struct iris_resource *res = calloc(1, sizeof(struct iris_resource)); 473 if (!res) 474 return NULL; 475 476 res->base.b = *templ; 477 res->base.b.screen = pscreen; 478 res->orig_screen = iris_pscreen_ref(pscreen); 479 pipe_reference_init(&res->base.b.reference, 1); 480 threaded_resource_init(&res->base.b); 481 482 res->aux.possible_usages = 1 << ISL_AUX_USAGE_NONE; 483 res->aux.sampler_usages = 1 << ISL_AUX_USAGE_NONE; 484 485 if (templ->target == PIPE_BUFFER) 486 util_range_init(&res->valid_buffer_range); 487 488 return res; 489} 490 491unsigned 492iris_get_num_logical_layers(const struct iris_resource *res, unsigned level) 493{ 494 if (res->surf.dim == ISL_SURF_DIM_3D) 495 return minify(res->surf.logical_level0_px.depth, level); 496 else 497 return res->surf.logical_level0_px.array_len; 498} 499 500static enum isl_aux_state ** 501create_aux_state_map(struct iris_resource *res, enum isl_aux_state initial) 502{ 503 assert(res->aux.state == NULL); 504 505 uint32_t total_slices = 0; 506 for (uint32_t level = 0; level < res->surf.levels; level++) 507 total_slices += iris_get_num_logical_layers(res, level); 508 509 const size_t per_level_array_size = 510 res->surf.levels * sizeof(enum isl_aux_state *); 511 512 /* We're going to allocate a single chunk of data for both the per-level 513 * reference array and the arrays of aux_state. This makes cleanup 514 * significantly easier. 515 */ 516 const size_t total_size = 517 per_level_array_size + total_slices * sizeof(enum isl_aux_state); 518 519 void *data = malloc(total_size); 520 if (!data) 521 return NULL; 522 523 enum isl_aux_state **per_level_arr = data; 524 enum isl_aux_state *s = data + per_level_array_size; 525 for (uint32_t level = 0; level < res->surf.levels; level++) { 526 per_level_arr[level] = s; 527 const unsigned level_layers = iris_get_num_logical_layers(res, level); 528 for (uint32_t a = 0; a < level_layers; a++) 529 *(s++) = initial; 530 } 531 assert((void *)s == data + total_size); 532 533 return per_level_arr; 534} 535 536static unsigned 537iris_get_aux_clear_color_state_size(struct iris_screen *screen) 538{ 539 const struct intel_device_info *devinfo = &screen->devinfo; 540 return devinfo->ver >= 10 ? screen->isl_dev.ss.clear_color_state_size : 0; 541} 542 543static void 544map_aux_addresses(struct iris_screen *screen, struct iris_resource *res, 545 enum isl_format format, unsigned plane) 546{ 547 const struct intel_device_info *devinfo = &screen->devinfo; 548 if (devinfo->ver >= 12 && isl_aux_usage_has_ccs(res->aux.usage)) { 549 void *aux_map_ctx = iris_bufmgr_get_aux_map_context(screen->bufmgr); 550 assert(aux_map_ctx); 551 const unsigned aux_offset = res->aux.extra_aux.surf.size_B > 0 ? 552 res->aux.extra_aux.offset : res->aux.offset; 553 const uint64_t format_bits = 554 intel_aux_map_format_bits(res->surf.tiling, format, plane); 555 intel_aux_map_add_mapping(aux_map_ctx, res->bo->address + res->offset, 556 res->aux.bo->address + aux_offset, 557 res->surf.size_B, format_bits); 558 res->bo->aux_map_address = res->aux.bo->address; 559 } 560} 561 562static bool 563want_ccs_e_for_format(const struct intel_device_info *devinfo, 564 enum isl_format format) 565{ 566 if (!isl_format_supports_ccs_e(devinfo, format)) 567 return false; 568 569 const struct isl_format_layout *fmtl = isl_format_get_layout(format); 570 571 /* CCS_E seems to significantly hurt performance with 32-bit floating 572 * point formats. For example, Paraview's "Wavelet Volume" case uses 573 * both R32_FLOAT and R32G32B32A32_FLOAT, and enabling CCS_E for those 574 * formats causes a 62% FPS drop. 575 * 576 * However, many benchmarks seem to use 16-bit float with no issues. 577 */ 578 if (fmtl->channels.r.bits == 32 && fmtl->channels.r.type == ISL_SFLOAT) 579 return false; 580 581 return true; 582} 583 584static enum isl_surf_dim 585target_to_isl_surf_dim(enum pipe_texture_target target) 586{ 587 switch (target) { 588 case PIPE_BUFFER: 589 case PIPE_TEXTURE_1D: 590 case PIPE_TEXTURE_1D_ARRAY: 591 return ISL_SURF_DIM_1D; 592 case PIPE_TEXTURE_2D: 593 case PIPE_TEXTURE_CUBE: 594 case PIPE_TEXTURE_RECT: 595 case PIPE_TEXTURE_2D_ARRAY: 596 case PIPE_TEXTURE_CUBE_ARRAY: 597 return ISL_SURF_DIM_2D; 598 case PIPE_TEXTURE_3D: 599 return ISL_SURF_DIM_3D; 600 case PIPE_MAX_TEXTURE_TYPES: 601 break; 602 } 603 unreachable("invalid texture type"); 604} 605 606static bool 607iris_resource_configure_main(const struct iris_screen *screen, 608 struct iris_resource *res, 609 const struct pipe_resource *templ, 610 uint64_t modifier, uint32_t row_pitch_B) 611{ 612 res->mod_info = isl_drm_modifier_get_info(modifier); 613 614 if (modifier != DRM_FORMAT_MOD_INVALID && res->mod_info == NULL) 615 return false; 616 617 isl_tiling_flags_t tiling_flags = 0; 618 619 if (res->mod_info != NULL) { 620 tiling_flags = 1 << res->mod_info->tiling; 621 } else if (templ->usage == PIPE_USAGE_STAGING || 622 templ->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR)) { 623 tiling_flags = ISL_TILING_LINEAR_BIT; 624 } else if (templ->bind & PIPE_BIND_SCANOUT) { 625 tiling_flags = screen->devinfo.has_tiling_uapi ? 626 ISL_TILING_X_BIT : ISL_TILING_LINEAR_BIT; 627 } else { 628 tiling_flags = ISL_TILING_ANY_MASK; 629 } 630 631 isl_surf_usage_flags_t usage = 0; 632 633 if (templ->usage == PIPE_USAGE_STAGING) 634 usage |= ISL_SURF_USAGE_STAGING_BIT; 635 636 if (templ->bind & PIPE_BIND_RENDER_TARGET) 637 usage |= ISL_SURF_USAGE_RENDER_TARGET_BIT; 638 639 if (templ->bind & PIPE_BIND_SAMPLER_VIEW) 640 usage |= ISL_SURF_USAGE_TEXTURE_BIT; 641 642 if (templ->bind & PIPE_BIND_SHADER_IMAGE) 643 usage |= ISL_SURF_USAGE_STORAGE_BIT; 644 645 if (templ->bind & PIPE_BIND_SCANOUT) 646 usage |= ISL_SURF_USAGE_DISPLAY_BIT; 647 648 if (templ->target == PIPE_TEXTURE_CUBE || 649 templ->target == PIPE_TEXTURE_CUBE_ARRAY) { 650 usage |= ISL_SURF_USAGE_CUBE_BIT; 651 } 652 653 if (templ->usage != PIPE_USAGE_STAGING && 654 util_format_is_depth_or_stencil(templ->format)) { 655 656 /* Should be handled by u_transfer_helper */ 657 assert(!util_format_is_depth_and_stencil(templ->format)); 658 659 usage |= templ->format == PIPE_FORMAT_S8_UINT ? 660 ISL_SURF_USAGE_STENCIL_BIT : ISL_SURF_USAGE_DEPTH_BIT; 661 } 662 663 const enum isl_format format = 664 iris_format_for_usage(&screen->devinfo, templ->format, usage).fmt; 665 666 const struct isl_surf_init_info init_info = { 667 .dim = target_to_isl_surf_dim(templ->target), 668 .format = format, 669 .width = templ->width0, 670 .height = templ->height0, 671 .depth = templ->depth0, 672 .levels = templ->last_level + 1, 673 .array_len = templ->array_size, 674 .samples = MAX2(templ->nr_samples, 1), 675 .min_alignment_B = 0, 676 .row_pitch_B = row_pitch_B, 677 .usage = usage, 678 .tiling_flags = tiling_flags 679 }; 680 681 if (!isl_surf_init_s(&screen->isl_dev, &res->surf, &init_info)) 682 return false; 683 684 res->internal_format = templ->format; 685 686 return true; 687} 688 689static bool 690iris_get_ccs_surf(const struct isl_device *dev, 691 const struct isl_surf *surf, 692 struct isl_surf *aux_surf, 693 struct isl_surf *extra_aux_surf, 694 uint32_t row_pitch_B) 695{ 696 assert(extra_aux_surf->size_B == 0); 697 698 struct isl_surf *ccs_surf; 699 const struct isl_surf *hiz_or_mcs_surf; 700 if (aux_surf->size_B > 0) { 701 assert(aux_surf->usage & (ISL_SURF_USAGE_HIZ_BIT | 702 ISL_SURF_USAGE_MCS_BIT)); 703 hiz_or_mcs_surf = aux_surf; 704 ccs_surf = extra_aux_surf; 705 } else { 706 hiz_or_mcs_surf = NULL; 707 ccs_surf = aux_surf; 708 } 709 710 return isl_surf_get_ccs_surf(dev, surf, hiz_or_mcs_surf, 711 ccs_surf, row_pitch_B); 712} 713 714/** 715 * Configure aux for the resource, but don't allocate it. For images which 716 * might be shared with modifiers, we must allocate the image and aux data in 717 * a single bo. 718 * 719 * Returns false on unexpected error (e.g. allocation failed, or invalid 720 * configuration result). 721 */ 722static bool 723iris_resource_configure_aux(struct iris_screen *screen, 724 struct iris_resource *res, bool imported) 725{ 726 const struct intel_device_info *devinfo = &screen->devinfo; 727 728 /* Try to create the auxiliary surfaces allowed by the modifier or by 729 * the user if no modifier is specified. 730 */ 731 assert(!res->mod_info || 732 res->mod_info->aux_usage == ISL_AUX_USAGE_NONE || 733 res->mod_info->aux_usage == ISL_AUX_USAGE_CCS_E || 734 res->mod_info->aux_usage == ISL_AUX_USAGE_GFX12_CCS_E || 735 res->mod_info->aux_usage == ISL_AUX_USAGE_MC); 736 737 const bool has_mcs = !res->mod_info && 738 isl_surf_get_mcs_surf(&screen->isl_dev, &res->surf, &res->aux.surf); 739 740 const bool has_hiz = !res->mod_info && !INTEL_DEBUG(DEBUG_NO_HIZ) && 741 isl_surf_get_hiz_surf(&screen->isl_dev, &res->surf, &res->aux.surf); 742 743 const bool has_ccs = 744 ((!res->mod_info && !INTEL_DEBUG(DEBUG_NO_RBC)) || 745 (res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE)) && 746 iris_get_ccs_surf(&screen->isl_dev, &res->surf, &res->aux.surf, 747 &res->aux.extra_aux.surf, 0); 748 749 /* Having both HIZ and MCS is impossible. */ 750 assert(!has_mcs || !has_hiz); 751 752 if (res->mod_info && has_ccs) { 753 /* Only allow a CCS modifier if the aux was created successfully. */ 754 res->aux.possible_usages |= 1 << res->mod_info->aux_usage; 755 } else if (has_mcs) { 756 res->aux.possible_usages |= 757 1 << (has_ccs ? ISL_AUX_USAGE_MCS_CCS : ISL_AUX_USAGE_MCS); 758 } else if (has_hiz) { 759 if (!has_ccs) { 760 res->aux.possible_usages |= 1 << ISL_AUX_USAGE_HIZ; 761 } else if (res->surf.samples == 1 && 762 (res->surf.usage & ISL_SURF_USAGE_TEXTURE_BIT)) { 763 /* If this resource is single-sampled and will be used as a texture, 764 * put the HiZ surface in write-through mode so that we can sample 765 * from it. 766 */ 767 res->aux.possible_usages |= 1 << ISL_AUX_USAGE_HIZ_CCS_WT; 768 } else { 769 res->aux.possible_usages |= 1 << ISL_AUX_USAGE_HIZ_CCS; 770 } 771 } else if (has_ccs && isl_surf_usage_is_stencil(res->surf.usage)) { 772 res->aux.possible_usages |= 1 << ISL_AUX_USAGE_STC_CCS; 773 } else if (has_ccs) { 774 if (want_ccs_e_for_format(devinfo, res->surf.format)) { 775 res->aux.possible_usages |= devinfo->ver < 12 ? 776 1 << ISL_AUX_USAGE_CCS_E : 1 << ISL_AUX_USAGE_GFX12_CCS_E; 777 } else if (isl_format_supports_ccs_d(devinfo, res->surf.format)) { 778 res->aux.possible_usages |= 1 << ISL_AUX_USAGE_CCS_D; 779 } 780 } 781 782 res->aux.usage = util_last_bit(res->aux.possible_usages) - 1; 783 784 if (!has_hiz || iris_sample_with_depth_aux(devinfo, res)) 785 res->aux.sampler_usages = res->aux.possible_usages; 786 787 enum isl_aux_state initial_state; 788 assert(!res->aux.bo); 789 790 switch (res->aux.usage) { 791 case ISL_AUX_USAGE_NONE: 792 /* Update relevant fields to indicate that aux is disabled. */ 793 iris_resource_disable_aux(res); 794 795 /* Having no aux buffer is only okay if there's no modifier with aux. */ 796 return !res->mod_info || res->mod_info->aux_usage == ISL_AUX_USAGE_NONE; 797 case ISL_AUX_USAGE_HIZ: 798 case ISL_AUX_USAGE_HIZ_CCS: 799 case ISL_AUX_USAGE_HIZ_CCS_WT: 800 initial_state = ISL_AUX_STATE_AUX_INVALID; 801 break; 802 case ISL_AUX_USAGE_MCS: 803 case ISL_AUX_USAGE_MCS_CCS: 804 /* The Ivybridge PRM, Vol 2 Part 1 p326 says: 805 * 806 * "When MCS buffer is enabled and bound to MSRT, it is required 807 * that it is cleared prior to any rendering." 808 * 809 * Since we only use the MCS buffer for rendering, we just clear it 810 * immediately on allocation. The clear value for MCS buffers is all 811 * 1's, so we simply memset it to 0xff. 812 */ 813 initial_state = ISL_AUX_STATE_CLEAR; 814 break; 815 case ISL_AUX_USAGE_CCS_D: 816 case ISL_AUX_USAGE_CCS_E: 817 case ISL_AUX_USAGE_GFX12_CCS_E: 818 case ISL_AUX_USAGE_STC_CCS: 819 case ISL_AUX_USAGE_MC: 820 /* When CCS_E is used, we need to ensure that the CCS starts off in 821 * a valid state. From the Sky Lake PRM, "MCS Buffer for Render 822 * Target(s)": 823 * 824 * "If Software wants to enable Color Compression without Fast 825 * clear, Software needs to initialize MCS with zeros." 826 * 827 * A CCS value of 0 indicates that the corresponding block is in the 828 * pass-through state which is what we want. 829 * 830 * For CCS_D, do the same thing. On Gfx9+, this avoids having any 831 * undefined bits in the aux buffer. 832 */ 833 if (imported) { 834 assert(res->aux.usage != ISL_AUX_USAGE_STC_CCS); 835 initial_state = 836 isl_drm_modifier_get_default_aux_state(res->mod_info->modifier); 837 } else { 838 initial_state = ISL_AUX_STATE_PASS_THROUGH; 839 } 840 break; 841 default: 842 unreachable("Unsupported aux mode"); 843 } 844 845 /* Create the aux_state for the auxiliary buffer. */ 846 res->aux.state = create_aux_state_map(res, initial_state); 847 if (!res->aux.state) 848 return false; 849 850 return true; 851} 852 853/** 854 * Initialize the aux buffer contents. 855 * 856 * Returns false on unexpected error (e.g. mapping a BO failed). 857 */ 858static bool 859iris_resource_init_aux_buf(struct iris_resource *res, 860 unsigned clear_color_state_size) 861{ 862 void *map = iris_bo_map(NULL, res->aux.bo, MAP_WRITE | MAP_RAW); 863 864 if (!map) 865 return false; 866 867 if (iris_resource_get_aux_state(res, 0, 0) != ISL_AUX_STATE_AUX_INVALID) { 868 /* See iris_resource_configure_aux for the memset_value rationale. */ 869 uint8_t memset_value = isl_aux_usage_has_mcs(res->aux.usage) ? 0xFF : 0; 870 memset((char*)map + res->aux.offset, memset_value, 871 res->aux.surf.size_B); 872 } 873 874 memset((char*)map + res->aux.extra_aux.offset, 875 0, res->aux.extra_aux.surf.size_B); 876 877 /* Zero the indirect clear color to match ::fast_clear_color. */ 878 memset((char *)map + res->aux.clear_color_offset, 0, 879 clear_color_state_size); 880 881 iris_bo_unmap(res->aux.bo); 882 883 if (clear_color_state_size > 0) { 884 res->aux.clear_color_bo = res->aux.bo; 885 iris_bo_reference(res->aux.clear_color_bo); 886 } 887 888 return true; 889} 890 891static void 892import_aux_info(struct iris_resource *res, 893 const struct iris_resource *aux_res) 894{ 895 assert(aux_res->aux.surf.row_pitch_B && aux_res->aux.offset); 896 assert(res->bo == aux_res->aux.bo); 897 assert(res->aux.surf.row_pitch_B == aux_res->aux.surf.row_pitch_B); 898 assert(res->bo->size >= aux_res->aux.offset + res->aux.surf.size_B); 899 900 iris_bo_reference(aux_res->aux.bo); 901 res->aux.bo = aux_res->aux.bo; 902 res->aux.offset = aux_res->aux.offset; 903} 904 905static void 906iris_resource_finish_aux_import(struct pipe_screen *pscreen, 907 struct iris_resource *res) 908{ 909 struct iris_screen *screen = (struct iris_screen *)pscreen; 910 911 /* Create an array of resources. Combining main and aux planes is easier 912 * with indexing as opposed to scanning the linked list. 913 */ 914 struct iris_resource *r[4] = { NULL, }; 915 unsigned num_planes = 0; 916 unsigned num_main_planes = 0; 917 for (struct pipe_resource *p_res = &res->base.b; p_res; p_res = p_res->next) { 918 r[num_planes] = (struct iris_resource *)p_res; 919 num_main_planes += r[num_planes++]->bo != NULL; 920 } 921 922 /* Get an ISL format to use with the aux-map. */ 923 enum isl_format format; 924 switch (res->external_format) { 925 case PIPE_FORMAT_NV12: format = ISL_FORMAT_PLANAR_420_8; break; 926 case PIPE_FORMAT_P010: format = ISL_FORMAT_PLANAR_420_10; break; 927 case PIPE_FORMAT_P012: format = ISL_FORMAT_PLANAR_420_12; break; 928 case PIPE_FORMAT_P016: format = ISL_FORMAT_PLANAR_420_16; break; 929 case PIPE_FORMAT_YUYV: format = ISL_FORMAT_YCRCB_NORMAL; break; 930 case PIPE_FORMAT_UYVY: format = ISL_FORMAT_YCRCB_SWAPY; break; 931 default: format = res->surf.format; break; 932 } 933 934 /* Combine main and aux plane information. */ 935 switch (res->mod_info->modifier) { 936 case I915_FORMAT_MOD_Y_TILED_CCS: 937 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 938 assert(num_main_planes == 1 && num_planes == 2); 939 import_aux_info(r[0], r[1]); 940 map_aux_addresses(screen, r[0], format, 0); 941 942 /* Add on a clear color BO. 943 * 944 * Also add some padding to make sure the fast clear color state buffer 945 * starts at a 4K alignment to avoid some unknown issues. See the 946 * matching comment in iris_resource_create_with_modifiers(). 947 */ 948 if (iris_get_aux_clear_color_state_size(screen) > 0) { 949 res->aux.clear_color_bo = 950 iris_bo_alloc(screen->bufmgr, "clear color_buffer", 951 iris_get_aux_clear_color_state_size(screen), 4096, 952 IRIS_MEMZONE_OTHER, BO_ALLOC_ZEROED); 953 } 954 break; 955 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 956 assert(num_main_planes == 1 && num_planes == 3); 957 import_aux_info(r[0], r[1]); 958 map_aux_addresses(screen, r[0], format, 0); 959 960 /* Import the clear color BO. */ 961 iris_bo_reference(r[2]->aux.clear_color_bo); 962 r[0]->aux.clear_color_bo = r[2]->aux.clear_color_bo; 963 r[0]->aux.clear_color_offset = r[2]->aux.clear_color_offset; 964 r[0]->aux.clear_color_unknown = true; 965 break; 966 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 967 if (num_main_planes == 1 && num_planes == 2) { 968 import_aux_info(r[0], r[1]); 969 map_aux_addresses(screen, r[0], format, 0); 970 } else if (num_main_planes == 2 && num_planes == 4) { 971 import_aux_info(r[0], r[2]); 972 import_aux_info(r[1], r[3]); 973 map_aux_addresses(screen, r[0], format, 0); 974 map_aux_addresses(screen, r[1], format, 1); 975 } else { 976 /* Gallium has lowered a single main plane into two. */ 977 assert(num_main_planes == 2 && num_planes == 3); 978 assert(isl_format_is_yuv(format) && !isl_format_is_planar(format)); 979 import_aux_info(r[0], r[2]); 980 import_aux_info(r[1], r[2]); 981 map_aux_addresses(screen, r[0], format, 0); 982 } 983 assert(!isl_aux_usage_has_fast_clears(res->mod_info->aux_usage)); 984 break; 985 default: 986 assert(res->mod_info->aux_usage == ISL_AUX_USAGE_NONE); 987 break; 988 } 989} 990 991static struct pipe_resource * 992iris_resource_create_for_buffer(struct pipe_screen *pscreen, 993 const struct pipe_resource *templ) 994{ 995 struct iris_screen *screen = (struct iris_screen *)pscreen; 996 struct iris_resource *res = iris_alloc_resource(pscreen, templ); 997 998 assert(templ->target == PIPE_BUFFER); 999 assert(templ->height0 <= 1); 1000 assert(templ->depth0 <= 1); 1001 assert(templ->format == PIPE_FORMAT_NONE || 1002 util_format_get_blocksize(templ->format) == 1); 1003 1004 res->internal_format = templ->format; 1005 res->surf.tiling = ISL_TILING_LINEAR; 1006 1007 enum iris_memory_zone memzone = IRIS_MEMZONE_OTHER; 1008 const char *name = templ->target == PIPE_BUFFER ? "buffer" : "miptree"; 1009 if (templ->flags & IRIS_RESOURCE_FLAG_SHADER_MEMZONE) { 1010 memzone = IRIS_MEMZONE_SHADER; 1011 name = "shader kernels"; 1012 } else if (templ->flags & IRIS_RESOURCE_FLAG_SURFACE_MEMZONE) { 1013 memzone = IRIS_MEMZONE_SURFACE; 1014 name = "surface state"; 1015 } else if (templ->flags & IRIS_RESOURCE_FLAG_DYNAMIC_MEMZONE) { 1016 memzone = IRIS_MEMZONE_DYNAMIC; 1017 name = "dynamic state"; 1018 } else if (templ->flags & IRIS_RESOURCE_FLAG_BINDLESS_MEMZONE) { 1019 memzone = IRIS_MEMZONE_BINDLESS; 1020 name = "bindless surface state"; 1021 } 1022 1023 unsigned flags = iris_resource_alloc_flags(screen, templ); 1024 1025 res->bo = 1026 iris_bo_alloc(screen->bufmgr, name, templ->width0, 1, memzone, flags); 1027 1028 if (!res->bo) { 1029 iris_resource_destroy(pscreen, &res->base.b); 1030 return NULL; 1031 } 1032 1033 if (templ->bind & PIPE_BIND_SHARED) { 1034 iris_bo_mark_exported(res->bo); 1035 res->base.is_shared = true; 1036 } 1037 1038 return &res->base.b; 1039} 1040 1041static struct pipe_resource * 1042iris_resource_create_with_modifiers(struct pipe_screen *pscreen, 1043 const struct pipe_resource *templ, 1044 const uint64_t *modifiers, 1045 int modifiers_count) 1046{ 1047 struct iris_screen *screen = (struct iris_screen *)pscreen; 1048 struct intel_device_info *devinfo = &screen->devinfo; 1049 struct iris_resource *res = iris_alloc_resource(pscreen, templ); 1050 1051 if (!res) 1052 return NULL; 1053 1054 uint64_t modifier = 1055 select_best_modifier(devinfo, templ, modifiers, modifiers_count); 1056 1057 if (modifier == DRM_FORMAT_MOD_INVALID && modifiers_count > 0) { 1058 fprintf(stderr, "Unsupported modifier, resource creation failed.\n"); 1059 goto fail; 1060 } 1061 1062 UNUSED const bool isl_surf_created_successfully = 1063 iris_resource_configure_main(screen, res, templ, modifier, 0); 1064 assert(isl_surf_created_successfully); 1065 1066 const char *name = "miptree"; 1067 enum iris_memory_zone memzone = IRIS_MEMZONE_OTHER; 1068 1069 unsigned int flags = iris_resource_alloc_flags(screen, templ); 1070 1071 /* These are for u_upload_mgr buffers only */ 1072 assert(!(templ->flags & (IRIS_RESOURCE_FLAG_SHADER_MEMZONE | 1073 IRIS_RESOURCE_FLAG_SURFACE_MEMZONE | 1074 IRIS_RESOURCE_FLAG_DYNAMIC_MEMZONE | 1075 IRIS_RESOURCE_FLAG_BINDLESS_MEMZONE))); 1076 1077 if (!iris_resource_configure_aux(screen, res, false)) 1078 goto fail; 1079 1080 /* Modifiers require the aux data to be in the same buffer as the main 1081 * surface, but we combine them even when a modifier is not being used. 1082 */ 1083 uint64_t bo_size = res->surf.size_B; 1084 1085 /* Allocate space for the aux buffer. */ 1086 if (res->aux.surf.size_B > 0) { 1087 res->aux.offset = ALIGN(bo_size, res->aux.surf.alignment_B); 1088 bo_size = res->aux.offset + res->aux.surf.size_B; 1089 } 1090 1091 /* Allocate space for the extra aux buffer. */ 1092 if (res->aux.extra_aux.surf.size_B > 0) { 1093 res->aux.extra_aux.offset = 1094 ALIGN(bo_size, res->aux.extra_aux.surf.alignment_B); 1095 bo_size = res->aux.extra_aux.offset + res->aux.extra_aux.surf.size_B; 1096 } 1097 1098 /* Allocate space for the indirect clear color. 1099 * 1100 * Also add some padding to make sure the fast clear color state buffer 1101 * starts at a 4K alignment. We believe that 256B might be enough, but due 1102 * to lack of testing we will leave this as 4K for now. 1103 */ 1104 if (res->aux.surf.size_B > 0) { 1105 res->aux.clear_color_offset = ALIGN(bo_size, 4096); 1106 bo_size = res->aux.clear_color_offset + 1107 iris_get_aux_clear_color_state_size(screen); 1108 } 1109 1110 uint32_t alignment = MAX2(4096, res->surf.alignment_B); 1111 res->bo = 1112 iris_bo_alloc(screen->bufmgr, name, bo_size, alignment, memzone, flags); 1113 1114 if (!res->bo) 1115 goto fail; 1116 1117 if (res->aux.surf.size_B > 0) { 1118 res->aux.bo = res->bo; 1119 iris_bo_reference(res->aux.bo); 1120 unsigned clear_color_state_size = 1121 iris_get_aux_clear_color_state_size(screen); 1122 if (!iris_resource_init_aux_buf(res, clear_color_state_size)) 1123 goto fail; 1124 map_aux_addresses(screen, res, res->surf.format, 0); 1125 } 1126 1127 if (templ->bind & PIPE_BIND_SHARED) { 1128 iris_bo_mark_exported(res->bo); 1129 res->base.is_shared = true; 1130 } 1131 1132 return &res->base.b; 1133 1134fail: 1135 fprintf(stderr, "XXX: resource creation failed\n"); 1136 iris_resource_destroy(pscreen, &res->base.b); 1137 return NULL; 1138} 1139 1140static struct pipe_resource * 1141iris_resource_create(struct pipe_screen *pscreen, 1142 const struct pipe_resource *templ) 1143{ 1144 if (templ->target == PIPE_BUFFER) 1145 return iris_resource_create_for_buffer(pscreen, templ); 1146 else 1147 return iris_resource_create_with_modifiers(pscreen, templ, NULL, 0); 1148} 1149 1150static uint64_t 1151tiling_to_modifier(uint32_t tiling) 1152{ 1153 static const uint64_t map[] = { 1154 [I915_TILING_NONE] = DRM_FORMAT_MOD_LINEAR, 1155 [I915_TILING_X] = I915_FORMAT_MOD_X_TILED, 1156 [I915_TILING_Y] = I915_FORMAT_MOD_Y_TILED, 1157 }; 1158 1159 assert(tiling < ARRAY_SIZE(map)); 1160 1161 return map[tiling]; 1162} 1163 1164static struct pipe_resource * 1165iris_resource_from_user_memory(struct pipe_screen *pscreen, 1166 const struct pipe_resource *templ, 1167 void *user_memory) 1168{ 1169 struct iris_screen *screen = (struct iris_screen *)pscreen; 1170 struct iris_bufmgr *bufmgr = screen->bufmgr; 1171 struct iris_resource *res = iris_alloc_resource(pscreen, templ); 1172 if (!res) 1173 return NULL; 1174 1175 assert(templ->target == PIPE_BUFFER); 1176 1177 res->internal_format = templ->format; 1178 res->base.is_user_ptr = true; 1179 res->bo = iris_bo_create_userptr(bufmgr, "user", 1180 user_memory, templ->width0, 1181 IRIS_MEMZONE_OTHER); 1182 if (!res->bo) { 1183 iris_resource_destroy(pscreen, &res->base.b); 1184 return NULL; 1185 } 1186 1187 util_range_add(&res->base.b, &res->valid_buffer_range, 0, templ->width0); 1188 1189 return &res->base.b; 1190} 1191 1192static bool 1193mod_plane_is_clear_color(uint64_t modifier, uint32_t plane) 1194{ 1195 ASSERTED const struct isl_drm_modifier_info *mod_info = 1196 isl_drm_modifier_get_info(modifier); 1197 assert(mod_info); 1198 1199 switch (modifier) { 1200 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 1201 assert(mod_info->supports_clear_color); 1202 return plane == 2; 1203 default: 1204 assert(!mod_info->supports_clear_color); 1205 return false; 1206 } 1207} 1208 1209static unsigned 1210get_num_planes(const struct pipe_resource *resource) 1211{ 1212 unsigned count = 0; 1213 for (const struct pipe_resource *cur = resource; cur; cur = cur->next) 1214 count++; 1215 1216 return count; 1217} 1218 1219static struct pipe_resource * 1220iris_resource_from_handle(struct pipe_screen *pscreen, 1221 const struct pipe_resource *templ, 1222 struct winsys_handle *whandle, 1223 unsigned usage) 1224{ 1225 assert(templ->target != PIPE_BUFFER); 1226 1227 struct iris_screen *screen = (struct iris_screen *)pscreen; 1228 struct iris_bufmgr *bufmgr = screen->bufmgr; 1229 struct iris_resource *res = iris_alloc_resource(pscreen, templ); 1230 if (!res) 1231 return NULL; 1232 1233 switch (whandle->type) { 1234 case WINSYS_HANDLE_TYPE_FD: 1235 res->bo = iris_bo_import_dmabuf(bufmgr, whandle->handle); 1236 break; 1237 case WINSYS_HANDLE_TYPE_SHARED: 1238 res->bo = iris_bo_gem_create_from_name(bufmgr, "winsys image", 1239 whandle->handle); 1240 break; 1241 default: 1242 unreachable("invalid winsys handle type"); 1243 } 1244 if (!res->bo) 1245 goto fail; 1246 1247 res->offset = whandle->offset; 1248 res->external_format = whandle->format; 1249 1250 /* Create a surface for each plane specified by the external format. */ 1251 if (whandle->plane < util_format_get_num_planes(whandle->format)) { 1252 uint64_t modifier = whandle->modifier; 1253 1254 if (whandle->modifier == DRM_FORMAT_MOD_INVALID) { 1255 /* We don't have a modifier; match whatever GEM_GET_TILING says */ 1256 uint32_t tiling; 1257 iris_gem_get_tiling(res->bo, &tiling); 1258 modifier = tiling_to_modifier(tiling); 1259 } 1260 1261 UNUSED const bool isl_surf_created_successfully = 1262 iris_resource_configure_main(screen, res, templ, modifier, 1263 whandle->stride); 1264 assert(isl_surf_created_successfully); 1265 1266 UNUSED const bool ok = iris_resource_configure_aux(screen, res, true); 1267 assert(ok); 1268 /* The gallium dri layer will create a separate plane resource for the 1269 * aux image. iris_resource_finish_aux_import will merge the separate aux 1270 * parameters back into a single iris_resource. 1271 */ 1272 } else if (mod_plane_is_clear_color(whandle->modifier, whandle->plane)) { 1273 res->aux.clear_color_offset = whandle->offset; 1274 res->aux.clear_color_bo = res->bo; 1275 res->bo = NULL; 1276 } else { 1277 /* Save modifier import information to reconstruct later. After import, 1278 * this will be available under a second image accessible from the main 1279 * image with res->base.next. See iris_resource_finish_aux_import. 1280 */ 1281 res->aux.surf.row_pitch_B = whandle->stride; 1282 res->aux.offset = whandle->offset; 1283 res->aux.bo = res->bo; 1284 res->bo = NULL; 1285 } 1286 1287 if (get_num_planes(&res->base.b) == 1288 iris_get_dmabuf_modifier_planes(pscreen, whandle->modifier, 1289 whandle->format)) { 1290 iris_resource_finish_aux_import(pscreen, res); 1291 } 1292 1293 return &res->base.b; 1294 1295fail: 1296 iris_resource_destroy(pscreen, &res->base.b); 1297 return NULL; 1298} 1299 1300static struct pipe_resource * 1301iris_resource_from_memobj(struct pipe_screen *pscreen, 1302 const struct pipe_resource *templ, 1303 struct pipe_memory_object *pmemobj, 1304 uint64_t offset) 1305{ 1306 struct iris_screen *screen = (struct iris_screen *)pscreen; 1307 struct iris_memory_object *memobj = (struct iris_memory_object *)pmemobj; 1308 struct iris_resource *res = iris_alloc_resource(pscreen, templ); 1309 1310 if (!res) 1311 return NULL; 1312 1313 if (templ->flags & PIPE_RESOURCE_FLAG_TEXTURING_MORE_LIKELY) { 1314 UNUSED const bool isl_surf_created_successfully = 1315 iris_resource_configure_main(screen, res, templ, DRM_FORMAT_MOD_INVALID, 0); 1316 assert(isl_surf_created_successfully); 1317 } 1318 1319 res->bo = memobj->bo; 1320 res->offset = offset; 1321 res->external_format = memobj->format; 1322 1323 iris_bo_reference(memobj->bo); 1324 1325 return &res->base.b; 1326} 1327 1328/* Handle combined depth/stencil with memory objects. 1329 * 1330 * This function is modeled after u_transfer_helper_resource_create. 1331 */ 1332static struct pipe_resource * 1333iris_resource_from_memobj_wrapper(struct pipe_screen *pscreen, 1334 const struct pipe_resource *templ, 1335 struct pipe_memory_object *pmemobj, 1336 uint64_t offset) 1337{ 1338 enum pipe_format format = templ->format; 1339 1340 /* Normal case, no special handling: */ 1341 if (!(util_format_is_depth_and_stencil(format))) 1342 return iris_resource_from_memobj(pscreen, templ, pmemobj, offset); 1343 1344 struct pipe_resource t = *templ; 1345 t.format = util_format_get_depth_only(format); 1346 1347 struct pipe_resource *prsc = 1348 iris_resource_from_memobj(pscreen, &t, pmemobj, offset); 1349 if (!prsc) 1350 return NULL; 1351 1352 struct iris_resource *res = (struct iris_resource *) prsc; 1353 1354 /* Stencil offset in the buffer without aux. */ 1355 uint64_t s_offset = offset + 1356 ALIGN(res->surf.size_B, res->surf.alignment_B); 1357 1358 prsc->format = format; /* frob the format back to the "external" format */ 1359 1360 t.format = PIPE_FORMAT_S8_UINT; 1361 struct pipe_resource *stencil = 1362 iris_resource_from_memobj(pscreen, &t, pmemobj, s_offset); 1363 if (!stencil) { 1364 iris_resource_destroy(pscreen, prsc); 1365 return NULL; 1366 } 1367 1368 iris_resource_set_separate_stencil(prsc, stencil); 1369 return prsc; 1370} 1371 1372static void 1373iris_flush_resource(struct pipe_context *ctx, struct pipe_resource *resource) 1374{ 1375 struct iris_context *ice = (struct iris_context *)ctx; 1376 struct iris_resource *res = (void *) resource; 1377 const struct isl_drm_modifier_info *mod = res->mod_info; 1378 1379 iris_resource_prepare_access(ice, res, 1380 0, INTEL_REMAINING_LEVELS, 1381 0, INTEL_REMAINING_LAYERS, 1382 mod ? mod->aux_usage : ISL_AUX_USAGE_NONE, 1383 mod ? mod->supports_clear_color : false); 1384 1385 if (!res->mod_info && res->aux.usage != ISL_AUX_USAGE_NONE) { 1386 /* flush_resource may be used to prepare an image for sharing external 1387 * to the driver (e.g. via eglCreateImage). To account for this, make 1388 * sure to get rid of any compression that a consumer wouldn't know how 1389 * to handle. 1390 */ 1391 for (int i = 0; i < IRIS_BATCH_COUNT; i++) { 1392 if (iris_batch_references(&ice->batches[i], res->bo)) 1393 iris_batch_flush(&ice->batches[i]); 1394 } 1395 1396 iris_resource_disable_aux(res); 1397 } 1398} 1399 1400/** 1401 * Reallocate a (non-external) resource into new storage, copying the data 1402 * and modifying the original resource to point at the new storage. 1403 * 1404 * This is useful for e.g. moving a suballocated internal resource to a 1405 * dedicated allocation that can be exported by itself. 1406 */ 1407static void 1408iris_reallocate_resource_inplace(struct iris_context *ice, 1409 struct iris_resource *old_res, 1410 unsigned new_bind_flag) 1411{ 1412 struct pipe_screen *pscreen = ice->ctx.screen; 1413 1414 if (iris_bo_is_external(old_res->bo)) 1415 return; 1416 1417 assert(old_res->mod_info == NULL); 1418 assert(old_res->bo == old_res->aux.bo || old_res->aux.bo == NULL); 1419 assert(old_res->bo == old_res->aux.clear_color_bo || 1420 old_res->aux.clear_color_bo == NULL); 1421 assert(old_res->external_format == PIPE_FORMAT_NONE); 1422 1423 struct pipe_resource templ = old_res->base.b; 1424 templ.bind |= new_bind_flag; 1425 1426 struct iris_resource *new_res = 1427 (void *) pscreen->resource_create(pscreen, &templ); 1428 1429 assert(iris_bo_is_real(new_res->bo)); 1430 1431 struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER]; 1432 1433 if (old_res->base.b.target == PIPE_BUFFER) { 1434 struct pipe_box box = (struct pipe_box) { 1435 .width = old_res->base.b.width0, 1436 .height = 1, 1437 }; 1438 1439 iris_copy_region(&ice->blorp, batch, &new_res->base.b, 0, 0, 0, 0, 1440 &old_res->base.b, 0, &box); 1441 } else { 1442 for (unsigned l = 0; l <= templ.last_level; l++) { 1443 struct pipe_box box = (struct pipe_box) { 1444 .width = u_minify(templ.width0, l), 1445 .height = u_minify(templ.height0, l), 1446 .depth = util_num_layers(&templ, l), 1447 }; 1448 1449 iris_copy_region(&ice->blorp, batch, &new_res->base.b, l, 0, 0, 0, 1450 &old_res->base.b, l, &box); 1451 } 1452 } 1453 1454 iris_flush_resource(&ice->ctx, &new_res->base.b); 1455 1456 struct iris_bo *old_bo = old_res->bo; 1457 struct iris_bo *old_aux_bo = old_res->aux.bo; 1458 struct iris_bo *old_clear_color_bo = old_res->aux.clear_color_bo; 1459 1460 /* Replace the structure fields with the new ones */ 1461 old_res->base.b.bind = templ.bind; 1462 old_res->bo = new_res->bo; 1463 old_res->aux.surf = new_res->aux.surf; 1464 old_res->aux.bo = new_res->aux.bo; 1465 old_res->aux.offset = new_res->aux.offset; 1466 old_res->aux.extra_aux.surf = new_res->aux.extra_aux.surf; 1467 old_res->aux.extra_aux.offset = new_res->aux.extra_aux.offset; 1468 old_res->aux.clear_color_bo = new_res->aux.clear_color_bo; 1469 old_res->aux.clear_color_offset = new_res->aux.clear_color_offset; 1470 old_res->aux.usage = new_res->aux.usage; 1471 old_res->aux.possible_usages = new_res->aux.possible_usages; 1472 old_res->aux.sampler_usages = new_res->aux.sampler_usages; 1473 1474 if (new_res->aux.state) { 1475 assert(old_res->aux.state); 1476 for (unsigned l = 0; l <= templ.last_level; l++) { 1477 unsigned layers = util_num_layers(&templ, l); 1478 for (unsigned z = 0; z < layers; z++) { 1479 enum isl_aux_state aux = 1480 iris_resource_get_aux_state(new_res, l, z); 1481 iris_resource_set_aux_state(ice, old_res, l, z, 1, aux); 1482 } 1483 } 1484 } 1485 1486 /* old_res now points at the new BOs, make new_res point at the old ones 1487 * so they'll be freed when we unreference the resource below. 1488 */ 1489 new_res->bo = old_bo; 1490 new_res->aux.bo = old_aux_bo; 1491 new_res->aux.clear_color_bo = old_clear_color_bo; 1492 1493 pipe_resource_reference((struct pipe_resource **)&new_res, NULL); 1494} 1495 1496static void 1497iris_resource_disable_suballoc_on_first_query(struct pipe_screen *pscreen, 1498 struct pipe_context *ctx, 1499 struct iris_resource *res) 1500{ 1501 if (iris_bo_is_real(res->bo)) 1502 return; 1503 1504 assert(!(res->base.b.bind & PIPE_BIND_SHARED)); 1505 1506 bool destroy_context; 1507 if (ctx) { 1508 ctx = threaded_context_unwrap_sync(ctx); 1509 destroy_context = false; 1510 } else { 1511 /* We need to execute a blit on some GPU context, but the DRI layer 1512 * often doesn't give us one. So we have to invent a temporary one. 1513 * 1514 * We can't store a permanent context in the screen, as it would cause 1515 * circular refcounting where screens reference contexts that reference 1516 * resources, while resources reference screens...causing nothing to be 1517 * freed. So we just create and destroy a temporary one here. 1518 */ 1519 ctx = iris_create_context(pscreen, NULL, 0); 1520 destroy_context = true; 1521 } 1522 1523 struct iris_context *ice = (struct iris_context *)ctx; 1524 1525 iris_reallocate_resource_inplace(ice, res, PIPE_BIND_SHARED); 1526 assert(res->base.b.bind & PIPE_BIND_SHARED); 1527 1528 if (destroy_context) 1529 iris_destroy_context(ctx); 1530} 1531 1532 1533static void 1534iris_resource_disable_aux_on_first_query(struct pipe_resource *resource, 1535 unsigned usage) 1536{ 1537 struct iris_resource *res = (struct iris_resource *)resource; 1538 bool mod_with_aux = 1539 res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 1540 1541 /* Disable aux usage if explicit flush not set and this is the first time 1542 * we are dealing with this resource and the resource was not created with 1543 * a modifier with aux. 1544 */ 1545 if (!mod_with_aux && 1546 (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH) && res->aux.usage != 0) && 1547 p_atomic_read(&resource->reference.count) == 1) { 1548 iris_resource_disable_aux(res); 1549 } 1550} 1551 1552static bool 1553iris_resource_get_param(struct pipe_screen *pscreen, 1554 struct pipe_context *ctx, 1555 struct pipe_resource *resource, 1556 unsigned plane, 1557 unsigned layer, 1558 unsigned level, 1559 enum pipe_resource_param param, 1560 unsigned handle_usage, 1561 uint64_t *value) 1562{ 1563 struct iris_screen *screen = (struct iris_screen *)pscreen; 1564 struct iris_resource *res = (struct iris_resource *)resource; 1565 bool mod_with_aux = 1566 res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 1567 bool wants_aux = mod_with_aux && plane > 0; 1568 bool result; 1569 unsigned handle; 1570 1571 iris_resource_disable_aux_on_first_query(resource, handle_usage); 1572 iris_resource_disable_suballoc_on_first_query(pscreen, ctx, res); 1573 1574 struct iris_bo *bo = wants_aux ? res->aux.bo : res->bo; 1575 1576 assert(iris_bo_is_real(bo)); 1577 1578 switch (param) { 1579 case PIPE_RESOURCE_PARAM_NPLANES: 1580 if (mod_with_aux) { 1581 *value = iris_get_dmabuf_modifier_planes(pscreen, 1582 res->mod_info->modifier, 1583 res->external_format); 1584 } else { 1585 *value = get_num_planes(&res->base.b); 1586 } 1587 return true; 1588 case PIPE_RESOURCE_PARAM_STRIDE: 1589 *value = wants_aux ? res->aux.surf.row_pitch_B : res->surf.row_pitch_B; 1590 return true; 1591 case PIPE_RESOURCE_PARAM_OFFSET: 1592 *value = wants_aux ? 1593 mod_plane_is_clear_color(res->mod_info->modifier, plane) ? 1594 res->aux.clear_color_offset : res->aux.offset : 0; 1595 return true; 1596 case PIPE_RESOURCE_PARAM_MODIFIER: 1597 *value = res->mod_info ? res->mod_info->modifier : 1598 tiling_to_modifier(isl_tiling_to_i915_tiling(res->surf.tiling)); 1599 return true; 1600 case PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED: 1601 if (!wants_aux) 1602 iris_gem_set_tiling(bo, &res->surf); 1603 1604 result = iris_bo_flink(bo, &handle) == 0; 1605 if (result) 1606 *value = handle; 1607 return result; 1608 case PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS: { 1609 if (!wants_aux) 1610 iris_gem_set_tiling(bo, &res->surf); 1611 1612 /* Because we share the same drm file across multiple iris_screen, when 1613 * we export a GEM handle we must make sure it is valid in the DRM file 1614 * descriptor the caller is using (this is the FD given at screen 1615 * creation). 1616 */ 1617 uint32_t handle; 1618 if (iris_bo_export_gem_handle_for_device(bo, screen->winsys_fd, &handle)) 1619 return false; 1620 *value = handle; 1621 return true; 1622 } 1623 1624 case PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD: 1625 if (!wants_aux) 1626 iris_gem_set_tiling(bo, &res->surf); 1627 1628 result = iris_bo_export_dmabuf(bo, (int *) &handle) == 0; 1629 if (result) 1630 *value = handle; 1631 return result; 1632 default: 1633 return false; 1634 } 1635} 1636 1637static bool 1638iris_resource_get_handle(struct pipe_screen *pscreen, 1639 struct pipe_context *ctx, 1640 struct pipe_resource *resource, 1641 struct winsys_handle *whandle, 1642 unsigned usage) 1643{ 1644 struct iris_screen *screen = (struct iris_screen *) pscreen; 1645 struct iris_resource *res = (struct iris_resource *)resource; 1646 bool mod_with_aux = 1647 res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 1648 1649 iris_resource_disable_aux_on_first_query(resource, usage); 1650 iris_resource_disable_suballoc_on_first_query(pscreen, ctx, res); 1651 1652 assert(iris_bo_is_real(res->bo)); 1653 1654 struct iris_bo *bo; 1655 if (res->mod_info && 1656 mod_plane_is_clear_color(res->mod_info->modifier, whandle->plane)) { 1657 bo = res->aux.clear_color_bo; 1658 whandle->offset = res->aux.clear_color_offset; 1659 } else if (mod_with_aux && whandle->plane > 0) { 1660 bo = res->aux.bo; 1661 whandle->stride = res->aux.surf.row_pitch_B; 1662 whandle->offset = res->aux.offset; 1663 } else { 1664 /* If this is a buffer, stride should be 0 - no need to special case */ 1665 whandle->stride = res->surf.row_pitch_B; 1666 bo = res->bo; 1667 } 1668 1669 whandle->format = res->external_format; 1670 whandle->modifier = 1671 res->mod_info ? res->mod_info->modifier 1672 : tiling_to_modifier(isl_tiling_to_i915_tiling(res->surf.tiling)); 1673 1674#ifndef NDEBUG 1675 enum isl_aux_usage allowed_usage = 1676 usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH ? res->aux.usage : 1677 res->mod_info ? res->mod_info->aux_usage : ISL_AUX_USAGE_NONE; 1678 1679 if (res->aux.usage != allowed_usage) { 1680 enum isl_aux_state aux_state = iris_resource_get_aux_state(res, 0, 0); 1681 assert(aux_state == ISL_AUX_STATE_RESOLVED || 1682 aux_state == ISL_AUX_STATE_PASS_THROUGH); 1683 } 1684#endif 1685 1686 switch (whandle->type) { 1687 case WINSYS_HANDLE_TYPE_SHARED: 1688 iris_gem_set_tiling(bo, &res->surf); 1689 return iris_bo_flink(bo, &whandle->handle) == 0; 1690 case WINSYS_HANDLE_TYPE_KMS: { 1691 iris_gem_set_tiling(bo, &res->surf); 1692 1693 /* Because we share the same drm file across multiple iris_screen, when 1694 * we export a GEM handle we must make sure it is valid in the DRM file 1695 * descriptor the caller is using (this is the FD given at screen 1696 * creation). 1697 */ 1698 uint32_t handle; 1699 if (iris_bo_export_gem_handle_for_device(bo, screen->winsys_fd, &handle)) 1700 return false; 1701 whandle->handle = handle; 1702 return true; 1703 } 1704 case WINSYS_HANDLE_TYPE_FD: 1705 iris_gem_set_tiling(bo, &res->surf); 1706 return iris_bo_export_dmabuf(bo, (int *) &whandle->handle) == 0; 1707 } 1708 1709 return false; 1710} 1711 1712static bool 1713resource_is_busy(struct iris_context *ice, 1714 struct iris_resource *res) 1715{ 1716 bool busy = iris_bo_busy(res->bo); 1717 1718 for (int i = 0; i < IRIS_BATCH_COUNT; i++) 1719 busy |= iris_batch_references(&ice->batches[i], res->bo); 1720 1721 return busy; 1722} 1723 1724void 1725iris_replace_buffer_storage(struct pipe_context *ctx, 1726 struct pipe_resource *p_dst, 1727 struct pipe_resource *p_src, 1728 unsigned num_rebinds, 1729 uint32_t rebind_mask, 1730 uint32_t delete_buffer_id) 1731{ 1732 struct iris_screen *screen = (void *) ctx->screen; 1733 struct iris_context *ice = (void *) ctx; 1734 struct iris_resource *dst = (void *) p_dst; 1735 struct iris_resource *src = (void *) p_src; 1736 1737 assert(memcmp(&dst->surf, &src->surf, sizeof(dst->surf)) == 0); 1738 1739 struct iris_bo *old_bo = dst->bo; 1740 1741 /* Swap out the backing storage */ 1742 iris_bo_reference(src->bo); 1743 dst->bo = src->bo; 1744 1745 /* Rebind the buffer, replacing any state referring to the old BO's 1746 * address, and marking state dirty so it's reemitted. 1747 */ 1748 screen->vtbl.rebind_buffer(ice, dst); 1749 1750 iris_bo_unreference(old_bo); 1751} 1752 1753static void 1754iris_invalidate_resource(struct pipe_context *ctx, 1755 struct pipe_resource *resource) 1756{ 1757 struct iris_screen *screen = (void *) ctx->screen; 1758 struct iris_context *ice = (void *) ctx; 1759 struct iris_resource *res = (void *) resource; 1760 1761 if (resource->target != PIPE_BUFFER) 1762 return; 1763 1764 /* If it's already invalidated, don't bother doing anything. */ 1765 if (res->valid_buffer_range.start > res->valid_buffer_range.end) 1766 return; 1767 1768 if (!resource_is_busy(ice, res)) { 1769 /* The resource is idle, so just mark that it contains no data and 1770 * keep using the same underlying buffer object. 1771 */ 1772 util_range_set_empty(&res->valid_buffer_range); 1773 return; 1774 } 1775 1776 /* Otherwise, try and replace the backing storage with a new BO. */ 1777 1778 /* We can't reallocate memory we didn't allocate in the first place. */ 1779 if (res->bo->gem_handle && res->bo->real.userptr) 1780 return; 1781 1782 struct iris_bo *old_bo = res->bo; 1783 struct iris_bo *new_bo = 1784 iris_bo_alloc(screen->bufmgr, res->bo->name, resource->width0, 1, 1785 iris_memzone_for_address(old_bo->address), 0); 1786 if (!new_bo) 1787 return; 1788 1789 /* Swap out the backing storage */ 1790 res->bo = new_bo; 1791 1792 /* Rebind the buffer, replacing any state referring to the old BO's 1793 * address, and marking state dirty so it's reemitted. 1794 */ 1795 screen->vtbl.rebind_buffer(ice, res); 1796 1797 util_range_set_empty(&res->valid_buffer_range); 1798 1799 iris_bo_unreference(old_bo); 1800} 1801 1802static void 1803iris_flush_staging_region(struct pipe_transfer *xfer, 1804 const struct pipe_box *flush_box) 1805{ 1806 if (!(xfer->usage & PIPE_MAP_WRITE)) 1807 return; 1808 1809 struct iris_transfer *map = (void *) xfer; 1810 1811 struct pipe_box src_box = *flush_box; 1812 1813 /* Account for extra alignment padding in staging buffer */ 1814 if (xfer->resource->target == PIPE_BUFFER) 1815 src_box.x += xfer->box.x % IRIS_MAP_BUFFER_ALIGNMENT; 1816 1817 struct pipe_box dst_box = (struct pipe_box) { 1818 .x = xfer->box.x + flush_box->x, 1819 .y = xfer->box.y + flush_box->y, 1820 .z = xfer->box.z + flush_box->z, 1821 .width = flush_box->width, 1822 .height = flush_box->height, 1823 .depth = flush_box->depth, 1824 }; 1825 1826 iris_copy_region(map->blorp, map->batch, xfer->resource, xfer->level, 1827 dst_box.x, dst_box.y, dst_box.z, map->staging, 0, 1828 &src_box); 1829} 1830 1831static void 1832iris_unmap_copy_region(struct iris_transfer *map) 1833{ 1834 iris_resource_destroy(map->staging->screen, map->staging); 1835 1836 map->ptr = NULL; 1837} 1838 1839static void 1840iris_map_copy_region(struct iris_transfer *map) 1841{ 1842 struct pipe_screen *pscreen = &map->batch->screen->base; 1843 struct pipe_transfer *xfer = &map->base.b; 1844 struct pipe_box *box = &xfer->box; 1845 struct iris_resource *res = (void *) xfer->resource; 1846 1847 unsigned extra = xfer->resource->target == PIPE_BUFFER ? 1848 box->x % IRIS_MAP_BUFFER_ALIGNMENT : 0; 1849 1850 struct pipe_resource templ = (struct pipe_resource) { 1851 .usage = PIPE_USAGE_STAGING, 1852 .width0 = box->width + extra, 1853 .height0 = box->height, 1854 .depth0 = 1, 1855 .nr_samples = xfer->resource->nr_samples, 1856 .nr_storage_samples = xfer->resource->nr_storage_samples, 1857 .array_size = box->depth, 1858 .format = res->internal_format, 1859 }; 1860 1861 if (xfer->resource->target == PIPE_BUFFER) 1862 templ.target = PIPE_BUFFER; 1863 else if (templ.array_size > 1) 1864 templ.target = PIPE_TEXTURE_2D_ARRAY; 1865 else 1866 templ.target = PIPE_TEXTURE_2D; 1867 1868 map->staging = iris_resource_create(pscreen, &templ); 1869 assert(map->staging); 1870 1871 if (templ.target != PIPE_BUFFER) { 1872 struct isl_surf *surf = &((struct iris_resource *) map->staging)->surf; 1873 xfer->stride = isl_surf_get_row_pitch_B(surf); 1874 xfer->layer_stride = isl_surf_get_array_pitch(surf); 1875 } 1876 1877 if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 1878 iris_copy_region(map->blorp, map->batch, map->staging, 0, extra, 0, 0, 1879 xfer->resource, xfer->level, box); 1880 /* Ensure writes to the staging BO land before we map it below. */ 1881 iris_emit_pipe_control_flush(map->batch, 1882 "transfer read: flush before mapping", 1883 PIPE_CONTROL_RENDER_TARGET_FLUSH | 1884 PIPE_CONTROL_TILE_CACHE_FLUSH | 1885 PIPE_CONTROL_CS_STALL); 1886 } 1887 1888 struct iris_bo *staging_bo = iris_resource_bo(map->staging); 1889 1890 if (iris_batch_references(map->batch, staging_bo)) 1891 iris_batch_flush(map->batch); 1892 1893 map->ptr = 1894 iris_bo_map(map->dbg, staging_bo, xfer->usage & MAP_FLAGS) + extra; 1895 1896 map->unmap = iris_unmap_copy_region; 1897} 1898 1899static void 1900get_image_offset_el(const struct isl_surf *surf, unsigned level, unsigned z, 1901 unsigned *out_x0_el, unsigned *out_y0_el) 1902{ 1903 ASSERTED uint32_t z0_el, a0_el; 1904 if (surf->dim == ISL_SURF_DIM_3D) { 1905 isl_surf_get_image_offset_el(surf, level, 0, z, 1906 out_x0_el, out_y0_el, &z0_el, &a0_el); 1907 } else { 1908 isl_surf_get_image_offset_el(surf, level, z, 0, 1909 out_x0_el, out_y0_el, &z0_el, &a0_el); 1910 } 1911 assert(z0_el == 0 && a0_el == 0); 1912} 1913 1914/** 1915 * Get pointer offset into stencil buffer. 1916 * 1917 * The stencil buffer is W tiled. Since the GTT is incapable of W fencing, we 1918 * must decode the tile's layout in software. 1919 * 1920 * See 1921 * - PRM, 2011 Sandy Bridge, Volume 1, Part 2, Section 4.5.2.1 W-Major Tile 1922 * Format. 1923 * - PRM, 2011 Sandy Bridge, Volume 1, Part 2, Section 4.5.3 Tiling Algorithm 1924 * 1925 * Even though the returned offset is always positive, the return type is 1926 * signed due to 1927 * commit e8b1c6d6f55f5be3bef25084fdd8b6127517e137 1928 * mesa: Fix return type of _mesa_get_format_bytes() (#37351) 1929 */ 1930static intptr_t 1931s8_offset(uint32_t stride, uint32_t x, uint32_t y) 1932{ 1933 uint32_t tile_size = 4096; 1934 uint32_t tile_width = 64; 1935 uint32_t tile_height = 64; 1936 uint32_t row_size = 64 * stride / 2; /* Two rows are interleaved. */ 1937 1938 uint32_t tile_x = x / tile_width; 1939 uint32_t tile_y = y / tile_height; 1940 1941 /* The byte's address relative to the tile's base addres. */ 1942 uint32_t byte_x = x % tile_width; 1943 uint32_t byte_y = y % tile_height; 1944 1945 uintptr_t u = tile_y * row_size 1946 + tile_x * tile_size 1947 + 512 * (byte_x / 8) 1948 + 64 * (byte_y / 8) 1949 + 32 * ((byte_y / 4) % 2) 1950 + 16 * ((byte_x / 4) % 2) 1951 + 8 * ((byte_y / 2) % 2) 1952 + 4 * ((byte_x / 2) % 2) 1953 + 2 * (byte_y % 2) 1954 + 1 * (byte_x % 2); 1955 1956 return u; 1957} 1958 1959static void 1960iris_unmap_s8(struct iris_transfer *map) 1961{ 1962 struct pipe_transfer *xfer = &map->base.b; 1963 const struct pipe_box *box = &xfer->box; 1964 struct iris_resource *res = (struct iris_resource *) xfer->resource; 1965 struct isl_surf *surf = &res->surf; 1966 1967 if (xfer->usage & PIPE_MAP_WRITE) { 1968 uint8_t *untiled_s8_map = map->ptr; 1969 uint8_t *tiled_s8_map = 1970 iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 1971 1972 for (int s = 0; s < box->depth; s++) { 1973 unsigned x0_el, y0_el; 1974 get_image_offset_el(surf, xfer->level, box->z + s, &x0_el, &y0_el); 1975 1976 for (uint32_t y = 0; y < box->height; y++) { 1977 for (uint32_t x = 0; x < box->width; x++) { 1978 ptrdiff_t offset = s8_offset(surf->row_pitch_B, 1979 x0_el + box->x + x, 1980 y0_el + box->y + y); 1981 tiled_s8_map[offset] = 1982 untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x]; 1983 } 1984 } 1985 } 1986 } 1987 1988 free(map->buffer); 1989} 1990 1991static void 1992iris_map_s8(struct iris_transfer *map) 1993{ 1994 struct pipe_transfer *xfer = &map->base.b; 1995 const struct pipe_box *box = &xfer->box; 1996 struct iris_resource *res = (struct iris_resource *) xfer->resource; 1997 struct isl_surf *surf = &res->surf; 1998 1999 xfer->stride = surf->row_pitch_B; 2000 xfer->layer_stride = xfer->stride * box->height; 2001 2002 /* The tiling and detiling functions require that the linear buffer has 2003 * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we 2004 * over-allocate the linear buffer to get the proper alignment. 2005 */ 2006 map->buffer = map->ptr = malloc(xfer->layer_stride * box->depth); 2007 assert(map->buffer); 2008 2009 /* One of either READ_BIT or WRITE_BIT or both is set. READ_BIT implies no 2010 * INVALIDATE_RANGE_BIT. WRITE_BIT needs the original values read in unless 2011 * invalidate is set, since we'll be writing the whole rectangle from our 2012 * temporary buffer back out. 2013 */ 2014 if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 2015 uint8_t *untiled_s8_map = map->ptr; 2016 uint8_t *tiled_s8_map = 2017 iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 2018 2019 for (int s = 0; s < box->depth; s++) { 2020 unsigned x0_el, y0_el; 2021 get_image_offset_el(surf, xfer->level, box->z + s, &x0_el, &y0_el); 2022 2023 for (uint32_t y = 0; y < box->height; y++) { 2024 for (uint32_t x = 0; x < box->width; x++) { 2025 ptrdiff_t offset = s8_offset(surf->row_pitch_B, 2026 x0_el + box->x + x, 2027 y0_el + box->y + y); 2028 untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x] = 2029 tiled_s8_map[offset]; 2030 } 2031 } 2032 } 2033 } 2034 2035 map->unmap = iris_unmap_s8; 2036} 2037 2038/* Compute extent parameters for use with tiled_memcpy functions. 2039 * xs are in units of bytes and ys are in units of strides. 2040 */ 2041static inline void 2042tile_extents(const struct isl_surf *surf, 2043 const struct pipe_box *box, 2044 unsigned level, int z, 2045 unsigned *x1_B, unsigned *x2_B, 2046 unsigned *y1_el, unsigned *y2_el) 2047{ 2048 const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format); 2049 const unsigned cpp = fmtl->bpb / 8; 2050 2051 assert(box->x % fmtl->bw == 0); 2052 assert(box->y % fmtl->bh == 0); 2053 2054 unsigned x0_el, y0_el; 2055 get_image_offset_el(surf, level, box->z + z, &x0_el, &y0_el); 2056 2057 *x1_B = (box->x / fmtl->bw + x0_el) * cpp; 2058 *y1_el = box->y / fmtl->bh + y0_el; 2059 *x2_B = (DIV_ROUND_UP(box->x + box->width, fmtl->bw) + x0_el) * cpp; 2060 *y2_el = DIV_ROUND_UP(box->y + box->height, fmtl->bh) + y0_el; 2061} 2062 2063static void 2064iris_unmap_tiled_memcpy(struct iris_transfer *map) 2065{ 2066 struct pipe_transfer *xfer = &map->base.b; 2067 const struct pipe_box *box = &xfer->box; 2068 struct iris_resource *res = (struct iris_resource *) xfer->resource; 2069 struct isl_surf *surf = &res->surf; 2070 2071 const bool has_swizzling = false; 2072 2073 if (xfer->usage & PIPE_MAP_WRITE) { 2074 char *dst = 2075 iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 2076 2077 for (int s = 0; s < box->depth; s++) { 2078 unsigned x1, x2, y1, y2; 2079 tile_extents(surf, box, xfer->level, s, &x1, &x2, &y1, &y2); 2080 2081 void *ptr = map->ptr + s * xfer->layer_stride; 2082 2083 isl_memcpy_linear_to_tiled(x1, x2, y1, y2, dst, ptr, 2084 surf->row_pitch_B, xfer->stride, 2085 has_swizzling, surf->tiling, ISL_MEMCPY); 2086 } 2087 } 2088 os_free_aligned(map->buffer); 2089 map->buffer = map->ptr = NULL; 2090} 2091 2092static void 2093iris_map_tiled_memcpy(struct iris_transfer *map) 2094{ 2095 struct pipe_transfer *xfer = &map->base.b; 2096 const struct pipe_box *box = &xfer->box; 2097 struct iris_resource *res = (struct iris_resource *) xfer->resource; 2098 struct isl_surf *surf = &res->surf; 2099 2100 xfer->stride = ALIGN(surf->row_pitch_B, 16); 2101 xfer->layer_stride = xfer->stride * box->height; 2102 2103 unsigned x1, x2, y1, y2; 2104 tile_extents(surf, box, xfer->level, 0, &x1, &x2, &y1, &y2); 2105 2106 /* The tiling and detiling functions require that the linear buffer has 2107 * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we 2108 * over-allocate the linear buffer to get the proper alignment. 2109 */ 2110 map->buffer = 2111 os_malloc_aligned(xfer->layer_stride * box->depth, 16); 2112 assert(map->buffer); 2113 map->ptr = (char *)map->buffer + (x1 & 0xf); 2114 2115 const bool has_swizzling = false; 2116 2117 if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 2118 char *src = 2119 iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 2120 2121 for (int s = 0; s < box->depth; s++) { 2122 unsigned x1, x2, y1, y2; 2123 tile_extents(surf, box, xfer->level, s, &x1, &x2, &y1, &y2); 2124 2125 /* Use 's' rather than 'box->z' to rebase the first slice to 0. */ 2126 void *ptr = map->ptr + s * xfer->layer_stride; 2127 2128 isl_memcpy_tiled_to_linear(x1, x2, y1, y2, ptr, src, xfer->stride, 2129 surf->row_pitch_B, has_swizzling, 2130 surf->tiling, ISL_MEMCPY_STREAMING_LOAD); 2131 } 2132 } 2133 2134 map->unmap = iris_unmap_tiled_memcpy; 2135} 2136 2137static void 2138iris_map_direct(struct iris_transfer *map) 2139{ 2140 struct pipe_transfer *xfer = &map->base.b; 2141 struct pipe_box *box = &xfer->box; 2142 struct iris_resource *res = (struct iris_resource *) xfer->resource; 2143 2144 void *ptr = iris_bo_map(map->dbg, res->bo, xfer->usage & MAP_FLAGS); 2145 2146 if (res->base.b.target == PIPE_BUFFER) { 2147 xfer->stride = 0; 2148 xfer->layer_stride = 0; 2149 2150 map->ptr = ptr + box->x; 2151 } else { 2152 struct isl_surf *surf = &res->surf; 2153 const struct isl_format_layout *fmtl = 2154 isl_format_get_layout(surf->format); 2155 const unsigned cpp = fmtl->bpb / 8; 2156 unsigned x0_el, y0_el; 2157 2158 get_image_offset_el(surf, xfer->level, box->z, &x0_el, &y0_el); 2159 2160 xfer->stride = isl_surf_get_row_pitch_B(surf); 2161 xfer->layer_stride = isl_surf_get_array_pitch(surf); 2162 2163 map->ptr = ptr + (y0_el + box->y) * xfer->stride + (x0_el + box->x) * cpp; 2164 } 2165} 2166 2167static bool 2168can_promote_to_async(const struct iris_resource *res, 2169 const struct pipe_box *box, 2170 enum pipe_map_flags usage) 2171{ 2172 /* If we're writing to a section of the buffer that hasn't even been 2173 * initialized with useful data, then we can safely promote this write 2174 * to be unsynchronized. This helps the common pattern of appending data. 2175 */ 2176 return res->base.b.target == PIPE_BUFFER && (usage & PIPE_MAP_WRITE) && 2177 !(usage & TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED) && 2178 !util_ranges_intersect(&res->valid_buffer_range, box->x, 2179 box->x + box->width); 2180} 2181 2182static void * 2183iris_transfer_map(struct pipe_context *ctx, 2184 struct pipe_resource *resource, 2185 unsigned level, 2186 enum pipe_map_flags usage, 2187 const struct pipe_box *box, 2188 struct pipe_transfer **ptransfer) 2189{ 2190 struct iris_context *ice = (struct iris_context *)ctx; 2191 struct iris_resource *res = (struct iris_resource *)resource; 2192 struct isl_surf *surf = &res->surf; 2193 2194 if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) { 2195 /* Replace the backing storage with a fresh buffer for non-async maps */ 2196 if (!(usage & (PIPE_MAP_UNSYNCHRONIZED | 2197 TC_TRANSFER_MAP_NO_INVALIDATE))) 2198 iris_invalidate_resource(ctx, resource); 2199 2200 /* If we can discard the whole resource, we can discard the range. */ 2201 usage |= PIPE_MAP_DISCARD_RANGE; 2202 } 2203 2204 if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && 2205 can_promote_to_async(res, box, usage)) { 2206 usage |= PIPE_MAP_UNSYNCHRONIZED; 2207 } 2208 2209 /* Avoid using GPU copies for persistent/coherent buffers, as the idea 2210 * there is to access them simultaneously on the CPU & GPU. This also 2211 * avoids trying to use GPU copies for our u_upload_mgr buffers which 2212 * contain state we're constructing for a GPU draw call, which would 2213 * kill us with infinite stack recursion. 2214 */ 2215 if (usage & (PIPE_MAP_PERSISTENT | PIPE_MAP_COHERENT)) 2216 usage |= PIPE_MAP_DIRECTLY; 2217 2218 /* We cannot provide a direct mapping of tiled resources, and we 2219 * may not be able to mmap imported BOs since they may come from 2220 * other devices that I915_GEM_MMAP cannot work with. 2221 */ 2222 if ((usage & PIPE_MAP_DIRECTLY) && 2223 (surf->tiling != ISL_TILING_LINEAR || iris_bo_is_imported(res->bo))) 2224 return NULL; 2225 2226 bool map_would_stall = false; 2227 2228 if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { 2229 map_would_stall = 2230 resource_is_busy(ice, res) || 2231 iris_has_invalid_primary(res, level, 1, box->z, box->depth); 2232 2233 if (map_would_stall && (usage & PIPE_MAP_DONTBLOCK) && 2234 (usage & PIPE_MAP_DIRECTLY)) 2235 return NULL; 2236 } 2237 2238 struct iris_transfer *map; 2239 2240 if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) 2241 map = slab_alloc(&ice->transfer_pool_unsync); 2242 else 2243 map = slab_alloc(&ice->transfer_pool); 2244 2245 if (!map) 2246 return NULL; 2247 2248 struct pipe_transfer *xfer = &map->base.b; 2249 2250 memset(map, 0, sizeof(*map)); 2251 map->dbg = &ice->dbg; 2252 2253 pipe_resource_reference(&xfer->resource, resource); 2254 xfer->level = level; 2255 xfer->usage = usage; 2256 xfer->box = *box; 2257 *ptransfer = xfer; 2258 2259 map->dest_had_defined_contents = 2260 util_ranges_intersect(&res->valid_buffer_range, box->x, 2261 box->x + box->width); 2262 2263 if (usage & PIPE_MAP_WRITE) 2264 util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width); 2265 2266 if (iris_bo_mmap_mode(res->bo) != IRIS_MMAP_NONE) { 2267 /* GPU copies are not useful for buffer reads. Instead of stalling to 2268 * read from the original buffer, we'd simply copy it to a temporary... 2269 * then stall (a bit longer) to read from that buffer. 2270 * 2271 * Images are less clear-cut. Resolves can be destructive, removing 2272 * some of the underlying compression, so we'd rather blit the data to 2273 * a linear temporary and map that, to avoid the resolve. 2274 */ 2275 if (!(usage & PIPE_MAP_DISCARD_RANGE) && 2276 !iris_has_invalid_primary(res, level, 1, box->z, box->depth)) { 2277 usage |= PIPE_MAP_DIRECTLY; 2278 } 2279 2280 const struct isl_format_layout *fmtl = 2281 isl_format_get_layout(surf->format); 2282 if (fmtl->txc == ISL_TXC_ASTC) 2283 usage |= PIPE_MAP_DIRECTLY; 2284 2285 /* We can map directly if it wouldn't stall, there's no compression, 2286 * and we aren't doing an uncached read. 2287 */ 2288 if (!map_would_stall && 2289 !isl_aux_usage_has_compression(res->aux.usage) && 2290 !((usage & PIPE_MAP_READ) && 2291 iris_bo_mmap_mode(res->bo) != IRIS_MMAP_WB)) { 2292 usage |= PIPE_MAP_DIRECTLY; 2293 } 2294 } 2295 2296 /* TODO: Teach iris_map_tiled_memcpy about Tile4... */ 2297 if (res->surf.tiling == ISL_TILING_4) 2298 usage &= ~PIPE_MAP_DIRECTLY; 2299 2300 if (!(usage & PIPE_MAP_DIRECTLY)) { 2301 /* If we need a synchronous mapping and the resource is busy, or needs 2302 * resolving, we copy to/from a linear temporary buffer using the GPU. 2303 */ 2304 map->batch = &ice->batches[IRIS_BATCH_RENDER]; 2305 map->blorp = &ice->blorp; 2306 iris_map_copy_region(map); 2307 } else { 2308 /* Otherwise we're free to map on the CPU. */ 2309 2310 if (resource->target != PIPE_BUFFER) { 2311 iris_resource_access_raw(ice, res, level, box->z, box->depth, 2312 usage & PIPE_MAP_WRITE); 2313 } 2314 2315 if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { 2316 for (int i = 0; i < IRIS_BATCH_COUNT; i++) { 2317 if (iris_batch_references(&ice->batches[i], res->bo)) 2318 iris_batch_flush(&ice->batches[i]); 2319 } 2320 } 2321 2322 if (surf->tiling == ISL_TILING_W) { 2323 /* TODO: Teach iris_map_tiled_memcpy about W-tiling... */ 2324 iris_map_s8(map); 2325 } else if (surf->tiling != ISL_TILING_LINEAR) { 2326 iris_map_tiled_memcpy(map); 2327 } else { 2328 iris_map_direct(map); 2329 } 2330 } 2331 2332 return map->ptr; 2333} 2334 2335static void 2336iris_transfer_flush_region(struct pipe_context *ctx, 2337 struct pipe_transfer *xfer, 2338 const struct pipe_box *box) 2339{ 2340 struct iris_context *ice = (struct iris_context *)ctx; 2341 struct iris_resource *res = (struct iris_resource *) xfer->resource; 2342 struct iris_transfer *map = (void *) xfer; 2343 2344 if (map->staging) 2345 iris_flush_staging_region(xfer, box); 2346 2347 uint32_t history_flush = 0; 2348 2349 if (res->base.b.target == PIPE_BUFFER) { 2350 if (map->staging) 2351 history_flush |= PIPE_CONTROL_RENDER_TARGET_FLUSH | 2352 PIPE_CONTROL_TILE_CACHE_FLUSH; 2353 2354 if (map->dest_had_defined_contents) 2355 history_flush |= iris_flush_bits_for_history(ice, res); 2356 2357 util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width); 2358 } 2359 2360 if (history_flush & ~PIPE_CONTROL_CS_STALL) { 2361 for (int i = 0; i < IRIS_BATCH_COUNT; i++) { 2362 struct iris_batch *batch = &ice->batches[i]; 2363 if (batch->contains_draw || batch->cache.render->entries) { 2364 iris_batch_maybe_flush(batch, 24); 2365 iris_emit_pipe_control_flush(batch, 2366 "cache history: transfer flush", 2367 history_flush); 2368 } 2369 } 2370 } 2371 2372 /* Make sure we flag constants dirty even if there's no need to emit 2373 * any PIPE_CONTROLs to a batch. 2374 */ 2375 iris_dirty_for_history(ice, res); 2376} 2377 2378static void 2379iris_transfer_unmap(struct pipe_context *ctx, struct pipe_transfer *xfer) 2380{ 2381 struct iris_context *ice = (struct iris_context *)ctx; 2382 struct iris_transfer *map = (void *) xfer; 2383 2384 if (!(xfer->usage & (PIPE_MAP_FLUSH_EXPLICIT | 2385 PIPE_MAP_COHERENT))) { 2386 struct pipe_box flush_box = { 2387 .x = 0, .y = 0, .z = 0, 2388 .width = xfer->box.width, 2389 .height = xfer->box.height, 2390 .depth = xfer->box.depth, 2391 }; 2392 iris_transfer_flush_region(ctx, xfer, &flush_box); 2393 } 2394 2395 if (map->unmap) 2396 map->unmap(map); 2397 2398 pipe_resource_reference(&xfer->resource, NULL); 2399 2400 /* transfer_unmap is always called from the driver thread, so we have to 2401 * use transfer_pool, not transfer_pool_unsync. Freeing an object into a 2402 * different pool is allowed, however. 2403 */ 2404 slab_free(&ice->transfer_pool, map); 2405} 2406 2407/** 2408 * The pipe->texture_subdata() driver hook. 2409 * 2410 * Mesa's state tracker takes this path whenever possible, even with 2411 * PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER set. 2412 */ 2413static void 2414iris_texture_subdata(struct pipe_context *ctx, 2415 struct pipe_resource *resource, 2416 unsigned level, 2417 unsigned usage, 2418 const struct pipe_box *box, 2419 const void *data, 2420 unsigned stride, 2421 unsigned layer_stride) 2422{ 2423 struct iris_context *ice = (struct iris_context *)ctx; 2424 struct iris_resource *res = (struct iris_resource *)resource; 2425 const struct isl_surf *surf = &res->surf; 2426 2427 assert(resource->target != PIPE_BUFFER); 2428 2429 /* Just use the transfer-based path for linear buffers - it will already 2430 * do a direct mapping, or a simple linear staging buffer. 2431 * 2432 * Linear staging buffers appear to be better than tiled ones, too, so 2433 * take that path if we need the GPU to perform color compression, or 2434 * stall-avoidance blits. 2435 * 2436 * TODO: Teach isl_memcpy_linear_to_tiled about Tile4... 2437 */ 2438 if (surf->tiling == ISL_TILING_LINEAR || 2439 surf->tiling == ISL_TILING_4 || 2440 isl_aux_usage_has_compression(res->aux.usage) || 2441 resource_is_busy(ice, res) || 2442 iris_bo_mmap_mode(res->bo) == IRIS_MMAP_NONE) { 2443 return u_default_texture_subdata(ctx, resource, level, usage, box, 2444 data, stride, layer_stride); 2445 } 2446 2447 /* No state trackers pass any flags other than PIPE_MAP_WRITE */ 2448 2449 iris_resource_access_raw(ice, res, level, box->z, box->depth, true); 2450 2451 for (int i = 0; i < IRIS_BATCH_COUNT; i++) { 2452 if (iris_batch_references(&ice->batches[i], res->bo)) 2453 iris_batch_flush(&ice->batches[i]); 2454 } 2455 2456 uint8_t *dst = iris_bo_map(&ice->dbg, res->bo, MAP_WRITE | MAP_RAW); 2457 2458 for (int s = 0; s < box->depth; s++) { 2459 const uint8_t *src = data + s * layer_stride; 2460 2461 if (surf->tiling == ISL_TILING_W) { 2462 unsigned x0_el, y0_el; 2463 get_image_offset_el(surf, level, box->z + s, &x0_el, &y0_el); 2464 2465 for (unsigned y = 0; y < box->height; y++) { 2466 for (unsigned x = 0; x < box->width; x++) { 2467 ptrdiff_t offset = s8_offset(surf->row_pitch_B, 2468 x0_el + box->x + x, 2469 y0_el + box->y + y); 2470 dst[offset] = src[y * stride + x]; 2471 } 2472 } 2473 } else { 2474 unsigned x1, x2, y1, y2; 2475 2476 tile_extents(surf, box, level, s, &x1, &x2, &y1, &y2); 2477 2478 isl_memcpy_linear_to_tiled(x1, x2, y1, y2, 2479 (void *)dst, (void *)src, 2480 surf->row_pitch_B, stride, 2481 false, surf->tiling, ISL_MEMCPY); 2482 } 2483 } 2484} 2485 2486/** 2487 * Mark state dirty that needs to be re-emitted when a resource is written. 2488 */ 2489void 2490iris_dirty_for_history(struct iris_context *ice, 2491 struct iris_resource *res) 2492{ 2493 const uint64_t stages = res->bind_stages; 2494 uint64_t dirty = 0ull; 2495 uint64_t stage_dirty = 0ull; 2496 2497 if (res->bind_history & PIPE_BIND_CONSTANT_BUFFER) { 2498 for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) { 2499 if (stages & (1u << stage)) { 2500 struct iris_shader_state *shs = &ice->state.shaders[stage]; 2501 shs->dirty_cbufs |= ~0u; 2502 } 2503 } 2504 dirty |= IRIS_DIRTY_RENDER_MISC_BUFFER_FLUSHES | 2505 IRIS_DIRTY_COMPUTE_MISC_BUFFER_FLUSHES; 2506 stage_dirty |= (stages << IRIS_SHIFT_FOR_STAGE_DIRTY_CONSTANTS); 2507 } 2508 2509 if (res->bind_history & (PIPE_BIND_SAMPLER_VIEW | 2510 PIPE_BIND_SHADER_IMAGE)) { 2511 dirty |= IRIS_DIRTY_RENDER_RESOLVES_AND_FLUSHES | 2512 IRIS_DIRTY_COMPUTE_RESOLVES_AND_FLUSHES; 2513 stage_dirty |= (stages << IRIS_SHIFT_FOR_STAGE_DIRTY_BINDINGS); 2514 } 2515 2516 if (res->bind_history & PIPE_BIND_SHADER_BUFFER) { 2517 dirty |= IRIS_DIRTY_RENDER_MISC_BUFFER_FLUSHES | 2518 IRIS_DIRTY_COMPUTE_MISC_BUFFER_FLUSHES; 2519 stage_dirty |= (stages << IRIS_SHIFT_FOR_STAGE_DIRTY_BINDINGS); 2520 } 2521 2522 if (res->bind_history & PIPE_BIND_VERTEX_BUFFER) 2523 dirty |= IRIS_DIRTY_VERTEX_BUFFER_FLUSHES; 2524 2525 ice->state.dirty |= dirty; 2526 ice->state.stage_dirty |= stage_dirty; 2527} 2528 2529/** 2530 * Produce a set of PIPE_CONTROL bits which ensure data written to a 2531 * resource becomes visible, and any stale read cache data is invalidated. 2532 */ 2533uint32_t 2534iris_flush_bits_for_history(struct iris_context *ice, 2535 struct iris_resource *res) 2536{ 2537 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen; 2538 2539 uint32_t flush = PIPE_CONTROL_CS_STALL; 2540 2541 if (res->bind_history & PIPE_BIND_CONSTANT_BUFFER) { 2542 flush |= PIPE_CONTROL_CONST_CACHE_INVALIDATE; 2543 flush |= screen->compiler->indirect_ubos_use_sampler ? 2544 PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE : 2545 PIPE_CONTROL_DATA_CACHE_FLUSH; 2546 } 2547 2548 if (res->bind_history & PIPE_BIND_SAMPLER_VIEW) 2549 flush |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE; 2550 2551 if (res->bind_history & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER)) 2552 flush |= PIPE_CONTROL_VF_CACHE_INVALIDATE; 2553 2554 if (res->bind_history & (PIPE_BIND_SHADER_BUFFER | PIPE_BIND_SHADER_IMAGE)) 2555 flush |= PIPE_CONTROL_DATA_CACHE_FLUSH; 2556 2557 return flush; 2558} 2559 2560void 2561iris_flush_and_dirty_for_history(struct iris_context *ice, 2562 struct iris_batch *batch, 2563 struct iris_resource *res, 2564 uint32_t extra_flags, 2565 const char *reason) 2566{ 2567 if (res->base.b.target != PIPE_BUFFER) 2568 return; 2569 2570 uint32_t flush = iris_flush_bits_for_history(ice, res) | extra_flags; 2571 2572 iris_emit_pipe_control_flush(batch, reason, flush); 2573 2574 iris_dirty_for_history(ice, res); 2575} 2576 2577bool 2578iris_resource_set_clear_color(struct iris_context *ice, 2579 struct iris_resource *res, 2580 union isl_color_value color) 2581{ 2582 if (res->aux.clear_color_unknown || 2583 memcmp(&res->aux.clear_color, &color, sizeof(color)) != 0) { 2584 res->aux.clear_color = color; 2585 res->aux.clear_color_unknown = false; 2586 return true; 2587 } 2588 2589 return false; 2590} 2591 2592static enum pipe_format 2593iris_resource_get_internal_format(struct pipe_resource *p_res) 2594{ 2595 struct iris_resource *res = (void *) p_res; 2596 return res->internal_format; 2597} 2598 2599static const struct u_transfer_vtbl transfer_vtbl = { 2600 .resource_create = iris_resource_create, 2601 .resource_destroy = iris_resource_destroy, 2602 .transfer_map = iris_transfer_map, 2603 .transfer_unmap = iris_transfer_unmap, 2604 .transfer_flush_region = iris_transfer_flush_region, 2605 .get_internal_format = iris_resource_get_internal_format, 2606 .set_stencil = iris_resource_set_separate_stencil, 2607 .get_stencil = iris_resource_get_separate_stencil, 2608}; 2609 2610void 2611iris_init_screen_resource_functions(struct pipe_screen *pscreen) 2612{ 2613 pscreen->query_dmabuf_modifiers = iris_query_dmabuf_modifiers; 2614 pscreen->is_dmabuf_modifier_supported = iris_is_dmabuf_modifier_supported; 2615 pscreen->get_dmabuf_modifier_planes = iris_get_dmabuf_modifier_planes; 2616 pscreen->resource_create_with_modifiers = 2617 iris_resource_create_with_modifiers; 2618 pscreen->resource_create = u_transfer_helper_resource_create; 2619 pscreen->resource_from_user_memory = iris_resource_from_user_memory; 2620 pscreen->resource_from_handle = iris_resource_from_handle; 2621 pscreen->resource_from_memobj = iris_resource_from_memobj_wrapper; 2622 pscreen->resource_get_handle = iris_resource_get_handle; 2623 pscreen->resource_get_param = iris_resource_get_param; 2624 pscreen->resource_destroy = u_transfer_helper_resource_destroy; 2625 pscreen->memobj_create_from_handle = iris_memobj_create_from_handle; 2626 pscreen->memobj_destroy = iris_memobj_destroy; 2627 pscreen->transfer_helper = 2628 u_transfer_helper_create(&transfer_vtbl, true, true, false, true); 2629} 2630 2631void 2632iris_init_resource_functions(struct pipe_context *ctx) 2633{ 2634 ctx->flush_resource = iris_flush_resource; 2635 ctx->invalidate_resource = iris_invalidate_resource; 2636 ctx->buffer_map = u_transfer_helper_transfer_map; 2637 ctx->texture_map = u_transfer_helper_transfer_map; 2638 ctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 2639 ctx->buffer_unmap = u_transfer_helper_transfer_unmap; 2640 ctx->texture_unmap = u_transfer_helper_transfer_unmap; 2641 ctx->buffer_subdata = u_default_buffer_subdata; 2642 ctx->texture_subdata = iris_texture_subdata; 2643} 2644