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