ilo: remove ilo_image_disable_aux()
[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 "core/ilo_state_vf.h"
29 #include "core/ilo_state_sol.h"
30 #include "core/ilo_state_surface.h"
31
32 #include "ilo_screen.h"
33 #include "ilo_resource.h"
34
35 /*
36 * From the Ivy Bridge PRM, volume 1 part 1, page 105:
37 *
38 * "In addition to restrictions on maximum height, width, and depth,
39 * surfaces are also restricted to a maximum size in bytes. This
40 * maximum is 2 GB for all products and all surface types."
41 */
42 static const size_t ilo_max_resource_size = 1u << 31;
43
44 static const char *
45 resource_get_bo_name(const struct pipe_resource *templ)
46 {
47 static const char *target_names[PIPE_MAX_TEXTURE_TYPES] = {
48 [PIPE_BUFFER] = "buf",
49 [PIPE_TEXTURE_1D] = "tex-1d",
50 [PIPE_TEXTURE_2D] = "tex-2d",
51 [PIPE_TEXTURE_3D] = "tex-3d",
52 [PIPE_TEXTURE_CUBE] = "tex-cube",
53 [PIPE_TEXTURE_RECT] = "tex-rect",
54 [PIPE_TEXTURE_1D_ARRAY] = "tex-1d-array",
55 [PIPE_TEXTURE_2D_ARRAY] = "tex-2d-array",
56 [PIPE_TEXTURE_CUBE_ARRAY] = "tex-cube-array",
57 };
58 const char *name = target_names[templ->target];
59
60 if (templ->target == PIPE_BUFFER) {
61 switch (templ->bind) {
62 case PIPE_BIND_VERTEX_BUFFER:
63 name = "buf-vb";
64 break;
65 case PIPE_BIND_INDEX_BUFFER:
66 name = "buf-ib";
67 break;
68 case PIPE_BIND_CONSTANT_BUFFER:
69 name = "buf-cb";
70 break;
71 case PIPE_BIND_STREAM_OUTPUT:
72 name = "buf-so";
73 break;
74 default:
75 break;
76 }
77 }
78
79 return name;
80 }
81
82 static bool
83 resource_get_cpu_init(const struct pipe_resource *templ)
84 {
85 return (templ->bind & (PIPE_BIND_DEPTH_STENCIL |
86 PIPE_BIND_RENDER_TARGET |
87 PIPE_BIND_STREAM_OUTPUT)) ? false : true;
88 }
89
90 static enum gen_surface_tiling
91 winsys_to_surface_tiling(enum intel_tiling_mode tiling)
92 {
93 switch (tiling) {
94 case INTEL_TILING_NONE:
95 return GEN6_TILING_NONE;
96 case INTEL_TILING_X:
97 return GEN6_TILING_X;
98 case INTEL_TILING_Y:
99 return GEN6_TILING_Y;
100 default:
101 assert(!"unknown tiling");
102 return GEN6_TILING_NONE;
103 }
104 }
105
106 static inline enum intel_tiling_mode
107 surface_to_winsys_tiling(enum gen_surface_tiling tiling)
108 {
109 switch (tiling) {
110 case GEN6_TILING_NONE:
111 return INTEL_TILING_NONE;
112 case GEN6_TILING_X:
113 return INTEL_TILING_X;
114 case GEN6_TILING_Y:
115 return INTEL_TILING_Y;
116 default:
117 assert(!"unknown tiling");
118 return GEN6_TILING_NONE;
119 }
120 }
121
122 static void
123 tex_free_slices(struct ilo_texture *tex)
124 {
125 FREE(tex->slices[0]);
126 }
127
128 static bool
129 tex_alloc_slices(struct ilo_texture *tex)
130 {
131 const struct pipe_resource *templ = &tex->base;
132 struct ilo_texture_slice *slices;
133 int depth, lv;
134
135 /* sum the depths of all levels */
136 depth = 0;
137 for (lv = 0; lv <= templ->last_level; lv++)
138 depth += u_minify(templ->depth0, lv);
139
140 /*
141 * There are (depth * tex->base.array_size) slices in total. Either depth
142 * is one (non-3D) or templ->array_size is one (non-array), but it does
143 * not matter.
144 */
145 slices = CALLOC(depth * templ->array_size, sizeof(*slices));
146 if (!slices)
147 return false;
148
149 tex->slices[0] = slices;
150
151 /* point to the respective positions in the buffer */
152 for (lv = 1; lv <= templ->last_level; lv++) {
153 tex->slices[lv] = tex->slices[lv - 1] +
154 u_minify(templ->depth0, lv - 1) * templ->array_size;
155 }
156
157 return true;
158 }
159
160 static bool
161 tex_create_bo(struct ilo_texture *tex)
162 {
163 struct ilo_screen *is = ilo_screen(tex->base.screen);
164 const char *name = resource_get_bo_name(&tex->base);
165 const bool cpu_init = resource_get_cpu_init(&tex->base);
166 struct intel_bo *bo;
167
168 bo = intel_winsys_alloc_bo(is->dev.winsys, name,
169 tex->image.bo_stride * tex->image.bo_height, cpu_init);
170
171 /* set the tiling for transfer and export */
172 if (bo && (tex->image.tiling == GEN6_TILING_X ||
173 tex->image.tiling == GEN6_TILING_Y)) {
174 const enum intel_tiling_mode tiling =
175 surface_to_winsys_tiling(tex->image.tiling);
176
177 if (intel_bo_set_tiling(bo, tiling, tex->image.bo_stride)) {
178 intel_bo_unref(bo);
179 bo = NULL;
180 }
181 }
182 if (!bo)
183 return false;
184
185 intel_bo_unref(tex->vma.bo);
186 ilo_vma_set_bo(&tex->vma, &is->dev, bo, 0);
187
188 return true;
189 }
190
191 static bool
192 tex_create_separate_stencil(struct ilo_texture *tex)
193 {
194 struct pipe_resource templ = tex->base;
195 struct pipe_resource *s8;
196
197 /*
198 * Unless PIPE_BIND_DEPTH_STENCIL is set, the resource may have other
199 * tilings. But that should be fine since it will never be bound as the
200 * stencil buffer, and our transfer code can handle all tilings.
201 */
202 templ.format = PIPE_FORMAT_S8_UINT;
203
204 /* no stencil texturing */
205 templ.bind &= ~PIPE_BIND_SAMPLER_VIEW;
206
207 s8 = tex->base.screen->resource_create(tex->base.screen, &templ);
208 if (!s8)
209 return false;
210
211 tex->separate_s8 = ilo_texture(s8);
212
213 assert(tex->separate_s8->image.format == PIPE_FORMAT_S8_UINT);
214
215 return true;
216 }
217
218 static bool
219 tex_create_hiz(struct ilo_texture *tex)
220 {
221 const struct pipe_resource *templ = &tex->base;
222 const uint32_t size = tex->image.aux.bo_stride * tex->image.aux.bo_height;
223 struct ilo_screen *is = ilo_screen(tex->base.screen);
224 struct intel_bo *bo;
225
226 bo = intel_winsys_alloc_bo(is->dev.winsys, "hiz texture", size, false);
227 if (!bo)
228 return false;
229
230 ilo_vma_init(&tex->aux_vma, &is->dev, size, 4096);
231 ilo_vma_set_bo(&tex->aux_vma, &is->dev, bo, 0);
232
233 if (tex->imported) {
234 unsigned lv;
235
236 for (lv = 0; lv <= templ->last_level; lv++) {
237 if (tex->image.aux.enables & (1 << lv)) {
238 const unsigned num_slices = (templ->target == PIPE_TEXTURE_3D) ?
239 u_minify(templ->depth0, lv) : templ->array_size;
240 /* this will trigger HiZ resolves */
241 const unsigned flags = ILO_TEXTURE_CPU_WRITE;
242
243 ilo_texture_set_slice_flags(tex, lv, 0, num_slices, flags, flags);
244 }
245 }
246 }
247
248 return true;
249 }
250
251 static bool
252 tex_create_mcs(struct ilo_texture *tex)
253 {
254 const uint32_t size = tex->image.aux.bo_stride * tex->image.aux.bo_height;
255 struct ilo_screen *is = ilo_screen(tex->base.screen);
256 struct intel_bo *bo;
257
258 assert(tex->image.aux.enables == (1 << (tex->base.last_level + 1)) - 1);
259
260 bo = intel_winsys_alloc_bo(is->dev.winsys, "mcs texture", size, false);
261 if (!bo)
262 return false;
263
264 ilo_vma_init(&tex->aux_vma, &is->dev, size, 4096);
265 ilo_vma_set_bo(&tex->aux_vma, &is->dev, bo, 0);
266
267 return true;
268 }
269
270 static void
271 tex_destroy(struct ilo_texture *tex)
272 {
273 if (tex->separate_s8)
274 tex_destroy(tex->separate_s8);
275
276 intel_bo_unref(tex->vma.bo);
277 intel_bo_unref(tex->aux_vma.bo);
278
279 tex_free_slices(tex);
280 FREE(tex);
281 }
282
283 static bool
284 tex_alloc_bos(struct ilo_texture *tex)
285 {
286 if (!tex->imported && !tex_create_bo(tex))
287 return false;
288
289 /* allocate separate stencil resource */
290 if (tex->image.separate_stencil && !tex_create_separate_stencil(tex))
291 return false;
292
293 switch (tex->image.aux.type) {
294 case ILO_IMAGE_AUX_HIZ:
295 if (!tex_create_hiz(tex))
296 return false;
297 break;
298 case ILO_IMAGE_AUX_MCS:
299 if (!tex_create_mcs(tex))
300 return false;
301 break;
302 default:
303 break;
304 }
305
306 return true;
307 }
308
309 static bool
310 tex_import_handle(struct ilo_texture *tex,
311 const struct winsys_handle *handle)
312 {
313 struct ilo_screen *is = ilo_screen(tex->base.screen);
314 const struct pipe_resource *templ = &tex->base;
315 const char *name = resource_get_bo_name(&tex->base);
316 enum intel_tiling_mode tiling;
317 unsigned long pitch;
318 struct intel_bo *bo;
319
320 bo = intel_winsys_import_handle(is->dev.winsys, name, handle,
321 tex->image.bo_height, &tiling, &pitch);
322 if (!bo)
323 return false;
324
325 if (!ilo_image_init_for_imported(&tex->image, &is->dev, templ,
326 winsys_to_surface_tiling(tiling), pitch)) {
327 ilo_err("failed to import handle for texture\n");
328 intel_bo_unref(bo);
329 return false;
330 }
331
332 ilo_vma_init(&tex->vma, &is->dev,
333 tex->image.bo_stride * tex->image.bo_height, 4096);
334 ilo_vma_set_bo(&tex->vma, &is->dev, bo, 0);
335
336 tex->imported = true;
337
338 return true;
339 }
340
341 static bool
342 tex_init_image(struct ilo_texture *tex,
343 const struct winsys_handle *handle)
344 {
345 struct ilo_screen *is = ilo_screen(tex->base.screen);
346 const struct pipe_resource *templ = &tex->base;
347 struct ilo_image *img = &tex->image;
348
349 if (handle) {
350 if (!tex_import_handle(tex, handle))
351 return false;
352 } else {
353 ilo_image_init(img, &is->dev, templ);
354 ilo_vma_init(&tex->vma, &is->dev,
355 img->bo_stride * img->bo_height, 4096);
356 }
357
358 if (img->bo_height > ilo_max_resource_size / img->bo_stride)
359 return false;
360
361 if (templ->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) {
362 /* require on-the-fly tiling/untiling or format conversion */
363 if (img->tiling == GEN8_TILING_W || img->separate_stencil ||
364 img->format != templ->format)
365 return false;
366 }
367
368 if (!tex_alloc_slices(tex))
369 return false;
370
371 return true;
372 }
373
374 static struct pipe_resource *
375 tex_create(struct pipe_screen *screen,
376 const struct pipe_resource *templ,
377 const struct winsys_handle *handle)
378 {
379 struct ilo_texture *tex;
380
381 tex = CALLOC_STRUCT(ilo_texture);
382 if (!tex)
383 return NULL;
384
385 tex->base = *templ;
386 tex->base.screen = screen;
387 pipe_reference_init(&tex->base.reference, 1);
388
389 if (!tex_init_image(tex, handle)) {
390 FREE(tex);
391 return NULL;
392 }
393
394 if (!tex_alloc_bos(tex)) {
395 tex_destroy(tex);
396 return NULL;
397 }
398
399 return &tex->base;
400 }
401
402 static bool
403 tex_get_handle(struct ilo_texture *tex, struct winsys_handle *handle)
404 {
405 struct ilo_screen *is = ilo_screen(tex->base.screen);
406 enum intel_tiling_mode tiling;
407 int err;
408
409 /* must match what tex_create_bo() sets */
410 if (tex->image.tiling == GEN8_TILING_W)
411 tiling = INTEL_TILING_NONE;
412 else
413 tiling = surface_to_winsys_tiling(tex->image.tiling);
414
415 err = intel_winsys_export_handle(is->dev.winsys, tex->vma.bo, tiling,
416 tex->image.bo_stride, tex->image.bo_height, handle);
417
418 return !err;
419 }
420
421 static bool
422 buf_create_bo(struct ilo_buffer_resource *buf)
423 {
424 struct ilo_screen *is = ilo_screen(buf->base.screen);
425 const char *name = resource_get_bo_name(&buf->base);
426 const bool cpu_init = resource_get_cpu_init(&buf->base);
427 struct intel_bo *bo;
428
429 bo = intel_winsys_alloc_bo(is->dev.winsys, name, buf->bo_size, cpu_init);
430 if (!bo)
431 return false;
432
433 intel_bo_unref(buf->vma.bo);
434 ilo_vma_set_bo(&buf->vma, &is->dev, bo, 0);
435
436 return true;
437 }
438
439 static void
440 buf_destroy(struct ilo_buffer_resource *buf)
441 {
442 intel_bo_unref(buf->vma.bo);
443 FREE(buf);
444 }
445
446 static struct pipe_resource *
447 buf_create(struct pipe_screen *screen, const struct pipe_resource *templ)
448 {
449 const struct ilo_screen *is = ilo_screen(screen);
450 struct ilo_buffer_resource *buf;
451 uint32_t alignment;
452 unsigned size;
453
454 buf = CALLOC_STRUCT(ilo_buffer_resource);
455 if (!buf)
456 return NULL;
457
458 buf->base = *templ;
459 buf->base.screen = screen;
460 pipe_reference_init(&buf->base.reference, 1);
461
462 size = templ->width0;
463
464 /*
465 * As noted in ilo_format_translate(), we treat some 3-component formats as
466 * 4-component formats to work around hardware limitations. Imagine the
467 * case where the vertex buffer holds a single PIPE_FORMAT_R16G16B16_FLOAT
468 * vertex, and buf->bo_size is 6. The hardware would fail to fetch it at
469 * boundary check because the vertex buffer is expected to hold a
470 * PIPE_FORMAT_R16G16B16A16_FLOAT vertex and that takes at least 8 bytes.
471 *
472 * For the workaround to work, we should add 2 to the bo size. But that
473 * would waste a page when the bo size is already page aligned. Let's
474 * round it to page size for now and revisit this when needed.
475 */
476 if ((templ->bind & PIPE_BIND_VERTEX_BUFFER) &&
477 ilo_dev_gen(&is->dev) < ILO_GEN(7.5))
478 size = align(size, 4096);
479
480 if (templ->bind & PIPE_BIND_VERTEX_BUFFER)
481 size = ilo_state_vertex_buffer_size(&is->dev, size, &alignment);
482 if (templ->bind & PIPE_BIND_INDEX_BUFFER)
483 size = ilo_state_index_buffer_size(&is->dev, size, &alignment);
484 if (templ->bind & PIPE_BIND_STREAM_OUTPUT)
485 size = ilo_state_sol_buffer_size(&is->dev, size, &alignment);
486
487 buf->bo_size = size;
488 ilo_vma_init(&buf->vma, &is->dev, buf->bo_size, 4096);
489
490 if (buf->bo_size < templ->width0 || buf->bo_size > ilo_max_resource_size ||
491 !buf_create_bo(buf)) {
492 FREE(buf);
493 return NULL;
494 }
495
496 return &buf->base;
497 }
498
499 static boolean
500 ilo_can_create_resource(struct pipe_screen *screen,
501 const struct pipe_resource *templ)
502 {
503 struct ilo_image img;
504
505 if (templ->target == PIPE_BUFFER)
506 return (templ->width0 <= ilo_max_resource_size);
507
508 memset(&img, 0, sizeof(img));
509 ilo_image_init(&img, &ilo_screen(screen)->dev, templ);
510
511 return (img.bo_height <= ilo_max_resource_size / img.bo_stride);
512 }
513
514 static struct pipe_resource *
515 ilo_resource_create(struct pipe_screen *screen,
516 const struct pipe_resource *templ)
517 {
518 if (templ->target == PIPE_BUFFER)
519 return buf_create(screen, templ);
520 else
521 return tex_create(screen, templ, NULL);
522 }
523
524 static struct pipe_resource *
525 ilo_resource_from_handle(struct pipe_screen *screen,
526 const struct pipe_resource *templ,
527 struct winsys_handle *handle)
528 {
529 if (templ->target == PIPE_BUFFER)
530 return NULL;
531 else
532 return tex_create(screen, templ, handle);
533 }
534
535 static boolean
536 ilo_resource_get_handle(struct pipe_screen *screen,
537 struct pipe_resource *res,
538 struct winsys_handle *handle)
539 {
540 if (res->target == PIPE_BUFFER)
541 return false;
542 else
543 return tex_get_handle(ilo_texture(res), handle);
544
545 }
546
547 static void
548 ilo_resource_destroy(struct pipe_screen *screen,
549 struct pipe_resource *res)
550 {
551 if (res->target == PIPE_BUFFER)
552 buf_destroy((struct ilo_buffer_resource *) res);
553 else
554 tex_destroy(ilo_texture(res));
555 }
556
557 /**
558 * Initialize resource-related functions.
559 */
560 void
561 ilo_init_resource_functions(struct ilo_screen *is)
562 {
563 is->base.can_create_resource = ilo_can_create_resource;
564 is->base.resource_create = ilo_resource_create;
565 is->base.resource_from_handle = ilo_resource_from_handle;
566 is->base.resource_get_handle = ilo_resource_get_handle;
567 is->base.resource_destroy = ilo_resource_destroy;
568 }
569
570 bool
571 ilo_resource_rename_bo(struct pipe_resource *res)
572 {
573 if (res->target == PIPE_BUFFER) {
574 return buf_create_bo((struct ilo_buffer_resource *) res);
575 } else {
576 struct ilo_texture *tex = ilo_texture(res);
577
578 /* an imported texture cannot be renamed */
579 if (tex->imported)
580 return false;
581
582 return tex_create_bo(tex);
583 }
584 }