ilo: add 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 "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 intel_bo_unref(tex->image.bo);
182 tex->image.bo = 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
221 bo = intel_winsys_alloc_bo(is->dev.winsys, "hiz texture",
222 tex->image.aux.bo_stride * tex->image.aux.bo_height, false);
223 if (!bo)
224 return false;
225
226 tex->image.aux.bo = bo;
227
228 if (tex->imported) {
229 unsigned lv;
230
231 for (lv = 0; lv <= templ->last_level; lv++) {
232 if (tex->image.aux.enables & (1 << lv)) {
233 const unsigned num_slices = (templ->target == PIPE_TEXTURE_3D) ?
234 u_minify(templ->depth0, lv) : templ->array_size;
235 /* this will trigger HiZ resolves */
236 const unsigned flags = ILO_TEXTURE_CPU_WRITE;
237
238 ilo_texture_set_slice_flags(tex, lv, 0, num_slices, flags, flags);
239 }
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 tex->image.aux.bo = 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 intel_bo_unref(tex->image.bo);
271 intel_bo_unref(tex->image.aux.bo);
272
273 tex_free_slices(tex);
274 FREE(tex);
275 }
276
277 static bool
278 tex_alloc_bos(struct ilo_texture *tex)
279 {
280 struct ilo_screen *is = ilo_screen(tex->base.screen);
281
282 if (!tex->imported && !tex_create_bo(tex))
283 return false;
284
285 /* allocate separate stencil resource */
286 if (tex->image.separate_stencil && !tex_create_separate_stencil(tex))
287 return false;
288
289 switch (tex->image.aux.type) {
290 case ILO_IMAGE_AUX_HIZ:
291 if (!tex_create_hiz(tex) &&
292 !ilo_image_disable_aux(&tex->image, &is->dev))
293 return false;
294 break;
295 case ILO_IMAGE_AUX_MCS:
296 if (!tex_create_mcs(tex) &&
297 !ilo_image_disable_aux(&tex->image, &is->dev))
298 return false;
299 break;
300 default:
301 break;
302 }
303
304 return true;
305 }
306
307 static bool
308 tex_import_handle(struct ilo_texture *tex,
309 const struct winsys_handle *handle)
310 {
311 struct ilo_screen *is = ilo_screen(tex->base.screen);
312 const struct pipe_resource *templ = &tex->base;
313 const char *name = resource_get_bo_name(&tex->base);
314 enum intel_tiling_mode tiling;
315 unsigned long pitch;
316 struct intel_bo *bo;
317
318 bo = intel_winsys_import_handle(is->dev.winsys, name, handle,
319 tex->image.bo_height, &tiling, &pitch);
320 if (!bo)
321 return false;
322
323 if (!ilo_image_init_for_imported(&tex->image, &is->dev, templ,
324 winsys_to_surface_tiling(tiling), pitch)) {
325 ilo_err("failed to import handle for texture\n");
326 intel_bo_unref(bo);
327 return false;
328 }
329
330 tex->image.bo = bo;
331
332 tex->imported = true;
333
334 return true;
335 }
336
337 static bool
338 tex_init_image(struct ilo_texture *tex,
339 const struct winsys_handle *handle)
340 {
341 struct ilo_screen *is = ilo_screen(tex->base.screen);
342 const struct pipe_resource *templ = &tex->base;
343 struct ilo_image *img = &tex->image;
344
345 if (handle) {
346 if (!tex_import_handle(tex, handle))
347 return false;
348 } else {
349 ilo_image_init(img, &is->dev, templ);
350 }
351
352 if (img->bo_height > ilo_max_resource_size / img->bo_stride)
353 return false;
354
355 if (templ->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) {
356 /* require on-the-fly tiling/untiling or format conversion */
357 if (img->tiling == GEN8_TILING_W || img->separate_stencil ||
358 img->format != templ->format)
359 return false;
360 }
361
362 if (!tex_alloc_slices(tex))
363 return false;
364
365 return true;
366 }
367
368 static struct pipe_resource *
369 tex_create(struct pipe_screen *screen,
370 const struct pipe_resource *templ,
371 const struct winsys_handle *handle)
372 {
373 struct ilo_texture *tex;
374
375 tex = CALLOC_STRUCT(ilo_texture);
376 if (!tex)
377 return NULL;
378
379 tex->base = *templ;
380 tex->base.screen = screen;
381 pipe_reference_init(&tex->base.reference, 1);
382
383 if (!tex_init_image(tex, handle)) {
384 FREE(tex);
385 return NULL;
386 }
387
388 if (!tex_alloc_bos(tex)) {
389 tex_destroy(tex);
390 return NULL;
391 }
392
393 return &tex->base;
394 }
395
396 static bool
397 tex_get_handle(struct ilo_texture *tex, struct winsys_handle *handle)
398 {
399 struct ilo_screen *is = ilo_screen(tex->base.screen);
400 enum intel_tiling_mode tiling;
401 int err;
402
403 /* must match what tex_create_bo() sets */
404 if (tex->image.tiling == GEN8_TILING_W)
405 tiling = INTEL_TILING_NONE;
406 else
407 tiling = surface_to_winsys_tiling(tex->image.tiling);
408
409 err = intel_winsys_export_handle(is->dev.winsys, tex->image.bo, tiling,
410 tex->image.bo_stride, tex->image.bo_height, handle);
411
412 return !err;
413 }
414
415 static bool
416 buf_create_bo(struct ilo_buffer_resource *buf)
417 {
418 struct ilo_screen *is = ilo_screen(buf->base.screen);
419 const char *name = resource_get_bo_name(&buf->base);
420 const bool cpu_init = resource_get_cpu_init(&buf->base);
421 struct intel_bo *bo;
422
423 bo = intel_winsys_alloc_bo(is->dev.winsys, name,
424 buf->buffer.bo_size, cpu_init);
425 if (!bo)
426 return false;
427
428 intel_bo_unref(buf->buffer.bo);
429 buf->buffer.bo = bo;
430
431 return true;
432 }
433
434 static void
435 buf_destroy(struct ilo_buffer_resource *buf)
436 {
437 intel_bo_unref(buf->buffer.bo);
438 FREE(buf);
439 }
440
441 static struct pipe_resource *
442 buf_create(struct pipe_screen *screen, const struct pipe_resource *templ)
443 {
444 const struct ilo_screen *is = ilo_screen(screen);
445 struct ilo_buffer_resource *buf;
446
447 buf = CALLOC_STRUCT(ilo_buffer_resource);
448 if (!buf)
449 return NULL;
450
451 buf->base = *templ;
452 buf->base.screen = screen;
453 pipe_reference_init(&buf->base.reference, 1);
454
455 ilo_buffer_init(&buf->buffer, &is->dev,
456 templ->width0, templ->bind, templ->flags);
457
458 if (buf->buffer.bo_size < templ->width0 ||
459 buf->buffer.bo_size > ilo_max_resource_size ||
460 !buf_create_bo(buf)) {
461 FREE(buf);
462 return NULL;
463 }
464
465 return &buf->base;
466 }
467
468 static boolean
469 ilo_can_create_resource(struct pipe_screen *screen,
470 const struct pipe_resource *templ)
471 {
472 struct ilo_image img;
473
474 if (templ->target == PIPE_BUFFER)
475 return (templ->width0 <= ilo_max_resource_size);
476
477 memset(&img, 0, sizeof(img));
478 ilo_image_init(&img, &ilo_screen(screen)->dev, templ);
479
480 return (img.bo_height <= ilo_max_resource_size / img.bo_stride);
481 }
482
483 static struct pipe_resource *
484 ilo_resource_create(struct pipe_screen *screen,
485 const struct pipe_resource *templ)
486 {
487 if (templ->target == PIPE_BUFFER)
488 return buf_create(screen, templ);
489 else
490 return tex_create(screen, templ, NULL);
491 }
492
493 static struct pipe_resource *
494 ilo_resource_from_handle(struct pipe_screen *screen,
495 const struct pipe_resource *templ,
496 struct winsys_handle *handle)
497 {
498 if (templ->target == PIPE_BUFFER)
499 return NULL;
500 else
501 return tex_create(screen, templ, handle);
502 }
503
504 static boolean
505 ilo_resource_get_handle(struct pipe_screen *screen,
506 struct pipe_resource *res,
507 struct winsys_handle *handle)
508 {
509 if (res->target == PIPE_BUFFER)
510 return false;
511 else
512 return tex_get_handle(ilo_texture(res), handle);
513
514 }
515
516 static void
517 ilo_resource_destroy(struct pipe_screen *screen,
518 struct pipe_resource *res)
519 {
520 if (res->target == PIPE_BUFFER)
521 buf_destroy((struct ilo_buffer_resource *) res);
522 else
523 tex_destroy(ilo_texture(res));
524 }
525
526 /**
527 * Initialize resource-related functions.
528 */
529 void
530 ilo_init_resource_functions(struct ilo_screen *is)
531 {
532 is->base.can_create_resource = ilo_can_create_resource;
533 is->base.resource_create = ilo_resource_create;
534 is->base.resource_from_handle = ilo_resource_from_handle;
535 is->base.resource_get_handle = ilo_resource_get_handle;
536 is->base.resource_destroy = ilo_resource_destroy;
537 }
538
539 bool
540 ilo_resource_rename_bo(struct pipe_resource *res)
541 {
542 if (res->target == PIPE_BUFFER) {
543 return buf_create_bo((struct ilo_buffer_resource *) res);
544 } else {
545 struct ilo_texture *tex = ilo_texture(res);
546
547 /* an imported texture cannot be renamed */
548 if (tex->imported)
549 return false;
550
551 return tex_create_bo(tex);
552 }
553 }