2 * Copyright © 2017 Intel Corporation
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:
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
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.
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"
41 #include "drm-uapi/drm_fourcc.h"
42 #include "drm-uapi/i915_drm.h"
44 // XXX: u_transfer_helper...for separate stencil...
46 enum modifier_priority
{
47 MODIFIER_PRIORITY_INVALID
= 0,
48 MODIFIER_PRIORITY_LINEAR
,
51 MODIFIER_PRIORITY_Y_CCS
,
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
,
63 modifier_is_supported(const struct gen_device_info
*devinfo
,
66 /* XXX: do something real */
68 case I915_FORMAT_MOD_Y_TILED
:
69 case I915_FORMAT_MOD_X_TILED
:
70 case DRM_FORMAT_MOD_LINEAR
:
72 case I915_FORMAT_MOD_Y_TILED_CCS
:
73 case DRM_FORMAT_MOD_INVALID
:
80 select_best_modifier(struct gen_device_info
*devinfo
,
81 const uint64_t *modifiers
,
84 enum modifier_priority prio
= MODIFIER_PRIORITY_INVALID
;
86 for (int i
= 0; i
< count
; i
++) {
87 if (!modifier_is_supported(devinfo
, modifiers
[i
]))
90 switch (modifiers
[i
]) {
91 case I915_FORMAT_MOD_Y_TILED_CCS
:
92 prio
= MAX2(prio
, MODIFIER_PRIORITY_Y_CCS
);
94 case I915_FORMAT_MOD_Y_TILED
:
95 prio
= MAX2(prio
, MODIFIER_PRIORITY_Y
);
97 case I915_FORMAT_MOD_X_TILED
:
98 prio
= MAX2(prio
, MODIFIER_PRIORITY_X
);
100 case DRM_FORMAT_MOD_LINEAR
:
101 prio
= MAX2(prio
, MODIFIER_PRIORITY_LINEAR
);
103 case DRM_FORMAT_MOD_INVALID
:
109 return priority_to_modifier
[prio
];
112 static enum isl_surf_dim
113 target_to_isl_surf_dim(enum pipe_texture_target target
)
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
:
131 unreachable("invalid texture type");
134 static isl_surf_usage_flags_t
135 pipe_bind_to_isl_usage(unsigned bindings
)
137 isl_surf_usage_flags_t usage
= 0;
139 if (bindings
& PIPE_BIND_RENDER_TARGET
)
140 usage
|= ISL_SURF_USAGE_RENDER_TARGET_BIT
;
142 if (bindings
& PIPE_BIND_SAMPLER_VIEW
)
143 usage
|= ISL_SURF_USAGE_TEXTURE_BIT
;
145 if (bindings
& (PIPE_BIND_SHADER_IMAGE
| PIPE_BIND_SHADER_BUFFER
))
146 usage
|= ISL_SURF_USAGE_STORAGE_BIT
;
148 if (bindings
& PIPE_BIND_DISPLAY_TARGET
)
149 usage
|= ISL_SURF_USAGE_DISPLAY_BIT
;
155 iris_resource_destroy(struct pipe_screen
*screen
,
156 struct pipe_resource
*resource
)
158 struct iris_resource
*res
= (struct iris_resource
*)resource
;
160 iris_bo_unreference(res
->bo
);
163 static struct iris_resource
*
164 iris_alloc_resource(struct pipe_screen
*pscreen
,
165 const struct pipe_resource
*templ
)
167 struct iris_resource
*res
= calloc(1, sizeof(struct iris_resource
));
172 res
->base
.screen
= pscreen
;
173 pipe_reference_init(&res
->base
.reference
, 1);
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
,
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
);
190 bool depth
= util_format_is_depth_or_stencil(templ
->format
);
192 uint64_t modifier
= DRM_FORMAT_MOD_INVALID
;
194 if (modifiers_count
== 0 || !modifiers
) {
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
;
201 modifier
= I915_FORMAT_MOD_Y_TILED
;
203 /* XXX: make sure this doesn't do stupid things for internal textures */
206 if (templ
->target
== PIPE_BUFFER
|| templ
->usage
== PIPE_USAGE_STAGING
)
207 modifier
= DRM_FORMAT_MOD_LINEAR
;
209 if (templ
->bind
& (PIPE_BIND_LINEAR
| PIPE_BIND_CURSOR
))
210 modifier
= DRM_FORMAT_MOD_LINEAR
;
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
)
219 const struct isl_drm_modifier_info
*mod_info
=
220 isl_drm_modifier_get_info(modifier
);
222 isl_surf_usage_flags_t usage
= pipe_bind_to_isl_usage(templ
->bind
);
224 if (templ
->target
== PIPE_TEXTURE_CUBE
)
225 usage
|= ISL_SURF_USAGE_CUBE_BIT
;
227 // XXX: separate stencil...
228 enum pipe_format pfmt
= templ
->format
;
230 if (util_format_is_depth_or_stencil(pfmt
) &&
231 templ
->usage
!= PIPE_USAGE_STAGING
)
232 usage
|= ISL_SURF_USAGE_DEPTH_BIT
;
234 if (util_format_is_depth_and_stencil(pfmt
)) {
236 pfmt
= PIPE_FORMAT_X8Z24_UNORM
;
239 enum isl_format isl_format
= iris_isl_format_for_pipe_format(pfmt
);
240 assert(isl_format
!= ISL_FORMAT_UNSUPPORTED
);
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,
255 .tiling_flags
= 1 << mod_info
->tiling
);
256 assert(isl_surf_created_successfully
);
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";
271 res
->bo
= iris_bo_alloc_tiled(screen
->bufmgr
, name
, res
->surf
.size_B
,
273 isl_tiling_to_i915_tiling(res
->surf
.tiling
),
274 res
->surf
.row_pitch_B
, 0);
281 iris_resource_destroy(pscreen
, &res
->base
);
285 static struct pipe_resource
*
286 iris_resource_create(struct pipe_screen
*pscreen
,
287 const struct pipe_resource
*templ
)
289 return iris_resource_create_with_modifiers(pscreen
, templ
, NULL
, 0);
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
,
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
);
304 if (whandle
->offset
!= 0) {
305 dbg_printf("Attempt to import unsupported winsys offset %u\n",
310 switch (whandle
->type
) {
311 case WINSYS_HANDLE_TYPE_SHARED
:
312 res
->bo
= iris_bo_import_dmabuf(bufmgr
, whandle
->handle
);
314 case WINSYS_HANDLE_TYPE_FD
:
315 res
->bo
= iris_bo_gem_create_from_name(bufmgr
, "winsys image",
319 unreachable("invalid winsys handle type");
322 const struct isl_drm_modifier_info
*mod_info
=
323 isl_drm_modifier_get_info(whandle
->modifier
);
326 isl_surf_usage_flags_t isl_usage
= ISL_SURF_USAGE_DISPLAY_BIT
;
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,
340 .tiling_flags
= 1 << mod_info
->tiling
);
342 assert(res
->bo
->tiling_mode
== isl_tiling_to_i915_tiling(res
->surf
.tiling
));
347 iris_resource_destroy(pscreen
, &res
->base
);
352 iris_resource_get_handle(struct pipe_screen
*pscreen
,
353 struct pipe_context
*ctx
,
354 struct pipe_resource
*resource
,
355 struct winsys_handle
*whandle
,
358 struct iris_resource
*res
= (struct iris_resource
*)resource
;
360 whandle
->stride
= res
->surf
.row_pitch_B
;
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;
374 struct iris_transfer
{
375 struct pipe_transfer base
;
376 struct pipe_debug_callback
*dbg
;
381 void (*unmap
)(struct iris_transfer
*);
384 /* Compute extent parameters for use with tiled_memcpy functions.
385 * xs are in units of bytes and ys are in units of strides.
388 tile_extents(struct isl_surf
*surf
,
389 const struct pipe_box
*box
,
391 unsigned int *x1_B
, unsigned int *x2_B
,
392 unsigned int *y1_el
, unsigned int *y2_el
)
394 const struct isl_format_layout
*fmtl
= isl_format_get_layout(surf
->format
);
395 const unsigned cpp
= fmtl
->bpb
/ 8;
397 assert(box
->x
% fmtl
->bw
== 0);
398 assert(box
->y
% fmtl
->bh
== 0);
400 unsigned x0_el
, y0_el
;
401 isl_surf_get_image_offset_el(surf
, level
, box
->z
, box
->z
, &x0_el
, &y0_el
);
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
;
410 iris_unmap_tiled_memcpy(struct iris_transfer
*map
)
412 struct pipe_transfer
*xfer
= &map
->base
;
413 struct iris_resource
*res
= (struct iris_resource
*) xfer
->resource
;
414 struct isl_surf
*surf
= &res
->surf
;
416 const bool has_swizzling
= false; // XXX: swizzling?
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
);
422 char *dst
= iris_bo_map(map
->dbg
, res
->bo
, xfer
->usage
| MAP_RAW
);
423 // XXX: dst += mt->offset;
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
);
429 os_free_aligned(map
->buffer
);
430 map
->buffer
= map
->ptr
= NULL
;
434 iris_map_tiled_memcpy(struct iris_transfer
*map
)
436 struct pipe_transfer
*xfer
= &map
->base
;
437 struct iris_resource
*res
= (struct iris_resource
*) xfer
->resource
;
438 struct isl_surf
*surf
= &res
->surf
;
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);
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.
449 os_malloc_aligned(map
->stride
* (y2
- y1
) + (x1
& 0xf), 16);
450 map
->ptr
= (char *)map
->buffer
+ (x1
& 0xf);
453 const bool has_swizzling
= false; // XXX: swizzling?
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?
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
);
465 map
->unmap
= iris_unmap_tiled_memcpy
;
469 iris_transfer_map(struct pipe_context
*ctx
,
470 struct pipe_resource
*resource
,
472 enum pipe_transfer_usage usage
,
473 const struct pipe_box
*box
,
474 struct pipe_transfer
**ptransfer
)
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
;
480 if (surf
->tiling
!= ISL_TILING_LINEAR
&&
481 (usage
& PIPE_TRANSFER_MAP_DIRECTLY
))
484 struct iris_transfer
*map
= calloc(1, sizeof(struct iris_transfer
));
485 struct pipe_transfer
*xfer
= &map
->base
;
487 // PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE
488 // PIPE_TRANSFER_DISCARD_RANGE
493 map
->dbg
= &ice
->dbg
;
495 pipe_resource_reference(&xfer
->resource
, resource
);
499 xfer
->stride
= isl_surf_get_row_pitch_B(surf
);
500 xfer
->layer_stride
= isl_surf_get_array_pitch(surf
);
503 if (!(usage
& PIPE_TRANSFER_UNSYNCHRONIZED
) &&
504 iris_batch_references(&ice
->render_batch
, res
->bo
)) {
505 iris_batch_flush(&ice
->render_batch
);
508 if ((usage
& PIPE_TRANSFER_DONTBLOCK
) && iris_bo_busy(res
->bo
))
511 xfer
->usage
&= (PIPE_TRANSFER_READ
|
512 PIPE_TRANSFER_WRITE
|
513 PIPE_TRANSFER_UNSYNCHRONIZED
|
514 PIPE_TRANSFER_PERSISTENT
|
515 PIPE_TRANSFER_COHERENT
);
517 if (surf
->tiling
!= ISL_TILING_LINEAR
) {
518 iris_map_tiled_memcpy(map
);
521 map
->ptr
= iris_bo_map(&ice
->dbg
, res
->bo
, xfer
->usage
);
528 iris_transfer_flush_region(struct pipe_context
*pipe
,
529 struct pipe_transfer
*transfer
,
530 const struct pipe_box
*box
)
535 iris_transfer_unmap(struct pipe_context
*pipe
, struct pipe_transfer
*xfer
)
537 struct iris_transfer
*map
= xfer
;
542 pipe_resource_reference(&xfer
->resource
, NULL
);
547 iris_buffer_subdata(struct pipe_context
*pipe
,
548 struct pipe_resource
*resource
,
549 unsigned usage
, unsigned offset
,
550 unsigned size
, const void *data
)
555 iris_texture_subdata(struct pipe_context
*pipe
,
556 struct pipe_resource
*resource
,
559 const struct pipe_box
*box
,
562 unsigned layer_stride
)
568 iris_resource_copy_region(struct pipe_context
*ctx
,
569 struct pipe_resource
*dst
,
571 unsigned dstx
, unsigned dsty
, unsigned dstz
,
572 struct pipe_resource
*src
,
574 const struct pipe_box
*src_box
)
579 iris_flush_resource(struct pipe_context
*ctx
, struct pipe_resource
*resource
)
584 iris_generate_mipmap(struct pipe_context
*ctx
,
585 struct pipe_resource
*resource
,
586 enum pipe_format format
,
589 unsigned first_layer
,
596 iris_init_screen_resource_functions(struct pipe_screen
*pscreen
)
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
;
607 iris_init_resource_functions(struct pipe_context
*ctx
)
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
;