6c90f01085b38a531f84ad0a140efe3fdcf1ba06
[mesa.git] / src / gallium / drivers / iris / iris_resource.c
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 #include <stdio.h>
24 #include <errno.h>
25 #include "pipe/p_defines.h"
26 #include "pipe/p_state.h"
27 #include "pipe/p_context.h"
28 #include "pipe/p_screen.h"
29 #include "util/os_memory.h"
30 #include "util/u_cpu_detect.h"
31 #include "util/u_inlines.h"
32 #include "util/u_format.h"
33 #include "util/u_upload_mgr.h"
34 #include "util/ralloc.h"
35 #include "iris_batch.h"
36 #include "iris_context.h"
37 #include "iris_resource.h"
38 #include "iris_screen.h"
39 #include "intel/common/gen_debug.h"
40 #include "isl/isl.h"
41 #include "drm-uapi/drm_fourcc.h"
42 #include "drm-uapi/i915_drm.h"
43
44 // XXX: u_transfer_helper...for separate stencil...
45
46 enum modifier_priority {
47 MODIFIER_PRIORITY_INVALID = 0,
48 MODIFIER_PRIORITY_LINEAR,
49 MODIFIER_PRIORITY_X,
50 MODIFIER_PRIORITY_Y,
51 MODIFIER_PRIORITY_Y_CCS,
52 };
53
54 static const uint64_t priority_to_modifier[] = {
55 [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID,
56 [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR,
57 [MODIFIER_PRIORITY_X] = I915_FORMAT_MOD_X_TILED,
58 [MODIFIER_PRIORITY_Y] = I915_FORMAT_MOD_Y_TILED,
59 [MODIFIER_PRIORITY_Y_CCS] = I915_FORMAT_MOD_Y_TILED_CCS,
60 };
61
62 static bool
63 modifier_is_supported(const struct gen_device_info *devinfo,
64 uint64_t modifier)
65 {
66 /* XXX: do something real */
67 switch (modifier) {
68 case I915_FORMAT_MOD_Y_TILED:
69 case I915_FORMAT_MOD_X_TILED:
70 case DRM_FORMAT_MOD_LINEAR:
71 return true;
72 case I915_FORMAT_MOD_Y_TILED_CCS:
73 case DRM_FORMAT_MOD_INVALID:
74 default:
75 return false;
76 }
77 }
78
79 static uint64_t
80 select_best_modifier(struct gen_device_info *devinfo,
81 const uint64_t *modifiers,
82 int count)
83 {
84 enum modifier_priority prio = MODIFIER_PRIORITY_INVALID;
85
86 for (int i = 0; i < count; i++) {
87 if (!modifier_is_supported(devinfo, modifiers[i]))
88 continue;
89
90 switch (modifiers[i]) {
91 case I915_FORMAT_MOD_Y_TILED_CCS:
92 prio = MAX2(prio, MODIFIER_PRIORITY_Y_CCS);
93 break;
94 case I915_FORMAT_MOD_Y_TILED:
95 prio = MAX2(prio, MODIFIER_PRIORITY_Y);
96 break;
97 case I915_FORMAT_MOD_X_TILED:
98 prio = MAX2(prio, MODIFIER_PRIORITY_X);
99 break;
100 case DRM_FORMAT_MOD_LINEAR:
101 prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR);
102 break;
103 case DRM_FORMAT_MOD_INVALID:
104 default:
105 break;
106 }
107 }
108
109 return priority_to_modifier[prio];
110 }
111
112 static enum isl_surf_dim
113 target_to_isl_surf_dim(enum pipe_texture_target target)
114 {
115 switch (target) {
116 case PIPE_BUFFER:
117 case PIPE_TEXTURE_1D:
118 case PIPE_TEXTURE_1D_ARRAY:
119 return ISL_SURF_DIM_1D;
120 case PIPE_TEXTURE_2D:
121 case PIPE_TEXTURE_CUBE:
122 case PIPE_TEXTURE_RECT:
123 case PIPE_TEXTURE_2D_ARRAY:
124 case PIPE_TEXTURE_CUBE_ARRAY:
125 return ISL_SURF_DIM_2D;
126 case PIPE_TEXTURE_3D:
127 return ISL_SURF_DIM_3D;
128 case PIPE_MAX_TEXTURE_TYPES:
129 break;
130 }
131 unreachable("invalid texture type");
132 }
133
134 static isl_surf_usage_flags_t
135 pipe_bind_to_isl_usage(unsigned bindings)
136 {
137 isl_surf_usage_flags_t usage = 0;
138
139 if (bindings & PIPE_BIND_RENDER_TARGET)
140 usage |= ISL_SURF_USAGE_RENDER_TARGET_BIT;
141
142 if (bindings & PIPE_BIND_SAMPLER_VIEW)
143 usage |= ISL_SURF_USAGE_TEXTURE_BIT;
144
145 if (bindings & (PIPE_BIND_SHADER_IMAGE | PIPE_BIND_SHADER_BUFFER))
146 usage |= ISL_SURF_USAGE_STORAGE_BIT;
147
148 if (bindings & PIPE_BIND_DISPLAY_TARGET)
149 usage |= ISL_SURF_USAGE_DISPLAY_BIT;
150
151 return usage;
152 }
153
154 static void
155 iris_resource_destroy(struct pipe_screen *screen,
156 struct pipe_resource *resource)
157 {
158 struct iris_resource *res = (struct iris_resource *)resource;
159
160 iris_bo_unreference(res->bo);
161 }
162
163 static struct iris_resource *
164 iris_alloc_resource(struct pipe_screen *pscreen,
165 const struct pipe_resource *templ)
166 {
167 struct iris_resource *res = calloc(1, sizeof(struct iris_resource));
168 if (!res)
169 return NULL;
170
171 res->base = *templ;
172 res->base.screen = pscreen;
173 pipe_reference_init(&res->base.reference, 1);
174
175 return res;
176 }
177
178 static struct pipe_resource *
179 iris_resource_create_with_modifiers(struct pipe_screen *pscreen,
180 const struct pipe_resource *templ,
181 const uint64_t *modifiers,
182 int modifiers_count)
183 {
184 struct iris_screen *screen = (struct iris_screen *)pscreen;
185 struct gen_device_info *devinfo = &screen->devinfo;
186 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
187 if (!res)
188 return NULL;
189
190 bool depth = util_format_is_depth_or_stencil(templ->format);
191
192 uint64_t modifier = DRM_FORMAT_MOD_INVALID;
193
194 if (modifiers_count == 0 || !modifiers) {
195 if (depth) {
196 modifier = I915_FORMAT_MOD_Y_TILED;
197 } else if (templ->bind & PIPE_BIND_DISPLAY_TARGET) {
198 /* Display is X-tiled for historical reasons. */
199 modifier = I915_FORMAT_MOD_X_TILED;
200 } else {
201 modifier = I915_FORMAT_MOD_Y_TILED;
202 }
203 /* XXX: make sure this doesn't do stupid things for internal textures */
204 }
205
206 if (templ->target == PIPE_BUFFER || templ->usage == PIPE_USAGE_STAGING)
207 modifier = DRM_FORMAT_MOD_LINEAR;
208
209 if (templ->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR))
210 modifier = DRM_FORMAT_MOD_LINEAR;
211
212 if (modifier == DRM_FORMAT_MOD_INVALID) {
213 /* User requested specific modifiers */
214 modifier = select_best_modifier(devinfo, modifiers, modifiers_count);
215 if (modifier == DRM_FORMAT_MOD_INVALID)
216 return NULL;
217 }
218
219 const struct isl_drm_modifier_info *mod_info =
220 isl_drm_modifier_get_info(modifier);
221
222 isl_surf_usage_flags_t usage = pipe_bind_to_isl_usage(templ->bind);
223
224 if (templ->target == PIPE_TEXTURE_CUBE)
225 usage |= ISL_SURF_USAGE_CUBE_BIT;
226
227 // XXX: separate stencil...
228 enum pipe_format pfmt = templ->format;
229
230 if (util_format_is_depth_or_stencil(pfmt) &&
231 templ->usage != PIPE_USAGE_STAGING)
232 usage |= ISL_SURF_USAGE_DEPTH_BIT;
233
234 if (util_format_is_depth_and_stencil(pfmt)) {
235 // XXX: Z32S8
236 pfmt = PIPE_FORMAT_X8Z24_UNORM;
237 }
238
239 enum isl_format isl_format = iris_isl_format_for_pipe_format(pfmt);
240 assert(isl_format != ISL_FORMAT_UNSUPPORTED);
241
242 UNUSED const bool isl_surf_created_successfully =
243 isl_surf_init(&screen->isl_dev, &res->surf,
244 .dim = target_to_isl_surf_dim(templ->target),
245 .format = isl_format,
246 .width = templ->width0,
247 .height = templ->height0,
248 .depth = templ->depth0,
249 .levels = templ->last_level + 1,
250 .array_len = templ->array_size,
251 .samples = MAX2(templ->nr_samples, 1),
252 .min_alignment_B = 0,
253 .row_pitch_B = 0,
254 .usage = usage,
255 .tiling_flags = 1 << mod_info->tiling);
256 assert(isl_surf_created_successfully);
257
258 enum iris_memory_zone memzone = IRIS_MEMZONE_OTHER;
259 const char *name = templ->target == PIPE_BUFFER ? "buffer" : "miptree";
260 if (templ->flags & IRIS_RESOURCE_FLAG_SHADER_MEMZONE) {
261 memzone = IRIS_MEMZONE_SHADER;
262 name = "shader kernels";
263 } else if (templ->flags & IRIS_RESOURCE_FLAG_SURFACE_MEMZONE) {
264 memzone = IRIS_MEMZONE_SURFACE;
265 name = "surface state";
266 } else if (templ->flags & IRIS_RESOURCE_FLAG_DYNAMIC_MEMZONE) {
267 memzone = IRIS_MEMZONE_DYNAMIC;
268 name = "dynamic state";
269 }
270
271 res->bo = iris_bo_alloc_tiled(screen->bufmgr, name, res->surf.size_B,
272 memzone,
273 isl_tiling_to_i915_tiling(res->surf.tiling),
274 res->surf.row_pitch_B, 0);
275 if (!res->bo)
276 goto fail;
277
278 return &res->base;
279
280 fail:
281 iris_resource_destroy(pscreen, &res->base);
282 return NULL;
283 }
284
285 static struct pipe_resource *
286 iris_resource_create(struct pipe_screen *pscreen,
287 const struct pipe_resource *templ)
288 {
289 return iris_resource_create_with_modifiers(pscreen, templ, NULL, 0);
290 }
291
292 static struct pipe_resource *
293 iris_resource_from_handle(struct pipe_screen *pscreen,
294 const struct pipe_resource *templ,
295 struct winsys_handle *whandle,
296 unsigned usage)
297 {
298 struct iris_screen *screen = (struct iris_screen *)pscreen;
299 struct iris_bufmgr *bufmgr = screen->bufmgr;
300 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
301 if (!res)
302 return NULL;
303
304 if (whandle->offset != 0) {
305 dbg_printf("Attempt to import unsupported winsys offset %u\n",
306 whandle->offset);
307 goto fail;
308 }
309
310 switch (whandle->type) {
311 case WINSYS_HANDLE_TYPE_SHARED:
312 res->bo = iris_bo_import_dmabuf(bufmgr, whandle->handle);
313 break;
314 case WINSYS_HANDLE_TYPE_FD:
315 res->bo = iris_bo_gem_create_from_name(bufmgr, "winsys image",
316 whandle->handle);
317 break;
318 default:
319 unreachable("invalid winsys handle type");
320 }
321
322 const struct isl_drm_modifier_info *mod_info =
323 isl_drm_modifier_get_info(whandle->modifier);
324
325 // XXX: usage...
326 isl_surf_usage_flags_t isl_usage = ISL_SURF_USAGE_DISPLAY_BIT;
327
328 isl_surf_init(&screen->isl_dev, &res->surf,
329 .dim = target_to_isl_surf_dim(templ->target),
330 .format = iris_isl_format_for_pipe_format(templ->format),
331 .width = templ->width0,
332 .height = templ->height0,
333 .depth = templ->depth0,
334 .levels = templ->last_level + 1,
335 .array_len = templ->array_size,
336 .samples = MAX2(templ->nr_samples, 1),
337 .min_alignment_B = 0,
338 .row_pitch_B = 0,
339 .usage = isl_usage,
340 .tiling_flags = 1 << mod_info->tiling);
341
342 assert(res->bo->tiling_mode == isl_tiling_to_i915_tiling(res->surf.tiling));
343
344 return &res->base;
345
346 fail:
347 iris_resource_destroy(pscreen, &res->base);
348 return NULL;
349 }
350
351 static boolean
352 iris_resource_get_handle(struct pipe_screen *pscreen,
353 struct pipe_context *ctx,
354 struct pipe_resource *resource,
355 struct winsys_handle *whandle,
356 unsigned usage)
357 {
358 struct iris_resource *res = (struct iris_resource *)resource;
359
360 whandle->stride = res->surf.row_pitch_B;
361
362 switch (whandle->type) {
363 case WINSYS_HANDLE_TYPE_SHARED:
364 return iris_bo_flink(res->bo, &whandle->handle) == 0;
365 case WINSYS_HANDLE_TYPE_KMS:
366 return iris_bo_export_gem_handle(res->bo) != 0;
367 case WINSYS_HANDLE_TYPE_FD:
368 return iris_bo_export_dmabuf(res->bo, (int *) &whandle->handle) == 0;
369 }
370
371 return false;
372 }
373
374 struct iris_transfer {
375 struct pipe_transfer base;
376 struct pipe_debug_callback *dbg;
377 void *buffer;
378 void *ptr;
379 int stride;
380
381 void (*unmap)(struct iris_transfer *);
382 };
383
384 /* Compute extent parameters for use with tiled_memcpy functions.
385 * xs are in units of bytes and ys are in units of strides.
386 */
387 static inline void
388 tile_extents(struct isl_surf *surf,
389 const struct pipe_box *box,
390 unsigned int level,
391 unsigned int *x1_B, unsigned int *x2_B,
392 unsigned int *y1_el, unsigned int *y2_el)
393 {
394 const struct isl_format_layout *fmtl = isl_format_get_layout(surf->format);
395 const unsigned cpp = fmtl->bpb / 8;
396
397 assert(box->x % fmtl->bw == 0);
398 assert(box->y % fmtl->bh == 0);
399
400 unsigned x0_el, y0_el;
401 isl_surf_get_image_offset_el(surf, level, box->z, box->z, &x0_el, &y0_el);
402
403 *x1_B = (box->x / fmtl->bw + x0_el) * cpp;
404 *y1_el = box->y / fmtl->bh + y0_el;
405 *x2_B = (DIV_ROUND_UP(box->x + box->width, fmtl->bw) + x0_el) * cpp;
406 *y2_el = DIV_ROUND_UP(box->y + box->height, fmtl->bh) + y0_el;
407 }
408
409 static void
410 iris_unmap_tiled_memcpy(struct iris_transfer *map)
411 {
412 struct pipe_transfer *xfer = &map->base;
413 struct iris_resource *res = (struct iris_resource *) xfer->resource;
414 struct isl_surf *surf = &res->surf;
415
416 const bool has_swizzling = false; // XXX: swizzling?
417
418 if (xfer->usage & PIPE_TRANSFER_WRITE) {
419 unsigned int x1, x2, y1, y2;
420 tile_extents(surf, &xfer->box, xfer->level, &x1, &x2, &y1, &y2);
421
422 char *dst = iris_bo_map(map->dbg, res->bo, xfer->usage | MAP_RAW);
423 // XXX: dst += mt->offset;
424
425 isl_memcpy_linear_to_tiled(x1, x2, y1, y2, dst, map->ptr,
426 surf->row_pitch_B, map->stride,
427 has_swizzling, surf->tiling, ISL_MEMCPY);
428 }
429 os_free_aligned(map->buffer);
430 map->buffer = map->ptr = NULL;
431 }
432
433 static void
434 iris_map_tiled_memcpy(struct iris_transfer *map)
435 {
436 struct pipe_transfer *xfer = &map->base;
437 struct iris_resource *res = (struct iris_resource *) xfer->resource;
438 struct isl_surf *surf = &res->surf;
439
440 unsigned int x1, x2, y1, y2;
441 tile_extents(surf, &xfer->box, xfer->level, &x1, &x2, &y1, &y2);
442 map->stride = ALIGN(surf->row_pitch_B, 16);
443
444 /* The tiling and detiling functions require that the linear buffer has
445 * a 16-byte alignment (that is, its `x0` is 16-byte aligned). Here we
446 * over-allocate the linear buffer to get the proper alignment.
447 */
448 map->buffer =
449 os_malloc_aligned(map->stride * (y2 - y1) + (x1 & 0xf), 16);
450 map->ptr = (char *)map->buffer + (x1 & 0xf);
451 assert(map->buffer);
452
453 const bool has_swizzling = false; // XXX: swizzling?
454
455 // XXX: PIPE_TRANSFER_READ?
456 if (!(xfer->usage & PIPE_TRANSFER_DISCARD_RANGE)) {
457 char *src = iris_bo_map(map->dbg, res->bo, xfer->usage | MAP_RAW);
458 // XXX: += mt->offset?
459
460 isl_memcpy_tiled_to_linear(x1, x2, y1, y2, map->ptr, src, map->stride,
461 surf->row_pitch_B, has_swizzling,
462 surf->tiling, ISL_MEMCPY);
463 }
464
465 map->unmap = iris_unmap_tiled_memcpy;
466 }
467
468 static void *
469 iris_transfer_map(struct pipe_context *ctx,
470 struct pipe_resource *resource,
471 unsigned level,
472 enum pipe_transfer_usage usage,
473 const struct pipe_box *box,
474 struct pipe_transfer **ptransfer)
475 {
476 struct iris_context *ice = (struct iris_context *)ctx;
477 struct iris_resource *res = (struct iris_resource *)resource;
478 struct isl_surf *surf = &res->surf;
479
480 if (surf->tiling != ISL_TILING_LINEAR &&
481 (usage & PIPE_TRANSFER_MAP_DIRECTLY))
482 return NULL;
483
484 struct iris_transfer *map = calloc(1, sizeof(struct iris_transfer));
485 struct pipe_transfer *xfer = &map->base;
486
487 // PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE
488 // PIPE_TRANSFER_DISCARD_RANGE
489
490 if (!map)
491 return NULL;
492
493 map->dbg = &ice->dbg;
494
495 pipe_resource_reference(&xfer->resource, resource);
496 xfer->level = level;
497 xfer->usage = usage;
498 xfer->box = *box;
499 xfer->stride = isl_surf_get_row_pitch_B(surf);
500 xfer->layer_stride = isl_surf_get_array_pitch(surf);
501 *ptransfer = xfer;
502
503 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
504 iris_batch_references(&ice->render_batch, res->bo)) {
505 iris_batch_flush(&ice->render_batch);
506 }
507
508 if ((usage & PIPE_TRANSFER_DONTBLOCK) && iris_bo_busy(res->bo))
509 return NULL;
510
511 xfer->usage &= (PIPE_TRANSFER_READ |
512 PIPE_TRANSFER_WRITE |
513 PIPE_TRANSFER_UNSYNCHRONIZED |
514 PIPE_TRANSFER_PERSISTENT |
515 PIPE_TRANSFER_COHERENT);
516
517 if (surf->tiling != ISL_TILING_LINEAR) {
518 iris_map_tiled_memcpy(map);
519 } else {
520 // XXX: apply box
521 map->ptr = iris_bo_map(&ice->dbg, res->bo, xfer->usage);
522 }
523
524 return map->ptr;
525 }
526
527 static void
528 iris_transfer_flush_region(struct pipe_context *pipe,
529 struct pipe_transfer *transfer,
530 const struct pipe_box *box)
531 {
532 }
533
534 static void
535 iris_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *xfer)
536 {
537 struct iris_transfer *map = xfer;
538
539 if (map->unmap)
540 map->unmap(map);
541
542 pipe_resource_reference(&xfer->resource, NULL);
543 free(map);
544 }
545
546 static void
547 iris_buffer_subdata(struct pipe_context *pipe,
548 struct pipe_resource *resource,
549 unsigned usage, unsigned offset,
550 unsigned size, const void *data)
551 {
552 }
553
554 static void
555 iris_texture_subdata(struct pipe_context *pipe,
556 struct pipe_resource *resource,
557 unsigned level,
558 unsigned usage,
559 const struct pipe_box *box,
560 const void *data,
561 unsigned stride,
562 unsigned layer_stride)
563 {
564 }
565
566
567 static void
568 iris_resource_copy_region(struct pipe_context *ctx,
569 struct pipe_resource *dst,
570 unsigned dst_level,
571 unsigned dstx, unsigned dsty, unsigned dstz,
572 struct pipe_resource *src,
573 unsigned src_level,
574 const struct pipe_box *src_box)
575 {
576 }
577
578 static void
579 iris_flush_resource(struct pipe_context *ctx, struct pipe_resource *resource)
580 {
581 }
582
583 static boolean
584 iris_generate_mipmap(struct pipe_context *ctx,
585 struct pipe_resource *resource,
586 enum pipe_format format,
587 unsigned base_level,
588 unsigned last_level,
589 unsigned first_layer,
590 unsigned last_layer)
591 {
592 return true;
593 }
594
595 void
596 iris_init_screen_resource_functions(struct pipe_screen *pscreen)
597 {
598 pscreen->resource_create_with_modifiers =
599 iris_resource_create_with_modifiers;
600 pscreen->resource_create = iris_resource_create;
601 pscreen->resource_from_handle = iris_resource_from_handle;
602 pscreen->resource_get_handle = iris_resource_get_handle;
603 pscreen->resource_destroy = iris_resource_destroy;
604 }
605
606 void
607 iris_init_resource_functions(struct pipe_context *ctx)
608 {
609 ctx->flush_resource = iris_flush_resource;
610 ctx->transfer_map = iris_transfer_map;
611 ctx->transfer_flush_region = iris_transfer_flush_region;
612 ctx->transfer_unmap = iris_transfer_unmap;
613 ctx->buffer_subdata = iris_buffer_subdata;
614 ctx->texture_subdata = iris_texture_subdata;
615 ctx->resource_copy_region = iris_resource_copy_region;
616 }