ilo: add ilo_image_init_for_imported()
[mesa.git] / src / gallium / drivers / ilo / ilo_resource.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2012-2013 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include "ilo_screen.h"
29 #include "ilo_resource.h"
30
31 /*
32 * From the Ivy Bridge PRM, volume 1 part 1, page 105:
33 *
34 * "In addition to restrictions on maximum height, width, and depth,
35 * surfaces are also restricted to a maximum size in bytes. This
36 * maximum is 2 GB for all products and all surface types."
37 */
38 static const size_t ilo_max_resource_size = 1u << 31;
39
40 static const char *
41 resource_get_bo_name(const struct pipe_resource *templ)
42 {
43 static const char *target_names[PIPE_MAX_TEXTURE_TYPES] = {
44 [PIPE_BUFFER] = "buf",
45 [PIPE_TEXTURE_1D] = "tex-1d",
46 [PIPE_TEXTURE_2D] = "tex-2d",
47 [PIPE_TEXTURE_3D] = "tex-3d",
48 [PIPE_TEXTURE_CUBE] = "tex-cube",
49 [PIPE_TEXTURE_RECT] = "tex-rect",
50 [PIPE_TEXTURE_1D_ARRAY] = "tex-1d-array",
51 [PIPE_TEXTURE_2D_ARRAY] = "tex-2d-array",
52 [PIPE_TEXTURE_CUBE_ARRAY] = "tex-cube-array",
53 };
54 const char *name = target_names[templ->target];
55
56 if (templ->target == PIPE_BUFFER) {
57 switch (templ->bind) {
58 case PIPE_BIND_VERTEX_BUFFER:
59 name = "buf-vb";
60 break;
61 case PIPE_BIND_INDEX_BUFFER:
62 name = "buf-ib";
63 break;
64 case PIPE_BIND_CONSTANT_BUFFER:
65 name = "buf-cb";
66 break;
67 case PIPE_BIND_STREAM_OUTPUT:
68 name = "buf-so";
69 break;
70 default:
71 break;
72 }
73 }
74
75 return name;
76 }
77
78 static bool
79 resource_get_cpu_init(const struct pipe_resource *templ)
80 {
81 return (templ->bind & (PIPE_BIND_DEPTH_STENCIL |
82 PIPE_BIND_RENDER_TARGET |
83 PIPE_BIND_STREAM_OUTPUT)) ? false : true;
84 }
85
86 static enum gen_surface_tiling
87 winsys_to_surface_tiling(enum intel_tiling_mode tiling)
88 {
89 switch (tiling) {
90 case INTEL_TILING_NONE:
91 return GEN6_TILING_NONE;
92 case INTEL_TILING_X:
93 return GEN6_TILING_X;
94 case INTEL_TILING_Y:
95 return GEN6_TILING_Y;
96 default:
97 assert(!"unknown tiling");
98 return GEN6_TILING_NONE;
99 }
100 }
101
102 static inline enum intel_tiling_mode
103 surface_to_winsys_tiling(enum gen_surface_tiling tiling)
104 {
105 switch (tiling) {
106 case GEN6_TILING_NONE:
107 return INTEL_TILING_NONE;
108 case GEN6_TILING_X:
109 return INTEL_TILING_X;
110 case GEN6_TILING_Y:
111 return INTEL_TILING_Y;
112 default:
113 assert(!"unknown tiling");
114 return GEN6_TILING_NONE;
115 }
116 }
117
118 static void
119 tex_free_slices(struct ilo_texture *tex)
120 {
121 FREE(tex->slices[0]);
122 }
123
124 static bool
125 tex_alloc_slices(struct ilo_texture *tex)
126 {
127 const struct pipe_resource *templ = &tex->base;
128 struct ilo_texture_slice *slices;
129 int depth, lv;
130
131 /* sum the depths of all levels */
132 depth = 0;
133 for (lv = 0; lv <= templ->last_level; lv++)
134 depth += u_minify(templ->depth0, lv);
135
136 /*
137 * There are (depth * tex->base.array_size) slices in total. Either depth
138 * is one (non-3D) or templ->array_size is one (non-array), but it does
139 * not matter.
140 */
141 slices = CALLOC(depth * templ->array_size, sizeof(*slices));
142 if (!slices)
143 return false;
144
145 tex->slices[0] = slices;
146
147 /* point to the respective positions in the buffer */
148 for (lv = 1; lv <= templ->last_level; lv++) {
149 tex->slices[lv] = tex->slices[lv - 1] +
150 u_minify(templ->depth0, lv - 1) * templ->array_size;
151 }
152
153 return true;
154 }
155
156 static bool
157 tex_create_bo(struct ilo_texture *tex)
158 {
159 struct ilo_screen *is = ilo_screen(tex->base.screen);
160 const char *name = resource_get_bo_name(&tex->base);
161 const bool cpu_init = resource_get_cpu_init(&tex->base);
162 struct intel_bo *bo;
163
164 bo = intel_winsys_alloc_bo(is->dev.winsys, name,
165 tex->image.bo_stride * tex->image.bo_height, cpu_init);
166
167 /* set the tiling for transfer and export */
168 if (bo && (tex->image.tiling == GEN6_TILING_X ||
169 tex->image.tiling == GEN6_TILING_Y)) {
170 const enum intel_tiling_mode tiling =
171 surface_to_winsys_tiling(tex->image.tiling);
172
173 if (intel_bo_set_tiling(bo, tiling, tex->image.bo_stride)) {
174 intel_bo_unref(bo);
175 bo = NULL;
176 }
177 }
178 if (!bo)
179 return false;
180
181 ilo_image_set_bo(&tex->image, bo);
182 intel_bo_unref(bo);
183
184 return true;
185 }
186
187 static bool
188 tex_create_separate_stencil(struct ilo_texture *tex)
189 {
190 struct pipe_resource templ = tex->base;
191 struct pipe_resource *s8;
192
193 /*
194 * Unless PIPE_BIND_DEPTH_STENCIL is set, the resource may have other
195 * tilings. But that should be fine since it will never be bound as the
196 * stencil buffer, and our transfer code can handle all tilings.
197 */
198 templ.format = PIPE_FORMAT_S8_UINT;
199
200 /* no stencil texturing */
201 templ.bind &= ~PIPE_BIND_SAMPLER_VIEW;
202
203 s8 = tex->base.screen->resource_create(tex->base.screen, &templ);
204 if (!s8)
205 return false;
206
207 tex->separate_s8 = ilo_texture(s8);
208
209 assert(tex->separate_s8->image.format == PIPE_FORMAT_S8_UINT);
210
211 return true;
212 }
213
214 static bool
215 tex_create_hiz(struct ilo_texture *tex)
216 {
217 const struct pipe_resource *templ = &tex->base;
218 struct ilo_screen *is = ilo_screen(tex->base.screen);
219 struct intel_bo *bo;
220 unsigned lv;
221
222 bo = intel_winsys_alloc_bo(is->dev.winsys, "hiz texture",
223 tex->image.aux.bo_stride * tex->image.aux.bo_height, false);
224 if (!bo)
225 return false;
226
227 ilo_image_set_aux_bo(&tex->image, bo);
228
229 for (lv = 0; lv <= templ->last_level; lv++) {
230 if (tex->image.aux.enables & (1 << lv)) {
231 const unsigned num_slices = (templ->target == PIPE_TEXTURE_3D) ?
232 u_minify(templ->depth0, lv) : templ->array_size;
233 unsigned flags = ILO_TEXTURE_HIZ;
234
235 /* this will trigger a HiZ resolve */
236 if (tex->imported)
237 flags |= ILO_TEXTURE_CPU_WRITE;
238
239 ilo_texture_set_slice_flags(tex, lv, 0, num_slices, flags, flags);
240 }
241 }
242
243 return true;
244 }
245
246 static bool
247 tex_create_mcs(struct ilo_texture *tex)
248 {
249 struct ilo_screen *is = ilo_screen(tex->base.screen);
250 struct intel_bo *bo;
251
252 assert(tex->image.aux.enables == (1 << (tex->base.last_level + 1)) - 1);
253
254 bo = intel_winsys_alloc_bo(is->dev.winsys, "mcs texture",
255 tex->image.aux.bo_stride * tex->image.aux.bo_height, false);
256 if (!bo)
257 return false;
258
259 ilo_image_set_aux_bo(&tex->image, bo);
260
261 return true;
262 }
263
264 static void
265 tex_destroy(struct ilo_texture *tex)
266 {
267 if (tex->separate_s8)
268 tex_destroy(tex->separate_s8);
269
270 ilo_image_cleanup(&tex->image);
271
272 tex_free_slices(tex);
273 FREE(tex);
274 }
275
276 static bool
277 tex_alloc_bos(struct ilo_texture *tex)
278 {
279 struct ilo_screen *is = ilo_screen(tex->base.screen);
280
281 if (!tex->imported && !tex_create_bo(tex))
282 return false;
283
284 /* allocate separate stencil resource */
285 if (tex->image.separate_stencil && !tex_create_separate_stencil(tex))
286 return false;
287
288 switch (tex->image.aux.type) {
289 case ILO_IMAGE_AUX_HIZ:
290 if (!tex_create_hiz(tex)) {
291 /* Separate Stencil Buffer requires HiZ to be enabled */
292 if (ilo_dev_gen(&is->dev) == ILO_GEN(6) &&
293 tex->image.separate_stencil)
294 return false;
295 }
296 break;
297 case ILO_IMAGE_AUX_MCS:
298 if (!tex_create_mcs(tex))
299 return false;
300 break;
301 default:
302 break;
303 }
304
305 return true;
306 }
307
308 static bool
309 tex_import_handle(struct ilo_texture *tex,
310 const struct winsys_handle *handle)
311 {
312 struct ilo_screen *is = ilo_screen(tex->base.screen);
313 const struct pipe_resource *templ = &tex->base;
314 const char *name = resource_get_bo_name(&tex->base);
315 enum intel_tiling_mode tiling;
316 unsigned long pitch;
317 struct intel_bo *bo;
318
319 bo = intel_winsys_import_handle(is->dev.winsys, name, handle,
320 tex->image.bo_height, &tiling, &pitch);
321 if (!bo)
322 return false;
323
324 if (!ilo_image_init_for_imported(&tex->image, &is->dev, templ,
325 winsys_to_surface_tiling(tiling), pitch)) {
326 ilo_err("failed to import handle for texture\n");
327 intel_bo_unref(bo);
328 return false;
329 }
330
331 ilo_image_set_bo(&tex->image, bo);
332 intel_bo_unref(bo);
333
334 tex->imported = true;
335
336 return true;
337 }
338
339 static bool
340 tex_init_image(struct ilo_texture *tex,
341 const struct winsys_handle *handle)
342 {
343 struct ilo_screen *is = ilo_screen(tex->base.screen);
344 const struct pipe_resource *templ = &tex->base;
345 struct ilo_image *img = &tex->image;
346
347 if (handle) {
348 if (!tex_import_handle(tex, handle))
349 return false;
350 } else {
351 ilo_image_init(img, &is->dev, templ);
352 }
353
354 if (img->bo_height > ilo_max_resource_size / img->bo_stride)
355 return false;
356
357 if (templ->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) {
358 /* require on-the-fly tiling/untiling or format conversion */
359 if (img->tiling == GEN8_TILING_W || img->separate_stencil ||
360 img->format != templ->format)
361 return false;
362 }
363
364 if (!tex_alloc_slices(tex))
365 return false;
366
367 return true;
368 }
369
370 static struct pipe_resource *
371 tex_create(struct pipe_screen *screen,
372 const struct pipe_resource *templ,
373 const struct winsys_handle *handle)
374 {
375 struct ilo_texture *tex;
376
377 tex = CALLOC_STRUCT(ilo_texture);
378 if (!tex)
379 return NULL;
380
381 tex->base = *templ;
382 tex->base.screen = screen;
383 pipe_reference_init(&tex->base.reference, 1);
384
385 if (!tex_init_image(tex, handle)) {
386 FREE(tex);
387 return NULL;
388 }
389
390 if (!tex_alloc_bos(tex)) {
391 tex_destroy(tex);
392 return NULL;
393 }
394
395 return &tex->base;
396 }
397
398 static bool
399 tex_get_handle(struct ilo_texture *tex, struct winsys_handle *handle)
400 {
401 struct ilo_screen *is = ilo_screen(tex->base.screen);
402 enum intel_tiling_mode tiling;
403 int err;
404
405 /* must match what tex_create_bo() sets */
406 if (tex->image.tiling == GEN8_TILING_W)
407 tiling = INTEL_TILING_NONE;
408 else
409 tiling = surface_to_winsys_tiling(tex->image.tiling);
410
411 err = intel_winsys_export_handle(is->dev.winsys, tex->image.bo, tiling,
412 tex->image.bo_stride, tex->image.bo_height, handle);
413
414 return !err;
415 }
416
417 static bool
418 buf_create_bo(struct ilo_buffer_resource *buf)
419 {
420 struct ilo_screen *is = ilo_screen(buf->base.screen);
421 const char *name = resource_get_bo_name(&buf->base);
422 const bool cpu_init = resource_get_cpu_init(&buf->base);
423 struct intel_bo *bo;
424
425 bo = intel_winsys_alloc_bo(is->dev.winsys, name,
426 buf->buffer.bo_size, cpu_init);
427 if (!bo)
428 return false;
429
430 ilo_buffer_set_bo(&buf->buffer, bo);
431 intel_bo_unref(bo);
432
433 return true;
434 }
435
436 static void
437 buf_destroy(struct ilo_buffer_resource *buf)
438 {
439 ilo_buffer_cleanup(&buf->buffer);
440 FREE(buf);
441 }
442
443 static struct pipe_resource *
444 buf_create(struct pipe_screen *screen, const struct pipe_resource *templ)
445 {
446 const struct ilo_screen *is = ilo_screen(screen);
447 struct ilo_buffer_resource *buf;
448
449 buf = CALLOC_STRUCT(ilo_buffer_resource);
450 if (!buf)
451 return NULL;
452
453 buf->base = *templ;
454 buf->base.screen = screen;
455 pipe_reference_init(&buf->base.reference, 1);
456
457 ilo_buffer_init(&buf->buffer, &is->dev,
458 templ->width0, templ->bind, templ->flags);
459
460 if (buf->buffer.bo_size < templ->width0 ||
461 buf->buffer.bo_size > ilo_max_resource_size ||
462 !buf_create_bo(buf)) {
463 FREE(buf);
464 return NULL;
465 }
466
467 return &buf->base;
468 }
469
470 static boolean
471 ilo_can_create_resource(struct pipe_screen *screen,
472 const struct pipe_resource *templ)
473 {
474 struct ilo_image img;
475
476 if (templ->target == PIPE_BUFFER)
477 return (templ->width0 <= ilo_max_resource_size);
478
479 memset(&img, 0, sizeof(img));
480 ilo_image_init(&img, &ilo_screen(screen)->dev, templ);
481
482 return (img.bo_height <= ilo_max_resource_size / img.bo_stride);
483 }
484
485 static struct pipe_resource *
486 ilo_resource_create(struct pipe_screen *screen,
487 const struct pipe_resource *templ)
488 {
489 if (templ->target == PIPE_BUFFER)
490 return buf_create(screen, templ);
491 else
492 return tex_create(screen, templ, NULL);
493 }
494
495 static struct pipe_resource *
496 ilo_resource_from_handle(struct pipe_screen *screen,
497 const struct pipe_resource *templ,
498 struct winsys_handle *handle)
499 {
500 if (templ->target == PIPE_BUFFER)
501 return NULL;
502 else
503 return tex_create(screen, templ, handle);
504 }
505
506 static boolean
507 ilo_resource_get_handle(struct pipe_screen *screen,
508 struct pipe_resource *res,
509 struct winsys_handle *handle)
510 {
511 if (res->target == PIPE_BUFFER)
512 return false;
513 else
514 return tex_get_handle(ilo_texture(res), handle);
515
516 }
517
518 static void
519 ilo_resource_destroy(struct pipe_screen *screen,
520 struct pipe_resource *res)
521 {
522 if (res->target == PIPE_BUFFER)
523 buf_destroy((struct ilo_buffer_resource *) res);
524 else
525 tex_destroy(ilo_texture(res));
526 }
527
528 /**
529 * Initialize resource-related functions.
530 */
531 void
532 ilo_init_resource_functions(struct ilo_screen *is)
533 {
534 is->base.can_create_resource = ilo_can_create_resource;
535 is->base.resource_create = ilo_resource_create;
536 is->base.resource_from_handle = ilo_resource_from_handle;
537 is->base.resource_get_handle = ilo_resource_get_handle;
538 is->base.resource_destroy = ilo_resource_destroy;
539 }
540
541 bool
542 ilo_resource_rename_bo(struct pipe_resource *res)
543 {
544 if (res->target == PIPE_BUFFER) {
545 return buf_create_bo((struct ilo_buffer_resource *) res);
546 } else {
547 struct ilo_texture *tex = ilo_texture(res);
548
549 /* an imported texture cannot be renamed */
550 if (tex->imported)
551 return false;
552
553 return tex_create_bo(tex);
554 }
555 }