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