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 iris_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_memory.h"
42 #include "util/u_threaded_context.h"
43 #include "util/u_transfer.h"
44 #include "util/u_transfer_helper.h"
45 #include "util/u_upload_mgr.h"
46 #include "util/ralloc.h"
47 #include "iris_batch.h"
48 #include "iris_context.h"
49 #include "iris_resource.h"
50 #include "iris_screen.h"
51 #include "intel/common/intel_aux_map.h"
52 #include "intel/dev/intel_debug.h"
53 #include "isl/isl.h"
54 #include "drm-uapi/drm_fourcc.h"
55 #include "drm-uapi/i915_drm.h"
56
57 enum modifier_priority {
58 MODIFIER_PRIORITY_INVALID = 0,
59 MODIFIER_PRIORITY_LINEAR,
60 MODIFIER_PRIORITY_X,
61 MODIFIER_PRIORITY_Y,
62 MODIFIER_PRIORITY_Y_CCS,
63 MODIFIER_PRIORITY_Y_GFX12_RC_CCS,
64 MODIFIER_PRIORITY_Y_GFX12_RC_CCS_CC,
65 };
66
67 static const uint64_t priority_to_modifier[] = {
68 [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID,
69 [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR,
70 [MODIFIER_PRIORITY_X] = I915_FORMAT_MOD_X_TILED,
71 [MODIFIER_PRIORITY_Y] = I915_FORMAT_MOD_Y_TILED,
72 [MODIFIER_PRIORITY_Y_CCS] = I915_FORMAT_MOD_Y_TILED_CCS,
73 [MODIFIER_PRIORITY_Y_GFX12_RC_CCS] = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
74 [MODIFIER_PRIORITY_Y_GFX12_RC_CCS_CC] = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC,
75 };
76
77 static bool
modifier_is_supported(const struct intel_device_info * devinfo,enum pipe_format pfmt,unsigned bind,uint64_t modifier)78 modifier_is_supported(const struct intel_device_info *devinfo,
79 enum pipe_format pfmt, unsigned bind,
80 uint64_t modifier)
81 {
82 /* Check for basic device support. */
83 switch (modifier) {
84 case DRM_FORMAT_MOD_LINEAR:
85 case I915_FORMAT_MOD_X_TILED:
86 break;
87 case I915_FORMAT_MOD_Y_TILED:
88 if (devinfo->ver <= 8 && (bind & PIPE_BIND_SCANOUT))
89 return false;
90 if (devinfo->verx10 >= 125)
91 return false;
92 break;
93 case I915_FORMAT_MOD_Y_TILED_CCS:
94 if (devinfo->ver <= 8 || devinfo->ver >= 12)
95 return false;
96 break;
97 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
98 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
99 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
100 if (devinfo->verx10 != 120)
101 return false;
102 break;
103 case DRM_FORMAT_MOD_INVALID:
104 default:
105 return false;
106 }
107
108 /* Check remaining requirements. */
109 switch (modifier) {
110 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
111 if (pfmt != PIPE_FORMAT_BGRA8888_UNORM &&
112 pfmt != PIPE_FORMAT_RGBA8888_UNORM &&
113 pfmt != PIPE_FORMAT_BGRX8888_UNORM &&
114 pfmt != PIPE_FORMAT_RGBX8888_UNORM &&
115 pfmt != PIPE_FORMAT_NV12 &&
116 pfmt != PIPE_FORMAT_P010 &&
117 pfmt != PIPE_FORMAT_P012 &&
118 pfmt != PIPE_FORMAT_P016 &&
119 pfmt != PIPE_FORMAT_YUYV &&
120 pfmt != PIPE_FORMAT_UYVY) {
121 return false;
122 }
123 break;
124 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
125 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
126 case I915_FORMAT_MOD_Y_TILED_CCS: {
127 if (INTEL_DEBUG(DEBUG_NO_RBC))
128 return false;
129
130 enum isl_format rt_format =
131 iris_format_for_usage(devinfo, pfmt,
132 ISL_SURF_USAGE_RENDER_TARGET_BIT).fmt;
133
134 if (rt_format == ISL_FORMAT_UNSUPPORTED ||
135 !isl_format_supports_ccs_e(devinfo, rt_format))
136 return false;
137 break;
138 }
139 default:
140 break;
141 }
142
143 return true;
144 }
145
146 static uint64_t
select_best_modifier(struct intel_device_info * devinfo,const struct pipe_resource * templ,const uint64_t * modifiers,int count)147 select_best_modifier(struct intel_device_info *devinfo,
148 const struct pipe_resource *templ,
149 const uint64_t *modifiers,
150 int count)
151 {
152 enum modifier_priority prio = MODIFIER_PRIORITY_INVALID;
153
154 for (int i = 0; i < count; i++) {
155 if (!modifier_is_supported(devinfo, templ->format, templ->bind,
156 modifiers[i]))
157 continue;
158
159 switch (modifiers[i]) {
160 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
161 prio = MAX2(prio, MODIFIER_PRIORITY_Y_GFX12_RC_CCS_CC);
162 break;
163 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
164 prio = MAX2(prio, MODIFIER_PRIORITY_Y_GFX12_RC_CCS);
165 break;
166 case I915_FORMAT_MOD_Y_TILED_CCS:
167 prio = MAX2(prio, MODIFIER_PRIORITY_Y_CCS);
168 break;
169 case I915_FORMAT_MOD_Y_TILED:
170 prio = MAX2(prio, MODIFIER_PRIORITY_Y);
171 break;
172 case I915_FORMAT_MOD_X_TILED:
173 prio = MAX2(prio, MODIFIER_PRIORITY_X);
174 break;
175 case DRM_FORMAT_MOD_LINEAR:
176 prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR);
177 break;
178 case DRM_FORMAT_MOD_INVALID:
179 default:
180 break;
181 }
182 }
183
184 return priority_to_modifier[prio];
185 }
186
is_modifier_external_only(enum pipe_format pfmt,uint64_t modifier)187 static inline bool is_modifier_external_only(enum pipe_format pfmt,
188 uint64_t modifier)
189 {
190 /* Only allow external usage for the following cases: YUV formats
191 * and the media-compression modifier. The render engine lacks
192 * support for rendering to a media-compressed surface if the
193 * compression ratio is large enough. By requiring external usage
194 * of media-compressed surfaces, resolves are avoided.
195 */
196 return util_format_is_yuv(pfmt) ||
197 modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
198 }
199
200 static void
iris_query_dmabuf_modifiers(struct pipe_screen * pscreen,enum pipe_format pfmt,int max,uint64_t * modifiers,unsigned int * external_only,int * count)201 iris_query_dmabuf_modifiers(struct pipe_screen *pscreen,
202 enum pipe_format pfmt,
203 int max,
204 uint64_t *modifiers,
205 unsigned int *external_only,
206 int *count)
207 {
208 struct iris_screen *screen = (void *) pscreen;
209 const struct intel_device_info *devinfo = &screen->devinfo;
210
211 uint64_t all_modifiers[] = {
212 DRM_FORMAT_MOD_LINEAR,
213 I915_FORMAT_MOD_X_TILED,
214 I915_FORMAT_MOD_Y_TILED,
215 I915_FORMAT_MOD_Y_TILED_CCS,
216 I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
217 I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
218 I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC,
219 };
220
221 int supported_mods = 0;
222
223 for (int i = 0; i < ARRAY_SIZE(all_modifiers); i++) {
224 if (!modifier_is_supported(devinfo, pfmt, 0, all_modifiers[i]))
225 continue;
226
227 if (supported_mods < max) {
228 if (modifiers)
229 modifiers[supported_mods] = all_modifiers[i];
230
231 if (external_only) {
232 external_only[supported_mods] =
233 is_modifier_external_only(pfmt, all_modifiers[i]);
234 }
235 }
236
237 supported_mods++;
238 }
239
240 *count = supported_mods;
241 }
242
243 static bool
iris_is_dmabuf_modifier_supported(struct pipe_screen * pscreen,uint64_t modifier,enum pipe_format pfmt,bool * external_only)244 iris_is_dmabuf_modifier_supported(struct pipe_screen *pscreen,
245 uint64_t modifier, enum pipe_format pfmt,
246 bool *external_only)
247 {
248 struct iris_screen *screen = (void *) pscreen;
249 const struct intel_device_info *devinfo = &screen->devinfo;
250
251 if (modifier_is_supported(devinfo, pfmt, 0, modifier)) {
252 if (external_only)
253 *external_only = is_modifier_external_only(pfmt, modifier);
254
255 return true;
256 }
257
258 return false;
259 }
260
261 static unsigned int
iris_get_dmabuf_modifier_planes(struct pipe_screen * pscreen,uint64_t modifier,enum pipe_format format)262 iris_get_dmabuf_modifier_planes(struct pipe_screen *pscreen, uint64_t modifier,
263 enum pipe_format format)
264 {
265 unsigned int planes = util_format_get_num_planes(format);
266
267 switch (modifier) {
268 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
269 return 3;
270 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
271 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
272 case I915_FORMAT_MOD_Y_TILED_CCS:
273 return 2 * planes;
274 default:
275 return planes;
276 }
277 }
278
279 enum isl_format
iris_image_view_get_format(struct iris_context * ice,const struct pipe_image_view * img)280 iris_image_view_get_format(struct iris_context *ice,
281 const struct pipe_image_view *img)
282 {
283 struct iris_screen *screen = (struct iris_screen *)ice->ctx.screen;
284 const struct intel_device_info *devinfo = &screen->devinfo;
285
286 isl_surf_usage_flags_t usage = ISL_SURF_USAGE_STORAGE_BIT;
287 enum isl_format isl_fmt =
288 iris_format_for_usage(devinfo, img->format, usage).fmt;
289
290 if (img->shader_access & PIPE_IMAGE_ACCESS_READ) {
291 /* On Gfx8, try to use typed surfaces reads (which support a
292 * limited number of formats), and if not possible, fall back
293 * to untyped reads.
294 */
295 if (devinfo->ver == 8 &&
296 !isl_has_matching_typed_storage_image_format(devinfo, isl_fmt))
297 return ISL_FORMAT_RAW;
298 else
299 return isl_lower_storage_image_format(devinfo, isl_fmt);
300 }
301
302 return isl_fmt;
303 }
304
305 static struct pipe_memory_object *
iris_memobj_create_from_handle(struct pipe_screen * pscreen,struct winsys_handle * whandle,bool dedicated)306 iris_memobj_create_from_handle(struct pipe_screen *pscreen,
307 struct winsys_handle *whandle,
308 bool dedicated)
309 {
310 struct iris_screen *screen = (struct iris_screen *)pscreen;
311 struct iris_memory_object *memobj = CALLOC_STRUCT(iris_memory_object);
312 struct iris_bo *bo;
313
314 if (!memobj)
315 return NULL;
316
317 switch (whandle->type) {
318 case WINSYS_HANDLE_TYPE_SHARED:
319 bo = iris_bo_gem_create_from_name(screen->bufmgr, "winsys image",
320 whandle->handle);
321 break;
322 case WINSYS_HANDLE_TYPE_FD:
323 bo = iris_bo_import_dmabuf(screen->bufmgr, whandle->handle);
324 break;
325 default:
326 unreachable("invalid winsys handle type");
327 }
328
329 if (!bo) {
330 free(memobj);
331 return NULL;
332 }
333
334 memobj->b.dedicated = dedicated;
335 memobj->bo = bo;
336 memobj->format = whandle->format;
337 memobj->stride = whandle->stride;
338
339 return &memobj->b;
340 }
341
342 static void
iris_memobj_destroy(struct pipe_screen * pscreen,struct pipe_memory_object * pmemobj)343 iris_memobj_destroy(struct pipe_screen *pscreen,
344 struct pipe_memory_object *pmemobj)
345 {
346 struct iris_memory_object *memobj = (struct iris_memory_object *)pmemobj;
347
348 iris_bo_unreference(memobj->bo);
349 free(memobj);
350 }
351
352 struct pipe_resource *
iris_resource_get_separate_stencil(struct pipe_resource * p_res)353 iris_resource_get_separate_stencil(struct pipe_resource *p_res)
354 {
355 /* For packed depth-stencil, we treat depth as the primary resource
356 * and store S8 as the "second plane" resource.
357 */
358 if (p_res->next && p_res->next->format == PIPE_FORMAT_S8_UINT)
359 return p_res->next;
360
361 return NULL;
362
363 }
364
365 static void
iris_resource_set_separate_stencil(struct pipe_resource * p_res,struct pipe_resource * stencil)366 iris_resource_set_separate_stencil(struct pipe_resource *p_res,
367 struct pipe_resource *stencil)
368 {
369 assert(util_format_has_depth(util_format_description(p_res->format)));
370 pipe_resource_reference(&p_res->next, stencil);
371 }
372
373 void
iris_get_depth_stencil_resources(struct pipe_resource * res,struct iris_resource ** out_z,struct iris_resource ** out_s)374 iris_get_depth_stencil_resources(struct pipe_resource *res,
375 struct iris_resource **out_z,
376 struct iris_resource **out_s)
377 {
378 if (!res) {
379 *out_z = NULL;
380 *out_s = NULL;
381 return;
382 }
383
384 if (res->format != PIPE_FORMAT_S8_UINT) {
385 *out_z = (void *) res;
386 *out_s = (void *) iris_resource_get_separate_stencil(res);
387 } else {
388 *out_z = NULL;
389 *out_s = (void *) res;
390 }
391 }
392
393 void
iris_resource_disable_aux(struct iris_resource * res)394 iris_resource_disable_aux(struct iris_resource *res)
395 {
396 iris_bo_unreference(res->aux.bo);
397 iris_bo_unreference(res->aux.clear_color_bo);
398 free(res->aux.state);
399
400 res->aux.usage = ISL_AUX_USAGE_NONE;
401 res->aux.possible_usages = 1 << ISL_AUX_USAGE_NONE;
402 res->aux.sampler_usages = 1 << ISL_AUX_USAGE_NONE;
403 res->aux.surf.size_B = 0;
404 res->aux.bo = NULL;
405 res->aux.extra_aux.surf.size_B = 0;
406 res->aux.clear_color_bo = NULL;
407 res->aux.state = NULL;
408 }
409
410 static uint32_t
iris_resource_alloc_flags(const struct iris_screen * screen,const struct pipe_resource * templ)411 iris_resource_alloc_flags(const struct iris_screen *screen,
412 const struct pipe_resource *templ)
413 {
414 if (templ->flags & IRIS_RESOURCE_FLAG_DEVICE_MEM)
415 return 0;
416
417 uint32_t flags = 0;
418
419 switch (templ->usage) {
420 case PIPE_USAGE_STAGING:
421 flags |= BO_ALLOC_SMEM | BO_ALLOC_COHERENT;
422 break;
423 case PIPE_USAGE_STREAM:
424 flags |= BO_ALLOC_SMEM;
425 break;
426 case PIPE_USAGE_DYNAMIC:
427 case PIPE_USAGE_DEFAULT:
428 case PIPE_USAGE_IMMUTABLE:
429 /* Use LMEM for these if possible */
430 break;
431 }
432
433 /* Scanout and shared buffers need to be WC (shared because they might be
434 * used for scanout)
435 */
436 if (templ->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_SHARED))
437 flags |= BO_ALLOC_SCANOUT;
438
439 if (templ->flags & (PIPE_RESOURCE_FLAG_MAP_COHERENT |
440 PIPE_RESOURCE_FLAG_MAP_PERSISTENT))
441 flags |= BO_ALLOC_SMEM;
442
443 if ((templ->bind & PIPE_BIND_SHARED) ||
444 util_format_get_num_planes(templ->format) > 1)
445 flags |= BO_ALLOC_NO_SUBALLOC;
446
447 return flags;
448 }
449
450 static void
iris_resource_destroy(struct pipe_screen * screen,struct pipe_resource * p_res)451 iris_resource_destroy(struct pipe_screen *screen,
452 struct pipe_resource *p_res)
453 {
454 struct iris_resource *res = (struct iris_resource *) p_res;
455
456 if (p_res->target == PIPE_BUFFER)
457 util_range_destroy(&res->valid_buffer_range);
458
459 iris_resource_disable_aux(res);
460
461 threaded_resource_deinit(p_res);
462 iris_bo_unreference(res->bo);
463 iris_pscreen_unref(res->orig_screen);
464
465 free(res);
466 }
467
468 static struct iris_resource *
iris_alloc_resource(struct pipe_screen * pscreen,const struct pipe_resource * templ)469 iris_alloc_resource(struct pipe_screen *pscreen,
470 const struct pipe_resource *templ)
471 {
472 struct iris_resource *res = calloc(1, sizeof(struct iris_resource));
473 if (!res)
474 return NULL;
475
476 res->base.b = *templ;
477 res->base.b.screen = pscreen;
478 res->orig_screen = iris_pscreen_ref(pscreen);
479 pipe_reference_init(&res->base.b.reference, 1);
480 threaded_resource_init(&res->base.b);
481
482 res->aux.possible_usages = 1 << ISL_AUX_USAGE_NONE;
483 res->aux.sampler_usages = 1 << ISL_AUX_USAGE_NONE;
484
485 if (templ->target == PIPE_BUFFER)
486 util_range_init(&res->valid_buffer_range);
487
488 return res;
489 }
490
491 unsigned
iris_get_num_logical_layers(const struct iris_resource * res,unsigned level)492 iris_get_num_logical_layers(const struct iris_resource *res, unsigned level)
493 {
494 if (res->surf.dim == ISL_SURF_DIM_3D)
495 return minify(res->surf.logical_level0_px.depth, level);
496 else
497 return res->surf.logical_level0_px.array_len;
498 }
499
500 static enum isl_aux_state **
create_aux_state_map(struct iris_resource * res,enum isl_aux_state initial)501 create_aux_state_map(struct iris_resource *res, enum isl_aux_state initial)
502 {
503 assert(res->aux.state == NULL);
504
505 uint32_t total_slices = 0;
506 for (uint32_t level = 0; level < res->surf.levels; level++)
507 total_slices += iris_get_num_logical_layers(res, level);
508
509 const size_t per_level_array_size =
510 res->surf.levels * sizeof(enum isl_aux_state *);
511
512 /* We're going to allocate a single chunk of data for both the per-level
513 * reference array and the arrays of aux_state. This makes cleanup
514 * significantly easier.
515 */
516 const size_t total_size =
517 per_level_array_size + total_slices * sizeof(enum isl_aux_state);
518
519 void *data = malloc(total_size);
520 if (!data)
521 return NULL;
522
523 enum isl_aux_state **per_level_arr = data;
524 enum isl_aux_state *s = data + per_level_array_size;
525 for (uint32_t level = 0; level < res->surf.levels; level++) {
526 per_level_arr[level] = s;
527 const unsigned level_layers = iris_get_num_logical_layers(res, level);
528 for (uint32_t a = 0; a < level_layers; a++)
529 *(s++) = initial;
530 }
531 assert((void *)s == data + total_size);
532
533 return per_level_arr;
534 }
535
536 static unsigned
iris_get_aux_clear_color_state_size(struct iris_screen * screen)537 iris_get_aux_clear_color_state_size(struct iris_screen *screen)
538 {
539 const struct intel_device_info *devinfo = &screen->devinfo;
540 return devinfo->ver >= 10 ? screen->isl_dev.ss.clear_color_state_size : 0;
541 }
542
543 static void
map_aux_addresses(struct iris_screen * screen,struct iris_resource * res,enum isl_format format,unsigned plane)544 map_aux_addresses(struct iris_screen *screen, struct iris_resource *res,
545 enum isl_format format, unsigned plane)
546 {
547 const struct intel_device_info *devinfo = &screen->devinfo;
548 if (devinfo->ver >= 12 && isl_aux_usage_has_ccs(res->aux.usage)) {
549 void *aux_map_ctx = iris_bufmgr_get_aux_map_context(screen->bufmgr);
550 assert(aux_map_ctx);
551 const unsigned aux_offset = res->aux.extra_aux.surf.size_B > 0 ?
552 res->aux.extra_aux.offset : res->aux.offset;
553 const uint64_t format_bits =
554 intel_aux_map_format_bits(res->surf.tiling, format, plane);
555 intel_aux_map_add_mapping(aux_map_ctx, res->bo->address + res->offset,
556 res->aux.bo->address + aux_offset,
557 res->surf.size_B, format_bits);
558 res->bo->aux_map_address = res->aux.bo->address;
559 }
560 }
561
562 static bool
want_ccs_e_for_format(const struct intel_device_info * devinfo,enum isl_format format)563 want_ccs_e_for_format(const struct intel_device_info *devinfo,
564 enum isl_format format)
565 {
566 if (!isl_format_supports_ccs_e(devinfo, format))
567 return false;
568
569 const struct isl_format_layout *fmtl = isl_format_get_layout(format);
570
571 /* CCS_E seems to significantly hurt performance with 32-bit floating
572 * point formats. For example, Paraview's "Wavelet Volume" case uses
573 * both R32_FLOAT and R32G32B32A32_FLOAT, and enabling CCS_E for those
574 * formats causes a 62% FPS drop.
575 *
576 * However, many benchmarks seem to use 16-bit float with no issues.
577 */
578 if (fmtl->channels.r.bits == 32 && fmtl->channels.r.type == ISL_SFLOAT)
579 return false;
580
581 return true;
582 }
583
584 static enum isl_surf_dim
target_to_isl_surf_dim(enum pipe_texture_target target)585 target_to_isl_surf_dim(enum pipe_texture_target target)
586 {
587 switch (target) {
588 case PIPE_BUFFER:
589 case PIPE_TEXTURE_1D:
590 case PIPE_TEXTURE_1D_ARRAY:
591 return ISL_SURF_DIM_1D;
592 case PIPE_TEXTURE_2D:
593 case PIPE_TEXTURE_CUBE:
594 case PIPE_TEXTURE_RECT:
595 case PIPE_TEXTURE_2D_ARRAY:
596 case PIPE_TEXTURE_CUBE_ARRAY:
597 return ISL_SURF_DIM_2D;
598 case PIPE_TEXTURE_3D:
599 return ISL_SURF_DIM_3D;
600 case PIPE_MAX_TEXTURE_TYPES:
601 break;
602 }
603 unreachable("invalid texture type");
604 }
605
606 static bool
iris_resource_configure_main(const struct iris_screen * screen,struct iris_resource * res,const struct pipe_resource * templ,uint64_t modifier,uint32_t row_pitch_B)607 iris_resource_configure_main(const struct iris_screen *screen,
608 struct iris_resource *res,
609 const struct pipe_resource *templ,
610 uint64_t modifier, uint32_t row_pitch_B)
611 {
612 res->mod_info = isl_drm_modifier_get_info(modifier);
613
614 if (modifier != DRM_FORMAT_MOD_INVALID && res->mod_info == NULL)
615 return false;
616
617 isl_tiling_flags_t tiling_flags = 0;
618
619 if (res->mod_info != NULL) {
620 tiling_flags = 1 << res->mod_info->tiling;
621 } else if (templ->usage == PIPE_USAGE_STAGING ||
622 templ->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR)) {
623 tiling_flags = ISL_TILING_LINEAR_BIT;
624 } else if (templ->bind & PIPE_BIND_SCANOUT) {
625 tiling_flags = screen->devinfo.has_tiling_uapi ?
626 ISL_TILING_X_BIT : ISL_TILING_LINEAR_BIT;
627 } else {
628 tiling_flags = ISL_TILING_ANY_MASK;
629 }
630
631 isl_surf_usage_flags_t usage = 0;
632
633 if (templ->usage == PIPE_USAGE_STAGING)
634 usage |= ISL_SURF_USAGE_STAGING_BIT;
635
636 if (templ->bind & PIPE_BIND_RENDER_TARGET)
637 usage |= ISL_SURF_USAGE_RENDER_TARGET_BIT;
638
639 if (templ->bind & PIPE_BIND_SAMPLER_VIEW)
640 usage |= ISL_SURF_USAGE_TEXTURE_BIT;
641
642 if (templ->bind & PIPE_BIND_SHADER_IMAGE)
643 usage |= ISL_SURF_USAGE_STORAGE_BIT;
644
645 if (templ->bind & PIPE_BIND_SCANOUT)
646 usage |= ISL_SURF_USAGE_DISPLAY_BIT;
647
648 if (templ->target == PIPE_TEXTURE_CUBE ||
649 templ->target == PIPE_TEXTURE_CUBE_ARRAY) {
650 usage |= ISL_SURF_USAGE_CUBE_BIT;
651 }
652
653 if (templ->usage != PIPE_USAGE_STAGING &&
654 util_format_is_depth_or_stencil(templ->format)) {
655
656 /* Should be handled by u_transfer_helper */
657 assert(!util_format_is_depth_and_stencil(templ->format));
658
659 usage |= templ->format == PIPE_FORMAT_S8_UINT ?
660 ISL_SURF_USAGE_STENCIL_BIT : ISL_SURF_USAGE_DEPTH_BIT;
661 }
662
663 const enum isl_format format =
664 iris_format_for_usage(&screen->devinfo, templ->format, usage).fmt;
665
666 const struct isl_surf_init_info init_info = {
667 .dim = target_to_isl_surf_dim(templ->target),
668 .format = format,
669 .width = templ->width0,
670 .height = templ->height0,
671 .depth = templ->depth0,
672 .levels = templ->last_level + 1,
673 .array_len = templ->array_size,
674 .samples = MAX2(templ->nr_samples, 1),
675 .min_alignment_B = 0,
676 .row_pitch_B = row_pitch_B,
677 .usage = usage,
678 .tiling_flags = tiling_flags
679 };
680
681 if (!isl_surf_init_s(&screen->isl_dev, &res->surf, &init_info))
682 return false;
683
684 res->internal_format = templ->format;
685
686 return true;
687 }
688
689 static bool
iris_get_ccs_surf(const struct isl_device * dev,const struct isl_surf * surf,struct isl_surf * aux_surf,struct isl_surf * extra_aux_surf,uint32_t row_pitch_B)690 iris_get_ccs_surf(const struct isl_device *dev,
691 const struct isl_surf *surf,
692 struct isl_surf *aux_surf,
693 struct isl_surf *extra_aux_surf,
694 uint32_t row_pitch_B)
695 {
696 assert(extra_aux_surf->size_B == 0);
697
698 struct isl_surf *ccs_surf;
699 const struct isl_surf *hiz_or_mcs_surf;
700 if (aux_surf->size_B > 0) {
701 assert(aux_surf->usage & (ISL_SURF_USAGE_HIZ_BIT |
702 ISL_SURF_USAGE_MCS_BIT));
703 hiz_or_mcs_surf = aux_surf;
704 ccs_surf = extra_aux_surf;
705 } else {
706 hiz_or_mcs_surf = NULL;
707 ccs_surf = aux_surf;
708 }
709
710 return isl_surf_get_ccs_surf(dev, surf, hiz_or_mcs_surf,
711 ccs_surf, row_pitch_B);
712 }
713
714 /**
715 * Configure aux for the resource, but don't allocate it. For images which
716 * might be shared with modifiers, we must allocate the image and aux data in
717 * a single bo.
718 *
719 * Returns false on unexpected error (e.g. allocation failed, or invalid
720 * configuration result).
721 */
722 static bool
iris_resource_configure_aux(struct iris_screen * screen,struct iris_resource * res,bool imported)723 iris_resource_configure_aux(struct iris_screen *screen,
724 struct iris_resource *res, bool imported)
725 {
726 const struct intel_device_info *devinfo = &screen->devinfo;
727
728 /* Try to create the auxiliary surfaces allowed by the modifier or by
729 * the user if no modifier is specified.
730 */
731 assert(!res->mod_info ||
732 res->mod_info->aux_usage == ISL_AUX_USAGE_NONE ||
733 res->mod_info->aux_usage == ISL_AUX_USAGE_CCS_E ||
734 res->mod_info->aux_usage == ISL_AUX_USAGE_GFX12_CCS_E ||
735 res->mod_info->aux_usage == ISL_AUX_USAGE_MC);
736
737 const bool has_mcs = !res->mod_info &&
738 isl_surf_get_mcs_surf(&screen->isl_dev, &res->surf, &res->aux.surf);
739
740 const bool has_hiz = !res->mod_info && !INTEL_DEBUG(DEBUG_NO_HIZ) &&
741 isl_surf_get_hiz_surf(&screen->isl_dev, &res->surf, &res->aux.surf);
742
743 const bool has_ccs =
744 ((!res->mod_info && !INTEL_DEBUG(DEBUG_NO_RBC)) ||
745 (res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE)) &&
746 iris_get_ccs_surf(&screen->isl_dev, &res->surf, &res->aux.surf,
747 &res->aux.extra_aux.surf, 0);
748
749 /* Having both HIZ and MCS is impossible. */
750 assert(!has_mcs || !has_hiz);
751
752 if (res->mod_info && has_ccs) {
753 /* Only allow a CCS modifier if the aux was created successfully. */
754 res->aux.possible_usages |= 1 << res->mod_info->aux_usage;
755 } else if (has_mcs) {
756 res->aux.possible_usages |=
757 1 << (has_ccs ? ISL_AUX_USAGE_MCS_CCS : ISL_AUX_USAGE_MCS);
758 } else if (has_hiz) {
759 if (!has_ccs) {
760 res->aux.possible_usages |= 1 << ISL_AUX_USAGE_HIZ;
761 } else if (res->surf.samples == 1 &&
762 (res->surf.usage & ISL_SURF_USAGE_TEXTURE_BIT)) {
763 /* If this resource is single-sampled and will be used as a texture,
764 * put the HiZ surface in write-through mode so that we can sample
765 * from it.
766 */
767 res->aux.possible_usages |= 1 << ISL_AUX_USAGE_HIZ_CCS_WT;
768 } else {
769 res->aux.possible_usages |= 1 << ISL_AUX_USAGE_HIZ_CCS;
770 }
771 } else if (has_ccs && isl_surf_usage_is_stencil(res->surf.usage)) {
772 res->aux.possible_usages |= 1 << ISL_AUX_USAGE_STC_CCS;
773 } else if (has_ccs) {
774 if (want_ccs_e_for_format(devinfo, res->surf.format)) {
775 res->aux.possible_usages |= devinfo->ver < 12 ?
776 1 << ISL_AUX_USAGE_CCS_E : 1 << ISL_AUX_USAGE_GFX12_CCS_E;
777 } else if (isl_format_supports_ccs_d(devinfo, res->surf.format)) {
778 res->aux.possible_usages |= 1 << ISL_AUX_USAGE_CCS_D;
779 }
780 }
781
782 res->aux.usage = util_last_bit(res->aux.possible_usages) - 1;
783
784 if (!has_hiz || iris_sample_with_depth_aux(devinfo, res))
785 res->aux.sampler_usages = res->aux.possible_usages;
786
787 enum isl_aux_state initial_state;
788 assert(!res->aux.bo);
789
790 switch (res->aux.usage) {
791 case ISL_AUX_USAGE_NONE:
792 /* Update relevant fields to indicate that aux is disabled. */
793 iris_resource_disable_aux(res);
794
795 /* Having no aux buffer is only okay if there's no modifier with aux. */
796 return !res->mod_info || res->mod_info->aux_usage == ISL_AUX_USAGE_NONE;
797 case ISL_AUX_USAGE_HIZ:
798 case ISL_AUX_USAGE_HIZ_CCS:
799 case ISL_AUX_USAGE_HIZ_CCS_WT:
800 initial_state = ISL_AUX_STATE_AUX_INVALID;
801 break;
802 case ISL_AUX_USAGE_MCS:
803 case ISL_AUX_USAGE_MCS_CCS:
804 /* The Ivybridge PRM, Vol 2 Part 1 p326 says:
805 *
806 * "When MCS buffer is enabled and bound to MSRT, it is required
807 * that it is cleared prior to any rendering."
808 *
809 * Since we only use the MCS buffer for rendering, we just clear it
810 * immediately on allocation. The clear value for MCS buffers is all
811 * 1's, so we simply memset it to 0xff.
812 */
813 initial_state = ISL_AUX_STATE_CLEAR;
814 break;
815 case ISL_AUX_USAGE_CCS_D:
816 case ISL_AUX_USAGE_CCS_E:
817 case ISL_AUX_USAGE_GFX12_CCS_E:
818 case ISL_AUX_USAGE_STC_CCS:
819 case ISL_AUX_USAGE_MC:
820 /* When CCS_E is used, we need to ensure that the CCS starts off in
821 * a valid state. From the Sky Lake PRM, "MCS Buffer for Render
822 * Target(s)":
823 *
824 * "If Software wants to enable Color Compression without Fast
825 * clear, Software needs to initialize MCS with zeros."
826 *
827 * A CCS value of 0 indicates that the corresponding block is in the
828 * pass-through state which is what we want.
829 *
830 * For CCS_D, do the same thing. On Gfx9+, this avoids having any
831 * undefined bits in the aux buffer.
832 */
833 if (imported) {
834 assert(res->aux.usage != ISL_AUX_USAGE_STC_CCS);
835 initial_state =
836 isl_drm_modifier_get_default_aux_state(res->mod_info->modifier);
837 } else {
838 initial_state = ISL_AUX_STATE_PASS_THROUGH;
839 }
840 break;
841 default:
842 unreachable("Unsupported aux mode");
843 }
844
845 /* Create the aux_state for the auxiliary buffer. */
846 res->aux.state = create_aux_state_map(res, initial_state);
847 if (!res->aux.state)
848 return false;
849
850 return true;
851 }
852
853 /**
854 * Initialize the aux buffer contents.
855 *
856 * Returns false on unexpected error (e.g. mapping a BO failed).
857 */
858 static bool
iris_resource_init_aux_buf(struct iris_resource * res,unsigned clear_color_state_size)859 iris_resource_init_aux_buf(struct iris_resource *res,
860 unsigned clear_color_state_size)
861 {
862 void *map = iris_bo_map(NULL, res->aux.bo, MAP_WRITE | MAP_RAW);
863
864 if (!map)
865 return false;
866
867 if (iris_resource_get_aux_state(res, 0, 0) != ISL_AUX_STATE_AUX_INVALID) {
868 /* See iris_resource_configure_aux for the memset_value rationale. */
869 uint8_t memset_value = isl_aux_usage_has_mcs(res->aux.usage) ? 0xFF : 0;
870 memset((char*)map + res->aux.offset, memset_value,
871 res->aux.surf.size_B);
872 }
873
874 memset((char*)map + res->aux.extra_aux.offset,
875 0, res->aux.extra_aux.surf.size_B);
876
877 /* Zero the indirect clear color to match ::fast_clear_color. */
878 memset((char *)map + res->aux.clear_color_offset, 0,
879 clear_color_state_size);
880
881 iris_bo_unmap(res->aux.bo);
882
883 if (clear_color_state_size > 0) {
884 res->aux.clear_color_bo = res->aux.bo;
885 iris_bo_reference(res->aux.clear_color_bo);
886 }
887
888 return true;
889 }
890
891 static void
import_aux_info(struct iris_resource * res,const struct iris_resource * aux_res)892 import_aux_info(struct iris_resource *res,
893 const struct iris_resource *aux_res)
894 {
895 assert(aux_res->aux.surf.row_pitch_B && aux_res->aux.offset);
896 assert(res->bo == aux_res->aux.bo);
897 assert(res->aux.surf.row_pitch_B == aux_res->aux.surf.row_pitch_B);
898 assert(res->bo->size >= aux_res->aux.offset + res->aux.surf.size_B);
899
900 iris_bo_reference(aux_res->aux.bo);
901 res->aux.bo = aux_res->aux.bo;
902 res->aux.offset = aux_res->aux.offset;
903 }
904
905 static void
iris_resource_finish_aux_import(struct pipe_screen * pscreen,struct iris_resource * res)906 iris_resource_finish_aux_import(struct pipe_screen *pscreen,
907 struct iris_resource *res)
908 {
909 struct iris_screen *screen = (struct iris_screen *)pscreen;
910
911 /* Create an array of resources. Combining main and aux planes is easier
912 * with indexing as opposed to scanning the linked list.
913 */
914 struct iris_resource *r[4] = { NULL, };
915 unsigned num_planes = 0;
916 unsigned num_main_planes = 0;
917 for (struct pipe_resource *p_res = &res->base.b; p_res; p_res = p_res->next) {
918 r[num_planes] = (struct iris_resource *)p_res;
919 num_main_planes += r[num_planes++]->bo != NULL;
920 }
921
922 /* Get an ISL format to use with the aux-map. */
923 enum isl_format format;
924 switch (res->external_format) {
925 case PIPE_FORMAT_NV12: format = ISL_FORMAT_PLANAR_420_8; break;
926 case PIPE_FORMAT_P010: format = ISL_FORMAT_PLANAR_420_10; break;
927 case PIPE_FORMAT_P012: format = ISL_FORMAT_PLANAR_420_12; break;
928 case PIPE_FORMAT_P016: format = ISL_FORMAT_PLANAR_420_16; break;
929 case PIPE_FORMAT_YUYV: format = ISL_FORMAT_YCRCB_NORMAL; break;
930 case PIPE_FORMAT_UYVY: format = ISL_FORMAT_YCRCB_SWAPY; break;
931 default: format = res->surf.format; break;
932 }
933
934 /* Combine main and aux plane information. */
935 switch (res->mod_info->modifier) {
936 case I915_FORMAT_MOD_Y_TILED_CCS:
937 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
938 assert(num_main_planes == 1 && num_planes == 2);
939 import_aux_info(r[0], r[1]);
940 map_aux_addresses(screen, r[0], format, 0);
941
942 /* Add on a clear color BO.
943 *
944 * Also add some padding to make sure the fast clear color state buffer
945 * starts at a 4K alignment to avoid some unknown issues. See the
946 * matching comment in iris_resource_create_with_modifiers().
947 */
948 if (iris_get_aux_clear_color_state_size(screen) > 0) {
949 res->aux.clear_color_bo =
950 iris_bo_alloc(screen->bufmgr, "clear color_buffer",
951 iris_get_aux_clear_color_state_size(screen), 4096,
952 IRIS_MEMZONE_OTHER, BO_ALLOC_ZEROED);
953 }
954 break;
955 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
956 assert(num_main_planes == 1 && num_planes == 3);
957 import_aux_info(r[0], r[1]);
958 map_aux_addresses(screen, r[0], format, 0);
959
960 /* Import the clear color BO. */
961 iris_bo_reference(r[2]->aux.clear_color_bo);
962 r[0]->aux.clear_color_bo = r[2]->aux.clear_color_bo;
963 r[0]->aux.clear_color_offset = r[2]->aux.clear_color_offset;
964 r[0]->aux.clear_color_unknown = true;
965 break;
966 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
967 if (num_main_planes == 1 && num_planes == 2) {
968 import_aux_info(r[0], r[1]);
969 map_aux_addresses(screen, r[0], format, 0);
970 } else if (num_main_planes == 2 && num_planes == 4) {
971 import_aux_info(r[0], r[2]);
972 import_aux_info(r[1], r[3]);
973 map_aux_addresses(screen, r[0], format, 0);
974 map_aux_addresses(screen, r[1], format, 1);
975 } else {
976 /* Gallium has lowered a single main plane into two. */
977 assert(num_main_planes == 2 && num_planes == 3);
978 assert(isl_format_is_yuv(format) && !isl_format_is_planar(format));
979 import_aux_info(r[0], r[2]);
980 import_aux_info(r[1], r[2]);
981 map_aux_addresses(screen, r[0], format, 0);
982 }
983 assert(!isl_aux_usage_has_fast_clears(res->mod_info->aux_usage));
984 break;
985 default:
986 assert(res->mod_info->aux_usage == ISL_AUX_USAGE_NONE);
987 break;
988 }
989 }
990
991 static struct pipe_resource *
iris_resource_create_for_buffer(struct pipe_screen * pscreen,const struct pipe_resource * templ)992 iris_resource_create_for_buffer(struct pipe_screen *pscreen,
993 const struct pipe_resource *templ)
994 {
995 struct iris_screen *screen = (struct iris_screen *)pscreen;
996 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
997
998 assert(templ->target == PIPE_BUFFER);
999 assert(templ->height0 <= 1);
1000 assert(templ->depth0 <= 1);
1001 assert(templ->format == PIPE_FORMAT_NONE ||
1002 util_format_get_blocksize(templ->format) == 1);
1003
1004 res->internal_format = templ->format;
1005 res->surf.tiling = ISL_TILING_LINEAR;
1006
1007 enum iris_memory_zone memzone = IRIS_MEMZONE_OTHER;
1008 const char *name = templ->target == PIPE_BUFFER ? "buffer" : "miptree";
1009 if (templ->flags & IRIS_RESOURCE_FLAG_SHADER_MEMZONE) {
1010 memzone = IRIS_MEMZONE_SHADER;
1011 name = "shader kernels";
1012 } else if (templ->flags & IRIS_RESOURCE_FLAG_SURFACE_MEMZONE) {
1013 memzone = IRIS_MEMZONE_SURFACE;
1014 name = "surface state";
1015 } else if (templ->flags & IRIS_RESOURCE_FLAG_DYNAMIC_MEMZONE) {
1016 memzone = IRIS_MEMZONE_DYNAMIC;
1017 name = "dynamic state";
1018 } else if (templ->flags & IRIS_RESOURCE_FLAG_BINDLESS_MEMZONE) {
1019 memzone = IRIS_MEMZONE_BINDLESS;
1020 name = "bindless surface state";
1021 }
1022
1023 unsigned flags = iris_resource_alloc_flags(screen, templ);
1024
1025 res->bo =
1026 iris_bo_alloc(screen->bufmgr, name, templ->width0, 1, memzone, flags);
1027
1028 if (!res->bo) {
1029 iris_resource_destroy(pscreen, &res->base.b);
1030 return NULL;
1031 }
1032
1033 if (templ->bind & PIPE_BIND_SHARED) {
1034 iris_bo_mark_exported(res->bo);
1035 res->base.is_shared = true;
1036 }
1037
1038 return &res->base.b;
1039 }
1040
1041 static struct pipe_resource *
iris_resource_create_with_modifiers(struct pipe_screen * pscreen,const struct pipe_resource * templ,const uint64_t * modifiers,int modifiers_count)1042 iris_resource_create_with_modifiers(struct pipe_screen *pscreen,
1043 const struct pipe_resource *templ,
1044 const uint64_t *modifiers,
1045 int modifiers_count)
1046 {
1047 struct iris_screen *screen = (struct iris_screen *)pscreen;
1048 struct intel_device_info *devinfo = &screen->devinfo;
1049 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
1050
1051 if (!res)
1052 return NULL;
1053
1054 uint64_t modifier =
1055 select_best_modifier(devinfo, templ, modifiers, modifiers_count);
1056
1057 if (modifier == DRM_FORMAT_MOD_INVALID && modifiers_count > 0) {
1058 fprintf(stderr, "Unsupported modifier, resource creation failed.\n");
1059 goto fail;
1060 }
1061
1062 UNUSED const bool isl_surf_created_successfully =
1063 iris_resource_configure_main(screen, res, templ, modifier, 0);
1064 assert(isl_surf_created_successfully);
1065
1066 const char *name = "miptree";
1067 enum iris_memory_zone memzone = IRIS_MEMZONE_OTHER;
1068
1069 unsigned int flags = iris_resource_alloc_flags(screen, templ);
1070
1071 /* These are for u_upload_mgr buffers only */
1072 assert(!(templ->flags & (IRIS_RESOURCE_FLAG_SHADER_MEMZONE |
1073 IRIS_RESOURCE_FLAG_SURFACE_MEMZONE |
1074 IRIS_RESOURCE_FLAG_DYNAMIC_MEMZONE |
1075 IRIS_RESOURCE_FLAG_BINDLESS_MEMZONE)));
1076
1077 if (!iris_resource_configure_aux(screen, res, false))
1078 goto fail;
1079
1080 /* Modifiers require the aux data to be in the same buffer as the main
1081 * surface, but we combine them even when a modifier is not being used.
1082 */
1083 uint64_t bo_size = res->surf.size_B;
1084
1085 /* Allocate space for the aux buffer. */
1086 if (res->aux.surf.size_B > 0) {
1087 res->aux.offset = ALIGN(bo_size, res->aux.surf.alignment_B);
1088 bo_size = res->aux.offset + res->aux.surf.size_B;
1089 }
1090
1091 /* Allocate space for the extra aux buffer. */
1092 if (res->aux.extra_aux.surf.size_B > 0) {
1093 res->aux.extra_aux.offset =
1094 ALIGN(bo_size, res->aux.extra_aux.surf.alignment_B);
1095 bo_size = res->aux.extra_aux.offset + res->aux.extra_aux.surf.size_B;
1096 }
1097
1098 /* Allocate space for the indirect clear color.
1099 *
1100 * Also add some padding to make sure the fast clear color state buffer
1101 * starts at a 4K alignment. We believe that 256B might be enough, but due
1102 * to lack of testing we will leave this as 4K for now.
1103 */
1104 if (res->aux.surf.size_B > 0) {
1105 res->aux.clear_color_offset = ALIGN(bo_size, 4096);
1106 bo_size = res->aux.clear_color_offset +
1107 iris_get_aux_clear_color_state_size(screen);
1108 }
1109
1110 uint32_t alignment = MAX2(4096, res->surf.alignment_B);
1111 res->bo =
1112 iris_bo_alloc(screen->bufmgr, name, bo_size, alignment, memzone, flags);
1113
1114 if (!res->bo)
1115 goto fail;
1116
1117 if (res->aux.surf.size_B > 0) {
1118 res->aux.bo = res->bo;
1119 iris_bo_reference(res->aux.bo);
1120 unsigned clear_color_state_size =
1121 iris_get_aux_clear_color_state_size(screen);
1122 if (!iris_resource_init_aux_buf(res, clear_color_state_size))
1123 goto fail;
1124 map_aux_addresses(screen, res, res->surf.format, 0);
1125 }
1126
1127 if (templ->bind & PIPE_BIND_SHARED) {
1128 iris_bo_mark_exported(res->bo);
1129 res->base.is_shared = true;
1130 }
1131
1132 return &res->base.b;
1133
1134 fail:
1135 fprintf(stderr, "XXX: resource creation failed\n");
1136 iris_resource_destroy(pscreen, &res->base.b);
1137 return NULL;
1138 }
1139
1140 static struct pipe_resource *
iris_resource_create(struct pipe_screen * pscreen,const struct pipe_resource * templ)1141 iris_resource_create(struct pipe_screen *pscreen,
1142 const struct pipe_resource *templ)
1143 {
1144 if (templ->target == PIPE_BUFFER)
1145 return iris_resource_create_for_buffer(pscreen, templ);
1146 else
1147 return iris_resource_create_with_modifiers(pscreen, templ, NULL, 0);
1148 }
1149
1150 static uint64_t
tiling_to_modifier(uint32_t tiling)1151 tiling_to_modifier(uint32_t tiling)
1152 {
1153 static const uint64_t map[] = {
1154 [I915_TILING_NONE] = DRM_FORMAT_MOD_LINEAR,
1155 [I915_TILING_X] = I915_FORMAT_MOD_X_TILED,
1156 [I915_TILING_Y] = I915_FORMAT_MOD_Y_TILED,
1157 };
1158
1159 assert(tiling < ARRAY_SIZE(map));
1160
1161 return map[tiling];
1162 }
1163
1164 static struct pipe_resource *
iris_resource_from_user_memory(struct pipe_screen * pscreen,const struct pipe_resource * templ,void * user_memory)1165 iris_resource_from_user_memory(struct pipe_screen *pscreen,
1166 const struct pipe_resource *templ,
1167 void *user_memory)
1168 {
1169 struct iris_screen *screen = (struct iris_screen *)pscreen;
1170 struct iris_bufmgr *bufmgr = screen->bufmgr;
1171 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
1172 if (!res)
1173 return NULL;
1174
1175 assert(templ->target == PIPE_BUFFER);
1176
1177 res->internal_format = templ->format;
1178 res->base.is_user_ptr = true;
1179 res->bo = iris_bo_create_userptr(bufmgr, "user",
1180 user_memory, templ->width0,
1181 IRIS_MEMZONE_OTHER);
1182 if (!res->bo) {
1183 iris_resource_destroy(pscreen, &res->base.b);
1184 return NULL;
1185 }
1186
1187 util_range_add(&res->base.b, &res->valid_buffer_range, 0, templ->width0);
1188
1189 return &res->base.b;
1190 }
1191
1192 static bool
mod_plane_is_clear_color(uint64_t modifier,uint32_t plane)1193 mod_plane_is_clear_color(uint64_t modifier, uint32_t plane)
1194 {
1195 ASSERTED const struct isl_drm_modifier_info *mod_info =
1196 isl_drm_modifier_get_info(modifier);
1197 assert(mod_info);
1198
1199 switch (modifier) {
1200 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
1201 assert(mod_info->supports_clear_color);
1202 return plane == 2;
1203 default:
1204 assert(!mod_info->supports_clear_color);
1205 return false;
1206 }
1207 }
1208
1209 static unsigned
get_num_planes(const struct pipe_resource * resource)1210 get_num_planes(const struct pipe_resource *resource)
1211 {
1212 unsigned count = 0;
1213 for (const struct pipe_resource *cur = resource; cur; cur = cur->next)
1214 count++;
1215
1216 return count;
1217 }
1218
1219 static struct pipe_resource *
iris_resource_from_handle(struct pipe_screen * pscreen,const struct pipe_resource * templ,struct winsys_handle * whandle,unsigned usage)1220 iris_resource_from_handle(struct pipe_screen *pscreen,
1221 const struct pipe_resource *templ,
1222 struct winsys_handle *whandle,
1223 unsigned usage)
1224 {
1225 assert(templ->target != PIPE_BUFFER);
1226
1227 struct iris_screen *screen = (struct iris_screen *)pscreen;
1228 struct iris_bufmgr *bufmgr = screen->bufmgr;
1229 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
1230 if (!res)
1231 return NULL;
1232
1233 switch (whandle->type) {
1234 case WINSYS_HANDLE_TYPE_FD:
1235 res->bo = iris_bo_import_dmabuf(bufmgr, whandle->handle);
1236 break;
1237 case WINSYS_HANDLE_TYPE_SHARED:
1238 res->bo = iris_bo_gem_create_from_name(bufmgr, "winsys image",
1239 whandle->handle);
1240 break;
1241 default:
1242 unreachable("invalid winsys handle type");
1243 }
1244 if (!res->bo)
1245 goto fail;
1246
1247 res->offset = whandle->offset;
1248 res->external_format = whandle->format;
1249
1250 /* Create a surface for each plane specified by the external format. */
1251 if (whandle->plane < util_format_get_num_planes(whandle->format)) {
1252 uint64_t modifier = whandle->modifier;
1253
1254 if (whandle->modifier == DRM_FORMAT_MOD_INVALID) {
1255 /* We don't have a modifier; match whatever GEM_GET_TILING says */
1256 uint32_t tiling;
1257 iris_gem_get_tiling(res->bo, &tiling);
1258 modifier = tiling_to_modifier(tiling);
1259 }
1260
1261 UNUSED const bool isl_surf_created_successfully =
1262 iris_resource_configure_main(screen, res, templ, modifier,
1263 whandle->stride);
1264 assert(isl_surf_created_successfully);
1265
1266 UNUSED const bool ok = iris_resource_configure_aux(screen, res, true);
1267 assert(ok);
1268 /* The gallium dri layer will create a separate plane resource for the
1269 * aux image. iris_resource_finish_aux_import will merge the separate aux
1270 * parameters back into a single iris_resource.
1271 */
1272 } else if (mod_plane_is_clear_color(whandle->modifier, whandle->plane)) {
1273 res->aux.clear_color_offset = whandle->offset;
1274 res->aux.clear_color_bo = res->bo;
1275 res->bo = NULL;
1276 } else {
1277 /* Save modifier import information to reconstruct later. After import,
1278 * this will be available under a second image accessible from the main
1279 * image with res->base.next. See iris_resource_finish_aux_import.
1280 */
1281 res->aux.surf.row_pitch_B = whandle->stride;
1282 res->aux.offset = whandle->offset;
1283 res->aux.bo = res->bo;
1284 res->bo = NULL;
1285 }
1286
1287 if (get_num_planes(&res->base.b) ==
1288 iris_get_dmabuf_modifier_planes(pscreen, whandle->modifier,
1289 whandle->format)) {
1290 iris_resource_finish_aux_import(pscreen, res);
1291 }
1292
1293 return &res->base.b;
1294
1295 fail:
1296 iris_resource_destroy(pscreen, &res->base.b);
1297 return NULL;
1298 }
1299
1300 static struct pipe_resource *
iris_resource_from_memobj(struct pipe_screen * pscreen,const struct pipe_resource * templ,struct pipe_memory_object * pmemobj,uint64_t offset)1301 iris_resource_from_memobj(struct pipe_screen *pscreen,
1302 const struct pipe_resource *templ,
1303 struct pipe_memory_object *pmemobj,
1304 uint64_t offset)
1305 {
1306 struct iris_screen *screen = (struct iris_screen *)pscreen;
1307 struct iris_memory_object *memobj = (struct iris_memory_object *)pmemobj;
1308 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
1309
1310 if (!res)
1311 return NULL;
1312
1313 if (templ->flags & PIPE_RESOURCE_FLAG_TEXTURING_MORE_LIKELY) {
1314 UNUSED const bool isl_surf_created_successfully =
1315 iris_resource_configure_main(screen, res, templ, DRM_FORMAT_MOD_INVALID, 0);
1316 assert(isl_surf_created_successfully);
1317 }
1318
1319 res->bo = memobj->bo;
1320 res->offset = offset;
1321 res->external_format = memobj->format;
1322
1323 iris_bo_reference(memobj->bo);
1324
1325 return &res->base.b;
1326 }
1327
1328 /* Handle combined depth/stencil with memory objects.
1329 *
1330 * This function is modeled after u_transfer_helper_resource_create.
1331 */
1332 static struct pipe_resource *
iris_resource_from_memobj_wrapper(struct pipe_screen * pscreen,const struct pipe_resource * templ,struct pipe_memory_object * pmemobj,uint64_t offset)1333 iris_resource_from_memobj_wrapper(struct pipe_screen *pscreen,
1334 const struct pipe_resource *templ,
1335 struct pipe_memory_object *pmemobj,
1336 uint64_t offset)
1337 {
1338 enum pipe_format format = templ->format;
1339
1340 /* Normal case, no special handling: */
1341 if (!(util_format_is_depth_and_stencil(format)))
1342 return iris_resource_from_memobj(pscreen, templ, pmemobj, offset);
1343
1344 struct pipe_resource t = *templ;
1345 t.format = util_format_get_depth_only(format);
1346
1347 struct pipe_resource *prsc =
1348 iris_resource_from_memobj(pscreen, &t, pmemobj, offset);
1349 if (!prsc)
1350 return NULL;
1351
1352 struct iris_resource *res = (struct iris_resource *) prsc;
1353
1354 /* Stencil offset in the buffer without aux. */
1355 uint64_t s_offset = offset +
1356 ALIGN(res->surf.size_B, res->surf.alignment_B);
1357
1358 prsc->format = format; /* frob the format back to the "external" format */
1359
1360 t.format = PIPE_FORMAT_S8_UINT;
1361 struct pipe_resource *stencil =
1362 iris_resource_from_memobj(pscreen, &t, pmemobj, s_offset);
1363 if (!stencil) {
1364 iris_resource_destroy(pscreen, prsc);
1365 return NULL;
1366 }
1367
1368 iris_resource_set_separate_stencil(prsc, stencil);
1369 return prsc;
1370 }
1371
1372 static void
iris_flush_resource(struct pipe_context * ctx,struct pipe_resource * resource)1373 iris_flush_resource(struct pipe_context *ctx, struct pipe_resource *resource)
1374 {
1375 struct iris_context *ice = (struct iris_context *)ctx;
1376 struct iris_resource *res = (void *) resource;
1377 const struct isl_drm_modifier_info *mod = res->mod_info;
1378
1379 iris_resource_prepare_access(ice, res,
1380 0, INTEL_REMAINING_LEVELS,
1381 0, INTEL_REMAINING_LAYERS,
1382 mod ? mod->aux_usage : ISL_AUX_USAGE_NONE,
1383 mod ? mod->supports_clear_color : false);
1384
1385 if (!res->mod_info && res->aux.usage != ISL_AUX_USAGE_NONE) {
1386 /* flush_resource may be used to prepare an image for sharing external
1387 * to the driver (e.g. via eglCreateImage). To account for this, make
1388 * sure to get rid of any compression that a consumer wouldn't know how
1389 * to handle.
1390 */
1391 for (int i = 0; i < IRIS_BATCH_COUNT; i++) {
1392 if (iris_batch_references(&ice->batches[i], res->bo))
1393 iris_batch_flush(&ice->batches[i]);
1394 }
1395
1396 iris_resource_disable_aux(res);
1397 }
1398 }
1399
1400 /**
1401 * Reallocate a (non-external) resource into new storage, copying the data
1402 * and modifying the original resource to point at the new storage.
1403 *
1404 * This is useful for e.g. moving a suballocated internal resource to a
1405 * dedicated allocation that can be exported by itself.
1406 */
1407 static void
iris_reallocate_resource_inplace(struct iris_context * ice,struct iris_resource * old_res,unsigned new_bind_flag)1408 iris_reallocate_resource_inplace(struct iris_context *ice,
1409 struct iris_resource *old_res,
1410 unsigned new_bind_flag)
1411 {
1412 struct pipe_screen *pscreen = ice->ctx.screen;
1413
1414 if (iris_bo_is_external(old_res->bo))
1415 return;
1416
1417 assert(old_res->mod_info == NULL);
1418 assert(old_res->bo == old_res->aux.bo || old_res->aux.bo == NULL);
1419 assert(old_res->bo == old_res->aux.clear_color_bo ||
1420 old_res->aux.clear_color_bo == NULL);
1421 assert(old_res->external_format == PIPE_FORMAT_NONE);
1422
1423 struct pipe_resource templ = old_res->base.b;
1424 templ.bind |= new_bind_flag;
1425
1426 struct iris_resource *new_res =
1427 (void *) pscreen->resource_create(pscreen, &templ);
1428
1429 assert(iris_bo_is_real(new_res->bo));
1430
1431 struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
1432
1433 if (old_res->base.b.target == PIPE_BUFFER) {
1434 struct pipe_box box = (struct pipe_box) {
1435 .width = old_res->base.b.width0,
1436 .height = 1,
1437 };
1438
1439 iris_copy_region(&ice->blorp, batch, &new_res->base.b, 0, 0, 0, 0,
1440 &old_res->base.b, 0, &box);
1441 } else {
1442 for (unsigned l = 0; l <= templ.last_level; l++) {
1443 struct pipe_box box = (struct pipe_box) {
1444 .width = u_minify(templ.width0, l),
1445 .height = u_minify(templ.height0, l),
1446 .depth = util_num_layers(&templ, l),
1447 };
1448
1449 iris_copy_region(&ice->blorp, batch, &new_res->base.b, l, 0, 0, 0,
1450 &old_res->base.b, l, &box);
1451 }
1452 }
1453
1454 iris_flush_resource(&ice->ctx, &new_res->base.b);
1455
1456 struct iris_bo *old_bo = old_res->bo;
1457 struct iris_bo *old_aux_bo = old_res->aux.bo;
1458 struct iris_bo *old_clear_color_bo = old_res->aux.clear_color_bo;
1459
1460 /* Replace the structure fields with the new ones */
1461 old_res->base.b.bind = templ.bind;
1462 old_res->bo = new_res->bo;
1463 old_res->aux.surf = new_res->aux.surf;
1464 old_res->aux.bo = new_res->aux.bo;
1465 old_res->aux.offset = new_res->aux.offset;
1466 old_res->aux.extra_aux.surf = new_res->aux.extra_aux.surf;
1467 old_res->aux.extra_aux.offset = new_res->aux.extra_aux.offset;
1468 old_res->aux.clear_color_bo = new_res->aux.clear_color_bo;
1469 old_res->aux.clear_color_offset = new_res->aux.clear_color_offset;
1470 old_res->aux.usage = new_res->aux.usage;
1471 old_res->aux.possible_usages = new_res->aux.possible_usages;
1472 old_res->aux.sampler_usages = new_res->aux.sampler_usages;
1473
1474 if (new_res->aux.state) {
1475 assert(old_res->aux.state);
1476 for (unsigned l = 0; l <= templ.last_level; l++) {
1477 unsigned layers = util_num_layers(&templ, l);
1478 for (unsigned z = 0; z < layers; z++) {
1479 enum isl_aux_state aux =
1480 iris_resource_get_aux_state(new_res, l, z);
1481 iris_resource_set_aux_state(ice, old_res, l, z, 1, aux);
1482 }
1483 }
1484 }
1485
1486 /* old_res now points at the new BOs, make new_res point at the old ones
1487 * so they'll be freed when we unreference the resource below.
1488 */
1489 new_res->bo = old_bo;
1490 new_res->aux.bo = old_aux_bo;
1491 new_res->aux.clear_color_bo = old_clear_color_bo;
1492
1493 pipe_resource_reference((struct pipe_resource **)&new_res, NULL);
1494 }
1495
1496 static void
iris_resource_disable_suballoc_on_first_query(struct pipe_screen * pscreen,struct pipe_context * ctx,struct iris_resource * res)1497 iris_resource_disable_suballoc_on_first_query(struct pipe_screen *pscreen,
1498 struct pipe_context *ctx,
1499 struct iris_resource *res)
1500 {
1501 if (iris_bo_is_real(res->bo))
1502 return;
1503
1504 assert(!(res->base.b.bind & PIPE_BIND_SHARED));
1505
1506 bool destroy_context;
1507 if (ctx) {
1508 ctx = threaded_context_unwrap_sync(ctx);
1509 destroy_context = false;
1510 } else {
1511 /* We need to execute a blit on some GPU context, but the DRI layer
1512 * often doesn't give us one. So we have to invent a temporary one.
1513 *
1514 * We can't store a permanent context in the screen, as it would cause
1515 * circular refcounting where screens reference contexts that reference
1516 * resources, while resources reference screens...causing nothing to be
1517 * freed. So we just create and destroy a temporary one here.
1518 */
1519 ctx = iris_create_context(pscreen, NULL, 0);
1520 destroy_context = true;
1521 }
1522
1523 struct iris_context *ice = (struct iris_context *)ctx;
1524
1525 iris_reallocate_resource_inplace(ice, res, PIPE_BIND_SHARED);
1526 assert(res->base.b.bind & PIPE_BIND_SHARED);
1527
1528 if (destroy_context)
1529 iris_destroy_context(ctx);
1530 }
1531
1532
1533 static void
iris_resource_disable_aux_on_first_query(struct pipe_resource * resource,unsigned usage)1534 iris_resource_disable_aux_on_first_query(struct pipe_resource *resource,
1535 unsigned usage)
1536 {
1537 struct iris_resource *res = (struct iris_resource *)resource;
1538 bool mod_with_aux =
1539 res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE;
1540
1541 /* Disable aux usage if explicit flush not set and this is the first time
1542 * we are dealing with this resource and the resource was not created with
1543 * a modifier with aux.
1544 */
1545 if (!mod_with_aux &&
1546 (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH) && res->aux.usage != 0) &&
1547 p_atomic_read(&resource->reference.count) == 1) {
1548 iris_resource_disable_aux(res);
1549 }
1550 }
1551
1552 static bool
iris_resource_get_param(struct pipe_screen * pscreen,struct pipe_context * ctx,struct pipe_resource * resource,unsigned plane,unsigned layer,unsigned level,enum pipe_resource_param param,unsigned handle_usage,uint64_t * value)1553 iris_resource_get_param(struct pipe_screen *pscreen,
1554 struct pipe_context *ctx,
1555 struct pipe_resource *resource,
1556 unsigned plane,
1557 unsigned layer,
1558 unsigned level,
1559 enum pipe_resource_param param,
1560 unsigned handle_usage,
1561 uint64_t *value)
1562 {
1563 struct iris_screen *screen = (struct iris_screen *)pscreen;
1564 struct iris_resource *res = (struct iris_resource *)resource;
1565 bool mod_with_aux =
1566 res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE;
1567 bool wants_aux = mod_with_aux && plane > 0;
1568 bool result;
1569 unsigned handle;
1570
1571 iris_resource_disable_aux_on_first_query(resource, handle_usage);
1572 iris_resource_disable_suballoc_on_first_query(pscreen, ctx, res);
1573
1574 struct iris_bo *bo = wants_aux ? res->aux.bo : res->bo;
1575
1576 assert(iris_bo_is_real(bo));
1577
1578 switch (param) {
1579 case PIPE_RESOURCE_PARAM_NPLANES:
1580 if (mod_with_aux) {
1581 *value = iris_get_dmabuf_modifier_planes(pscreen,
1582 res->mod_info->modifier,
1583 res->external_format);
1584 } else {
1585 *value = get_num_planes(&res->base.b);
1586 }
1587 return true;
1588 case PIPE_RESOURCE_PARAM_STRIDE:
1589 *value = wants_aux ? res->aux.surf.row_pitch_B : res->surf.row_pitch_B;
1590 return true;
1591 case PIPE_RESOURCE_PARAM_OFFSET:
1592 *value = wants_aux ?
1593 mod_plane_is_clear_color(res->mod_info->modifier, plane) ?
1594 res->aux.clear_color_offset : res->aux.offset : 0;
1595 return true;
1596 case PIPE_RESOURCE_PARAM_MODIFIER:
1597 *value = res->mod_info ? res->mod_info->modifier :
1598 tiling_to_modifier(isl_tiling_to_i915_tiling(res->surf.tiling));
1599 return true;
1600 case PIPE_RESOURCE_PARAM_HANDLE_TYPE_SHARED:
1601 if (!wants_aux)
1602 iris_gem_set_tiling(bo, &res->surf);
1603
1604 result = iris_bo_flink(bo, &handle) == 0;
1605 if (result)
1606 *value = handle;
1607 return result;
1608 case PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS: {
1609 if (!wants_aux)
1610 iris_gem_set_tiling(bo, &res->surf);
1611
1612 /* Because we share the same drm file across multiple iris_screen, when
1613 * we export a GEM handle we must make sure it is valid in the DRM file
1614 * descriptor the caller is using (this is the FD given at screen
1615 * creation).
1616 */
1617 uint32_t handle;
1618 if (iris_bo_export_gem_handle_for_device(bo, screen->winsys_fd, &handle))
1619 return false;
1620 *value = handle;
1621 return true;
1622 }
1623
1624 case PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD:
1625 if (!wants_aux)
1626 iris_gem_set_tiling(bo, &res->surf);
1627
1628 result = iris_bo_export_dmabuf(bo, (int *) &handle) == 0;
1629 if (result)
1630 *value = handle;
1631 return result;
1632 default:
1633 return false;
1634 }
1635 }
1636
1637 static bool
iris_resource_get_handle(struct pipe_screen * pscreen,struct pipe_context * ctx,struct pipe_resource * resource,struct winsys_handle * whandle,unsigned usage)1638 iris_resource_get_handle(struct pipe_screen *pscreen,
1639 struct pipe_context *ctx,
1640 struct pipe_resource *resource,
1641 struct winsys_handle *whandle,
1642 unsigned usage)
1643 {
1644 struct iris_screen *screen = (struct iris_screen *) pscreen;
1645 struct iris_resource *res = (struct iris_resource *)resource;
1646 bool mod_with_aux =
1647 res->mod_info && res->mod_info->aux_usage != ISL_AUX_USAGE_NONE;
1648
1649 iris_resource_disable_aux_on_first_query(resource, usage);
1650 iris_resource_disable_suballoc_on_first_query(pscreen, ctx, res);
1651
1652 assert(iris_bo_is_real(res->bo));
1653
1654 struct iris_bo *bo;
1655 if (res->mod_info &&
1656 mod_plane_is_clear_color(res->mod_info->modifier, whandle->plane)) {
1657 bo = res->aux.clear_color_bo;
1658 whandle->offset = res->aux.clear_color_offset;
1659 } else if (mod_with_aux && whandle->plane > 0) {
1660 bo = res->aux.bo;
1661 whandle->stride = res->aux.surf.row_pitch_B;
1662 whandle->offset = res->aux.offset;
1663 } else {
1664 /* If this is a buffer, stride should be 0 - no need to special case */
1665 whandle->stride = res->surf.row_pitch_B;
1666 bo = res->bo;
1667 }
1668
1669 whandle->format = res->external_format;
1670 whandle->modifier =
1671 res->mod_info ? res->mod_info->modifier
1672 : tiling_to_modifier(isl_tiling_to_i915_tiling(res->surf.tiling));
1673
1674 #ifndef NDEBUG
1675 enum isl_aux_usage allowed_usage =
1676 usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH ? res->aux.usage :
1677 res->mod_info ? res->mod_info->aux_usage : ISL_AUX_USAGE_NONE;
1678
1679 if (res->aux.usage != allowed_usage) {
1680 enum isl_aux_state aux_state = iris_resource_get_aux_state(res, 0, 0);
1681 assert(aux_state == ISL_AUX_STATE_RESOLVED ||
1682 aux_state == ISL_AUX_STATE_PASS_THROUGH);
1683 }
1684 #endif
1685
1686 switch (whandle->type) {
1687 case WINSYS_HANDLE_TYPE_SHARED:
1688 iris_gem_set_tiling(bo, &res->surf);
1689 return iris_bo_flink(bo, &whandle->handle) == 0;
1690 case WINSYS_HANDLE_TYPE_KMS: {
1691 iris_gem_set_tiling(bo, &res->surf);
1692
1693 /* Because we share the same drm file across multiple iris_screen, when
1694 * we export a GEM handle we must make sure it is valid in the DRM file
1695 * descriptor the caller is using (this is the FD given at screen
1696 * creation).
1697 */
1698 uint32_t handle;
1699 if (iris_bo_export_gem_handle_for_device(bo, screen->winsys_fd, &handle))
1700 return false;
1701 whandle->handle = handle;
1702 return true;
1703 }
1704 case WINSYS_HANDLE_TYPE_FD:
1705 iris_gem_set_tiling(bo, &res->surf);
1706 return iris_bo_export_dmabuf(bo, (int *) &whandle->handle) == 0;
1707 }
1708
1709 return false;
1710 }
1711
1712 static bool
resource_is_busy(struct iris_context * ice,struct iris_resource * res)1713 resource_is_busy(struct iris_context *ice,
1714 struct iris_resource *res)
1715 {
1716 bool busy = iris_bo_busy(res->bo);
1717
1718 for (int i = 0; i < IRIS_BATCH_COUNT; i++)
1719 busy |= iris_batch_references(&ice->batches[i], res->bo);
1720
1721 return busy;
1722 }
1723
1724 void
iris_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)1725 iris_replace_buffer_storage(struct pipe_context *ctx,
1726 struct pipe_resource *p_dst,
1727 struct pipe_resource *p_src,
1728 unsigned num_rebinds,
1729 uint32_t rebind_mask,
1730 uint32_t delete_buffer_id)
1731 {
1732 struct iris_screen *screen = (void *) ctx->screen;
1733 struct iris_context *ice = (void *) ctx;
1734 struct iris_resource *dst = (void *) p_dst;
1735 struct iris_resource *src = (void *) p_src;
1736
1737 assert(memcmp(&dst->surf, &src->surf, sizeof(dst->surf)) == 0);
1738
1739 struct iris_bo *old_bo = dst->bo;
1740
1741 /* Swap out the backing storage */
1742 iris_bo_reference(src->bo);
1743 dst->bo = src->bo;
1744
1745 /* Rebind the buffer, replacing any state referring to the old BO's
1746 * address, and marking state dirty so it's reemitted.
1747 */
1748 screen->vtbl.rebind_buffer(ice, dst);
1749
1750 iris_bo_unreference(old_bo);
1751 }
1752
1753 static void
iris_invalidate_resource(struct pipe_context * ctx,struct pipe_resource * resource)1754 iris_invalidate_resource(struct pipe_context *ctx,
1755 struct pipe_resource *resource)
1756 {
1757 struct iris_screen *screen = (void *) ctx->screen;
1758 struct iris_context *ice = (void *) ctx;
1759 struct iris_resource *res = (void *) resource;
1760
1761 if (resource->target != PIPE_BUFFER)
1762 return;
1763
1764 /* If it's already invalidated, don't bother doing anything. */
1765 if (res->valid_buffer_range.start > res->valid_buffer_range.end)
1766 return;
1767
1768 if (!resource_is_busy(ice, res)) {
1769 /* The resource is idle, so just mark that it contains no data and
1770 * keep using the same underlying buffer object.
1771 */
1772 util_range_set_empty(&res->valid_buffer_range);
1773 return;
1774 }
1775
1776 /* Otherwise, try and replace the backing storage with a new BO. */
1777
1778 /* We can't reallocate memory we didn't allocate in the first place. */
1779 if (res->bo->gem_handle && res->bo->real.userptr)
1780 return;
1781
1782 struct iris_bo *old_bo = res->bo;
1783 struct iris_bo *new_bo =
1784 iris_bo_alloc(screen->bufmgr, res->bo->name, resource->width0, 1,
1785 iris_memzone_for_address(old_bo->address), 0);
1786 if (!new_bo)
1787 return;
1788
1789 /* Swap out the backing storage */
1790 res->bo = new_bo;
1791
1792 /* Rebind the buffer, replacing any state referring to the old BO's
1793 * address, and marking state dirty so it's reemitted.
1794 */
1795 screen->vtbl.rebind_buffer(ice, res);
1796
1797 util_range_set_empty(&res->valid_buffer_range);
1798
1799 iris_bo_unreference(old_bo);
1800 }
1801
1802 static void
iris_flush_staging_region(struct pipe_transfer * xfer,const struct pipe_box * flush_box)1803 iris_flush_staging_region(struct pipe_transfer *xfer,
1804 const struct pipe_box *flush_box)
1805 {
1806 if (!(xfer->usage & PIPE_MAP_WRITE))
1807 return;
1808
1809 struct iris_transfer *map = (void *) xfer;
1810
1811 struct pipe_box src_box = *flush_box;
1812
1813 /* Account for extra alignment padding in staging buffer */
1814 if (xfer->resource->target == PIPE_BUFFER)
1815 src_box.x += xfer->box.x % IRIS_MAP_BUFFER_ALIGNMENT;
1816
1817 struct pipe_box dst_box = (struct pipe_box) {
1818 .x = xfer->box.x + flush_box->x,
1819 .y = xfer->box.y + flush_box->y,
1820 .z = xfer->box.z + flush_box->z,
1821 .width = flush_box->width,
1822 .height = flush_box->height,
1823 .depth = flush_box->depth,
1824 };
1825
1826 iris_copy_region(map->blorp, map->batch, xfer->resource, xfer->level,
1827 dst_box.x, dst_box.y, dst_box.z, map->staging, 0,
1828 &src_box);
1829 }
1830
1831 static void
iris_unmap_copy_region(struct iris_transfer * map)1832 iris_unmap_copy_region(struct iris_transfer *map)
1833 {
1834 iris_resource_destroy(map->staging->screen, map->staging);
1835
1836 map->ptr = NULL;
1837 }
1838
1839 static void
iris_map_copy_region(struct iris_transfer * map)1840 iris_map_copy_region(struct iris_transfer *map)
1841 {
1842 struct pipe_screen *pscreen = &map->batch->screen->base;
1843 struct pipe_transfer *xfer = &map->base.b;
1844 struct pipe_box *box = &xfer->box;
1845 struct iris_resource *res = (void *) xfer->resource;
1846
1847 unsigned extra = xfer->resource->target == PIPE_BUFFER ?
1848 box->x % IRIS_MAP_BUFFER_ALIGNMENT : 0;
1849
1850 struct pipe_resource templ = (struct pipe_resource) {
1851 .usage = PIPE_USAGE_STAGING,
1852 .width0 = box->width + extra,
1853 .height0 = box->height,
1854 .depth0 = 1,
1855 .nr_samples = xfer->resource->nr_samples,
1856 .nr_storage_samples = xfer->resource->nr_storage_samples,
1857 .array_size = box->depth,
1858 .format = res->internal_format,
1859 };
1860
1861 if (xfer->resource->target == PIPE_BUFFER)
1862 templ.target = PIPE_BUFFER;
1863 else if (templ.array_size > 1)
1864 templ.target = PIPE_TEXTURE_2D_ARRAY;
1865 else
1866 templ.target = PIPE_TEXTURE_2D;
1867
1868 map->staging = iris_resource_create(pscreen, &templ);
1869 assert(map->staging);
1870
1871 if (templ.target != PIPE_BUFFER) {
1872 struct isl_surf *surf = &((struct iris_resource *) map->staging)->surf;
1873 xfer->stride = isl_surf_get_row_pitch_B(surf);
1874 xfer->layer_stride = isl_surf_get_array_pitch(surf);
1875 }
1876
1877 if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) {
1878 iris_copy_region(map->blorp, map->batch, map->staging, 0, extra, 0, 0,
1879 xfer->resource, xfer->level, box);
1880 /* Ensure writes to the staging BO land before we map it below. */
1881 iris_emit_pipe_control_flush(map->batch,
1882 "transfer read: flush before mapping",
1883 PIPE_CONTROL_RENDER_TARGET_FLUSH |
1884 PIPE_CONTROL_TILE_CACHE_FLUSH |
1885 PIPE_CONTROL_CS_STALL);
1886 }
1887
1888 struct iris_bo *staging_bo = iris_resource_bo(map->staging);
1889
1890 if (iris_batch_references(map->batch, staging_bo))
1891 iris_batch_flush(map->batch);
1892
1893 map->ptr =
1894 iris_bo_map(map->dbg, staging_bo, xfer->usage & MAP_FLAGS) + extra;
1895
1896 map->unmap = iris_unmap_copy_region;
1897 }
1898
1899 static void
get_image_offset_el(const struct isl_surf * surf,unsigned level,unsigned z,unsigned * out_x0_el,unsigned * out_y0_el)1900 get_image_offset_el(const struct isl_surf *surf, unsigned level, unsigned z,
1901 unsigned *out_x0_el, unsigned *out_y0_el)
1902 {
1903 ASSERTED uint32_t z0_el, a0_el;
1904 if (surf->dim == ISL_SURF_DIM_3D) {
1905 isl_surf_get_image_offset_el(surf, level, 0, z,
1906 out_x0_el, out_y0_el, &z0_el, &a0_el);
1907 } else {
1908 isl_surf_get_image_offset_el(surf, level, z, 0,
1909 out_x0_el, out_y0_el, &z0_el, &a0_el);
1910 }
1911 assert(z0_el == 0 && a0_el == 0);
1912 }
1913
1914 /**
1915 * Get pointer offset into stencil buffer.
1916 *
1917 * The stencil buffer is W tiled. Since the GTT is incapable of W fencing, we
1918 * must decode the tile's layout in software.
1919 *
1920 * See
1921 * - PRM, 2011 Sandy Bridge, Volume 1, Part 2, Section 4.5.2.1 W-Major Tile
1922 * Format.
1923 * - PRM, 2011 Sandy Bridge, Volume 1, Part 2, Section 4.5.3 Tiling Algorithm
1924 *
1925 * Even though the returned offset is always positive, the return type is
1926 * signed due to
1927 * commit e8b1c6d6f55f5be3bef25084fdd8b6127517e137
1928 * mesa: Fix return type of _mesa_get_format_bytes() (#37351)
1929 */
1930 static intptr_t
s8_offset(uint32_t stride,uint32_t x,uint32_t y)1931 s8_offset(uint32_t stride, uint32_t x, uint32_t y)
1932 {
1933 uint32_t tile_size = 4096;
1934 uint32_t tile_width = 64;
1935 uint32_t tile_height = 64;
1936 uint32_t row_size = 64 * stride / 2; /* Two rows are interleaved. */
1937
1938 uint32_t tile_x = x / tile_width;
1939 uint32_t tile_y = y / tile_height;
1940
1941 /* The byte's address relative to the tile's base addres. */
1942 uint32_t byte_x = x % tile_width;
1943 uint32_t byte_y = y % tile_height;
1944
1945 uintptr_t u = tile_y * row_size
1946 + tile_x * tile_size
1947 + 512 * (byte_x / 8)
1948 + 64 * (byte_y / 8)
1949 + 32 * ((byte_y / 4) % 2)
1950 + 16 * ((byte_x / 4) % 2)
1951 + 8 * ((byte_y / 2) % 2)
1952 + 4 * ((byte_x / 2) % 2)
1953 + 2 * (byte_y % 2)
1954 + 1 * (byte_x % 2);
1955
1956 return u;
1957 }
1958
1959 static void
iris_unmap_s8(struct iris_transfer * map)1960 iris_unmap_s8(struct iris_transfer *map)
1961 {
1962 struct pipe_transfer *xfer = &map->base.b;
1963 const struct pipe_box *box = &xfer->box;
1964 struct iris_resource *res = (struct iris_resource *) xfer->resource;
1965 struct isl_surf *surf = &res->surf;
1966
1967 if (xfer->usage & PIPE_MAP_WRITE) {
1968 uint8_t *untiled_s8_map = map->ptr;
1969 uint8_t *tiled_s8_map =
1970 iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS);
1971
1972 for (int s = 0; s < box->depth; s++) {
1973 unsigned x0_el, y0_el;
1974 get_image_offset_el(surf, xfer->level, box->z + s, &x0_el, &y0_el);
1975
1976 for (uint32_t y = 0; y < box->height; y++) {
1977 for (uint32_t x = 0; x < box->width; x++) {
1978 ptrdiff_t offset = s8_offset(surf->row_pitch_B,
1979 x0_el + box->x + x,
1980 y0_el + box->y + y);
1981 tiled_s8_map[offset] =
1982 untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x];
1983 }
1984 }
1985 }
1986 }
1987
1988 free(map->buffer);
1989 }
1990
1991 static void
iris_map_s8(struct iris_transfer * map)1992 iris_map_s8(struct iris_transfer *map)
1993 {
1994 struct pipe_transfer *xfer = &map->base.b;
1995 const struct pipe_box *box = &xfer->box;
1996 struct iris_resource *res = (struct iris_resource *) xfer->resource;
1997 struct isl_surf *surf = &res->surf;
1998
1999 xfer->stride = surf->row_pitch_B;
2000 xfer->layer_stride = xfer->stride * box->height;
2001
2002 /* The tiling and detiling functions require that the linear buffer has
2003 * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we
2004 * over-allocate the linear buffer to get the proper alignment.
2005 */
2006 map->buffer = map->ptr = malloc(xfer->layer_stride * box->depth);
2007 assert(map->buffer);
2008
2009 /* One of either READ_BIT or WRITE_BIT or both is set. READ_BIT implies no
2010 * INVALIDATE_RANGE_BIT. WRITE_BIT needs the original values read in unless
2011 * invalidate is set, since we'll be writing the whole rectangle from our
2012 * temporary buffer back out.
2013 */
2014 if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) {
2015 uint8_t *untiled_s8_map = map->ptr;
2016 uint8_t *tiled_s8_map =
2017 iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS);
2018
2019 for (int s = 0; s < box->depth; s++) {
2020 unsigned x0_el, y0_el;
2021 get_image_offset_el(surf, xfer->level, box->z + s, &x0_el, &y0_el);
2022
2023 for (uint32_t y = 0; y < box->height; y++) {
2024 for (uint32_t x = 0; x < box->width; x++) {
2025 ptrdiff_t offset = s8_offset(surf->row_pitch_B,
2026 x0_el + box->x + x,
2027 y0_el + box->y + y);
2028 untiled_s8_map[s * xfer->layer_stride + y * xfer->stride + x] =
2029 tiled_s8_map[offset];
2030 }
2031 }
2032 }
2033 }
2034
2035 map->unmap = iris_unmap_s8;
2036 }
2037
2038 /* Compute extent parameters for use with tiled_memcpy functions.
2039 * xs are in units of bytes and ys are in units of strides.
2040 */
2041 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)2042 tile_extents(const struct isl_surf *surf,
2043 const struct pipe_box *box,
2044 unsigned level, int z,
2045 unsigned *x1_B, unsigned *x2_B,
2046 unsigned *y1_el, unsigned *y2_el)
2047 {
2048 const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
2049 const unsigned cpp = fmtl->bpb / 8;
2050
2051 assert(box->x % fmtl->bw == 0);
2052 assert(box->y % fmtl->bh == 0);
2053
2054 unsigned x0_el, y0_el;
2055 get_image_offset_el(surf, level, box->z + z, &x0_el, &y0_el);
2056
2057 *x1_B = (box->x / fmtl->bw + x0_el) * cpp;
2058 *y1_el = box->y / fmtl->bh + y0_el;
2059 *x2_B = (DIV_ROUND_UP(box->x + box->width, fmtl->bw) + x0_el) * cpp;
2060 *y2_el = DIV_ROUND_UP(box->y + box->height, fmtl->bh) + y0_el;
2061 }
2062
2063 static void
iris_unmap_tiled_memcpy(struct iris_transfer * map)2064 iris_unmap_tiled_memcpy(struct iris_transfer *map)
2065 {
2066 struct pipe_transfer *xfer = &map->base.b;
2067 const struct pipe_box *box = &xfer->box;
2068 struct iris_resource *res = (struct iris_resource *) xfer->resource;
2069 struct isl_surf *surf = &res->surf;
2070
2071 const bool has_swizzling = false;
2072
2073 if (xfer->usage & PIPE_MAP_WRITE) {
2074 char *dst =
2075 iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS);
2076
2077 for (int s = 0; s < box->depth; s++) {
2078 unsigned x1, x2, y1, y2;
2079 tile_extents(surf, box, xfer->level, s, &x1, &x2, &y1, &y2);
2080
2081 void *ptr = map->ptr + s * xfer->layer_stride;
2082
2083 isl_memcpy_linear_to_tiled(x1, x2, y1, y2, dst, ptr,
2084 surf->row_pitch_B, xfer->stride,
2085 has_swizzling, surf->tiling, ISL_MEMCPY);
2086 }
2087 }
2088 os_free_aligned(map->buffer);
2089 map->buffer = map->ptr = NULL;
2090 }
2091
2092 static void
iris_map_tiled_memcpy(struct iris_transfer * map)2093 iris_map_tiled_memcpy(struct iris_transfer *map)
2094 {
2095 struct pipe_transfer *xfer = &map->base.b;
2096 const struct pipe_box *box = &xfer->box;
2097 struct iris_resource *res = (struct iris_resource *) xfer->resource;
2098 struct isl_surf *surf = &res->surf;
2099
2100 xfer->stride = ALIGN(surf->row_pitch_B, 16);
2101 xfer->layer_stride = xfer->stride * box->height;
2102
2103 unsigned x1, x2, y1, y2;
2104 tile_extents(surf, box, xfer->level, 0, &x1, &x2, &y1, &y2);
2105
2106 /* The tiling and detiling functions require that the linear buffer has
2107 * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we
2108 * over-allocate the linear buffer to get the proper alignment.
2109 */
2110 map->buffer =
2111 os_malloc_aligned(xfer->layer_stride * box->depth, 16);
2112 assert(map->buffer);
2113 map->ptr = (char *)map->buffer + (x1 & 0xf);
2114
2115 const bool has_swizzling = false;
2116
2117 if (!(xfer->usage & PIPE_MAP_DISCARD_RANGE)) {
2118 char *src =
2119 iris_bo_map(map->dbg, res->bo, (xfer->usage | MAP_RAW) & MAP_FLAGS);
2120
2121 for (int s = 0; s < box->depth; s++) {
2122 unsigned x1, x2, y1, y2;
2123 tile_extents(surf, box, xfer->level, s, &x1, &x2, &y1, &y2);
2124
2125 /* Use 's' rather than 'box->z' to rebase the first slice to 0. */
2126 void *ptr = map->ptr + s * xfer->layer_stride;
2127
2128 isl_memcpy_tiled_to_linear(x1, x2, y1, y2, ptr, src, xfer->stride,
2129 surf->row_pitch_B, has_swizzling,
2130 surf->tiling, ISL_MEMCPY_STREAMING_LOAD);
2131 }
2132 }
2133
2134 map->unmap = iris_unmap_tiled_memcpy;
2135 }
2136
2137 static void
iris_map_direct(struct iris_transfer * map)2138 iris_map_direct(struct iris_transfer *map)
2139 {
2140 struct pipe_transfer *xfer = &map->base.b;
2141 struct pipe_box *box = &xfer->box;
2142 struct iris_resource *res = (struct iris_resource *) xfer->resource;
2143
2144 void *ptr = iris_bo_map(map->dbg, res->bo, xfer->usage & MAP_FLAGS);
2145
2146 if (res->base.b.target == PIPE_BUFFER) {
2147 xfer->stride = 0;
2148 xfer->layer_stride = 0;
2149
2150 map->ptr = ptr + box->x;
2151 } else {
2152 struct isl_surf *surf = &res->surf;
2153 const struct isl_format_layout *fmtl =
2154 isl_format_get_layout(surf->format);
2155 const unsigned cpp = fmtl->bpb / 8;
2156 unsigned x0_el, y0_el;
2157
2158 get_image_offset_el(surf, xfer->level, box->z, &x0_el, &y0_el);
2159
2160 xfer->stride = isl_surf_get_row_pitch_B(surf);
2161 xfer->layer_stride = isl_surf_get_array_pitch(surf);
2162
2163 map->ptr = ptr + (y0_el + box->y) * xfer->stride + (x0_el + box->x) * cpp;
2164 }
2165 }
2166
2167 static bool
can_promote_to_async(const struct iris_resource * res,const struct pipe_box * box,enum pipe_map_flags usage)2168 can_promote_to_async(const struct iris_resource *res,
2169 const struct pipe_box *box,
2170 enum pipe_map_flags usage)
2171 {
2172 /* If we're writing to a section of the buffer that hasn't even been
2173 * initialized with useful data, then we can safely promote this write
2174 * to be unsynchronized. This helps the common pattern of appending data.
2175 */
2176 return res->base.b.target == PIPE_BUFFER && (usage & PIPE_MAP_WRITE) &&
2177 !(usage & TC_TRANSFER_MAP_NO_INFER_UNSYNCHRONIZED) &&
2178 !util_ranges_intersect(&res->valid_buffer_range, box->x,
2179 box->x + box->width);
2180 }
2181
2182 static void *
iris_transfer_map(struct pipe_context * ctx,struct pipe_resource * resource,unsigned level,enum pipe_map_flags usage,const struct pipe_box * box,struct pipe_transfer ** ptransfer)2183 iris_transfer_map(struct pipe_context *ctx,
2184 struct pipe_resource *resource,
2185 unsigned level,
2186 enum pipe_map_flags usage,
2187 const struct pipe_box *box,
2188 struct pipe_transfer **ptransfer)
2189 {
2190 struct iris_context *ice = (struct iris_context *)ctx;
2191 struct iris_resource *res = (struct iris_resource *)resource;
2192 struct isl_surf *surf = &res->surf;
2193
2194 if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) {
2195 /* Replace the backing storage with a fresh buffer for non-async maps */
2196 if (!(usage & (PIPE_MAP_UNSYNCHRONIZED |
2197 TC_TRANSFER_MAP_NO_INVALIDATE)))
2198 iris_invalidate_resource(ctx, resource);
2199
2200 /* If we can discard the whole resource, we can discard the range. */
2201 usage |= PIPE_MAP_DISCARD_RANGE;
2202 }
2203
2204 if (!(usage & PIPE_MAP_UNSYNCHRONIZED) &&
2205 can_promote_to_async(res, box, usage)) {
2206 usage |= PIPE_MAP_UNSYNCHRONIZED;
2207 }
2208
2209 /* Avoid using GPU copies for persistent/coherent buffers, as the idea
2210 * there is to access them simultaneously on the CPU & GPU. This also
2211 * avoids trying to use GPU copies for our u_upload_mgr buffers which
2212 * contain state we're constructing for a GPU draw call, which would
2213 * kill us with infinite stack recursion.
2214 */
2215 if (usage & (PIPE_MAP_PERSISTENT | PIPE_MAP_COHERENT))
2216 usage |= PIPE_MAP_DIRECTLY;
2217
2218 /* We cannot provide a direct mapping of tiled resources, and we
2219 * may not be able to mmap imported BOs since they may come from
2220 * other devices that I915_GEM_MMAP cannot work with.
2221 */
2222 if ((usage & PIPE_MAP_DIRECTLY) &&
2223 (surf->tiling != ISL_TILING_LINEAR || iris_bo_is_imported(res->bo)))
2224 return NULL;
2225
2226 bool map_would_stall = false;
2227
2228 if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) {
2229 map_would_stall =
2230 resource_is_busy(ice, res) ||
2231 iris_has_invalid_primary(res, level, 1, box->z, box->depth);
2232
2233 if (map_would_stall && (usage & PIPE_MAP_DONTBLOCK) &&
2234 (usage & PIPE_MAP_DIRECTLY))
2235 return NULL;
2236 }
2237
2238 struct iris_transfer *map;
2239
2240 if (usage & TC_TRANSFER_MAP_THREADED_UNSYNC)
2241 map = slab_alloc(&ice->transfer_pool_unsync);
2242 else
2243 map = slab_alloc(&ice->transfer_pool);
2244
2245 if (!map)
2246 return NULL;
2247
2248 struct pipe_transfer *xfer = &map->base.b;
2249
2250 memset(map, 0, sizeof(*map));
2251 map->dbg = &ice->dbg;
2252
2253 pipe_resource_reference(&xfer->resource, resource);
2254 xfer->level = level;
2255 xfer->usage = usage;
2256 xfer->box = *box;
2257 *ptransfer = xfer;
2258
2259 map->dest_had_defined_contents =
2260 util_ranges_intersect(&res->valid_buffer_range, box->x,
2261 box->x + box->width);
2262
2263 if (usage & PIPE_MAP_WRITE)
2264 util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width);
2265
2266 if (iris_bo_mmap_mode(res->bo) != IRIS_MMAP_NONE) {
2267 /* GPU copies are not useful for buffer reads. Instead of stalling to
2268 * read from the original buffer, we'd simply copy it to a temporary...
2269 * then stall (a bit longer) to read from that buffer.
2270 *
2271 * Images are less clear-cut. Resolves can be destructive, removing
2272 * some of the underlying compression, so we'd rather blit the data to
2273 * a linear temporary and map that, to avoid the resolve.
2274 */
2275 if (!(usage & PIPE_MAP_DISCARD_RANGE) &&
2276 !iris_has_invalid_primary(res, level, 1, box->z, box->depth)) {
2277 usage |= PIPE_MAP_DIRECTLY;
2278 }
2279
2280 const struct isl_format_layout *fmtl =
2281 isl_format_get_layout(surf->format);
2282 if (fmtl->txc == ISL_TXC_ASTC)
2283 usage |= PIPE_MAP_DIRECTLY;
2284
2285 /* We can map directly if it wouldn't stall, there's no compression,
2286 * and we aren't doing an uncached read.
2287 */
2288 if (!map_would_stall &&
2289 !isl_aux_usage_has_compression(res->aux.usage) &&
2290 !((usage & PIPE_MAP_READ) &&
2291 iris_bo_mmap_mode(res->bo) != IRIS_MMAP_WB)) {
2292 usage |= PIPE_MAP_DIRECTLY;
2293 }
2294 }
2295
2296 /* TODO: Teach iris_map_tiled_memcpy about Tile4... */
2297 if (res->surf.tiling == ISL_TILING_4)
2298 usage &= ~PIPE_MAP_DIRECTLY;
2299
2300 if (!(usage & PIPE_MAP_DIRECTLY)) {
2301 /* If we need a synchronous mapping and the resource is busy, or needs
2302 * resolving, we copy to/from a linear temporary buffer using the GPU.
2303 */
2304 map->batch = &ice->batches[IRIS_BATCH_RENDER];
2305 map->blorp = &ice->blorp;
2306 iris_map_copy_region(map);
2307 } else {
2308 /* Otherwise we're free to map on the CPU. */
2309
2310 if (resource->target != PIPE_BUFFER) {
2311 iris_resource_access_raw(ice, res, level, box->z, box->depth,
2312 usage & PIPE_MAP_WRITE);
2313 }
2314
2315 if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) {
2316 for (int i = 0; i < IRIS_BATCH_COUNT; i++) {
2317 if (iris_batch_references(&ice->batches[i], res->bo))
2318 iris_batch_flush(&ice->batches[i]);
2319 }
2320 }
2321
2322 if (surf->tiling == ISL_TILING_W) {
2323 /* TODO: Teach iris_map_tiled_memcpy about W-tiling... */
2324 iris_map_s8(map);
2325 } else if (surf->tiling != ISL_TILING_LINEAR) {
2326 iris_map_tiled_memcpy(map);
2327 } else {
2328 iris_map_direct(map);
2329 }
2330 }
2331
2332 return map->ptr;
2333 }
2334
2335 static void
iris_transfer_flush_region(struct pipe_context * ctx,struct pipe_transfer * xfer,const struct pipe_box * box)2336 iris_transfer_flush_region(struct pipe_context *ctx,
2337 struct pipe_transfer *xfer,
2338 const struct pipe_box *box)
2339 {
2340 struct iris_context *ice = (struct iris_context *)ctx;
2341 struct iris_resource *res = (struct iris_resource *) xfer->resource;
2342 struct iris_transfer *map = (void *) xfer;
2343
2344 if (map->staging)
2345 iris_flush_staging_region(xfer, box);
2346
2347 uint32_t history_flush = 0;
2348
2349 if (res->base.b.target == PIPE_BUFFER) {
2350 if (map->staging)
2351 history_flush |= PIPE_CONTROL_RENDER_TARGET_FLUSH |
2352 PIPE_CONTROL_TILE_CACHE_FLUSH;
2353
2354 if (map->dest_had_defined_contents)
2355 history_flush |= iris_flush_bits_for_history(ice, res);
2356
2357 util_range_add(&res->base.b, &res->valid_buffer_range, box->x, box->x + box->width);
2358 }
2359
2360 if (history_flush & ~PIPE_CONTROL_CS_STALL) {
2361 for (int i = 0; i < IRIS_BATCH_COUNT; i++) {
2362 struct iris_batch *batch = &ice->batches[i];
2363 if (batch->contains_draw || batch->cache.render->entries) {
2364 iris_batch_maybe_flush(batch, 24);
2365 iris_emit_pipe_control_flush(batch,
2366 "cache history: transfer flush",
2367 history_flush);
2368 }
2369 }
2370 }
2371
2372 /* Make sure we flag constants dirty even if there's no need to emit
2373 * any PIPE_CONTROLs to a batch.
2374 */
2375 iris_dirty_for_history(ice, res);
2376 }
2377
2378 static void
iris_transfer_unmap(struct pipe_context * ctx,struct pipe_transfer * xfer)2379 iris_transfer_unmap(struct pipe_context *ctx, struct pipe_transfer *xfer)
2380 {
2381 struct iris_context *ice = (struct iris_context *)ctx;
2382 struct iris_transfer *map = (void *) xfer;
2383
2384 if (!(xfer->usage & (PIPE_MAP_FLUSH_EXPLICIT |
2385 PIPE_MAP_COHERENT))) {
2386 struct pipe_box flush_box = {
2387 .x = 0, .y = 0, .z = 0,
2388 .width = xfer->box.width,
2389 .height = xfer->box.height,
2390 .depth = xfer->box.depth,
2391 };
2392 iris_transfer_flush_region(ctx, xfer, &flush_box);
2393 }
2394
2395 if (map->unmap)
2396 map->unmap(map);
2397
2398 pipe_resource_reference(&xfer->resource, NULL);
2399
2400 /* transfer_unmap is always called from the driver thread, so we have to
2401 * use transfer_pool, not transfer_pool_unsync. Freeing an object into a
2402 * different pool is allowed, however.
2403 */
2404 slab_free(&ice->transfer_pool, map);
2405 }
2406
2407 /**
2408 * The pipe->texture_subdata() driver hook.
2409 *
2410 * Mesa's state tracker takes this path whenever possible, even with
2411 * PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER set.
2412 */
2413 static void
iris_texture_subdata(struct pipe_context * ctx,struct pipe_resource * resource,unsigned level,unsigned usage,const struct pipe_box * box,const void * data,unsigned stride,unsigned layer_stride)2414 iris_texture_subdata(struct pipe_context *ctx,
2415 struct pipe_resource *resource,
2416 unsigned level,
2417 unsigned usage,
2418 const struct pipe_box *box,
2419 const void *data,
2420 unsigned stride,
2421 unsigned layer_stride)
2422 {
2423 struct iris_context *ice = (struct iris_context *)ctx;
2424 struct iris_resource *res = (struct iris_resource *)resource;
2425 const struct isl_surf *surf = &res->surf;
2426
2427 assert(resource->target != PIPE_BUFFER);
2428
2429 /* Just use the transfer-based path for linear buffers - it will already
2430 * do a direct mapping, or a simple linear staging buffer.
2431 *
2432 * Linear staging buffers appear to be better than tiled ones, too, so
2433 * take that path if we need the GPU to perform color compression, or
2434 * stall-avoidance blits.
2435 *
2436 * TODO: Teach isl_memcpy_linear_to_tiled about Tile4...
2437 */
2438 if (surf->tiling == ISL_TILING_LINEAR ||
2439 surf->tiling == ISL_TILING_4 ||
2440 isl_aux_usage_has_compression(res->aux.usage) ||
2441 resource_is_busy(ice, res) ||
2442 iris_bo_mmap_mode(res->bo) == IRIS_MMAP_NONE) {
2443 return u_default_texture_subdata(ctx, resource, level, usage, box,
2444 data, stride, layer_stride);
2445 }
2446
2447 /* No state trackers pass any flags other than PIPE_MAP_WRITE */
2448
2449 iris_resource_access_raw(ice, res, level, box->z, box->depth, true);
2450
2451 for (int i = 0; i < IRIS_BATCH_COUNT; i++) {
2452 if (iris_batch_references(&ice->batches[i], res->bo))
2453 iris_batch_flush(&ice->batches[i]);
2454 }
2455
2456 uint8_t *dst = iris_bo_map(&ice->dbg, res->bo, MAP_WRITE | MAP_RAW);
2457
2458 for (int s = 0; s < box->depth; s++) {
2459 const uint8_t *src = data + s * layer_stride;
2460
2461 if (surf->tiling == ISL_TILING_W) {
2462 unsigned x0_el, y0_el;
2463 get_image_offset_el(surf, level, box->z + s, &x0_el, &y0_el);
2464
2465 for (unsigned y = 0; y < box->height; y++) {
2466 for (unsigned x = 0; x < box->width; x++) {
2467 ptrdiff_t offset = s8_offset(surf->row_pitch_B,
2468 x0_el + box->x + x,
2469 y0_el + box->y + y);
2470 dst[offset] = src[y * stride + x];
2471 }
2472 }
2473 } else {
2474 unsigned x1, x2, y1, y2;
2475
2476 tile_extents(surf, box, level, s, &x1, &x2, &y1, &y2);
2477
2478 isl_memcpy_linear_to_tiled(x1, x2, y1, y2,
2479 (void *)dst, (void *)src,
2480 surf->row_pitch_B, stride,
2481 false, surf->tiling, ISL_MEMCPY);
2482 }
2483 }
2484 }
2485
2486 /**
2487 * Mark state dirty that needs to be re-emitted when a resource is written.
2488 */
2489 void
iris_dirty_for_history(struct iris_context * ice,struct iris_resource * res)2490 iris_dirty_for_history(struct iris_context *ice,
2491 struct iris_resource *res)
2492 {
2493 const uint64_t stages = res->bind_stages;
2494 uint64_t dirty = 0ull;
2495 uint64_t stage_dirty = 0ull;
2496
2497 if (res->bind_history & PIPE_BIND_CONSTANT_BUFFER) {
2498 for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) {
2499 if (stages & (1u << stage)) {
2500 struct iris_shader_state *shs = &ice->state.shaders[stage];
2501 shs->dirty_cbufs |= ~0u;
2502 }
2503 }
2504 dirty |= IRIS_DIRTY_RENDER_MISC_BUFFER_FLUSHES |
2505 IRIS_DIRTY_COMPUTE_MISC_BUFFER_FLUSHES;
2506 stage_dirty |= (stages << IRIS_SHIFT_FOR_STAGE_DIRTY_CONSTANTS);
2507 }
2508
2509 if (res->bind_history & (PIPE_BIND_SAMPLER_VIEW |
2510 PIPE_BIND_SHADER_IMAGE)) {
2511 dirty |= IRIS_DIRTY_RENDER_RESOLVES_AND_FLUSHES |
2512 IRIS_DIRTY_COMPUTE_RESOLVES_AND_FLUSHES;
2513 stage_dirty |= (stages << IRIS_SHIFT_FOR_STAGE_DIRTY_BINDINGS);
2514 }
2515
2516 if (res->bind_history & PIPE_BIND_SHADER_BUFFER) {
2517 dirty |= IRIS_DIRTY_RENDER_MISC_BUFFER_FLUSHES |
2518 IRIS_DIRTY_COMPUTE_MISC_BUFFER_FLUSHES;
2519 stage_dirty |= (stages << IRIS_SHIFT_FOR_STAGE_DIRTY_BINDINGS);
2520 }
2521
2522 if (res->bind_history & PIPE_BIND_VERTEX_BUFFER)
2523 dirty |= IRIS_DIRTY_VERTEX_BUFFER_FLUSHES;
2524
2525 ice->state.dirty |= dirty;
2526 ice->state.stage_dirty |= stage_dirty;
2527 }
2528
2529 /**
2530 * Produce a set of PIPE_CONTROL bits which ensure data written to a
2531 * resource becomes visible, and any stale read cache data is invalidated.
2532 */
2533 uint32_t
iris_flush_bits_for_history(struct iris_context * ice,struct iris_resource * res)2534 iris_flush_bits_for_history(struct iris_context *ice,
2535 struct iris_resource *res)
2536 {
2537 struct iris_screen *screen = (struct iris_screen *) ice->ctx.screen;
2538
2539 uint32_t flush = PIPE_CONTROL_CS_STALL;
2540
2541 if (res->bind_history & PIPE_BIND_CONSTANT_BUFFER) {
2542 flush |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
2543 flush |= screen->compiler->indirect_ubos_use_sampler ?
2544 PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE :
2545 PIPE_CONTROL_DATA_CACHE_FLUSH;
2546 }
2547
2548 if (res->bind_history & PIPE_BIND_SAMPLER_VIEW)
2549 flush |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
2550
2551 if (res->bind_history & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER))
2552 flush |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
2553
2554 if (res->bind_history & (PIPE_BIND_SHADER_BUFFER | PIPE_BIND_SHADER_IMAGE))
2555 flush |= PIPE_CONTROL_DATA_CACHE_FLUSH;
2556
2557 return flush;
2558 }
2559
2560 void
iris_flush_and_dirty_for_history(struct iris_context * ice,struct iris_batch * batch,struct iris_resource * res,uint32_t extra_flags,const char * reason)2561 iris_flush_and_dirty_for_history(struct iris_context *ice,
2562 struct iris_batch *batch,
2563 struct iris_resource *res,
2564 uint32_t extra_flags,
2565 const char *reason)
2566 {
2567 if (res->base.b.target != PIPE_BUFFER)
2568 return;
2569
2570 uint32_t flush = iris_flush_bits_for_history(ice, res) | extra_flags;
2571
2572 iris_emit_pipe_control_flush(batch, reason, flush);
2573
2574 iris_dirty_for_history(ice, res);
2575 }
2576
2577 bool
iris_resource_set_clear_color(struct iris_context * ice,struct iris_resource * res,union isl_color_value color)2578 iris_resource_set_clear_color(struct iris_context *ice,
2579 struct iris_resource *res,
2580 union isl_color_value color)
2581 {
2582 if (res->aux.clear_color_unknown ||
2583 memcmp(&res->aux.clear_color, &color, sizeof(color)) != 0) {
2584 res->aux.clear_color = color;
2585 res->aux.clear_color_unknown = false;
2586 return true;
2587 }
2588
2589 return false;
2590 }
2591
2592 static enum pipe_format
iris_resource_get_internal_format(struct pipe_resource * p_res)2593 iris_resource_get_internal_format(struct pipe_resource *p_res)
2594 {
2595 struct iris_resource *res = (void *) p_res;
2596 return res->internal_format;
2597 }
2598
2599 static const struct u_transfer_vtbl transfer_vtbl = {
2600 .resource_create = iris_resource_create,
2601 .resource_destroy = iris_resource_destroy,
2602 .transfer_map = iris_transfer_map,
2603 .transfer_unmap = iris_transfer_unmap,
2604 .transfer_flush_region = iris_transfer_flush_region,
2605 .get_internal_format = iris_resource_get_internal_format,
2606 .set_stencil = iris_resource_set_separate_stencil,
2607 .get_stencil = iris_resource_get_separate_stencil,
2608 };
2609
2610 void
iris_init_screen_resource_functions(struct pipe_screen * pscreen)2611 iris_init_screen_resource_functions(struct pipe_screen *pscreen)
2612 {
2613 pscreen->query_dmabuf_modifiers = iris_query_dmabuf_modifiers;
2614 pscreen->is_dmabuf_modifier_supported = iris_is_dmabuf_modifier_supported;
2615 pscreen->get_dmabuf_modifier_planes = iris_get_dmabuf_modifier_planes;
2616 pscreen->resource_create_with_modifiers =
2617 iris_resource_create_with_modifiers;
2618 pscreen->resource_create = u_transfer_helper_resource_create;
2619 pscreen->resource_from_user_memory = iris_resource_from_user_memory;
2620 pscreen->resource_from_handle = iris_resource_from_handle;
2621 pscreen->resource_from_memobj = iris_resource_from_memobj_wrapper;
2622 pscreen->resource_get_handle = iris_resource_get_handle;
2623 pscreen->resource_get_param = iris_resource_get_param;
2624 pscreen->resource_destroy = u_transfer_helper_resource_destroy;
2625 pscreen->memobj_create_from_handle = iris_memobj_create_from_handle;
2626 pscreen->memobj_destroy = iris_memobj_destroy;
2627 pscreen->transfer_helper =
2628 u_transfer_helper_create(&transfer_vtbl, true, true, false, true);
2629 }
2630
2631 void
iris_init_resource_functions(struct pipe_context * ctx)2632 iris_init_resource_functions(struct pipe_context *ctx)
2633 {
2634 ctx->flush_resource = iris_flush_resource;
2635 ctx->invalidate_resource = iris_invalidate_resource;
2636 ctx->buffer_map = u_transfer_helper_transfer_map;
2637 ctx->texture_map = u_transfer_helper_transfer_map;
2638 ctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;
2639 ctx->buffer_unmap = u_transfer_helper_transfer_unmap;
2640 ctx->texture_unmap = u_transfer_helper_transfer_unmap;
2641 ctx->buffer_subdata = u_default_buffer_subdata;
2642 ctx->texture_subdata = iris_texture_subdata;
2643 }
2644