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