17ec681f3Smrg/* 27ec681f3Smrg * Copyright © 2017 Intel Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice shall be included 127ec681f3Smrg * in all copies or substantial portions of the Software. 137ec681f3Smrg * 147ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 157ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 167ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 177ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 187ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 197ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 207ec681f3Smrg * DEALINGS IN THE SOFTWARE. 217ec681f3Smrg */ 227ec681f3Smrg 237ec681f3Smrg/** 247ec681f3Smrg * @file crocus_resource.c 257ec681f3Smrg * 267ec681f3Smrg * Resources are images, buffers, and other objects used by the GPU. 277ec681f3Smrg * 287ec681f3Smrg * XXX: explain resources 297ec681f3Smrg */ 307ec681f3Smrg 317ec681f3Smrg#include <stdio.h> 327ec681f3Smrg#include <errno.h> 337ec681f3Smrg#include "pipe/p_defines.h" 347ec681f3Smrg#include "pipe/p_state.h" 357ec681f3Smrg#include "pipe/p_context.h" 367ec681f3Smrg#include "pipe/p_screen.h" 377ec681f3Smrg#include "util/os_memory.h" 387ec681f3Smrg#include "util/u_cpu_detect.h" 397ec681f3Smrg#include "util/u_inlines.h" 407ec681f3Smrg#include "util/format/u_format.h" 417ec681f3Smrg#include "util/u_threaded_context.h" 427ec681f3Smrg#include "util/u_transfer.h" 437ec681f3Smrg#include "util/u_transfer_helper.h" 447ec681f3Smrg#include "util/u_upload_mgr.h" 457ec681f3Smrg#include "util/ralloc.h" 467ec681f3Smrg#include "util/u_memory.h" 477ec681f3Smrg#include "crocus_batch.h" 487ec681f3Smrg#include "crocus_context.h" 497ec681f3Smrg#include "crocus_resource.h" 507ec681f3Smrg#include "crocus_screen.h" 517ec681f3Smrg#include "intel/dev/intel_debug.h" 527ec681f3Smrg#include "isl/isl.h" 537ec681f3Smrg#include "drm-uapi/drm_fourcc.h" 547ec681f3Smrg#include "drm-uapi/i915_drm.h" 557ec681f3Smrg 567ec681f3Smrgenum modifier_priority { 577ec681f3Smrg MODIFIER_PRIORITY_INVALID = 0, 587ec681f3Smrg MODIFIER_PRIORITY_LINEAR, 597ec681f3Smrg MODIFIER_PRIORITY_X, 607ec681f3Smrg MODIFIER_PRIORITY_Y, 617ec681f3Smrg MODIFIER_PRIORITY_Y_CCS, 627ec681f3Smrg}; 637ec681f3Smrg 647ec681f3Smrgstatic const uint64_t priority_to_modifier[] = { 657ec681f3Smrg [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID, 667ec681f3Smrg [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR, 677ec681f3Smrg [MODIFIER_PRIORITY_X] = I915_FORMAT_MOD_X_TILED, 687ec681f3Smrg [MODIFIER_PRIORITY_Y] = I915_FORMAT_MOD_Y_TILED, 697ec681f3Smrg [MODIFIER_PRIORITY_Y_CCS] = I915_FORMAT_MOD_Y_TILED_CCS, 707ec681f3Smrg}; 717ec681f3Smrg 727ec681f3Smrgstatic bool 737ec681f3Smrgmodifier_is_supported(const struct intel_device_info *devinfo, 747ec681f3Smrg enum pipe_format pfmt, unsigned bind, 757ec681f3Smrg uint64_t modifier) 767ec681f3Smrg{ 777ec681f3Smrg /* XXX: do something real */ 787ec681f3Smrg switch (modifier) { 797ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_CCS: 807ec681f3Smrg return false; 817ec681f3Smrg case I915_FORMAT_MOD_Y_TILED: 827ec681f3Smrg if (bind & PIPE_BIND_SCANOUT) 837ec681f3Smrg return false; 847ec681f3Smrg return devinfo->ver >= 6; 857ec681f3Smrg case I915_FORMAT_MOD_X_TILED: 867ec681f3Smrg case DRM_FORMAT_MOD_LINEAR: 877ec681f3Smrg return true; 887ec681f3Smrg case DRM_FORMAT_MOD_INVALID: 897ec681f3Smrg default: 907ec681f3Smrg return false; 917ec681f3Smrg } 927ec681f3Smrg} 937ec681f3Smrg 947ec681f3Smrgstatic uint64_t 957ec681f3Smrgselect_best_modifier(struct intel_device_info *devinfo, 967ec681f3Smrg const struct pipe_resource *templ, 977ec681f3Smrg const uint64_t *modifiers, 987ec681f3Smrg int count) 997ec681f3Smrg{ 1007ec681f3Smrg enum modifier_priority prio = MODIFIER_PRIORITY_INVALID; 1017ec681f3Smrg 1027ec681f3Smrg for (int i = 0; i < count; i++) { 1037ec681f3Smrg if (!modifier_is_supported(devinfo, templ->format, templ->bind, 1047ec681f3Smrg modifiers[i])) 1057ec681f3Smrg continue; 1067ec681f3Smrg 1077ec681f3Smrg switch (modifiers[i]) { 1087ec681f3Smrg case I915_FORMAT_MOD_Y_TILED_CCS: 1097ec681f3Smrg prio = MAX2(prio, MODIFIER_PRIORITY_Y_CCS); 1107ec681f3Smrg break; 1117ec681f3Smrg case I915_FORMAT_MOD_Y_TILED: 1127ec681f3Smrg prio = MAX2(prio, MODIFIER_PRIORITY_Y); 1137ec681f3Smrg break; 1147ec681f3Smrg case I915_FORMAT_MOD_X_TILED: 1157ec681f3Smrg prio = MAX2(prio, MODIFIER_PRIORITY_X); 1167ec681f3Smrg break; 1177ec681f3Smrg case DRM_FORMAT_MOD_LINEAR: 1187ec681f3Smrg prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR); 1197ec681f3Smrg break; 1207ec681f3Smrg case DRM_FORMAT_MOD_INVALID: 1217ec681f3Smrg default: 1227ec681f3Smrg break; 1237ec681f3Smrg } 1247ec681f3Smrg } 1257ec681f3Smrg 1267ec681f3Smrg return priority_to_modifier[prio]; 1277ec681f3Smrg} 1287ec681f3Smrg 1297ec681f3Smrgstatic enum isl_surf_dim 1307ec681f3Smrgcrocus_target_to_isl_surf_dim(enum pipe_texture_target target) 1317ec681f3Smrg{ 1327ec681f3Smrg switch (target) { 1337ec681f3Smrg case PIPE_BUFFER: 1347ec681f3Smrg case PIPE_TEXTURE_1D: 1357ec681f3Smrg case PIPE_TEXTURE_1D_ARRAY: 1367ec681f3Smrg return ISL_SURF_DIM_1D; 1377ec681f3Smrg case PIPE_TEXTURE_2D: 1387ec681f3Smrg case PIPE_TEXTURE_CUBE: 1397ec681f3Smrg case PIPE_TEXTURE_RECT: 1407ec681f3Smrg case PIPE_TEXTURE_2D_ARRAY: 1417ec681f3Smrg case PIPE_TEXTURE_CUBE_ARRAY: 1427ec681f3Smrg return ISL_SURF_DIM_2D; 1437ec681f3Smrg case PIPE_TEXTURE_3D: 1447ec681f3Smrg return ISL_SURF_DIM_3D; 1457ec681f3Smrg case PIPE_MAX_TEXTURE_TYPES: 1467ec681f3Smrg break; 1477ec681f3Smrg } 1487ec681f3Smrg unreachable("invalid texture type"); 1497ec681f3Smrg} 1507ec681f3Smrg 1517ec681f3Smrgstatic isl_surf_usage_flags_t 1527ec681f3Smrgpipe_bind_to_isl_usage(unsigned bindings) 1537ec681f3Smrg{ 1547ec681f3Smrg isl_surf_usage_flags_t usage = 0; 1557ec681f3Smrg 1567ec681f3Smrg if (bindings & PIPE_BIND_RENDER_TARGET) 1577ec681f3Smrg usage |= ISL_SURF_USAGE_RENDER_TARGET_BIT; 1587ec681f3Smrg 1597ec681f3Smrg if (bindings & PIPE_BIND_SAMPLER_VIEW) 1607ec681f3Smrg usage |= ISL_SURF_USAGE_TEXTURE_BIT; 1617ec681f3Smrg 1627ec681f3Smrg if (bindings & (PIPE_BIND_SHADER_IMAGE | PIPE_BIND_SHADER_BUFFER)) 1637ec681f3Smrg usage |= ISL_SURF_USAGE_STORAGE_BIT; 1647ec681f3Smrg 1657ec681f3Smrg if (bindings & PIPE_BIND_SCANOUT) 1667ec681f3Smrg usage |= ISL_SURF_USAGE_DISPLAY_BIT; 1677ec681f3Smrg return usage; 1687ec681f3Smrg} 1697ec681f3Smrg 1707ec681f3Smrgstatic bool 1717ec681f3Smrgcrocus_resource_configure_main(const struct crocus_screen *screen, 1727ec681f3Smrg struct crocus_resource *res, 1737ec681f3Smrg const struct pipe_resource *templ, 1747ec681f3Smrg uint64_t modifier, uint32_t row_pitch_B) 1757ec681f3Smrg{ 1767ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 1777ec681f3Smrg const struct util_format_description *format_desc = 1787ec681f3Smrg util_format_description(templ->format); 1797ec681f3Smrg const bool has_depth = util_format_has_depth(format_desc); 1807ec681f3Smrg isl_surf_usage_flags_t usage = pipe_bind_to_isl_usage(templ->bind); 1817ec681f3Smrg isl_tiling_flags_t tiling_flags = ISL_TILING_ANY_MASK; 1827ec681f3Smrg 1837ec681f3Smrg /* TODO: This used to be because there wasn't BLORP to handle Y-tiling. */ 1847ec681f3Smrg if (devinfo->ver < 6 && !util_format_is_depth_or_stencil(templ->format)) 1857ec681f3Smrg tiling_flags &= ~ISL_TILING_Y0_BIT; 1867ec681f3Smrg 1877ec681f3Smrg if (modifier != DRM_FORMAT_MOD_INVALID) { 1887ec681f3Smrg res->mod_info = isl_drm_modifier_get_info(modifier); 1897ec681f3Smrg 1907ec681f3Smrg tiling_flags = 1 << res->mod_info->tiling; 1917ec681f3Smrg } else { 1927ec681f3Smrg if (templ->bind & PIPE_BIND_RENDER_TARGET && devinfo->ver < 6) { 1937ec681f3Smrg modifier = I915_FORMAT_MOD_X_TILED; 1947ec681f3Smrg res->mod_info = isl_drm_modifier_get_info(modifier); 1957ec681f3Smrg tiling_flags = 1 << res->mod_info->tiling; 1967ec681f3Smrg } 1977ec681f3Smrg /* Use linear for staging buffers */ 1987ec681f3Smrg if (templ->usage == PIPE_USAGE_STAGING || 1997ec681f3Smrg templ->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR) ) 2007ec681f3Smrg tiling_flags = ISL_TILING_LINEAR_BIT; 2017ec681f3Smrg else if (templ->bind & PIPE_BIND_SCANOUT) 2027ec681f3Smrg tiling_flags = screen->devinfo.has_tiling_uapi ? 2037ec681f3Smrg ISL_TILING_X_BIT : ISL_TILING_LINEAR_BIT; 2047ec681f3Smrg } 2057ec681f3Smrg 2067ec681f3Smrg if (templ->target == PIPE_TEXTURE_CUBE || 2077ec681f3Smrg templ->target == PIPE_TEXTURE_CUBE_ARRAY) 2087ec681f3Smrg usage |= ISL_SURF_USAGE_CUBE_BIT; 2097ec681f3Smrg 2107ec681f3Smrg if (templ->usage != PIPE_USAGE_STAGING) { 2117ec681f3Smrg if (templ->format == PIPE_FORMAT_S8_UINT) 2127ec681f3Smrg usage |= ISL_SURF_USAGE_STENCIL_BIT; 2137ec681f3Smrg else if (has_depth) { 2147ec681f3Smrg /* combined DS only on gen4/5 */ 2157ec681f3Smrg if (devinfo->ver < 6) { 2167ec681f3Smrg if (templ->format == PIPE_FORMAT_Z24X8_UNORM || 2177ec681f3Smrg templ->format == PIPE_FORMAT_Z24_UNORM_S8_UINT || 2187ec681f3Smrg templ->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) 2197ec681f3Smrg usage |= ISL_SURF_USAGE_STENCIL_BIT; 2207ec681f3Smrg } 2217ec681f3Smrg usage |= ISL_SURF_USAGE_DEPTH_BIT; 2227ec681f3Smrg } 2237ec681f3Smrg 2247ec681f3Smrg if (templ->format == PIPE_FORMAT_S8_UINT) 2257ec681f3Smrg tiling_flags = ISL_TILING_W_BIT; 2267ec681f3Smrg } 2277ec681f3Smrg 2287ec681f3Smrg const enum isl_format format = 2297ec681f3Smrg crocus_format_for_usage(&screen->devinfo, templ->format, usage).fmt; 2307ec681f3Smrg 2317ec681f3Smrg if (row_pitch_B == 0 && templ->usage == PIPE_USAGE_STAGING && 2327ec681f3Smrg templ->target == PIPE_TEXTURE_2D && 2337ec681f3Smrg devinfo->ver < 6) { 2347ec681f3Smrg /* align row pitch to 4 so we can keep using BLT engine */ 2357ec681f3Smrg row_pitch_B = util_format_get_stride(templ->format, templ->width0); 2367ec681f3Smrg row_pitch_B = ALIGN(row_pitch_B, 4); 2377ec681f3Smrg } 2387ec681f3Smrg 2397ec681f3Smrg const struct isl_surf_init_info init_info = { 2407ec681f3Smrg .dim = crocus_target_to_isl_surf_dim(templ->target), 2417ec681f3Smrg .format = format, 2427ec681f3Smrg .width = templ->width0, 2437ec681f3Smrg .height = templ->height0, 2447ec681f3Smrg .depth = templ->depth0, 2457ec681f3Smrg .levels = templ->last_level + 1, 2467ec681f3Smrg .array_len = templ->array_size, 2477ec681f3Smrg .samples = MAX2(templ->nr_samples, 1), 2487ec681f3Smrg .min_alignment_B = 0, 2497ec681f3Smrg .row_pitch_B = row_pitch_B, 2507ec681f3Smrg .usage = usage, 2517ec681f3Smrg .tiling_flags = tiling_flags 2527ec681f3Smrg }; 2537ec681f3Smrg 2547ec681f3Smrg if (!isl_surf_init_s(&screen->isl_dev, &res->surf, &init_info)) 2557ec681f3Smrg return false; 2567ec681f3Smrg 2577ec681f3Smrg res->internal_format = templ->format; 2587ec681f3Smrg 2597ec681f3Smrg return true; 2607ec681f3Smrg} 2617ec681f3Smrg 2627ec681f3Smrgstatic void 2637ec681f3Smrgcrocus_query_dmabuf_modifiers(struct pipe_screen *pscreen, 2647ec681f3Smrg enum pipe_format pfmt, 2657ec681f3Smrg int max, 2667ec681f3Smrg uint64_t *modifiers, 2677ec681f3Smrg unsigned int *external_only, 2687ec681f3Smrg int *count) 2697ec681f3Smrg{ 2707ec681f3Smrg struct crocus_screen *screen = (void *) pscreen; 2717ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 2727ec681f3Smrg 2737ec681f3Smrg uint64_t all_modifiers[] = { 2747ec681f3Smrg DRM_FORMAT_MOD_LINEAR, 2757ec681f3Smrg I915_FORMAT_MOD_X_TILED, 2767ec681f3Smrg I915_FORMAT_MOD_Y_TILED, 2777ec681f3Smrg I915_FORMAT_MOD_Y_TILED_CCS, 2787ec681f3Smrg }; 2797ec681f3Smrg 2807ec681f3Smrg int supported_mods = 0; 2817ec681f3Smrg 2827ec681f3Smrg for (int i = 0; i < ARRAY_SIZE(all_modifiers); i++) { 2837ec681f3Smrg if (!modifier_is_supported(devinfo, pfmt, 0, all_modifiers[i])) 2847ec681f3Smrg continue; 2857ec681f3Smrg 2867ec681f3Smrg if (supported_mods < max) { 2877ec681f3Smrg if (modifiers) 2887ec681f3Smrg modifiers[supported_mods] = all_modifiers[i]; 2897ec681f3Smrg 2907ec681f3Smrg if (external_only) 2917ec681f3Smrg external_only[supported_mods] = util_format_is_yuv(pfmt); 2927ec681f3Smrg } 2937ec681f3Smrg 2947ec681f3Smrg supported_mods++; 2957ec681f3Smrg } 2967ec681f3Smrg 2977ec681f3Smrg *count = supported_mods; 2987ec681f3Smrg} 2997ec681f3Smrg 3007ec681f3Smrgstatic struct pipe_resource * 3017ec681f3Smrgcrocus_resource_get_separate_stencil(struct pipe_resource *p_res) 3027ec681f3Smrg{ 3037ec681f3Smrg return _crocus_resource_get_separate_stencil(p_res); 3047ec681f3Smrg} 3057ec681f3Smrg 3067ec681f3Smrgstatic void 3077ec681f3Smrgcrocus_resource_set_separate_stencil(struct pipe_resource *p_res, 3087ec681f3Smrg struct pipe_resource *stencil) 3097ec681f3Smrg{ 3107ec681f3Smrg assert(util_format_has_depth(util_format_description(p_res->format))); 3117ec681f3Smrg pipe_resource_reference(&p_res->next, stencil); 3127ec681f3Smrg} 3137ec681f3Smrg 3147ec681f3Smrgvoid 3157ec681f3Smrgcrocus_resource_disable_aux(struct crocus_resource *res) 3167ec681f3Smrg{ 3177ec681f3Smrg crocus_bo_unreference(res->aux.bo); 3187ec681f3Smrg free(res->aux.state); 3197ec681f3Smrg 3207ec681f3Smrg res->aux.usage = ISL_AUX_USAGE_NONE; 3217ec681f3Smrg res->aux.has_hiz = 0; 3227ec681f3Smrg res->aux.surf.size_B = 0; 3237ec681f3Smrg res->aux.surf.levels = 0; 3247ec681f3Smrg res->aux.bo = NULL; 3257ec681f3Smrg res->aux.state = NULL; 3267ec681f3Smrg} 3277ec681f3Smrg 3287ec681f3Smrgstatic void 3297ec681f3Smrgcrocus_resource_destroy(struct pipe_screen *screen, 3307ec681f3Smrg struct pipe_resource *resource) 3317ec681f3Smrg{ 3327ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *)resource; 3337ec681f3Smrg 3347ec681f3Smrg if (resource->target == PIPE_BUFFER) 3357ec681f3Smrg util_range_destroy(&res->valid_buffer_range); 3367ec681f3Smrg 3377ec681f3Smrg if (res->shadow) 3387ec681f3Smrg pipe_resource_reference((struct pipe_resource **)&res->shadow, NULL); 3397ec681f3Smrg crocus_resource_disable_aux(res); 3407ec681f3Smrg 3417ec681f3Smrg threaded_resource_deinit(resource); 3427ec681f3Smrg crocus_bo_unreference(res->bo); 3437ec681f3Smrg crocus_pscreen_unref(res->orig_screen); 3447ec681f3Smrg free(res); 3457ec681f3Smrg} 3467ec681f3Smrg 3477ec681f3Smrgstatic struct crocus_resource * 3487ec681f3Smrgcrocus_alloc_resource(struct pipe_screen *pscreen, 3497ec681f3Smrg const struct pipe_resource *templ) 3507ec681f3Smrg{ 3517ec681f3Smrg struct crocus_resource *res = calloc(1, sizeof(struct crocus_resource)); 3527ec681f3Smrg if (!res) 3537ec681f3Smrg return NULL; 3547ec681f3Smrg 3557ec681f3Smrg res->base.b = *templ; 3567ec681f3Smrg res->base.b.screen = pscreen; 3577ec681f3Smrg res->orig_screen = crocus_pscreen_ref(pscreen); 3587ec681f3Smrg pipe_reference_init(&res->base.b.reference, 1); 3597ec681f3Smrg threaded_resource_init(&res->base.b); 3607ec681f3Smrg 3617ec681f3Smrg if (templ->target == PIPE_BUFFER) 3627ec681f3Smrg util_range_init(&res->valid_buffer_range); 3637ec681f3Smrg 3647ec681f3Smrg return res; 3657ec681f3Smrg} 3667ec681f3Smrg 3677ec681f3Smrgunsigned 3687ec681f3Smrgcrocus_get_num_logical_layers(const struct crocus_resource *res, unsigned level) 3697ec681f3Smrg{ 3707ec681f3Smrg if (res->surf.dim == ISL_SURF_DIM_3D) 3717ec681f3Smrg return minify(res->surf.logical_level0_px.depth, level); 3727ec681f3Smrg else 3737ec681f3Smrg return res->surf.logical_level0_px.array_len; 3747ec681f3Smrg} 3757ec681f3Smrg 3767ec681f3Smrgstatic enum isl_aux_state ** 3777ec681f3Smrgcreate_aux_state_map(struct crocus_resource *res, enum isl_aux_state initial) 3787ec681f3Smrg{ 3797ec681f3Smrg assert(res->aux.state == NULL); 3807ec681f3Smrg 3817ec681f3Smrg uint32_t total_slices = 0; 3827ec681f3Smrg for (uint32_t level = 0; level < res->surf.levels; level++) 3837ec681f3Smrg total_slices += crocus_get_num_logical_layers(res, level); 3847ec681f3Smrg 3857ec681f3Smrg const size_t per_level_array_size = 3867ec681f3Smrg res->surf.levels * sizeof(enum isl_aux_state *); 3877ec681f3Smrg 3887ec681f3Smrg /* We're going to allocate a single chunk of data for both the per-level 3897ec681f3Smrg * reference array and the arrays of aux_state. This makes cleanup 3907ec681f3Smrg * significantly easier. 3917ec681f3Smrg */ 3927ec681f3Smrg const size_t total_size = 3937ec681f3Smrg per_level_array_size + total_slices * sizeof(enum isl_aux_state); 3947ec681f3Smrg 3957ec681f3Smrg void *data = malloc(total_size); 3967ec681f3Smrg if (!data) 3977ec681f3Smrg return NULL; 3987ec681f3Smrg 3997ec681f3Smrg enum isl_aux_state **per_level_arr = data; 4007ec681f3Smrg enum isl_aux_state *s = data + per_level_array_size; 4017ec681f3Smrg for (uint32_t level = 0; level < res->surf.levels; level++) { 4027ec681f3Smrg per_level_arr[level] = s; 4037ec681f3Smrg const unsigned level_layers = crocus_get_num_logical_layers(res, level); 4047ec681f3Smrg for (uint32_t a = 0; a < level_layers; a++) 4057ec681f3Smrg *(s++) = initial; 4067ec681f3Smrg } 4077ec681f3Smrg assert((void *)s == data + total_size); 4087ec681f3Smrg 4097ec681f3Smrg return per_level_arr; 4107ec681f3Smrg} 4117ec681f3Smrg 4127ec681f3Smrg/** 4137ec681f3Smrg * Configure aux for the resource, but don't allocate it. For images which 4147ec681f3Smrg * might be shared with modifiers, we must allocate the image and aux data in 4157ec681f3Smrg * a single bo. 4167ec681f3Smrg * 4177ec681f3Smrg * Returns false on unexpected error (e.g. allocation failed, or invalid 4187ec681f3Smrg * configuration result). 4197ec681f3Smrg */ 4207ec681f3Smrgstatic bool 4217ec681f3Smrgcrocus_resource_configure_aux(struct crocus_screen *screen, 4227ec681f3Smrg struct crocus_resource *res, bool imported, 4237ec681f3Smrg uint64_t *aux_size_B, 4247ec681f3Smrg uint32_t *alloc_flags) 4257ec681f3Smrg{ 4267ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 4277ec681f3Smrg 4287ec681f3Smrg /* Try to create the auxiliary surfaces allowed by the modifier or by 4297ec681f3Smrg * the user if no modifier is specified. 4307ec681f3Smrg */ 4317ec681f3Smrg assert(!res->mod_info || res->mod_info->aux_usage == ISL_AUX_USAGE_NONE); 4327ec681f3Smrg 4337ec681f3Smrg const bool has_mcs = devinfo->ver >= 7 && !res->mod_info && 4347ec681f3Smrg isl_surf_get_mcs_surf(&screen->isl_dev, &res->surf, &res->aux.surf); 4357ec681f3Smrg 4367ec681f3Smrg const bool has_hiz = devinfo->ver >= 6 && !res->mod_info && 4377ec681f3Smrg !INTEL_DEBUG(DEBUG_NO_HIZ) && 4387ec681f3Smrg isl_surf_get_hiz_surf(&screen->isl_dev, &res->surf, &res->aux.surf); 4397ec681f3Smrg 4407ec681f3Smrg const bool has_ccs = 4417ec681f3Smrg ((devinfo->ver >= 7 && !res->mod_info && !INTEL_DEBUG(DEBUG_NO_RBC)) || 4427ec681f3Smrg (res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE)) && 4437ec681f3Smrg isl_surf_get_ccs_surf(&screen->isl_dev, &res->surf, NULL, 4447ec681f3Smrg &res->aux.surf, 0); 4457ec681f3Smrg 4467ec681f3Smrg /* Having more than one type of compression is impossible */ 4477ec681f3Smrg assert(has_ccs + has_mcs + has_hiz <= 1); 4487ec681f3Smrg 4497ec681f3Smrg if (res->mod_info && has_ccs) { 4507ec681f3Smrg res->aux.usage = res->mod_info->aux_usage; 4517ec681f3Smrg } else if (has_mcs) { 4527ec681f3Smrg res->aux.usage = ISL_AUX_USAGE_MCS; 4537ec681f3Smrg } else if (has_hiz) { 4547ec681f3Smrg res->aux.usage = ISL_AUX_USAGE_HIZ; 4557ec681f3Smrg } else if (has_ccs) { 4567ec681f3Smrg if (isl_format_supports_ccs_d(devinfo, res->surf.format)) 4577ec681f3Smrg res->aux.usage = ISL_AUX_USAGE_CCS_D; 4587ec681f3Smrg } 4597ec681f3Smrg 4607ec681f3Smrg enum isl_aux_state initial_state = ISL_AUX_STATE_AUX_INVALID; 4617ec681f3Smrg *aux_size_B = 0; 4627ec681f3Smrg *alloc_flags = 0; 4637ec681f3Smrg assert(!res->aux.bo); 4647ec681f3Smrg 4657ec681f3Smrg switch (res->aux.usage) { 4667ec681f3Smrg case ISL_AUX_USAGE_NONE: 4677ec681f3Smrg /* Having no aux buffer is only okay if there's no modifier with aux. */ 4687ec681f3Smrg res->aux.surf.levels = 0; 4697ec681f3Smrg return !res->mod_info || res->mod_info->aux_usage == ISL_AUX_USAGE_NONE; 4707ec681f3Smrg case ISL_AUX_USAGE_HIZ: 4717ec681f3Smrg initial_state = ISL_AUX_STATE_AUX_INVALID; 4727ec681f3Smrg break; 4737ec681f3Smrg case ISL_AUX_USAGE_MCS: 4747ec681f3Smrg /* The Ivybridge PRM, Vol 2 Part 1 p326 says: 4757ec681f3Smrg * 4767ec681f3Smrg * "When MCS buffer is enabled and bound to MSRT, it is required 4777ec681f3Smrg * that it is cleared prior to any rendering." 4787ec681f3Smrg * 4797ec681f3Smrg * Since we only use the MCS buffer for rendering, we just clear it 4807ec681f3Smrg * immediately on allocation. The clear value for MCS buffers is all 4817ec681f3Smrg * 1's, so we simply memset it to 0xff. 4827ec681f3Smrg */ 4837ec681f3Smrg initial_state = ISL_AUX_STATE_CLEAR; 4847ec681f3Smrg break; 4857ec681f3Smrg case ISL_AUX_USAGE_CCS_D: 4867ec681f3Smrg /* When CCS_E is used, we need to ensure that the CCS starts off in 4877ec681f3Smrg * a valid state. From the Sky Lake PRM, "MCS Buffer for Render 4887ec681f3Smrg * Target(s)": 4897ec681f3Smrg * 4907ec681f3Smrg * "If Software wants to enable Color Compression without Fast 4917ec681f3Smrg * clear, Software needs to initialize MCS with zeros." 4927ec681f3Smrg * 4937ec681f3Smrg * A CCS value of 0 indicates that the corresponding block is in the 4947ec681f3Smrg * pass-through state which is what we want. 4957ec681f3Smrg * 4967ec681f3Smrg * For CCS_D, do the same thing. On Gen9+, this avoids having any 4977ec681f3Smrg * undefined bits in the aux buffer. 4987ec681f3Smrg */ 4997ec681f3Smrg if (imported) 5007ec681f3Smrg initial_state = 5017ec681f3Smrg isl_drm_modifier_get_default_aux_state(res->mod_info->modifier); 5027ec681f3Smrg else 5037ec681f3Smrg initial_state = ISL_AUX_STATE_PASS_THROUGH; 5047ec681f3Smrg *alloc_flags |= BO_ALLOC_ZEROED; 5057ec681f3Smrg break; 5067ec681f3Smrg default: 5077ec681f3Smrg unreachable("non-crocus aux"); 5087ec681f3Smrg } 5097ec681f3Smrg 5107ec681f3Smrg /* Create the aux_state for the auxiliary buffer. */ 5117ec681f3Smrg res->aux.state = create_aux_state_map(res, initial_state); 5127ec681f3Smrg if (!res->aux.state) 5137ec681f3Smrg return false; 5147ec681f3Smrg 5157ec681f3Smrg /* Increase the aux offset if the main and aux surfaces will share a BO. */ 5167ec681f3Smrg res->aux.offset = 5177ec681f3Smrg !res->mod_info || res->mod_info->aux_usage == res->aux.usage ? 5187ec681f3Smrg ALIGN(res->surf.size_B, res->aux.surf.alignment_B) : 0; 5197ec681f3Smrg uint64_t size = res->aux.surf.size_B; 5207ec681f3Smrg 5217ec681f3Smrg /* Allocate space in the buffer for storing the clear color. On modern 5227ec681f3Smrg * platforms (gen > 9), we can read it directly from such buffer. 5237ec681f3Smrg * 5247ec681f3Smrg * On gen <= 9, we are going to store the clear color on the buffer 5257ec681f3Smrg * anyways, and copy it back to the surface state during state emission. 5267ec681f3Smrg * 5277ec681f3Smrg * Also add some padding to make sure the fast clear color state buffer 5287ec681f3Smrg * starts at a 4K alignment. We believe that 256B might be enough, but due 5297ec681f3Smrg * to lack of testing we will leave this as 4K for now. 5307ec681f3Smrg */ 5317ec681f3Smrg size = ALIGN(size, 4096); 5327ec681f3Smrg *aux_size_B = size; 5337ec681f3Smrg 5347ec681f3Smrg if (isl_aux_usage_has_hiz(res->aux.usage)) { 5357ec681f3Smrg for (unsigned level = 0; level < res->surf.levels; ++level) { 5367ec681f3Smrg uint32_t width = u_minify(res->surf.phys_level0_sa.width, level); 5377ec681f3Smrg uint32_t height = u_minify(res->surf.phys_level0_sa.height, level); 5387ec681f3Smrg 5397ec681f3Smrg /* Disable HiZ for LOD > 0 unless the width/height are 8x4 aligned. 5407ec681f3Smrg * For LOD == 0, we can grow the dimensions to make it work. 5417ec681f3Smrg */ 5427ec681f3Smrg if (devinfo->verx10 < 75 || 5437ec681f3Smrg (level == 0 || ((width & 7) == 0 && (height & 3) == 0))) 5447ec681f3Smrg res->aux.has_hiz |= 1 << level; 5457ec681f3Smrg } 5467ec681f3Smrg } 5477ec681f3Smrg 5487ec681f3Smrg return true; 5497ec681f3Smrg} 5507ec681f3Smrg 5517ec681f3Smrg/** 5527ec681f3Smrg * Initialize the aux buffer contents. 5537ec681f3Smrg * 5547ec681f3Smrg * Returns false on unexpected error (e.g. mapping a BO failed). 5557ec681f3Smrg */ 5567ec681f3Smrgstatic bool 5577ec681f3Smrgcrocus_resource_init_aux_buf(struct crocus_resource *res, uint32_t alloc_flags) 5587ec681f3Smrg{ 5597ec681f3Smrg if (!(alloc_flags & BO_ALLOC_ZEROED)) { 5607ec681f3Smrg void *map = crocus_bo_map(NULL, res->aux.bo, MAP_WRITE | MAP_RAW); 5617ec681f3Smrg 5627ec681f3Smrg if (!map) 5637ec681f3Smrg return false; 5647ec681f3Smrg 5657ec681f3Smrg if (crocus_resource_get_aux_state(res, 0, 0) != ISL_AUX_STATE_AUX_INVALID) { 5667ec681f3Smrg uint8_t memset_value = isl_aux_usage_has_mcs(res->aux.usage) ? 0xFF : 0; 5677ec681f3Smrg memset((char*)map + res->aux.offset, memset_value, 5687ec681f3Smrg res->aux.surf.size_B); 5697ec681f3Smrg } 5707ec681f3Smrg 5717ec681f3Smrg crocus_bo_unmap(res->aux.bo); 5727ec681f3Smrg } 5737ec681f3Smrg 5747ec681f3Smrg return true; 5757ec681f3Smrg} 5767ec681f3Smrg 5777ec681f3Smrg/** 5787ec681f3Smrg * Allocate the initial aux surface for a resource based on aux.usage 5797ec681f3Smrg * 5807ec681f3Smrg * Returns false on unexpected error (e.g. allocation failed, or invalid 5817ec681f3Smrg * configuration result). 5827ec681f3Smrg */ 5837ec681f3Smrgstatic bool 5847ec681f3Smrgcrocus_resource_alloc_separate_aux(struct crocus_screen *screen, 5857ec681f3Smrg struct crocus_resource *res) 5867ec681f3Smrg{ 5877ec681f3Smrg uint32_t alloc_flags; 5887ec681f3Smrg uint64_t size; 5897ec681f3Smrg if (!crocus_resource_configure_aux(screen, res, false, &size, &alloc_flags)) 5907ec681f3Smrg return false; 5917ec681f3Smrg 5927ec681f3Smrg if (size == 0) 5937ec681f3Smrg return true; 5947ec681f3Smrg 5957ec681f3Smrg /* Allocate the auxiliary buffer. ISL has stricter set of alignment rules 5967ec681f3Smrg * the drm allocator. Therefore, one can pass the ISL dimensions in terms 5977ec681f3Smrg * of bytes instead of trying to recalculate based on different format 5987ec681f3Smrg * block sizes. 5997ec681f3Smrg */ 6007ec681f3Smrg res->aux.bo = crocus_bo_alloc_tiled(screen->bufmgr, "aux buffer", size, 4096, 6017ec681f3Smrg isl_tiling_to_i915_tiling(res->aux.surf.tiling), 6027ec681f3Smrg res->aux.surf.row_pitch_B, alloc_flags); 6037ec681f3Smrg if (!res->aux.bo) { 6047ec681f3Smrg return false; 6057ec681f3Smrg } 6067ec681f3Smrg 6077ec681f3Smrg if (!crocus_resource_init_aux_buf(res, alloc_flags)) 6087ec681f3Smrg return false; 6097ec681f3Smrg 6107ec681f3Smrg return true; 6117ec681f3Smrg} 6127ec681f3Smrg 6137ec681f3Smrgvoid 6147ec681f3Smrgcrocus_resource_finish_aux_import(struct pipe_screen *pscreen, 6157ec681f3Smrg struct crocus_resource *res) 6167ec681f3Smrg{ 6177ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *)pscreen; 6187ec681f3Smrg assert(crocus_resource_unfinished_aux_import(res)); 6197ec681f3Smrg assert(!res->mod_info->supports_clear_color); 6207ec681f3Smrg 6217ec681f3Smrg struct crocus_resource *aux_res = (void *) res->base.b.next; 6227ec681f3Smrg assert(aux_res->aux.surf.row_pitch_B && aux_res->aux.offset && 6237ec681f3Smrg aux_res->aux.bo); 6247ec681f3Smrg 6257ec681f3Smrg assert(res->bo == aux_res->aux.bo); 6267ec681f3Smrg crocus_bo_reference(aux_res->aux.bo); 6277ec681f3Smrg res->aux.bo = aux_res->aux.bo; 6287ec681f3Smrg 6297ec681f3Smrg res->aux.offset = aux_res->aux.offset; 6307ec681f3Smrg 6317ec681f3Smrg assert(res->bo->size >= (res->aux.offset + res->aux.surf.size_B)); 6327ec681f3Smrg assert(aux_res->aux.surf.row_pitch_B == res->aux.surf.row_pitch_B); 6337ec681f3Smrg 6347ec681f3Smrg crocus_resource_destroy(&screen->base, res->base.b.next); 6357ec681f3Smrg res->base.b.next = NULL; 6367ec681f3Smrg} 6377ec681f3Smrg 6387ec681f3Smrgstatic struct pipe_resource * 6397ec681f3Smrgcrocus_resource_create_for_buffer(struct pipe_screen *pscreen, 6407ec681f3Smrg const struct pipe_resource *templ) 6417ec681f3Smrg{ 6427ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *)pscreen; 6437ec681f3Smrg struct crocus_resource *res = crocus_alloc_resource(pscreen, templ); 6447ec681f3Smrg 6457ec681f3Smrg assert(templ->target == PIPE_BUFFER); 6467ec681f3Smrg assert(templ->height0 <= 1); 6477ec681f3Smrg assert(templ->depth0 <= 1); 6487ec681f3Smrg assert(templ->format == PIPE_FORMAT_NONE || 6497ec681f3Smrg util_format_get_blocksize(templ->format) == 1); 6507ec681f3Smrg 6517ec681f3Smrg res->internal_format = templ->format; 6527ec681f3Smrg res->surf.tiling = ISL_TILING_LINEAR; 6537ec681f3Smrg 6547ec681f3Smrg const char *name = templ->target == PIPE_BUFFER ? "buffer" : "miptree"; 6557ec681f3Smrg 6567ec681f3Smrg res->bo = crocus_bo_alloc(screen->bufmgr, name, templ->width0); 6577ec681f3Smrg if (!res->bo) { 6587ec681f3Smrg crocus_resource_destroy(pscreen, &res->base.b); 6597ec681f3Smrg return NULL; 6607ec681f3Smrg } 6617ec681f3Smrg 6627ec681f3Smrg return &res->base.b; 6637ec681f3Smrg} 6647ec681f3Smrg 6657ec681f3Smrgstatic struct pipe_resource * 6667ec681f3Smrgcrocus_resource_create_with_modifiers(struct pipe_screen *pscreen, 6677ec681f3Smrg const struct pipe_resource *templ, 6687ec681f3Smrg const uint64_t *modifiers, 6697ec681f3Smrg int modifiers_count) 6707ec681f3Smrg{ 6717ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *)pscreen; 6727ec681f3Smrg struct intel_device_info *devinfo = &screen->devinfo; 6737ec681f3Smrg struct crocus_resource *res = crocus_alloc_resource(pscreen, templ); 6747ec681f3Smrg 6757ec681f3Smrg if (!res) 6767ec681f3Smrg return NULL; 6777ec681f3Smrg 6787ec681f3Smrg uint64_t modifier = 6797ec681f3Smrg select_best_modifier(devinfo, templ, modifiers, modifiers_count); 6807ec681f3Smrg 6817ec681f3Smrg if (modifier == DRM_FORMAT_MOD_INVALID && modifiers_count > 0) { 6827ec681f3Smrg fprintf(stderr, "Unsupported modifier, resource creation failed.\n"); 6837ec681f3Smrg goto fail; 6847ec681f3Smrg } 6857ec681f3Smrg 6867ec681f3Smrg if (templ->usage == PIPE_USAGE_STAGING && 6877ec681f3Smrg templ->bind == PIPE_BIND_DEPTH_STENCIL && 6887ec681f3Smrg devinfo->ver < 6) 6897ec681f3Smrg return NULL; 6907ec681f3Smrg 6917ec681f3Smrg const bool isl_surf_created_successfully = 6927ec681f3Smrg crocus_resource_configure_main(screen, res, templ, modifier, 0); 6937ec681f3Smrg if (!isl_surf_created_successfully) 6947ec681f3Smrg return NULL; 6957ec681f3Smrg 6967ec681f3Smrg const char *name = "miptree"; 6977ec681f3Smrg 6987ec681f3Smrg unsigned int flags = 0; 6997ec681f3Smrg if (templ->usage == PIPE_USAGE_STAGING) 7007ec681f3Smrg flags |= BO_ALLOC_COHERENT; 7017ec681f3Smrg 7027ec681f3Smrg uint64_t aux_size = 0; 7037ec681f3Smrg uint32_t aux_preferred_alloc_flags; 7047ec681f3Smrg 7057ec681f3Smrg if (!crocus_resource_configure_aux(screen, res, false, &aux_size, 7067ec681f3Smrg &aux_preferred_alloc_flags)) { 7077ec681f3Smrg goto fail; 7087ec681f3Smrg } 7097ec681f3Smrg 7107ec681f3Smrg /* Modifiers require the aux data to be in the same buffer as the main 7117ec681f3Smrg * surface, but we combine them even when a modifiers is not being used. 7127ec681f3Smrg */ 7137ec681f3Smrg const uint64_t bo_size = 7147ec681f3Smrg MAX2(res->surf.size_B, res->aux.offset + aux_size); 7157ec681f3Smrg uint32_t alignment = MAX2(4096, res->surf.alignment_B); 7167ec681f3Smrg res->bo = crocus_bo_alloc_tiled(screen->bufmgr, name, bo_size, alignment, 7177ec681f3Smrg isl_tiling_to_i915_tiling(res->surf.tiling), 7187ec681f3Smrg res->surf.row_pitch_B, flags); 7197ec681f3Smrg 7207ec681f3Smrg if (!res->bo) 7217ec681f3Smrg goto fail; 7227ec681f3Smrg 7237ec681f3Smrg if (aux_size > 0) { 7247ec681f3Smrg res->aux.bo = res->bo; 7257ec681f3Smrg crocus_bo_reference(res->aux.bo); 7267ec681f3Smrg if (!crocus_resource_init_aux_buf(res, flags)) 7277ec681f3Smrg goto fail; 7287ec681f3Smrg } 7297ec681f3Smrg 7307ec681f3Smrg if (templ->format == PIPE_FORMAT_S8_UINT && !(templ->usage == PIPE_USAGE_STAGING) && 7317ec681f3Smrg devinfo->ver == 7 && (templ->bind & PIPE_BIND_SAMPLER_VIEW)) { 7327ec681f3Smrg struct pipe_resource templ_shadow = (struct pipe_resource) { 7337ec681f3Smrg .usage = 0, 7347ec681f3Smrg .bind = PIPE_BIND_SAMPLER_VIEW, 7357ec681f3Smrg .width0 = res->base.b.width0, 7367ec681f3Smrg .height0 = res->base.b.height0, 7377ec681f3Smrg .depth0 = res->base.b.depth0, 7387ec681f3Smrg .last_level = res->base.b.last_level, 7397ec681f3Smrg .nr_samples = res->base.b.nr_samples, 7407ec681f3Smrg .nr_storage_samples = res->base.b.nr_storage_samples, 7417ec681f3Smrg .array_size = res->base.b.array_size, 7427ec681f3Smrg .format = PIPE_FORMAT_R8_UINT, 7437ec681f3Smrg .target = res->base.b.target, 7447ec681f3Smrg }; 7457ec681f3Smrg res->shadow = (struct crocus_resource *)screen->base.resource_create(&screen->base, &templ_shadow); 7467ec681f3Smrg assert(res->shadow); 7477ec681f3Smrg } 7487ec681f3Smrg 7497ec681f3Smrg return &res->base.b; 7507ec681f3Smrg 7517ec681f3Smrgfail: 7527ec681f3Smrg fprintf(stderr, "XXX: resource creation failed\n"); 7537ec681f3Smrg crocus_resource_destroy(pscreen, &res->base.b); 7547ec681f3Smrg return NULL; 7557ec681f3Smrg 7567ec681f3Smrg} 7577ec681f3Smrg 7587ec681f3Smrgstatic struct pipe_resource * 7597ec681f3Smrgcrocus_resource_create(struct pipe_screen *pscreen, 7607ec681f3Smrg const struct pipe_resource *templ) 7617ec681f3Smrg{ 7627ec681f3Smrg if (templ->target == PIPE_BUFFER) 7637ec681f3Smrg return crocus_resource_create_for_buffer(pscreen, templ); 7647ec681f3Smrg else 7657ec681f3Smrg return crocus_resource_create_with_modifiers(pscreen, templ, NULL, 0); 7667ec681f3Smrg} 7677ec681f3Smrg 7687ec681f3Smrgstatic uint64_t 7697ec681f3Smrgtiling_to_modifier(uint32_t tiling) 7707ec681f3Smrg{ 7717ec681f3Smrg static const uint64_t map[] = { 7727ec681f3Smrg [I915_TILING_NONE] = DRM_FORMAT_MOD_LINEAR, 7737ec681f3Smrg [I915_TILING_X] = I915_FORMAT_MOD_X_TILED, 7747ec681f3Smrg [I915_TILING_Y] = I915_FORMAT_MOD_Y_TILED, 7757ec681f3Smrg }; 7767ec681f3Smrg 7777ec681f3Smrg assert(tiling < ARRAY_SIZE(map)); 7787ec681f3Smrg 7797ec681f3Smrg return map[tiling]; 7807ec681f3Smrg} 7817ec681f3Smrg 7827ec681f3Smrgstatic struct pipe_resource * 7837ec681f3Smrgcrocus_resource_from_user_memory(struct pipe_screen *pscreen, 7847ec681f3Smrg const struct pipe_resource *templ, 7857ec681f3Smrg void *user_memory) 7867ec681f3Smrg{ 7877ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *)pscreen; 7887ec681f3Smrg struct crocus_bufmgr *bufmgr = screen->bufmgr; 7897ec681f3Smrg struct crocus_resource *res = crocus_alloc_resource(pscreen, templ); 7907ec681f3Smrg if (!res) 7917ec681f3Smrg return NULL; 7927ec681f3Smrg 7937ec681f3Smrg assert(templ->target == PIPE_BUFFER); 7947ec681f3Smrg 7957ec681f3Smrg res->internal_format = templ->format; 7967ec681f3Smrg res->bo = crocus_bo_create_userptr(bufmgr, "user", 7977ec681f3Smrg user_memory, templ->width0); 7987ec681f3Smrg if (!res->bo) { 7997ec681f3Smrg free(res); 8007ec681f3Smrg return NULL; 8017ec681f3Smrg } 8027ec681f3Smrg 8037ec681f3Smrg util_range_add(&res->base.b, &res->valid_buffer_range, 0, templ->width0); 8047ec681f3Smrg 8057ec681f3Smrg return &res->base.b; 8067ec681f3Smrg} 8077ec681f3Smrg 8087ec681f3Smrgstatic struct pipe_resource * 8097ec681f3Smrgcrocus_resource_from_handle(struct pipe_screen *pscreen, 8107ec681f3Smrg const struct pipe_resource *templ, 8117ec681f3Smrg struct winsys_handle *whandle, 8127ec681f3Smrg unsigned usage) 8137ec681f3Smrg{ 8147ec681f3Smrg assert(templ->target != PIPE_BUFFER); 8157ec681f3Smrg 8167ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *)pscreen; 8177ec681f3Smrg struct crocus_bufmgr *bufmgr = screen->bufmgr; 8187ec681f3Smrg struct crocus_resource *res = crocus_alloc_resource(pscreen, templ); 8197ec681f3Smrg 8207ec681f3Smrg if (!res) 8217ec681f3Smrg return NULL; 8227ec681f3Smrg 8237ec681f3Smrg switch (whandle->type) { 8247ec681f3Smrg case WINSYS_HANDLE_TYPE_FD: 8257ec681f3Smrg res->bo = crocus_bo_import_dmabuf(bufmgr, whandle->handle, 8267ec681f3Smrg whandle->modifier); 8277ec681f3Smrg break; 8287ec681f3Smrg case WINSYS_HANDLE_TYPE_SHARED: 8297ec681f3Smrg res->bo = crocus_bo_gem_create_from_name(bufmgr, "winsys image", 8307ec681f3Smrg whandle->handle); 8317ec681f3Smrg break; 8327ec681f3Smrg default: 8337ec681f3Smrg unreachable("invalid winsys handle type"); 8347ec681f3Smrg } 8357ec681f3Smrg if (!res->bo) 8367ec681f3Smrg return NULL; 8377ec681f3Smrg 8387ec681f3Smrg res->offset = whandle->offset; 8397ec681f3Smrg res->external_format = whandle->format; 8407ec681f3Smrg 8417ec681f3Smrg if (whandle->plane < util_format_get_num_planes(whandle->format)) { 8427ec681f3Smrg const uint64_t modifier = 8437ec681f3Smrg whandle->modifier != DRM_FORMAT_MOD_INVALID ? 8447ec681f3Smrg whandle->modifier : tiling_to_modifier(res->bo->tiling_mode); 8457ec681f3Smrg 8467ec681f3Smrg UNUSED const bool isl_surf_created_successfully = 8477ec681f3Smrg crocus_resource_configure_main(screen, res, templ, modifier, 8487ec681f3Smrg whandle->stride); 8497ec681f3Smrg assert(isl_surf_created_successfully); 8507ec681f3Smrg assert(res->bo->tiling_mode == 8517ec681f3Smrg isl_tiling_to_i915_tiling(res->surf.tiling)); 8527ec681f3Smrg 8537ec681f3Smrg // XXX: create_ccs_buf_for_image? 8547ec681f3Smrg if (whandle->modifier == DRM_FORMAT_MOD_INVALID) { 8557ec681f3Smrg if (!crocus_resource_alloc_separate_aux(screen, res)) 8567ec681f3Smrg goto fail; 8577ec681f3Smrg } else { 8587ec681f3Smrg if (res->mod_info->aux_usage != ISL_AUX_USAGE_NONE) { 8597ec681f3Smrg uint32_t alloc_flags; 8607ec681f3Smrg uint64_t size; 8617ec681f3Smrg UNUSED bool ok = crocus_resource_configure_aux(screen, res, true, &size, 8627ec681f3Smrg &alloc_flags); 8637ec681f3Smrg assert(ok); 8647ec681f3Smrg /* The gallium dri layer will create a separate plane resource 8657ec681f3Smrg * for the aux image. crocus_resource_finish_aux_import will 8667ec681f3Smrg * merge the separate aux parameters back into a single 8677ec681f3Smrg * crocus_resource. 8687ec681f3Smrg */ 8697ec681f3Smrg } 8707ec681f3Smrg } 8717ec681f3Smrg } else { 8727ec681f3Smrg /* Save modifier import information to reconstruct later. After 8737ec681f3Smrg * import, this will be available under a second image accessible 8747ec681f3Smrg * from the main image with res->base.next. See 8757ec681f3Smrg * crocus_resource_finish_aux_import. 8767ec681f3Smrg */ 8777ec681f3Smrg res->aux.surf.row_pitch_B = whandle->stride; 8787ec681f3Smrg res->aux.offset = whandle->offset; 8797ec681f3Smrg res->aux.bo = res->bo; 8807ec681f3Smrg res->bo = NULL; 8817ec681f3Smrg } 8827ec681f3Smrg 8837ec681f3Smrg return &res->base.b; 8847ec681f3Smrg 8857ec681f3Smrgfail: 8867ec681f3Smrg crocus_resource_destroy(pscreen, &res->base.b); 8877ec681f3Smrg return NULL; 8887ec681f3Smrg} 8897ec681f3Smrg 8907ec681f3Smrgstatic struct pipe_resource * 8917ec681f3Smrgcrocus_resource_from_memobj(struct pipe_screen *pscreen, 8927ec681f3Smrg const struct pipe_resource *templ, 8937ec681f3Smrg struct pipe_memory_object *pmemobj, 8947ec681f3Smrg uint64_t offset) 8957ec681f3Smrg{ 8967ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *)pscreen; 8977ec681f3Smrg struct crocus_memory_object *memobj = (struct crocus_memory_object *)pmemobj; 8987ec681f3Smrg struct crocus_resource *res = crocus_alloc_resource(pscreen, templ); 8997ec681f3Smrg 9007ec681f3Smrg if (!res) 9017ec681f3Smrg return NULL; 9027ec681f3Smrg 9037ec681f3Smrg /* Disable Depth, and combined Depth+Stencil for now. */ 9047ec681f3Smrg if (util_format_has_depth(util_format_description(templ->format))) 9057ec681f3Smrg return NULL; 9067ec681f3Smrg 9077ec681f3Smrg if (templ->flags & PIPE_RESOURCE_FLAG_TEXTURING_MORE_LIKELY) { 9087ec681f3Smrg UNUSED const bool isl_surf_created_successfully = 9097ec681f3Smrg crocus_resource_configure_main(screen, res, templ, DRM_FORMAT_MOD_INVALID, 0); 9107ec681f3Smrg assert(isl_surf_created_successfully); 9117ec681f3Smrg } 9127ec681f3Smrg 9137ec681f3Smrg res->bo = memobj->bo; 9147ec681f3Smrg res->offset = offset; 9157ec681f3Smrg res->external_format = memobj->format; 9167ec681f3Smrg 9177ec681f3Smrg crocus_bo_reference(memobj->bo); 9187ec681f3Smrg 9197ec681f3Smrg return &res->base.b; 9207ec681f3Smrg} 9217ec681f3Smrg 9227ec681f3Smrgstatic void 9237ec681f3Smrgcrocus_flush_resource(struct pipe_context *ctx, struct pipe_resource *resource) 9247ec681f3Smrg{ 9257ec681f3Smrg struct crocus_context *ice = (struct crocus_context *)ctx; 9267ec681f3Smrg struct crocus_resource *res = (void *) resource; 9277ec681f3Smrg const struct isl_drm_modifier_info *mod = res->mod_info; 9287ec681f3Smrg 9297ec681f3Smrg crocus_resource_prepare_access(ice, res, 9307ec681f3Smrg 0, INTEL_REMAINING_LEVELS, 9317ec681f3Smrg 0, INTEL_REMAINING_LAYERS, 9327ec681f3Smrg mod ? mod->aux_usage : ISL_AUX_USAGE_NONE, 9337ec681f3Smrg mod ? mod->supports_clear_color : false); 9347ec681f3Smrg} 9357ec681f3Smrg 9367ec681f3Smrgstatic void 9377ec681f3Smrgcrocus_resource_disable_aux_on_first_query(struct pipe_resource *resource, 9387ec681f3Smrg unsigned usage) 9397ec681f3Smrg{ 9407ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *)resource; 9417ec681f3Smrg bool mod_with_aux = 9427ec681f3Smrg res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 9437ec681f3Smrg 9447ec681f3Smrg /* Disable aux usage if explicit flush not set and this is the first time 9457ec681f3Smrg * we are dealing with this resource and the resource was not created with 9467ec681f3Smrg * a modifier with aux. 9477ec681f3Smrg */ 9487ec681f3Smrg if (!mod_with_aux && 9497ec681f3Smrg (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH) && res->aux.usage != 0) && 9507ec681f3Smrg p_atomic_read(&resource->reference.count) == 1) { 9517ec681f3Smrg crocus_resource_disable_aux(res); 9527ec681f3Smrg } 9537ec681f3Smrg} 9547ec681f3Smrg 9557ec681f3Smrgstatic bool 9567ec681f3Smrgcrocus_resource_get_param(struct pipe_screen *pscreen, 9577ec681f3Smrg struct pipe_context *context, 9587ec681f3Smrg struct pipe_resource *resource, 9597ec681f3Smrg unsigned plane, 9607ec681f3Smrg unsigned layer, 9617ec681f3Smrg unsigned level, 9627ec681f3Smrg enum pipe_resource_param param, 9637ec681f3Smrg unsigned handle_usage, 9647ec681f3Smrg uint64_t *value) 9657ec681f3Smrg{ 9667ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *)pscreen; 9677ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *)resource; 9687ec681f3Smrg bool mod_with_aux = 9697ec681f3Smrg res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 9707ec681f3Smrg bool wants_aux = mod_with_aux && plane > 0; 9717ec681f3Smrg bool result; 9727ec681f3Smrg unsigned handle; 9737ec681f3Smrg 9747ec681f3Smrg if (crocus_resource_unfinished_aux_import(res)) 9757ec681f3Smrg crocus_resource_finish_aux_import(pscreen, res); 9767ec681f3Smrg 9777ec681f3Smrg struct crocus_bo *bo = wants_aux ? res->aux.bo : res->bo; 9787ec681f3Smrg 9797ec681f3Smrg crocus_resource_disable_aux_on_first_query(resource, handle_usage); 9807ec681f3Smrg 9817ec681f3Smrg switch (param) { 9827ec681f3Smrg case PIPE_RESOURCE_PARAM_NPLANES: 9837ec681f3Smrg if (mod_with_aux) { 9847ec681f3Smrg *value = util_format_get_num_planes(res->external_format); 9857ec681f3Smrg } else { 9867ec681f3Smrg unsigned count = 0; 9877ec681f3Smrg for (struct pipe_resource *cur = resource; cur; cur = cur->next) 9887ec681f3Smrg count++; 9897ec681f3Smrg *value = count; 9907ec681f3Smrg } 9917ec681f3Smrg return true; 9927ec681f3Smrg case PIPE_RESOURCE_PARAM_STRIDE: 9937ec681f3Smrg *value = wants_aux ? res->aux.surf.row_pitch_B : res->surf.row_pitch_B; 9947ec681f3Smrg return true; 9957ec681f3Smrg case PIPE_RESOURCE_PARAM_OFFSET: 9967ec681f3Smrg *value = wants_aux ? res->aux.offset : 0; 9977ec681f3Smrg return true; 9987ec681f3Smrg case PIPE_RESOURCE_PARAM_MODIFIER: 9997ec681f3Smrg *value = res->mod_info ? res->mod_info->modifier : 10007ec681f3Smrg tiling_to_modifier(isl_tiling_to_i915_tiling(res->surf.tiling)); 10017ec681f3Smrg return true; 10027ec681f3Smrg case PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED: 10037ec681f3Smrg result = crocus_bo_flink(bo, &handle) == 0; 10047ec681f3Smrg if (result) 10057ec681f3Smrg *value = handle; 10067ec681f3Smrg return result; 10077ec681f3Smrg case PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS: { 10087ec681f3Smrg /* Because we share the same drm file across multiple crocus_screen, when 10097ec681f3Smrg * we export a GEM handle we must make sure it is valid in the DRM file 10107ec681f3Smrg * descriptor the caller is using (this is the FD given at screen 10117ec681f3Smrg * creation). 10127ec681f3Smrg */ 10137ec681f3Smrg uint32_t handle; 10147ec681f3Smrg if (crocus_bo_export_gem_handle_for_device(bo, screen->winsys_fd, &handle)) 10157ec681f3Smrg return false; 10167ec681f3Smrg *value = handle; 10177ec681f3Smrg return true; 10187ec681f3Smrg } 10197ec681f3Smrg case PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD: 10207ec681f3Smrg result = crocus_bo_export_dmabuf(bo, (int *) &handle) == 0; 10217ec681f3Smrg if (result) 10227ec681f3Smrg *value = handle; 10237ec681f3Smrg return result; 10247ec681f3Smrg default: 10257ec681f3Smrg return false; 10267ec681f3Smrg } 10277ec681f3Smrg} 10287ec681f3Smrg 10297ec681f3Smrgstatic bool 10307ec681f3Smrgcrocus_resource_get_handle(struct pipe_screen *pscreen, 10317ec681f3Smrg struct pipe_context *ctx, 10327ec681f3Smrg struct pipe_resource *resource, 10337ec681f3Smrg struct winsys_handle *whandle, 10347ec681f3Smrg unsigned usage) 10357ec681f3Smrg{ 10367ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *) pscreen; 10377ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *)resource; 10387ec681f3Smrg bool mod_with_aux = 10397ec681f3Smrg res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE; 10407ec681f3Smrg 10417ec681f3Smrg crocus_resource_disable_aux_on_first_query(resource, usage); 10427ec681f3Smrg 10437ec681f3Smrg struct crocus_bo *bo; 10447ec681f3Smrg if (mod_with_aux && whandle->plane > 0) { 10457ec681f3Smrg assert(res->aux.bo); 10467ec681f3Smrg bo = res->aux.bo; 10477ec681f3Smrg whandle->stride = res->aux.surf.row_pitch_B; 10487ec681f3Smrg whandle->offset = res->aux.offset; 10497ec681f3Smrg } else { 10507ec681f3Smrg /* If this is a buffer, stride should be 0 - no need to special case */ 10517ec681f3Smrg whandle->stride = res->surf.row_pitch_B; 10527ec681f3Smrg bo = res->bo; 10537ec681f3Smrg } 10547ec681f3Smrg whandle->format = res->external_format; 10557ec681f3Smrg whandle->modifier = 10567ec681f3Smrg res->mod_info ? res->mod_info->modifier 10577ec681f3Smrg : tiling_to_modifier(res->bo->tiling_mode); 10587ec681f3Smrg 10597ec681f3Smrg#ifndef NDEBUG 10607ec681f3Smrg enum isl_aux_usage allowed_usage = 10617ec681f3Smrg res->mod_info ? res->mod_info->aux_usage : ISL_AUX_USAGE_NONE; 10627ec681f3Smrg 10637ec681f3Smrg if (res->aux.usage != allowed_usage) { 10647ec681f3Smrg enum isl_aux_state aux_state = crocus_resource_get_aux_state(res, 0, 0); 10657ec681f3Smrg assert(aux_state == ISL_AUX_STATE_RESOLVED || 10667ec681f3Smrg aux_state == ISL_AUX_STATE_PASS_THROUGH); 10677ec681f3Smrg } 10687ec681f3Smrg#endif 10697ec681f3Smrg 10707ec681f3Smrg switch (whandle->type) { 10717ec681f3Smrg case WINSYS_HANDLE_TYPE_SHARED: 10727ec681f3Smrg return crocus_bo_flink(bo, &whandle->handle) == 0; 10737ec681f3Smrg case WINSYS_HANDLE_TYPE_KMS: { 10747ec681f3Smrg /* Because we share the same drm file across multiple crocus_screen, when 10757ec681f3Smrg * we export a GEM handle we must make sure it is valid in the DRM file 10767ec681f3Smrg * descriptor the caller is using (this is the FD given at screen 10777ec681f3Smrg * creation). 10787ec681f3Smrg */ 10797ec681f3Smrg uint32_t handle; 10807ec681f3Smrg if (crocus_bo_export_gem_handle_for_device(bo, screen->winsys_fd, &handle)) 10817ec681f3Smrg return false; 10827ec681f3Smrg whandle->handle = handle; 10837ec681f3Smrg return true; 10847ec681f3Smrg } 10857ec681f3Smrg case WINSYS_HANDLE_TYPE_FD: 10867ec681f3Smrg return crocus_bo_export_dmabuf(bo, (int *) &whandle->handle) == 0; 10877ec681f3Smrg } 10887ec681f3Smrg 10897ec681f3Smrg return false; 10907ec681f3Smrg} 10917ec681f3Smrg 10927ec681f3Smrgstatic bool 10937ec681f3Smrgresource_is_busy(struct crocus_context *ice, 10947ec681f3Smrg struct crocus_resource *res) 10957ec681f3Smrg{ 10967ec681f3Smrg bool busy = crocus_bo_busy(res->bo); 10977ec681f3Smrg 10987ec681f3Smrg for (int i = 0; i < ice->batch_count; i++) 10997ec681f3Smrg busy |= crocus_batch_references(&ice->batches[i], res->bo); 11007ec681f3Smrg 11017ec681f3Smrg return busy; 11027ec681f3Smrg} 11037ec681f3Smrg 11047ec681f3Smrgvoid 11057ec681f3Smrgcrocus_replace_buffer_storage(struct pipe_context *ctx, 11067ec681f3Smrg struct pipe_resource *p_dst, 11077ec681f3Smrg struct pipe_resource *p_src, 11087ec681f3Smrg unsigned num_rebinds, 11097ec681f3Smrg uint32_t rebind_mask, 11107ec681f3Smrg uint32_t delete_buffer_id) 11117ec681f3Smrg{ 11127ec681f3Smrg struct crocus_screen *screen = (void *) ctx->screen; 11137ec681f3Smrg struct crocus_context *ice = (void *) ctx; 11147ec681f3Smrg struct crocus_resource *dst = (void *) p_dst; 11157ec681f3Smrg struct crocus_resource *src = (void *) p_src; 11167ec681f3Smrg 11177ec681f3Smrg assert(memcmp(&dst->surf, &src->surf, sizeof(dst->surf)) == 0); 11187ec681f3Smrg 11197ec681f3Smrg struct crocus_bo *old_bo = dst->bo; 11207ec681f3Smrg 11217ec681f3Smrg /* Swap out the backing storage */ 11227ec681f3Smrg crocus_bo_reference(src->bo); 11237ec681f3Smrg dst->bo = src->bo; 11247ec681f3Smrg 11257ec681f3Smrg /* Rebind the buffer, replacing any state referring to the old BO's 11267ec681f3Smrg * address, and marking state dirty so it's reemitted. 11277ec681f3Smrg */ 11287ec681f3Smrg screen->vtbl.rebind_buffer(ice, dst); 11297ec681f3Smrg 11307ec681f3Smrg crocus_bo_unreference(old_bo); 11317ec681f3Smrg} 11327ec681f3Smrg 11337ec681f3Smrgstatic void 11347ec681f3Smrgcrocus_invalidate_resource(struct pipe_context *ctx, 11357ec681f3Smrg struct pipe_resource *resource) 11367ec681f3Smrg{ 11377ec681f3Smrg struct crocus_screen *screen = (void *) ctx->screen; 11387ec681f3Smrg struct crocus_context *ice = (void *) ctx; 11397ec681f3Smrg struct crocus_resource *res = (void *) resource; 11407ec681f3Smrg 11417ec681f3Smrg if (resource->target != PIPE_BUFFER) 11427ec681f3Smrg return; 11437ec681f3Smrg 11447ec681f3Smrg /* If it's already invalidated, don't bother doing anything. */ 11457ec681f3Smrg if (res->valid_buffer_range.start > res->valid_buffer_range.end) 11467ec681f3Smrg return; 11477ec681f3Smrg 11487ec681f3Smrg if (!resource_is_busy(ice, res)) { 11497ec681f3Smrg /* The resource is idle, so just mark that it contains no data and 11507ec681f3Smrg * keep using the same underlying buffer object. 11517ec681f3Smrg */ 11527ec681f3Smrg util_range_set_empty(&res->valid_buffer_range); 11537ec681f3Smrg return; 11547ec681f3Smrg } 11557ec681f3Smrg 11567ec681f3Smrg /* Otherwise, try and replace the backing storage with a new BO. */ 11577ec681f3Smrg 11587ec681f3Smrg /* We can't reallocate memory we didn't allocate in the first place. */ 11597ec681f3Smrg if (res->bo->userptr) 11607ec681f3Smrg return; 11617ec681f3Smrg 11627ec681f3Smrg struct crocus_bo *old_bo = res->bo; 11637ec681f3Smrg struct crocus_bo *new_bo = 11647ec681f3Smrg crocus_bo_alloc(screen->bufmgr, res->bo->name, resource->width0); 11657ec681f3Smrg 11667ec681f3Smrg if (!new_bo) 11677ec681f3Smrg return; 11687ec681f3Smrg 11697ec681f3Smrg /* Swap out the backing storage */ 11707ec681f3Smrg res->bo = new_bo; 11717ec681f3Smrg 11727ec681f3Smrg /* Rebind the buffer, replacing any state referring to the old BO's 11737ec681f3Smrg * address, and marking state dirty so it's reemitted. 11747ec681f3Smrg */ 11757ec681f3Smrg screen->vtbl.rebind_buffer(ice, res); 11767ec681f3Smrg 11777ec681f3Smrg util_range_set_empty(&res->valid_buffer_range); 11787ec681f3Smrg 11797ec681f3Smrg crocus_bo_unreference(old_bo); 11807ec681f3Smrg} 11817ec681f3Smrg 11827ec681f3Smrgstatic void 11837ec681f3Smrgcrocus_flush_staging_region(struct pipe_transfer *xfer, 11847ec681f3Smrg const struct pipe_box *flush_box) 11857ec681f3Smrg{ 11867ec681f3Smrg if (!(xfer->usage & PIPE_MAP_WRITE)) 11877ec681f3Smrg return; 11887ec681f3Smrg 11897ec681f3Smrg struct crocus_transfer *map = (void *) xfer; 11907ec681f3Smrg 11917ec681f3Smrg struct pipe_box src_box = *flush_box; 11927ec681f3Smrg 11937ec681f3Smrg /* Account for extra alignment padding in staging buffer */ 11947ec681f3Smrg if (xfer->resource->target == PIPE_BUFFER) 11957ec681f3Smrg src_box.x += xfer->box.x % CROCUS_MAP_BUFFER_ALIGNMENT; 11967ec681f3Smrg 11977ec681f3Smrg struct pipe_box dst_box = (struct pipe_box) { 11987ec681f3Smrg .x = xfer->box.x + flush_box->x, 11997ec681f3Smrg .y = xfer->box.y + flush_box->y, 12007ec681f3Smrg .z = xfer->box.z + flush_box->z, 12017ec681f3Smrg .width = flush_box->width, 12027ec681f3Smrg .height = flush_box->height, 12037ec681f3Smrg .depth = flush_box->depth, 12047ec681f3Smrg }; 12057ec681f3Smrg 12067ec681f3Smrg crocus_copy_region(map->blorp, map->batch, xfer->resource, xfer->level, 12077ec681f3Smrg dst_box.x, dst_box.y, dst_box.z, map->staging, 0, 12087ec681f3Smrg &src_box); 12097ec681f3Smrg} 12107ec681f3Smrg 12117ec681f3Smrgstatic void 12127ec681f3Smrgcrocus_unmap_copy_region(struct crocus_transfer *map) 12137ec681f3Smrg{ 12147ec681f3Smrg crocus_resource_destroy(map->staging->screen, map->staging); 12157ec681f3Smrg 12167ec681f3Smrg map->ptr = NULL; 12177ec681f3Smrg} 12187ec681f3Smrg 12197ec681f3Smrgstatic void 12207ec681f3Smrgcrocus_map_copy_region(struct crocus_transfer *map) 12217ec681f3Smrg{ 12227ec681f3Smrg struct pipe_screen *pscreen = &map->batch->screen->base; 12237ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 12247ec681f3Smrg struct pipe_box *box = &xfer->box; 12257ec681f3Smrg struct crocus_resource *res = (void *) xfer->resource; 12267ec681f3Smrg 12277ec681f3Smrg unsigned extra = xfer->resource->target == PIPE_BUFFER ? 12287ec681f3Smrg box->x % CROCUS_MAP_BUFFER_ALIGNMENT : 0; 12297ec681f3Smrg 12307ec681f3Smrg struct pipe_resource templ = (struct pipe_resource) { 12317ec681f3Smrg .usage = PIPE_USAGE_STAGING, 12327ec681f3Smrg .width0 = box->width + extra, 12337ec681f3Smrg .height0 = box->height, 12347ec681f3Smrg .depth0 = 1, 12357ec681f3Smrg .nr_samples = xfer->resource->nr_samples, 12367ec681f3Smrg .nr_storage_samples = xfer->resource->nr_storage_samples, 12377ec681f3Smrg .array_size = box->depth, 12387ec681f3Smrg .format = res->internal_format, 12397ec681f3Smrg }; 12407ec681f3Smrg 12417ec681f3Smrg if (xfer->resource->target == PIPE_BUFFER) 12427ec681f3Smrg templ.target = PIPE_BUFFER; 12437ec681f3Smrg else if (templ.array_size > 1) 12447ec681f3Smrg templ.target = PIPE_TEXTURE_2D_ARRAY; 12457ec681f3Smrg else 12467ec681f3Smrg templ.target = PIPE_TEXTURE_2D; 12477ec681f3Smrg 12487ec681f3Smrg map->staging = crocus_resource_create(pscreen, &templ); 12497ec681f3Smrg assert(map->staging); 12507ec681f3Smrg 12517ec681f3Smrg if (templ.target != PIPE_BUFFER) { 12527ec681f3Smrg struct isl_surf *surf = &((struct crocus_resource *) map->staging)->surf; 12537ec681f3Smrg xfer->stride = isl_surf_get_row_pitch_B(surf); 12547ec681f3Smrg xfer->layer_stride = isl_surf_get_array_pitch(surf); 12557ec681f3Smrg } 12567ec681f3Smrg 12577ec681f3Smrg if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 12587ec681f3Smrg crocus_copy_region(map->blorp, map->batch, map->staging, 0, extra, 0, 0, 12597ec681f3Smrg xfer->resource, xfer->level, box); 12607ec681f3Smrg /* Ensure writes to the staging BO land before we map it below. */ 12617ec681f3Smrg crocus_emit_pipe_control_flush(map->batch, 12627ec681f3Smrg "transfer read: flush before mapping", 12637ec681f3Smrg PIPE_CONTROL_RENDER_TARGET_FLUSH | 12647ec681f3Smrg PIPE_CONTROL_CS_STALL); 12657ec681f3Smrg } 12667ec681f3Smrg 12677ec681f3Smrg struct crocus_bo *staging_bo = crocus_resource_bo(map->staging); 12687ec681f3Smrg 12697ec681f3Smrg if (crocus_batch_references(map->batch, staging_bo)) 12707ec681f3Smrg crocus_batch_flush(map->batch); 12717ec681f3Smrg 12727ec681f3Smrg map->ptr = 12737ec681f3Smrg crocus_bo_map(map->dbg, staging_bo, xfer->usage & MAP_FLAGS) + extra; 12747ec681f3Smrg 12757ec681f3Smrg map->unmap = crocus_unmap_copy_region; 12767ec681f3Smrg} 12777ec681f3Smrg 12787ec681f3Smrgstatic void 12797ec681f3Smrgget_image_offset_el(const struct isl_surf *surf, unsigned level, unsigned z, 12807ec681f3Smrg unsigned *out_x0_el, unsigned *out_y0_el) 12817ec681f3Smrg{ 12827ec681f3Smrg ASSERTED uint32_t z0_el, a0_el; 12837ec681f3Smrg if (surf->dim == ISL_SURF_DIM_3D) { 12847ec681f3Smrg isl_surf_get_image_offset_el(surf, level, 0, z, 12857ec681f3Smrg out_x0_el, out_y0_el, &z0_el, &a0_el); 12867ec681f3Smrg } else { 12877ec681f3Smrg isl_surf_get_image_offset_el(surf, level, z, 0, 12887ec681f3Smrg out_x0_el, out_y0_el, &z0_el, &a0_el); 12897ec681f3Smrg } 12907ec681f3Smrg assert(z0_el == 0 && a0_el == 0); 12917ec681f3Smrg} 12927ec681f3Smrg 12937ec681f3Smrgvoid 12947ec681f3Smrgcrocus_resource_get_image_offset(struct crocus_resource *res, 12957ec681f3Smrg uint32_t level, uint32_t z, 12967ec681f3Smrg uint32_t *x, uint32_t *y) 12977ec681f3Smrg{ 12987ec681f3Smrg get_image_offset_el(&res->surf, level, z, x, y); 12997ec681f3Smrg} 13007ec681f3Smrg 13017ec681f3Smrg/** 13027ec681f3Smrg * Get pointer offset into stencil buffer. 13037ec681f3Smrg * 13047ec681f3Smrg * The stencil buffer is W tiled. Since the GTT is incapable of W fencing, we 13057ec681f3Smrg * must decode the tile's layout in software. 13067ec681f3Smrg * 13077ec681f3Smrg * See 13087ec681f3Smrg * - PRM, 2011 Sandy Bridge, Volume 1, Part 2, Section 4.5.2.1 W-Major Tile 13097ec681f3Smrg * Format. 13107ec681f3Smrg * - PRM, 2011 Sandy Bridge, Volume 1, Part 2, Section 4.5.3 Tiling Algorithm 13117ec681f3Smrg * 13127ec681f3Smrg * Even though the returned offset is always positive, the return type is 13137ec681f3Smrg * signed due to 13147ec681f3Smrg * commit e8b1c6d6f55f5be3bef25084fdd8b6127517e137 13157ec681f3Smrg * mesa: Fix return type of _mesa_get_format_bytes() (#37351) 13167ec681f3Smrg */ 13177ec681f3Smrgstatic intptr_t 13187ec681f3Smrgs8_offset(uint32_t stride, uint32_t x, uint32_t y, bool swizzled) 13197ec681f3Smrg{ 13207ec681f3Smrg uint32_t tile_size = 4096; 13217ec681f3Smrg uint32_t tile_width = 64; 13227ec681f3Smrg uint32_t tile_height = 64; 13237ec681f3Smrg uint32_t row_size = 64 * stride / 2; /* Two rows are interleaved. */ 13247ec681f3Smrg 13257ec681f3Smrg uint32_t tile_x = x / tile_width; 13267ec681f3Smrg uint32_t tile_y = y / tile_height; 13277ec681f3Smrg 13287ec681f3Smrg /* The byte's address relative to the tile's base addres. */ 13297ec681f3Smrg uint32_t byte_x = x % tile_width; 13307ec681f3Smrg uint32_t byte_y = y % tile_height; 13317ec681f3Smrg 13327ec681f3Smrg uintptr_t u = tile_y * row_size 13337ec681f3Smrg + tile_x * tile_size 13347ec681f3Smrg + 512 * (byte_x / 8) 13357ec681f3Smrg + 64 * (byte_y / 8) 13367ec681f3Smrg + 32 * ((byte_y / 4) % 2) 13377ec681f3Smrg + 16 * ((byte_x / 4) % 2) 13387ec681f3Smrg + 8 * ((byte_y / 2) % 2) 13397ec681f3Smrg + 4 * ((byte_x / 2) % 2) 13407ec681f3Smrg + 2 * (byte_y % 2) 13417ec681f3Smrg + 1 * (byte_x % 2); 13427ec681f3Smrg 13437ec681f3Smrg if (swizzled) { 13447ec681f3Smrg /* adjust for bit6 swizzling */ 13457ec681f3Smrg if (((byte_x / 8) % 2) == 1) { 13467ec681f3Smrg if (((byte_y / 8) % 2) == 0) { 13477ec681f3Smrg u += 64; 13487ec681f3Smrg } else { 13497ec681f3Smrg u -= 64; 13507ec681f3Smrg } 13517ec681f3Smrg } 13527ec681f3Smrg } 13537ec681f3Smrg 13547ec681f3Smrg return u; 13557ec681f3Smrg} 13567ec681f3Smrg 13577ec681f3Smrgstatic void 13587ec681f3Smrgcrocus_unmap_s8(struct crocus_transfer *map) 13597ec681f3Smrg{ 13607ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 13617ec681f3Smrg const struct pipe_box *box = &xfer->box; 13627ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 13637ec681f3Smrg struct isl_surf *surf = &res->surf; 13647ec681f3Smrg 13657ec681f3Smrg if (xfer->usage & PIPE_MAP_WRITE) { 13667ec681f3Smrg uint8_t *untiled_s8_map = map->ptr; 13677ec681f3Smrg uint8_t *tiled_s8_map = 13687ec681f3Smrg crocus_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 13697ec681f3Smrg 13707ec681f3Smrg for (int s = 0; s < box->depth; s++) { 13717ec681f3Smrg unsigned x0_el, y0_el; 13727ec681f3Smrg get_image_offset_el(surf, xfer->level, box->z + s, &x0_el, &y0_el); 13737ec681f3Smrg 13747ec681f3Smrg for (uint32_t y = 0; y < box->height; y++) { 13757ec681f3Smrg for (uint32_t x = 0; x < box->width; x++) { 13767ec681f3Smrg ptrdiff_t offset = s8_offset(surf->row_pitch_B, 13777ec681f3Smrg x0_el + box->x + x, 13787ec681f3Smrg y0_el + box->y + y, 13797ec681f3Smrg map->has_swizzling); 13807ec681f3Smrg tiled_s8_map[offset] = 13817ec681f3Smrg untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x]; 13827ec681f3Smrg } 13837ec681f3Smrg } 13847ec681f3Smrg } 13857ec681f3Smrg } 13867ec681f3Smrg 13877ec681f3Smrg free(map->buffer); 13887ec681f3Smrg} 13897ec681f3Smrg 13907ec681f3Smrgstatic void 13917ec681f3Smrgcrocus_map_s8(struct crocus_transfer *map) 13927ec681f3Smrg{ 13937ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 13947ec681f3Smrg const struct pipe_box *box = &xfer->box; 13957ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 13967ec681f3Smrg struct isl_surf *surf = &res->surf; 13977ec681f3Smrg 13987ec681f3Smrg xfer->stride = surf->row_pitch_B; 13997ec681f3Smrg xfer->layer_stride = xfer->stride * box->height; 14007ec681f3Smrg 14017ec681f3Smrg /* The tiling and detiling functions require that the linear buffer has 14027ec681f3Smrg * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we 14037ec681f3Smrg * over-allocate the linear buffer to get the proper alignment. 14047ec681f3Smrg */ 14057ec681f3Smrg map->buffer = map->ptr = malloc(xfer->layer_stride * box->depth); 14067ec681f3Smrg assert(map->buffer); 14077ec681f3Smrg 14087ec681f3Smrg /* One of either READ_BIT or WRITE_BIT or both is set. READ_BIT implies no 14097ec681f3Smrg * INVALIDATE_RANGE_BIT. WRITE_BIT needs the original values read in unless 14107ec681f3Smrg * invalidate is set, since we'll be writing the whole rectangle from our 14117ec681f3Smrg * temporary buffer back out. 14127ec681f3Smrg */ 14137ec681f3Smrg if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 14147ec681f3Smrg uint8_t *untiled_s8_map = map->ptr; 14157ec681f3Smrg uint8_t *tiled_s8_map = 14167ec681f3Smrg crocus_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 14177ec681f3Smrg 14187ec681f3Smrg for (int s = 0; s < box->depth; s++) { 14197ec681f3Smrg unsigned x0_el, y0_el; 14207ec681f3Smrg get_image_offset_el(surf, xfer->level, box->z + s, &x0_el, &y0_el); 14217ec681f3Smrg 14227ec681f3Smrg for (uint32_t y = 0; y < box->height; y++) { 14237ec681f3Smrg for (uint32_t x = 0; x < box->width; x++) { 14247ec681f3Smrg ptrdiff_t offset = s8_offset(surf->row_pitch_B, 14257ec681f3Smrg x0_el + box->x + x, 14267ec681f3Smrg y0_el + box->y + y, 14277ec681f3Smrg map->has_swizzling); 14287ec681f3Smrg untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x] = 14297ec681f3Smrg tiled_s8_map[offset]; 14307ec681f3Smrg } 14317ec681f3Smrg } 14327ec681f3Smrg } 14337ec681f3Smrg } 14347ec681f3Smrg 14357ec681f3Smrg map->unmap = crocus_unmap_s8; 14367ec681f3Smrg} 14377ec681f3Smrg 14387ec681f3Smrg/* Compute extent parameters for use with tiled_memcpy functions. 14397ec681f3Smrg * xs are in units of bytes and ys are in units of strides. 14407ec681f3Smrg */ 14417ec681f3Smrgstatic inline void 14427ec681f3Smrgtile_extents(const struct isl_surf *surf, 14437ec681f3Smrg const struct pipe_box *box, 14447ec681f3Smrg unsigned level, int z, 14457ec681f3Smrg unsigned *x1_B, unsigned *x2_B, 14467ec681f3Smrg unsigned *y1_el, unsigned *y2_el) 14477ec681f3Smrg{ 14487ec681f3Smrg const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format); 14497ec681f3Smrg const unsigned cpp = fmtl->bpb / 8; 14507ec681f3Smrg 14517ec681f3Smrg assert(box->x % fmtl->bw == 0); 14527ec681f3Smrg assert(box->y % fmtl->bh == 0); 14537ec681f3Smrg 14547ec681f3Smrg unsigned x0_el, y0_el; 14557ec681f3Smrg get_image_offset_el(surf, level, box->z + z, &x0_el, &y0_el); 14567ec681f3Smrg 14577ec681f3Smrg *x1_B = (box->x / fmtl->bw + x0_el) * cpp; 14587ec681f3Smrg *y1_el = box->y / fmtl->bh + y0_el; 14597ec681f3Smrg *x2_B = (DIV_ROUND_UP(box->x + box->width, fmtl->bw) + x0_el) * cpp; 14607ec681f3Smrg *y2_el = DIV_ROUND_UP(box->y + box->height, fmtl->bh) + y0_el; 14617ec681f3Smrg} 14627ec681f3Smrg 14637ec681f3Smrgstatic void 14647ec681f3Smrgcrocus_unmap_tiled_memcpy(struct crocus_transfer *map) 14657ec681f3Smrg{ 14667ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 14677ec681f3Smrg const struct pipe_box *box = &xfer->box; 14687ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 14697ec681f3Smrg struct isl_surf *surf = &res->surf; 14707ec681f3Smrg 14717ec681f3Smrg if (xfer->usage & PIPE_MAP_WRITE) { 14727ec681f3Smrg char *dst = 14737ec681f3Smrg crocus_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 14747ec681f3Smrg 14757ec681f3Smrg for (int s = 0; s < box->depth; s++) { 14767ec681f3Smrg unsigned x1, x2, y1, y2; 14777ec681f3Smrg tile_extents(surf, box, xfer->level, s, &x1, &x2, &y1, &y2); 14787ec681f3Smrg 14797ec681f3Smrg void *ptr = map->ptr + s * xfer->layer_stride; 14807ec681f3Smrg 14817ec681f3Smrg isl_memcpy_linear_to_tiled(x1, x2, y1, y2, dst, ptr, 14827ec681f3Smrg surf->row_pitch_B, xfer->stride, 14837ec681f3Smrg map->has_swizzling, 14847ec681f3Smrg surf->tiling, ISL_MEMCPY); 14857ec681f3Smrg } 14867ec681f3Smrg } 14877ec681f3Smrg os_free_aligned(map->buffer); 14887ec681f3Smrg map->buffer = map->ptr = NULL; 14897ec681f3Smrg} 14907ec681f3Smrg 14917ec681f3Smrgstatic void 14927ec681f3Smrgcrocus_map_tiled_memcpy(struct crocus_transfer *map) 14937ec681f3Smrg{ 14947ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 14957ec681f3Smrg const struct pipe_box *box = &xfer->box; 14967ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 14977ec681f3Smrg struct isl_surf *surf = &res->surf; 14987ec681f3Smrg 14997ec681f3Smrg xfer->stride = ALIGN(surf->row_pitch_B, 16); 15007ec681f3Smrg xfer->layer_stride = xfer->stride * box->height; 15017ec681f3Smrg 15027ec681f3Smrg unsigned x1, x2, y1, y2; 15037ec681f3Smrg tile_extents(surf, box, xfer->level, 0, &x1, &x2, &y1, &y2); 15047ec681f3Smrg 15057ec681f3Smrg /* The tiling and detiling functions require that the linear buffer has 15067ec681f3Smrg * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we 15077ec681f3Smrg * over-allocate the linear buffer to get the proper alignment. 15087ec681f3Smrg */ 15097ec681f3Smrg map->buffer = 15107ec681f3Smrg os_malloc_aligned(xfer->layer_stride * box->depth, 16); 15117ec681f3Smrg assert(map->buffer); 15127ec681f3Smrg map->ptr = (char *)map->buffer + (x1 & 0xf); 15137ec681f3Smrg 15147ec681f3Smrg if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) { 15157ec681f3Smrg char *src = 15167ec681f3Smrg crocus_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS); 15177ec681f3Smrg 15187ec681f3Smrg for (int s = 0; s < box->depth; s++) { 15197ec681f3Smrg unsigned x1, x2, y1, y2; 15207ec681f3Smrg tile_extents(surf, box, xfer->level, s, &x1, &x2, &y1, &y2); 15217ec681f3Smrg 15227ec681f3Smrg /* Use 's' rather than 'box->z' to rebase the first slice to 0. */ 15237ec681f3Smrg void *ptr = map->ptr + s * xfer->layer_stride; 15247ec681f3Smrg 15257ec681f3Smrg isl_memcpy_tiled_to_linear(x1, x2, y1, y2, ptr, src, xfer->stride, 15267ec681f3Smrg surf->row_pitch_B, 15277ec681f3Smrg map->has_swizzling, 15287ec681f3Smrg surf->tiling, 15297ec681f3Smrg#if defined(USE_SSE41) 15307ec681f3Smrg util_get_cpu_caps()->has_sse4_1 ? ISL_MEMCPY_STREAMING_LOAD : 15317ec681f3Smrg#endif 15327ec681f3Smrg ISL_MEMCPY); 15337ec681f3Smrg } 15347ec681f3Smrg } 15357ec681f3Smrg 15367ec681f3Smrg map->unmap = crocus_unmap_tiled_memcpy; 15377ec681f3Smrg} 15387ec681f3Smrg 15397ec681f3Smrgstatic void 15407ec681f3Smrgcrocus_map_direct(struct crocus_transfer *map) 15417ec681f3Smrg{ 15427ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 15437ec681f3Smrg struct pipe_box *box = &xfer->box; 15447ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 15457ec681f3Smrg 15467ec681f3Smrg void *ptr = crocus_bo_map(map->dbg, res->bo, xfer->usage & MAP_FLAGS); 15477ec681f3Smrg 15487ec681f3Smrg if (res->base.b.target == PIPE_BUFFER) { 15497ec681f3Smrg xfer->stride = 0; 15507ec681f3Smrg xfer->layer_stride = 0; 15517ec681f3Smrg 15527ec681f3Smrg map->ptr = ptr + box->x; 15537ec681f3Smrg } else { 15547ec681f3Smrg struct isl_surf *surf = &res->surf; 15557ec681f3Smrg const struct isl_format_layout *fmtl = 15567ec681f3Smrg isl_format_get_layout(surf->format); 15577ec681f3Smrg const unsigned cpp = fmtl->bpb / 8; 15587ec681f3Smrg unsigned x0_el, y0_el; 15597ec681f3Smrg 15607ec681f3Smrg assert(box->x % fmtl->bw == 0); 15617ec681f3Smrg assert(box->y % fmtl->bh == 0); 15627ec681f3Smrg get_image_offset_el(surf, xfer->level, box->z, &x0_el, &y0_el); 15637ec681f3Smrg 15647ec681f3Smrg x0_el += box->x / fmtl->bw; 15657ec681f3Smrg y0_el += box->y / fmtl->bh; 15667ec681f3Smrg 15677ec681f3Smrg xfer->stride = isl_surf_get_row_pitch_B(surf); 15687ec681f3Smrg xfer->layer_stride = isl_surf_get_array_pitch(surf); 15697ec681f3Smrg 15707ec681f3Smrg map->ptr = ptr + y0_el * xfer->stride + x0_el * cpp; 15717ec681f3Smrg } 15727ec681f3Smrg} 15737ec681f3Smrg 15747ec681f3Smrgstatic bool 15757ec681f3Smrgcan_promote_to_async(const struct crocus_resource *res, 15767ec681f3Smrg const struct pipe_box *box, 15777ec681f3Smrg unsigned usage) 15787ec681f3Smrg{ 15797ec681f3Smrg /* If we're writing to a section of the buffer that hasn't even been 15807ec681f3Smrg * initialized with useful data, then we can safely promote this write 15817ec681f3Smrg * to be unsynchronized. This helps the common pattern of appending data. 15827ec681f3Smrg */ 15837ec681f3Smrg return res->base.b.target == PIPE_BUFFER && (usage & PIPE_MAP_WRITE) && 15847ec681f3Smrg !(usage & TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED) && 15857ec681f3Smrg !util_ranges_intersect(&res->valid_buffer_range, box->x, 15867ec681f3Smrg box->x + box->width); 15877ec681f3Smrg} 15887ec681f3Smrg 15897ec681f3Smrgstatic void * 15907ec681f3Smrgcrocus_transfer_map(struct pipe_context *ctx, 15917ec681f3Smrg struct pipe_resource *resource, 15927ec681f3Smrg unsigned level, 15937ec681f3Smrg unsigned usage, 15947ec681f3Smrg const struct pipe_box *box, 15957ec681f3Smrg struct pipe_transfer **ptransfer) 15967ec681f3Smrg{ 15977ec681f3Smrg struct crocus_context *ice = (struct crocus_context *)ctx; 15987ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *)resource; 15997ec681f3Smrg struct isl_surf *surf = &res->surf; 16007ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *)ctx->screen; 16017ec681f3Smrg 16027ec681f3Smrg if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) { 16037ec681f3Smrg /* Replace the backing storage with a fresh buffer for non-async maps */ 16047ec681f3Smrg if (!(usage & (PIPE_MAP_UNSYNCHRONIZED | 16057ec681f3Smrg TC_TRANSFER_MAP_NO_INVALIDATE))) 16067ec681f3Smrg crocus_invalidate_resource(ctx, resource); 16077ec681f3Smrg 16087ec681f3Smrg /* If we can discard the whole resource, we can discard the range. */ 16097ec681f3Smrg usage |= PIPE_MAP_DISCARD_RANGE; 16107ec681f3Smrg } 16117ec681f3Smrg 16127ec681f3Smrg if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && 16137ec681f3Smrg can_promote_to_async(res, box, usage)) { 16147ec681f3Smrg usage |= PIPE_MAP_UNSYNCHRONIZED; 16157ec681f3Smrg } 16167ec681f3Smrg 16177ec681f3Smrg bool map_would_stall = false; 16187ec681f3Smrg 16197ec681f3Smrg if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { 16207ec681f3Smrg map_would_stall = resource_is_busy(ice, res) || 16217ec681f3Smrg crocus_has_invalid_primary(res, level, 1, box->z, box->depth); 16227ec681f3Smrg 16237ec681f3Smrg 16247ec681f3Smrg if (map_would_stall && (usage & PIPE_MAP_DONTBLOCK) && 16257ec681f3Smrg (usage & PIPE_MAP_DIRECTLY)) 16267ec681f3Smrg return NULL; 16277ec681f3Smrg } 16287ec681f3Smrg 16297ec681f3Smrg if (surf->tiling != ISL_TILING_LINEAR && 16307ec681f3Smrg (usage & PIPE_MAP_DIRECTLY)) 16317ec681f3Smrg return NULL; 16327ec681f3Smrg 16337ec681f3Smrg struct crocus_transfer *map; 16347ec681f3Smrg if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC) 16357ec681f3Smrg map = slab_alloc(&ice->transfer_pool_unsync); 16367ec681f3Smrg else 16377ec681f3Smrg map = slab_alloc(&ice->transfer_pool); 16387ec681f3Smrg 16397ec681f3Smrg struct pipe_transfer *xfer = &map->base.b; 16407ec681f3Smrg 16417ec681f3Smrg if (!map) 16427ec681f3Smrg return NULL; 16437ec681f3Smrg 16447ec681f3Smrg memset(map, 0, sizeof(*map)); 16457ec681f3Smrg map->dbg = &ice->dbg; 16467ec681f3Smrg 16477ec681f3Smrg map->has_swizzling = ((struct crocus_screen *)ctx->screen)->has_swizzling; 16487ec681f3Smrg pipe_resource_reference(&xfer->resource, resource); 16497ec681f3Smrg xfer->level = level; 16507ec681f3Smrg xfer->usage = usage; 16517ec681f3Smrg xfer->box = *box; 16527ec681f3Smrg *ptransfer = xfer; 16537ec681f3Smrg 16547ec681f3Smrg map->dest_had_defined_contents = 16557ec681f3Smrg util_ranges_intersect(&res->valid_buffer_range, box->x, 16567ec681f3Smrg box->x + box->width); 16577ec681f3Smrg 16587ec681f3Smrg if (usage & PIPE_MAP_WRITE) 16597ec681f3Smrg util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width); 16607ec681f3Smrg 16617ec681f3Smrg /* Avoid using GPU copies for persistent/coherent buffers, as the idea 16627ec681f3Smrg * there is to access them simultaneously on the CPU & GPU. This also 16637ec681f3Smrg * avoids trying to use GPU copies for our u_upload_mgr buffers which 16647ec681f3Smrg * contain state we're constructing for a GPU draw call, which would 16657ec681f3Smrg * kill us with infinite stack recursion. 16667ec681f3Smrg */ 16677ec681f3Smrg bool no_gpu = usage & (PIPE_MAP_PERSISTENT | 16687ec681f3Smrg PIPE_MAP_COHERENT | 16697ec681f3Smrg PIPE_MAP_DIRECTLY); 16707ec681f3Smrg 16717ec681f3Smrg /* GPU copies are not useful for buffer reads. Instead of stalling to 16727ec681f3Smrg * read from the original buffer, we'd simply copy it to a temporary... 16737ec681f3Smrg * then stall (a bit longer) to read from that buffer. 16747ec681f3Smrg * 16757ec681f3Smrg * Images are less clear-cut. Color resolves are destructive, removing 16767ec681f3Smrg * the underlying compression, so we'd rather blit the data to a linear 16777ec681f3Smrg * temporary and map that, to avoid the resolve. (It might be better to 16787ec681f3Smrg * a tiled temporary and use the tiled_memcpy paths...) 16797ec681f3Smrg */ 16807ec681f3Smrg if (!(usage & PIPE_MAP_DISCARD_RANGE) && 16817ec681f3Smrg !crocus_has_invalid_primary(res, level, 1, box->z, box->depth)) 16827ec681f3Smrg no_gpu = true; 16837ec681f3Smrg 16847ec681f3Smrg const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format); 16857ec681f3Smrg if (fmtl->txc == ISL_TXC_ASTC) 16867ec681f3Smrg no_gpu = true; 16877ec681f3Smrg 16887ec681f3Smrg if (map_would_stall && !no_gpu) { 16897ec681f3Smrg /* If we need a synchronous mapping and the resource is busy, or needs 16907ec681f3Smrg * resolving, we copy to/from a linear temporary buffer using the GPU. 16917ec681f3Smrg */ 16927ec681f3Smrg map->batch = &ice->batches[CROCUS_BATCH_RENDER]; 16937ec681f3Smrg map->blorp = &ice->blorp; 16947ec681f3Smrg crocus_map_copy_region(map); 16957ec681f3Smrg } else { 16967ec681f3Smrg /* Otherwise we're free to map on the CPU. */ 16977ec681f3Smrg 16987ec681f3Smrg if (resource->target != PIPE_BUFFER) { 16997ec681f3Smrg crocus_resource_access_raw(ice, res, 17007ec681f3Smrg level, box->z, box->depth, 17017ec681f3Smrg usage & PIPE_MAP_WRITE); 17027ec681f3Smrg } 17037ec681f3Smrg 17047ec681f3Smrg if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { 17057ec681f3Smrg for (int i = 0; i < ice->batch_count; i++) { 17067ec681f3Smrg if (crocus_batch_references(&ice->batches[i], res->bo)) 17077ec681f3Smrg crocus_batch_flush(&ice->batches[i]); 17087ec681f3Smrg } 17097ec681f3Smrg } 17107ec681f3Smrg 17117ec681f3Smrg if (surf->tiling == ISL_TILING_W) { 17127ec681f3Smrg /* TODO: Teach crocus_map_tiled_memcpy about W-tiling... */ 17137ec681f3Smrg crocus_map_s8(map); 17147ec681f3Smrg } else if (surf->tiling != ISL_TILING_LINEAR && screen->devinfo.ver > 4) { 17157ec681f3Smrg crocus_map_tiled_memcpy(map); 17167ec681f3Smrg } else { 17177ec681f3Smrg crocus_map_direct(map); 17187ec681f3Smrg } 17197ec681f3Smrg } 17207ec681f3Smrg 17217ec681f3Smrg return map->ptr; 17227ec681f3Smrg} 17237ec681f3Smrg 17247ec681f3Smrgstatic void 17257ec681f3Smrgcrocus_transfer_flush_region(struct pipe_context *ctx, 17267ec681f3Smrg struct pipe_transfer *xfer, 17277ec681f3Smrg const struct pipe_box *box) 17287ec681f3Smrg{ 17297ec681f3Smrg struct crocus_context *ice = (struct crocus_context *)ctx; 17307ec681f3Smrg struct crocus_resource *res = (struct crocus_resource *) xfer->resource; 17317ec681f3Smrg struct crocus_transfer *map = (void *) xfer; 17327ec681f3Smrg 17337ec681f3Smrg if (map->staging) 17347ec681f3Smrg crocus_flush_staging_region(xfer, box); 17357ec681f3Smrg 17367ec681f3Smrg uint32_t history_flush = 0; 17377ec681f3Smrg 17387ec681f3Smrg if (res->base.b.target == PIPE_BUFFER) { 17397ec681f3Smrg if (map->staging) 17407ec681f3Smrg history_flush |= PIPE_CONTROL_RENDER_TARGET_FLUSH; 17417ec681f3Smrg 17427ec681f3Smrg if (map->dest_had_defined_contents) 17437ec681f3Smrg history_flush |= crocus_flush_bits_for_history(res); 17447ec681f3Smrg 17457ec681f3Smrg util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width); 17467ec681f3Smrg } 17477ec681f3Smrg 17487ec681f3Smrg if (history_flush & ~PIPE_CONTROL_CS_STALL) { 17497ec681f3Smrg for (int i = 0; i < ice->batch_count; i++) { 17507ec681f3Smrg struct crocus_batch *batch = &ice->batches[i]; 17517ec681f3Smrg 17527ec681f3Smrg if (!batch->command.bo) 17537ec681f3Smrg continue; 17547ec681f3Smrg if (batch->contains_draw || batch->cache.render->entries) { 17557ec681f3Smrg crocus_batch_maybe_flush(batch, 24); 17567ec681f3Smrg crocus_emit_pipe_control_flush(batch, 17577ec681f3Smrg "cache history: transfer flush", 17587ec681f3Smrg history_flush); 17597ec681f3Smrg } 17607ec681f3Smrg } 17617ec681f3Smrg } 17627ec681f3Smrg 17637ec681f3Smrg /* Make sure we flag constants dirty even if there's no need to emit 17647ec681f3Smrg * any PIPE_CONTROLs to a batch. 17657ec681f3Smrg */ 17667ec681f3Smrg crocus_dirty_for_history(ice, res); 17677ec681f3Smrg} 17687ec681f3Smrg 17697ec681f3Smrgstatic void 17707ec681f3Smrgcrocus_transfer_unmap(struct pipe_context *ctx, struct pipe_transfer *xfer) 17717ec681f3Smrg{ 17727ec681f3Smrg struct crocus_context *ice = (struct crocus_context *)ctx; 17737ec681f3Smrg struct crocus_transfer *map = (void *) xfer; 17747ec681f3Smrg 17757ec681f3Smrg if (!(xfer->usage & (PIPE_MAP_FLUSH_EXPLICIT | 17767ec681f3Smrg PIPE_MAP_COHERENT))) { 17777ec681f3Smrg struct pipe_box flush_box = { 17787ec681f3Smrg .x = 0, .y = 0, .z = 0, 17797ec681f3Smrg .width = xfer->box.width, 17807ec681f3Smrg .height = xfer->box.height, 17817ec681f3Smrg .depth = xfer->box.depth, 17827ec681f3Smrg }; 17837ec681f3Smrg crocus_transfer_flush_region(ctx, xfer, &flush_box); 17847ec681f3Smrg } 17857ec681f3Smrg 17867ec681f3Smrg if (map->unmap) 17877ec681f3Smrg map->unmap(map); 17887ec681f3Smrg 17897ec681f3Smrg pipe_resource_reference(&xfer->resource, NULL); 17907ec681f3Smrg /* transfer_unmap is always called from the driver thread, so we have to 17917ec681f3Smrg * use transfer_pool, not transfer_pool_unsync. Freeing an object into a 17927ec681f3Smrg * different pool is allowed, however. 17937ec681f3Smrg */ 17947ec681f3Smrg slab_free(&ice->transfer_pool, map); 17957ec681f3Smrg} 17967ec681f3Smrg 17977ec681f3Smrg/** 17987ec681f3Smrg * Mark state dirty that needs to be re-emitted when a resource is written. 17997ec681f3Smrg */ 18007ec681f3Smrgvoid 18017ec681f3Smrgcrocus_dirty_for_history(struct crocus_context *ice, 18027ec681f3Smrg struct crocus_resource *res) 18037ec681f3Smrg{ 18047ec681f3Smrg uint64_t stage_dirty = 0ull; 18057ec681f3Smrg 18067ec681f3Smrg if (res->bind_history & PIPE_BIND_CONSTANT_BUFFER) { 18077ec681f3Smrg stage_dirty |= ((uint64_t)res->bind_stages) << CROCUS_SHIFT_FOR_STAGE_DIRTY_CONSTANTS; 18087ec681f3Smrg } 18097ec681f3Smrg 18107ec681f3Smrg ice->state.stage_dirty |= stage_dirty; 18117ec681f3Smrg} 18127ec681f3Smrg 18137ec681f3Smrg/** 18147ec681f3Smrg * Produce a set of PIPE_CONTROL bits which ensure data written to a 18157ec681f3Smrg * resource becomes visible, and any stale read cache data is invalidated. 18167ec681f3Smrg */ 18177ec681f3Smrguint32_t 18187ec681f3Smrgcrocus_flush_bits_for_history(struct crocus_resource *res) 18197ec681f3Smrg{ 18207ec681f3Smrg uint32_t flush = PIPE_CONTROL_CS_STALL; 18217ec681f3Smrg 18227ec681f3Smrg if (res->bind_history & PIPE_BIND_CONSTANT_BUFFER) { 18237ec681f3Smrg flush |= PIPE_CONTROL_CONST_CACHE_INVALIDATE | 18247ec681f3Smrg PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE; 18257ec681f3Smrg } 18267ec681f3Smrg 18277ec681f3Smrg if (res->bind_history & PIPE_BIND_SAMPLER_VIEW) 18287ec681f3Smrg flush |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE; 18297ec681f3Smrg 18307ec681f3Smrg if (res->bind_history & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER)) 18317ec681f3Smrg flush |= PIPE_CONTROL_VF_CACHE_INVALIDATE; 18327ec681f3Smrg 18337ec681f3Smrg if (res->bind_history & (PIPE_BIND_SHADER_BUFFER | PIPE_BIND_SHADER_IMAGE)) 18347ec681f3Smrg flush |= PIPE_CONTROL_DATA_CACHE_FLUSH; 18357ec681f3Smrg 18367ec681f3Smrg return flush; 18377ec681f3Smrg} 18387ec681f3Smrg 18397ec681f3Smrgvoid 18407ec681f3Smrgcrocus_flush_and_dirty_for_history(struct crocus_context *ice, 18417ec681f3Smrg struct crocus_batch *batch, 18427ec681f3Smrg struct crocus_resource *res, 18437ec681f3Smrg uint32_t extra_flags, 18447ec681f3Smrg const char *reason) 18457ec681f3Smrg{ 18467ec681f3Smrg if (res->base.b.target != PIPE_BUFFER) 18477ec681f3Smrg return; 18487ec681f3Smrg 18497ec681f3Smrg uint32_t flush = crocus_flush_bits_for_history(res) | extra_flags; 18507ec681f3Smrg 18517ec681f3Smrg crocus_emit_pipe_control_flush(batch, reason, flush); 18527ec681f3Smrg 18537ec681f3Smrg crocus_dirty_for_history(ice, res); 18547ec681f3Smrg} 18557ec681f3Smrg 18567ec681f3Smrgbool 18577ec681f3Smrgcrocus_resource_set_clear_color(struct crocus_context *ice, 18587ec681f3Smrg struct crocus_resource *res, 18597ec681f3Smrg union isl_color_value color) 18607ec681f3Smrg{ 18617ec681f3Smrg if (memcmp(&res->aux.clear_color, &color, sizeof(color)) != 0) { 18627ec681f3Smrg res->aux.clear_color = color; 18637ec681f3Smrg return true; 18647ec681f3Smrg } 18657ec681f3Smrg 18667ec681f3Smrg return false; 18677ec681f3Smrg} 18687ec681f3Smrg 18697ec681f3Smrgunion isl_color_value 18707ec681f3Smrgcrocus_resource_get_clear_color(const struct crocus_resource *res) 18717ec681f3Smrg{ 18727ec681f3Smrg assert(res->aux.bo); 18737ec681f3Smrg 18747ec681f3Smrg return res->aux.clear_color; 18757ec681f3Smrg} 18767ec681f3Smrg 18777ec681f3Smrgstatic enum pipe_format 18787ec681f3Smrgcrocus_resource_get_internal_format(struct pipe_resource *p_res) 18797ec681f3Smrg{ 18807ec681f3Smrg struct crocus_resource *res = (void *) p_res; 18817ec681f3Smrg return res->internal_format; 18827ec681f3Smrg} 18837ec681f3Smrg 18847ec681f3Smrgstatic const struct u_transfer_vtbl transfer_vtbl = { 18857ec681f3Smrg .resource_create = crocus_resource_create, 18867ec681f3Smrg .resource_destroy = crocus_resource_destroy, 18877ec681f3Smrg .transfer_map = crocus_transfer_map, 18887ec681f3Smrg .transfer_unmap = crocus_transfer_unmap, 18897ec681f3Smrg .transfer_flush_region = crocus_transfer_flush_region, 18907ec681f3Smrg .get_internal_format = crocus_resource_get_internal_format, 18917ec681f3Smrg .set_stencil = crocus_resource_set_separate_stencil, 18927ec681f3Smrg .get_stencil = crocus_resource_get_separate_stencil, 18937ec681f3Smrg}; 18947ec681f3Smrg 18957ec681f3Smrgstatic bool 18967ec681f3Smrgcrocus_is_dmabuf_modifier_supported(struct pipe_screen *pscreen, 18977ec681f3Smrg uint64_t modifier, enum pipe_format pfmt, 18987ec681f3Smrg bool *external_only) 18997ec681f3Smrg{ 19007ec681f3Smrg struct crocus_screen *screen = (void *) pscreen; 19017ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 19027ec681f3Smrg 19037ec681f3Smrg if (modifier_is_supported(devinfo, pfmt, 0, modifier)) { 19047ec681f3Smrg if (external_only) 19057ec681f3Smrg *external_only = false; 19067ec681f3Smrg 19077ec681f3Smrg return true; 19087ec681f3Smrg } 19097ec681f3Smrg 19107ec681f3Smrg return false; 19117ec681f3Smrg} 19127ec681f3Smrg 19137ec681f3Smrgstatic unsigned int 19147ec681f3Smrgcrocus_get_dmabuf_modifier_planes(struct pipe_screen *pscreen, uint64_t modifier, 19157ec681f3Smrg enum pipe_format format) 19167ec681f3Smrg{ 19177ec681f3Smrg return util_format_get_num_planes(format); 19187ec681f3Smrg} 19197ec681f3Smrg 19207ec681f3Smrgstatic struct pipe_memory_object * 19217ec681f3Smrgcrocus_memobj_create_from_handle(struct pipe_screen *pscreen, 19227ec681f3Smrg struct winsys_handle *whandle, 19237ec681f3Smrg bool dedicated) 19247ec681f3Smrg{ 19257ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *)pscreen; 19267ec681f3Smrg struct crocus_memory_object *memobj = CALLOC_STRUCT(crocus_memory_object); 19277ec681f3Smrg struct crocus_bo *bo; 19287ec681f3Smrg const struct isl_drm_modifier_info *mod_inf; 19297ec681f3Smrg 19307ec681f3Smrg if (!memobj) 19317ec681f3Smrg return NULL; 19327ec681f3Smrg 19337ec681f3Smrg switch (whandle->type) { 19347ec681f3Smrg case WINSYS_HANDLE_TYPE_SHARED: 19357ec681f3Smrg bo = crocus_bo_gem_create_from_name(screen->bufmgr, "winsys image", 19367ec681f3Smrg whandle->handle); 19377ec681f3Smrg break; 19387ec681f3Smrg case WINSYS_HANDLE_TYPE_FD: 19397ec681f3Smrg mod_inf = isl_drm_modifier_get_info(whandle->modifier); 19407ec681f3Smrg if (mod_inf) { 19417ec681f3Smrg bo = crocus_bo_import_dmabuf(screen->bufmgr, whandle->handle, 19427ec681f3Smrg whandle->modifier); 19437ec681f3Smrg } else { 19447ec681f3Smrg /* If we can't get information about the tiling from the 19457ec681f3Smrg * kernel we ignore it. We are going to set it when we 19467ec681f3Smrg * create the resource. 19477ec681f3Smrg */ 19487ec681f3Smrg bo = crocus_bo_import_dmabuf_no_mods(screen->bufmgr, 19497ec681f3Smrg whandle->handle); 19507ec681f3Smrg } 19517ec681f3Smrg 19527ec681f3Smrg break; 19537ec681f3Smrg default: 19547ec681f3Smrg unreachable("invalid winsys handle type"); 19557ec681f3Smrg } 19567ec681f3Smrg 19577ec681f3Smrg if (!bo) { 19587ec681f3Smrg free(memobj); 19597ec681f3Smrg return NULL; 19607ec681f3Smrg } 19617ec681f3Smrg 19627ec681f3Smrg memobj->b.dedicated = dedicated; 19637ec681f3Smrg memobj->bo = bo; 19647ec681f3Smrg memobj->format = whandle->format; 19657ec681f3Smrg memobj->stride = whandle->stride; 19667ec681f3Smrg 19677ec681f3Smrg return &memobj->b; 19687ec681f3Smrg} 19697ec681f3Smrg 19707ec681f3Smrgstatic void 19717ec681f3Smrgcrocus_memobj_destroy(struct pipe_screen *pscreen, 19727ec681f3Smrg struct pipe_memory_object *pmemobj) 19737ec681f3Smrg{ 19747ec681f3Smrg struct crocus_memory_object *memobj = (struct crocus_memory_object *)pmemobj; 19757ec681f3Smrg 19767ec681f3Smrg crocus_bo_unreference(memobj->bo); 19777ec681f3Smrg free(memobj); 19787ec681f3Smrg} 19797ec681f3Smrg 19807ec681f3Smrgvoid 19817ec681f3Smrgcrocus_init_screen_resource_functions(struct pipe_screen *pscreen) 19827ec681f3Smrg{ 19837ec681f3Smrg struct crocus_screen *screen = (void *) pscreen; 19847ec681f3Smrg pscreen->query_dmabuf_modifiers = crocus_query_dmabuf_modifiers; 19857ec681f3Smrg pscreen->is_dmabuf_modifier_supported = crocus_is_dmabuf_modifier_supported; 19867ec681f3Smrg pscreen->get_dmabuf_modifier_planes = crocus_get_dmabuf_modifier_planes; 19877ec681f3Smrg pscreen->resource_create_with_modifiers = 19887ec681f3Smrg crocus_resource_create_with_modifiers; 19897ec681f3Smrg pscreen->resource_create = u_transfer_helper_resource_create; 19907ec681f3Smrg pscreen->resource_from_user_memory = crocus_resource_from_user_memory; 19917ec681f3Smrg pscreen->resource_from_handle = crocus_resource_from_handle; 19927ec681f3Smrg pscreen->resource_from_memobj = crocus_resource_from_memobj; 19937ec681f3Smrg pscreen->resource_get_handle = crocus_resource_get_handle; 19947ec681f3Smrg pscreen->resource_get_param = crocus_resource_get_param; 19957ec681f3Smrg pscreen->resource_destroy = u_transfer_helper_resource_destroy; 19967ec681f3Smrg pscreen->memobj_create_from_handle = crocus_memobj_create_from_handle; 19977ec681f3Smrg pscreen->memobj_destroy = crocus_memobj_destroy; 19987ec681f3Smrg pscreen->transfer_helper = 19997ec681f3Smrg u_transfer_helper_create(&transfer_vtbl, screen->devinfo.ver >= 6, 20007ec681f3Smrg screen->devinfo.ver >= 6, false, true); 20017ec681f3Smrg} 20027ec681f3Smrg 20037ec681f3Smrgvoid 20047ec681f3Smrgcrocus_init_resource_functions(struct pipe_context *ctx) 20057ec681f3Smrg{ 20067ec681f3Smrg ctx->flush_resource = crocus_flush_resource; 20077ec681f3Smrg ctx->invalidate_resource = crocus_invalidate_resource; 20087ec681f3Smrg ctx->buffer_map = u_transfer_helper_transfer_map; 20097ec681f3Smrg ctx->texture_map = u_transfer_helper_transfer_map; 20107ec681f3Smrg ctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 20117ec681f3Smrg ctx->buffer_unmap = u_transfer_helper_transfer_unmap; 20127ec681f3Smrg ctx->texture_unmap = u_transfer_helper_transfer_unmap; 20137ec681f3Smrg ctx->buffer_subdata = u_default_buffer_subdata; 20147ec681f3Smrg ctx->texture_subdata = u_default_texture_subdata; 20157ec681f3Smrg} 2016