92c9b038a3d522a63787eca9aba269ef4ed29410
[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/u_inlines.h"
30 #include "util/u_format.h"
31 #include "util/u_upload_mgr.h"
32 #include "util/ralloc.h"
33 #include "iris_batch.h"
34 #include "iris_context.h"
35 #include "iris_resource.h"
36 #include "iris_screen.h"
37 #include "intel/common/gen_debug.h"
38 #include "drm-uapi/drm_fourcc.h"
39 #include "drm-uapi/i915_drm.h"
40
41 enum modifier_priority {
42 MODIFIER_PRIORITY_INVALID = 0,
43 MODIFIER_PRIORITY_LINEAR,
44 MODIFIER_PRIORITY_X,
45 MODIFIER_PRIORITY_Y,
46 MODIFIER_PRIORITY_Y_CCS,
47 };
48
49 static const uint64_t priority_to_modifier[] = {
50 [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID,
51 [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR,
52 [MODIFIER_PRIORITY_X] = I915_FORMAT_MOD_X_TILED,
53 [MODIFIER_PRIORITY_Y] = I915_FORMAT_MOD_Y_TILED,
54 [MODIFIER_PRIORITY_Y_CCS] = I915_FORMAT_MOD_Y_TILED_CCS,
55 };
56
57 static bool
58 modifier_is_supported(const struct gen_device_info *devinfo,
59 uint64_t modifier)
60 {
61 /* XXX: do something real */
62 switch (modifier) {
63 case I915_FORMAT_MOD_Y_TILED:
64 case I915_FORMAT_MOD_X_TILED:
65 case DRM_FORMAT_MOD_LINEAR:
66 return true;
67 case I915_FORMAT_MOD_Y_TILED_CCS:
68 case DRM_FORMAT_MOD_INVALID:
69 default:
70 return false;
71 }
72 }
73
74 static uint64_t
75 select_best_modifier(struct gen_device_info *devinfo,
76 const uint64_t *modifiers,
77 int count)
78 {
79 enum modifier_priority prio = MODIFIER_PRIORITY_INVALID;
80
81 for (int i = 0; i < count; i++) {
82 if (!modifier_is_supported(devinfo, modifiers[i]))
83 continue;
84
85 switch (modifiers[i]) {
86 case I915_FORMAT_MOD_Y_TILED_CCS:
87 prio = MAX2(prio, MODIFIER_PRIORITY_Y_CCS);
88 break;
89 case I915_FORMAT_MOD_Y_TILED:
90 prio = MAX2(prio, MODIFIER_PRIORITY_Y);
91 break;
92 case I915_FORMAT_MOD_X_TILED:
93 prio = MAX2(prio, MODIFIER_PRIORITY_X);
94 break;
95 case DRM_FORMAT_MOD_LINEAR:
96 prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR);
97 break;
98 case DRM_FORMAT_MOD_INVALID:
99 default:
100 break;
101 }
102 }
103
104 return priority_to_modifier[prio];
105 }
106
107 static enum isl_surf_dim
108 target_to_isl_surf_dim(enum pipe_texture_target target)
109 {
110 switch (target) {
111 case PIPE_BUFFER:
112 case PIPE_TEXTURE_1D:
113 case PIPE_TEXTURE_1D_ARRAY:
114 return ISL_SURF_DIM_1D;
115 case PIPE_TEXTURE_2D:
116 case PIPE_TEXTURE_CUBE:
117 case PIPE_TEXTURE_RECT:
118 case PIPE_TEXTURE_2D_ARRAY:
119 case PIPE_TEXTURE_CUBE_ARRAY:
120 return ISL_SURF_DIM_2D;
121 case PIPE_TEXTURE_3D:
122 return ISL_SURF_DIM_3D;
123 case PIPE_MAX_TEXTURE_TYPES:
124 break;
125 }
126 unreachable("invalid texture type");
127 }
128
129 static isl_surf_usage_flags_t
130 pipe_bind_to_isl_usage(unsigned bindings)
131 {
132 isl_surf_usage_flags_t usage = 0;
133
134 if (bindings & PIPE_BIND_DEPTH_STENCIL)
135 usage |= ISL_SURF_USAGE_DEPTH_BIT | ISL_SURF_USAGE_STENCIL_BIT;
136
137 if (bindings & PIPE_BIND_RENDER_TARGET)
138 usage |= ISL_SURF_USAGE_RENDER_TARGET_BIT;
139
140 if (bindings & PIPE_BIND_SHADER_IMAGE)
141 usage |= ISL_SURF_USAGE_STORAGE_BIT;
142
143 if (bindings & PIPE_BIND_DISPLAY_TARGET)
144 usage |= ISL_SURF_USAGE_DISPLAY_BIT;
145
146 /* XXX: what to do with these? */
147 if (bindings & PIPE_BIND_BLENDABLE)
148 ;
149 if (bindings & PIPE_BIND_SAMPLER_VIEW)
150 ;
151 if (bindings & PIPE_BIND_VERTEX_BUFFER)
152 ;
153 if (bindings & PIPE_BIND_INDEX_BUFFER)
154 ;
155 if (bindings & PIPE_BIND_CONSTANT_BUFFER)
156 ;
157
158 if (bindings & PIPE_BIND_STREAM_OUTPUT)
159 ;
160 if (bindings & PIPE_BIND_CURSOR)
161 ;
162 if (bindings & PIPE_BIND_CUSTOM)
163 ;
164
165 if (bindings & PIPE_BIND_GLOBAL)
166 ;
167 if (bindings & PIPE_BIND_SHADER_BUFFER)
168 ;
169 if (bindings & PIPE_BIND_COMPUTE_RESOURCE)
170 ;
171 if (bindings & PIPE_BIND_COMMAND_ARGS_BUFFER)
172 ;
173 if (bindings & PIPE_BIND_QUERY_BUFFER)
174 ;
175
176 return usage;
177 }
178
179 static void
180 iris_resource_destroy(struct pipe_screen *screen,
181 struct pipe_resource *resource)
182 {
183 struct iris_resource *res = (struct iris_resource *)resource;
184
185 iris_bo_unreference(res->bo);
186 }
187
188 static struct iris_resource *
189 iris_alloc_resource(struct pipe_screen *pscreen,
190 const struct pipe_resource *templ)
191 {
192 struct iris_resource *res = calloc(1, sizeof(struct iris_resource));
193 if (!res)
194 return NULL;
195
196 res->base = *templ;
197 res->base.screen = pscreen;
198 pipe_reference_init(&res->base.reference, 1);
199
200 return res;
201 }
202
203 static struct pipe_resource *
204 iris_resource_create_with_modifiers(struct pipe_screen *pscreen,
205 const struct pipe_resource *templ,
206 const uint64_t *modifiers,
207 int modifiers_count)
208 {
209 struct iris_screen *screen = (struct iris_screen *)pscreen;
210 struct gen_device_info *devinfo = &screen->devinfo;
211 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
212 if (!res)
213 return NULL;
214
215 uint64_t modifier = DRM_FORMAT_MOD_INVALID;
216
217 if (modifiers_count == 0) {
218 /* Display is X-tiled for historical reasons. */
219 modifier = (templ->bind & PIPE_BIND_DISPLAY_TARGET) ?
220 I915_FORMAT_MOD_X_TILED : I915_FORMAT_MOD_Y_TILED;
221 /* XXX: make sure this doesn't do stupid things for internal textures */
222 }
223
224 if (templ->target == PIPE_BUFFER)
225 modifier = DRM_FORMAT_MOD_LINEAR;
226
227 if (templ->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR))
228 modifier = DRM_FORMAT_MOD_LINEAR;
229
230 if (modifier == DRM_FORMAT_MOD_INVALID) {
231 /* User requested specific modifiers */
232 modifier = select_best_modifier(devinfo, modifiers, modifiers_count);
233 if (modifier == DRM_FORMAT_MOD_INVALID)
234 return NULL;
235 }
236
237 const struct isl_drm_modifier_info *mod_info =
238 isl_drm_modifier_get_info(modifier);
239
240 isl_surf_usage_flags_t usage = pipe_bind_to_isl_usage(templ->bind);
241
242 if (templ->target == PIPE_TEXTURE_CUBE)
243 usage |= ISL_SURF_USAGE_CUBE_BIT;
244
245 isl_surf_init(&screen->isl_dev, &res->surf,
246 .dim = target_to_isl_surf_dim(templ->target),
247 .format = iris_isl_format_for_pipe_format(templ->format),
248 .width = templ->width0,
249 .height = templ->height0,
250 .depth = templ->depth0,
251 .levels = templ->last_level + 1,
252 .array_len = templ->array_size,
253 .samples = MAX2(templ->nr_samples, 1),
254 .min_alignment_B = 0,
255 .row_pitch_B = 0,
256 .usage = usage,
257 .tiling_flags = 1 << mod_info->tiling);
258
259 enum iris_memory_zone memzone = IRIS_MEMZONE_OTHER;
260 const char *name = "resource";
261 if (templ->flags & IRIS_RESOURCE_FLAG_INSTRUCTION_CACHE) {
262 memzone = IRIS_MEMZONE_SHADER;
263 name = "shader kernels";
264 }
265
266 res->bo = iris_bo_alloc_tiled(screen->bufmgr, name, res->surf.size_B,
267 IRIS_MEMZONE_OTHER,
268 isl_tiling_to_i915_tiling(res->surf.tiling),
269 res->surf.row_pitch_B, 0);
270 if (!res->bo)
271 goto fail;
272
273 return &res->base;
274
275 fail:
276 iris_resource_destroy(pscreen, &res->base);
277 return NULL;
278 }
279
280 static struct pipe_resource *
281 iris_resource_create(struct pipe_screen *pscreen,
282 const struct pipe_resource *templ)
283 {
284 return iris_resource_create_with_modifiers(pscreen, templ, NULL, 0);
285 }
286
287 static struct pipe_resource *
288 iris_resource_from_handle(struct pipe_screen *pscreen,
289 const struct pipe_resource *templ,
290 struct winsys_handle *whandle,
291 unsigned usage)
292 {
293 struct iris_screen *screen = (struct iris_screen *)pscreen;
294 struct iris_bufmgr *bufmgr = screen->bufmgr;
295 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
296 if (!res)
297 return NULL;
298
299 if (whandle->offset != 0) {
300 dbg_printf("Attempt to import unsupported winsys offset %u\n",
301 whandle->offset);
302 goto fail;
303 }
304
305 switch (whandle->type) {
306 case WINSYS_HANDLE_TYPE_SHARED:
307 res->bo = iris_bo_import_dmabuf(bufmgr, whandle->handle);
308 break;
309 case WINSYS_HANDLE_TYPE_FD:
310 res->bo = iris_bo_gem_create_from_name(bufmgr, "winsys image",
311 whandle->handle);
312 break;
313 default:
314 unreachable("invalid winsys handle type");
315 }
316
317 const struct isl_drm_modifier_info *mod_info =
318 isl_drm_modifier_get_info(whandle->modifier);
319
320 // XXX: usage...
321 isl_surf_usage_flags_t isl_usage = ISL_SURF_USAGE_DISPLAY_BIT;
322
323 isl_surf_init(&screen->isl_dev, &res->surf,
324 .dim = target_to_isl_surf_dim(templ->target),
325 .format = iris_isl_format_for_pipe_format(templ->format),
326 .width = templ->width0,
327 .height = templ->height0,
328 .depth = templ->depth0,
329 .levels = templ->last_level + 1,
330 .array_len = templ->array_size,
331 .samples = MAX2(templ->nr_samples, 1),
332 .min_alignment_B = 0,
333 .row_pitch_B = 0,
334 .usage = isl_usage,
335 .tiling_flags = 1 << mod_info->tiling);
336
337 assert(res->bo->tiling_mode == isl_tiling_to_i915_tiling(res->surf.tiling));
338
339 return &res->base;
340
341 fail:
342 iris_resource_destroy(pscreen, &res->base);
343 return NULL;
344 }
345
346 static boolean
347 iris_resource_get_handle(struct pipe_screen *pscreen,
348 struct pipe_context *ctx,
349 struct pipe_resource *resource,
350 struct winsys_handle *whandle,
351 unsigned usage)
352 {
353 struct iris_resource *res = (struct iris_resource *)resource;
354
355 whandle->stride = res->surf.row_pitch_B;
356
357 switch (whandle->type) {
358 case WINSYS_HANDLE_TYPE_SHARED:
359 return iris_bo_flink(res->bo, &whandle->handle) == 0;
360 case WINSYS_HANDLE_TYPE_KMS:
361 return iris_bo_export_gem_handle(res->bo) != 0;
362 case WINSYS_HANDLE_TYPE_FD:
363 return iris_bo_export_dmabuf(res->bo, (int *) &whandle->handle) == 0;
364 }
365
366 return false;
367 }
368
369 static void *
370 iris_transfer_map(struct pipe_context *ctx,
371 struct pipe_resource *resource,
372 unsigned level,
373 enum pipe_transfer_usage usage,
374 const struct pipe_box *box,
375 struct pipe_transfer **ptransfer)
376 {
377 struct iris_context *ice = (struct iris_context *)ctx;
378 struct iris_resource *res = (struct iris_resource *)resource;
379 struct pipe_transfer *transfer;
380
381 // PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE
382 // PIPE_TRANSFER_DISCARD_RANGE
383 // PIPE_TRANSFER_MAP_DIRECTLY
384
385 transfer = calloc(1, sizeof(struct pipe_transfer));
386 if (!transfer)
387 return NULL;
388
389 pipe_resource_reference(&transfer->resource, resource);
390 transfer->level = level;
391 transfer->usage = usage;
392 transfer->box = *box;
393 transfer->stride = isl_surf_get_row_pitch_B(&res->surf);
394 transfer->layer_stride = isl_surf_get_array_pitch(&res->surf);
395 *ptransfer = transfer;
396
397 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
398 iris_batch_references(&ice->render_batch, res->bo)) {
399 iris_batch_flush(&ice->render_batch);
400 }
401
402 if ((usage & PIPE_TRANSFER_DONTBLOCK) && iris_bo_busy(res->bo))
403 return NULL;
404
405 usage &= (PIPE_TRANSFER_READ |
406 PIPE_TRANSFER_WRITE |
407 PIPE_TRANSFER_UNSYNCHRONIZED |
408 PIPE_TRANSFER_PERSISTENT |
409 PIPE_TRANSFER_COHERENT);
410
411 return iris_bo_map(&ice->dbg, res->bo, usage);
412 }
413
414 static void
415 iris_transfer_flush_region(struct pipe_context *pipe,
416 struct pipe_transfer *transfer,
417 const struct pipe_box *box)
418 {
419 }
420
421 static void
422 iris_transfer_unmap(struct pipe_context *pipe,
423 struct pipe_transfer *transfer)
424 {
425 pipe_resource_reference(&transfer->resource, NULL);
426 free(transfer);
427 }
428
429 static void
430 iris_buffer_subdata(struct pipe_context *pipe,
431 struct pipe_resource *resource,
432 unsigned usage, unsigned offset,
433 unsigned size, const void *data)
434 {
435 }
436
437 static void
438 iris_texture_subdata(struct pipe_context *pipe,
439 struct pipe_resource *resource,
440 unsigned level,
441 unsigned usage,
442 const struct pipe_box *box,
443 const void *data,
444 unsigned stride,
445 unsigned layer_stride)
446 {
447 }
448
449
450 static void
451 iris_resource_copy_region(struct pipe_context *ctx,
452 struct pipe_resource *dst,
453 unsigned dst_level,
454 unsigned dstx, unsigned dsty, unsigned dstz,
455 struct pipe_resource *src,
456 unsigned src_level,
457 const struct pipe_box *src_box)
458 {
459 }
460
461 static void
462 iris_flush_resource(struct pipe_context *ctx, struct pipe_resource *resource)
463 {
464 }
465
466 static boolean
467 iris_generate_mipmap(struct pipe_context *ctx,
468 struct pipe_resource *resource,
469 enum pipe_format format,
470 unsigned base_level,
471 unsigned last_level,
472 unsigned first_layer,
473 unsigned last_layer)
474 {
475 return true;
476 }
477
478 void
479 iris_init_screen_resource_functions(struct pipe_screen *pscreen)
480 {
481 pscreen->resource_create_with_modifiers =
482 iris_resource_create_with_modifiers;
483 pscreen->resource_create = iris_resource_create;
484 pscreen->resource_from_handle = iris_resource_from_handle;
485 pscreen->resource_get_handle = iris_resource_get_handle;
486 pscreen->resource_destroy = iris_resource_destroy;
487 }
488
489 void
490 iris_init_resource_functions(struct pipe_context *ctx)
491 {
492 ctx->flush_resource = iris_flush_resource;
493 ctx->transfer_map = iris_transfer_map;
494 ctx->transfer_flush_region = iris_transfer_flush_region;
495 ctx->transfer_unmap = iris_transfer_unmap;
496 ctx->buffer_subdata = iris_buffer_subdata;
497 ctx->texture_subdata = iris_texture_subdata;
498 ctx->resource_copy_region = iris_resource_copy_region;
499 }