iris: Initial commit of a new 'iris' driver for Intel Gen8+ GPUs.
[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_resource.h"
34 #include "iris_screen.h"
35 #include "intel/common/gen_debug.h"
36 #include "drm-uapi/drm_fourcc.h"
37 #include "drm-uapi/i915_drm.h"
38
39 enum modifier_priority {
40 MODIFIER_PRIORITY_INVALID = 0,
41 MODIFIER_PRIORITY_LINEAR,
42 MODIFIER_PRIORITY_X,
43 MODIFIER_PRIORITY_Y,
44 MODIFIER_PRIORITY_Y_CCS,
45 };
46
47 static const uint64_t priority_to_modifier[] = {
48 [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID,
49 [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR,
50 [MODIFIER_PRIORITY_X] = I915_FORMAT_MOD_X_TILED,
51 [MODIFIER_PRIORITY_Y] = I915_FORMAT_MOD_Y_TILED,
52 [MODIFIER_PRIORITY_Y_CCS] = I915_FORMAT_MOD_Y_TILED_CCS,
53 };
54
55 static bool
56 modifier_is_supported(const struct gen_device_info *devinfo,
57 uint64_t modifier)
58 {
59 /* XXX: do something real */
60 switch (modifier) {
61 case I915_FORMAT_MOD_Y_TILED:
62 case I915_FORMAT_MOD_X_TILED:
63 case DRM_FORMAT_MOD_LINEAR:
64 return true;
65 case I915_FORMAT_MOD_Y_TILED_CCS:
66 case DRM_FORMAT_MOD_INVALID:
67 default:
68 return false;
69 }
70 }
71
72 static uint64_t
73 select_best_modifier(struct gen_device_info *devinfo,
74 const uint64_t *modifiers,
75 int count)
76 {
77 enum modifier_priority prio = MODIFIER_PRIORITY_INVALID;
78
79 for (int i = 0; i < count; i++) {
80 if (!modifier_is_supported(devinfo, modifiers[i]))
81 continue;
82
83 switch (modifiers[i]) {
84 case I915_FORMAT_MOD_Y_TILED_CCS:
85 prio = MAX2(prio, MODIFIER_PRIORITY_Y_CCS);
86 break;
87 case I915_FORMAT_MOD_Y_TILED:
88 prio = MAX2(prio, MODIFIER_PRIORITY_Y);
89 break;
90 case I915_FORMAT_MOD_X_TILED:
91 prio = MAX2(prio, MODIFIER_PRIORITY_X);
92 break;
93 case DRM_FORMAT_MOD_LINEAR:
94 prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR);
95 break;
96 case DRM_FORMAT_MOD_INVALID:
97 default:
98 break;
99 }
100 }
101
102 return priority_to_modifier[prio];
103 }
104
105 static enum isl_surf_dim
106 target_to_isl_surf_dim(enum pipe_texture_target target)
107 {
108 switch (target) {
109 case PIPE_BUFFER:
110 case PIPE_TEXTURE_1D:
111 case PIPE_TEXTURE_1D_ARRAY:
112 return ISL_SURF_DIM_1D;
113 case PIPE_TEXTURE_2D:
114 case PIPE_TEXTURE_CUBE:
115 case PIPE_TEXTURE_RECT:
116 case PIPE_TEXTURE_2D_ARRAY:
117 case PIPE_TEXTURE_CUBE_ARRAY:
118 return ISL_SURF_DIM_2D;
119 case PIPE_TEXTURE_3D:
120 return ISL_SURF_DIM_3D;
121 case PIPE_MAX_TEXTURE_TYPES:
122 break;
123 }
124 unreachable("invalid texture type");
125 }
126
127 static isl_surf_usage_flags_t
128 pipe_bind_to_isl_usage(unsigned bindings)
129 {
130 isl_surf_usage_flags_t usage = 0;
131
132 if (bindings & PIPE_BIND_DEPTH_STENCIL)
133 usage |= ISL_SURF_USAGE_DEPTH_BIT | ISL_SURF_USAGE_STENCIL_BIT;
134
135 if (bindings & PIPE_BIND_RENDER_TARGET)
136 usage |= ISL_SURF_USAGE_RENDER_TARGET_BIT;
137
138 if (bindings & PIPE_BIND_SHADER_IMAGE)
139 usage |= ISL_SURF_USAGE_STORAGE_BIT;
140
141 if (bindings & PIPE_BIND_DISPLAY_TARGET)
142 usage |= ISL_SURF_USAGE_DISPLAY_BIT;
143
144 /* XXX: what to do with these? */
145 if (bindings & PIPE_BIND_BLENDABLE)
146 ;
147 if (bindings & PIPE_BIND_SAMPLER_VIEW)
148 ;
149 if (bindings & PIPE_BIND_VERTEX_BUFFER)
150 ;
151 if (bindings & PIPE_BIND_INDEX_BUFFER)
152 ;
153 if (bindings & PIPE_BIND_CONSTANT_BUFFER)
154 ;
155
156 if (bindings & PIPE_BIND_STREAM_OUTPUT)
157 ;
158 if (bindings & PIPE_BIND_CURSOR)
159 ;
160 if (bindings & PIPE_BIND_CUSTOM)
161 ;
162
163 if (bindings & PIPE_BIND_GLOBAL)
164 ;
165 if (bindings & PIPE_BIND_SHADER_BUFFER)
166 ;
167 if (bindings & PIPE_BIND_COMPUTE_RESOURCE)
168 ;
169 if (bindings & PIPE_BIND_COMMAND_ARGS_BUFFER)
170 ;
171 if (bindings & PIPE_BIND_QUERY_BUFFER)
172 ;
173
174 return usage;
175 }
176
177 static void
178 iris_resource_destroy(struct pipe_screen *screen,
179 struct pipe_resource *resource)
180 {
181 struct iris_resource *res = (struct iris_resource *)resource;
182
183 iris_bo_unreference(res->bo);
184 }
185
186 static struct iris_resource *
187 iris_alloc_resource(struct pipe_screen *pscreen,
188 const struct pipe_resource *templ)
189 {
190 struct iris_resource *res = calloc(1, sizeof(struct iris_resource));
191 if (!res)
192 return NULL;
193
194 res->base = *templ;
195 res->base.screen = pscreen;
196 pipe_reference_init(&res->base.reference, 1);
197
198 return res;
199 }
200
201 static struct pipe_resource *
202 iris_resource_create_with_modifiers(struct pipe_screen *pscreen,
203 const struct pipe_resource *templ,
204 const uint64_t *modifiers,
205 int modifiers_count)
206 {
207 struct iris_screen *screen = (struct iris_screen *)pscreen;
208 struct gen_device_info *devinfo = &screen->devinfo;
209 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
210 if (!res)
211 return NULL;
212
213 uint64_t modifier = DRM_FORMAT_MOD_INVALID;
214
215 if (templ->target == PIPE_BUFFER)
216 modifier = DRM_FORMAT_MOD_LINEAR;
217
218 if (templ->bind & (PIPE_BIND_LINEAR | PIPE_BIND_CURSOR))
219 modifier = DRM_FORMAT_MOD_LINEAR;
220
221 if (modifiers_count == 0) {
222 /* Display is X-tiled for historical reasons. */
223 modifier = (templ->bind & PIPE_BIND_DISPLAY_TARGET) ?
224 I915_FORMAT_MOD_X_TILED : I915_FORMAT_MOD_Y_TILED;
225 /* XXX: make sure this doesn't do stupid things for internal textures */
226 }
227
228 if (modifier == DRM_FORMAT_MOD_INVALID) {
229 /* User requested specific modifiers */
230 modifier = select_best_modifier(devinfo, modifiers, modifiers_count);
231 if (modifier == DRM_FORMAT_MOD_INVALID)
232 return NULL;
233 }
234
235 const struct isl_drm_modifier_info *mod_info =
236 isl_drm_modifier_get_info(modifier);
237
238 isl_surf_usage_flags_t usage = pipe_bind_to_isl_usage(templ->bind);
239
240 if (templ->target == PIPE_TEXTURE_CUBE)
241 usage |= ISL_SURF_USAGE_CUBE_BIT;
242
243 isl_surf_init(&screen->isl_dev, &res->surf,
244 .dim = target_to_isl_surf_dim(templ->target),
245 .format = iris_isl_format_for_pipe_format(templ->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
257 res->bo = iris_bo_alloc_tiled(screen->bufmgr, "resource", res->surf.size_B,
258 isl_tiling_to_i915_tiling(res->surf.tiling),
259 res->surf.row_pitch_B, 0);
260 if (!res->bo)
261 goto fail;
262
263 return &res->base;
264
265 fail:
266 iris_resource_destroy(pscreen, &res->base);
267 return NULL;
268 }
269
270 static struct pipe_resource *
271 iris_resource_create(struct pipe_screen *pscreen,
272 const struct pipe_resource *templ)
273 {
274 return iris_resource_create_with_modifiers(pscreen, templ, NULL, 0);
275 }
276
277 static struct pipe_resource *
278 iris_resource_from_handle(struct pipe_screen *pscreen,
279 const struct pipe_resource *templ,
280 struct winsys_handle *whandle,
281 unsigned usage)
282 {
283 struct iris_screen *screen = (struct iris_screen *)pscreen;
284 struct iris_bufmgr *bufmgr = screen->bufmgr;
285 struct iris_resource *res = iris_alloc_resource(pscreen, templ);
286 if (!res)
287 return NULL;
288
289 if (whandle->offset != 0) {
290 dbg_printf("Attempt to import unsupported winsys offset %u\n",
291 whandle->offset);
292 goto fail;
293 }
294
295 switch (whandle->type) {
296 case WINSYS_HANDLE_TYPE_SHARED:
297 res->bo = iris_bo_import_dmabuf(bufmgr, whandle->handle);
298 break;
299 case WINSYS_HANDLE_TYPE_FD:
300 res->bo = iris_bo_gem_create_from_name(bufmgr, "winsys image",
301 whandle->handle);
302 break;
303 default:
304 unreachable("invalid winsys handle type");
305 }
306
307 const struct isl_drm_modifier_info *mod_info =
308 isl_drm_modifier_get_info(whandle->modifier);
309
310 // XXX: usage...
311 isl_surf_usage_flags_t isl_usage = ISL_SURF_USAGE_DISPLAY_BIT;
312
313 isl_surf_init(&screen->isl_dev, &res->surf,
314 .dim = target_to_isl_surf_dim(templ->target),
315 .format = iris_isl_format_for_pipe_format(templ->format),
316 .width = templ->width0,
317 .height = templ->height0,
318 .depth = templ->depth0,
319 .levels = templ->last_level + 1,
320 .array_len = templ->array_size,
321 .samples = MAX2(templ->nr_samples, 1),
322 .min_alignment_B = 0,
323 .row_pitch_B = 0,
324 .usage = isl_usage,
325 .tiling_flags = 1 << mod_info->tiling);
326
327 assert(res->bo->tiling_mode == isl_tiling_to_i915_tiling(res->surf.tiling));
328
329 return &res->base;
330
331 fail:
332 iris_resource_destroy(pscreen, &res->base);
333 return NULL;
334 }
335
336 static boolean
337 iris_resource_get_handle(struct pipe_screen *pscreen,
338 struct pipe_context *ctx,
339 struct pipe_resource *resource,
340 struct winsys_handle *whandle,
341 unsigned usage)
342 {
343 struct iris_resource *res = (struct iris_resource *)resource;
344
345 whandle->stride = res->surf.row_pitch_B;
346
347 switch (whandle->type) {
348 case WINSYS_HANDLE_TYPE_SHARED:
349 return iris_bo_flink(res->bo, &whandle->handle) > 0;
350 case WINSYS_HANDLE_TYPE_KMS:
351 return iris_bo_export_gem_handle(res->bo);
352 case WINSYS_HANDLE_TYPE_FD:
353 return iris_bo_export_dmabuf(res->bo, (int *) &whandle->handle) > 0;
354 }
355
356 return false;
357 }
358
359 void
360 iris_init_screen_resource_functions(struct pipe_screen *pscreen)
361 {
362 pscreen->resource_create_with_modifiers =
363 iris_resource_create_with_modifiers;
364 pscreen->resource_create = iris_resource_create;
365 pscreen->resource_from_handle = iris_resource_from_handle;
366 pscreen->resource_get_handle = iris_resource_get_handle;
367 pscreen->resource_destroy = iris_resource_destroy;
368 }