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 crocus_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_threaded_context.h" 42#include "util/u_transfer.h" 43#include "util/u_transfer_helper.h" 44#include "util/u_upload_mgr.h" 45#include "util/ralloc.h" 46#include "util/u_memory.h" 47#include "crocus_batch.h" 48#include "crocus_context.h" 49#include "crocus_resource.h" 50#include "crocus_screen.h" 51#include "intel/dev/intel_debug.h" 52#include "isl/isl.h" 53#include "drm-uapi/drm_fourcc.h" 54#include "drm-uapi/i915_drm.h" 55 56enum modifier_priority { 57 MODIFIER_PRIORITY_INVALID = 0, 58 MODIFIER_PRIORITY_LINEAR, 59 MODIFIER_PRIORITY_X, 60 MODIFIER_PRIORITY_Y, 61 MODIFIER_PRIORITY_Y_CCS, 62}; 63 64static const uint64_t priority_to_modifier[] = { 65 [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID, 66 [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR, 67 [MODIFIER_PRIORITY_X] = I915_FORMAT_MOD_X_TILED, 68 [MODIFIER_PRIORITY_Y] = I915_FORMAT_MOD_Y_TILED, 69 [MODIFIER_PRIORITY_Y_CCS] = I915_FORMAT_MOD_Y_TILED_CCS, 70}; 71 72static bool 73modifier_is_supported(const struct intel_device_info *devinfo, 74 enum pipe_format pfmt, unsigned bind, 75 uint64_t modifier) 76{ 77 /* XXX: do something real */ 78 switch (modifier) { 79 case I915_FORMAT_MOD_Y_TILED_CCS: 80 return false; 81 case I915_FORMAT_MOD_Y_TILED: 82 if (bind & PIPE_BIND_SCANOUT) 83 return false; 84 return devinfo->ver >= 6; 85 case I915_FORMAT_MOD_X_TILED: 86 case DRM_FORMAT_MOD_LINEAR: 87 return true; 88 case DRM_FORMAT_MOD_INVALID: 89 default: 90 return false; 91 } 92} 93 94static uint64_t 95select_best_modifier(struct intel_device_info *devinfo, 96 const struct pipe_resource *templ, 97 const uint64_t *modifiers, 98 int count) 99{ 100 enum modifier_priority prio = MODIFIER_PRIORITY_INVALID; 101 102 for (int i = 0; i < count; i++) { 103 if (!modifier_is_supported(devinfo, templ->format, templ->bind, 104 modifiers[i])) 105 continue; 106 107 switch (modifiers[i]) { 108 case I915_FORMAT_MOD_Y_TILED_CCS: 109 prio = MAX2(prio, MODIFIER_PRIORITY_Y_CCS); 110 break; 111 case I915_FORMAT_MOD_Y_TILED: 112 prio = MAX2(prio, MODIFIER_PRIORITY_Y); 113 break; 114 case I915_FORMAT_MOD_X_TILED: 115 prio = MAX2(prio, MODIFIER_PRIORITY_X); 116 break; 117 case DRM_FORMAT_MOD_LINEAR: 118 prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR); 119 break; 120 case DRM_FORMAT_MOD_INVALID: 121 default: 122 break; 123 } 124 } 125 126 return priority_to_modifier[prio]; 127} 128 129static enum isl_surf_dim 130crocus_target_to_isl_surf_dim(enum pipe_texture_target target) 131{ 132 switch (target) { 133 case PIPE_BUFFER: 134 case PIPE_TEXTURE_1D: 135 case PIPE_TEXTURE_1D_ARRAY: 136 return ISL_SURF_DIM_1D; 137 case PIPE_TEXTURE_2D: 138 case PIPE_TEXTURE_CUBE: 139 case PIPE_TEXTURE_RECT: 140 case PIPE_TEXTURE_2D_ARRAY: 141 case PIPE_TEXTURE_CUBE_ARRAY: 142 return ISL_SURF_DIM_2D; 143 case PIPE_TEXTURE_3D: 144 return ISL_SURF_DIM_3D; 145 case PIPE_MAX_TEXTURE_TYPES: 146 break; 147 } 148 unreachable("invalid texture type"); 149} 150 151static isl_surf_usage_flags_t 152pipe_bind_to_isl_usage(unsigned bindings) 153{ 154 isl_surf_usage_flags_t usage = 0; 155 156 if (bindings & PIPE_BIND_RENDER_TARGET) 157 usage |= ISL_SURF_USAGE_RENDER_TARGET_BIT; 158 159 if (bindings & PIPE_BIND_SAMPLER_VIEW) 160 usage |= ISL_SURF_USAGE_TEXTURE_BIT; 161 162 if (bindings & (PIPE_BIND_SHADER_IMAGE | PIPE_BIND_SHADER_BUFFER)) 163 usage |= ISL_SURF_USAGE_STORAGE_BIT; 164 165 if (bindings & PIPE_BIND_SCANOUT) 166 usage |= ISL_SURF_USAGE_DISPLAY_BIT; 167 return usage; 168} 169 170static bool 171crocus_resource_configure_main(const struct crocus_screen *screen, 172 struct crocus_resource *res, 173 const struct pipe_resource *templ, 174 uint64_t modifier, uint32_t row_pitch_B) 175{ 176 const struct intel_device_info *devinfo = &screen->devinfo; 177 const struct util_format_description *format_desc = 178 util_format_description(templ->format); 179 const bool has_depth = util_format_has_depth(format_desc); 180 isl_surf_usage_flags_t usage = pipe_bind_to_isl_usage(templ->bind); 181 isl_tiling_flags_t tiling_flags = ISL_TILING_ANY_MASK; 182 183 /* TODO: This used to be because there wasn't BLORP to handle Y-tiling. */ 184 if (devinfo->ver < 6 && !util_format_is_depth_or_stencil(templ->format)) 185 tiling_flags &= ~ISL_TILING_Y0_BIT; 186 187 if (modifier != DRM_FORMAT_MOD_INVALID) { 188 res->mod_info = isl_drm_modifier_get_info(modifier); 189 190 tiling_flags = 1 << res->mod_info->tiling; 191 } else { 192 if (templ->bind & PIPE_BIND_RENDER_TARGET && devinfo->ver < 6) { 193 modifier = I915_FORMAT_MOD_X_TILED; 194 res->mod_info = isl_drm_modifier_get_info(modifier); 195 tiling_flags = 1 << res->mod_info->tiling; 196 } 197 /* Use linear for staging buffers */ 198 if (templ->usage == PIPE_USAGE_STAGING || 199 templ->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR) ) 200 tiling_flags = ISL_TILING_LINEAR_BIT; 201 else if (templ->bind & PIPE_BIND_SCANOUT) 202 tiling_flags = screen->devinfo.has_tiling_uapi ? 203 ISL_TILING_X_BIT : ISL_TILING_LINEAR_BIT; 204 } 205 206 if (templ->target == PIPE_TEXTURE_CUBE || 207 templ->target == PIPE_TEXTURE_CUBE_ARRAY) 208 usage |= ISL_SURF_USAGE_CUBE_BIT; 209 210 if (templ->usage != PIPE_USAGE_STAGING) { 211 if (templ->format == PIPE_FORMAT_S8_UINT) 212 usage |= ISL_SURF_USAGE_STENCIL_BIT; 213 else if (has_depth) { 214 /* combined DS only on gen4/5 */ 215 if (devinfo->ver < 6) { 216 if (templ->format == PIPE_FORMAT_Z24X8_UNORM || 217 templ->format == PIPE_FORMAT_Z24_UNORM_S8_UINT || 218 templ->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) 219 usage |= ISL_SURF_USAGE_STENCIL_BIT; 220 } 221 usage |= ISL_SURF_USAGE_DEPTH_BIT; 222 } 223 224 if (templ->format == PIPE_FORMAT_S8_UINT) 225 tiling_flags = ISL_TILING_W_BIT; 226 } 227 228 const enum isl_format format = 229 crocus_format_for_usage(&screen->devinfo, templ->format, usage).fmt; 230 231 if (row_pitch_B == 0 && templ->usage == PIPE_USAGE_STAGING && 232 templ->target == PIPE_TEXTURE_2D && 233 devinfo->ver < 6) { 234 /* align row pitch to 4 so we can keep using BLT engine */ 235 row_pitch_B = util_format_get_stride(templ->format, templ->width0); 236 row_pitch_B = ALIGN(row_pitch_B, 4); 237 } 238 239 const struct isl_surf_init_info init_info = { 240 .dim = crocus_target_to_isl_surf_dim(templ->target), 241 .format = format, 242 .width = templ->width0, 243 .height = templ->height0, 244 .depth = templ->depth0, 245 .levels = templ->last_level + 1, 246 .array_len = templ->array_size, 247 .samples = MAX2(templ->nr_samples, 1), 248 .min_alignment_B = 0, 249 .row_pitch_B = row_pitch_B, 250 .usage = usage, 251 .tiling_flags = tiling_flags 252 }; 253 254 if (!isl_surf_init_s(&screen->isl_dev, &res->surf, &init_info)) 255 return false; 256 257 /* 258 * Don't create staging surfaces that will use > half the aperture 259 * since staging implies you are sending to another resource, 260 * which there is no way to fit both into aperture. 261 */ 262 if (templ->usage == PIPE_USAGE_STAGING) 263 if (res->surf.size_B > screen->aperture_threshold / 2) 264 return false; 265 266 res->internal_format = templ->format; 267 268 return true; 269} 270 271static void 272crocus_query_dmabuf_modifiers(struct pipe_screen *pscreen, 273 enum pipe_format pfmt, 274 int max, 275 uint64_t *modifiers, 276 unsigned int *external_only, 277 int *count) 278{ 279 struct crocus_screen *screen = (void *) pscreen; 280 const struct intel_device_info *devinfo = &screen->devinfo; 281 282 uint64_t all_modifiers[] = { 283 DRM_FORMAT_MOD_LINEAR, 284 I915_FORMAT_MOD_X_TILED, 285 I915_FORMAT_MOD_Y_TILED, 286 I915_FORMAT_MOD_Y_TILED_CCS, 287 }; 288 289 int supported_mods = 0; 290 291 for (int i = 0; i < ARRAY_SIZE(all_modifiers); i++) { 292 if (!modifier_is_supported(devinfo, pfmt, 0, all_modifiers[i])) 293 continue; 294 295 if (supported_mods < max) { 296 if (modifiers) 297 modifiers[supported_mods] = all_modifiers[i]; 298 299 if (external_only) 300 external_only[supported_mods] = util_format_is_yuv(pfmt); 301 } 302 303 supported_mods++; 304 } 305 306 *count = supported_mods; 307} 308 309static struct pipe_resource * 310crocus_resource_get_separate_stencil(struct pipe_resource *p_res) 311{ 312 return _crocus_resource_get_separate_stencil(p_res); 313} 314 315static void 316crocus_resource_set_separate_stencil(struct pipe_resource *p_res, 317 struct pipe_resource *stencil) 318{ 319 assert(util_format_has_depth(util_format_description(p_res->format))); 320 pipe_resource_reference(&p_res->next, stencil); 321} 322 323void 324crocus_resource_disable_aux(struct crocus_resource *res) 325{ 326 crocus_bo_unreference(res->aux.bo); 327 free(res->aux.state); 328 329 res->aux.usage = ISL_AUX_USAGE_NONE; 330 res->aux.has_hiz = 0; 331 res->aux.surf.size_B = 0; 332 res->aux.surf.levels = 0; 333 res->aux.bo = NULL; 334 res->aux.state = NULL; 335} 336 337static void 338crocus_resource_destroy(struct pipe_screen *screen, 339 struct pipe_resource *resource) 340{ 341 struct crocus_resource *res = (struct crocus_resource *)resource; 342 343 if (resource->target == PIPE_BUFFER) 344 util_range_destroy(&res->valid_buffer_range); 345 346 if (res->shadow) 347 pipe_resource_reference((struct pipe_resource **)&res->shadow, NULL); 348 crocus_resource_disable_aux(res); 349 350 threaded_resource_deinit(resource); 351 crocus_bo_unreference(res->bo); 352 crocus_pscreen_unref(res->orig_screen); 353 free(res); 354} 355 356static struct crocus_resource * 357crocus_alloc_resource(struct pipe_screen *pscreen, 358 const struct pipe_resource *templ) 359{ 360 struct crocus_resource *res = calloc(1, sizeof(struct crocus_resource)); 361 if (!res) 362 return NULL; 363 364 res->base.b = *templ; 365 res->base.b.screen = pscreen; 366 res->orig_screen = crocus_pscreen_ref(pscreen); 367 pipe_reference_init(&res->base.b.reference, 1); 368 threaded_resource_init(&res->base.b, false); 369 370 if (templ->target == PIPE_BUFFER) 371 util_range_init(&res->valid_buffer_range); 372 373 return res; 374} 375 376unsigned 377crocus_get_num_logical_layers(const struct crocus_resource *res, unsigned level) 378{ 379 if (res->surf.dim == ISL_SURF_DIM_3D) 380 return u_minify(res->surf.logical_level0_px.depth, level); 381 else 382 return res->surf.logical_level0_px.array_len; 383} 384 385static enum isl_aux_state ** 386create_aux_state_map(struct crocus_resource *res, enum isl_aux_state initial) 387{ 388 assert(res->aux.state == NULL); 389 390 uint32_t total_slices = 0; 391 for (uint32_t level = 0; level < res->surf.levels; level++) 392 total_slices += crocus_get_num_logical_layers(res, level); 393 394 const size_t per_level_array_size = 395 res->surf.levels * sizeof(enum isl_aux_state *); 396 397 /* We're going to allocate a single chunk of data for both the per-level 398 * reference array and the arrays of aux_state. This makes cleanup 399 * significantly easier. 400 */ 401 const size_t total_size = 402 per_level_array_size + total_slices * sizeof(enum isl_aux_state); 403 404 void *data = malloc(total_size); 405 if (!data) 406 return NULL; 407 408 enum isl_aux_state **per_level_arr = data; 409 enum isl_aux_state *s = data + per_level_array_size; 410 for (uint32_t level = 0; level < res->surf.levels; level++) { 411 per_level_arr[level] = s; 412 const unsigned level_layers = crocus_get_num_logical_layers(res, level); 413 for (uint32_t a = 0; a < level_layers; a++) 414 *(s++) = initial; 415 } 416 assert((void *)s == data + total_size); 417 418 return per_level_arr; 419} 420 421/** 422 * Configure aux for the resource, but don't allocate it. For images which 423 * might be shared with modifiers, we must allocate the image and aux data in 424 * a single bo. 425 * 426 * Returns false on unexpected error (e.g. allocation failed, or invalid 427 * configuration result). 428 */ 429static bool 430crocus_resource_configure_aux(struct crocus_screen *screen, 431 struct crocus_resource *res, bool imported, 432 uint64_t *aux_size_B, 433 uint32_t *alloc_flags) 434{ 435 const struct intel_device_info *devinfo = &screen->devinfo; 436 437 /* Try to create the auxiliary surfaces allowed by the modifier or by 438 * the user if no modifier is specified. 439 */ 440 assert(!res->mod_info || res->mod_info->aux_usage == ISL_AUX_USAGE_NONE); 441 442 const bool has_mcs = devinfo->ver >= 7 && !res->mod_info && 443 isl_surf_get_mcs_surf(&screen->isl_dev, &res->surf, &res->aux.surf); 444 445 const bool has_hiz = devinfo->ver >= 6 && !res->mod_info && 446 !INTEL_DEBUG(DEBUG_NO_HIZ) && 447 isl_surf_get_hiz_surf(&screen->isl_dev, &res->surf, &res->aux.surf); 448 449 const bool has_ccs = 450 ((devinfo->ver >= 7 && !res->mod_info && !INTEL_DEBUG(DEBUG_NO_CCS)) || 451 (res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE)) && 452 isl_surf_get_ccs_surf(&screen->isl_dev, &res->surf, NULL, 453 &res->aux.surf, 0); 454 455 /* Having more than one type of compression is impossible */ 456 assert(has_ccs + has_mcs + has_hiz <= 1); 457 458 if (res->mod_info && has_ccs) { 459 res->aux.usage = res->mod_info->aux_usage; 460 } else if (has_mcs) { 461 res->aux.usage = ISL_AUX_USAGE_MCS; 462 } else if (has_hiz) { 463 res->aux.usage = ISL_AUX_USAGE_HIZ; 464 } else if (has_ccs) { 465 if (isl_format_supports_ccs_d(devinfo, res->surf.format)) 466 res->aux.usage = ISL_AUX_USAGE_CCS_D; 467 } 468 469 enum isl_aux_state initial_state = ISL_AUX_STATE_AUX_INVALID; 470 *aux_size_B = 0; 471 *alloc_flags = 0; 472 assert(!res->aux.bo); 473 474 switch (res->aux.usage) { 475 case ISL_AUX_USAGE_NONE: 476 /* Having no aux buffer is only okay if there's no modifier with aux. */ 477 res->aux.surf.levels = 0; 478 return !res->mod_info || res->mod_info->aux_usage == ISL_AUX_USAGE_NONE; 479 case ISL_AUX_USAGE_HIZ: 480 initial_state = ISL_AUX_STATE_AUX_INVALID; 481 break; 482 case ISL_AUX_USAGE_MCS: 483 /* The Ivybridge PRM, Vol 2 Part 1 p326 says: 484 * 485 * "When MCS buffer is enabled and bound to MSRT, it is required 486 * that it is cleared prior to any rendering." 487 * 488 * Since we only use the MCS buffer for rendering, we just clear it 489 * immediately on allocation. The clear value for MCS buffers is all 490 * 1's, so we simply memset it to 0xff. 491 */ 492 initial_state = ISL_AUX_STATE_CLEAR; 493 break; 494 case ISL_AUX_USAGE_CCS_D: 495 /* When CCS_E is used, we need to ensure that the CCS starts off in 496 * a valid state. From the Sky Lake PRM, "MCS Buffer for Render 497 * Target(s)": 498 * 499 * "If Software wants to enable Color Compression without Fast 500 * clear, Software needs to initialize MCS with zeros." 501 * 502 * A CCS value of 0 indicates that the corresponding block is in the 503 * pass-through state which is what we want. 504 * 505 * For CCS_D, do the same thing. On Gen9+, this avoids having any 506 * undefined bits in the aux buffer. 507 */ 508 if (imported) 509 initial_state = 510 isl_drm_modifier_get_default_aux_state(res->mod_info->modifier); 511 else 512 initial_state = ISL_AUX_STATE_PASS_THROUGH; 513 *alloc_flags |= BO_ALLOC_ZEROED; 514 break; 515 default: 516 unreachable("non-crocus aux"); 517 } 518 519 /* Create the aux_state for the auxiliary buffer. */ 520 res->aux.state = create_aux_state_map(res, initial_state); 521 if (!res->aux.state) 522 return false; 523 524 /* Increase the aux offset if the main and aux surfaces will share a BO. */ 525 res->aux.offset = 526 !res->mod_info || res->mod_info->aux_usage == res->aux.usage ? 527 ALIGN(res->surf.size_B, res->aux.surf.alignment_B) : 0; 528 uint64_t size = res->aux.surf.size_B; 529 530 /* Allocate space in the buffer for storing the clear color. On modern 531 * platforms (gen > 9), we can read it directly from such buffer. 532 * 533 * On gen <= 9, we are going to store the clear color on the buffer 534 * anyways, and copy it back to the surface state during state emission. 535 * 536 * Also add some padding to make sure the fast clear color state buffer 537 * starts at a 4K alignment. We believe that 256B might be enough, but due 538 * to lack of testing we will leave this as 4K for now. 539 */ 540 size = ALIGN(size, 4096); 541 *aux_size_B = size; 542 543 if (isl_aux_usage_has_hiz(res->aux.usage)) { 544 for (unsigned level = 0; level < res->surf.levels; ++level) { 545 uint32_t width = u_minify(res->surf.phys_level0_sa.width, level); 546 uint32_t height = u_minify(res->surf.phys_level0_sa.height, level); 547 548 /* Disable HiZ for LOD > 0 unless the width/height are 8x4 aligned. 549 * For LOD == 0, we can grow the dimensions to make it work. 550 */ 551 if (devinfo->verx10 < 75 || 552 (level == 0 || ((width & 7) == 0 && (height & 3) == 0))) 553 res->aux.has_hiz |= 1 << level; 554 } 555 } 556 557 return true; 558} 559 560/** 561 * Initialize the aux buffer contents. 562 * 563 * Returns false on unexpected error (e.g. mapping a BO failed). 564 */ 565static bool 566crocus_resource_init_aux_buf(struct crocus_resource *res, uint32_t alloc_flags) 567{ 568 if (!(alloc_flags & BO_ALLOC_ZEROED)) { 569 void *map = crocus_bo_map(NULL, res->aux.bo, MAP_WRITE | MAP_RAW); 570 571 if (!map) 572 return false; 573 574 if (crocus_resource_get_aux_state(res, 0, 0) != ISL_AUX_STATE_AUX_INVALID) { 575 uint8_t memset_value = isl_aux_usage_has_mcs(res->aux.usage) ? 0xFF : 0; 576 memset((char*)map + res->aux.offset, memset_value, 577 res->aux.surf.size_B); 578 } 579 580 crocus_bo_unmap(res->aux.bo); 581 } 582 583 return true; 584} 585 586/** 587 * Allocate the initial aux surface for a resource based on aux.usage 588 * 589 * Returns false on unexpected error (e.g. allocation failed, or invalid 590 * configuration result). 591 */ 592static bool 593crocus_resource_alloc_separate_aux(struct crocus_screen *screen, 594 struct crocus_resource *res) 595{ 596 uint32_t alloc_flags; 597 uint64_t size; 598 if (!crocus_resource_configure_aux(screen, res, false, &size, &alloc_flags)) 599 return false; 600 601 if (size == 0) 602 return true; 603 604 /* Allocate the auxiliary buffer. ISL has stricter set of alignment rules 605 * the drm allocator. Therefore, one can pass the ISL dimensions in terms 606 * of bytes instead of trying to recalculate based on different format 607 * block sizes. 608 */ 609 res->aux.bo = crocus_bo_alloc_tiled(screen->bufmgr, "aux buffer", size, 4096, 610 isl_tiling_to_i915_tiling(res->aux.surf.tiling), 611 res->aux.surf.row_pitch_B, alloc_flags); 612 if (!res->aux.bo) { 613 return false; 614 } 615 616 if (!crocus_resource_init_aux_buf(res, alloc_flags)) 617 return false; 618 619 return true; 620} 621 622void 623crocus_resource_finish_aux_import(struct pipe_screen *pscreen, 624 struct crocus_resource *res) 625{ 626 struct crocus_screen *screen = (struct crocus_screen *)pscreen; 627 assert(crocus_resource_unfinished_aux_import(res)); 628 assert(!res->mod_info->supports_clear_color); 629 630 struct crocus_resource *aux_res = (void *) res->base.b.next; 631 assert(aux_res->aux.surf.row_pitch_B && aux_res->aux.offset && 632 aux_res->aux.bo); 633 634 assert(res->bo == aux_res->aux.bo); 635 crocus_bo_reference(aux_res->aux.bo); 636 res->aux.bo = aux_res->aux.bo; 637 638 res->aux.offset = aux_res->aux.offset; 639 640 assert(res->bo->size >= (res->aux.offset + res->aux.surf.size_B)); 641 assert(aux_res->aux.surf.row_pitch_B == res->aux.surf.row_pitch_B); 642 643 crocus_resource_destroy(&screen->base, res->base.b.next); 644 res->base.b.next = NULL; 645} 646 647static struct pipe_resource * 648crocus_resource_create_for_buffer(struct pipe_screen *pscreen, 649 const struct pipe_resource *templ) 650{ 651 struct crocus_screen *screen = (struct crocus_screen *)pscreen; 652 struct crocus_resource *res = crocus_alloc_resource(pscreen, templ); 653 654 assert(templ->target == PIPE_BUFFER); 655 assert(templ->height0 <= 1); 656 assert(templ->depth0 <= 1); 657 assert(templ->format == PIPE_FORMAT_NONE || 658 util_format_get_blocksize(templ->format) == 1); 659 660 res->internal_format = templ->format; 661 res->surf.tiling = ISL_TILING_LINEAR; 662 663 const char *name = templ->target == PIPE_BUFFER ? "buffer" : "miptree"; 664 665 res->bo = crocus_bo_alloc(screen->bufmgr, name, templ->width0); 666 if (!res->bo) { 667 crocus_resource_destroy(pscreen, &res->base.b); 668 return NULL; 669 } 670 671 return &res->base.b; 672} 673 674static struct pipe_resource * 675crocus_resource_create_with_modifiers(struct pipe_screen *pscreen, 676 const struct pipe_resource *templ, 677 const uint64_t *modifiers, 678 int modifiers_count) 679{ 680 struct crocus_screen *screen = (struct crocus_screen *)pscreen; 681 struct intel_device_info *devinfo = &screen->devinfo; 682 struct crocus_resource *res = crocus_alloc_resource(pscreen, templ); 683 684 if (!res) 685 return NULL; 686 687 uint64_t modifier = 688 select_best_modifier(devinfo, templ, modifiers, modifiers_count); 689 690 if (modifier == DRM_FORMAT_MOD_INVALID && modifiers_count > 0) { 691 fprintf(stderr, "Unsupported modifier, resource creation failed.\n"); 692 goto fail; 693 } 694 695 if (templ->usage == PIPE_USAGE_STAGING && 696 templ->bind == PIPE_BIND_DEPTH_STENCIL && 697 devinfo->ver < 6) 698 goto fail; 699 700 const bool isl_surf_created_successfully = 701 crocus_resource_configure_main(screen, res, templ, modifier, 0); 702 if (!isl_surf_created_successfully) 703 goto fail; 704 705 const char *name = "miptree"; 706 707 unsigned int flags = 0; 708 if (templ->usage == PIPE_USAGE_STAGING) 709 flags |= BO_ALLOC_COHERENT; 710 711 /* Scanout buffers need to be WC. */ 712 if (templ->bind & PIPE_BIND_SCANOUT) 713 flags |= BO_ALLOC_SCANOUT; 714 715 uint64_t aux_size = 0; 716 uint32_t aux_preferred_alloc_flags; 717 718 if (!crocus_resource_configure_aux(screen, res, false, &aux_size, 719 &aux_preferred_alloc_flags)) { 720 goto fail; 721 } 722 723 /* Modifiers require the aux data to be in the same buffer as the main 724 * surface, but we combine them even when a modifiers is not being used. 725 */ 726 const uint64_t bo_size = 727 MAX2(res->surf.size_B, res->aux.offset + aux_size); 728 uint32_t alignment = MAX2(4096, res->surf.alignment_B); 729 res->bo = crocus_bo_alloc_tiled(screen->bufmgr, name, bo_size, alignment, 730 isl_tiling_to_i915_tiling(res->surf.tiling), 731 res->surf.row_pitch_B, flags); 732 733 if (!res->bo) 734 goto fail; 735 736 if (aux_size > 0) { 737 res->aux.bo = res->bo; 738 crocus_bo_reference(res->aux.bo); 739 if (!crocus_resource_init_aux_buf(res, flags)) 740 goto fail; 741 } 742 743 if (templ->format == PIPE_FORMAT_S8_UINT && !(templ->usage == PIPE_USAGE_STAGING) && 744 devinfo->ver == 7 && (templ->bind & PIPE_BIND_SAMPLER_VIEW)) { 745 struct pipe_resource templ_shadow = (struct pipe_resource) { 746 .usage = 0, 747 .bind = PIPE_BIND_SAMPLER_VIEW, 748 .width0 = res->base.b.width0, 749 .height0 = res->base.b.height0, 750 .depth0 = res->base.b.depth0, 751 .last_level = res->base.b.last_level, 752 .nr_samples = res->base.b.nr_samples, 753 .nr_storage_samples = res->base.b.nr_storage_samples, 754 .array_size = res->base.b.array_size, 755 .format = PIPE_FORMAT_R8_UINT, 756 .target = res->base.b.target, 757 }; 758 res->shadow = (struct crocus_resource *)screen->base.resource_create(&screen->base, &templ_shadow); 759 assert(res->shadow); 760 } 761 762 return &res->base.b; 763 764fail: 765 fprintf(stderr, "XXX: resource creation failed\n"); 766 crocus_resource_destroy(pscreen, &res->base.b); 767 return NULL; 768 769} 770 771static struct pipe_resource * 772crocus_resource_create(struct pipe_screen *pscreen, 773 const struct pipe_resource *templ) 774{ 775 if (templ->target == PIPE_BUFFER) 776 return crocus_resource_create_for_buffer(pscreen, templ); 777 else 778 return crocus_resource_create_with_modifiers(pscreen, templ, NULL, 0); 779} 780 781static uint64_t 782tiling_to_modifier(uint32_t tiling) 783{ 784 static const uint64_t map[] = { 785 [I915_TILING_NONE] = DRM_FORMAT_MOD_LINEAR, 786 [I915_TILING_X] = I915_FORMAT_MOD_X_TILED, 787 [I915_TILING_Y] = I915_FORMAT_MOD_Y_TILED, 788 }; 789 790 assert(tiling < ARRAY_SIZE(map)); 791 792 return map[tiling]; 793} 794 795static struct pipe_resource * 796crocus_resource_from_user_memory(struct pipe_screen *pscreen, 797 const struct pipe_resource *templ, 798 void *user_memory) 799{ 800 struct crocus_screen *screen = (struct crocus_screen *)pscreen; 801 struct crocus_bufmgr *bufmgr = screen->bufmgr; 802 struct crocus_resource *res = crocus_alloc_resource(pscreen, templ); 803 if (!res) 804 return NULL; 805 806 assert(templ->target == PIPE_BUFFER); 807 808 res->internal_format = templ->format; 809 res->bo = crocus_bo_create_userptr(bufmgr, "user", 810 user_memory, templ->width0); 811 if (!res->bo) { 812 free(res); 813 return NULL; 814 } 815 816 util_range_add(&res->base.b, &res->valid_buffer_range, 0, templ->width0); 817 818 return &res->base.b; 819} 820 821static struct pipe_resource * 822crocus_resource_from_handle(struct pipe_screen *pscreen, 823 const struct pipe_resource *templ, 824 struct winsys_handle *whandle, 825 unsigned usage) 826{ 827 assert(templ->target != PIPE_BUFFER); 828 829 struct crocus_screen *screen = (struct crocus_screen *)pscreen; 830 struct crocus_bufmgr *bufmgr = screen->bufmgr; 831 struct crocus_resource *res = crocus_alloc_resource(pscreen, templ); 832 833 if (!res) 834 return NULL; 835 836 switch (whandle->type) { 837 case WINSYS_HANDLE_TYPE_FD: 838 res->bo = crocus_bo_import_dmabuf(bufmgr, whandle->handle, 839 whandle->modifier); 840 break; 841 case WINSYS_HANDLE_TYPE_SHARED: 842 res->bo = crocus_bo_gem_create_from_name(bufmgr, "winsys image", 843 whandle->handle); 844 break; 845 default: 846 unreachable("invalid winsys handle type"); 847 } 848 if (!res->bo) 849 return NULL; 850 851 res->offset = whandle->offset; 852 res->external_format = whandle->format; 853 854 if (whandle->plane < util_format_get_num_planes(whandle->format)) { 855 const uint64_t modifier = 856 whandle->modifier != DRM_FORMAT_MOD_INVALID ? 857 whandle->modifier : tiling_to_modifier(res->bo->tiling_mode); 858 859 UNUSED const bool isl_surf_created_successfully = 860 crocus_resource_configure_main(screen, res, templ, modifier, 861 whandle->stride); 862 assert(isl_surf_created_successfully); 863 assert(res->bo->tiling_mode == 864 isl_tiling_to_i915_tiling(res->surf.tiling)); 865 866 // XXX: create_ccs_buf_for_image? 867 if (whandle->modifier == DRM_FORMAT_MOD_INVALID) { 868 if (!crocus_resource_alloc_separate_aux(screen, res)) 869 goto fail; 870 } else { 871 if (res->mod_info->aux_usage != ISL_AUX_USAGE_NONE) { 872 uint32_t alloc_flags; 873 uint64_t size; 874 UNUSED bool ok = crocus_resource_configure_aux(screen, res, true, &size, 875 &alloc_flags); 876 assert(ok); 877 /* The gallium dri layer will create a separate plane resource 878 * for the aux image. crocus_resource_finish_aux_import will 879 * merge the separate aux parameters back into a single 880 * crocus_resource. 881 */ 882 } 883 } 884 } else { 885 /* Save modifier import information to reconstruct later. After 886 * import, this will be available under a second image accessible 887 * from the main image with res->base.next. See 888 * crocus_resource_finish_aux_import. 889 */ 890 res->aux.surf.row_pitch_B = whandle->stride; 891 res->aux.offset = whandle->offset; 892 res->aux.bo = res->bo; 893 res->bo = NULL; 894 } 895 896 return &res->base.b; 897 898fail: 899 crocus_resource_destroy(pscreen, &res->base.b); 900 return NULL; 901} 902 903static struct pipe_resource * 904crocus_resource_from_memobj(struct pipe_screen *pscreen, 905 const struct pipe_resource *templ, 906 struct pipe_memory_object *pmemobj, 907 uint64_t offset) 908{ 909 struct crocus_screen *screen = (struct crocus_screen *)pscreen; 910 struct crocus_memory_object *memobj = (struct crocus_memory_object *)pmemobj; 911 struct crocus_resource *res = crocus_alloc_resource(pscreen, templ); 912 913 if (!res) 914 return NULL; 915 916 /* Disable Depth, and combined Depth+Stencil for now. */ 917 if (util_format_has_depth(util_format_description(templ->format))) 918 return NULL; 919 920 if (templ->flags & PIPE_RESOURCE_FLAG_TEXTURING_MORE_LIKELY) { 921 UNUSED const bool isl_surf_created_successfully = 922 crocus_resource_configure_main(screen, res, templ, DRM_FORMAT_MOD_INVALID, 0); 923 assert(isl_surf_created_successfully); 924 } 925 926 res->bo = memobj->bo; 927 res->offset = offset; 928 res->external_format = memobj->format; 929 930 crocus_bo_reference(memobj->bo); 931 932 return &res->base.b; 933} 934 935static void 936crocus_flush_resource(struct pipe_context *ctx, struct pipe_resource *resource) 937{ 938 struct crocus_context *ice = (struct crocus_context *)ctx; 939 struct crocus_resource *res = (void *) resource; 940 const struct isl_drm_modifier_info *mod = res->mod_info; 941 942 crocus_resource_prepare_access(ice, res, 943 0, INTEL_REMAINING_LEVELS, 944 0, INTEL_REMAINING_LAYERS, 945 mod ? mod->aux_usage : ISL_AUX_USAGE_NONE, 946 mod ? mod->supports_clear_color : false); 947} 948 949static void 950crocus_resource_disable_aux_on_first_query(struct pipe_resource *resource, 951 unsigned usage) 952{ 953 struct crocus_resource *res = (struct crocus_resource *)resource; 954 bool mod_with_aux = 955 res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 956 957 /* Disable aux usage if explicit flush not set and this is the first time 958 * we are dealing with this resource and the resource was not created with 959 * a modifier with aux. 960 */ 961 if (!mod_with_aux && 962 (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH) && res->aux.usage != 0) && 963 p_atomic_read(&resource->reference.count) == 1) { 964 crocus_resource_disable_aux(res); 965 } 966} 967 968static bool 969crocus_resource_get_param(struct pipe_screen *pscreen, 970 struct pipe_context *context, 971 struct pipe_resource *resource, 972 unsigned plane, 973 unsigned layer, 974 unsigned level, 975 enum pipe_resource_param param, 976 unsigned handle_usage, 977 uint64_t *value) 978{ 979 struct crocus_screen *screen = (struct crocus_screen *)pscreen; 980 struct crocus_resource *res = (struct crocus_resource *)resource; 981 bool mod_with_aux = 982 res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 983 bool wants_aux = mod_with_aux && plane > 0; 984 bool result; 985 unsigned handle; 986 987 if (crocus_resource_unfinished_aux_import(res)) 988 crocus_resource_finish_aux_import(pscreen, res); 989 990 struct crocus_bo *bo = wants_aux ? res->aux.bo : res->bo; 991 992 crocus_resource_disable_aux_on_first_query(resource, handle_usage); 993 994 switch (param) { 995 case PIPE_RESOURCE_PARAM_NPLANES: 996 if (mod_with_aux) { 997 *value = util_format_get_num_planes(res->external_format); 998 } else { 999 unsigned count = 0; 1000 for (struct pipe_resource *cur = resource; cur; cur = cur->next) 1001 count++; 1002 *value = count; 1003 } 1004 return true; 1005 case PIPE_RESOURCE_PARAM_STRIDE: 1006 *value = wants_aux ? res->aux.surf.row_pitch_B : res->surf.row_pitch_B; 1007 return true; 1008 case PIPE_RESOURCE_PARAM_OFFSET: 1009 *value = wants_aux ? res->aux.offset : 0; 1010 return true; 1011 case PIPE_RESOURCE_PARAM_MODIFIER: 1012 *value = res->mod_info ? res->mod_info->modifier : 1013 tiling_to_modifier(isl_tiling_to_i915_tiling(res->surf.tiling)); 1014 return true; 1015 case PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED: 1016 result = crocus_bo_flink(bo, &handle) == 0; 1017 if (result) 1018 *value = handle; 1019 return result; 1020 case PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS: { 1021 /* Because we share the same drm file across multiple crocus_screen, when 1022 * we export a GEM handle we must make sure it is valid in the DRM file 1023 * descriptor the caller is using (this is the FD given at screen 1024 * creation). 1025 */ 1026 uint32_t handle; 1027 if (crocus_bo_export_gem_handle_for_device(bo, screen->winsys_fd, &handle)) 1028 return false; 1029 *value = handle; 1030 return true; 1031 } 1032 case PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD: 1033 result = crocus_bo_export_dmabuf(bo, (int *) &handle) == 0; 1034 if (result) 1035 *value = handle; 1036 return result; 1037 default: 1038 return false; 1039 } 1040} 1041 1042static bool 1043crocus_resource_get_handle(struct pipe_screen *pscreen, 1044 struct pipe_context *ctx, 1045 struct pipe_resource *resource, 1046 struct winsys_handle *whandle, 1047 unsigned usage) 1048{ 1049 struct crocus_screen *screen = (struct crocus_screen *) pscreen; 1050 struct crocus_resource *res = (struct crocus_resource *)resource; 1051 bool mod_with_aux = 1052 res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 1053 1054 crocus_resource_disable_aux_on_first_query(resource, usage); 1055 1056 struct crocus_bo *bo; 1057 if (mod_with_aux && whandle->plane > 0) { 1058 assert(res->aux.bo); 1059 bo = res->aux.bo; 1060 whandle->stride = res->aux.surf.row_pitch_B; 1061 whandle->offset = res->aux.offset; 1062 } else { 1063 /* If this is a buffer, stride should be 0 - no need to special case */ 1064 whandle->stride = res->surf.row_pitch_B; 1065 bo = res->bo; 1066 } 1067 whandle->format = res->external_format; 1068 whandle->modifier = 1069 res->mod_info ? res->mod_info->modifier 1070 : tiling_to_modifier(res->bo->tiling_mode); 1071 1072#ifndef NDEBUG 1073 enum isl_aux_usage allowed_usage = 1074 res->mod_info ? res->mod_info->aux_usage : ISL_AUX_USAGE_NONE; 1075 1076 if (res->aux.usage != allowed_usage) { 1077 enum isl_aux_state aux_state = crocus_resource_get_aux_state(res, 0, 0); 1078 assert(aux_state == ISL_AUX_STATE_RESOLVED || 1079 aux_state == ISL_AUX_STATE_PASS_THROUGH); 1080 } 1081#endif 1082 1083 switch (whandle->type) { 1084 case WINSYS_HANDLE_TYPE_SHARED: 1085 return crocus_bo_flink(bo, &whandle->handle) == 0; 1086 case WINSYS_HANDLE_TYPE_KMS: { 1087 /* Because we share the same drm file across multiple crocus_screen, when 1088 * we export a GEM handle we must make sure it is valid in the DRM file 1089 * descriptor the caller is using (this is the FD given at screen 1090 * creation). 1091 */ 1092 uint32_t handle; 1093 if (crocus_bo_export_gem_handle_for_device(bo, screen->winsys_fd, &handle)) 1094 return false; 1095 whandle->handle = handle; 1096 return true; 1097 } 1098 case WINSYS_HANDLE_TYPE_FD: 1099 return crocus_bo_export_dmabuf(bo, (int *) &whandle->handle) == 0; 1100 } 1101 1102 return false; 1103} 1104 1105static bool 1106resource_is_busy(struct crocus_context *ice, 1107 struct crocus_resource *res) 1108{ 1109 bool busy = crocus_bo_busy(res->bo); 1110 1111 for (int i = 0; i < ice->batch_count; i++) 1112 busy |= crocus_batch_references(&ice->batches[i], res->bo); 1113 1114 return busy; 1115} 1116 1117void 1118crocus_replace_buffer_storage(struct pipe_context *ctx, 1119 struct pipe_resource *p_dst, 1120 struct pipe_resource *p_src, 1121 unsigned num_rebinds, 1122 uint32_t rebind_mask, 1123 uint32_t delete_buffer_id) 1124{ 1125 struct crocus_screen *screen = (void *) ctx->screen; 1126 struct crocus_context *ice = (void *) ctx; 1127 struct crocus_resource *dst = (void *) p_dst; 1128 struct crocus_resource *src = (void *) p_src; 1129 1130 assert(memcmp(&dst->surf, &src->surf, sizeof(dst->surf)) == 0); 1131 1132 struct crocus_bo *old_bo = dst->bo; 1133 1134 /* Swap out the backing storage */ 1135 crocus_bo_reference(src->bo); 1136 dst->bo = src->bo; 1137 1138 /* Rebind the buffer, replacing any state referring to the old BO's 1139 * address, and marking state dirty so it's reemitted. 1140 */ 1141 screen->vtbl.rebind_buffer(ice, dst); 1142 1143 crocus_bo_unreference(old_bo); 1144} 1145 1146static void 1147crocus_invalidate_resource(struct pipe_context *ctx, 1148 struct pipe_resource *resource) 1149{ 1150 struct crocus_screen *screen = (void *) ctx->screen; 1151 struct crocus_context *ice = (void *) ctx; 1152 struct crocus_resource *res = (void *) resource; 1153 1154 if (resource->target != PIPE_BUFFER) 1155 return; 1156 1157 /* If it's already invalidated, don't bother doing anything. */ 1158 if (res->valid_buffer_range.start > res->valid_buffer_range.end) 1159 return; 1160 1161 if (!resource_is_busy(ice, res)) { 1162 /* The resource is idle, so just mark that it contains no data and 1163 * keep using the same underlying buffer object. 1164 */ 1165 util_range_set_empty(&res->valid_buffer_range); 1166 return; 1167 } 1168 1169 /* Otherwise, try and replace the backing storage with a new BO. */ 1170 1171 /* We can't reallocate memory we didn't allocate in the first place. */ 1172 if (res->bo->userptr) 1173 return; 1174 1175 struct crocus_bo *old_bo = res->bo; 1176 struct crocus_bo *new_bo = 1177 crocus_bo_alloc(screen->bufmgr, res->bo->name, resource->width0); 1178 1179 if (!new_bo) 1180 return; 1181 1182 /* Swap out the backing storage */ 1183 res->bo = new_bo; 1184 1185 /* Rebind the buffer, replacing any state referring to the old BO's 1186 * address, and marking state dirty so it's reemitted. 1187 */ 1188 screen->vtbl.rebind_buffer(ice, res); 1189 1190 util_range_set_empty(&res->valid_buffer_range); 1191 1192 crocus_bo_unreference(old_bo); 1193} 1194 1195static void 1196crocus_flush_staging_region(struct pipe_transfer *xfer, 1197 const struct pipe_box *flush_box) 1198{ 1199 if (!(xfer->usage & PIPE_MAP_WRITE)) 1200 return; 1201 1202 struct crocus_transfer *map = (void *) xfer; 1203 1204 struct pipe_box src_box = *flush_box; 1205 1206 /* Account for extra alignment padding in staging buffer */ 1207 if (xfer->resource->target == PIPE_BUFFER) 1208 src_box.x += xfer->box.x % CROCUS_MAP_BUFFER_ALIGNMENT; 1209 1210 struct pipe_box dst_box = (struct pipe_box) { 1211 .x = xfer->box.x + flush_box->x, 1212 .y = xfer->box.y + flush_box->y, 1213 .z = xfer->box.z + flush_box->z, 1214 .width = flush_box->width, 1215 .height = flush_box->height, 1216 .depth = flush_box->depth, 1217 }; 1218 1219 crocus_copy_region(map->blorp, map->batch, xfer->resource, xfer->level, 1220 dst_box.x, dst_box.y, dst_box.z, map->staging, 0, 1221 &src_box); 1222} 1223 1224static void 1225crocus_unmap_copy_region(struct crocus_transfer *map) 1226{ 1227 crocus_resource_destroy(map->staging->screen, map->staging); 1228 1229 map->ptr = NULL; 1230} 1231 1232static void 1233crocus_map_copy_region(struct crocus_transfer *map) 1234{ 1235 struct pipe_screen *pscreen = &map->batch->screen->base; 1236 struct pipe_transfer *xfer = &map->base.b; 1237 struct pipe_box *box = &xfer->box; 1238 struct crocus_resource *res = (void *) xfer->resource; 1239 1240 unsigned extra = xfer->resource->target == PIPE_BUFFER ? 1241 box->x % CROCUS_MAP_BUFFER_ALIGNMENT : 0; 1242 1243 struct pipe_resource templ = (struct pipe_resource) { 1244 .usage = PIPE_USAGE_STAGING, 1245 .width0 = box->width + extra, 1246 .height0 = box->height, 1247 .depth0 = 1, 1248 .nr_samples = xfer->resource->nr_samples, 1249 .nr_storage_samples = xfer->resource->nr_storage_samples, 1250 .array_size = box->depth, 1251 .format = res->internal_format, 1252 }; 1253 1254 if (xfer->resource->target == PIPE_BUFFER) 1255 templ.target = PIPE_BUFFER; 1256 else if (templ.array_size > 1) 1257 templ.target = PIPE_TEXTURE_2D_ARRAY; 1258 else 1259 templ.target = PIPE_TEXTURE_2D; 1260 1261 map->staging = crocus_resource_create(pscreen, &templ); 1262 assert(map->staging); 1263 1264 if (templ.target != PIPE_BUFFER) { 1265 struct isl_surf *surf = &((struct crocus_resource *) map->staging)->surf; 1266 xfer->stride = isl_surf_get_row_pitch_B(surf); 1267 xfer->layer_stride = isl_surf_get_array_pitch(surf); 1268 } 1269 1270 if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 1271 crocus_copy_region(map->blorp, map->batch, map->staging, 0, extra, 0, 0, 1272 xfer->resource, xfer->level, box); 1273 /* Ensure writes to the staging BO land before we map it below. */ 1274 crocus_emit_pipe_control_flush(map->batch, 1275 "transfer read: flush before mapping", 1276 PIPE_CONTROL_RENDER_TARGET_FLUSH | 1277 PIPE_CONTROL_CS_STALL); 1278 } 1279 1280 struct crocus_bo *staging_bo = crocus_resource_bo(map->staging); 1281 1282 if (crocus_batch_references(map->batch, staging_bo)) 1283 crocus_batch_flush(map->batch); 1284 1285 map->ptr = 1286 crocus_bo_map(map->dbg, staging_bo, xfer->usage & MAP_FLAGS) + extra; 1287 1288 map->unmap = crocus_unmap_copy_region; 1289} 1290 1291static void 1292get_image_offset_el(const struct isl_surf *surf, unsigned level, unsigned z, 1293 unsigned *out_x0_el, unsigned *out_y0_el) 1294{ 1295 ASSERTED uint32_t z0_el, a0_el; 1296 if (surf->dim == ISL_SURF_DIM_3D) { 1297 isl_surf_get_image_offset_el(surf, level, 0, z, 1298 out_x0_el, out_y0_el, &z0_el, &a0_el); 1299 } else { 1300 isl_surf_get_image_offset_el(surf, level, z, 0, 1301 out_x0_el, out_y0_el, &z0_el, &a0_el); 1302 } 1303 assert(z0_el == 0 && a0_el == 0); 1304} 1305 1306void 1307crocus_resource_get_image_offset(struct crocus_resource *res, 1308 uint32_t level, uint32_t z, 1309 uint32_t *x, uint32_t *y) 1310{ 1311 get_image_offset_el(&res->surf, level, z, x, y); 1312} 1313 1314/** 1315 * Get pointer offset into stencil buffer. 1316 * 1317 * The stencil buffer is W tiled. Since the GTT is incapable of W fencing, we 1318 * must decode the tile's layout in software. 1319 * 1320 * See 1321 * - PRM, 2011 Sandy Bridge, Volume 1, Part 2, Section 4.5.2.1 W-Major Tile 1322 * Format. 1323 * - PRM, 2011 Sandy Bridge, Volume 1, Part 2, Section 4.5.3 Tiling Algorithm 1324 * 1325 * Even though the returned offset is always positive, the return type is 1326 * signed due to 1327 * commit e8b1c6d6f55f5be3bef25084fdd8b6127517e137 1328 * mesa: Fix return type of _mesa_get_format_bytes() (#37351) 1329 */ 1330static intptr_t 1331s8_offset(uint32_t stride, uint32_t x, uint32_t y, bool swizzled) 1332{ 1333 uint32_t tile_size = 4096; 1334 uint32_t tile_width = 64; 1335 uint32_t tile_height = 64; 1336 uint32_t row_size = 64 * stride / 2; /* Two rows are interleaved. */ 1337 1338 uint32_t tile_x = x / tile_width; 1339 uint32_t tile_y = y / tile_height; 1340 1341 /* The byte's address relative to the tile's base addres. */ 1342 uint32_t byte_x = x % tile_width; 1343 uint32_t byte_y = y % tile_height; 1344 1345 uintptr_t u = tile_y * row_size 1346 + tile_x * tile_size 1347 + 512 * (byte_x / 8) 1348 + 64 * (byte_y / 8) 1349 + 32 * ((byte_y / 4) % 2) 1350 + 16 * ((byte_x / 4) % 2) 1351 + 8 * ((byte_y / 2) % 2) 1352 + 4 * ((byte_x / 2) % 2) 1353 + 2 * (byte_y % 2) 1354 + 1 * (byte_x % 2); 1355 1356 if (swizzled) { 1357 /* adjust for bit6 swizzling */ 1358 if (((byte_x / 8) % 2) == 1) { 1359 if (((byte_y / 8) % 2) == 0) { 1360 u += 64; 1361 } else { 1362 u -= 64; 1363 } 1364 } 1365 } 1366 1367 return u; 1368} 1369 1370static void 1371crocus_unmap_s8(struct crocus_transfer *map) 1372{ 1373 struct pipe_transfer *xfer = &map->base.b; 1374 const struct pipe_box *box = &xfer->box; 1375 struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 1376 struct isl_surf *surf = &res->surf; 1377 1378 if (xfer->usage & PIPE_MAP_WRITE) { 1379 uint8_t *untiled_s8_map = map->ptr; 1380 uint8_t *tiled_s8_map = 1381 crocus_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 1382 1383 for (int s = 0; s < box->depth; s++) { 1384 unsigned x0_el, y0_el; 1385 get_image_offset_el(surf, xfer->level, box->z + s, &x0_el, &y0_el); 1386 1387 for (uint32_t y = 0; y < box->height; y++) { 1388 for (uint32_t x = 0; x < box->width; x++) { 1389 ptrdiff_t offset = s8_offset(surf->row_pitch_B, 1390 x0_el + box->x + x, 1391 y0_el + box->y + y, 1392 map->has_swizzling); 1393 tiled_s8_map[offset] = 1394 untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x]; 1395 } 1396 } 1397 } 1398 } 1399 1400 free(map->buffer); 1401} 1402 1403static void 1404crocus_map_s8(struct crocus_transfer *map) 1405{ 1406 struct pipe_transfer *xfer = &map->base.b; 1407 const struct pipe_box *box = &xfer->box; 1408 struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 1409 struct isl_surf *surf = &res->surf; 1410 1411 xfer->stride = surf->row_pitch_B; 1412 xfer->layer_stride = xfer->stride * box->height; 1413 1414 /* The tiling and detiling functions require that the linear buffer has 1415 * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we 1416 * over-allocate the linear buffer to get the proper alignment. 1417 */ 1418 map->buffer = map->ptr = malloc(xfer->layer_stride * box->depth); 1419 assert(map->buffer); 1420 1421 /* One of either READ_BIT or WRITE_BIT or both is set. READ_BIT implies no 1422 * INVALIDATE_RANGE_BIT. WRITE_BIT needs the original values read in unless 1423 * invalidate is set, since we'll be writing the whole rectangle from our 1424 * temporary buffer back out. 1425 */ 1426 if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 1427 uint8_t *untiled_s8_map = map->ptr; 1428 uint8_t *tiled_s8_map = 1429 crocus_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 1430 1431 for (int s = 0; s < box->depth; s++) { 1432 unsigned x0_el, y0_el; 1433 get_image_offset_el(surf, xfer->level, box->z + s, &x0_el, &y0_el); 1434 1435 for (uint32_t y = 0; y < box->height; y++) { 1436 for (uint32_t x = 0; x < box->width; x++) { 1437 ptrdiff_t offset = s8_offset(surf->row_pitch_B, 1438 x0_el + box->x + x, 1439 y0_el + box->y + y, 1440 map->has_swizzling); 1441 untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x] = 1442 tiled_s8_map[offset]; 1443 } 1444 } 1445 } 1446 } 1447 1448 map->unmap = crocus_unmap_s8; 1449} 1450 1451/* Compute extent parameters for use with tiled_memcpy functions. 1452 * xs are in units of bytes and ys are in units of strides. 1453 */ 1454static inline void 1455tile_extents(const struct isl_surf *surf, 1456 const struct pipe_box *box, 1457 unsigned level, int z, 1458 unsigned *x1_B, unsigned *x2_B, 1459 unsigned *y1_el, unsigned *y2_el) 1460{ 1461 const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format); 1462 const unsigned cpp = fmtl->bpb / 8; 1463 1464 assert(box->x % fmtl->bw == 0); 1465 assert(box->y % fmtl->bh == 0); 1466 1467 unsigned x0_el, y0_el; 1468 get_image_offset_el(surf, level, box->z + z, &x0_el, &y0_el); 1469 1470 *x1_B = (box->x / fmtl->bw + x0_el) * cpp; 1471 *y1_el = box->y / fmtl->bh + y0_el; 1472 *x2_B = (DIV_ROUND_UP(box->x + box->width, fmtl->bw) + x0_el) * cpp; 1473 *y2_el = DIV_ROUND_UP(box->y + box->height, fmtl->bh) + y0_el; 1474} 1475 1476static void 1477crocus_unmap_tiled_memcpy(struct crocus_transfer *map) 1478{ 1479 struct pipe_transfer *xfer = &map->base.b; 1480 const struct pipe_box *box = &xfer->box; 1481 struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 1482 struct isl_surf *surf = &res->surf; 1483 1484 if (xfer->usage & PIPE_MAP_WRITE) { 1485 char *dst = 1486 crocus_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 1487 1488 for (int s = 0; s < box->depth; s++) { 1489 unsigned x1, x2, y1, y2; 1490 tile_extents(surf, box, xfer->level, s, &x1, &x2, &y1, &y2); 1491 1492 void *ptr = map->ptr + s * xfer->layer_stride; 1493 1494 isl_memcpy_linear_to_tiled(x1, x2, y1, y2, dst, ptr, 1495 surf->row_pitch_B, xfer->stride, 1496 map->has_swizzling, 1497 surf->tiling, ISL_MEMCPY); 1498 } 1499 } 1500 os_free_aligned(map->buffer); 1501 map->buffer = map->ptr = NULL; 1502} 1503 1504static void 1505crocus_map_tiled_memcpy(struct crocus_transfer *map) 1506{ 1507 struct pipe_transfer *xfer = &map->base.b; 1508 const struct pipe_box *box = &xfer->box; 1509 struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 1510 struct isl_surf *surf = &res->surf; 1511 1512 xfer->stride = ALIGN(surf->row_pitch_B, 16); 1513 xfer->layer_stride = xfer->stride * box->height; 1514 1515 unsigned x1, x2, y1, y2; 1516 tile_extents(surf, box, xfer->level, 0, &x1, &x2, &y1, &y2); 1517 1518 /* The tiling and detiling functions require that the linear buffer has 1519 * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we 1520 * over-allocate the linear buffer to get the proper alignment. 1521 */ 1522 map->buffer = 1523 os_malloc_aligned(xfer->layer_stride * box->depth, 16); 1524 assert(map->buffer); 1525 map->ptr = (char *)map->buffer + (x1 & 0xf); 1526 1527 if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 1528 char *src = 1529 crocus_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 1530 1531 for (int s = 0; s < box->depth; s++) { 1532 unsigned x1, x2, y1, y2; 1533 tile_extents(surf, box, xfer->level, s, &x1, &x2, &y1, &y2); 1534 1535 /* Use 's' rather than 'box->z' to rebase the first slice to 0. */ 1536 void *ptr = map->ptr + s * xfer->layer_stride; 1537 1538 isl_memcpy_tiled_to_linear(x1, x2, y1, y2, ptr, src, xfer->stride, 1539 surf->row_pitch_B, 1540 map->has_swizzling, 1541 surf->tiling, 1542#if defined(USE_SSE41) 1543 util_get_cpu_caps()->has_sse4_1 ? ISL_MEMCPY_STREAMING_LOAD : 1544#endif 1545 ISL_MEMCPY); 1546 } 1547 } 1548 1549 map->unmap = crocus_unmap_tiled_memcpy; 1550} 1551 1552static void 1553crocus_map_direct(struct crocus_transfer *map) 1554{ 1555 struct pipe_transfer *xfer = &map->base.b; 1556 struct pipe_box *box = &xfer->box; 1557 struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 1558 1559 void *ptr = crocus_bo_map(map->dbg, res->bo, xfer->usage & MAP_FLAGS); 1560 1561 if (res->base.b.target == PIPE_BUFFER) { 1562 xfer->stride = 0; 1563 xfer->layer_stride = 0; 1564 1565 map->ptr = ptr + box->x; 1566 } else { 1567 struct isl_surf *surf = &res->surf; 1568 const struct isl_format_layout *fmtl = 1569 isl_format_get_layout(surf->format); 1570 const unsigned cpp = fmtl->bpb / 8; 1571 unsigned x0_el, y0_el; 1572 1573 assert(box->x % fmtl->bw == 0); 1574 assert(box->y % fmtl->bh == 0); 1575 get_image_offset_el(surf, xfer->level, box->z, &x0_el, &y0_el); 1576 1577 x0_el += box->x / fmtl->bw; 1578 y0_el += box->y / fmtl->bh; 1579 1580 xfer->stride = isl_surf_get_row_pitch_B(surf); 1581 xfer->layer_stride = isl_surf_get_array_pitch(surf); 1582 1583 map->ptr = ptr + y0_el * xfer->stride + x0_el * cpp; 1584 } 1585} 1586 1587static bool 1588can_promote_to_async(const struct crocus_resource *res, 1589 const struct pipe_box *box, 1590 unsigned usage) 1591{ 1592 /* If we're writing to a section of the buffer that hasn't even been 1593 * initialized with useful data, then we can safely promote this write 1594 * to be unsynchronized. This helps the common pattern of appending data. 1595 */ 1596 return res->base.b.target == PIPE_BUFFER && (usage & PIPE_MAP_WRITE) && 1597 !(usage & TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED) && 1598 !util_ranges_intersect(&res->valid_buffer_range, box->x, 1599 box->x + box->width); 1600} 1601 1602static void * 1603crocus_transfer_map(struct pipe_context *ctx, 1604 struct pipe_resource *resource, 1605 unsigned level, 1606 unsigned usage, 1607 const struct pipe_box *box, 1608 struct pipe_transfer **ptransfer) 1609{ 1610 struct crocus_context *ice = (struct crocus_context *)ctx; 1611 struct crocus_resource *res = (struct crocus_resource *)resource; 1612 struct isl_surf *surf = &res->surf; 1613 struct crocus_screen *screen = (struct crocus_screen *)ctx->screen; 1614 1615 if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) { 1616 /* Replace the backing storage with a fresh buffer for non-async maps */ 1617 if (!(usage & (PIPE_MAP_UNSYNCHRONIZED | 1618 TC_TRANSFER_MAP_NO_INVALIDATE))) 1619 crocus_invalidate_resource(ctx, resource); 1620 1621 /* If we can discard the whole resource, we can discard the range. */ 1622 usage |= PIPE_MAP_DISCARD_RANGE; 1623 } 1624 1625 if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && 1626 can_promote_to_async(res, box, usage)) { 1627 usage |= PIPE_MAP_UNSYNCHRONIZED; 1628 } 1629 1630 bool map_would_stall = false; 1631 1632 if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { 1633 map_would_stall = resource_is_busy(ice, res) || 1634 crocus_has_invalid_primary(res, level, 1, box->z, box->depth); 1635 1636 1637 if (map_would_stall && (usage & PIPE_MAP_DONTBLOCK) && 1638 (usage & PIPE_MAP_DIRECTLY)) 1639 return NULL; 1640 } 1641 1642 if (surf->tiling != ISL_TILING_LINEAR && 1643 (usage & PIPE_MAP_DIRECTLY)) 1644 return NULL; 1645 1646 struct crocus_transfer *map; 1647 if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) 1648 map = slab_zalloc(&ice->transfer_pool_unsync); 1649 else 1650 map = slab_zalloc(&ice->transfer_pool); 1651 1652 struct pipe_transfer *xfer = &map->base.b; 1653 1654 if (!map) 1655 return NULL; 1656 1657 map->dbg = &ice->dbg; 1658 1659 map->has_swizzling = screen->devinfo.has_bit6_swizzle; 1660 pipe_resource_reference(&xfer->resource, resource); 1661 xfer->level = level; 1662 xfer->usage = usage; 1663 xfer->box = *box; 1664 *ptransfer = xfer; 1665 1666 map->dest_had_defined_contents = 1667 util_ranges_intersect(&res->valid_buffer_range, box->x, 1668 box->x + box->width); 1669 1670 if (usage & PIPE_MAP_WRITE) 1671 util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width); 1672 1673 /* Avoid using GPU copies for persistent/coherent buffers, as the idea 1674 * there is to access them simultaneously on the CPU & GPU. This also 1675 * avoids trying to use GPU copies for our u_upload_mgr buffers which 1676 * contain state we're constructing for a GPU draw call, which would 1677 * kill us with infinite stack recursion. 1678 */ 1679 bool no_gpu = usage & (PIPE_MAP_PERSISTENT | 1680 PIPE_MAP_COHERENT | 1681 PIPE_MAP_DIRECTLY); 1682 1683 /* GPU copies are not useful for buffer reads. Instead of stalling to 1684 * read from the original buffer, we'd simply copy it to a temporary... 1685 * then stall (a bit longer) to read from that buffer. 1686 * 1687 * Images are less clear-cut. Color resolves are destructive, removing 1688 * the underlying compression, so we'd rather blit the data to a linear 1689 * temporary and map that, to avoid the resolve. (It might be better to 1690 * a tiled temporary and use the tiled_memcpy paths...) 1691 */ 1692 if (!(usage & PIPE_MAP_DISCARD_RANGE) && 1693 !crocus_has_invalid_primary(res, level, 1, box->z, box->depth)) 1694 no_gpu = true; 1695 1696 const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format); 1697 if (fmtl->txc == ISL_TXC_ASTC) 1698 no_gpu = true; 1699 1700 if (map_would_stall && !no_gpu) { 1701 /* If we need a synchronous mapping and the resource is busy, or needs 1702 * resolving, we copy to/from a linear temporary buffer using the GPU. 1703 */ 1704 map->batch = &ice->batches[CROCUS_BATCH_RENDER]; 1705 map->blorp = &ice->blorp; 1706 crocus_map_copy_region(map); 1707 } else { 1708 /* Otherwise we're free to map on the CPU. */ 1709 1710 if (resource->target != PIPE_BUFFER) { 1711 crocus_resource_access_raw(ice, res, 1712 level, box->z, box->depth, 1713 usage & PIPE_MAP_WRITE); 1714 } 1715 1716 if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { 1717 for (int i = 0; i < ice->batch_count; i++) { 1718 if (crocus_batch_references(&ice->batches[i], res->bo)) 1719 crocus_batch_flush(&ice->batches[i]); 1720 } 1721 } 1722 1723 if (surf->tiling == ISL_TILING_W) { 1724 /* TODO: Teach crocus_map_tiled_memcpy about W-tiling... */ 1725 crocus_map_s8(map); 1726 } else if (surf->tiling != ISL_TILING_LINEAR && screen->devinfo.ver > 4) { 1727 crocus_map_tiled_memcpy(map); 1728 } else { 1729 crocus_map_direct(map); 1730 } 1731 } 1732 1733 return map->ptr; 1734} 1735 1736static void 1737crocus_transfer_flush_region(struct pipe_context *ctx, 1738 struct pipe_transfer *xfer, 1739 const struct pipe_box *box) 1740{ 1741 struct crocus_context *ice = (struct crocus_context *)ctx; 1742 struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 1743 struct crocus_transfer *map = (void *) xfer; 1744 1745 if (map->staging) 1746 crocus_flush_staging_region(xfer, box); 1747 1748 uint32_t history_flush = 0; 1749 1750 if (res->base.b.target == PIPE_BUFFER) { 1751 if (map->staging) 1752 history_flush |= PIPE_CONTROL_RENDER_TARGET_FLUSH; 1753 1754 if (map->dest_had_defined_contents) 1755 history_flush |= crocus_flush_bits_for_history(res); 1756 1757 util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width); 1758 } 1759 1760 if (history_flush & ~PIPE_CONTROL_CS_STALL) { 1761 for (int i = 0; i < ice->batch_count; i++) { 1762 struct crocus_batch *batch = &ice->batches[i]; 1763 1764 if (!batch->command.bo) 1765 continue; 1766 if (batch->contains_draw || batch->cache.render->entries) { 1767 crocus_batch_maybe_flush(batch, 24); 1768 crocus_emit_pipe_control_flush(batch, 1769 "cache history: transfer flush", 1770 history_flush); 1771 } 1772 } 1773 } 1774 1775 /* Make sure we flag constants dirty even if there's no need to emit 1776 * any PIPE_CONTROLs to a batch. 1777 */ 1778 crocus_dirty_for_history(ice, res); 1779} 1780 1781static void 1782crocus_transfer_unmap(struct pipe_context *ctx, struct pipe_transfer *xfer) 1783{ 1784 struct crocus_context *ice = (struct crocus_context *)ctx; 1785 struct crocus_transfer *map = (void *) xfer; 1786 1787 if (!(xfer->usage & (PIPE_MAP_FLUSH_EXPLICIT | 1788 PIPE_MAP_COHERENT))) { 1789 struct pipe_box flush_box = { 1790 .x = 0, .y = 0, .z = 0, 1791 .width = xfer->box.width, 1792 .height = xfer->box.height, 1793 .depth = xfer->box.depth, 1794 }; 1795 crocus_transfer_flush_region(ctx, xfer, &flush_box); 1796 } 1797 1798 if (map->unmap) 1799 map->unmap(map); 1800 1801 pipe_resource_reference(&xfer->resource, NULL); 1802 /* transfer_unmap is always called from the driver thread, so we have to 1803 * use transfer_pool, not transfer_pool_unsync. Freeing an object into a 1804 * different pool is allowed, however. 1805 */ 1806 slab_free(&ice->transfer_pool, map); 1807} 1808 1809/** 1810 * Mark state dirty that needs to be re-emitted when a resource is written. 1811 */ 1812void 1813crocus_dirty_for_history(struct crocus_context *ice, 1814 struct crocus_resource *res) 1815{ 1816 uint64_t stage_dirty = 0ull; 1817 1818 if (res->bind_history & PIPE_BIND_CONSTANT_BUFFER) { 1819 stage_dirty |= ((uint64_t)res->bind_stages) << CROCUS_SHIFT_FOR_STAGE_DIRTY_CONSTANTS; 1820 } 1821 1822 ice->state.stage_dirty |= stage_dirty; 1823} 1824 1825/** 1826 * Produce a set of PIPE_CONTROL bits which ensure data written to a 1827 * resource becomes visible, and any stale read cache data is invalidated. 1828 */ 1829uint32_t 1830crocus_flush_bits_for_history(struct crocus_resource *res) 1831{ 1832 uint32_t flush = PIPE_CONTROL_CS_STALL; 1833 1834 if (res->bind_history & PIPE_BIND_CONSTANT_BUFFER) { 1835 flush |= PIPE_CONTROL_CONST_CACHE_INVALIDATE | 1836 PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE; 1837 } 1838 1839 if (res->bind_history & PIPE_BIND_SAMPLER_VIEW) 1840 flush |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE; 1841 1842 if (res->bind_history & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER)) 1843 flush |= PIPE_CONTROL_VF_CACHE_INVALIDATE; 1844 1845 if (res->bind_history & (PIPE_BIND_SHADER_BUFFER | PIPE_BIND_SHADER_IMAGE)) 1846 flush |= PIPE_CONTROL_DATA_CACHE_FLUSH; 1847 1848 return flush; 1849} 1850 1851void 1852crocus_flush_and_dirty_for_history(struct crocus_context *ice, 1853 struct crocus_batch *batch, 1854 struct crocus_resource *res, 1855 uint32_t extra_flags, 1856 const char *reason) 1857{ 1858 if (res->base.b.target != PIPE_BUFFER) 1859 return; 1860 1861 uint32_t flush = crocus_flush_bits_for_history(res) | extra_flags; 1862 1863 crocus_emit_pipe_control_flush(batch, reason, flush); 1864 1865 crocus_dirty_for_history(ice, res); 1866} 1867 1868bool 1869crocus_resource_set_clear_color(struct crocus_context *ice, 1870 struct crocus_resource *res, 1871 union isl_color_value color) 1872{ 1873 if (memcmp(&res->aux.clear_color, &color, sizeof(color)) != 0) { 1874 res->aux.clear_color = color; 1875 return true; 1876 } 1877 1878 return false; 1879} 1880 1881union isl_color_value 1882crocus_resource_get_clear_color(const struct crocus_resource *res) 1883{ 1884 assert(res->aux.bo); 1885 1886 return res->aux.clear_color; 1887} 1888 1889static enum pipe_format 1890crocus_resource_get_internal_format(struct pipe_resource *p_res) 1891{ 1892 struct crocus_resource *res = (void *) p_res; 1893 return res->internal_format; 1894} 1895 1896static const struct u_transfer_vtbl transfer_vtbl = { 1897 .resource_create = crocus_resource_create, 1898 .resource_destroy = crocus_resource_destroy, 1899 .transfer_map = crocus_transfer_map, 1900 .transfer_unmap = crocus_transfer_unmap, 1901 .transfer_flush_region = crocus_transfer_flush_region, 1902 .get_internal_format = crocus_resource_get_internal_format, 1903 .set_stencil = crocus_resource_set_separate_stencil, 1904 .get_stencil = crocus_resource_get_separate_stencil, 1905}; 1906 1907static bool 1908crocus_is_dmabuf_modifier_supported(struct pipe_screen *pscreen, 1909 uint64_t modifier, enum pipe_format pfmt, 1910 bool *external_only) 1911{ 1912 struct crocus_screen *screen = (void *) pscreen; 1913 const struct intel_device_info *devinfo = &screen->devinfo; 1914 1915 if (modifier_is_supported(devinfo, pfmt, 0, modifier)) { 1916 if (external_only) 1917 *external_only = false; 1918 1919 return true; 1920 } 1921 1922 return false; 1923} 1924 1925static unsigned int 1926crocus_get_dmabuf_modifier_planes(struct pipe_screen *pscreen, uint64_t modifier, 1927 enum pipe_format format) 1928{ 1929 return util_format_get_num_planes(format); 1930} 1931 1932static struct pipe_memory_object * 1933crocus_memobj_create_from_handle(struct pipe_screen *pscreen, 1934 struct winsys_handle *whandle, 1935 bool dedicated) 1936{ 1937 struct crocus_screen *screen = (struct crocus_screen *)pscreen; 1938 struct crocus_memory_object *memobj = CALLOC_STRUCT(crocus_memory_object); 1939 struct crocus_bo *bo; 1940 const struct isl_drm_modifier_info *mod_inf; 1941 1942 if (!memobj) 1943 return NULL; 1944 1945 switch (whandle->type) { 1946 case WINSYS_HANDLE_TYPE_SHARED: 1947 bo = crocus_bo_gem_create_from_name(screen->bufmgr, "winsys image", 1948 whandle->handle); 1949 break; 1950 case WINSYS_HANDLE_TYPE_FD: 1951 mod_inf = isl_drm_modifier_get_info(whandle->modifier); 1952 if (mod_inf) { 1953 bo = crocus_bo_import_dmabuf(screen->bufmgr, whandle->handle, 1954 whandle->modifier); 1955 } else { 1956 /* If we can't get information about the tiling from the 1957 * kernel we ignore it. We are going to set it when we 1958 * create the resource. 1959 */ 1960 bo = crocus_bo_import_dmabuf_no_mods(screen->bufmgr, 1961 whandle->handle); 1962 } 1963 1964 break; 1965 default: 1966 unreachable("invalid winsys handle type"); 1967 } 1968 1969 if (!bo) { 1970 free(memobj); 1971 return NULL; 1972 } 1973 1974 memobj->b.dedicated = dedicated; 1975 memobj->bo = bo; 1976 memobj->format = whandle->format; 1977 memobj->stride = whandle->stride; 1978 1979 return &memobj->b; 1980} 1981 1982static void 1983crocus_memobj_destroy(struct pipe_screen *pscreen, 1984 struct pipe_memory_object *pmemobj) 1985{ 1986 struct crocus_memory_object *memobj = (struct crocus_memory_object *)pmemobj; 1987 1988 crocus_bo_unreference(memobj->bo); 1989 free(memobj); 1990} 1991 1992void 1993crocus_init_screen_resource_functions(struct pipe_screen *pscreen) 1994{ 1995 struct crocus_screen *screen = (void *) pscreen; 1996 pscreen->query_dmabuf_modifiers = crocus_query_dmabuf_modifiers; 1997 pscreen->is_dmabuf_modifier_supported = crocus_is_dmabuf_modifier_supported; 1998 pscreen->get_dmabuf_modifier_planes = crocus_get_dmabuf_modifier_planes; 1999 pscreen->resource_create_with_modifiers = 2000 crocus_resource_create_with_modifiers; 2001 pscreen->resource_create = u_transfer_helper_resource_create; 2002 pscreen->resource_from_user_memory = crocus_resource_from_user_memory; 2003 pscreen->resource_from_handle = crocus_resource_from_handle; 2004 pscreen->resource_from_memobj = crocus_resource_from_memobj; 2005 pscreen->resource_get_handle = crocus_resource_get_handle; 2006 pscreen->resource_get_param = crocus_resource_get_param; 2007 pscreen->resource_destroy = u_transfer_helper_resource_destroy; 2008 pscreen->memobj_create_from_handle = crocus_memobj_create_from_handle; 2009 pscreen->memobj_destroy = crocus_memobj_destroy; 2010 pscreen->transfer_helper = 2011 u_transfer_helper_create(&transfer_vtbl, screen->devinfo.ver >= 6, 2012 screen->devinfo.ver >= 6, false, true, false); 2013} 2014 2015void 2016crocus_init_resource_functions(struct pipe_context *ctx) 2017{ 2018 ctx->flush_resource = crocus_flush_resource; 2019 ctx->invalidate_resource = crocus_invalidate_resource; 2020 ctx->buffer_map = u_transfer_helper_transfer_map; 2021 ctx->texture_map = u_transfer_helper_transfer_map; 2022 ctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 2023 ctx->buffer_unmap = u_transfer_helper_transfer_unmap; 2024 ctx->texture_unmap = u_transfer_helper_transfer_unmap; 2025 ctx->buffer_subdata = u_default_buffer_subdata; 2026 ctx->texture_subdata = u_default_texture_subdata; 2027} 2028