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 "core/ilo_state_vf.h"
29 #include "core/ilo_state_sol.h"
30 #include "core/ilo_state_surface.h"
32 #include "ilo_screen.h"
33 #include "ilo_resource.h"
36 * From the Ivy Bridge PRM, volume 1 part 1, page 105:
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."
42 static const size_t ilo_max_resource_size
= 1u << 31;
45 resource_get_bo_name(const struct pipe_resource
*templ
)
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",
58 const char *name
= target_names
[templ
->target
];
60 if (templ
->target
== PIPE_BUFFER
) {
61 switch (templ
->bind
) {
62 case PIPE_BIND_VERTEX_BUFFER
:
65 case PIPE_BIND_INDEX_BUFFER
:
68 case PIPE_BIND_CONSTANT_BUFFER
:
71 case PIPE_BIND_STREAM_OUTPUT
:
83 resource_get_cpu_init(const struct pipe_resource
*templ
)
85 return (templ
->bind
& (PIPE_BIND_DEPTH_STENCIL
|
86 PIPE_BIND_RENDER_TARGET
|
87 PIPE_BIND_STREAM_OUTPUT
)) ? false : true;
90 static enum gen_surface_type
91 get_surface_type(enum pipe_texture_target target
)
95 case PIPE_TEXTURE_1D_ARRAY
:
96 return GEN6_SURFTYPE_1D
;
98 case PIPE_TEXTURE_RECT
:
99 case PIPE_TEXTURE_2D_ARRAY
:
100 return GEN6_SURFTYPE_2D
;
101 case PIPE_TEXTURE_3D
:
102 return GEN6_SURFTYPE_3D
;
103 case PIPE_TEXTURE_CUBE
:
104 case PIPE_TEXTURE_CUBE_ARRAY
:
105 return GEN6_SURFTYPE_CUBE
;
107 assert(!"unknown texture target");
108 return GEN6_SURFTYPE_NULL
;
113 resource_get_image_info(const struct pipe_resource
*templ
,
114 const struct ilo_dev
*dev
,
115 enum pipe_format image_format
,
116 struct ilo_image_info
*info
)
118 memset(info
, 0, sizeof(*info
));
120 info
->type
= get_surface_type(templ
->target
);
121 info
->format
= image_format
;
123 info
->width
= templ
->width0
;
124 info
->height
= templ
->height0
;
125 info
->depth
= templ
->depth0
;
126 info
->array_size
= templ
->array_size
;
127 info
->level_count
= templ
->last_level
+ 1;
128 info
->sample_count
= (templ
->nr_samples
) ? templ
->nr_samples
: 1;
130 info
->aux_disable
= (templ
->usage
== PIPE_USAGE_STAGING
);
132 if (templ
->bind
& PIPE_BIND_LINEAR
)
133 info
->valid_tilings
= 1 << GEN6_TILING_NONE
;
135 info
->bind_surface_sampler
= (templ
->bind
& PIPE_BIND_SAMPLER_VIEW
);
136 info
->bind_surface_dp_render
= (templ
->bind
& PIPE_BIND_RENDER_TARGET
);
137 info
->bind_surface_dp_typed
= (templ
->bind
&
138 (PIPE_BIND_SHADER_RESOURCE
| PIPE_BIND_COMPUTE_RESOURCE
));
139 info
->bind_zs
= (templ
->bind
& PIPE_BIND_DEPTH_STENCIL
);
140 info
->bind_scanout
= (templ
->bind
& PIPE_BIND_SCANOUT
);
141 info
->bind_cursor
= (templ
->bind
& PIPE_BIND_CURSOR
);
144 static enum gen_surface_tiling
145 winsys_to_surface_tiling(enum intel_tiling_mode tiling
)
148 case INTEL_TILING_NONE
:
149 return GEN6_TILING_NONE
;
151 return GEN6_TILING_X
;
153 return GEN6_TILING_Y
;
155 assert(!"unknown tiling");
156 return GEN6_TILING_NONE
;
160 static inline enum intel_tiling_mode
161 surface_to_winsys_tiling(enum gen_surface_tiling tiling
)
164 case GEN6_TILING_NONE
:
165 return INTEL_TILING_NONE
;
167 return INTEL_TILING_X
;
169 return INTEL_TILING_Y
;
171 assert(!"unknown tiling");
172 return GEN6_TILING_NONE
;
177 tex_free_slices(struct ilo_texture
*tex
)
179 FREE(tex
->slices
[0]);
183 tex_alloc_slices(struct ilo_texture
*tex
)
185 const struct pipe_resource
*templ
= &tex
->base
;
186 struct ilo_texture_slice
*slices
;
189 /* sum the depths of all levels */
191 for (lv
= 0; lv
<= templ
->last_level
; lv
++)
192 depth
+= u_minify(templ
->depth0
, lv
);
195 * There are (depth * tex->base.array_size) slices in total. Either depth
196 * is one (non-3D) or templ->array_size is one (non-array), but it does
199 slices
= CALLOC(depth
* templ
->array_size
, sizeof(*slices
));
203 tex
->slices
[0] = slices
;
205 /* point to the respective positions in the buffer */
206 for (lv
= 1; lv
<= templ
->last_level
; lv
++) {
207 tex
->slices
[lv
] = tex
->slices
[lv
- 1] +
208 u_minify(templ
->depth0
, lv
- 1) * templ
->array_size
;
215 tex_create_bo(struct ilo_texture
*tex
)
217 struct ilo_screen
*is
= ilo_screen(tex
->base
.screen
);
218 const char *name
= resource_get_bo_name(&tex
->base
);
219 const bool cpu_init
= resource_get_cpu_init(&tex
->base
);
222 bo
= intel_winsys_alloc_bo(is
->dev
.winsys
, name
,
223 tex
->image
.bo_stride
* tex
->image
.bo_height
, cpu_init
);
225 /* set the tiling for transfer and export */
226 if (bo
&& (tex
->image
.tiling
== GEN6_TILING_X
||
227 tex
->image
.tiling
== GEN6_TILING_Y
)) {
228 const enum intel_tiling_mode tiling
=
229 surface_to_winsys_tiling(tex
->image
.tiling
);
231 if (intel_bo_set_tiling(bo
, tiling
, tex
->image
.bo_stride
)) {
239 intel_bo_unref(tex
->vma
.bo
);
240 ilo_vma_set_bo(&tex
->vma
, &is
->dev
, bo
, 0);
246 tex_create_separate_stencil(struct ilo_texture
*tex
)
248 struct pipe_resource templ
= tex
->base
;
249 struct pipe_resource
*s8
;
252 * Unless PIPE_BIND_DEPTH_STENCIL is set, the resource may have other
253 * tilings. But that should be fine since it will never be bound as the
254 * stencil buffer, and our transfer code can handle all tilings.
256 templ
.format
= PIPE_FORMAT_S8_UINT
;
258 /* no stencil texturing */
259 templ
.bind
&= ~PIPE_BIND_SAMPLER_VIEW
;
261 s8
= tex
->base
.screen
->resource_create(tex
->base
.screen
, &templ
);
265 tex
->separate_s8
= ilo_texture(s8
);
267 assert(tex
->separate_s8
->image
.format
== PIPE_FORMAT_S8_UINT
);
273 tex_create_hiz(struct ilo_texture
*tex
)
275 const struct pipe_resource
*templ
= &tex
->base
;
276 const uint32_t size
= tex
->image
.aux
.bo_stride
* tex
->image
.aux
.bo_height
;
277 struct ilo_screen
*is
= ilo_screen(tex
->base
.screen
);
280 bo
= intel_winsys_alloc_bo(is
->dev
.winsys
, "hiz texture", size
, false);
284 ilo_vma_init(&tex
->aux_vma
, &is
->dev
, size
, 4096);
285 ilo_vma_set_bo(&tex
->aux_vma
, &is
->dev
, bo
, 0);
290 for (lv
= 0; lv
<= templ
->last_level
; lv
++) {
291 if (tex
->image
.aux
.enables
& (1 << lv
)) {
292 const unsigned num_slices
= (templ
->target
== PIPE_TEXTURE_3D
) ?
293 u_minify(templ
->depth0
, lv
) : templ
->array_size
;
294 /* this will trigger HiZ resolves */
295 const unsigned flags
= ILO_TEXTURE_CPU_WRITE
;
297 ilo_texture_set_slice_flags(tex
, lv
, 0, num_slices
, flags
, flags
);
306 tex_create_mcs(struct ilo_texture
*tex
)
308 const uint32_t size
= tex
->image
.aux
.bo_stride
* tex
->image
.aux
.bo_height
;
309 struct ilo_screen
*is
= ilo_screen(tex
->base
.screen
);
312 assert(tex
->image
.aux
.enables
== (1 << (tex
->base
.last_level
+ 1)) - 1);
314 bo
= intel_winsys_alloc_bo(is
->dev
.winsys
, "mcs texture", size
, false);
318 ilo_vma_init(&tex
->aux_vma
, &is
->dev
, size
, 4096);
319 ilo_vma_set_bo(&tex
->aux_vma
, &is
->dev
, bo
, 0);
325 tex_destroy(struct ilo_texture
*tex
)
327 if (tex
->separate_s8
)
328 tex_destroy(tex
->separate_s8
);
330 intel_bo_unref(tex
->vma
.bo
);
331 intel_bo_unref(tex
->aux_vma
.bo
);
333 tex_free_slices(tex
);
338 tex_alloc_bos(struct ilo_texture
*tex
)
340 if (!tex
->imported
&& !tex_create_bo(tex
))
343 /* allocate separate stencil resource */
344 if (tex
->image
.separate_stencil
&& !tex_create_separate_stencil(tex
))
347 switch (tex
->image
.aux
.type
) {
348 case ILO_IMAGE_AUX_HIZ
:
349 if (!tex_create_hiz(tex
))
352 case ILO_IMAGE_AUX_MCS
:
353 if (!tex_create_mcs(tex
))
363 static struct intel_bo
*
364 tex_import_handle(struct ilo_texture
*tex
,
365 const struct winsys_handle
*handle
,
366 struct ilo_image_info
*info
)
368 struct ilo_screen
*is
= ilo_screen(tex
->base
.screen
);
369 const struct pipe_resource
*templ
= &tex
->base
;
370 const char *name
= resource_get_bo_name(&tex
->base
);
371 enum intel_tiling_mode tiling
;
375 bo
= intel_winsys_import_handle(is
->dev
.winsys
, name
, handle
,
376 tex
->image
.bo_height
, &tiling
, &pitch
);
377 /* modify image info */
379 const uint8_t valid_tilings
= 1 << winsys_to_surface_tiling(tiling
);
381 if (info
->valid_tilings
&& !(info
->valid_tilings
& valid_tilings
)) {
386 info
->valid_tilings
= valid_tilings
;
387 info
->force_bo_stride
= pitch
;
389 /* assume imported RTs are also scanouts */
390 if (!info
->bind_scanout
)
391 info
->bind_scanout
= (templ
->usage
& PIPE_BIND_RENDER_TARGET
);
398 tex_init_image(struct ilo_texture
*tex
,
399 const struct winsys_handle
*handle
)
401 struct ilo_screen
*is
= ilo_screen(tex
->base
.screen
);
402 const struct pipe_resource
*templ
= &tex
->base
;
403 struct ilo_image
*img
= &tex
->image
;
404 struct intel_bo
*imported_bo
= NULL
;;
405 struct ilo_image_info info
;
407 resource_get_image_info(templ
, &is
->dev
, templ
->format
, &info
);
410 imported_bo
= tex_import_handle(tex
, handle
, &info
);
415 if (!ilo_image_init(img
, &is
->dev
, &info
)) {
416 intel_bo_unref(imported_bo
);
420 if (img
->bo_height
> ilo_max_resource_size
/ img
->bo_stride
||
421 !ilo_vma_init(&tex
->vma
, &is
->dev
, img
->bo_stride
* img
->bo_height
,
423 intel_bo_unref(imported_bo
);
428 ilo_vma_set_bo(&tex
->vma
, &is
->dev
, imported_bo
, 0);
429 tex
->imported
= true;
432 if (templ
->flags
& PIPE_RESOURCE_FLAG_MAP_PERSISTENT
) {
433 /* require on-the-fly tiling/untiling or format conversion */
434 if (img
->tiling
== GEN8_TILING_W
|| img
->separate_stencil
||
435 img
->format
!= templ
->format
)
439 if (!tex_alloc_slices(tex
))
445 static struct pipe_resource
*
446 tex_create(struct pipe_screen
*screen
,
447 const struct pipe_resource
*templ
,
448 const struct winsys_handle
*handle
)
450 struct ilo_texture
*tex
;
452 tex
= CALLOC_STRUCT(ilo_texture
);
457 tex
->base
.screen
= screen
;
458 pipe_reference_init(&tex
->base
.reference
, 1);
460 if (!tex_init_image(tex
, handle
)) {
465 if (!tex_alloc_bos(tex
)) {
474 tex_get_handle(struct ilo_texture
*tex
, struct winsys_handle
*handle
)
476 struct ilo_screen
*is
= ilo_screen(tex
->base
.screen
);
477 enum intel_tiling_mode tiling
;
480 /* must match what tex_create_bo() sets */
481 if (tex
->image
.tiling
== GEN8_TILING_W
)
482 tiling
= INTEL_TILING_NONE
;
484 tiling
= surface_to_winsys_tiling(tex
->image
.tiling
);
486 err
= intel_winsys_export_handle(is
->dev
.winsys
, tex
->vma
.bo
, tiling
,
487 tex
->image
.bo_stride
, tex
->image
.bo_height
, handle
);
493 buf_create_bo(struct ilo_buffer_resource
*buf
)
495 struct ilo_screen
*is
= ilo_screen(buf
->base
.screen
);
496 const char *name
= resource_get_bo_name(&buf
->base
);
497 const bool cpu_init
= resource_get_cpu_init(&buf
->base
);
500 bo
= intel_winsys_alloc_bo(is
->dev
.winsys
, name
, buf
->bo_size
, cpu_init
);
504 intel_bo_unref(buf
->vma
.bo
);
505 ilo_vma_set_bo(&buf
->vma
, &is
->dev
, bo
, 0);
511 buf_destroy(struct ilo_buffer_resource
*buf
)
513 intel_bo_unref(buf
->vma
.bo
);
517 static struct pipe_resource
*
518 buf_create(struct pipe_screen
*screen
, const struct pipe_resource
*templ
)
520 const struct ilo_screen
*is
= ilo_screen(screen
);
521 struct ilo_buffer_resource
*buf
;
525 buf
= CALLOC_STRUCT(ilo_buffer_resource
);
530 buf
->base
.screen
= screen
;
531 pipe_reference_init(&buf
->base
.reference
, 1);
533 size
= templ
->width0
;
536 * As noted in ilo_format_translate(), we treat some 3-component formats as
537 * 4-component formats to work around hardware limitations. Imagine the
538 * case where the vertex buffer holds a single PIPE_FORMAT_R16G16B16_FLOAT
539 * vertex, and buf->bo_size is 6. The hardware would fail to fetch it at
540 * boundary check because the vertex buffer is expected to hold a
541 * PIPE_FORMAT_R16G16B16A16_FLOAT vertex and that takes at least 8 bytes.
543 * For the workaround to work, we should add 2 to the bo size. But that
544 * would waste a page when the bo size is already page aligned. Let's
545 * round it to page size for now and revisit this when needed.
547 if ((templ
->bind
& PIPE_BIND_VERTEX_BUFFER
) &&
548 ilo_dev_gen(&is
->dev
) < ILO_GEN(7.5))
549 size
= align(size
, 4096);
551 if (templ
->bind
& PIPE_BIND_VERTEX_BUFFER
)
552 size
= ilo_state_vertex_buffer_size(&is
->dev
, size
, &alignment
);
553 if (templ
->bind
& PIPE_BIND_INDEX_BUFFER
)
554 size
= ilo_state_index_buffer_size(&is
->dev
, size
, &alignment
);
555 if (templ
->bind
& PIPE_BIND_STREAM_OUTPUT
)
556 size
= ilo_state_sol_buffer_size(&is
->dev
, size
, &alignment
);
559 ilo_vma_init(&buf
->vma
, &is
->dev
, buf
->bo_size
, 4096);
561 if (buf
->bo_size
< templ
->width0
|| buf
->bo_size
> ilo_max_resource_size
||
562 !buf_create_bo(buf
)) {
571 ilo_can_create_resource(struct pipe_screen
*screen
,
572 const struct pipe_resource
*templ
)
574 struct ilo_screen
*is
= ilo_screen(screen
);
575 struct ilo_image_info info
;
576 struct ilo_image img
;
578 if (templ
->target
== PIPE_BUFFER
)
579 return (templ
->width0
<= ilo_max_resource_size
);
581 resource_get_image_info(templ
, &is
->dev
, templ
->format
, &info
);
583 memset(&img
, 0, sizeof(img
));
584 ilo_image_init(&img
, &ilo_screen(screen
)->dev
, &info
);
586 return (img
.bo_height
<= ilo_max_resource_size
/ img
.bo_stride
);
589 static struct pipe_resource
*
590 ilo_resource_create(struct pipe_screen
*screen
,
591 const struct pipe_resource
*templ
)
593 if (templ
->target
== PIPE_BUFFER
)
594 return buf_create(screen
, templ
);
596 return tex_create(screen
, templ
, NULL
);
599 static struct pipe_resource
*
600 ilo_resource_from_handle(struct pipe_screen
*screen
,
601 const struct pipe_resource
*templ
,
602 struct winsys_handle
*handle
)
604 if (templ
->target
== PIPE_BUFFER
)
607 return tex_create(screen
, templ
, handle
);
611 ilo_resource_get_handle(struct pipe_screen
*screen
,
612 struct pipe_resource
*res
,
613 struct winsys_handle
*handle
)
615 if (res
->target
== PIPE_BUFFER
)
618 return tex_get_handle(ilo_texture(res
), handle
);
623 ilo_resource_destroy(struct pipe_screen
*screen
,
624 struct pipe_resource
*res
)
626 if (res
->target
== PIPE_BUFFER
)
627 buf_destroy((struct ilo_buffer_resource
*) res
);
629 tex_destroy(ilo_texture(res
));
633 * Initialize resource-related functions.
636 ilo_init_resource_functions(struct ilo_screen
*is
)
638 is
->base
.can_create_resource
= ilo_can_create_resource
;
639 is
->base
.resource_create
= ilo_resource_create
;
640 is
->base
.resource_from_handle
= ilo_resource_from_handle
;
641 is
->base
.resource_get_handle
= ilo_resource_get_handle
;
642 is
->base
.resource_destroy
= ilo_resource_destroy
;
646 ilo_resource_rename_bo(struct pipe_resource
*res
)
648 if (res
->target
== PIPE_BUFFER
) {
649 return buf_create_bo((struct ilo_buffer_resource
*) res
);
651 struct ilo_texture
*tex
= ilo_texture(res
);
653 /* an imported texture cannot be renamed */
657 return tex_create_bo(tex
);