iris: fix dmabuf retval comparisons
[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 res->bo = iris_bo_alloc_tiled(screen->bufmgr, "resource", res->surf.size_B,
260 isl_tiling_to_i915_tiling(res->surf.tiling),
261 res->surf.row_pitch_B, 0);
262 if (!res->bo)
263 goto fail;
264
265 if (templ->flags & IRIS_RESOURCE_FLAG_INSTRUCTION_CACHE) {
266 res->bo->kflags = EXEC_OBJECT_PINNED;
267 res->bo->name = "instruction cache";
268 // XXX: p_atomic_add is backwards :(
269 res->bo->gtt_offset = __atomic_fetch_add(&screen->next_instruction_address, res->bo->size, __ATOMIC_ACQ_REL);
270 }
271
272 return &res->base;
273
274 fail:
275 iris_resource_destroy(pscreen, &res->base);
276 return NULL;
277 }
278
279 static struct pipe_resource *
280 iris_resource_create(struct pipe_screen *pscreen,
281 const struct pipe_resource *templ)
282 {
283 return iris_resource_create_with_modifiers(pscreen, templ, NULL, 0);
284 }
285
286 static struct pipe_resource *
287 iris_resource_from_handle(struct pipe_screen *pscreen,
288 const struct pipe_resource *templ,
289 struct winsys_handle *whandle,
290 unsigned usage)
291 {
292 struct iris_screen *screen = (struct iris_screen *)pscreen;
293 struct iris_bufmgr *bufmgr = screen->bufmgr;
294 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
295 if (!res)
296 return NULL;
297
298 if (whandle->offset != 0) {
299 dbg_printf("Attempt to import unsupported winsys offset %u\n",
300 whandle->offset);
301 goto fail;
302 }
303
304 switch (whandle->type) {
305 case WINSYS_HANDLE_TYPE_SHARED:
306 res->bo = iris_bo_import_dmabuf(bufmgr, whandle->handle);
307 break;
308 case WINSYS_HANDLE_TYPE_FD:
309 res->bo = iris_bo_gem_create_from_name(bufmgr, "winsys image",
310 whandle->handle);
311 break;
312 default:
313 unreachable("invalid winsys handle type");
314 }
315
316 const struct isl_drm_modifier_info *mod_info =
317 isl_drm_modifier_get_info(whandle->modifier);
318
319 // XXX: usage...
320 isl_surf_usage_flags_t isl_usage = ISL_SURF_USAGE_DISPLAY_BIT;
321
322 isl_surf_init(&screen->isl_dev, &res->surf,
323 .dim = target_to_isl_surf_dim(templ->target),
324 .format = iris_isl_format_for_pipe_format(templ->format),
325 .width = templ->width0,
326 .height = templ->height0,
327 .depth = templ->depth0,
328 .levels = templ->last_level + 1,
329 .array_len = templ->array_size,
330 .samples = MAX2(templ->nr_samples, 1),
331 .min_alignment_B = 0,
332 .row_pitch_B = 0,
333 .usage = isl_usage,
334 .tiling_flags = 1 << mod_info->tiling);
335
336 assert(res->bo->tiling_mode == isl_tiling_to_i915_tiling(res->surf.tiling));
337
338 return &res->base;
339
340 fail:
341 iris_resource_destroy(pscreen, &res->base);
342 return NULL;
343 }
344
345 static boolean
346 iris_resource_get_handle(struct pipe_screen *pscreen,
347 struct pipe_context *ctx,
348 struct pipe_resource *resource,
349 struct winsys_handle *whandle,
350 unsigned usage)
351 {
352 struct iris_resource *res = (struct iris_resource *)resource;
353
354 whandle->stride = res->surf.row_pitch_B;
355
356 switch (whandle->type) {
357 case WINSYS_HANDLE_TYPE_SHARED:
358 return iris_bo_flink(res->bo, &whandle->handle) == 0;
359 case WINSYS_HANDLE_TYPE_KMS:
360 return iris_bo_export_gem_handle(res->bo) == 0;
361 case WINSYS_HANDLE_TYPE_FD:
362 return iris_bo_export_dmabuf(res->bo, (int *) &whandle->handle) == 0;
363 }
364
365 return false;
366 }
367
368 static void *
369 iris_transfer_map(struct pipe_context *ctx,
370 struct pipe_resource *resource,
371 unsigned level,
372 enum pipe_transfer_usage usage,
373 const struct pipe_box *box,
374 struct pipe_transfer **ptransfer)
375 {
376 struct iris_context *ice = (struct iris_context *)ctx;
377 struct iris_resource *res = (struct iris_resource *)resource;
378 struct pipe_transfer *transfer;
379
380 // PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE
381 // PIPE_TRANSFER_DISCARD_RANGE
382 // PIPE_TRANSFER_MAP_DIRECTLY
383
384 transfer = calloc(1, sizeof(struct pipe_transfer));
385 if (!transfer)
386 return NULL;
387
388 pipe_resource_reference(&transfer->resource, resource);
389 transfer->level = level;
390 transfer->usage = usage;
391 transfer->box = *box;
392 transfer->stride = 1;
393 transfer->layer_stride = 1;
394 *ptransfer = transfer;
395
396 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
397 iris_batch_references(&ice->render_batch, res->bo)) {
398 iris_batch_flush(&ice->render_batch);
399 }
400
401 if ((usage & PIPE_TRANSFER_DONTBLOCK) && iris_bo_busy(res->bo))
402 return NULL;
403
404 usage &= (PIPE_TRANSFER_READ |
405 PIPE_TRANSFER_WRITE |
406 PIPE_TRANSFER_UNSYNCHRONIZED |
407 PIPE_TRANSFER_PERSISTENT |
408 PIPE_TRANSFER_COHERENT);
409
410 return iris_bo_map(&ice->dbg, res->bo, usage);
411 }
412
413 static void
414 iris_transfer_flush_region(struct pipe_context *pipe,
415 struct pipe_transfer *transfer,
416 const struct pipe_box *box)
417 {
418 }
419
420 static void
421 iris_transfer_unmap(struct pipe_context *pipe,
422 struct pipe_transfer *transfer)
423 {
424 pipe_resource_reference(&transfer->resource, NULL);
425 free(transfer);
426 }
427
428 static void
429 iris_buffer_subdata(struct pipe_context *pipe,
430 struct pipe_resource *resource,
431 unsigned usage, unsigned offset,
432 unsigned size, const void *data)
433 {
434 }
435
436 static void
437 iris_texture_subdata(struct pipe_context *pipe,
438 struct pipe_resource *resource,
439 unsigned level,
440 unsigned usage,
441 const struct pipe_box *box,
442 const void *data,
443 unsigned stride,
444 unsigned layer_stride)
445 {
446 }
447
448
449 static void
450 iris_resource_copy_region(struct pipe_context *ctx,
451 struct pipe_resource *dst,
452 unsigned dst_level,
453 unsigned dstx, unsigned dsty, unsigned dstz,
454 struct pipe_resource *src,
455 unsigned src_level,
456 const struct pipe_box *src_box)
457 {
458 }
459
460 static void
461 iris_flush_resource(struct pipe_context *ctx, struct pipe_resource *resource)
462 {
463 }
464
465 static boolean
466 iris_generate_mipmap(struct pipe_context *ctx,
467 struct pipe_resource *resource,
468 enum pipe_format format,
469 unsigned base_level,
470 unsigned last_level,
471 unsigned first_layer,
472 unsigned last_layer)
473 {
474 return true;
475 }
476
477 void
478 iris_init_screen_resource_functions(struct pipe_screen *pscreen)
479 {
480 pscreen->resource_create_with_modifiers =
481 iris_resource_create_with_modifiers;
482 pscreen->resource_create = iris_resource_create;
483 pscreen->resource_from_handle = iris_resource_from_handle;
484 pscreen->resource_get_handle = iris_resource_get_handle;
485 pscreen->resource_destroy = iris_resource_destroy;
486 }
487
488 void
489 iris_init_resource_functions(struct pipe_context *ctx)
490 {
491 ctx->flush_resource = iris_flush_resource;
492 ctx->transfer_map = iris_transfer_map;
493 ctx->transfer_flush_region = iris_transfer_flush_region;
494 ctx->transfer_unmap = iris_transfer_unmap;
495 ctx->buffer_subdata = iris_buffer_subdata;
496 ctx->texture_subdata = iris_texture_subdata;
497 ctx->resource_copy_region = iris_resource_copy_region;
498 }