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