From 69967e3f0dd65dbf2f58102d06c43b9aa1b1fdfb Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Mon, 30 Jan 2023 20:11:49 -0600 Subject: [PATCH] nil: Create images Part-of: --- src/nouveau/nil/meson.build | 4 +- src/nouveau/nil/nil.c | 1 - src/nouveau/nil/nil.h | 11 --- src/nouveau/nil/nil_image.c | 199 ++++++++++++++++++++++++++++++++++++++++++++ src/nouveau/nil/nil_image.h | 112 +++++++++++++++++++++++++ 5 files changed, 313 insertions(+), 14 deletions(-) delete mode 100644 src/nouveau/nil/nil.c delete mode 100644 src/nouveau/nil/nil.h create mode 100644 src/nouveau/nil/nil_image.c create mode 100644 src/nouveau/nil/nil_image.h diff --git a/src/nouveau/nil/meson.build b/src/nouveau/nil/meson.build index d2231a0..585d2fe 100644 --- a/src/nouveau/nil/meson.build +++ b/src/nouveau/nil/meson.build @@ -19,8 +19,8 @@ # SOFTWARE. libnil_files = files( - 'nil.c', - 'nil.h', + 'nil_image.c', + 'nil_image.h', ) _libnil = static_library( diff --git a/src/nouveau/nil/nil.c b/src/nouveau/nil/nil.c deleted file mode 100644 index 8cf6c8d..0000000 --- a/src/nouveau/nil/nil.c +++ /dev/null @@ -1 +0,0 @@ -#include "nil.h" diff --git a/src/nouveau/nil/nil.h b/src/nouveau/nil/nil.h deleted file mode 100644 index 5f577be..0000000 --- a/src/nouveau/nil/nil.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef NIL_H -#define NIL_H - -#include -#include -#include - -#include "util/macros.h" -#include "util/format/u_format.h" - -#endif /* NIL_H */ diff --git a/src/nouveau/nil/nil_image.c b/src/nouveau/nil/nil_image.c new file mode 100644 index 0000000..6956fa3 --- /dev/null +++ b/src/nouveau/nil/nil_image.c @@ -0,0 +1,199 @@ +#include "nil_image.h" + +#include "util/u_math.h" + +static struct nil_extent4d +nil_minify_extent4d(struct nil_extent4d extent, uint32_t level) +{ + return (struct nil_extent4d) { + .w = u_minify(extent.w, level), + .h = u_minify(extent.h, level), + .d = u_minify(extent.d, level), + .a = extent.a, + }; +} + +static struct nil_extent4d +nil_extent4d_div_round_up(struct nil_extent4d num, struct nil_extent4d denom) +{ + return (struct nil_extent4d) { + .w = DIV_ROUND_UP(num.w, denom.w), + .h = DIV_ROUND_UP(num.h, denom.h), + .d = DIV_ROUND_UP(num.d, denom.d), + .a = DIV_ROUND_UP(num.a, denom.a), + }; +} + +static struct nil_extent4d +nil_extent4d_align(struct nil_extent4d ext, struct nil_extent4d align) +{ + return (struct nil_extent4d) { + .w = ALIGN_POT(ext.w, align.w), + .h = ALIGN_POT(ext.h, align.h), + .d = ALIGN_POT(ext.d, align.d), + .a = ALIGN_POT(ext.a, align.a), + }; +} + +static struct nil_extent4d +nil_extent4d_px_to_el(struct nil_extent4d extent_px, + enum pipe_format format) +{ + const struct util_format_description *fmt = + util_format_description(format); + + const struct nil_extent4d block_extent_px = { + .w = fmt->block.width, + .h = fmt->block.height, + .d = fmt->block.depth, + .a = 1, + }; + + return nil_extent4d_div_round_up(extent_px, block_extent_px); +} + +static struct nil_extent4d +nil_extent4d_el_to_B(struct nil_extent4d extent_el, + uint32_t B_per_el) +{ + struct nil_extent4d extent_B = extent_el; + extent_B.w *= B_per_el; + return extent_B; +} + +static struct nil_extent4d +nil_extent4d_B_to_GOB(struct nil_extent4d extent_B, + bool gob_height_8) +{ + const struct nil_extent4d gob_extent_B = { + .w = NIL_GOB_WIDTH_B, + .h = NIL_GOB_HEIGHT(gob_height_8), + .d = NIL_GOB_DEPTH, + .a = 1, + }; + + return nil_extent4d_div_round_up(extent_B, gob_extent_B); +} + +static struct nil_extent4d +nil_tiling_extent_B(struct nil_tiling tiling) +{ + if (tiling.is_tiled) { + return (struct nil_extent4d) { + .w = NIL_GOB_WIDTH_B, /* Tiles are always 1 GOB wide */ + .h = NIL_GOB_HEIGHT(tiling.gob_height_8) << tiling.y_log2, + .d = NIL_GOB_DEPTH << tiling.z_log2, + .a = 1, + }; + } else { + return nil_extent4d(1, 1, 1, 1); + } +} + +static struct nil_tiling +choose_tiling(struct nil_extent4d extent_B, + enum nil_image_usage_flags usage) +{ + struct nil_tiling tiling = { + .is_tiled = true, + .gob_height_8 = true, + }; + + const struct nil_extent4d extent_GOB = + nil_extent4d_B_to_GOB(extent_B, tiling.gob_height_8); + + const uint32_t height_log2 = util_logbase2_ceil(extent_GOB.height); + const uint32_t depth_log2 = util_logbase2_ceil(extent_GOB.depth); + + tiling.y_log2 = MIN2(height_log2, 5); + tiling.z_log2 = MIN2(depth_log2, 5); + + if (usage & NIL_IMAGE_USAGE_2D_VIEW_BIT) + tiling.z_log2 = 0; + + return tiling; +} + +static uint32_t +nil_tiling_size_B(struct nil_tiling tiling) +{ + const struct nil_extent4d extent_B = nil_tiling_extent_B(tiling); + return extent_B.w * extent_B.h * extent_B.d * extent_B.a; +} + +static struct nil_extent4d +nil_extent4d_B_to_tl(struct nil_extent4d extent_B, + struct nil_tiling tiling) +{ + return nil_extent4d_div_round_up(extent_B, nil_tiling_extent_B(tiling)); +} + +static struct nil_extent4d +image_level_extent_B(const struct nil_image *image, uint32_t level) +{ + const struct nil_extent4d level_extent_px = + nil_minify_extent4d(image->extent_px, level); + const struct nil_extent4d level_extent_el = + nil_extent4d_px_to_el(level_extent_px, image->format); + const uint32_t B_per_el = util_format_get_blocksize(image->format); + return nil_extent4d_el_to_B(level_extent_el, B_per_el); +} + +bool +nil_image_init(struct nouveau_ws_device *dev, + struct nil_image *image, + const struct nil_image_init_info *restrict info) +{ + switch (info->dim) { + case NIL_IMAGE_DIM_1D: + assert(info->extent_px.h == 1); + assert(info->extent_px.d == 1); + assert(info->samples == 1); + break; + case NIL_IMAGE_DIM_2D: + assert(info->extent_px.d == 1); + break; + case NIL_IMAGE_DIM_3D: + assert(info->extent_px.a == 1); + assert(info->samples == 1); + break; + } + + *image = (struct nil_image) { + .dim = info->dim, + .format = info->format, + .extent_px = info->extent_px, + .num_levels = info->levels, + /* TODO: Figure out miptails */ + .mip_tail_start = info->levels, + .num_samples = info->samples, + }; + + uint64_t layer_size_B = 0; + for (uint32_t l = 0; l < info->levels; l++) { + struct nil_extent4d lvl_ext_B = image_level_extent_B(image, l); + + /* Tiling is chosen per-level with LOD0 acting as a maximum */ + struct nil_tiling lvl_tiling = choose_tiling(lvl_ext_B, info->usage); + + /* Align the size to tiles */ + struct nil_extent4d lvl_tiling_ext_B = nil_tiling_extent_B(lvl_tiling); + lvl_ext_B = nil_extent4d_align(lvl_ext_B, lvl_tiling_ext_B); + + image->levels[l] = (struct nil_image_level) { + .offset_B = layer_size_B, + .tiling = lvl_tiling, + .row_stride_B = lvl_ext_B.width, + }; + layer_size_B += (uint64_t)lvl_ext_B.w * + (uint64_t)lvl_ext_B.h * + (uint64_t)lvl_ext_B.d; + } + + /* I have no idea why but hardware seems to align layer strides */ + image->array_stride_B = ALIGN(layer_size_B, 0x800); + + image->size_B = (uint64_t)image->array_stride_B * image->extent_px.a; + + return true; +} diff --git a/src/nouveau/nil/nil_image.h b/src/nouveau/nil/nil_image.h new file mode 100644 index 0000000..e1d79df --- /dev/null +++ b/src/nouveau/nil/nil_image.h @@ -0,0 +1,112 @@ +#ifndef NIL_H +#define NIL_H + +#include +#include +#include + +#include "util/macros.h" +#include "util/format/u_format.h" + +struct nouveau_ws_device; + +enum PACKED nil_image_dim { + NIL_IMAGE_DIM_1D = 1, + NIL_IMAGE_DIM_2D = 2, + NIL_IMAGE_DIM_3D = 3, +}; + +enum nil_image_usage_flags { + NIL_IMAGE_USAGE_RENDER_TARGET_BIT = BITFIELD_BIT(0), + NIL_IMAGE_USAGE_DEPTH_BIT = BITFIELD_BIT(1), + NIL_IMAGE_USAGE_STENCIL_BIT = BITFIELD_BIT(2), + NIL_IMAGE_USAGE_TEXTURE_BIT = BITFIELD_BIT(3), + NIL_IMAGE_USAGE_STORAGE_BIT = BITFIELD_BIT(4), + NIL_IMAGE_USAGE_CUBE_BIT = BITFIELD_BIT(5), + NIL_IMAGE_USAGE_2D_VIEW_BIT = BITFIELD_BIT(6), +}; + +struct nil_extent4d { + union { uint32_t w, width; }; + union { uint32_t h, height; }; + union { uint32_t d, depth; }; + union { uint32_t a, array_len; }; +}; + +static inline struct nil_extent4d +nil_extent4d(uint32_t w, uint32_t h, uint32_t d, uint32_t a) +{ + struct nil_extent4d e; + e.w = w; + e.h = h; + e.d = d; + e.a = a; + return e; +} + +#define NIL_GOB_WIDTH_B 64 +#define NIL_GOB_HEIGHT(gob_height_8) ((gob_height_8) ? 8 : 4) +#define NIL_GOB_DEPTH 1 +#define NIL_MAX_LEVELS 16 + +struct nil_tiling { + bool is_tiled:1; + bool gob_height_8:1; /**< GOB height is 4 or 8 */ + uint8_t y_log2:3; /**< log2 of the Y tile dimension in GOBs */ + uint8_t z_log2:3; /**< log2 of the Z tile dimension in GOBs */ +}; + +struct nil_image_init_info { + enum nil_image_dim dim; + enum pipe_format format; + + struct nil_extent4d extent_px; + uint32_t levels; + uint32_t samples; + + enum nil_image_usage_flags usage; +}; + +/** Represents the data layout of a single slice (level+lod) of an image */ +struct nil_image_level { + /** Offset into the image of this level in bytes */ + uint64_t offset_B; + + /** Tiling for this level */ + struct nil_tiling tiling; + + /** Stride between rows in bytes */ + uint32_t row_stride_B; +}; + +struct nil_image { + enum nil_image_dim dim; + enum pipe_format format; + + struct nil_extent4d extent_px; + uint8_t num_levels; + uint8_t mip_tail_start; + uint8_t num_samples; + + struct nil_image_level levels[NIL_MAX_LEVELS]; + + uint32_t array_stride_B; + + uint64_t size_B; +}; + +bool nil_image_init(struct nouveau_ws_device *dev, + struct nil_image *image, + const struct nil_image_init_info *restrict info); + +static inline uint64_t +nil_image_level_layer_offset_B(const struct nil_image *image, + uint32_t level, uint32_t layer) +{ + assert(level < image->num_levels); + assert(layer < image->extent_px.array_len); + return image->levels[level].offset_B + (layer * image->array_stride_B); +} + + +#endif /* NIL_H */ -- 2.7.4