2 * Mesa 3-D graphics library
4 * Copyright (C) 2012-2013 LunarG, Inc.
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
25 * Chia-I Wu <olv@lunarg.com>
28 #include "ilo_screen.h"
29 #include "ilo_resource.h"
32 * From the Ivy Bridge PRM, volume 1 part 1, page 105:
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."
38 static const size_t ilo_max_resource_size
= 1u << 31;
41 resource_get_bo_name(const struct pipe_resource
*templ
)
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",
54 const char *name
= target_names
[templ
->target
];
56 if (templ
->target
== PIPE_BUFFER
) {
57 switch (templ
->bind
) {
58 case PIPE_BIND_VERTEX_BUFFER
:
61 case PIPE_BIND_INDEX_BUFFER
:
64 case PIPE_BIND_CONSTANT_BUFFER
:
67 case PIPE_BIND_STREAM_OUTPUT
:
79 resource_get_cpu_init(const struct pipe_resource
*templ
)
81 return (templ
->bind
& (PIPE_BIND_DEPTH_STENCIL
|
82 PIPE_BIND_RENDER_TARGET
|
83 PIPE_BIND_STREAM_OUTPUT
)) ? false : true;
86 static enum gen_surface_tiling
87 winsys_to_surface_tiling(enum intel_tiling_mode tiling
)
90 case INTEL_TILING_NONE
:
91 return GEN6_TILING_NONE
;
97 assert(!"unknown tiling");
98 return GEN6_TILING_NONE
;
102 static inline enum intel_tiling_mode
103 surface_to_winsys_tiling(enum gen_surface_tiling tiling
)
106 case GEN6_TILING_NONE
:
107 return INTEL_TILING_NONE
;
109 return INTEL_TILING_X
;
111 return INTEL_TILING_Y
;
113 assert(!"unknown tiling");
114 return GEN6_TILING_NONE
;
119 tex_free_slices(struct ilo_texture
*tex
)
121 FREE(tex
->slices
[0]);
125 tex_alloc_slices(struct ilo_texture
*tex
)
127 const struct pipe_resource
*templ
= &tex
->base
;
128 struct ilo_texture_slice
*slices
;
131 /* sum the depths of all levels */
133 for (lv
= 0; lv
<= templ
->last_level
; lv
++)
134 depth
+= u_minify(templ
->depth0
, lv
);
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
141 slices
= CALLOC(depth
* templ
->array_size
, sizeof(*slices
));
145 tex
->slices
[0] = slices
;
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
;
157 tex_create_bo(struct ilo_texture
*tex
)
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
);
164 bo
= intel_winsys_alloc_bo(is
->dev
.winsys
, name
,
165 tex
->image
.bo_stride
* tex
->image
.bo_height
, cpu_init
);
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
);
173 if (intel_bo_set_tiling(bo
, tiling
, tex
->image
.bo_stride
)) {
181 intel_bo_unref(tex
->image
.bo
);
188 tex_create_separate_stencil(struct ilo_texture
*tex
)
190 struct pipe_resource templ
= tex
->base
;
191 struct pipe_resource
*s8
;
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.
198 templ
.format
= PIPE_FORMAT_S8_UINT
;
200 /* no stencil texturing */
201 templ
.bind
&= ~PIPE_BIND_SAMPLER_VIEW
;
203 s8
= tex
->base
.screen
->resource_create(tex
->base
.screen
, &templ
);
207 tex
->separate_s8
= ilo_texture(s8
);
209 assert(tex
->separate_s8
->image
.format
== PIPE_FORMAT_S8_UINT
);
215 tex_create_hiz(struct ilo_texture
*tex
)
217 const struct pipe_resource
*templ
= &tex
->base
;
218 struct ilo_screen
*is
= ilo_screen(tex
->base
.screen
);
221 bo
= intel_winsys_alloc_bo(is
->dev
.winsys
, "hiz texture",
222 tex
->image
.aux
.bo_stride
* tex
->image
.aux
.bo_height
, false);
226 tex
->image
.aux
.bo
= bo
;
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
;
238 ilo_texture_set_slice_flags(tex
, lv
, 0, num_slices
, flags
, flags
);
247 tex_create_mcs(struct ilo_texture
*tex
)
249 struct ilo_screen
*is
= ilo_screen(tex
->base
.screen
);
252 assert(tex
->image
.aux
.enables
== (1 << (tex
->base
.last_level
+ 1)) - 1);
254 bo
= intel_winsys_alloc_bo(is
->dev
.winsys
, "mcs texture",
255 tex
->image
.aux
.bo_stride
* tex
->image
.aux
.bo_height
, false);
259 tex
->image
.aux
.bo
= bo
;
265 tex_destroy(struct ilo_texture
*tex
)
267 if (tex
->separate_s8
)
268 tex_destroy(tex
->separate_s8
);
270 intel_bo_unref(tex
->image
.bo
);
271 intel_bo_unref(tex
->image
.aux
.bo
);
273 tex_free_slices(tex
);
278 tex_alloc_bos(struct ilo_texture
*tex
)
280 struct ilo_screen
*is
= ilo_screen(tex
->base
.screen
);
282 if (!tex
->imported
&& !tex_create_bo(tex
))
285 /* allocate separate stencil resource */
286 if (tex
->image
.separate_stencil
&& !tex_create_separate_stencil(tex
))
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
))
295 case ILO_IMAGE_AUX_MCS
:
296 if (!tex_create_mcs(tex
) &&
297 !ilo_image_disable_aux(&tex
->image
, &is
->dev
))
308 tex_import_handle(struct ilo_texture
*tex
,
309 const struct winsys_handle
*handle
)
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
;
318 bo
= intel_winsys_import_handle(is
->dev
.winsys
, name
, handle
,
319 tex
->image
.bo_height
, &tiling
, &pitch
);
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");
332 tex
->imported
= true;
338 tex_init_image(struct ilo_texture
*tex
,
339 const struct winsys_handle
*handle
)
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
;
346 if (!tex_import_handle(tex
, handle
))
349 ilo_image_init(img
, &is
->dev
, templ
);
352 if (img
->bo_height
> ilo_max_resource_size
/ img
->bo_stride
)
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
)
362 if (!tex_alloc_slices(tex
))
368 static struct pipe_resource
*
369 tex_create(struct pipe_screen
*screen
,
370 const struct pipe_resource
*templ
,
371 const struct winsys_handle
*handle
)
373 struct ilo_texture
*tex
;
375 tex
= CALLOC_STRUCT(ilo_texture
);
380 tex
->base
.screen
= screen
;
381 pipe_reference_init(&tex
->base
.reference
, 1);
383 if (!tex_init_image(tex
, handle
)) {
388 if (!tex_alloc_bos(tex
)) {
397 tex_get_handle(struct ilo_texture
*tex
, struct winsys_handle
*handle
)
399 struct ilo_screen
*is
= ilo_screen(tex
->base
.screen
);
400 enum intel_tiling_mode tiling
;
403 /* must match what tex_create_bo() sets */
404 if (tex
->image
.tiling
== GEN8_TILING_W
)
405 tiling
= INTEL_TILING_NONE
;
407 tiling
= surface_to_winsys_tiling(tex
->image
.tiling
);
409 err
= intel_winsys_export_handle(is
->dev
.winsys
, tex
->image
.bo
, tiling
,
410 tex
->image
.bo_stride
, tex
->image
.bo_height
, handle
);
416 buf_create_bo(struct ilo_buffer_resource
*buf
)
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
);
423 bo
= intel_winsys_alloc_bo(is
->dev
.winsys
, name
,
424 buf
->buffer
.bo_size
, cpu_init
);
428 intel_bo_unref(buf
->buffer
.bo
);
435 buf_destroy(struct ilo_buffer_resource
*buf
)
437 intel_bo_unref(buf
->buffer
.bo
);
441 static struct pipe_resource
*
442 buf_create(struct pipe_screen
*screen
, const struct pipe_resource
*templ
)
444 const struct ilo_screen
*is
= ilo_screen(screen
);
445 struct ilo_buffer_resource
*buf
;
448 buf
= CALLOC_STRUCT(ilo_buffer_resource
);
453 buf
->base
.screen
= screen
;
454 pipe_reference_init(&buf
->base
.reference
, 1);
456 size
= templ
->width0
;
459 * As noted in ilo_format_translate(), we treat some 3-component formats as
460 * 4-component formats to work around hardware limitations. Imagine the
461 * case where the vertex buffer holds a single PIPE_FORMAT_R16G16B16_FLOAT
462 * vertex, and buf->bo_size is 6. The hardware would fail to fetch it at
463 * boundary check because the vertex buffer is expected to hold a
464 * PIPE_FORMAT_R16G16B16A16_FLOAT vertex and that takes at least 8 bytes.
466 * For the workaround to work, we should add 2 to the bo size. But that
467 * would waste a page when the bo size is already page aligned. Let's
468 * round it to page size for now and revisit this when needed.
470 if ((templ
->bind
& PIPE_BIND_VERTEX_BUFFER
) &&
471 ilo_dev_gen(&is
->dev
) < ILO_GEN(7.5))
472 size
= align(size
, 4096);
474 ilo_buffer_init(&buf
->buffer
, &is
->dev
, size
, templ
->bind
, templ
->flags
);
476 if (buf
->buffer
.bo_size
< templ
->width0
||
477 buf
->buffer
.bo_size
> ilo_max_resource_size
||
478 !buf_create_bo(buf
)) {
487 ilo_can_create_resource(struct pipe_screen
*screen
,
488 const struct pipe_resource
*templ
)
490 struct ilo_image img
;
492 if (templ
->target
== PIPE_BUFFER
)
493 return (templ
->width0
<= ilo_max_resource_size
);
495 memset(&img
, 0, sizeof(img
));
496 ilo_image_init(&img
, &ilo_screen(screen
)->dev
, templ
);
498 return (img
.bo_height
<= ilo_max_resource_size
/ img
.bo_stride
);
501 static struct pipe_resource
*
502 ilo_resource_create(struct pipe_screen
*screen
,
503 const struct pipe_resource
*templ
)
505 if (templ
->target
== PIPE_BUFFER
)
506 return buf_create(screen
, templ
);
508 return tex_create(screen
, templ
, NULL
);
511 static struct pipe_resource
*
512 ilo_resource_from_handle(struct pipe_screen
*screen
,
513 const struct pipe_resource
*templ
,
514 struct winsys_handle
*handle
)
516 if (templ
->target
== PIPE_BUFFER
)
519 return tex_create(screen
, templ
, handle
);
523 ilo_resource_get_handle(struct pipe_screen
*screen
,
524 struct pipe_resource
*res
,
525 struct winsys_handle
*handle
)
527 if (res
->target
== PIPE_BUFFER
)
530 return tex_get_handle(ilo_texture(res
), handle
);
535 ilo_resource_destroy(struct pipe_screen
*screen
,
536 struct pipe_resource
*res
)
538 if (res
->target
== PIPE_BUFFER
)
539 buf_destroy((struct ilo_buffer_resource
*) res
);
541 tex_destroy(ilo_texture(res
));
545 * Initialize resource-related functions.
548 ilo_init_resource_functions(struct ilo_screen
*is
)
550 is
->base
.can_create_resource
= ilo_can_create_resource
;
551 is
->base
.resource_create
= ilo_resource_create
;
552 is
->base
.resource_from_handle
= ilo_resource_from_handle
;
553 is
->base
.resource_get_handle
= ilo_resource_get_handle
;
554 is
->base
.resource_destroy
= ilo_resource_destroy
;
558 ilo_resource_rename_bo(struct pipe_resource
*res
)
560 if (res
->target
== PIPE_BUFFER
) {
561 return buf_create_bo((struct ilo_buffer_resource
*) res
);
563 struct ilo_texture
*tex
= ilo_texture(res
);
565 /* an imported texture cannot be renamed */
569 return tex_create_bo(tex
);