19f464c52Smaya/* 29f464c52Smaya * Copyright © 2017 Intel Corporation 39f464c52Smaya * 49f464c52Smaya * Permission is hereby granted, free of charge, to any person obtaining a 59f464c52Smaya * copy of this software and associated documentation files (the "Software"), 69f464c52Smaya * to deal in the Software without restriction, including without limitation 79f464c52Smaya * the rights to use, copy, modify, merge, publish, distribute, sublicense, 89f464c52Smaya * and/or sell copies of the Software, and to permit persons to whom the 99f464c52Smaya * Software is furnished to do so, subject to the following conditions: 109f464c52Smaya * 119f464c52Smaya * The above copyright notice and this permission notice shall be included 129f464c52Smaya * in all copies or substantial portions of the Software. 139f464c52Smaya * 149f464c52Smaya * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 159f464c52Smaya * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 169f464c52Smaya * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 179f464c52Smaya * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 189f464c52Smaya * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 199f464c52Smaya * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 209f464c52Smaya * DEALINGS IN THE SOFTWARE. 219f464c52Smaya */ 229f464c52Smaya 239f464c52Smaya/** 249f464c52Smaya * @file iris_resource.c 259f464c52Smaya * 269f464c52Smaya * Resources are images, buffers, and other objects used by the GPU. 279f464c52Smaya * 289f464c52Smaya * XXX: explain resources 299f464c52Smaya */ 309f464c52Smaya 319f464c52Smaya#include <stdio.h> 329f464c52Smaya#include <errno.h> 339f464c52Smaya#include "pipe/p_defines.h" 349f464c52Smaya#include "pipe/p_state.h" 359f464c52Smaya#include "pipe/p_context.h" 369f464c52Smaya#include "pipe/p_screen.h" 379f464c52Smaya#include "util/os_memory.h" 389f464c52Smaya#include "util/u_cpu_detect.h" 399f464c52Smaya#include "util/u_inlines.h" 407ec681f3Smrg#include "util/format/u_format.h" 417ec681f3Smrg#include "util/u_memory.h" 429f464c52Smaya#include "util/u_threaded_context.h" 439f464c52Smaya#include "util/u_transfer.h" 449f464c52Smaya#include "util/u_transfer_helper.h" 459f464c52Smaya#include "util/u_upload_mgr.h" 469f464c52Smaya#include "util/ralloc.h" 479f464c52Smaya#include "iris_batch.h" 489f464c52Smaya#include "iris_context.h" 499f464c52Smaya#include "iris_resource.h" 509f464c52Smaya#include "iris_screen.h" 517ec681f3Smrg#include "intel/common/intel_aux_map.h" 527ec681f3Smrg#include "intel/dev/intel_debug.h" 539f464c52Smaya#include "isl/isl.h" 549f464c52Smaya#include "drm-uapi/drm_fourcc.h" 559f464c52Smaya#include "drm-uapi/i915_drm.h" 569f464c52Smaya 579f464c52Smayaenum modifier_priority { 589f464c52Smaya MODIFIER_PRIORITY_INVALID = 0, 599f464c52Smaya MODIFIER_PRIORITY_LINEAR, 609f464c52Smaya MODIFIER_PRIORITY_X, 619f464c52Smaya MODIFIER_PRIORITY_Y, 629f464c52Smaya MODIFIER_PRIORITY_Y_CCS, 637ec681f3Smrg MODIFIER_PRIORITY_Y_GFX12_RC_CCS, 647ec681f3Smrg MODIFIER_PRIORITY_Y_GFX12_RC_CCS_CC, 659f464c52Smaya}; 669f464c52Smaya 679f464c52Smayastatic const uint64_t priority_to_modifier[] = { 689f464c52Smaya [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID, 699f464c52Smaya [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR, 709f464c52Smaya [MODIFIER_PRIORITY_X] = I915_FORMAT_MOD_X_TILED, 719f464c52Smaya [MODIFIER_PRIORITY_Y] = I915_FORMAT_MOD_Y_TILED, 729f464c52Smaya [MODIFIER_PRIORITY_Y_CCS] = I915_FORMAT_MOD_Y_TILED_CCS, 737ec681f3Smrg [MODIFIER_PRIORITY_Y_GFX12_RC_CCS] = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, 747ec681f3Smrg [MODIFIER_PRIORITY_Y_GFX12_RC_CCS_CC] = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, 759f464c52Smaya}; 769f464c52Smaya 779f464c52Smayastatic bool 787ec681f3Smrgmodifier_is_supported(const struct intel_device_info *devinfo, 797ec681f3Smrg enum pipe_format pfmt, unsigned bind, 809f464c52Smaya uint64_t modifier) 819f464c52Smaya{ 827ec681f3Smrg /* Check for basic device support. */ 839f464c52Smaya switch (modifier) { 849f464c52Smaya case DRM_FORMAT_MOD_LINEAR: 857ec681f3Smrg case I915_FORMAT_MOD_X_TILED: 867ec681f3Smrg break; 877ec681f3Smrg case I915_FORMAT_MOD_Y_TILED: 887ec681f3Smrg if (devinfo->ver <= 8 && (bind & PIPE_BIND_SCANOUT)) 897ec681f3Smrg return false; 907ec681f3Smrg if (devinfo->verx10 >= 125) 917ec681f3Smrg return false; 927ec681f3Smrg break; 939f464c52Smaya case I915_FORMAT_MOD_Y_TILED_CCS: 947ec681f3Smrg if (devinfo->ver <= 8 || devinfo->ver >= 12) 957ec681f3Smrg return false; 967ec681f3Smrg break; 977ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 987ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 997ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 1007ec681f3Smrg if (devinfo->verx10 != 120) 1017ec681f3Smrg return false; 1027ec681f3Smrg break; 1039f464c52Smaya case DRM_FORMAT_MOD_INVALID: 1049f464c52Smaya default: 1059f464c52Smaya return false; 1069f464c52Smaya } 1077ec681f3Smrg 1087ec681f3Smrg /* Check remaining requirements. */ 1097ec681f3Smrg switch (modifier) { 1107ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 1117ec681f3Smrg if (pfmt != PIPE_FORMAT_BGRA8888_UNORM && 1127ec681f3Smrg pfmt != PIPE_FORMAT_RGBA8888_UNORM && 1137ec681f3Smrg pfmt != PIPE_FORMAT_BGRX8888_UNORM && 1147ec681f3Smrg pfmt != PIPE_FORMAT_RGBX8888_UNORM && 1157ec681f3Smrg pfmt != PIPE_FORMAT_NV12 && 1167ec681f3Smrg pfmt != PIPE_FORMAT_P010 && 1177ec681f3Smrg pfmt != PIPE_FORMAT_P012 && 1187ec681f3Smrg pfmt != PIPE_FORMAT_P016 && 1197ec681f3Smrg pfmt != PIPE_FORMAT_YUYV && 1207ec681f3Smrg pfmt != PIPE_FORMAT_UYVY) { 1217ec681f3Smrg return false; 1227ec681f3Smrg } 1237ec681f3Smrg break; 1247ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 1257ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 1267ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_CCS: { 1277ec681f3Smrg if (INTEL_DEBUG(DEBUG_NO_RBC)) 1287ec681f3Smrg return false; 1297ec681f3Smrg 1307ec681f3Smrg enum isl_format rt_format = 1317ec681f3Smrg iris_format_for_usage(devinfo, pfmt, 1327ec681f3Smrg ISL_SURF_USAGE_RENDER_TARGET_BIT).fmt; 1337ec681f3Smrg 1347ec681f3Smrg if (rt_format == ISL_FORMAT_UNSUPPORTED || 1357ec681f3Smrg !isl_format_supports_ccs_e(devinfo, rt_format)) 1367ec681f3Smrg return false; 1377ec681f3Smrg break; 1387ec681f3Smrg } 1397ec681f3Smrg default: 1407ec681f3Smrg break; 1417ec681f3Smrg } 1427ec681f3Smrg 1437ec681f3Smrg return true; 1449f464c52Smaya} 1459f464c52Smaya 1469f464c52Smayastatic uint64_t 1477ec681f3Smrgselect_best_modifier(struct intel_device_info *devinfo, 1487ec681f3Smrg const struct pipe_resource *templ, 1499f464c52Smaya const uint64_t *modifiers, 1509f464c52Smaya int count) 1519f464c52Smaya{ 1529f464c52Smaya enum modifier_priority prio = MODIFIER_PRIORITY_INVALID; 1539f464c52Smaya 1549f464c52Smaya for (int i = 0; i < count; i++) { 1557ec681f3Smrg if (!modifier_is_supported(devinfo, templ->format, templ->bind, 1567ec681f3Smrg modifiers[i])) 1579f464c52Smaya continue; 1589f464c52Smaya 1599f464c52Smaya switch (modifiers[i]) { 1607ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 1617ec681f3Smrg prio = MAX2(prio, MODIFIER_PRIORITY_Y_GFX12_RC_CCS_CC); 1627ec681f3Smrg break; 1637ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 1647ec681f3Smrg prio = MAX2(prio, MODIFIER_PRIORITY_Y_GFX12_RC_CCS); 1657ec681f3Smrg break; 1669f464c52Smaya case I915_FORMAT_MOD_Y_TILED_CCS: 1679f464c52Smaya prio = MAX2(prio, MODIFIER_PRIORITY_Y_CCS); 1689f464c52Smaya break; 1699f464c52Smaya case I915_FORMAT_MOD_Y_TILED: 1709f464c52Smaya prio = MAX2(prio, MODIFIER_PRIORITY_Y); 1719f464c52Smaya break; 1729f464c52Smaya case I915_FORMAT_MOD_X_TILED: 1739f464c52Smaya prio = MAX2(prio, MODIFIER_PRIORITY_X); 1749f464c52Smaya break; 1759f464c52Smaya case DRM_FORMAT_MOD_LINEAR: 1769f464c52Smaya prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR); 1779f464c52Smaya break; 1789f464c52Smaya case DRM_FORMAT_MOD_INVALID: 1799f464c52Smaya default: 1809f464c52Smaya break; 1819f464c52Smaya } 1829f464c52Smaya } 1839f464c52Smaya 1849f464c52Smaya return priority_to_modifier[prio]; 1859f464c52Smaya} 1869f464c52Smaya 1877ec681f3Smrgstatic inline bool is_modifier_external_only(enum pipe_format pfmt, 1887ec681f3Smrg uint64_t modifier) 1899f464c52Smaya{ 1907ec681f3Smrg /* Only allow external usage for the following cases: YUV formats 1917ec681f3Smrg * and the media-compression modifier. The render engine lacks 1927ec681f3Smrg * support for rendering to a media-compressed surface if the 1937ec681f3Smrg * compression ratio is large enough. By requiring external usage 1947ec681f3Smrg * of media-compressed surfaces, resolves are avoided. 1957ec681f3Smrg */ 1967ec681f3Smrg return util_format_is_yuv(pfmt) || 1977ec681f3Smrg modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; 1989f464c52Smaya} 1999f464c52Smaya 2009f464c52Smayastatic void 2019f464c52Smayairis_query_dmabuf_modifiers(struct pipe_screen *pscreen, 2029f464c52Smaya enum pipe_format pfmt, 2039f464c52Smaya int max, 2049f464c52Smaya uint64_t *modifiers, 2059f464c52Smaya unsigned int *external_only, 2069f464c52Smaya int *count) 2079f464c52Smaya{ 2089f464c52Smaya struct iris_screen *screen = (void *) pscreen; 2097ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 2109f464c52Smaya 2119f464c52Smaya uint64_t all_modifiers[] = { 2129f464c52Smaya DRM_FORMAT_MOD_LINEAR, 2139f464c52Smaya I915_FORMAT_MOD_X_TILED, 2149f464c52Smaya I915_FORMAT_MOD_Y_TILED, 2157ec681f3Smrg I915_FORMAT_MOD_Y_TILED_CCS, 2167ec681f3Smrg I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, 2177ec681f3Smrg I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS, 2187ec681f3Smrg I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, 2199f464c52Smaya }; 2209f464c52Smaya 2219f464c52Smaya int supported_mods = 0; 2229f464c52Smaya 2239f464c52Smaya for (int i = 0; i < ARRAY_SIZE(all_modifiers); i++) { 2247ec681f3Smrg if (!modifier_is_supported(devinfo, pfmt, 0, all_modifiers[i])) 2259f464c52Smaya continue; 2269f464c52Smaya 2279f464c52Smaya if (supported_mods < max) { 2289f464c52Smaya if (modifiers) 2299f464c52Smaya modifiers[supported_mods] = all_modifiers[i]; 2309f464c52Smaya 2317ec681f3Smrg if (external_only) { 2327ec681f3Smrg external_only[supported_mods] = 2337ec681f3Smrg is_modifier_external_only(pfmt, all_modifiers[i]); 2347ec681f3Smrg } 2359f464c52Smaya } 2369f464c52Smaya 2379f464c52Smaya supported_mods++; 2389f464c52Smaya } 2399f464c52Smaya 2409f464c52Smaya *count = supported_mods; 2419f464c52Smaya} 2429f464c52Smaya 2437ec681f3Smrgstatic bool 2447ec681f3Smrgiris_is_dmabuf_modifier_supported(struct pipe_screen *pscreen, 2457ec681f3Smrg uint64_t modifier, enum pipe_format pfmt, 2467ec681f3Smrg bool *external_only) 2479f464c52Smaya{ 2487ec681f3Smrg struct iris_screen *screen = (void *) pscreen; 2497ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 2509f464c52Smaya 2517ec681f3Smrg if (modifier_is_supported(devinfo, pfmt, 0, modifier)) { 2527ec681f3Smrg if (external_only) 2537ec681f3Smrg *external_only = is_modifier_external_only(pfmt, modifier); 2549f464c52Smaya 2557ec681f3Smrg return true; 2567ec681f3Smrg } 2579f464c52Smaya 2587ec681f3Smrg return false; 2597ec681f3Smrg} 2609f464c52Smaya 2617ec681f3Smrgstatic unsigned int 2627ec681f3Smrgiris_get_dmabuf_modifier_planes(struct pipe_screen *pscreen, uint64_t modifier, 2637ec681f3Smrg enum pipe_format format) 2647ec681f3Smrg{ 2657ec681f3Smrg unsigned int planes = util_format_get_num_planes(format); 2667ec681f3Smrg 2677ec681f3Smrg switch (modifier) { 2687ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 2697ec681f3Smrg return 3; 2707ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 2717ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 2727ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_CCS: 2737ec681f3Smrg return 2 * planes; 2747ec681f3Smrg default: 2757ec681f3Smrg return planes; 2767ec681f3Smrg } 2777ec681f3Smrg} 2787ec681f3Smrg 2797ec681f3Smrgenum isl_format 2807ec681f3Smrgiris_image_view_get_format(struct iris_context *ice, 2817ec681f3Smrg const struct pipe_image_view *img) 2827ec681f3Smrg{ 2837ec681f3Smrg struct iris_screen *screen = (struct iris_screen *)ice->ctx.screen; 2847ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 2857ec681f3Smrg 2867ec681f3Smrg isl_surf_usage_flags_t usage = ISL_SURF_USAGE_STORAGE_BIT; 2877ec681f3Smrg enum isl_format isl_fmt = 2887ec681f3Smrg iris_format_for_usage(devinfo, img->format, usage).fmt; 2897ec681f3Smrg 2907ec681f3Smrg if (img->shader_access & PIPE_IMAGE_ACCESS_READ) { 2917ec681f3Smrg /* On Gfx8, try to use typed surfaces reads (which support a 2927ec681f3Smrg * limited number of formats), and if not possible, fall back 2937ec681f3Smrg * to untyped reads. 2947ec681f3Smrg */ 2957ec681f3Smrg if (devinfo->ver == 8 && 2967ec681f3Smrg !isl_has_matching_typed_storage_image_format(devinfo, isl_fmt)) 2977ec681f3Smrg return ISL_FORMAT_RAW; 2987ec681f3Smrg else 2997ec681f3Smrg return isl_lower_storage_image_format(devinfo, isl_fmt); 3007ec681f3Smrg } 3017ec681f3Smrg 3027ec681f3Smrg return isl_fmt; 3037ec681f3Smrg} 3047ec681f3Smrg 3057ec681f3Smrgstatic struct pipe_memory_object * 3067ec681f3Smrgiris_memobj_create_from_handle(struct pipe_screen *pscreen, 3077ec681f3Smrg struct winsys_handle *whandle, 3087ec681f3Smrg bool dedicated) 3097ec681f3Smrg{ 3107ec681f3Smrg struct iris_screen *screen = (struct iris_screen *)pscreen; 3117ec681f3Smrg struct iris_memory_object *memobj = CALLOC_STRUCT(iris_memory_object); 3127ec681f3Smrg struct iris_bo *bo; 3137ec681f3Smrg 3147ec681f3Smrg if (!memobj) 3157ec681f3Smrg return NULL; 3167ec681f3Smrg 3177ec681f3Smrg switch (whandle->type) { 3187ec681f3Smrg case WINSYS_HANDLE_TYPE_SHARED: 3197ec681f3Smrg bo = iris_bo_gem_create_from_name(screen->bufmgr, "winsys image", 3207ec681f3Smrg whandle->handle); 3217ec681f3Smrg break; 3227ec681f3Smrg case WINSYS_HANDLE_TYPE_FD: 3237ec681f3Smrg bo = iris_bo_import_dmabuf(screen->bufmgr, whandle->handle); 3247ec681f3Smrg break; 3257ec681f3Smrg default: 3267ec681f3Smrg unreachable("invalid winsys handle type"); 3277ec681f3Smrg } 3287ec681f3Smrg 3297ec681f3Smrg if (!bo) { 3307ec681f3Smrg free(memobj); 3317ec681f3Smrg return NULL; 3327ec681f3Smrg } 3337ec681f3Smrg 3347ec681f3Smrg memobj->b.dedicated = dedicated; 3357ec681f3Smrg memobj->bo = bo; 3367ec681f3Smrg memobj->format = whandle->format; 3377ec681f3Smrg memobj->stride = whandle->stride; 3387ec681f3Smrg 3397ec681f3Smrg return &memobj->b; 3407ec681f3Smrg} 3417ec681f3Smrg 3427ec681f3Smrgstatic void 3437ec681f3Smrgiris_memobj_destroy(struct pipe_screen *pscreen, 3447ec681f3Smrg struct pipe_memory_object *pmemobj) 3457ec681f3Smrg{ 3467ec681f3Smrg struct iris_memory_object *memobj = (struct iris_memory_object *)pmemobj; 3479f464c52Smaya 3487ec681f3Smrg iris_bo_unreference(memobj->bo); 3497ec681f3Smrg free(memobj); 3509f464c52Smaya} 3519f464c52Smaya 3529f464c52Smayastruct pipe_resource * 3539f464c52Smayairis_resource_get_separate_stencil(struct pipe_resource *p_res) 3549f464c52Smaya{ 3559f464c52Smaya /* For packed depth-stencil, we treat depth as the primary resource 3569f464c52Smaya * and store S8 as the "second plane" resource. 3579f464c52Smaya */ 3587ec681f3Smrg if (p_res->next && p_res->next->format == PIPE_FORMAT_S8_UINT) 3597ec681f3Smrg return p_res->next; 3607ec681f3Smrg 3617ec681f3Smrg return NULL; 3627ec681f3Smrg 3639f464c52Smaya} 3649f464c52Smaya 3659f464c52Smayastatic void 3669f464c52Smayairis_resource_set_separate_stencil(struct pipe_resource *p_res, 3679f464c52Smaya struct pipe_resource *stencil) 3689f464c52Smaya{ 3699f464c52Smaya assert(util_format_has_depth(util_format_description(p_res->format))); 3709f464c52Smaya pipe_resource_reference(&p_res->next, stencil); 3719f464c52Smaya} 3729f464c52Smaya 3739f464c52Smayavoid 3749f464c52Smayairis_get_depth_stencil_resources(struct pipe_resource *res, 3759f464c52Smaya struct iris_resource **out_z, 3769f464c52Smaya struct iris_resource **out_s) 3779f464c52Smaya{ 3789f464c52Smaya if (!res) { 3799f464c52Smaya *out_z = NULL; 3809f464c52Smaya *out_s = NULL; 3819f464c52Smaya return; 3829f464c52Smaya } 3839f464c52Smaya 3849f464c52Smaya if (res->format != PIPE_FORMAT_S8_UINT) { 3859f464c52Smaya *out_z = (void *) res; 3869f464c52Smaya *out_s = (void *) iris_resource_get_separate_stencil(res); 3879f464c52Smaya } else { 3889f464c52Smaya *out_z = NULL; 3899f464c52Smaya *out_s = (void *) res; 3909f464c52Smaya } 3919f464c52Smaya} 3929f464c52Smaya 3939f464c52Smayavoid 3949f464c52Smayairis_resource_disable_aux(struct iris_resource *res) 3959f464c52Smaya{ 3969f464c52Smaya iris_bo_unreference(res->aux.bo); 3979f464c52Smaya iris_bo_unreference(res->aux.clear_color_bo); 3989f464c52Smaya free(res->aux.state); 3999f464c52Smaya 4009f464c52Smaya res->aux.usage = ISL_AUX_USAGE_NONE; 4019f464c52Smaya res->aux.possible_usages = 1 << ISL_AUX_USAGE_NONE; 4029f464c52Smaya res->aux.sampler_usages = 1 << ISL_AUX_USAGE_NONE; 4039f464c52Smaya res->aux.surf.size_B = 0; 4049f464c52Smaya res->aux.bo = NULL; 4057ec681f3Smrg res->aux.extra_aux.surf.size_B = 0; 4069f464c52Smaya res->aux.clear_color_bo = NULL; 4079f464c52Smaya res->aux.state = NULL; 4089f464c52Smaya} 4099f464c52Smaya 4107ec681f3Smrgstatic uint32_t 4117ec681f3Smrgiris_resource_alloc_flags(const struct iris_screen *screen, 4127ec681f3Smrg const struct pipe_resource *templ) 4137ec681f3Smrg{ 4147ec681f3Smrg if (templ->flags & IRIS_RESOURCE_FLAG_DEVICE_MEM) 4157ec681f3Smrg return 0; 4167ec681f3Smrg 4177ec681f3Smrg uint32_t flags = 0; 4187ec681f3Smrg 4197ec681f3Smrg switch (templ->usage) { 4207ec681f3Smrg case PIPE_USAGE_STAGING: 4217ec681f3Smrg flags |= BO_ALLOC_SMEM | BO_ALLOC_COHERENT; 4227ec681f3Smrg break; 4237ec681f3Smrg case PIPE_USAGE_STREAM: 4247ec681f3Smrg flags |= BO_ALLOC_SMEM; 4257ec681f3Smrg break; 4267ec681f3Smrg case PIPE_USAGE_DYNAMIC: 4277ec681f3Smrg case PIPE_USAGE_DEFAULT: 4287ec681f3Smrg case PIPE_USAGE_IMMUTABLE: 4297ec681f3Smrg /* Use LMEM for these if possible */ 4307ec681f3Smrg break; 4317ec681f3Smrg } 4327ec681f3Smrg 4337ec681f3Smrg /* Scanout and shared buffers need to be WC (shared because they might be 4347ec681f3Smrg * used for scanout) 4357ec681f3Smrg */ 4367ec681f3Smrg if (templ->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_SHARED)) 4377ec681f3Smrg flags |= BO_ALLOC_SCANOUT; 4387ec681f3Smrg 4397ec681f3Smrg if (templ->flags & (PIPE_RESOURCE_FLAG_MAP_COHERENT | 4407ec681f3Smrg PIPE_RESOURCE_FLAG_MAP_PERSISTENT)) 4417ec681f3Smrg flags |= BO_ALLOC_SMEM; 4427ec681f3Smrg 4437ec681f3Smrg if ((templ->bind & PIPE_BIND_SHARED) || 4447ec681f3Smrg util_format_get_num_planes(templ->format) > 1) 4457ec681f3Smrg flags |= BO_ALLOC_NO_SUBALLOC; 4467ec681f3Smrg 4477ec681f3Smrg return flags; 4487ec681f3Smrg} 4497ec681f3Smrg 4509f464c52Smayastatic void 4519f464c52Smayairis_resource_destroy(struct pipe_screen *screen, 4527ec681f3Smrg struct pipe_resource *p_res) 4539f464c52Smaya{ 4547ec681f3Smrg struct iris_resource *res = (struct iris_resource *) p_res; 4559f464c52Smaya 4567ec681f3Smrg if (p_res->target == PIPE_BUFFER) 4579f464c52Smaya util_range_destroy(&res->valid_buffer_range); 4589f464c52Smaya 4599f464c52Smaya iris_resource_disable_aux(res); 4609f464c52Smaya 4617ec681f3Smrg threaded_resource_deinit(p_res); 4629f464c52Smaya iris_bo_unreference(res->bo); 4637ec681f3Smrg iris_pscreen_unref(res->orig_screen); 4647ec681f3Smrg 4659f464c52Smaya free(res); 4669f464c52Smaya} 4679f464c52Smaya 4689f464c52Smayastatic struct iris_resource * 4699f464c52Smayairis_alloc_resource(struct pipe_screen *pscreen, 4709f464c52Smaya const struct pipe_resource *templ) 4719f464c52Smaya{ 4729f464c52Smaya struct iris_resource *res = calloc(1, sizeof(struct iris_resource)); 4739f464c52Smaya if (!res) 4749f464c52Smaya return NULL; 4759f464c52Smaya 4767ec681f3Smrg res->base.b = *templ; 4777ec681f3Smrg res->base.b.screen = pscreen; 4787ec681f3Smrg res->orig_screen = iris_pscreen_ref(pscreen); 4797ec681f3Smrg pipe_reference_init(&res->base.b.reference, 1); 4807ec681f3Smrg threaded_resource_init(&res->base.b); 4819f464c52Smaya 4829f464c52Smaya res->aux.possible_usages = 1 << ISL_AUX_USAGE_NONE; 4839f464c52Smaya res->aux.sampler_usages = 1 << ISL_AUX_USAGE_NONE; 4849f464c52Smaya 4859f464c52Smaya if (templ->target == PIPE_BUFFER) 4869f464c52Smaya util_range_init(&res->valid_buffer_range); 4879f464c52Smaya 4889f464c52Smaya return res; 4899f464c52Smaya} 4909f464c52Smaya 4919f464c52Smayaunsigned 4929f464c52Smayairis_get_num_logical_layers(const struct iris_resource *res, unsigned level) 4939f464c52Smaya{ 4949f464c52Smaya if (res->surf.dim == ISL_SURF_DIM_3D) 4959f464c52Smaya return minify(res->surf.logical_level0_px.depth, level); 4969f464c52Smaya else 4979f464c52Smaya return res->surf.logical_level0_px.array_len; 4989f464c52Smaya} 4999f464c52Smaya 5009f464c52Smayastatic enum isl_aux_state ** 5019f464c52Smayacreate_aux_state_map(struct iris_resource *res, enum isl_aux_state initial) 5029f464c52Smaya{ 5037ec681f3Smrg assert(res->aux.state == NULL); 5047ec681f3Smrg 5059f464c52Smaya uint32_t total_slices = 0; 5069f464c52Smaya for (uint32_t level = 0; level < res->surf.levels; level++) 5079f464c52Smaya total_slices += iris_get_num_logical_layers(res, level); 5089f464c52Smaya 5099f464c52Smaya const size_t per_level_array_size = 5109f464c52Smaya res->surf.levels * sizeof(enum isl_aux_state *); 5119f464c52Smaya 5129f464c52Smaya /* We're going to allocate a single chunk of data for both the per-level 5139f464c52Smaya * reference array and the arrays of aux_state. This makes cleanup 5149f464c52Smaya * significantly easier. 5159f464c52Smaya */ 5169f464c52Smaya const size_t total_size = 5179f464c52Smaya per_level_array_size + total_slices * sizeof(enum isl_aux_state); 5189f464c52Smaya 5199f464c52Smaya void *data = malloc(total_size); 5209f464c52Smaya if (!data) 5219f464c52Smaya return NULL; 5229f464c52Smaya 5239f464c52Smaya enum isl_aux_state **per_level_arr = data; 5249f464c52Smaya enum isl_aux_state *s = data + per_level_array_size; 5259f464c52Smaya for (uint32_t level = 0; level < res->surf.levels; level++) { 5269f464c52Smaya per_level_arr[level] = s; 5279f464c52Smaya const unsigned level_layers = iris_get_num_logical_layers(res, level); 5289f464c52Smaya for (uint32_t a = 0; a < level_layers; a++) 5299f464c52Smaya *(s++) = initial; 5309f464c52Smaya } 5319f464c52Smaya assert((void *)s == data + total_size); 5329f464c52Smaya 5339f464c52Smaya return per_level_arr; 5349f464c52Smaya} 5359f464c52Smaya 5367ec681f3Smrgstatic unsigned 5377ec681f3Smrgiris_get_aux_clear_color_state_size(struct iris_screen *screen) 5387ec681f3Smrg{ 5397ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 5407ec681f3Smrg return devinfo->ver >= 10 ? screen->isl_dev.ss.clear_color_state_size : 0; 5417ec681f3Smrg} 5427ec681f3Smrg 5437ec681f3Smrgstatic void 5447ec681f3Smrgmap_aux_addresses(struct iris_screen *screen, struct iris_resource *res, 5457ec681f3Smrg enum isl_format format, unsigned plane) 5467ec681f3Smrg{ 5477ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 5487ec681f3Smrg if (devinfo->ver >= 12 && isl_aux_usage_has_ccs(res->aux.usage)) { 5497ec681f3Smrg void *aux_map_ctx = iris_bufmgr_get_aux_map_context(screen->bufmgr); 5507ec681f3Smrg assert(aux_map_ctx); 5517ec681f3Smrg const unsigned aux_offset = res->aux.extra_aux.surf.size_B > 0 ? 5527ec681f3Smrg res->aux.extra_aux.offset : res->aux.offset; 5537ec681f3Smrg const uint64_t format_bits = 5547ec681f3Smrg intel_aux_map_format_bits(res->surf.tiling, format, plane); 5557ec681f3Smrg intel_aux_map_add_mapping(aux_map_ctx, res->bo->address + res->offset, 5567ec681f3Smrg res->aux.bo->address + aux_offset, 5577ec681f3Smrg res->surf.size_B, format_bits); 5587ec681f3Smrg res->bo->aux_map_address = res->aux.bo->address; 5597ec681f3Smrg } 5607ec681f3Smrg} 5617ec681f3Smrg 5627ec681f3Smrgstatic bool 5637ec681f3Smrgwant_ccs_e_for_format(const struct intel_device_info *devinfo, 5647ec681f3Smrg enum isl_format format) 5657ec681f3Smrg{ 5667ec681f3Smrg if (!isl_format_supports_ccs_e(devinfo, format)) 5677ec681f3Smrg return false; 5687ec681f3Smrg 5697ec681f3Smrg const struct isl_format_layout *fmtl = isl_format_get_layout(format); 5707ec681f3Smrg 5717ec681f3Smrg /* CCS_E seems to significantly hurt performance with 32-bit floating 5727ec681f3Smrg * point formats. For example, Paraview's "Wavelet Volume" case uses 5737ec681f3Smrg * both R32_FLOAT and R32G32B32A32_FLOAT, and enabling CCS_E for those 5747ec681f3Smrg * formats causes a 62% FPS drop. 5757ec681f3Smrg * 5767ec681f3Smrg * However, many benchmarks seem to use 16-bit float with no issues. 5777ec681f3Smrg */ 5787ec681f3Smrg if (fmtl->channels.r.bits == 32 && fmtl->channels.r.type == ISL_SFLOAT) 5797ec681f3Smrg return false; 5807ec681f3Smrg 5817ec681f3Smrg return true; 5827ec681f3Smrg} 5837ec681f3Smrg 5847ec681f3Smrgstatic enum isl_surf_dim 5857ec681f3Smrgtarget_to_isl_surf_dim(enum pipe_texture_target target) 5867ec681f3Smrg{ 5877ec681f3Smrg switch (target) { 5887ec681f3Smrg case PIPE_BUFFER: 5897ec681f3Smrg case PIPE_TEXTURE_1D: 5907ec681f3Smrg case PIPE_TEXTURE_1D_ARRAY: 5917ec681f3Smrg return ISL_SURF_DIM_1D; 5927ec681f3Smrg case PIPE_TEXTURE_2D: 5937ec681f3Smrg case PIPE_TEXTURE_CUBE: 5947ec681f3Smrg case PIPE_TEXTURE_RECT: 5957ec681f3Smrg case PIPE_TEXTURE_2D_ARRAY: 5967ec681f3Smrg case PIPE_TEXTURE_CUBE_ARRAY: 5977ec681f3Smrg return ISL_SURF_DIM_2D; 5987ec681f3Smrg case PIPE_TEXTURE_3D: 5997ec681f3Smrg return ISL_SURF_DIM_3D; 6007ec681f3Smrg case PIPE_MAX_TEXTURE_TYPES: 6017ec681f3Smrg break; 6027ec681f3Smrg } 6037ec681f3Smrg unreachable("invalid texture type"); 6047ec681f3Smrg} 6057ec681f3Smrg 6067ec681f3Smrgstatic bool 6077ec681f3Smrgiris_resource_configure_main(const struct iris_screen *screen, 6087ec681f3Smrg struct iris_resource *res, 6097ec681f3Smrg const struct pipe_resource *templ, 6107ec681f3Smrg uint64_t modifier, uint32_t row_pitch_B) 6117ec681f3Smrg{ 6127ec681f3Smrg res->mod_info = isl_drm_modifier_get_info(modifier); 6137ec681f3Smrg 6147ec681f3Smrg if (modifier != DRM_FORMAT_MOD_INVALID && res->mod_info == NULL) 6157ec681f3Smrg return false; 6167ec681f3Smrg 6177ec681f3Smrg isl_tiling_flags_t tiling_flags = 0; 6187ec681f3Smrg 6197ec681f3Smrg if (res->mod_info != NULL) { 6207ec681f3Smrg tiling_flags = 1 << res->mod_info->tiling; 6217ec681f3Smrg } else if (templ->usage == PIPE_USAGE_STAGING || 6227ec681f3Smrg templ->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR)) { 6237ec681f3Smrg tiling_flags = ISL_TILING_LINEAR_BIT; 6247ec681f3Smrg } else if (templ->bind & PIPE_BIND_SCANOUT) { 6257ec681f3Smrg tiling_flags = screen->devinfo.has_tiling_uapi ? 6267ec681f3Smrg ISL_TILING_X_BIT : ISL_TILING_LINEAR_BIT; 6277ec681f3Smrg } else { 6287ec681f3Smrg tiling_flags = ISL_TILING_ANY_MASK; 6297ec681f3Smrg } 6307ec681f3Smrg 6317ec681f3Smrg isl_surf_usage_flags_t usage = 0; 6327ec681f3Smrg 6337ec681f3Smrg if (templ->usage == PIPE_USAGE_STAGING) 6347ec681f3Smrg usage |= ISL_SURF_USAGE_STAGING_BIT; 6357ec681f3Smrg 6367ec681f3Smrg if (templ->bind & PIPE_BIND_RENDER_TARGET) 6377ec681f3Smrg usage |= ISL_SURF_USAGE_RENDER_TARGET_BIT; 6387ec681f3Smrg 6397ec681f3Smrg if (templ->bind & PIPE_BIND_SAMPLER_VIEW) 6407ec681f3Smrg usage |= ISL_SURF_USAGE_TEXTURE_BIT; 6417ec681f3Smrg 6427ec681f3Smrg if (templ->bind & PIPE_BIND_SHADER_IMAGE) 6437ec681f3Smrg usage |= ISL_SURF_USAGE_STORAGE_BIT; 6447ec681f3Smrg 6457ec681f3Smrg if (templ->bind & PIPE_BIND_SCANOUT) 6467ec681f3Smrg usage |= ISL_SURF_USAGE_DISPLAY_BIT; 6477ec681f3Smrg 6487ec681f3Smrg if (templ->target == PIPE_TEXTURE_CUBE || 6497ec681f3Smrg templ->target == PIPE_TEXTURE_CUBE_ARRAY) { 6507ec681f3Smrg usage |= ISL_SURF_USAGE_CUBE_BIT; 6517ec681f3Smrg } 6527ec681f3Smrg 6537ec681f3Smrg if (templ->usage != PIPE_USAGE_STAGING && 6547ec681f3Smrg util_format_is_depth_or_stencil(templ->format)) { 6557ec681f3Smrg 6567ec681f3Smrg /* Should be handled by u_transfer_helper */ 6577ec681f3Smrg assert(!util_format_is_depth_and_stencil(templ->format)); 6587ec681f3Smrg 6597ec681f3Smrg usage |= templ->format == PIPE_FORMAT_S8_UINT ? 6607ec681f3Smrg ISL_SURF_USAGE_STENCIL_BIT : ISL_SURF_USAGE_DEPTH_BIT; 6617ec681f3Smrg } 6627ec681f3Smrg 6637ec681f3Smrg const enum isl_format format = 6647ec681f3Smrg iris_format_for_usage(&screen->devinfo, templ->format, usage).fmt; 6657ec681f3Smrg 6667ec681f3Smrg const struct isl_surf_init_info init_info = { 6677ec681f3Smrg .dim = target_to_isl_surf_dim(templ->target), 6687ec681f3Smrg .format = format, 6697ec681f3Smrg .width = templ->width0, 6707ec681f3Smrg .height = templ->height0, 6717ec681f3Smrg .depth = templ->depth0, 6727ec681f3Smrg .levels = templ->last_level + 1, 6737ec681f3Smrg .array_len = templ->array_size, 6747ec681f3Smrg .samples = MAX2(templ->nr_samples, 1), 6757ec681f3Smrg .min_alignment_B = 0, 6767ec681f3Smrg .row_pitch_B = row_pitch_B, 6777ec681f3Smrg .usage = usage, 6787ec681f3Smrg .tiling_flags = tiling_flags 6797ec681f3Smrg }; 6807ec681f3Smrg 6817ec681f3Smrg if (!isl_surf_init_s(&screen->isl_dev, &res->surf, &init_info)) 6827ec681f3Smrg return false; 6837ec681f3Smrg 6847ec681f3Smrg res->internal_format = templ->format; 6857ec681f3Smrg 6867ec681f3Smrg return true; 6877ec681f3Smrg} 6887ec681f3Smrg 6897ec681f3Smrgstatic bool 6907ec681f3Smrgiris_get_ccs_surf(const struct isl_device *dev, 6917ec681f3Smrg const struct isl_surf *surf, 6927ec681f3Smrg struct isl_surf *aux_surf, 6937ec681f3Smrg struct isl_surf *extra_aux_surf, 6947ec681f3Smrg uint32_t row_pitch_B) 6957ec681f3Smrg{ 6967ec681f3Smrg assert(extra_aux_surf->size_B == 0); 6977ec681f3Smrg 6987ec681f3Smrg struct isl_surf *ccs_surf; 6997ec681f3Smrg const struct isl_surf *hiz_or_mcs_surf; 7007ec681f3Smrg if (aux_surf->size_B > 0) { 7017ec681f3Smrg assert(aux_surf->usage & (ISL_SURF_USAGE_HIZ_BIT | 7027ec681f3Smrg ISL_SURF_USAGE_MCS_BIT)); 7037ec681f3Smrg hiz_or_mcs_surf = aux_surf; 7047ec681f3Smrg ccs_surf = extra_aux_surf; 7057ec681f3Smrg } else { 7067ec681f3Smrg hiz_or_mcs_surf = NULL; 7077ec681f3Smrg ccs_surf = aux_surf; 7087ec681f3Smrg } 7097ec681f3Smrg 7107ec681f3Smrg return isl_surf_get_ccs_surf(dev, surf, hiz_or_mcs_surf, 7117ec681f3Smrg ccs_surf, row_pitch_B); 7127ec681f3Smrg} 7137ec681f3Smrg 7149f464c52Smaya/** 7157ec681f3Smrg * Configure aux for the resource, but don't allocate it. For images which 7167ec681f3Smrg * might be shared with modifiers, we must allocate the image and aux data in 7177ec681f3Smrg * a single bo. 7187ec681f3Smrg * 7197ec681f3Smrg * Returns false on unexpected error (e.g. allocation failed, or invalid 7207ec681f3Smrg * configuration result). 7219f464c52Smaya */ 7229f464c52Smayastatic bool 7237ec681f3Smrgiris_resource_configure_aux(struct iris_screen *screen, 7247ec681f3Smrg struct iris_resource *res, bool imported) 7259f464c52Smaya{ 7267ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 7277ec681f3Smrg 7287ec681f3Smrg /* Try to create the auxiliary surfaces allowed by the modifier or by 7297ec681f3Smrg * the user if no modifier is specified. 7307ec681f3Smrg */ 7317ec681f3Smrg assert(!res->mod_info || 7327ec681f3Smrg res->mod_info->aux_usage == ISL_AUX_USAGE_NONE || 7337ec681f3Smrg res->mod_info->aux_usage == ISL_AUX_USAGE_CCS_E || 7347ec681f3Smrg res->mod_info->aux_usage == ISL_AUX_USAGE_GFX12_CCS_E || 7357ec681f3Smrg res->mod_info->aux_usage == ISL_AUX_USAGE_MC); 7367ec681f3Smrg 7377ec681f3Smrg const bool has_mcs = !res->mod_info && 7387ec681f3Smrg isl_surf_get_mcs_surf(&screen->isl_dev, &res->surf, &res->aux.surf); 7397ec681f3Smrg 7407ec681f3Smrg const bool has_hiz = !res->mod_info && !INTEL_DEBUG(DEBUG_NO_HIZ) && 7417ec681f3Smrg isl_surf_get_hiz_surf(&screen->isl_dev, &res->surf, &res->aux.surf); 7427ec681f3Smrg 7437ec681f3Smrg const bool has_ccs = 7447ec681f3Smrg ((!res->mod_info && !INTEL_DEBUG(DEBUG_NO_RBC)) || 7457ec681f3Smrg (res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE)) && 7467ec681f3Smrg iris_get_ccs_surf(&screen->isl_dev, &res->surf, &res->aux.surf, 7477ec681f3Smrg &res->aux.extra_aux.surf, 0); 7487ec681f3Smrg 7497ec681f3Smrg /* Having both HIZ and MCS is impossible. */ 7507ec681f3Smrg assert(!has_mcs || !has_hiz); 7517ec681f3Smrg 7527ec681f3Smrg if (res->mod_info && has_ccs) { 7537ec681f3Smrg /* Only allow a CCS modifier if the aux was created successfully. */ 7547ec681f3Smrg res->aux.possible_usages |= 1 << res->mod_info->aux_usage; 7557ec681f3Smrg } else if (has_mcs) { 7567ec681f3Smrg res->aux.possible_usages |= 7577ec681f3Smrg 1 << (has_ccs ? ISL_AUX_USAGE_MCS_CCS : ISL_AUX_USAGE_MCS); 7587ec681f3Smrg } else if (has_hiz) { 7597ec681f3Smrg if (!has_ccs) { 7607ec681f3Smrg res->aux.possible_usages |= 1 << ISL_AUX_USAGE_HIZ; 7617ec681f3Smrg } else if (res->surf.samples == 1 && 7627ec681f3Smrg (res->surf.usage & ISL_SURF_USAGE_TEXTURE_BIT)) { 7637ec681f3Smrg /* If this resource is single-sampled and will be used as a texture, 7647ec681f3Smrg * put the HiZ surface in write-through mode so that we can sample 7657ec681f3Smrg * from it. 7667ec681f3Smrg */ 7677ec681f3Smrg res->aux.possible_usages |= 1 << ISL_AUX_USAGE_HIZ_CCS_WT; 7687ec681f3Smrg } else { 7697ec681f3Smrg res->aux.possible_usages |= 1 << ISL_AUX_USAGE_HIZ_CCS; 7707ec681f3Smrg } 7717ec681f3Smrg } else if (has_ccs && isl_surf_usage_is_stencil(res->surf.usage)) { 7727ec681f3Smrg res->aux.possible_usages |= 1 << ISL_AUX_USAGE_STC_CCS; 7737ec681f3Smrg } else if (has_ccs) { 7747ec681f3Smrg if (want_ccs_e_for_format(devinfo, res->surf.format)) { 7757ec681f3Smrg res->aux.possible_usages |= devinfo->ver < 12 ? 7767ec681f3Smrg 1 << ISL_AUX_USAGE_CCS_E : 1 << ISL_AUX_USAGE_GFX12_CCS_E; 7777ec681f3Smrg } else if (isl_format_supports_ccs_d(devinfo, res->surf.format)) { 7787ec681f3Smrg res->aux.possible_usages |= 1 << ISL_AUX_USAGE_CCS_D; 7797ec681f3Smrg } 7807ec681f3Smrg } 7819f464c52Smaya 7827ec681f3Smrg res->aux.usage = util_last_bit(res->aux.possible_usages) - 1; 7837ec681f3Smrg 7847ec681f3Smrg if (!has_hiz || iris_sample_with_depth_aux(devinfo, res)) 7857ec681f3Smrg res->aux.sampler_usages = res->aux.possible_usages; 7867ec681f3Smrg 7877ec681f3Smrg enum isl_aux_state initial_state; 7889f464c52Smaya assert(!res->aux.bo); 7899f464c52Smaya 7909f464c52Smaya switch (res->aux.usage) { 7919f464c52Smaya case ISL_AUX_USAGE_NONE: 7927ec681f3Smrg /* Update relevant fields to indicate that aux is disabled. */ 7937ec681f3Smrg iris_resource_disable_aux(res); 7947ec681f3Smrg 7957ec681f3Smrg /* Having no aux buffer is only okay if there's no modifier with aux. */ 7967ec681f3Smrg return !res->mod_info || res->mod_info->aux_usage == ISL_AUX_USAGE_NONE; 7979f464c52Smaya case ISL_AUX_USAGE_HIZ: 7987ec681f3Smrg case ISL_AUX_USAGE_HIZ_CCS: 7997ec681f3Smrg case ISL_AUX_USAGE_HIZ_CCS_WT: 8009f464c52Smaya initial_state = ISL_AUX_STATE_AUX_INVALID; 8019f464c52Smaya break; 8029f464c52Smaya case ISL_AUX_USAGE_MCS: 8037ec681f3Smrg case ISL_AUX_USAGE_MCS_CCS: 8049f464c52Smaya /* The Ivybridge PRM, Vol 2 Part 1 p326 says: 8059f464c52Smaya * 8069f464c52Smaya * "When MCS buffer is enabled and bound to MSRT, it is required 8079f464c52Smaya * that it is cleared prior to any rendering." 8089f464c52Smaya * 8099f464c52Smaya * Since we only use the MCS buffer for rendering, we just clear it 8109f464c52Smaya * immediately on allocation. The clear value for MCS buffers is all 8119f464c52Smaya * 1's, so we simply memset it to 0xff. 8129f464c52Smaya */ 8139f464c52Smaya initial_state = ISL_AUX_STATE_CLEAR; 8149f464c52Smaya break; 8159f464c52Smaya case ISL_AUX_USAGE_CCS_D: 8169f464c52Smaya case ISL_AUX_USAGE_CCS_E: 8177ec681f3Smrg case ISL_AUX_USAGE_GFX12_CCS_E: 8187ec681f3Smrg case ISL_AUX_USAGE_STC_CCS: 8197ec681f3Smrg case ISL_AUX_USAGE_MC: 8209f464c52Smaya /* When CCS_E is used, we need to ensure that the CCS starts off in 8219f464c52Smaya * a valid state. From the Sky Lake PRM, "MCS Buffer for Render 8229f464c52Smaya * Target(s)": 8239f464c52Smaya * 8249f464c52Smaya * "If Software wants to enable Color Compression without Fast 8259f464c52Smaya * clear, Software needs to initialize MCS with zeros." 8269f464c52Smaya * 8279f464c52Smaya * A CCS value of 0 indicates that the corresponding block is in the 8289f464c52Smaya * pass-through state which is what we want. 8299f464c52Smaya * 8307ec681f3Smrg * For CCS_D, do the same thing. On Gfx9+, this avoids having any 8319f464c52Smaya * undefined bits in the aux buffer. 8329f464c52Smaya */ 8337ec681f3Smrg if (imported) { 8347ec681f3Smrg assert(res->aux.usage != ISL_AUX_USAGE_STC_CCS); 8357ec681f3Smrg initial_state = 8367ec681f3Smrg isl_drm_modifier_get_default_aux_state(res->mod_info->modifier); 8377ec681f3Smrg } else { 8387ec681f3Smrg initial_state = ISL_AUX_STATE_PASS_THROUGH; 8397ec681f3Smrg } 8409f464c52Smaya break; 8417ec681f3Smrg default: 8427ec681f3Smrg unreachable("Unsupported aux mode"); 8439f464c52Smaya } 8449f464c52Smaya 8459f464c52Smaya /* Create the aux_state for the auxiliary buffer. */ 8469f464c52Smaya res->aux.state = create_aux_state_map(res, initial_state); 8479f464c52Smaya if (!res->aux.state) 8489f464c52Smaya return false; 8499f464c52Smaya 8507ec681f3Smrg return true; 8517ec681f3Smrg} 8529f464c52Smaya 8537ec681f3Smrg/** 8547ec681f3Smrg * Initialize the aux buffer contents. 8557ec681f3Smrg * 8567ec681f3Smrg * Returns false on unexpected error (e.g. mapping a BO failed). 8577ec681f3Smrg */ 8587ec681f3Smrgstatic bool 8597ec681f3Smrgiris_resource_init_aux_buf(struct iris_resource *res, 8607ec681f3Smrg unsigned clear_color_state_size) 8617ec681f3Smrg{ 8627ec681f3Smrg void *map = iris_bo_map(NULL, res->aux.bo, MAP_WRITE | MAP_RAW); 8639f464c52Smaya 8647ec681f3Smrg if (!map) 8659f464c52Smaya return false; 8669f464c52Smaya 8677ec681f3Smrg if (iris_resource_get_aux_state(res, 0, 0) != ISL_AUX_STATE_AUX_INVALID) { 8687ec681f3Smrg /* See iris_resource_configure_aux for the memset_value rationale. */ 8697ec681f3Smrg uint8_t memset_value = isl_aux_usage_has_mcs(res->aux.usage) ? 0xFF : 0; 8707ec681f3Smrg memset((char*)map + res->aux.offset, memset_value, 8717ec681f3Smrg res->aux.surf.size_B); 8727ec681f3Smrg } 8739f464c52Smaya 8747ec681f3Smrg memset((char*)map + res->aux.extra_aux.offset, 8757ec681f3Smrg 0, res->aux.extra_aux.surf.size_B); 8769f464c52Smaya 8777ec681f3Smrg /* Zero the indirect clear color to match ::fast_clear_color. */ 8787ec681f3Smrg memset((char *)map + res->aux.clear_color_offset, 0, 8797ec681f3Smrg clear_color_state_size); 8809f464c52Smaya 8817ec681f3Smrg iris_bo_unmap(res->aux.bo); 8829f464c52Smaya 8839f464c52Smaya if (clear_color_state_size > 0) { 8849f464c52Smaya res->aux.clear_color_bo = res->aux.bo; 8859f464c52Smaya iris_bo_reference(res->aux.clear_color_bo); 8869f464c52Smaya } 8879f464c52Smaya 8889f464c52Smaya return true; 8899f464c52Smaya} 8909f464c52Smaya 8917ec681f3Smrgstatic void 8927ec681f3Smrgimport_aux_info(struct iris_resource *res, 8937ec681f3Smrg const struct iris_resource *aux_res) 8949f464c52Smaya{ 8957ec681f3Smrg assert(aux_res->aux.surf.row_pitch_B && aux_res->aux.offset); 8967ec681f3Smrg assert(res->bo == aux_res->aux.bo); 8977ec681f3Smrg assert(res->aux.surf.row_pitch_B == aux_res->aux.surf.row_pitch_B); 8987ec681f3Smrg assert(res->bo->size >= aux_res->aux.offset + res->aux.surf.size_B); 8997ec681f3Smrg 9007ec681f3Smrg iris_bo_reference(aux_res->aux.bo); 9017ec681f3Smrg res->aux.bo = aux_res->aux.bo; 9027ec681f3Smrg res->aux.offset = aux_res->aux.offset; 9039f464c52Smaya} 9049f464c52Smaya 9057ec681f3Smrgstatic void 9067ec681f3Smrgiris_resource_finish_aux_import(struct pipe_screen *pscreen, 9077ec681f3Smrg struct iris_resource *res) 9089f464c52Smaya{ 9097ec681f3Smrg struct iris_screen *screen = (struct iris_screen *)pscreen; 9109f464c52Smaya 9117ec681f3Smrg /* Create an array of resources. Combining main and aux planes is easier 9127ec681f3Smrg * with indexing as opposed to scanning the linked list. 9139f464c52Smaya */ 9147ec681f3Smrg struct iris_resource *r[4] = { NULL, }; 9157ec681f3Smrg unsigned num_planes = 0; 9167ec681f3Smrg unsigned num_main_planes = 0; 9177ec681f3Smrg for (struct pipe_resource *p_res = &res->base.b; p_res; p_res = p_res->next) { 9187ec681f3Smrg r[num_planes] = (struct iris_resource *)p_res; 9197ec681f3Smrg num_main_planes += r[num_planes++]->bo != NULL; 9207ec681f3Smrg } 9219f464c52Smaya 9227ec681f3Smrg /* Get an ISL format to use with the aux-map. */ 9237ec681f3Smrg enum isl_format format; 9247ec681f3Smrg switch (res->external_format) { 9257ec681f3Smrg case PIPE_FORMAT_NV12: format = ISL_FORMAT_PLANAR_420_8; break; 9267ec681f3Smrg case PIPE_FORMAT_P010: format = ISL_FORMAT_PLANAR_420_10; break; 9277ec681f3Smrg case PIPE_FORMAT_P012: format = ISL_FORMAT_PLANAR_420_12; break; 9287ec681f3Smrg case PIPE_FORMAT_P016: format = ISL_FORMAT_PLANAR_420_16; break; 9297ec681f3Smrg case PIPE_FORMAT_YUYV: format = ISL_FORMAT_YCRCB_NORMAL; break; 9307ec681f3Smrg case PIPE_FORMAT_UYVY: format = ISL_FORMAT_YCRCB_SWAPY; break; 9317ec681f3Smrg default: format = res->surf.format; break; 9327ec681f3Smrg } 9339f464c52Smaya 9347ec681f3Smrg /* Combine main and aux plane information. */ 9357ec681f3Smrg switch (res->mod_info->modifier) { 9367ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_CCS: 9377ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 9387ec681f3Smrg assert(num_main_planes == 1 && num_planes == 2); 9397ec681f3Smrg import_aux_info(r[0], r[1]); 9407ec681f3Smrg map_aux_addresses(screen, r[0], format, 0); 9417ec681f3Smrg 9427ec681f3Smrg /* Add on a clear color BO. 9437ec681f3Smrg * 9447ec681f3Smrg * Also add some padding to make sure the fast clear color state buffer 9457ec681f3Smrg * starts at a 4K alignment to avoid some unknown issues. See the 9467ec681f3Smrg * matching comment in iris_resource_create_with_modifiers(). 9477ec681f3Smrg */ 9487ec681f3Smrg if (iris_get_aux_clear_color_state_size(screen) > 0) { 9497ec681f3Smrg res->aux.clear_color_bo = 9507ec681f3Smrg iris_bo_alloc(screen->bufmgr, "clear color_buffer", 9517ec681f3Smrg iris_get_aux_clear_color_state_size(screen), 4096, 9527ec681f3Smrg IRIS_MEMZONE_OTHER, BO_ALLOC_ZEROED); 9537ec681f3Smrg } 9547ec681f3Smrg break; 9557ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 9567ec681f3Smrg assert(num_main_planes == 1 && num_planes == 3); 9577ec681f3Smrg import_aux_info(r[0], r[1]); 9587ec681f3Smrg map_aux_addresses(screen, r[0], format, 0); 9597ec681f3Smrg 9607ec681f3Smrg /* Import the clear color BO. */ 9617ec681f3Smrg iris_bo_reference(r[2]->aux.clear_color_bo); 9627ec681f3Smrg r[0]->aux.clear_color_bo = r[2]->aux.clear_color_bo; 9637ec681f3Smrg r[0]->aux.clear_color_offset = r[2]->aux.clear_color_offset; 9647ec681f3Smrg r[0]->aux.clear_color_unknown = true; 9657ec681f3Smrg break; 9667ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 9677ec681f3Smrg if (num_main_planes == 1 && num_planes == 2) { 9687ec681f3Smrg import_aux_info(r[0], r[1]); 9697ec681f3Smrg map_aux_addresses(screen, r[0], format, 0); 9707ec681f3Smrg } else if (num_main_planes == 2 && num_planes == 4) { 9717ec681f3Smrg import_aux_info(r[0], r[2]); 9727ec681f3Smrg import_aux_info(r[1], r[3]); 9737ec681f3Smrg map_aux_addresses(screen, r[0], format, 0); 9747ec681f3Smrg map_aux_addresses(screen, r[1], format, 1); 9757ec681f3Smrg } else { 9767ec681f3Smrg /* Gallium has lowered a single main plane into two. */ 9777ec681f3Smrg assert(num_main_planes == 2 && num_planes == 3); 9787ec681f3Smrg assert(isl_format_is_yuv(format) && !isl_format_is_planar(format)); 9797ec681f3Smrg import_aux_info(r[0], r[2]); 9807ec681f3Smrg import_aux_info(r[1], r[2]); 9817ec681f3Smrg map_aux_addresses(screen, r[0], format, 0); 9827ec681f3Smrg } 9837ec681f3Smrg assert(!isl_aux_usage_has_fast_clears(res->mod_info->aux_usage)); 9847ec681f3Smrg break; 9857ec681f3Smrg default: 9867ec681f3Smrg assert(res->mod_info->aux_usage == ISL_AUX_USAGE_NONE); 9877ec681f3Smrg break; 9887ec681f3Smrg } 9899f464c52Smaya} 9909f464c52Smaya 9919f464c52Smayastatic struct pipe_resource * 9929f464c52Smayairis_resource_create_for_buffer(struct pipe_screen *pscreen, 9939f464c52Smaya const struct pipe_resource *templ) 9949f464c52Smaya{ 9959f464c52Smaya struct iris_screen *screen = (struct iris_screen *)pscreen; 9969f464c52Smaya struct iris_resource *res = iris_alloc_resource(pscreen, templ); 9979f464c52Smaya 9989f464c52Smaya assert(templ->target == PIPE_BUFFER); 9999f464c52Smaya assert(templ->height0 <= 1); 10009f464c52Smaya assert(templ->depth0 <= 1); 10019f464c52Smaya assert(templ->format == PIPE_FORMAT_NONE || 10029f464c52Smaya util_format_get_blocksize(templ->format) == 1); 10039f464c52Smaya 10049f464c52Smaya res->internal_format = templ->format; 10059f464c52Smaya res->surf.tiling = ISL_TILING_LINEAR; 10069f464c52Smaya 10079f464c52Smaya enum iris_memory_zone memzone = IRIS_MEMZONE_OTHER; 10089f464c52Smaya const char *name = templ->target == PIPE_BUFFER ? "buffer" : "miptree"; 10099f464c52Smaya if (templ->flags & IRIS_RESOURCE_FLAG_SHADER_MEMZONE) { 10109f464c52Smaya memzone = IRIS_MEMZONE_SHADER; 10119f464c52Smaya name = "shader kernels"; 10129f464c52Smaya } else if (templ->flags & IRIS_RESOURCE_FLAG_SURFACE_MEMZONE) { 10139f464c52Smaya memzone = IRIS_MEMZONE_SURFACE; 10149f464c52Smaya name = "surface state"; 10159f464c52Smaya } else if (templ->flags & IRIS_RESOURCE_FLAG_DYNAMIC_MEMZONE) { 10169f464c52Smaya memzone = IRIS_MEMZONE_DYNAMIC; 10179f464c52Smaya name = "dynamic state"; 10187ec681f3Smrg } else if (templ->flags & IRIS_RESOURCE_FLAG_BINDLESS_MEMZONE) { 10197ec681f3Smrg memzone = IRIS_MEMZONE_BINDLESS; 10207ec681f3Smrg name = "bindless surface state"; 10219f464c52Smaya } 10229f464c52Smaya 10237ec681f3Smrg unsigned flags = iris_resource_alloc_flags(screen, templ); 10247ec681f3Smrg 10257ec681f3Smrg res->bo = 10267ec681f3Smrg iris_bo_alloc(screen->bufmgr, name, templ->width0, 1, memzone, flags); 10277ec681f3Smrg 10289f464c52Smaya if (!res->bo) { 10297ec681f3Smrg iris_resource_destroy(pscreen, &res->base.b); 10309f464c52Smaya return NULL; 10319f464c52Smaya } 10329f464c52Smaya 10337ec681f3Smrg if (templ->bind & PIPE_BIND_SHARED) { 10347ec681f3Smrg iris_bo_mark_exported(res->bo); 10357ec681f3Smrg res->base.is_shared = true; 10367ec681f3Smrg } 10377ec681f3Smrg 10387ec681f3Smrg return &res->base.b; 10399f464c52Smaya} 10409f464c52Smaya 10419f464c52Smayastatic struct pipe_resource * 10429f464c52Smayairis_resource_create_with_modifiers(struct pipe_screen *pscreen, 10439f464c52Smaya const struct pipe_resource *templ, 10449f464c52Smaya const uint64_t *modifiers, 10459f464c52Smaya int modifiers_count) 10469f464c52Smaya{ 10479f464c52Smaya struct iris_screen *screen = (struct iris_screen *)pscreen; 10487ec681f3Smrg struct intel_device_info *devinfo = &screen->devinfo; 10499f464c52Smaya struct iris_resource *res = iris_alloc_resource(pscreen, templ); 10509f464c52Smaya 10519f464c52Smaya if (!res) 10529f464c52Smaya return NULL; 10539f464c52Smaya 10549f464c52Smaya uint64_t modifier = 10557ec681f3Smrg select_best_modifier(devinfo, templ, modifiers, modifiers_count); 10569f464c52Smaya 10577ec681f3Smrg if (modifier == DRM_FORMAT_MOD_INVALID && modifiers_count > 0) { 10587ec681f3Smrg fprintf(stderr, "Unsupported modifier, resource creation failed.\n"); 10597ec681f3Smrg goto fail; 10609f464c52Smaya } 10619f464c52Smaya 10629f464c52Smaya UNUSED const bool isl_surf_created_successfully = 10637ec681f3Smrg iris_resource_configure_main(screen, res, templ, modifier, 0); 10649f464c52Smaya assert(isl_surf_created_successfully); 10659f464c52Smaya 10667ec681f3Smrg const char *name = "miptree"; 10677ec681f3Smrg enum iris_memory_zone memzone = IRIS_MEMZONE_OTHER; 10689f464c52Smaya 10697ec681f3Smrg unsigned int flags = iris_resource_alloc_flags(screen, templ); 10709f464c52Smaya 10717ec681f3Smrg /* These are for u_upload_mgr buffers only */ 10727ec681f3Smrg assert(!(templ->flags & (IRIS_RESOURCE_FLAG_SHADER_MEMZONE | 10737ec681f3Smrg IRIS_RESOURCE_FLAG_SURFACE_MEMZONE | 10747ec681f3Smrg IRIS_RESOURCE_FLAG_DYNAMIC_MEMZONE | 10757ec681f3Smrg IRIS_RESOURCE_FLAG_BINDLESS_MEMZONE))); 10769f464c52Smaya 10777ec681f3Smrg if (!iris_resource_configure_aux(screen, res, false)) 10787ec681f3Smrg goto fail; 10799f464c52Smaya 10807ec681f3Smrg /* Modifiers require the aux data to be in the same buffer as the main 10817ec681f3Smrg * surface, but we combine them even when a modifier is not being used. 10829f464c52Smaya */ 10837ec681f3Smrg uint64_t bo_size = res->surf.size_B; 10849f464c52Smaya 10857ec681f3Smrg /* Allocate space for the aux buffer. */ 10867ec681f3Smrg if (res->aux.surf.size_B > 0) { 10877ec681f3Smrg res->aux.offset = ALIGN(bo_size, res->aux.surf.alignment_B); 10887ec681f3Smrg bo_size = res->aux.offset + res->aux.surf.size_B; 10897ec681f3Smrg } 10909f464c52Smaya 10917ec681f3Smrg /* Allocate space for the extra aux buffer. */ 10927ec681f3Smrg if (res->aux.extra_aux.surf.size_B > 0) { 10937ec681f3Smrg res->aux.extra_aux.offset = 10947ec681f3Smrg ALIGN(bo_size, res->aux.extra_aux.surf.alignment_B); 10957ec681f3Smrg bo_size = res->aux.extra_aux.offset + res->aux.extra_aux.surf.size_B; 10967ec681f3Smrg } 10979f464c52Smaya 10987ec681f3Smrg /* Allocate space for the indirect clear color. 10997ec681f3Smrg * 11007ec681f3Smrg * Also add some padding to make sure the fast clear color state buffer 11017ec681f3Smrg * starts at a 4K alignment. We believe that 256B might be enough, but due 11027ec681f3Smrg * to lack of testing we will leave this as 4K for now. 11037ec681f3Smrg */ 11047ec681f3Smrg if (res->aux.surf.size_B > 0) { 11057ec681f3Smrg res->aux.clear_color_offset = ALIGN(bo_size, 4096); 11067ec681f3Smrg bo_size = res->aux.clear_color_offset + 11077ec681f3Smrg iris_get_aux_clear_color_state_size(screen); 11087ec681f3Smrg } 11099f464c52Smaya 11107ec681f3Smrg uint32_t alignment = MAX2(4096, res->surf.alignment_B); 11117ec681f3Smrg res->bo = 11127ec681f3Smrg iris_bo_alloc(screen->bufmgr, name, bo_size, alignment, memzone, flags); 11139f464c52Smaya 11149f464c52Smaya if (!res->bo) 11159f464c52Smaya goto fail; 11169f464c52Smaya 11177ec681f3Smrg if (res->aux.surf.size_B > 0) { 11187ec681f3Smrg res->aux.bo = res->bo; 11197ec681f3Smrg iris_bo_reference(res->aux.bo); 11207ec681f3Smrg unsigned clear_color_state_size = 11217ec681f3Smrg iris_get_aux_clear_color_state_size(screen); 11227ec681f3Smrg if (!iris_resource_init_aux_buf(res, clear_color_state_size)) 11237ec681f3Smrg goto fail; 11247ec681f3Smrg map_aux_addresses(screen, res, res->surf.format, 0); 11257ec681f3Smrg } 11269f464c52Smaya 11277ec681f3Smrg if (templ->bind & PIPE_BIND_SHARED) { 11287ec681f3Smrg iris_bo_mark_exported(res->bo); 11297ec681f3Smrg res->base.is_shared = true; 11307ec681f3Smrg } 11317ec681f3Smrg 11327ec681f3Smrg return &res->base.b; 11339f464c52Smaya 11349f464c52Smayafail: 11359f464c52Smaya fprintf(stderr, "XXX: resource creation failed\n"); 11367ec681f3Smrg iris_resource_destroy(pscreen, &res->base.b); 11379f464c52Smaya return NULL; 11389f464c52Smaya} 11399f464c52Smaya 11409f464c52Smayastatic struct pipe_resource * 11419f464c52Smayairis_resource_create(struct pipe_screen *pscreen, 11429f464c52Smaya const struct pipe_resource *templ) 11439f464c52Smaya{ 11449f464c52Smaya if (templ->target == PIPE_BUFFER) 11459f464c52Smaya return iris_resource_create_for_buffer(pscreen, templ); 11469f464c52Smaya else 11479f464c52Smaya return iris_resource_create_with_modifiers(pscreen, templ, NULL, 0); 11489f464c52Smaya} 11499f464c52Smaya 11509f464c52Smayastatic uint64_t 11519f464c52Smayatiling_to_modifier(uint32_t tiling) 11529f464c52Smaya{ 11539f464c52Smaya static const uint64_t map[] = { 11549f464c52Smaya [I915_TILING_NONE] = DRM_FORMAT_MOD_LINEAR, 11559f464c52Smaya [I915_TILING_X] = I915_FORMAT_MOD_X_TILED, 11569f464c52Smaya [I915_TILING_Y] = I915_FORMAT_MOD_Y_TILED, 11579f464c52Smaya }; 11589f464c52Smaya 11599f464c52Smaya assert(tiling < ARRAY_SIZE(map)); 11609f464c52Smaya 11619f464c52Smaya return map[tiling]; 11629f464c52Smaya} 11639f464c52Smaya 11649f464c52Smayastatic struct pipe_resource * 11659f464c52Smayairis_resource_from_user_memory(struct pipe_screen *pscreen, 11669f464c52Smaya const struct pipe_resource *templ, 11679f464c52Smaya void *user_memory) 11689f464c52Smaya{ 11699f464c52Smaya struct iris_screen *screen = (struct iris_screen *)pscreen; 11709f464c52Smaya struct iris_bufmgr *bufmgr = screen->bufmgr; 11719f464c52Smaya struct iris_resource *res = iris_alloc_resource(pscreen, templ); 11729f464c52Smaya if (!res) 11739f464c52Smaya return NULL; 11749f464c52Smaya 11759f464c52Smaya assert(templ->target == PIPE_BUFFER); 11769f464c52Smaya 11779f464c52Smaya res->internal_format = templ->format; 11787ec681f3Smrg res->base.is_user_ptr = true; 11799f464c52Smaya res->bo = iris_bo_create_userptr(bufmgr, "user", 11809f464c52Smaya user_memory, templ->width0, 11819f464c52Smaya IRIS_MEMZONE_OTHER); 11829f464c52Smaya if (!res->bo) { 11837ec681f3Smrg iris_resource_destroy(pscreen, &res->base.b); 11847ec681f3Smrg return NULL; 11857ec681f3Smrg } 11867ec681f3Smrg 11877ec681f3Smrg util_range_add(&res->base.b, &res->valid_buffer_range, 0, templ->width0); 11887ec681f3Smrg 11897ec681f3Smrg return &res->base.b; 11907ec681f3Smrg} 11917ec681f3Smrg 11927ec681f3Smrgstatic bool 11937ec681f3Smrgmod_plane_is_clear_color(uint64_t modifier, uint32_t plane) 11947ec681f3Smrg{ 11957ec681f3Smrg ASSERTED const struct isl_drm_modifier_info *mod_info = 11967ec681f3Smrg isl_drm_modifier_get_info(modifier); 11977ec681f3Smrg assert(mod_info); 11987ec681f3Smrg 11997ec681f3Smrg switch (modifier) { 12007ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 12017ec681f3Smrg assert(mod_info->supports_clear_color); 12027ec681f3Smrg return plane == 2; 12037ec681f3Smrg default: 12047ec681f3Smrg assert(!mod_info->supports_clear_color); 12057ec681f3Smrg return false; 12067ec681f3Smrg } 12077ec681f3Smrg} 12087ec681f3Smrg 12097ec681f3Smrgstatic unsigned 12107ec681f3Smrgget_num_planes(const struct pipe_resource *resource) 12117ec681f3Smrg{ 12127ec681f3Smrg unsigned count = 0; 12137ec681f3Smrg for (const struct pipe_resource *cur = resource; cur; cur = cur->next) 12147ec681f3Smrg count++; 12157ec681f3Smrg 12167ec681f3Smrg return count; 12177ec681f3Smrg} 12187ec681f3Smrg 12197ec681f3Smrgstatic struct pipe_resource * 12207ec681f3Smrgiris_resource_from_handle(struct pipe_screen *pscreen, 12217ec681f3Smrg const struct pipe_resource *templ, 12227ec681f3Smrg struct winsys_handle *whandle, 12237ec681f3Smrg unsigned usage) 12247ec681f3Smrg{ 12257ec681f3Smrg assert(templ->target != PIPE_BUFFER); 12267ec681f3Smrg 12277ec681f3Smrg struct iris_screen *screen = (struct iris_screen *)pscreen; 12287ec681f3Smrg struct iris_bufmgr *bufmgr = screen->bufmgr; 12297ec681f3Smrg struct iris_resource *res = iris_alloc_resource(pscreen, templ); 12307ec681f3Smrg if (!res) 12319f464c52Smaya return NULL; 12327ec681f3Smrg 12337ec681f3Smrg switch (whandle->type) { 12347ec681f3Smrg case WINSYS_HANDLE_TYPE_FD: 12357ec681f3Smrg res->bo = iris_bo_import_dmabuf(bufmgr, whandle->handle); 12367ec681f3Smrg break; 12377ec681f3Smrg case WINSYS_HANDLE_TYPE_SHARED: 12387ec681f3Smrg res->bo = iris_bo_gem_create_from_name(bufmgr, "winsys image", 12397ec681f3Smrg whandle->handle); 12407ec681f3Smrg break; 12417ec681f3Smrg default: 12427ec681f3Smrg unreachable("invalid winsys handle type"); 12439f464c52Smaya } 12447ec681f3Smrg if (!res->bo) 12457ec681f3Smrg goto fail; 12467ec681f3Smrg 12477ec681f3Smrg res->offset = whandle->offset; 12487ec681f3Smrg res->external_format = whandle->format; 12499f464c52Smaya 12507ec681f3Smrg /* Create a surface for each plane specified by the external format. */ 12517ec681f3Smrg if (whandle->plane < util_format_get_num_planes(whandle->format)) { 12527ec681f3Smrg uint64_t modifier = whandle->modifier; 12539f464c52Smaya 12547ec681f3Smrg if (whandle->modifier == DRM_FORMAT_MOD_INVALID) { 12557ec681f3Smrg /* We don't have a modifier; match whatever GEM_GET_TILING says */ 12567ec681f3Smrg uint32_t tiling; 12577ec681f3Smrg iris_gem_get_tiling(res->bo, &tiling); 12587ec681f3Smrg modifier = tiling_to_modifier(tiling); 12597ec681f3Smrg } 12607ec681f3Smrg 12617ec681f3Smrg UNUSED const bool isl_surf_created_successfully = 12627ec681f3Smrg iris_resource_configure_main(screen, res, templ, modifier, 12637ec681f3Smrg whandle->stride); 12647ec681f3Smrg assert(isl_surf_created_successfully); 12657ec681f3Smrg 12667ec681f3Smrg UNUSED const bool ok = iris_resource_configure_aux(screen, res, true); 12677ec681f3Smrg assert(ok); 12687ec681f3Smrg /* The gallium dri layer will create a separate plane resource for the 12697ec681f3Smrg * aux image. iris_resource_finish_aux_import will merge the separate aux 12707ec681f3Smrg * parameters back into a single iris_resource. 12717ec681f3Smrg */ 12727ec681f3Smrg } else if (mod_plane_is_clear_color(whandle->modifier, whandle->plane)) { 12737ec681f3Smrg res->aux.clear_color_offset = whandle->offset; 12747ec681f3Smrg res->aux.clear_color_bo = res->bo; 12757ec681f3Smrg res->bo = NULL; 12767ec681f3Smrg } else { 12777ec681f3Smrg /* Save modifier import information to reconstruct later. After import, 12787ec681f3Smrg * this will be available under a second image accessible from the main 12797ec681f3Smrg * image with res->base.next. See iris_resource_finish_aux_import. 12807ec681f3Smrg */ 12817ec681f3Smrg res->aux.surf.row_pitch_B = whandle->stride; 12827ec681f3Smrg res->aux.offset = whandle->offset; 12837ec681f3Smrg res->aux.bo = res->bo; 12847ec681f3Smrg res->bo = NULL; 12857ec681f3Smrg } 12867ec681f3Smrg 12877ec681f3Smrg if (get_num_planes(&res->base.b) == 12887ec681f3Smrg iris_get_dmabuf_modifier_planes(pscreen, whandle->modifier, 12897ec681f3Smrg whandle->format)) { 12907ec681f3Smrg iris_resource_finish_aux_import(pscreen, res); 12917ec681f3Smrg } 12927ec681f3Smrg 12937ec681f3Smrg return &res->base.b; 12947ec681f3Smrg 12957ec681f3Smrgfail: 12967ec681f3Smrg iris_resource_destroy(pscreen, &res->base.b); 12977ec681f3Smrg return NULL; 12989f464c52Smaya} 12999f464c52Smaya 13009f464c52Smayastatic struct pipe_resource * 13017ec681f3Smrgiris_resource_from_memobj(struct pipe_screen *pscreen, 13029f464c52Smaya const struct pipe_resource *templ, 13037ec681f3Smrg struct pipe_memory_object *pmemobj, 13047ec681f3Smrg uint64_t offset) 13059f464c52Smaya{ 13069f464c52Smaya struct iris_screen *screen = (struct iris_screen *)pscreen; 13077ec681f3Smrg struct iris_memory_object *memobj = (struct iris_memory_object *)pmemobj; 13089f464c52Smaya struct iris_resource *res = iris_alloc_resource(pscreen, templ); 13097ec681f3Smrg 13109f464c52Smaya if (!res) 13119f464c52Smaya return NULL; 13129f464c52Smaya 13137ec681f3Smrg if (templ->flags & PIPE_RESOURCE_FLAG_TEXTURING_MORE_LIKELY) { 13147ec681f3Smrg UNUSED const bool isl_surf_created_successfully = 13157ec681f3Smrg iris_resource_configure_main(screen, res, templ, DRM_FORMAT_MOD_INVALID, 0); 13167ec681f3Smrg assert(isl_surf_created_successfully); 13179f464c52Smaya } 13189f464c52Smaya 13197ec681f3Smrg res->bo = memobj->bo; 13207ec681f3Smrg res->offset = offset; 13217ec681f3Smrg res->external_format = memobj->format; 13227ec681f3Smrg 13237ec681f3Smrg iris_bo_reference(memobj->bo); 13247ec681f3Smrg 13257ec681f3Smrg return &res->base.b; 13267ec681f3Smrg} 13277ec681f3Smrg 13287ec681f3Smrg/* Handle combined depth/stencil with memory objects. 13297ec681f3Smrg * 13307ec681f3Smrg * This function is modeled after u_transfer_helper_resource_create. 13317ec681f3Smrg */ 13327ec681f3Smrgstatic struct pipe_resource * 13337ec681f3Smrgiris_resource_from_memobj_wrapper(struct pipe_screen *pscreen, 13347ec681f3Smrg const struct pipe_resource *templ, 13357ec681f3Smrg struct pipe_memory_object *pmemobj, 13367ec681f3Smrg uint64_t offset) 13377ec681f3Smrg{ 13387ec681f3Smrg enum pipe_format format = templ->format; 13397ec681f3Smrg 13407ec681f3Smrg /* Normal case, no special handling: */ 13417ec681f3Smrg if (!(util_format_is_depth_and_stencil(format))) 13427ec681f3Smrg return iris_resource_from_memobj(pscreen, templ, pmemobj, offset); 13437ec681f3Smrg 13447ec681f3Smrg struct pipe_resource t = *templ; 13457ec681f3Smrg t.format = util_format_get_depth_only(format); 13467ec681f3Smrg 13477ec681f3Smrg struct pipe_resource *prsc = 13487ec681f3Smrg iris_resource_from_memobj(pscreen, &t, pmemobj, offset); 13497ec681f3Smrg if (!prsc) 13509f464c52Smaya return NULL; 13519f464c52Smaya 13527ec681f3Smrg struct iris_resource *res = (struct iris_resource *) prsc; 13539f464c52Smaya 13547ec681f3Smrg /* Stencil offset in the buffer without aux. */ 13557ec681f3Smrg uint64_t s_offset = offset + 13567ec681f3Smrg ALIGN(res->surf.size_B, res->surf.alignment_B); 13579f464c52Smaya 13587ec681f3Smrg prsc->format = format; /* frob the format back to the "external" format */ 13599f464c52Smaya 13607ec681f3Smrg t.format = PIPE_FORMAT_S8_UINT; 13617ec681f3Smrg struct pipe_resource *stencil = 13627ec681f3Smrg iris_resource_from_memobj(pscreen, &t, pmemobj, s_offset); 13637ec681f3Smrg if (!stencil) { 13647ec681f3Smrg iris_resource_destroy(pscreen, prsc); 13657ec681f3Smrg return NULL; 13669f464c52Smaya } 13679f464c52Smaya 13687ec681f3Smrg iris_resource_set_separate_stencil(prsc, stencil); 13697ec681f3Smrg return prsc; 13709f464c52Smaya} 13719f464c52Smaya 13729f464c52Smayastatic void 13739f464c52Smayairis_flush_resource(struct pipe_context *ctx, struct pipe_resource *resource) 13749f464c52Smaya{ 13759f464c52Smaya struct iris_context *ice = (struct iris_context *)ctx; 13769f464c52Smaya struct iris_resource *res = (void *) resource; 13779f464c52Smaya const struct isl_drm_modifier_info *mod = res->mod_info; 13789f464c52Smaya 13797ec681f3Smrg iris_resource_prepare_access(ice, res, 13809f464c52Smaya 0, INTEL_REMAINING_LEVELS, 13819f464c52Smaya 0, INTEL_REMAINING_LAYERS, 13829f464c52Smaya mod ? mod->aux_usage : ISL_AUX_USAGE_NONE, 13839f464c52Smaya mod ? mod->supports_clear_color : false); 13847ec681f3Smrg 13857ec681f3Smrg if (!res->mod_info && res->aux.usage != ISL_AUX_USAGE_NONE) { 13867ec681f3Smrg /* flush_resource may be used to prepare an image for sharing external 13877ec681f3Smrg * to the driver (e.g. via eglCreateImage). To account for this, make 13887ec681f3Smrg * sure to get rid of any compression that a consumer wouldn't know how 13897ec681f3Smrg * to handle. 13907ec681f3Smrg */ 13917ec681f3Smrg for (int i = 0; i < IRIS_BATCH_COUNT; i++) { 13927ec681f3Smrg if (iris_batch_references(&ice->batches[i], res->bo)) 13937ec681f3Smrg iris_batch_flush(&ice->batches[i]); 13947ec681f3Smrg } 13957ec681f3Smrg 13967ec681f3Smrg iris_resource_disable_aux(res); 13977ec681f3Smrg } 13987ec681f3Smrg} 13997ec681f3Smrg 14007ec681f3Smrg/** 14017ec681f3Smrg * Reallocate a (non-external) resource into new storage, copying the data 14027ec681f3Smrg * and modifying the original resource to point at the new storage. 14037ec681f3Smrg * 14047ec681f3Smrg * This is useful for e.g. moving a suballocated internal resource to a 14057ec681f3Smrg * dedicated allocation that can be exported by itself. 14067ec681f3Smrg */ 14077ec681f3Smrgstatic void 14087ec681f3Smrgiris_reallocate_resource_inplace(struct iris_context *ice, 14097ec681f3Smrg struct iris_resource *old_res, 14107ec681f3Smrg unsigned new_bind_flag) 14117ec681f3Smrg{ 14127ec681f3Smrg struct pipe_screen *pscreen = ice->ctx.screen; 14137ec681f3Smrg 14147ec681f3Smrg if (iris_bo_is_external(old_res->bo)) 14157ec681f3Smrg return; 14167ec681f3Smrg 14177ec681f3Smrg assert(old_res->mod_info == NULL); 14187ec681f3Smrg assert(old_res->bo == old_res->aux.bo || old_res->aux.bo == NULL); 14197ec681f3Smrg assert(old_res->bo == old_res->aux.clear_color_bo || 14207ec681f3Smrg old_res->aux.clear_color_bo == NULL); 14217ec681f3Smrg assert(old_res->external_format == PIPE_FORMAT_NONE); 14227ec681f3Smrg 14237ec681f3Smrg struct pipe_resource templ = old_res->base.b; 14247ec681f3Smrg templ.bind |= new_bind_flag; 14257ec681f3Smrg 14267ec681f3Smrg struct iris_resource *new_res = 14277ec681f3Smrg (void *) pscreen->resource_create(pscreen, &templ); 14287ec681f3Smrg 14297ec681f3Smrg assert(iris_bo_is_real(new_res->bo)); 14307ec681f3Smrg 14317ec681f3Smrg struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER]; 14327ec681f3Smrg 14337ec681f3Smrg if (old_res->base.b.target == PIPE_BUFFER) { 14347ec681f3Smrg struct pipe_box box = (struct pipe_box) { 14357ec681f3Smrg .width = old_res->base.b.width0, 14367ec681f3Smrg .height = 1, 14377ec681f3Smrg }; 14387ec681f3Smrg 14397ec681f3Smrg iris_copy_region(&ice->blorp, batch, &new_res->base.b, 0, 0, 0, 0, 14407ec681f3Smrg &old_res->base.b, 0, &box); 14417ec681f3Smrg } else { 14427ec681f3Smrg for (unsigned l = 0; l <= templ.last_level; l++) { 14437ec681f3Smrg struct pipe_box box = (struct pipe_box) { 14447ec681f3Smrg .width = u_minify(templ.width0, l), 14457ec681f3Smrg .height = u_minify(templ.height0, l), 14467ec681f3Smrg .depth = util_num_layers(&templ, l), 14477ec681f3Smrg }; 14487ec681f3Smrg 14497ec681f3Smrg iris_copy_region(&ice->blorp, batch, &new_res->base.b, l, 0, 0, 0, 14507ec681f3Smrg &old_res->base.b, l, &box); 14517ec681f3Smrg } 14527ec681f3Smrg } 14537ec681f3Smrg 14547ec681f3Smrg iris_flush_resource(&ice->ctx, &new_res->base.b); 14557ec681f3Smrg 14567ec681f3Smrg struct iris_bo *old_bo = old_res->bo; 14577ec681f3Smrg struct iris_bo *old_aux_bo = old_res->aux.bo; 14587ec681f3Smrg struct iris_bo *old_clear_color_bo = old_res->aux.clear_color_bo; 14597ec681f3Smrg 14607ec681f3Smrg /* Replace the structure fields with the new ones */ 14617ec681f3Smrg old_res->base.b.bind = templ.bind; 14627ec681f3Smrg old_res->bo = new_res->bo; 14637ec681f3Smrg old_res->aux.surf = new_res->aux.surf; 14647ec681f3Smrg old_res->aux.bo = new_res->aux.bo; 14657ec681f3Smrg old_res->aux.offset = new_res->aux.offset; 14667ec681f3Smrg old_res->aux.extra_aux.surf = new_res->aux.extra_aux.surf; 14677ec681f3Smrg old_res->aux.extra_aux.offset = new_res->aux.extra_aux.offset; 14687ec681f3Smrg old_res->aux.clear_color_bo = new_res->aux.clear_color_bo; 14697ec681f3Smrg old_res->aux.clear_color_offset = new_res->aux.clear_color_offset; 14707ec681f3Smrg old_res->aux.usage = new_res->aux.usage; 14717ec681f3Smrg old_res->aux.possible_usages = new_res->aux.possible_usages; 14727ec681f3Smrg old_res->aux.sampler_usages = new_res->aux.sampler_usages; 14737ec681f3Smrg 14747ec681f3Smrg if (new_res->aux.state) { 14757ec681f3Smrg assert(old_res->aux.state); 14767ec681f3Smrg for (unsigned l = 0; l <= templ.last_level; l++) { 14777ec681f3Smrg unsigned layers = util_num_layers(&templ, l); 14787ec681f3Smrg for (unsigned z = 0; z < layers; z++) { 14797ec681f3Smrg enum isl_aux_state aux = 14807ec681f3Smrg iris_resource_get_aux_state(new_res, l, z); 14817ec681f3Smrg iris_resource_set_aux_state(ice, old_res, l, z, 1, aux); 14827ec681f3Smrg } 14837ec681f3Smrg } 14847ec681f3Smrg } 14857ec681f3Smrg 14867ec681f3Smrg /* old_res now points at the new BOs, make new_res point at the old ones 14877ec681f3Smrg * so they'll be freed when we unreference the resource below. 14887ec681f3Smrg */ 14897ec681f3Smrg new_res->bo = old_bo; 14907ec681f3Smrg new_res->aux.bo = old_aux_bo; 14917ec681f3Smrg new_res->aux.clear_color_bo = old_clear_color_bo; 14927ec681f3Smrg 14937ec681f3Smrg pipe_resource_reference((struct pipe_resource **)&new_res, NULL); 14947ec681f3Smrg} 14957ec681f3Smrg 14967ec681f3Smrgstatic void 14977ec681f3Smrgiris_resource_disable_suballoc_on_first_query(struct pipe_screen *pscreen, 14987ec681f3Smrg struct pipe_context *ctx, 14997ec681f3Smrg struct iris_resource *res) 15007ec681f3Smrg{ 15017ec681f3Smrg if (iris_bo_is_real(res->bo)) 15027ec681f3Smrg return; 15037ec681f3Smrg 15047ec681f3Smrg assert(!(res->base.b.bind & PIPE_BIND_SHARED)); 15057ec681f3Smrg 15067ec681f3Smrg bool destroy_context; 15077ec681f3Smrg if (ctx) { 15087ec681f3Smrg ctx = threaded_context_unwrap_sync(ctx); 15097ec681f3Smrg destroy_context = false; 15107ec681f3Smrg } else { 15117ec681f3Smrg /* We need to execute a blit on some GPU context, but the DRI layer 15127ec681f3Smrg * often doesn't give us one. So we have to invent a temporary one. 15137ec681f3Smrg * 15147ec681f3Smrg * We can't store a permanent context in the screen, as it would cause 15157ec681f3Smrg * circular refcounting where screens reference contexts that reference 15167ec681f3Smrg * resources, while resources reference screens...causing nothing to be 15177ec681f3Smrg * freed. So we just create and destroy a temporary one here. 15187ec681f3Smrg */ 15197ec681f3Smrg ctx = iris_create_context(pscreen, NULL, 0); 15207ec681f3Smrg destroy_context = true; 15217ec681f3Smrg } 15227ec681f3Smrg 15237ec681f3Smrg struct iris_context *ice = (struct iris_context *)ctx; 15247ec681f3Smrg 15257ec681f3Smrg iris_reallocate_resource_inplace(ice, res, PIPE_BIND_SHARED); 15267ec681f3Smrg assert(res->base.b.bind & PIPE_BIND_SHARED); 15277ec681f3Smrg 15287ec681f3Smrg if (destroy_context) 15297ec681f3Smrg iris_destroy_context(ctx); 15307ec681f3Smrg} 15317ec681f3Smrg 15327ec681f3Smrg 15337ec681f3Smrgstatic void 15347ec681f3Smrgiris_resource_disable_aux_on_first_query(struct pipe_resource *resource, 15357ec681f3Smrg unsigned usage) 15367ec681f3Smrg{ 15377ec681f3Smrg struct iris_resource *res = (struct iris_resource *)resource; 15387ec681f3Smrg bool mod_with_aux = 15397ec681f3Smrg res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 15407ec681f3Smrg 15417ec681f3Smrg /* Disable aux usage if explicit flush not set and this is the first time 15427ec681f3Smrg * we are dealing with this resource and the resource was not created with 15437ec681f3Smrg * a modifier with aux. 15447ec681f3Smrg */ 15457ec681f3Smrg if (!mod_with_aux && 15467ec681f3Smrg (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH) && res->aux.usage != 0) && 15477ec681f3Smrg p_atomic_read(&resource->reference.count) == 1) { 15487ec681f3Smrg iris_resource_disable_aux(res); 15497ec681f3Smrg } 15509f464c52Smaya} 15519f464c52Smaya 15527ec681f3Smrgstatic bool 15537ec681f3Smrgiris_resource_get_param(struct pipe_screen *pscreen, 15547ec681f3Smrg struct pipe_context *ctx, 15557ec681f3Smrg struct pipe_resource *resource, 15567ec681f3Smrg unsigned plane, 15577ec681f3Smrg unsigned layer, 15587ec681f3Smrg unsigned level, 15597ec681f3Smrg enum pipe_resource_param param, 15607ec681f3Smrg unsigned handle_usage, 15617ec681f3Smrg uint64_t *value) 15627ec681f3Smrg{ 15637ec681f3Smrg struct iris_screen *screen = (struct iris_screen *)pscreen; 15647ec681f3Smrg struct iris_resource *res = (struct iris_resource *)resource; 15657ec681f3Smrg bool mod_with_aux = 15667ec681f3Smrg res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 15677ec681f3Smrg bool wants_aux = mod_with_aux && plane > 0; 15687ec681f3Smrg bool result; 15697ec681f3Smrg unsigned handle; 15707ec681f3Smrg 15717ec681f3Smrg iris_resource_disable_aux_on_first_query(resource, handle_usage); 15727ec681f3Smrg iris_resource_disable_suballoc_on_first_query(pscreen, ctx, res); 15737ec681f3Smrg 15747ec681f3Smrg struct iris_bo *bo = wants_aux ? res->aux.bo : res->bo; 15757ec681f3Smrg 15767ec681f3Smrg assert(iris_bo_is_real(bo)); 15777ec681f3Smrg 15787ec681f3Smrg switch (param) { 15797ec681f3Smrg case PIPE_RESOURCE_PARAM_NPLANES: 15807ec681f3Smrg if (mod_with_aux) { 15817ec681f3Smrg *value = iris_get_dmabuf_modifier_planes(pscreen, 15827ec681f3Smrg res->mod_info->modifier, 15837ec681f3Smrg res->external_format); 15847ec681f3Smrg } else { 15857ec681f3Smrg *value = get_num_planes(&res->base.b); 15867ec681f3Smrg } 15877ec681f3Smrg return true; 15887ec681f3Smrg case PIPE_RESOURCE_PARAM_STRIDE: 15897ec681f3Smrg *value = wants_aux ? res->aux.surf.row_pitch_B : res->surf.row_pitch_B; 15907ec681f3Smrg return true; 15917ec681f3Smrg case PIPE_RESOURCE_PARAM_OFFSET: 15927ec681f3Smrg *value = wants_aux ? 15937ec681f3Smrg mod_plane_is_clear_color(res->mod_info->modifier, plane) ? 15947ec681f3Smrg res->aux.clear_color_offset : res->aux.offset : 0; 15957ec681f3Smrg return true; 15967ec681f3Smrg case PIPE_RESOURCE_PARAM_MODIFIER: 15977ec681f3Smrg *value = res->mod_info ? res->mod_info->modifier : 15987ec681f3Smrg tiling_to_modifier(isl_tiling_to_i915_tiling(res->surf.tiling)); 15997ec681f3Smrg return true; 16007ec681f3Smrg case PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED: 16017ec681f3Smrg if (!wants_aux) 16027ec681f3Smrg iris_gem_set_tiling(bo, &res->surf); 16037ec681f3Smrg 16047ec681f3Smrg result = iris_bo_flink(bo, &handle) == 0; 16057ec681f3Smrg if (result) 16067ec681f3Smrg *value = handle; 16077ec681f3Smrg return result; 16087ec681f3Smrg case PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS: { 16097ec681f3Smrg if (!wants_aux) 16107ec681f3Smrg iris_gem_set_tiling(bo, &res->surf); 16117ec681f3Smrg 16127ec681f3Smrg /* Because we share the same drm file across multiple iris_screen, when 16137ec681f3Smrg * we export a GEM handle we must make sure it is valid in the DRM file 16147ec681f3Smrg * descriptor the caller is using (this is the FD given at screen 16157ec681f3Smrg * creation). 16167ec681f3Smrg */ 16177ec681f3Smrg uint32_t handle; 16187ec681f3Smrg if (iris_bo_export_gem_handle_for_device(bo, screen->winsys_fd, &handle)) 16197ec681f3Smrg return false; 16207ec681f3Smrg *value = handle; 16217ec681f3Smrg return true; 16227ec681f3Smrg } 16237ec681f3Smrg 16247ec681f3Smrg case PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD: 16257ec681f3Smrg if (!wants_aux) 16267ec681f3Smrg iris_gem_set_tiling(bo, &res->surf); 16277ec681f3Smrg 16287ec681f3Smrg result = iris_bo_export_dmabuf(bo, (int *) &handle) == 0; 16297ec681f3Smrg if (result) 16307ec681f3Smrg *value = handle; 16317ec681f3Smrg return result; 16327ec681f3Smrg default: 16337ec681f3Smrg return false; 16347ec681f3Smrg } 16357ec681f3Smrg} 16367ec681f3Smrg 16377ec681f3Smrgstatic bool 16389f464c52Smayairis_resource_get_handle(struct pipe_screen *pscreen, 16399f464c52Smaya struct pipe_context *ctx, 16409f464c52Smaya struct pipe_resource *resource, 16419f464c52Smaya struct winsys_handle *whandle, 16429f464c52Smaya unsigned usage) 16439f464c52Smaya{ 16447ec681f3Smrg struct iris_screen *screen = (struct iris_screen *) pscreen; 16459f464c52Smaya struct iris_resource *res = (struct iris_resource *)resource; 16467ec681f3Smrg bool mod_with_aux = 16477ec681f3Smrg res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 16487ec681f3Smrg 16497ec681f3Smrg iris_resource_disable_aux_on_first_query(resource, usage); 16507ec681f3Smrg iris_resource_disable_suballoc_on_first_query(pscreen, ctx, res); 16517ec681f3Smrg 16527ec681f3Smrg assert(iris_bo_is_real(res->bo)); 16537ec681f3Smrg 16547ec681f3Smrg struct iris_bo *bo; 16557ec681f3Smrg if (res->mod_info && 16567ec681f3Smrg mod_plane_is_clear_color(res->mod_info->modifier, whandle->plane)) { 16577ec681f3Smrg bo = res->aux.clear_color_bo; 16587ec681f3Smrg whandle->offset = res->aux.clear_color_offset; 16597ec681f3Smrg } else if (mod_with_aux && whandle->plane > 0) { 16607ec681f3Smrg bo = res->aux.bo; 16617ec681f3Smrg whandle->stride = res->aux.surf.row_pitch_B; 16627ec681f3Smrg whandle->offset = res->aux.offset; 16637ec681f3Smrg } else { 16647ec681f3Smrg /* If this is a buffer, stride should be 0 - no need to special case */ 16657ec681f3Smrg whandle->stride = res->surf.row_pitch_B; 16667ec681f3Smrg bo = res->bo; 16679f464c52Smaya } 16689f464c52Smaya 16697ec681f3Smrg whandle->format = res->external_format; 16709f464c52Smaya whandle->modifier = 16719f464c52Smaya res->mod_info ? res->mod_info->modifier 16727ec681f3Smrg : tiling_to_modifier(isl_tiling_to_i915_tiling(res->surf.tiling)); 16739f464c52Smaya 16749f464c52Smaya#ifndef NDEBUG 16759f464c52Smaya enum isl_aux_usage allowed_usage = 16767ec681f3Smrg usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH ? res->aux.usage : 16779f464c52Smaya res->mod_info ? res->mod_info->aux_usage : ISL_AUX_USAGE_NONE; 16789f464c52Smaya 16799f464c52Smaya if (res->aux.usage != allowed_usage) { 16809f464c52Smaya enum isl_aux_state aux_state = iris_resource_get_aux_state(res, 0, 0); 16819f464c52Smaya assert(aux_state == ISL_AUX_STATE_RESOLVED || 16829f464c52Smaya aux_state == ISL_AUX_STATE_PASS_THROUGH); 16839f464c52Smaya } 16849f464c52Smaya#endif 16859f464c52Smaya 16869f464c52Smaya switch (whandle->type) { 16879f464c52Smaya case WINSYS_HANDLE_TYPE_SHARED: 16887ec681f3Smrg iris_gem_set_tiling(bo, &res->surf); 16897ec681f3Smrg return iris_bo_flink(bo, &whandle->handle) == 0; 16907ec681f3Smrg case WINSYS_HANDLE_TYPE_KMS: { 16917ec681f3Smrg iris_gem_set_tiling(bo, &res->surf); 16927ec681f3Smrg 16937ec681f3Smrg /* Because we share the same drm file across multiple iris_screen, when 16947ec681f3Smrg * we export a GEM handle we must make sure it is valid in the DRM file 16957ec681f3Smrg * descriptor the caller is using (this is the FD given at screen 16967ec681f3Smrg * creation). 16977ec681f3Smrg */ 16987ec681f3Smrg uint32_t handle; 16997ec681f3Smrg if (iris_bo_export_gem_handle_for_device(bo, screen->winsys_fd, &handle)) 17007ec681f3Smrg return false; 17017ec681f3Smrg whandle->handle = handle; 17029f464c52Smaya return true; 17037ec681f3Smrg } 17049f464c52Smaya case WINSYS_HANDLE_TYPE_FD: 17057ec681f3Smrg iris_gem_set_tiling(bo, &res->surf); 17067ec681f3Smrg return iris_bo_export_dmabuf(bo, (int *) &whandle->handle) == 0; 17079f464c52Smaya } 17089f464c52Smaya 17099f464c52Smaya return false; 17109f464c52Smaya} 17119f464c52Smaya 17129f464c52Smayastatic bool 17139f464c52Smayaresource_is_busy(struct iris_context *ice, 17149f464c52Smaya struct iris_resource *res) 17159f464c52Smaya{ 17169f464c52Smaya bool busy = iris_bo_busy(res->bo); 17179f464c52Smaya 17189f464c52Smaya for (int i = 0; i < IRIS_BATCH_COUNT; i++) 17199f464c52Smaya busy |= iris_batch_references(&ice->batches[i], res->bo); 17209f464c52Smaya 17219f464c52Smaya return busy; 17229f464c52Smaya} 17239f464c52Smaya 17247ec681f3Smrgvoid 17257ec681f3Smrgiris_replace_buffer_storage(struct pipe_context *ctx, 17267ec681f3Smrg struct pipe_resource *p_dst, 17277ec681f3Smrg struct pipe_resource *p_src, 17287ec681f3Smrg unsigned num_rebinds, 17297ec681f3Smrg uint32_t rebind_mask, 17307ec681f3Smrg uint32_t delete_buffer_id) 17317ec681f3Smrg{ 17327ec681f3Smrg struct iris_screen *screen = (void *) ctx->screen; 17337ec681f3Smrg struct iris_context *ice = (void *) ctx; 17347ec681f3Smrg struct iris_resource *dst = (void *) p_dst; 17357ec681f3Smrg struct iris_resource *src = (void *) p_src; 17367ec681f3Smrg 17377ec681f3Smrg assert(memcmp(&dst->surf, &src->surf, sizeof(dst->surf)) == 0); 17387ec681f3Smrg 17397ec681f3Smrg struct iris_bo *old_bo = dst->bo; 17407ec681f3Smrg 17417ec681f3Smrg /* Swap out the backing storage */ 17427ec681f3Smrg iris_bo_reference(src->bo); 17437ec681f3Smrg dst->bo = src->bo; 17447ec681f3Smrg 17457ec681f3Smrg /* Rebind the buffer, replacing any state referring to the old BO's 17467ec681f3Smrg * address, and marking state dirty so it's reemitted. 17477ec681f3Smrg */ 17487ec681f3Smrg screen->vtbl.rebind_buffer(ice, dst); 17497ec681f3Smrg 17507ec681f3Smrg iris_bo_unreference(old_bo); 17517ec681f3Smrg} 17527ec681f3Smrg 17539f464c52Smayastatic void 17549f464c52Smayairis_invalidate_resource(struct pipe_context *ctx, 17559f464c52Smaya struct pipe_resource *resource) 17569f464c52Smaya{ 17579f464c52Smaya struct iris_screen *screen = (void *) ctx->screen; 17589f464c52Smaya struct iris_context *ice = (void *) ctx; 17599f464c52Smaya struct iris_resource *res = (void *) resource; 17609f464c52Smaya 17619f464c52Smaya if (resource->target != PIPE_BUFFER) 17629f464c52Smaya return; 17639f464c52Smaya 17647ec681f3Smrg /* If it's already invalidated, don't bother doing anything. */ 17657ec681f3Smrg if (res->valid_buffer_range.start > res->valid_buffer_range.end) 17667ec681f3Smrg return; 17677ec681f3Smrg 17689f464c52Smaya if (!resource_is_busy(ice, res)) { 17699f464c52Smaya /* The resource is idle, so just mark that it contains no data and 17709f464c52Smaya * keep using the same underlying buffer object. 17719f464c52Smaya */ 17729f464c52Smaya util_range_set_empty(&res->valid_buffer_range); 17739f464c52Smaya return; 17749f464c52Smaya } 17759f464c52Smaya 17769f464c52Smaya /* Otherwise, try and replace the backing storage with a new BO. */ 17779f464c52Smaya 17789f464c52Smaya /* We can't reallocate memory we didn't allocate in the first place. */ 17797ec681f3Smrg if (res->bo->gem_handle && res->bo->real.userptr) 17809f464c52Smaya return; 17819f464c52Smaya 17829f464c52Smaya struct iris_bo *old_bo = res->bo; 17839f464c52Smaya struct iris_bo *new_bo = 17847ec681f3Smrg iris_bo_alloc(screen->bufmgr, res->bo->name, resource->width0, 1, 17857ec681f3Smrg iris_memzone_for_address(old_bo->address), 0); 17869f464c52Smaya if (!new_bo) 17879f464c52Smaya return; 17889f464c52Smaya 17899f464c52Smaya /* Swap out the backing storage */ 17909f464c52Smaya res->bo = new_bo; 17919f464c52Smaya 17929f464c52Smaya /* Rebind the buffer, replacing any state referring to the old BO's 17939f464c52Smaya * address, and marking state dirty so it's reemitted. 17949f464c52Smaya */ 17957ec681f3Smrg screen->vtbl.rebind_buffer(ice, res); 17969f464c52Smaya 17979f464c52Smaya util_range_set_empty(&res->valid_buffer_range); 17989f464c52Smaya 17999f464c52Smaya iris_bo_unreference(old_bo); 18009f464c52Smaya} 18019f464c52Smaya 18029f464c52Smayastatic void 18039f464c52Smayairis_flush_staging_region(struct pipe_transfer *xfer, 18049f464c52Smaya const struct pipe_box *flush_box) 18059f464c52Smaya{ 18067ec681f3Smrg if (!(xfer->usage & PIPE_MAP_WRITE)) 18079f464c52Smaya return; 18089f464c52Smaya 18099f464c52Smaya struct iris_transfer *map = (void *) xfer; 18109f464c52Smaya 18119f464c52Smaya struct pipe_box src_box = *flush_box; 18129f464c52Smaya 18139f464c52Smaya /* Account for extra alignment padding in staging buffer */ 18149f464c52Smaya if (xfer->resource->target == PIPE_BUFFER) 18159f464c52Smaya src_box.x += xfer->box.x % IRIS_MAP_BUFFER_ALIGNMENT; 18169f464c52Smaya 18179f464c52Smaya struct pipe_box dst_box = (struct pipe_box) { 18189f464c52Smaya .x = xfer->box.x + flush_box->x, 18199f464c52Smaya .y = xfer->box.y + flush_box->y, 18209f464c52Smaya .z = xfer->box.z + flush_box->z, 18219f464c52Smaya .width = flush_box->width, 18229f464c52Smaya .height = flush_box->height, 18239f464c52Smaya .depth = flush_box->depth, 18249f464c52Smaya }; 18259f464c52Smaya 18269f464c52Smaya iris_copy_region(map->blorp, map->batch, xfer->resource, xfer->level, 18279f464c52Smaya dst_box.x, dst_box.y, dst_box.z, map->staging, 0, 18289f464c52Smaya &src_box); 18299f464c52Smaya} 18309f464c52Smaya 18319f464c52Smayastatic void 18329f464c52Smayairis_unmap_copy_region(struct iris_transfer *map) 18339f464c52Smaya{ 18349f464c52Smaya iris_resource_destroy(map->staging->screen, map->staging); 18359f464c52Smaya 18369f464c52Smaya map->ptr = NULL; 18379f464c52Smaya} 18389f464c52Smaya 18399f464c52Smayastatic void 18409f464c52Smayairis_map_copy_region(struct iris_transfer *map) 18419f464c52Smaya{ 18429f464c52Smaya struct pipe_screen *pscreen = &map->batch->screen->base; 18437ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 18449f464c52Smaya struct pipe_box *box = &xfer->box; 18459f464c52Smaya struct iris_resource *res = (void *) xfer->resource; 18469f464c52Smaya 18479f464c52Smaya unsigned extra = xfer->resource->target == PIPE_BUFFER ? 18489f464c52Smaya box->x % IRIS_MAP_BUFFER_ALIGNMENT : 0; 18499f464c52Smaya 18509f464c52Smaya struct pipe_resource templ = (struct pipe_resource) { 18519f464c52Smaya .usage = PIPE_USAGE_STAGING, 18529f464c52Smaya .width0 = box->width + extra, 18539f464c52Smaya .height0 = box->height, 18549f464c52Smaya .depth0 = 1, 18559f464c52Smaya .nr_samples = xfer->resource->nr_samples, 18569f464c52Smaya .nr_storage_samples = xfer->resource->nr_storage_samples, 18579f464c52Smaya .array_size = box->depth, 18589f464c52Smaya .format = res->internal_format, 18599f464c52Smaya }; 18609f464c52Smaya 18619f464c52Smaya if (xfer->resource->target == PIPE_BUFFER) 18629f464c52Smaya templ.target = PIPE_BUFFER; 18639f464c52Smaya else if (templ.array_size > 1) 18649f464c52Smaya templ.target = PIPE_TEXTURE_2D_ARRAY; 18659f464c52Smaya else 18669f464c52Smaya templ.target = PIPE_TEXTURE_2D; 18679f464c52Smaya 18689f464c52Smaya map->staging = iris_resource_create(pscreen, &templ); 18699f464c52Smaya assert(map->staging); 18709f464c52Smaya 18719f464c52Smaya if (templ.target != PIPE_BUFFER) { 18729f464c52Smaya struct isl_surf *surf = &((struct iris_resource *) map->staging)->surf; 18739f464c52Smaya xfer->stride = isl_surf_get_row_pitch_B(surf); 18749f464c52Smaya xfer->layer_stride = isl_surf_get_array_pitch(surf); 18759f464c52Smaya } 18769f464c52Smaya 18777ec681f3Smrg if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 18789f464c52Smaya iris_copy_region(map->blorp, map->batch, map->staging, 0, extra, 0, 0, 18799f464c52Smaya xfer->resource, xfer->level, box); 18809f464c52Smaya /* Ensure writes to the staging BO land before we map it below. */ 18819f464c52Smaya iris_emit_pipe_control_flush(map->batch, 18827ec681f3Smrg "transfer read: flush before mapping", 18839f464c52Smaya PIPE_CONTROL_RENDER_TARGET_FLUSH | 18847ec681f3Smrg PIPE_CONTROL_TILE_CACHE_FLUSH | 18859f464c52Smaya PIPE_CONTROL_CS_STALL); 18869f464c52Smaya } 18879f464c52Smaya 18889f464c52Smaya struct iris_bo *staging_bo = iris_resource_bo(map->staging); 18899f464c52Smaya 18909f464c52Smaya if (iris_batch_references(map->batch, staging_bo)) 18919f464c52Smaya iris_batch_flush(map->batch); 18929f464c52Smaya 18939f464c52Smaya map->ptr = 18949f464c52Smaya iris_bo_map(map->dbg, staging_bo, xfer->usage & MAP_FLAGS) + extra; 18959f464c52Smaya 18969f464c52Smaya map->unmap = iris_unmap_copy_region; 18979f464c52Smaya} 18989f464c52Smaya 18999f464c52Smayastatic void 19009f464c52Smayaget_image_offset_el(const struct isl_surf *surf, unsigned level, unsigned z, 19019f464c52Smaya unsigned *out_x0_el, unsigned *out_y0_el) 19029f464c52Smaya{ 19037ec681f3Smrg ASSERTED uint32_t z0_el, a0_el; 19049f464c52Smaya if (surf->dim == ISL_SURF_DIM_3D) { 19057ec681f3Smrg isl_surf_get_image_offset_el(surf, level, 0, z, 19067ec681f3Smrg out_x0_el, out_y0_el, &z0_el, &a0_el); 19079f464c52Smaya } else { 19087ec681f3Smrg isl_surf_get_image_offset_el(surf, level, z, 0, 19097ec681f3Smrg out_x0_el, out_y0_el, &z0_el, &a0_el); 19109f464c52Smaya } 19117ec681f3Smrg assert(z0_el == 0 && a0_el == 0); 19129f464c52Smaya} 19139f464c52Smaya 19149f464c52Smaya/** 19159f464c52Smaya * Get pointer offset into stencil buffer. 19169f464c52Smaya * 19179f464c52Smaya * The stencil buffer is W tiled. Since the GTT is incapable of W fencing, we 19189f464c52Smaya * must decode the tile's layout in software. 19199f464c52Smaya * 19209f464c52Smaya * See 19219f464c52Smaya * - PRM, 2011 Sandy Bridge, Volume 1, Part 2, Section 4.5.2.1 W-Major Tile 19229f464c52Smaya * Format. 19239f464c52Smaya * - PRM, 2011 Sandy Bridge, Volume 1, Part 2, Section 4.5.3 Tiling Algorithm 19249f464c52Smaya * 19259f464c52Smaya * Even though the returned offset is always positive, the return type is 19269f464c52Smaya * signed due to 19279f464c52Smaya * commit e8b1c6d6f55f5be3bef25084fdd8b6127517e137 19289f464c52Smaya * mesa: Fix return type of _mesa_get_format_bytes() (#37351) 19299f464c52Smaya */ 19309f464c52Smayastatic intptr_t 19317ec681f3Smrgs8_offset(uint32_t stride, uint32_t x, uint32_t y) 19329f464c52Smaya{ 19339f464c52Smaya uint32_t tile_size = 4096; 19349f464c52Smaya uint32_t tile_width = 64; 19359f464c52Smaya uint32_t tile_height = 64; 19369f464c52Smaya uint32_t row_size = 64 * stride / 2; /* Two rows are interleaved. */ 19379f464c52Smaya 19389f464c52Smaya uint32_t tile_x = x / tile_width; 19399f464c52Smaya uint32_t tile_y = y / tile_height; 19409f464c52Smaya 19419f464c52Smaya /* The byte's address relative to the tile's base addres. */ 19429f464c52Smaya uint32_t byte_x = x % tile_width; 19439f464c52Smaya uint32_t byte_y = y % tile_height; 19449f464c52Smaya 19459f464c52Smaya uintptr_t u = tile_y * row_size 19469f464c52Smaya + tile_x * tile_size 19479f464c52Smaya + 512 * (byte_x / 8) 19489f464c52Smaya + 64 * (byte_y / 8) 19499f464c52Smaya + 32 * ((byte_y / 4) % 2) 19509f464c52Smaya + 16 * ((byte_x / 4) % 2) 19519f464c52Smaya + 8 * ((byte_y / 2) % 2) 19529f464c52Smaya + 4 * ((byte_x / 2) % 2) 19539f464c52Smaya + 2 * (byte_y % 2) 19549f464c52Smaya + 1 * (byte_x % 2); 19559f464c52Smaya 19569f464c52Smaya return u; 19579f464c52Smaya} 19589f464c52Smaya 19599f464c52Smayastatic void 19609f464c52Smayairis_unmap_s8(struct iris_transfer *map) 19619f464c52Smaya{ 19627ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 19639f464c52Smaya const struct pipe_box *box = &xfer->box; 19649f464c52Smaya struct iris_resource *res = (struct iris_resource *) xfer->resource; 19659f464c52Smaya struct isl_surf *surf = &res->surf; 19669f464c52Smaya 19677ec681f3Smrg if (xfer->usage & PIPE_MAP_WRITE) { 19689f464c52Smaya uint8_t *untiled_s8_map = map->ptr; 19699f464c52Smaya uint8_t *tiled_s8_map = 19709f464c52Smaya iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 19719f464c52Smaya 19729f464c52Smaya for (int s = 0; s < box->depth; s++) { 19739f464c52Smaya unsigned x0_el, y0_el; 19749f464c52Smaya get_image_offset_el(surf, xfer->level, box->z + s, &x0_el, &y0_el); 19759f464c52Smaya 19769f464c52Smaya for (uint32_t y = 0; y < box->height; y++) { 19779f464c52Smaya for (uint32_t x = 0; x < box->width; x++) { 19789f464c52Smaya ptrdiff_t offset = s8_offset(surf->row_pitch_B, 19799f464c52Smaya x0_el + box->x + x, 19807ec681f3Smrg y0_el + box->y + y); 19819f464c52Smaya tiled_s8_map[offset] = 19829f464c52Smaya untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x]; 19839f464c52Smaya } 19849f464c52Smaya } 19859f464c52Smaya } 19869f464c52Smaya } 19879f464c52Smaya 19889f464c52Smaya free(map->buffer); 19899f464c52Smaya} 19909f464c52Smaya 19919f464c52Smayastatic void 19929f464c52Smayairis_map_s8(struct iris_transfer *map) 19939f464c52Smaya{ 19947ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 19959f464c52Smaya const struct pipe_box *box = &xfer->box; 19969f464c52Smaya struct iris_resource *res = (struct iris_resource *) xfer->resource; 19979f464c52Smaya struct isl_surf *surf = &res->surf; 19989f464c52Smaya 19999f464c52Smaya xfer->stride = surf->row_pitch_B; 20009f464c52Smaya xfer->layer_stride = xfer->stride * box->height; 20019f464c52Smaya 20029f464c52Smaya /* The tiling and detiling functions require that the linear buffer has 20039f464c52Smaya * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we 20049f464c52Smaya * over-allocate the linear buffer to get the proper alignment. 20059f464c52Smaya */ 20069f464c52Smaya map->buffer = map->ptr = malloc(xfer->layer_stride * box->depth); 20079f464c52Smaya assert(map->buffer); 20089f464c52Smaya 20099f464c52Smaya /* One of either READ_BIT or WRITE_BIT or both is set. READ_BIT implies no 20109f464c52Smaya * INVALIDATE_RANGE_BIT. WRITE_BIT needs the original values read in unless 20119f464c52Smaya * invalidate is set, since we'll be writing the whole rectangle from our 20129f464c52Smaya * temporary buffer back out. 20139f464c52Smaya */ 20147ec681f3Smrg if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 20159f464c52Smaya uint8_t *untiled_s8_map = map->ptr; 20169f464c52Smaya uint8_t *tiled_s8_map = 20179f464c52Smaya iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 20189f464c52Smaya 20199f464c52Smaya for (int s = 0; s < box->depth; s++) { 20209f464c52Smaya unsigned x0_el, y0_el; 20219f464c52Smaya get_image_offset_el(surf, xfer->level, box->z + s, &x0_el, &y0_el); 20229f464c52Smaya 20239f464c52Smaya for (uint32_t y = 0; y < box->height; y++) { 20249f464c52Smaya for (uint32_t x = 0; x < box->width; x++) { 20259f464c52Smaya ptrdiff_t offset = s8_offset(surf->row_pitch_B, 20269f464c52Smaya x0_el + box->x + x, 20277ec681f3Smrg y0_el + box->y + y); 20289f464c52Smaya untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x] = 20299f464c52Smaya tiled_s8_map[offset]; 20309f464c52Smaya } 20319f464c52Smaya } 20329f464c52Smaya } 20339f464c52Smaya } 20349f464c52Smaya 20359f464c52Smaya map->unmap = iris_unmap_s8; 20369f464c52Smaya} 20379f464c52Smaya 20389f464c52Smaya/* Compute extent parameters for use with tiled_memcpy functions. 20399f464c52Smaya * xs are in units of bytes and ys are in units of strides. 20409f464c52Smaya */ 20419f464c52Smayastatic inline void 20429f464c52Smayatile_extents(const struct isl_surf *surf, 20439f464c52Smaya const struct pipe_box *box, 20449f464c52Smaya unsigned level, int z, 20459f464c52Smaya unsigned *x1_B, unsigned *x2_B, 20469f464c52Smaya unsigned *y1_el, unsigned *y2_el) 20479f464c52Smaya{ 20489f464c52Smaya const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format); 20499f464c52Smaya const unsigned cpp = fmtl->bpb / 8; 20509f464c52Smaya 20519f464c52Smaya assert(box->x % fmtl->bw == 0); 20529f464c52Smaya assert(box->y % fmtl->bh == 0); 20539f464c52Smaya 20549f464c52Smaya unsigned x0_el, y0_el; 20559f464c52Smaya get_image_offset_el(surf, level, box->z + z, &x0_el, &y0_el); 20569f464c52Smaya 20579f464c52Smaya *x1_B = (box->x / fmtl->bw + x0_el) * cpp; 20589f464c52Smaya *y1_el = box->y / fmtl->bh + y0_el; 20599f464c52Smaya *x2_B = (DIV_ROUND_UP(box->x + box->width, fmtl->bw) + x0_el) * cpp; 20609f464c52Smaya *y2_el = DIV_ROUND_UP(box->y + box->height, fmtl->bh) + y0_el; 20619f464c52Smaya} 20629f464c52Smaya 20639f464c52Smayastatic void 20649f464c52Smayairis_unmap_tiled_memcpy(struct iris_transfer *map) 20659f464c52Smaya{ 20667ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 20679f464c52Smaya const struct pipe_box *box = &xfer->box; 20689f464c52Smaya struct iris_resource *res = (struct iris_resource *) xfer->resource; 20699f464c52Smaya struct isl_surf *surf = &res->surf; 20709f464c52Smaya 20719f464c52Smaya const bool has_swizzling = false; 20729f464c52Smaya 20737ec681f3Smrg if (xfer->usage & PIPE_MAP_WRITE) { 20749f464c52Smaya char *dst = 20759f464c52Smaya iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 20769f464c52Smaya 20779f464c52Smaya for (int s = 0; s < box->depth; s++) { 20789f464c52Smaya unsigned x1, x2, y1, y2; 20799f464c52Smaya tile_extents(surf, box, xfer->level, s, &x1, &x2, &y1, &y2); 20809f464c52Smaya 20819f464c52Smaya void *ptr = map->ptr + s * xfer->layer_stride; 20829f464c52Smaya 20839f464c52Smaya isl_memcpy_linear_to_tiled(x1, x2, y1, y2, dst, ptr, 20849f464c52Smaya surf->row_pitch_B, xfer->stride, 20859f464c52Smaya has_swizzling, surf->tiling, ISL_MEMCPY); 20869f464c52Smaya } 20879f464c52Smaya } 20889f464c52Smaya os_free_aligned(map->buffer); 20899f464c52Smaya map->buffer = map->ptr = NULL; 20909f464c52Smaya} 20919f464c52Smaya 20929f464c52Smayastatic void 20939f464c52Smayairis_map_tiled_memcpy(struct iris_transfer *map) 20949f464c52Smaya{ 20957ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 20969f464c52Smaya const struct pipe_box *box = &xfer->box; 20979f464c52Smaya struct iris_resource *res = (struct iris_resource *) xfer->resource; 20989f464c52Smaya struct isl_surf *surf = &res->surf; 20999f464c52Smaya 21009f464c52Smaya xfer->stride = ALIGN(surf->row_pitch_B, 16); 21019f464c52Smaya xfer->layer_stride = xfer->stride * box->height; 21029f464c52Smaya 21039f464c52Smaya unsigned x1, x2, y1, y2; 21049f464c52Smaya tile_extents(surf, box, xfer->level, 0, &x1, &x2, &y1, &y2); 21059f464c52Smaya 21069f464c52Smaya /* The tiling and detiling functions require that the linear buffer has 21079f464c52Smaya * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we 21089f464c52Smaya * over-allocate the linear buffer to get the proper alignment. 21099f464c52Smaya */ 21109f464c52Smaya map->buffer = 21119f464c52Smaya os_malloc_aligned(xfer->layer_stride * box->depth, 16); 21129f464c52Smaya assert(map->buffer); 21139f464c52Smaya map->ptr = (char *)map->buffer + (x1 & 0xf); 21149f464c52Smaya 21159f464c52Smaya const bool has_swizzling = false; 21169f464c52Smaya 21177ec681f3Smrg if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 21189f464c52Smaya char *src = 21199f464c52Smaya iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 21209f464c52Smaya 21219f464c52Smaya for (int s = 0; s < box->depth; s++) { 21229f464c52Smaya unsigned x1, x2, y1, y2; 21239f464c52Smaya tile_extents(surf, box, xfer->level, s, &x1, &x2, &y1, &y2); 21249f464c52Smaya 21259f464c52Smaya /* Use 's' rather than 'box->z' to rebase the first slice to 0. */ 21269f464c52Smaya void *ptr = map->ptr + s * xfer->layer_stride; 21279f464c52Smaya 21289f464c52Smaya isl_memcpy_tiled_to_linear(x1, x2, y1, y2, ptr, src, xfer->stride, 21299f464c52Smaya surf->row_pitch_B, has_swizzling, 21309f464c52Smaya surf->tiling, ISL_MEMCPY_STREAMING_LOAD); 21319f464c52Smaya } 21329f464c52Smaya } 21339f464c52Smaya 21349f464c52Smaya map->unmap = iris_unmap_tiled_memcpy; 21359f464c52Smaya} 21369f464c52Smaya 21379f464c52Smayastatic void 21389f464c52Smayairis_map_direct(struct iris_transfer *map) 21399f464c52Smaya{ 21407ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 21419f464c52Smaya struct pipe_box *box = &xfer->box; 21429f464c52Smaya struct iris_resource *res = (struct iris_resource *) xfer->resource; 21439f464c52Smaya 21449f464c52Smaya void *ptr = iris_bo_map(map->dbg, res->bo, xfer->usage & MAP_FLAGS); 21459f464c52Smaya 21467ec681f3Smrg if (res->base.b.target == PIPE_BUFFER) { 21479f464c52Smaya xfer->stride = 0; 21489f464c52Smaya xfer->layer_stride = 0; 21499f464c52Smaya 21509f464c52Smaya map->ptr = ptr + box->x; 21519f464c52Smaya } else { 21529f464c52Smaya struct isl_surf *surf = &res->surf; 21539f464c52Smaya const struct isl_format_layout *fmtl = 21549f464c52Smaya isl_format_get_layout(surf->format); 21559f464c52Smaya const unsigned cpp = fmtl->bpb / 8; 21569f464c52Smaya unsigned x0_el, y0_el; 21579f464c52Smaya 21589f464c52Smaya get_image_offset_el(surf, xfer->level, box->z, &x0_el, &y0_el); 21599f464c52Smaya 21609f464c52Smaya xfer->stride = isl_surf_get_row_pitch_B(surf); 21619f464c52Smaya xfer->layer_stride = isl_surf_get_array_pitch(surf); 21629f464c52Smaya 21639f464c52Smaya map->ptr = ptr + (y0_el + box->y) * xfer->stride + (x0_el + box->x) * cpp; 21649f464c52Smaya } 21659f464c52Smaya} 21669f464c52Smaya 21679f464c52Smayastatic bool 21689f464c52Smayacan_promote_to_async(const struct iris_resource *res, 21699f464c52Smaya const struct pipe_box *box, 21707ec681f3Smrg enum pipe_map_flags usage) 21719f464c52Smaya{ 21729f464c52Smaya /* If we're writing to a section of the buffer that hasn't even been 21739f464c52Smaya * initialized with useful data, then we can safely promote this write 21749f464c52Smaya * to be unsynchronized. This helps the common pattern of appending data. 21759f464c52Smaya */ 21767ec681f3Smrg return res->base.b.target == PIPE_BUFFER && (usage & PIPE_MAP_WRITE) && 21779f464c52Smaya !(usage & TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED) && 21789f464c52Smaya !util_ranges_intersect(&res->valid_buffer_range, box->x, 21799f464c52Smaya box->x + box->width); 21809f464c52Smaya} 21819f464c52Smaya 21829f464c52Smayastatic void * 21839f464c52Smayairis_transfer_map(struct pipe_context *ctx, 21849f464c52Smaya struct pipe_resource *resource, 21859f464c52Smaya unsigned level, 21867ec681f3Smrg enum pipe_map_flags usage, 21879f464c52Smaya const struct pipe_box *box, 21889f464c52Smaya struct pipe_transfer **ptransfer) 21899f464c52Smaya{ 21909f464c52Smaya struct iris_context *ice = (struct iris_context *)ctx; 21919f464c52Smaya struct iris_resource *res = (struct iris_resource *)resource; 21929f464c52Smaya struct isl_surf *surf = &res->surf; 21939f464c52Smaya 21947ec681f3Smrg if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) { 21959f464c52Smaya /* Replace the backing storage with a fresh buffer for non-async maps */ 21967ec681f3Smrg if (!(usage & (PIPE_MAP_UNSYNCHRONIZED | 21979f464c52Smaya TC_TRANSFER_MAP_NO_INVALIDATE))) 21989f464c52Smaya iris_invalidate_resource(ctx, resource); 21999f464c52Smaya 22009f464c52Smaya /* If we can discard the whole resource, we can discard the range. */ 22017ec681f3Smrg usage |= PIPE_MAP_DISCARD_RANGE; 22029f464c52Smaya } 22039f464c52Smaya 22047ec681f3Smrg if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && 22059f464c52Smaya can_promote_to_async(res, box, usage)) { 22067ec681f3Smrg usage |= PIPE_MAP_UNSYNCHRONIZED; 22079f464c52Smaya } 22089f464c52Smaya 22097ec681f3Smrg /* Avoid using GPU copies for persistent/coherent buffers, as the idea 22107ec681f3Smrg * there is to access them simultaneously on the CPU & GPU. This also 22117ec681f3Smrg * avoids trying to use GPU copies for our u_upload_mgr buffers which 22127ec681f3Smrg * contain state we're constructing for a GPU draw call, which would 22137ec681f3Smrg * kill us with infinite stack recursion. 22147ec681f3Smrg */ 22157ec681f3Smrg if (usage & (PIPE_MAP_PERSISTENT | PIPE_MAP_COHERENT)) 22167ec681f3Smrg usage |= PIPE_MAP_DIRECTLY; 22177ec681f3Smrg 22187ec681f3Smrg /* We cannot provide a direct mapping of tiled resources, and we 22197ec681f3Smrg * may not be able to mmap imported BOs since they may come from 22207ec681f3Smrg * other devices that I915_GEM_MMAP cannot work with. 22217ec681f3Smrg */ 22227ec681f3Smrg if ((usage & PIPE_MAP_DIRECTLY) && 22237ec681f3Smrg (surf->tiling != ISL_TILING_LINEAR || iris_bo_is_imported(res->bo))) 22247ec681f3Smrg return NULL; 22257ec681f3Smrg 22267ec681f3Smrg bool map_would_stall = false; 22277ec681f3Smrg 22287ec681f3Smrg if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { 22297ec681f3Smrg map_would_stall = 22307ec681f3Smrg resource_is_busy(ice, res) || 22317ec681f3Smrg iris_has_invalid_primary(res, level, 1, box->z, box->depth); 22329f464c52Smaya 22337ec681f3Smrg if (map_would_stall && (usage & PIPE_MAP_DONTBLOCK) && 22347ec681f3Smrg (usage & PIPE_MAP_DIRECTLY)) 22359f464c52Smaya return NULL; 22369f464c52Smaya } 22379f464c52Smaya 22387ec681f3Smrg struct iris_transfer *map; 22399f464c52Smaya 22407ec681f3Smrg if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) 22417ec681f3Smrg map = slab_alloc(&ice->transfer_pool_unsync); 22427ec681f3Smrg else 22437ec681f3Smrg map = slab_alloc(&ice->transfer_pool); 22449f464c52Smaya 22459f464c52Smaya if (!map) 22469f464c52Smaya return NULL; 22479f464c52Smaya 22487ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 22497ec681f3Smrg 22509f464c52Smaya memset(map, 0, sizeof(*map)); 22519f464c52Smaya map->dbg = &ice->dbg; 22529f464c52Smaya 22539f464c52Smaya pipe_resource_reference(&xfer->resource, resource); 22549f464c52Smaya xfer->level = level; 22559f464c52Smaya xfer->usage = usage; 22569f464c52Smaya xfer->box = *box; 22579f464c52Smaya *ptransfer = xfer; 22589f464c52Smaya 22597ec681f3Smrg map->dest_had_defined_contents = 22607ec681f3Smrg util_ranges_intersect(&res->valid_buffer_range, box->x, 22617ec681f3Smrg box->x + box->width); 22629f464c52Smaya 22637ec681f3Smrg if (usage & PIPE_MAP_WRITE) 22647ec681f3Smrg util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width); 22659f464c52Smaya 22667ec681f3Smrg if (iris_bo_mmap_mode(res->bo) != IRIS_MMAP_NONE) { 22677ec681f3Smrg /* GPU copies are not useful for buffer reads. Instead of stalling to 22687ec681f3Smrg * read from the original buffer, we'd simply copy it to a temporary... 22697ec681f3Smrg * then stall (a bit longer) to read from that buffer. 22707ec681f3Smrg * 22717ec681f3Smrg * Images are less clear-cut. Resolves can be destructive, removing 22727ec681f3Smrg * some of the underlying compression, so we'd rather blit the data to 22737ec681f3Smrg * a linear temporary and map that, to avoid the resolve. 22747ec681f3Smrg */ 22757ec681f3Smrg if (!(usage & PIPE_MAP_DISCARD_RANGE) && 22767ec681f3Smrg !iris_has_invalid_primary(res, level, 1, box->z, box->depth)) { 22777ec681f3Smrg usage |= PIPE_MAP_DIRECTLY; 22787ec681f3Smrg } 22797ec681f3Smrg 22807ec681f3Smrg const struct isl_format_layout *fmtl = 22817ec681f3Smrg isl_format_get_layout(surf->format); 22827ec681f3Smrg if (fmtl->txc == ISL_TXC_ASTC) 22837ec681f3Smrg usage |= PIPE_MAP_DIRECTLY; 22847ec681f3Smrg 22857ec681f3Smrg /* We can map directly if it wouldn't stall, there's no compression, 22867ec681f3Smrg * and we aren't doing an uncached read. 22877ec681f3Smrg */ 22887ec681f3Smrg if (!map_would_stall && 22897ec681f3Smrg !isl_aux_usage_has_compression(res->aux.usage) && 22907ec681f3Smrg !((usage & PIPE_MAP_READ) && 22917ec681f3Smrg iris_bo_mmap_mode(res->bo) != IRIS_MMAP_WB)) { 22927ec681f3Smrg usage |= PIPE_MAP_DIRECTLY; 22937ec681f3Smrg } 22949f464c52Smaya } 22959f464c52Smaya 22967ec681f3Smrg /* TODO: Teach iris_map_tiled_memcpy about Tile4... */ 22977ec681f3Smrg if (res->surf.tiling == ISL_TILING_4) 22987ec681f3Smrg usage &= ~PIPE_MAP_DIRECTLY; 22999f464c52Smaya 23007ec681f3Smrg if (!(usage & PIPE_MAP_DIRECTLY)) { 23017ec681f3Smrg /* If we need a synchronous mapping and the resource is busy, or needs 23027ec681f3Smrg * resolving, we copy to/from a linear temporary buffer using the GPU. 23039f464c52Smaya */ 23049f464c52Smaya map->batch = &ice->batches[IRIS_BATCH_RENDER]; 23059f464c52Smaya map->blorp = &ice->blorp; 23069f464c52Smaya iris_map_copy_region(map); 23079f464c52Smaya } else { 23087ec681f3Smrg /* Otherwise we're free to map on the CPU. */ 23097ec681f3Smrg 23107ec681f3Smrg if (resource->target != PIPE_BUFFER) { 23117ec681f3Smrg iris_resource_access_raw(ice, res, level, box->z, box->depth, 23127ec681f3Smrg usage & PIPE_MAP_WRITE); 23137ec681f3Smrg } 23147ec681f3Smrg 23157ec681f3Smrg if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { 23169f464c52Smaya for (int i = 0; i < IRIS_BATCH_COUNT; i++) { 23179f464c52Smaya if (iris_batch_references(&ice->batches[i], res->bo)) 23189f464c52Smaya iris_batch_flush(&ice->batches[i]); 23199f464c52Smaya } 23209f464c52Smaya } 23219f464c52Smaya 23229f464c52Smaya if (surf->tiling == ISL_TILING_W) { 23239f464c52Smaya /* TODO: Teach iris_map_tiled_memcpy about W-tiling... */ 23249f464c52Smaya iris_map_s8(map); 23259f464c52Smaya } else if (surf->tiling != ISL_TILING_LINEAR) { 23269f464c52Smaya iris_map_tiled_memcpy(map); 23279f464c52Smaya } else { 23289f464c52Smaya iris_map_direct(map); 23299f464c52Smaya } 23309f464c52Smaya } 23319f464c52Smaya 23329f464c52Smaya return map->ptr; 23339f464c52Smaya} 23349f464c52Smaya 23359f464c52Smayastatic void 23369f464c52Smayairis_transfer_flush_region(struct pipe_context *ctx, 23379f464c52Smaya struct pipe_transfer *xfer, 23389f464c52Smaya const struct pipe_box *box) 23399f464c52Smaya{ 23409f464c52Smaya struct iris_context *ice = (struct iris_context *)ctx; 23419f464c52Smaya struct iris_resource *res = (struct iris_resource *) xfer->resource; 23429f464c52Smaya struct iris_transfer *map = (void *) xfer; 23439f464c52Smaya 23449f464c52Smaya if (map->staging) 23459f464c52Smaya iris_flush_staging_region(xfer, box); 23469f464c52Smaya 23477ec681f3Smrg uint32_t history_flush = 0; 23487ec681f3Smrg 23497ec681f3Smrg if (res->base.b.target == PIPE_BUFFER) { 23507ec681f3Smrg if (map->staging) 23517ec681f3Smrg history_flush |= PIPE_CONTROL_RENDER_TARGET_FLUSH | 23527ec681f3Smrg PIPE_CONTROL_TILE_CACHE_FLUSH; 23537ec681f3Smrg 23547ec681f3Smrg if (map->dest_had_defined_contents) 23557ec681f3Smrg history_flush |= iris_flush_bits_for_history(ice, res); 23567ec681f3Smrg 23577ec681f3Smrg util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width); 23587ec681f3Smrg } 23597ec681f3Smrg 23607ec681f3Smrg if (history_flush & ~PIPE_CONTROL_CS_STALL) { 23617ec681f3Smrg for (int i = 0; i < IRIS_BATCH_COUNT; i++) { 23627ec681f3Smrg struct iris_batch *batch = &ice->batches[i]; 23637ec681f3Smrg if (batch->contains_draw || batch->cache.render->entries) { 23647ec681f3Smrg iris_batch_maybe_flush(batch, 24); 23657ec681f3Smrg iris_emit_pipe_control_flush(batch, 23667ec681f3Smrg "cache history: transfer flush", 23677ec681f3Smrg history_flush); 23687ec681f3Smrg } 23699f464c52Smaya } 23709f464c52Smaya } 23719f464c52Smaya 23729f464c52Smaya /* Make sure we flag constants dirty even if there's no need to emit 23739f464c52Smaya * any PIPE_CONTROLs to a batch. 23749f464c52Smaya */ 23759f464c52Smaya iris_dirty_for_history(ice, res); 23769f464c52Smaya} 23779f464c52Smaya 23789f464c52Smayastatic void 23799f464c52Smayairis_transfer_unmap(struct pipe_context *ctx, struct pipe_transfer *xfer) 23809f464c52Smaya{ 23819f464c52Smaya struct iris_context *ice = (struct iris_context *)ctx; 23829f464c52Smaya struct iris_transfer *map = (void *) xfer; 23839f464c52Smaya 23847ec681f3Smrg if (!(xfer->usage & (PIPE_MAP_FLUSH_EXPLICIT | 23857ec681f3Smrg PIPE_MAP_COHERENT))) { 23869f464c52Smaya struct pipe_box flush_box = { 23879f464c52Smaya .x = 0, .y = 0, .z = 0, 23889f464c52Smaya .width = xfer->box.width, 23899f464c52Smaya .height = xfer->box.height, 23909f464c52Smaya .depth = xfer->box.depth, 23919f464c52Smaya }; 23929f464c52Smaya iris_transfer_flush_region(ctx, xfer, &flush_box); 23939f464c52Smaya } 23949f464c52Smaya 23959f464c52Smaya if (map->unmap) 23969f464c52Smaya map->unmap(map); 23979f464c52Smaya 23989f464c52Smaya pipe_resource_reference(&xfer->resource, NULL); 23997ec681f3Smrg 24007ec681f3Smrg /* transfer_unmap is always called from the driver thread, so we have to 24017ec681f3Smrg * use transfer_pool, not transfer_pool_unsync. Freeing an object into a 24027ec681f3Smrg * different pool is allowed, however. 24037ec681f3Smrg */ 24049f464c52Smaya slab_free(&ice->transfer_pool, map); 24059f464c52Smaya} 24069f464c52Smaya 24077ec681f3Smrg/** 24087ec681f3Smrg * The pipe->texture_subdata() driver hook. 24097ec681f3Smrg * 24107ec681f3Smrg * Mesa's state tracker takes this path whenever possible, even with 24117ec681f3Smrg * PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER set. 24127ec681f3Smrg */ 24137ec681f3Smrgstatic void 24147ec681f3Smrgiris_texture_subdata(struct pipe_context *ctx, 24157ec681f3Smrg struct pipe_resource *resource, 24167ec681f3Smrg unsigned level, 24177ec681f3Smrg unsigned usage, 24187ec681f3Smrg const struct pipe_box *box, 24197ec681f3Smrg const void *data, 24207ec681f3Smrg unsigned stride, 24217ec681f3Smrg unsigned layer_stride) 24227ec681f3Smrg{ 24237ec681f3Smrg struct iris_context *ice = (struct iris_context *)ctx; 24247ec681f3Smrg struct iris_resource *res = (struct iris_resource *)resource; 24257ec681f3Smrg const struct isl_surf *surf = &res->surf; 24267ec681f3Smrg 24277ec681f3Smrg assert(resource->target != PIPE_BUFFER); 24287ec681f3Smrg 24297ec681f3Smrg /* Just use the transfer-based path for linear buffers - it will already 24307ec681f3Smrg * do a direct mapping, or a simple linear staging buffer. 24317ec681f3Smrg * 24327ec681f3Smrg * Linear staging buffers appear to be better than tiled ones, too, so 24337ec681f3Smrg * take that path if we need the GPU to perform color compression, or 24347ec681f3Smrg * stall-avoidance blits. 24357ec681f3Smrg * 24367ec681f3Smrg * TODO: Teach isl_memcpy_linear_to_tiled about Tile4... 24377ec681f3Smrg */ 24387ec681f3Smrg if (surf->tiling == ISL_TILING_LINEAR || 24397ec681f3Smrg surf->tiling == ISL_TILING_4 || 24407ec681f3Smrg isl_aux_usage_has_compression(res->aux.usage) || 24417ec681f3Smrg resource_is_busy(ice, res) || 24427ec681f3Smrg iris_bo_mmap_mode(res->bo) == IRIS_MMAP_NONE) { 24437ec681f3Smrg return u_default_texture_subdata(ctx, resource, level, usage, box, 24447ec681f3Smrg data, stride, layer_stride); 24457ec681f3Smrg } 24467ec681f3Smrg 24477ec681f3Smrg /* No state trackers pass any flags other than PIPE_MAP_WRITE */ 24487ec681f3Smrg 24497ec681f3Smrg iris_resource_access_raw(ice, res, level, box->z, box->depth, true); 24507ec681f3Smrg 24517ec681f3Smrg for (int i = 0; i < IRIS_BATCH_COUNT; i++) { 24527ec681f3Smrg if (iris_batch_references(&ice->batches[i], res->bo)) 24537ec681f3Smrg iris_batch_flush(&ice->batches[i]); 24547ec681f3Smrg } 24557ec681f3Smrg 24567ec681f3Smrg uint8_t *dst = iris_bo_map(&ice->dbg, res->bo, MAP_WRITE | MAP_RAW); 24577ec681f3Smrg 24587ec681f3Smrg for (int s = 0; s < box->depth; s++) { 24597ec681f3Smrg const uint8_t *src = data + s * layer_stride; 24607ec681f3Smrg 24617ec681f3Smrg if (surf->tiling == ISL_TILING_W) { 24627ec681f3Smrg unsigned x0_el, y0_el; 24637ec681f3Smrg get_image_offset_el(surf, level, box->z + s, &x0_el, &y0_el); 24647ec681f3Smrg 24657ec681f3Smrg for (unsigned y = 0; y < box->height; y++) { 24667ec681f3Smrg for (unsigned x = 0; x < box->width; x++) { 24677ec681f3Smrg ptrdiff_t offset = s8_offset(surf->row_pitch_B, 24687ec681f3Smrg x0_el + box->x + x, 24697ec681f3Smrg y0_el + box->y + y); 24707ec681f3Smrg dst[offset] = src[y * stride + x]; 24717ec681f3Smrg } 24727ec681f3Smrg } 24737ec681f3Smrg } else { 24747ec681f3Smrg unsigned x1, x2, y1, y2; 24757ec681f3Smrg 24767ec681f3Smrg tile_extents(surf, box, level, s, &x1, &x2, &y1, &y2); 24777ec681f3Smrg 24787ec681f3Smrg isl_memcpy_linear_to_tiled(x1, x2, y1, y2, 24797ec681f3Smrg (void *)dst, (void *)src, 24807ec681f3Smrg surf->row_pitch_B, stride, 24817ec681f3Smrg false, surf->tiling, ISL_MEMCPY); 24827ec681f3Smrg } 24837ec681f3Smrg } 24847ec681f3Smrg} 24857ec681f3Smrg 24869f464c52Smaya/** 24879f464c52Smaya * Mark state dirty that needs to be re-emitted when a resource is written. 24889f464c52Smaya */ 24899f464c52Smayavoid 24909f464c52Smayairis_dirty_for_history(struct iris_context *ice, 24919f464c52Smaya struct iris_resource *res) 24929f464c52Smaya{ 24937ec681f3Smrg const uint64_t stages = res->bind_stages; 24949f464c52Smaya uint64_t dirty = 0ull; 24957ec681f3Smrg uint64_t stage_dirty = 0ull; 24969f464c52Smaya 24979f464c52Smaya if (res->bind_history & PIPE_BIND_CONSTANT_BUFFER) { 24987ec681f3Smrg for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) { 24997ec681f3Smrg if (stages & (1u << stage)) { 25007ec681f3Smrg struct iris_shader_state *shs = &ice->state.shaders[stage]; 25017ec681f3Smrg shs->dirty_cbufs |= ~0u; 25027ec681f3Smrg } 25037ec681f3Smrg } 25047ec681f3Smrg dirty |= IRIS_DIRTY_RENDER_MISC_BUFFER_FLUSHES | 25057ec681f3Smrg IRIS_DIRTY_COMPUTE_MISC_BUFFER_FLUSHES; 25067ec681f3Smrg stage_dirty |= (stages << IRIS_SHIFT_FOR_STAGE_DIRTY_CONSTANTS); 25077ec681f3Smrg } 25087ec681f3Smrg 25097ec681f3Smrg if (res->bind_history & (PIPE_BIND_SAMPLER_VIEW | 25107ec681f3Smrg PIPE_BIND_SHADER_IMAGE)) { 25117ec681f3Smrg dirty |= IRIS_DIRTY_RENDER_RESOLVES_AND_FLUSHES | 25127ec681f3Smrg IRIS_DIRTY_COMPUTE_RESOLVES_AND_FLUSHES; 25137ec681f3Smrg stage_dirty |= (stages << IRIS_SHIFT_FOR_STAGE_DIRTY_BINDINGS); 25147ec681f3Smrg } 25157ec681f3Smrg 25167ec681f3Smrg if (res->bind_history & PIPE_BIND_SHADER_BUFFER) { 25177ec681f3Smrg dirty |= IRIS_DIRTY_RENDER_MISC_BUFFER_FLUSHES | 25187ec681f3Smrg IRIS_DIRTY_COMPUTE_MISC_BUFFER_FLUSHES; 25197ec681f3Smrg stage_dirty |= (stages << IRIS_SHIFT_FOR_STAGE_DIRTY_BINDINGS); 25209f464c52Smaya } 25219f464c52Smaya 25227ec681f3Smrg if (res->bind_history & PIPE_BIND_VERTEX_BUFFER) 25237ec681f3Smrg dirty |= IRIS_DIRTY_VERTEX_BUFFER_FLUSHES; 25247ec681f3Smrg 25259f464c52Smaya ice->state.dirty |= dirty; 25267ec681f3Smrg ice->state.stage_dirty |= stage_dirty; 25279f464c52Smaya} 25289f464c52Smaya 25299f464c52Smaya/** 25309f464c52Smaya * Produce a set of PIPE_CONTROL bits which ensure data written to a 25319f464c52Smaya * resource becomes visible, and any stale read cache data is invalidated. 25329f464c52Smaya */ 25339f464c52Smayauint32_t 25347ec681f3Smrgiris_flush_bits_for_history(struct iris_context *ice, 25357ec681f3Smrg struct iris_resource *res) 25369f464c52Smaya{ 25377ec681f3Smrg struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen; 25387ec681f3Smrg 25399f464c52Smaya uint32_t flush = PIPE_CONTROL_CS_STALL; 25409f464c52Smaya 25419f464c52Smaya if (res->bind_history & PIPE_BIND_CONSTANT_BUFFER) { 25427ec681f3Smrg flush |= PIPE_CONTROL_CONST_CACHE_INVALIDATE; 25437ec681f3Smrg flush |= screen->compiler->indirect_ubos_use_sampler ? 25447ec681f3Smrg PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE : 25457ec681f3Smrg PIPE_CONTROL_DATA_CACHE_FLUSH; 25469f464c52Smaya } 25479f464c52Smaya 25489f464c52Smaya if (res->bind_history & PIPE_BIND_SAMPLER_VIEW) 25499f464c52Smaya flush |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE; 25509f464c52Smaya 25519f464c52Smaya if (res->bind_history & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER)) 25529f464c52Smaya flush |= PIPE_CONTROL_VF_CACHE_INVALIDATE; 25539f464c52Smaya 25549f464c52Smaya if (res->bind_history & (PIPE_BIND_SHADER_BUFFER | PIPE_BIND_SHADER_IMAGE)) 25559f464c52Smaya flush |= PIPE_CONTROL_DATA_CACHE_FLUSH; 25569f464c52Smaya 25579f464c52Smaya return flush; 25589f464c52Smaya} 25599f464c52Smaya 25609f464c52Smayavoid 25619f464c52Smayairis_flush_and_dirty_for_history(struct iris_context *ice, 25629f464c52Smaya struct iris_batch *batch, 25637ec681f3Smrg struct iris_resource *res, 25647ec681f3Smrg uint32_t extra_flags, 25657ec681f3Smrg const char *reason) 25669f464c52Smaya{ 25677ec681f3Smrg if (res->base.b.target != PIPE_BUFFER) 25689f464c52Smaya return; 25699f464c52Smaya 25707ec681f3Smrg uint32_t flush = iris_flush_bits_for_history(ice, res) | extra_flags; 25719f464c52Smaya 25727ec681f3Smrg iris_emit_pipe_control_flush(batch, reason, flush); 25739f464c52Smaya 25749f464c52Smaya iris_dirty_for_history(ice, res); 25759f464c52Smaya} 25769f464c52Smaya 25779f464c52Smayabool 25789f464c52Smayairis_resource_set_clear_color(struct iris_context *ice, 25799f464c52Smaya struct iris_resource *res, 25809f464c52Smaya union isl_color_value color) 25819f464c52Smaya{ 25827ec681f3Smrg if (res->aux.clear_color_unknown || 25837ec681f3Smrg memcmp(&res->aux.clear_color, &color, sizeof(color)) != 0) { 25849f464c52Smaya res->aux.clear_color = color; 25857ec681f3Smrg res->aux.clear_color_unknown = false; 25869f464c52Smaya return true; 25879f464c52Smaya } 25889f464c52Smaya 25899f464c52Smaya return false; 25909f464c52Smaya} 25919f464c52Smaya 25929f464c52Smayastatic enum pipe_format 25939f464c52Smayairis_resource_get_internal_format(struct pipe_resource *p_res) 25949f464c52Smaya{ 25959f464c52Smaya struct iris_resource *res = (void *) p_res; 25969f464c52Smaya return res->internal_format; 25979f464c52Smaya} 25989f464c52Smaya 25999f464c52Smayastatic const struct u_transfer_vtbl transfer_vtbl = { 26009f464c52Smaya .resource_create = iris_resource_create, 26019f464c52Smaya .resource_destroy = iris_resource_destroy, 26029f464c52Smaya .transfer_map = iris_transfer_map, 26039f464c52Smaya .transfer_unmap = iris_transfer_unmap, 26049f464c52Smaya .transfer_flush_region = iris_transfer_flush_region, 26059f464c52Smaya .get_internal_format = iris_resource_get_internal_format, 26069f464c52Smaya .set_stencil = iris_resource_set_separate_stencil, 26079f464c52Smaya .get_stencil = iris_resource_get_separate_stencil, 26089f464c52Smaya}; 26099f464c52Smaya 26109f464c52Smayavoid 26119f464c52Smayairis_init_screen_resource_functions(struct pipe_screen *pscreen) 26129f464c52Smaya{ 26139f464c52Smaya pscreen->query_dmabuf_modifiers = iris_query_dmabuf_modifiers; 26147ec681f3Smrg pscreen->is_dmabuf_modifier_supported = iris_is_dmabuf_modifier_supported; 26157ec681f3Smrg pscreen->get_dmabuf_modifier_planes = iris_get_dmabuf_modifier_planes; 26169f464c52Smaya pscreen->resource_create_with_modifiers = 26179f464c52Smaya iris_resource_create_with_modifiers; 26189f464c52Smaya pscreen->resource_create = u_transfer_helper_resource_create; 26199f464c52Smaya pscreen->resource_from_user_memory = iris_resource_from_user_memory; 26209f464c52Smaya pscreen->resource_from_handle = iris_resource_from_handle; 26217ec681f3Smrg pscreen->resource_from_memobj = iris_resource_from_memobj_wrapper; 26229f464c52Smaya pscreen->resource_get_handle = iris_resource_get_handle; 26237ec681f3Smrg pscreen->resource_get_param = iris_resource_get_param; 26249f464c52Smaya pscreen->resource_destroy = u_transfer_helper_resource_destroy; 26257ec681f3Smrg pscreen->memobj_create_from_handle = iris_memobj_create_from_handle; 26267ec681f3Smrg pscreen->memobj_destroy = iris_memobj_destroy; 26279f464c52Smaya pscreen->transfer_helper = 26289f464c52Smaya u_transfer_helper_create(&transfer_vtbl, true, true, false, true); 26299f464c52Smaya} 26309f464c52Smaya 26319f464c52Smayavoid 26329f464c52Smayairis_init_resource_functions(struct pipe_context *ctx) 26339f464c52Smaya{ 26349f464c52Smaya ctx->flush_resource = iris_flush_resource; 26359f464c52Smaya ctx->invalidate_resource = iris_invalidate_resource; 26367ec681f3Smrg ctx->buffer_map = u_transfer_helper_transfer_map; 26377ec681f3Smrg ctx->texture_map = u_transfer_helper_transfer_map; 26389f464c52Smaya ctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 26397ec681f3Smrg ctx->buffer_unmap = u_transfer_helper_transfer_unmap; 26407ec681f3Smrg ctx->texture_unmap = u_transfer_helper_transfer_unmap; 26419f464c52Smaya ctx->buffer_subdata = u_default_buffer_subdata; 26427ec681f3Smrg ctx->texture_subdata = iris_texture_subdata; 26439f464c52Smaya} 2644