mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 05:18:08 +02:00
nil: Create images
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24326>
This commit is contained in:
parent
13abd1dbf2
commit
69967e3f0d
5 changed files with 313 additions and 14 deletions
|
|
@ -19,8 +19,8 @@
|
|||
# SOFTWARE.
|
||||
|
||||
libnil_files = files(
|
||||
'nil.c',
|
||||
'nil.h',
|
||||
'nil_image.c',
|
||||
'nil_image.h',
|
||||
)
|
||||
|
||||
_libnil = static_library(
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
#include "nil.h"
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef NIL_H
|
||||
#define NIL_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util/macros.h"
|
||||
#include "util/format/u_format.h"
|
||||
|
||||
#endif /* NIL_H */
|
||||
199
src/nouveau/nil/nil_image.c
Normal file
199
src/nouveau/nil/nil_image.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
112
src/nouveau/nil/nil_image.h
Normal file
112
src/nouveau/nil/nil_image.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
#ifndef NIL_H
|
||||
#define NIL_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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 */
|
||||
Loading…
Add table
Reference in a new issue