diff --git a/src/freedreno/fdl/fd5_layout.c b/src/freedreno/fdl/fd5_layout.c index 975a436d2e2..435e2841c43 100644 --- a/src/freedreno/fdl/fd5_layout.c +++ b/src/freedreno/fdl/fd5_layout.c @@ -17,24 +17,49 @@ fdl5_layout(struct fdl_layout *layout, enum pipe_format format, uint32_t depth0, uint32_t mip_levels, uint32_t array_size, bool is_3d) { - assert(nr_samples > 0); - layout->width0 = width0; - layout->height0 = height0; - layout->depth0 = depth0; + struct fdl_image_params params = { + .format = format, + .nr_samples = nr_samples, + .width0 = width0, + .height0 = height0, + .depth0 = depth0, + .mip_levels = mip_levels, + .array_size = array_size, + .tile_mode = layout->tile_mode, + .ubwc = layout->ubwc, + .is_3d = is_3d, + }; - layout->cpp = util_format_get_blocksize(format); - layout->cpp *= nr_samples; + return fdl5_layout_image(layout, ¶ms); +} + +void +fdl5_layout_image(struct fdl_layout *layout, const struct fdl_image_params *params) +{ + memset(layout, 0, sizeof(*layout)); + + assert(params->nr_samples > 0); + assert(!params->ubwc && !params->force_ubwc); + + layout->width0 = params->width0; + layout->height0 = params->height0; + layout->depth0 = params->depth0; + + layout->cpp = util_format_get_blocksize(params->format); + layout->cpp *= params->nr_samples; layout->cpp_shift = ffs(layout->cpp) - 1; - layout->format = format; - layout->nr_samples = nr_samples; - layout->layer_first = !is_3d; + layout->format = params->format; + layout->nr_samples = params->nr_samples; + layout->layer_first = !params->is_3d; + + layout->tile_mode = params->tile_mode; uint32_t heightalign = layout->cpp == 1 ? 32 : 16; /* in layer_first layout, the level (slice) contains just one * layer (since in fact the layer contains the slices) */ - uint32_t layers_in_level = layout->layer_first ? 1 : array_size; + uint32_t layers_in_level = layout->layer_first ? 1 : params->array_size; /* use 128 pixel alignment for cpp=1 and cpp=2 */ if (layout->cpp < 4 && layout->tile_mode) @@ -42,13 +67,13 @@ fdl5_layout(struct fdl_layout *layout, enum pipe_format format, else fdl_set_pitchalign(layout, fdl_cpp_shift(layout) + 6); - for (uint32_t level = 0; level < mip_levels; level++) { - uint32_t depth = u_minify(depth0, level); + for (uint32_t level = 0; level < params->mip_levels; level++) { + uint32_t depth = u_minify(params->depth0, level); struct fdl_slice *slice = &layout->slices[level]; uint32_t tile_mode = fdl_tile_mode(layout, level); uint32_t pitch = fdl_pitch(layout, level); uint32_t nblocksy = - util_format_get_nblocksy(format, u_minify(height0, level)); + util_format_get_nblocksy(params->format, u_minify(params->height0, level)); if (tile_mode) { nblocksy = align(nblocksy, heightalign); @@ -60,7 +85,7 @@ fdl5_layout(struct fdl_layout *layout, enum pipe_format format, * The pitch is already sufficiently aligned, but height * may not be: */ - if (level == mip_levels - 1) + if (level == params->mip_levels - 1) nblocksy = align(nblocksy, 32); } @@ -72,7 +97,7 @@ fdl5_layout(struct fdl_layout *layout, enum pipe_format format, * different than what this code does), so as soon as the layer size * range gets into range, we stop reducing it. */ - if (is_3d) { + if (params->is_3d) { if (level <= 1 || layout->slices[level - 1].size0 > 0xf000) { slice->size0 = align(nblocksy * pitch, 4096); } else { @@ -87,6 +112,6 @@ fdl5_layout(struct fdl_layout *layout, enum pipe_format format, if (layout->layer_first) { layout->layer_size = align64(layout->size, 4096); - layout->size = layout->layer_size * array_size; + layout->size = layout->layer_size * params->array_size; } } diff --git a/src/freedreno/fdl/fd6_layout.c b/src/freedreno/fdl/fd6_layout.c index 0b022a5151b..49c8b92db73 100644 --- a/src/freedreno/fdl/fd6_layout.c +++ b/src/freedreno/fdl/fd6_layout.c @@ -118,24 +118,53 @@ fdl6_layout(struct fdl_layout *layout, const struct fd_dev_info *info, uint32_t array_size, bool is_3d, bool is_mutable, bool force_ubwc, struct fdl_explicit_layout *explicit_layout) +{ + struct fdl_image_params params = { + .format = format, + .nr_samples = nr_samples, + .width0 = width0, + .height0 = height0, + .depth0 = depth0, + .mip_levels = mip_levels, + .array_size = array_size, + .tile_mode = layout->tile_mode, + .ubwc = layout->ubwc, + .force_ubwc = force_ubwc, + .is_3d = is_3d, + .is_mutable = is_mutable, + }; + + return fdl6_layout_image(layout, info, ¶ms, explicit_layout); +} + +bool +fdl6_layout_image(struct fdl_layout *layout, const struct fd_dev_info *info, + const struct fdl_image_params *params, + const struct fdl_explicit_layout *explicit_layout) { uint32_t offset = 0, heightalign; uint32_t ubwc_blockwidth, ubwc_blockheight; - assert(nr_samples > 0); - layout->width0 = width0; - layout->height0 = height0; - layout->depth0 = depth0; - layout->mip_levels = mip_levels; + memset(layout, 0, sizeof(*layout)); - layout->cpp = util_format_get_blocksize(format); - layout->cpp *= nr_samples; + assert(params->nr_samples > 0); + + layout->width0 = params->width0; + layout->height0 = params->height0; + layout->depth0 = params->depth0; + layout->mip_levels = params->mip_levels; + + layout->cpp = util_format_get_blocksize(params->format); + layout->cpp *= params->nr_samples; layout->cpp_shift = ffs(layout->cpp) - 1; - layout->format = format; - layout->nr_samples = nr_samples; - layout->layer_first = !is_3d; - layout->is_mutable = is_mutable; + layout->format = params->format; + layout->nr_samples = params->nr_samples; + layout->layer_first = !params->is_3d; + layout->is_mutable = params->is_mutable; + + layout->ubwc = params->ubwc; + layout->tile_mode = params->tile_mode; if (!util_is_power_of_two_or_zero(layout->cpp)) { /* R8G8B8 and other 3 component formats don't get UBWC: */ @@ -147,24 +176,24 @@ fdl6_layout(struct fdl_layout *layout, const struct fd_dev_info *info, /* For simplicity support UBWC only for 3D images without mipmaps, * most d3d11 games don't use mipmaps for 3D images. */ - if (depth0 > 1 && mip_levels > 1) + if (params->depth0 > 1 && params->mip_levels > 1) layout->ubwc = false; if (ubwc_blockwidth == 0) layout->ubwc = false; } - assert(!force_ubwc || layout->ubwc); + assert(!params->force_ubwc || layout->ubwc); - if (!force_ubwc && width0 < FDL_MIN_UBWC_WIDTH) { + if (!params->force_ubwc && params->width0 < FDL_MIN_UBWC_WIDTH) { layout->ubwc = false; /* Linear D/S is not supported by HW. */ - if (!util_format_is_depth_or_stencil(format)) + if (!util_format_is_depth_or_stencil(params->format)) layout->tile_mode = TILE6_LINEAR; } /* Linear D/S is not supported by HW. */ - if (util_format_is_depth_or_stencil(format)) + if (util_format_is_depth_or_stencil(params->format)) layout->tile_all = true; if (layout->ubwc && !info->a6xx.has_ubwc_linear_mipmap_fallback) @@ -173,7 +202,7 @@ fdl6_layout(struct fdl_layout *layout, const struct fd_dev_info *info, /* in layer_first layout, the level (slice) contains just one * layer (since in fact the layer contains the slices) */ - uint32_t layers_in_level = layout->layer_first ? 1 : array_size; + uint32_t layers_in_level = layout->layer_first ? 1 : params->array_size; /* note: for tiled+noubwc layouts, we can use a lower pitchalign * which will affect the linear levels only, (the hardware will still @@ -220,17 +249,17 @@ fdl6_layout(struct fdl_layout *layout, const struct fd_dev_info *info, return false; } - uint32_t ubwc_width0 = width0; - uint32_t ubwc_height0 = height0; + uint32_t ubwc_width0 = params->width0; + uint32_t ubwc_height0 = params->height0; uint32_t ubwc_tile_height_alignment = RGB_TILE_HEIGHT_ALIGNMENT; - if (mip_levels > 1) { + if (params->mip_levels > 1) { /* With mipmapping enabled, UBWC layout is power-of-two sized, * specified in log2 width/height in the descriptors. The height * alignment is 64 for mipmapping, but for buffer sharing (always * single level) other participants expect 16. */ - ubwc_width0 = util_next_power_of_two(width0); - ubwc_height0 = util_next_power_of_two(height0); + ubwc_width0 = util_next_power_of_two(params->width0); + ubwc_height0 = util_next_power_of_two(params->height0); ubwc_tile_height_alignment = 64; } layout->ubwc_width0 = align(DIV_ROUND_UP(ubwc_width0, ubwc_blockwidth), @@ -240,15 +269,15 @@ fdl6_layout(struct fdl_layout *layout, const struct fd_dev_info *info, uint32_t min_3d_layer_size = 0; - for (uint32_t level = 0; level < mip_levels; level++) { - uint32_t depth = u_minify(depth0, level); + for (uint32_t level = 0; level < params->mip_levels; level++) { + uint32_t depth = u_minify(params->depth0, level); struct fdl_slice *slice = &layout->slices[level]; struct fdl_slice *ubwc_slice = &layout->ubwc_slices[level]; enum a6xx_tile_mode tile_mode = fdl_tile_mode(layout, level); uint32_t pitch = fdl_pitch(layout, level); - uint32_t height = u_minify(height0, level); + uint32_t height = u_minify(params->height0, level); - uint32_t nblocksy = util_format_get_nblocksy(format, height); + uint32_t nblocksy = util_format_get_nblocksy(params->format, height); if (tile_mode) nblocksy = align(nblocksy, heightalign); @@ -259,7 +288,7 @@ fdl6_layout(struct fdl_layout *layout, const struct fd_dev_info *info, * The pitch is already sufficiently aligned, but height * may not be. note this only matters if last level is linear */ - if (level == mip_levels - 1) + if (level == params->mip_levels - 1) nblocksy = align(nblocksy, 4); slice->offset = offset + layout->size; @@ -269,7 +298,7 @@ fdl6_layout(struct fdl_layout *layout, const struct fd_dev_info *info, * until the value we specify in TEX_CONST_3_MIN_LAYERSZ, which is used to * make sure that we follow alignment requirements after minification. */ - if (is_3d) { + if (params->is_3d) { if (level == 0) { slice->size0 = align(nblocksy * pitch, 4096); } else if (min_3d_layer_size) { @@ -316,7 +345,7 @@ fdl6_layout(struct fdl_layout *layout, const struct fd_dev_info *info, if (layout->layer_first) { layout->layer_size = align64(layout->size, 4096); - layout->size = layout->layer_size * array_size; + layout->size = layout->layer_size * params->array_size; } /* Place the UBWC slices before the uncompressed slices, because the @@ -325,10 +354,12 @@ fdl6_layout(struct fdl_layout *layout, const struct fd_dev_info *info, * independently. */ if (layout->ubwc) { - assert(!(depth0 > 1 && mip_levels > 1)); - for (uint32_t level = 0; level < mip_levels; level++) - layout->slices[level].offset += layout->ubwc_layer_size * array_size * depth0; - layout->size += layout->ubwc_layer_size * array_size * depth0; + assert(!(params->depth0 > 1 && params->mip_levels > 1)); + for (uint32_t level = 0; level < params->mip_levels; level++) { + layout->slices[level].offset += + layout->ubwc_layer_size * params->array_size * params->depth0; + } + layout->size += layout->ubwc_layer_size * params->array_size * params->depth0; } /* include explicit offset in size */ diff --git a/src/freedreno/fdl/fd_layout_test.c b/src/freedreno/fdl/fd_layout_test.c index f913d6fdb06..35aa540bed0 100644 --- a/src/freedreno/fdl/fd_layout_test.c +++ b/src/freedreno/fdl/fd_layout_test.c @@ -12,11 +12,7 @@ bool fdl_test_layout(const struct testcase *testcase, const struct fd_dev_id *dev_id) { - struct fdl_layout layout = { - .ubwc = testcase->layout.ubwc, - .tile_mode = testcase->layout.tile_mode, - .tile_all = testcase->layout.tile_all, - }; + struct fdl_layout layout; bool ok = true; int max_size = MAX2(testcase->layout.width0, testcase->layout.height0); @@ -26,20 +22,25 @@ fdl_test_layout(const struct testcase *testcase, const struct fd_dev_id *dev_id) max_size = u_minify(max_size, 1); } + struct fdl_image_params params = { + .format = testcase->format, + .nr_samples = MAX2(testcase->layout.nr_samples, 1), + .width0 = testcase->layout.width0, + .height0 = MAX2(testcase->layout.height0, 1), + .depth0 = MAX2(testcase->layout.depth0, 1), + .mip_levels = mip_levels, + .array_size = MAX2(testcase->array_size, 1), + .is_3d = testcase->is_3d, + .ubwc = testcase->layout.ubwc, + .tile_mode = testcase->layout.tile_mode, + }; + if (fd_dev_gen(dev_id) >= 6) { const struct fd_dev_info *dev_info = fd_dev_info_raw(dev_id); - fdl6_layout(&layout, dev_info, testcase->format, - MAX2(testcase->layout.nr_samples, 1), testcase->layout.width0, - MAX2(testcase->layout.height0, 1), - MAX2(testcase->layout.depth0, 1), mip_levels, - MAX2(testcase->array_size, 1), testcase->is_3d, false, false, NULL); + fdl6_layout_image(&layout, dev_info, ¶ms, NULL); } else { assert(fd_dev_gen(dev_id) >= 5); - fdl5_layout(&layout, testcase->format, - MAX2(testcase->layout.nr_samples, 1), testcase->layout.width0, - MAX2(testcase->layout.height0, 1), - MAX2(testcase->layout.depth0, 1), mip_levels, - MAX2(testcase->array_size, 1), testcase->is_3d); + fdl5_layout_image(&layout, ¶ms); } /* fdl lays out UBWC data before the color data, while all we have diff --git a/src/freedreno/fdl/freedreno_layout.h b/src/freedreno/fdl/freedreno_layout.h index 3be3a1b1614..8ddb49f4738 100644 --- a/src/freedreno/fdl/freedreno_layout.h +++ b/src/freedreno/fdl/freedreno_layout.h @@ -75,6 +75,37 @@ struct fdl_explicit_layout { uint32_t pitch; }; +/** + * General layout params for images. + */ +struct fdl_image_params { + enum pipe_format format; + uint32_t nr_samples; + uint32_t width0; + uint32_t height0; + uint32_t depth0; + uint32_t mip_levels; + uint32_t array_size; + + /** + * Preferred tile mode, may be overriden by layout constraints. + */ + uint32_t tile_mode; + + /** + * UBWC preferred, may be overriden + */ + bool ubwc; + + /** + * Force UBWC, even when below the minimum width. + */ + bool force_ubwc; + + bool is_3d; + bool is_mutable; +}; + /** * Metadata shared between vk and gallium driver for interop. * @@ -232,6 +263,11 @@ const char *fdl_tile_mode_desc(const struct fdl_layout *layout, int level); void fdl_layout_buffer(struct fdl_layout *layout, uint32_t size); +void fdl5_layout_image(struct fdl_layout *layout, const struct fdl_image_params *params); +bool fdl6_layout_image(struct fdl_layout *layout, const struct fd_dev_info *info, + const struct fdl_image_params *params, + const struct fdl_explicit_layout *explicit_layout); + void fdl5_layout(struct fdl_layout *layout, enum pipe_format format, uint32_t nr_samples, uint32_t width0, uint32_t height0, uint32_t depth0, uint32_t mip_levels, uint32_t array_size,