nil: Rewrite the TIC code in Rust

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27397>
This commit is contained in:
Daniel Almeida 2024-04-05 20:23:52 -05:00 committed by Marge Bot
parent d5b7dd6ce5
commit 5577128c83
9 changed files with 671 additions and 700 deletions

View file

@ -51,6 +51,10 @@ _libbitview_rs = static_library(
rust_args : nak_rust_args, rust_args : nak_rust_args,
) )
idep_bitview_rs = declare_dependency(
link_with : _libbitview_rs,
)
libnak_deps = [ libnak_deps = [
idep_mesautil, idep_mesautil,
idep_nir_headers, idep_nir_headers,

View file

@ -55,14 +55,18 @@ impl Format {
} }
} }
fn info(&self) -> &nil_format_info { pub(crate) fn info(&self) -> &nil_format_info {
unsafe { &nil_format_table[self.p_format as usize] } unsafe { &nil_format_table[self.p_format as usize] }
} }
pub fn is_integer(&self) -> bool { pub(crate) fn is_integer(&self) -> bool {
unsafe { util_format_is_pure_integer((*self).into()) } unsafe { util_format_is_pure_integer((*self).into()) }
} }
pub(crate) fn is_srgb(&self) -> bool {
self.description().colorspace == UTIL_FORMAT_COLORSPACE_SRGB
}
pub fn supports_texturing(&self, dev: &nv_device_info) -> bool { pub fn supports_texturing(&self, dev: &nv_device_info) -> bool {
if self.info().support() & NIL_FORMAT_SUPPORTS_TEXTURE_BIT == 0 { if self.info().support() & NIL_FORMAT_SUPPORTS_TEXTURE_BIT == 0 {
return false; return false;
@ -83,7 +87,7 @@ impl Format {
self.supports_texturing(dev) && !self.is_integer() self.supports_texturing(dev) && !self.is_integer()
} }
pub fn supports_buffer(&self, _dev: &nv_device_info) -> bool { pub fn supports_buffer(&self) -> bool {
self.info().support() & NIL_FORMAT_SUPPORTS_BUFFER_BIT != 0 self.info().support() & NIL_FORMAT_SUPPORTS_BUFFER_BIT != 0
} }
@ -128,10 +132,10 @@ pub extern "C" fn nil_format_supports_filtering(
#[no_mangle] #[no_mangle]
pub extern "C" fn nil_format_supports_buffer( pub extern "C" fn nil_format_supports_buffer(
dev: &nv_device_info, _dev: &nv_device_info,
p_format: pipe_format, p_format: pipe_format,
) -> bool { ) -> bool {
Format::try_from(p_format).is_ok_and(|f| f.supports_buffer(dev)) Format::try_from(p_format).is_ok_and(|f| f.supports_buffer())
} }
#[no_mangle] #[no_mangle]

View file

@ -7,6 +7,7 @@ extern crate nvidia_headers;
mod extent; mod extent;
mod format; mod format;
mod image; mod image;
mod tic;
mod tiling; mod tiling;
pub trait ILog2Ceil { pub trait ILog2Ceil {

View file

@ -14,9 +14,14 @@ endif
prog_cbindgen = find_program('cbindgen', required : false, native : true) prog_cbindgen = find_program('cbindgen', required : false, native : true)
dep_paste = dependency('paste',
version : '>= 1.0.14',
fallback : ['paste', 'dep_paste'],
required : true,
)
libnil_files = files( libnil_files = files(
'nil.h', 'nil.h',
'nil_image_tic.c',
) )
nil_format_table = custom_target( nil_format_table = custom_target(
@ -40,10 +45,13 @@ _libnil_rs_files = files(
'extent.rs', 'extent.rs',
'format.rs', 'format.rs',
'image.rs', 'image.rs',
'tic.rs',
'tiling.rs', 'tiling.rs',
) )
_libnil_rs_deps = [ _libnil_rs_deps = [
dep_paste,
idep_bitview_rs,
idep_nvidia_headers_rs, idep_nvidia_headers_rs,
] ]

View file

@ -14,64 +14,4 @@
#include "nil_rs.h" #include "nil_rs.h"
struct nv_device_info;
enum ENUM_PACKED nil_view_type {
NIL_VIEW_TYPE_1D,
NIL_VIEW_TYPE_2D,
NIL_VIEW_TYPE_3D,
NIL_VIEW_TYPE_3D_SLICED,
NIL_VIEW_TYPE_CUBE,
NIL_VIEW_TYPE_1D_ARRAY,
NIL_VIEW_TYPE_2D_ARRAY,
NIL_VIEW_TYPE_CUBE_ARRAY,
};
struct nil_view {
enum nil_view_type type;
/**
* The format to use in the view
*
* This may differ from the format of the actual isl_surf but must have
* the same block size.
*/
enum pipe_format format;
uint32_t base_level;
uint32_t num_levels;
/**
* Base array layer
*
* For cube maps, both base_array_layer and array_len should be
* specified in terms of 2-D layers and must be a multiple of 6.
*/
uint32_t base_array_layer;
/**
* Array Length
*
* Indicates the number of array elements starting at Base Array Layer.
*/
uint32_t array_len;
enum pipe_swizzle swizzle[4];
/* VK_EXT_image_view_min_lod */
float min_lod_clamp;
};
void nil_image_fill_tic(struct nv_device_info *dev,
const struct nil_image *image,
const struct nil_view *view,
uint64_t base_address,
void *desc_out);
void nil_buffer_fill_tic(struct nv_device_info *dev,
uint64_t base_address,
enum pipe_format format,
uint32_t num_elements,
void *desc_out);
#endif /* NIL_H */ #endif /* NIL_H */

View file

@ -1,620 +0,0 @@
/*
* Copyright © 2022 Collabora Ltd.
* SPDX-License-Identifier: MIT
*/
#include "nil.h"
#include "nil_format_table.h"
#include "util/bitpack_helpers.h"
#include "nouveau_device.h"
#include "cl9097.h"
#include "cl9097tex.h"
#include "clb097.h"
#include "clb097tex.h"
#include "clc097.h"
#include "clc097tex.h"
#include "drf.h"
ALWAYS_INLINE static void
__set_u32(uint32_t *o, uint32_t v, unsigned lo, unsigned hi)
{
assert(lo <= hi && (lo / 32) == (hi / 32));
o[lo / 32] |= util_bitpack_uint(v, lo % 32, hi % 32);
}
#define FIXED_FRAC_BITS 8
ALWAYS_INLINE static void
__set_ufixed(uint32_t *o, float v, unsigned lo, unsigned hi)
{
assert(lo <= hi && (lo / 32) == (hi / 32));
o[lo / 32] |= util_bitpack_ufixed_clamp(v, lo % 32, hi % 32,
FIXED_FRAC_BITS);
}
ALWAYS_INLINE static void
__set_i32(uint32_t *o, int32_t v, unsigned lo, unsigned hi)
{
assert(lo <= hi && (lo / 32) == (hi / 32));
o[lo / 32] |= util_bitpack_sint(v, lo % 32, hi % 32);
}
ALWAYS_INLINE static void
__set_bool(uint32_t *o, bool b, unsigned lo, unsigned hi)
{
assert(lo == hi);
o[lo / 32] |= util_bitpack_uint(b, lo % 32, hi % 32);
}
#define MW(x) x
#define TH_SET_U(o, NV, VER, FIELD, val) \
__set_u32((o), (val), DRF_LO(NV##_TEXHEAD##VER##_##FIELD),\
DRF_HI(NV##_TEXHEAD##VER##_##FIELD))
#define TH_SET_UF(o, NV, VER, FIELD, val) \
__set_ufixed((o), (val), DRF_LO(NV##_TEXHEAD##VER##_##FIELD),\
DRF_HI(NV##_TEXHEAD##VER##_##FIELD))
#define TH_SET_I(o, NV, VER, FIELD, val) \
__set_i32((o), (val), DRF_LO(NV##_TEXHEAD##VER##_##FIELD),\
DRF_HI(NV##_TEXHEAD##VER##_##FIELD))
#define TH_SET_B(o, NV, VER, FIELD, b) \
__set_bool((o), (b), DRF_LO(NV##_TEXHEAD##VER##_##FIELD),\
DRF_HI(NV##_TEXHEAD##VER##_##FIELD))
#define TH_SET_E(o, NV, VER, FIELD, E) \
TH_SET_U((o), NV, VER, FIELD, NV##_TEXHEAD##VER##_##FIELD##_##E)
#define TH_NV9097_SET_U(o, IDX, FIELD, val) \
TH_SET_U(&(o)[IDX], NV9097, V2_##IDX, FIELD, (val));
#define TH_NV9097_SET_UF(o, IDX, FIELD, val) \
TH_SET_UF(&(o)[IDX], NV9097, V2_##IDX, FIELD, (val));
#define TH_NV9097_SET_I(o, IDX, FIELD, val) \
TH_SET_I(&(o)[IDX], NV9097, V2_##IDX, FIELD, (val));
#define TH_NV9097_SET_B(o, IDX, FIELD, b) \
TH_SET_B(&(o)[IDX], NV9097, V2_##IDX, FIELD, (b));
#define TH_NV9097_SET_E(o, IDX, FIELD, E) \
TH_SET_E(&(o)[IDX], NV9097, V2_##IDX, FIELD, E);
#define TH_NVB097_SET_U(o, VER, FIELD, val) \
TH_SET_U((o), NVB097, _##VER, FIELD, (val));
#define TH_NVB097_SET_UF(o, VER, FIELD, val) \
TH_SET_UF((o), NVB097, _##VER, FIELD, (val));
#define TH_NVB097_SET_I(o, VER, FIELD, val) \
TH_SET_I((o), NVB097, _##VER, FIELD, (val));
#define TH_NVB097_SET_B(o, VER, FIELD, b) \
TH_SET_B((o), NVB097, _##VER, FIELD, (b));
#define TH_NVB097_SET_E(o, VER, FIELD, E) \
TH_SET_E((o), NVB097, _##VER, FIELD, E);
#define TH_NVC097_SET_U(o, VER, FIELD, val) \
TH_SET_U((o), NVC097, _##VER, FIELD, (val));
static const struct nil_tic_format *
nil_tic_format_for_pipe(enum pipe_format format)
{
assert(format < PIPE_FORMAT_COUNT);
const struct nil_format_info *fmt = &nil_format_table[format];
return fmt->tic.comp_sizes == 0 ? NULL : &fmt->tic;
}
static inline uint32_t
nv9097_th_bl_source(const struct nil_tic_format *fmt,
enum pipe_swizzle swz, bool is_int)
{
switch (swz) {
case PIPE_SWIZZLE_X: return fmt->src_x;
case PIPE_SWIZZLE_Y: return fmt->src_y;
case PIPE_SWIZZLE_Z: return fmt->src_z;
case PIPE_SWIZZLE_W: return fmt->src_w;
case PIPE_SWIZZLE_0:
return NV9097_TEXHEADV2_0_X_SOURCE_IN_ZERO;
case PIPE_SWIZZLE_1:
return is_int ? NV9097_TEXHEADV2_0_X_SOURCE_IN_ONE_INT :
NV9097_TEXHEADV2_0_X_SOURCE_IN_ONE_FLOAT;
default:
unreachable("Invalid component swizzle");
}
}
static inline uint32_t
nvb097_th_bl_source(const struct nil_tic_format *fmt,
enum pipe_swizzle swz, bool is_int)
{
switch (swz) {
case PIPE_SWIZZLE_X: return fmt->src_x;
case PIPE_SWIZZLE_Y: return fmt->src_y;
case PIPE_SWIZZLE_Z: return fmt->src_z;
case PIPE_SWIZZLE_W: return fmt->src_w;
case PIPE_SWIZZLE_0:
return NVB097_TEXHEAD_BL_X_SOURCE_IN_ZERO;
case PIPE_SWIZZLE_1:
return is_int ? NVB097_TEXHEAD_BL_X_SOURCE_IN_ONE_INT :
NVB097_TEXHEAD_BL_X_SOURCE_IN_ONE_FLOAT;
default:
unreachable("Invalid component swizzle");
}
}
static uint32_t
nv9097_th_bl_0(enum pipe_format format, const enum pipe_swizzle swizzle[4])
{
const struct nil_tic_format *fmt = nil_tic_format_for_pipe(format);
const bool is_int = util_format_is_pure_integer(format);
uint32_t source[4];
for (unsigned i = 0; i < 4; i++)
source[i] = nvb097_th_bl_source(fmt, swizzle[i], is_int);
uint32_t th_0 = 0;
TH_NV9097_SET_U(&th_0, 0, COMPONENT_SIZES, fmt->comp_sizes);
TH_NV9097_SET_U(&th_0, 0, R_DATA_TYPE, fmt->type_r);
TH_NV9097_SET_U(&th_0, 0, G_DATA_TYPE, fmt->type_g);
TH_NV9097_SET_U(&th_0, 0, B_DATA_TYPE, fmt->type_b);
TH_NV9097_SET_U(&th_0, 0, A_DATA_TYPE, fmt->type_a);
TH_NV9097_SET_U(&th_0, 0, X_SOURCE, source[0]);
TH_NV9097_SET_U(&th_0, 0, Y_SOURCE, source[1]);
TH_NV9097_SET_U(&th_0, 0, Z_SOURCE, source[2]);
TH_NV9097_SET_U(&th_0, 0, W_SOURCE, source[3]);
return th_0;
}
static uint32_t
nvb097_th_bl_0(enum pipe_format format, const enum pipe_swizzle swizzle[4])
{
const struct nil_tic_format *fmt = nil_tic_format_for_pipe(format);
const bool is_int = util_format_is_pure_integer(format);
uint32_t source[4];
for (unsigned i = 0; i < 4; i++)
source[i] = nvb097_th_bl_source(fmt, swizzle[i], is_int);
uint32_t th_0 = 0;
TH_NVB097_SET_U(&th_0, BL, COMPONENTS, fmt->comp_sizes);
TH_NVB097_SET_U(&th_0, BL, R_DATA_TYPE, fmt->type_r);
TH_NVB097_SET_U(&th_0, BL, G_DATA_TYPE, fmt->type_g);
TH_NVB097_SET_U(&th_0, BL, B_DATA_TYPE, fmt->type_b);
TH_NVB097_SET_U(&th_0, BL, A_DATA_TYPE, fmt->type_a);
TH_NVB097_SET_U(&th_0, BL, X_SOURCE, source[0]);
TH_NVB097_SET_U(&th_0, BL, Y_SOURCE, source[1]);
TH_NVB097_SET_U(&th_0, BL, Z_SOURCE, source[2]);
TH_NVB097_SET_U(&th_0, BL, W_SOURCE, source[3]);
return th_0;
}
static uint32_t
pipe_to_nv_texture_type(enum nil_view_type type)
{
#define CASE(NIL, NV) \
case NIL_VIEW_TYPE_##NIL: return NVB097_TEXHEAD_BL_TEXTURE_TYPE_##NV; \
STATIC_ASSERT(NVB097_TEXHEAD_BL_TEXTURE_TYPE_##NV == NV9097_TEXHEADV2_2_TEXTURE_TYPE_##NV);
switch (type) {
CASE(1D, ONE_D);
CASE(2D, TWO_D);
CASE(3D, THREE_D);
CASE(3D_SLICED, THREE_D);
CASE(CUBE, CUBEMAP);
CASE(1D_ARRAY, ONE_D_ARRAY);
CASE(2D_ARRAY, TWO_D_ARRAY);
CASE(CUBE_ARRAY, CUBEMAP_ARRAY);
default: unreachable("Invalid image view type");
}
#undef CASE
}
static uint32_t
nil_to_nv9097_multi_sample_count(enum nil_sample_layout sample_layout)
{
#define CASE(SIZE) \
case NIL_SAMPLE_LAYOUT_##SIZE: \
return NV9097_TEXHEADV2_7_MULTI_SAMPLE_COUNT_MODE_##SIZE
switch (sample_layout) {
CASE(1X1);
CASE(2X1);
CASE(2X2);
CASE(4X2);
CASE(4X4);
default:
unreachable("Invalid sample layout");
}
#undef CASE
}
static uint32_t
nil_to_nvb097_multi_sample_count(enum nil_sample_layout sample_layout)
{
#define CASE(SIZE) \
case NIL_SAMPLE_LAYOUT_##SIZE: \
return NVB097_TEXHEAD_BL_MULTI_SAMPLE_COUNT_MODE_##SIZE
switch (sample_layout) {
CASE(1X1);
CASE(2X1);
CASE(2X2);
CASE(4X2);
CASE(4X4);
default:
unreachable("Invalid sample layout");
}
#undef CASE
}
static inline uint32_t
nil_max_mip_level(const struct nil_image *image,
const struct nil_view *view)
{
if (view->type != NIL_VIEW_TYPE_3D && view->array_len == 1 &&
view->base_level == 0 && view->num_levels == 1) {
/* The Unnormalized coordinates bit in the sampler gets ignored if the
* referenced image has more than one miplevel. Fortunately, Vulkan has
* restrictions requiring the view to be a single-layer single-LOD view
* in order to use nonnormalizedCoordinates = VK_TRUE in the sampler.
* From the Vulkan 1.3.255 spec:
*
* "When unnormalizedCoordinates is VK_TRUE, images the sampler is
* used with in the shader have the following requirements:
*
* - The viewType must be either VK_IMAGE_VIEW_TYPE_1D or
* VK_IMAGE_VIEW_TYPE_2D.
* - The image view must have a single layer and a single mip
* level."
*
* Under these conditions, the view is simply LOD 0 of a single array
* slice so we don't need to care about aray stride between slices so
* it's safe to set the number of miplevels to 0 regardless of how many
* the image actually has.
*/
return 0;
} else {
return image->num_levels - 1;
}
}
static struct nil_extent4d
nil_normalize_extent(const struct nil_image *image,
const struct nil_view *view)
{
struct nil_extent4d extent;
extent.width = image->extent_px.width;
extent.height = image->extent_px.height;
extent.array_len = 0;
switch (view->type) {
case NIL_VIEW_TYPE_1D:
case NIL_VIEW_TYPE_1D_ARRAY:
case NIL_VIEW_TYPE_2D:
case NIL_VIEW_TYPE_2D_ARRAY:
assert(image->extent_px.depth == 1);
extent.depth = view->array_len;
break;
case NIL_VIEW_TYPE_CUBE:
case NIL_VIEW_TYPE_CUBE_ARRAY:
assert(image->dim == NIL_IMAGE_DIM_2D);
assert(view->array_len % 6 == 0);
extent.depth = view->array_len / 6;
break;
case NIL_VIEW_TYPE_3D:
assert(image->dim == NIL_IMAGE_DIM_3D);
extent.depth = image->extent_px.depth;
break;
case NIL_VIEW_TYPE_3D_SLICED:
assert(image->dim == NIL_IMAGE_DIM_3D);
extent.depth = view->array_len;
break;
default:
unreachable("Unsupported image view target");
};
return extent;
}
static void
nv9097_nil_image_fill_tic(const struct nil_image *image,
const struct nil_view *view,
uint64_t base_address,
void *desc_out)
{
assert(util_format_get_blocksize(image->format.p_format) ==
util_format_get_blocksize(view->format));
assert(view->base_level + view->num_levels <= image->num_levels);
assert(view->base_array_layer + view->array_len <=
image->extent_px.array_len);
uint32_t th[8] = { };
TH_NV9097_SET_B(th, 4, USE_TEXTURE_HEADER_VERSION2, true);
th[0] = nv9097_th_bl_0(view->format, view->swizzle);
/* There's no base layer field in the texture header */
const uint64_t layer_address =
base_address + view->base_array_layer * image->array_stride_B;
TH_NV9097_SET_U(th, 1, OFFSET_LOWER, layer_address & 0xffffffff);
TH_NV9097_SET_U(th, 2, OFFSET_UPPER, layer_address >> 32);
const struct nil_tiling *tiling = &image->levels[0].tiling;
if (tiling->is_tiled) {
TH_NV9097_SET_E(th, 2, MEMORY_LAYOUT, BLOCKLINEAR);
assert(tiling->gob_height_is_8);
assert(tiling->x_log2 == 0);
TH_NV9097_SET_E(th, 2, GOBS_PER_BLOCK_WIDTH, ONE_GOB);
TH_NV9097_SET_U(th, 2, GOBS_PER_BLOCK_HEIGHT, tiling->y_log2);
TH_NV9097_SET_U(th, 2, GOBS_PER_BLOCK_DEPTH, tiling->z_log2);
TH_NV9097_SET_U(th, 2, TEXTURE_TYPE, pipe_to_nv_texture_type(view->type));
} else {
TH_NV9097_SET_E(th, 2, MEMORY_LAYOUT, PITCH);
uint32_t pitch = image->levels[0].row_stride_B;
TH_NV9097_SET_U(th, 3, PITCH, pitch);
assert(view->type == NIL_VIEW_TYPE_2D ||
view->type == NIL_VIEW_TYPE_2D_ARRAY);
assert(image->sample_layout == NIL_SAMPLE_LAYOUT_1X1);
assert(view->num_levels == 1);
TH_NV9097_SET_E(th, 2, TEXTURE_TYPE, TWO_D_NO_MIPMAP);
}
TH_NV9097_SET_E(th, 3, LOD_ANISO_QUALITY, LOD_QUALITY_HIGH);
TH_NV9097_SET_E(th, 3, LOD_ISO_QUALITY, LOD_QUALITY_HIGH);
TH_NV9097_SET_E(th, 3, ANISO_COARSE_SPREAD_MODIFIER, SPREAD_MODIFIER_NONE);
const struct nil_extent4d extent = nil_normalize_extent(image, view);
TH_NV9097_SET_U(th, 4, WIDTH, extent.width);
TH_NV9097_SET_U(th, 5, HEIGHT, extent.height);
TH_NV9097_SET_U(th, 5, DEPTH, extent.depth);
TH_NV9097_SET_U(th, 5, MAX_MIP_LEVEL, nil_max_mip_level(image, view));
TH_NV9097_SET_B(th, 2, S_R_G_B_CONVERSION,
util_format_is_srgb(view->format));
TH_NV9097_SET_E(th, 2, BORDER_SOURCE, BORDER_COLOR);
/* In the sampler, the two options for FLOAT_COORD_NORMALIZATION are:
*
* - FORCE_UNNORMALIZED_COORDS
* - USE_HEADER_SETTING
*
* So we set it to normalized in the header and let the sampler select
* that or force non-normalized.
*/
TH_NV9097_SET_B(th, 2, NORMALIZED_COORDS, true);
TH_NV9097_SET_E(th, 6, ANISO_FINE_SPREAD_FUNC, SPREAD_FUNC_TWO);
TH_NV9097_SET_E(th, 6, ANISO_COARSE_SPREAD_FUNC, SPREAD_FUNC_ONE);
TH_NV9097_SET_U(th, 7, RES_VIEW_MIN_MIP_LEVEL, view->base_level);
TH_NV9097_SET_U(th, 7, RES_VIEW_MAX_MIP_LEVEL,
view->num_levels + view->base_level - 1);
TH_NV9097_SET_U(th, 7, MULTI_SAMPLE_COUNT,
nil_to_nv9097_multi_sample_count(image->sample_layout));
TH_NV9097_SET_UF(th, 7, MIN_LOD_CLAMP,
view->min_lod_clamp - view->base_level);
memcpy(desc_out, th, sizeof(th));
}
static void
nvb097_nil_image_fill_tic(struct nv_device_info *dev,
const struct nil_image *image,
const struct nil_view *view,
uint64_t base_address,
void *desc_out)
{
assert(util_format_get_blocksize(image->format.p_format) ==
util_format_get_blocksize(view->format));
assert(view->base_level + view->num_levels <= image->num_levels);
uint32_t th[8] = { };
th[0] = nvb097_th_bl_0(view->format, view->swizzle);
const struct nil_tiling *tiling = &image->levels[0].tiling;
/* There's no base layer field in the texture header */
uint64_t layer_address = base_address;
if (view->type == NIL_VIEW_TYPE_3D_SLICED) {
assert(image->num_levels == 1);
assert(view->base_array_layer + view->array_len <=
image->extent_px.depth);
layer_address += nil_image_level_z_offset_B(image, view->base_level,
view->base_array_layer);
} else {
assert(view->base_array_layer + view->array_len <=
image->extent_px.array_len);
layer_address += view->base_array_layer * image->array_stride_B;
}
if (tiling->is_tiled) {
TH_NVB097_SET_E(th, BL, HEADER_VERSION, SELECT_BLOCKLINEAR);
assert((layer_address & BITFIELD_MASK(9)) == 0);
TH_NVB097_SET_U(th, BL, ADDRESS_BITS31TO9, (uint32_t)layer_address >> 9);
TH_NVB097_SET_U(th, BL, ADDRESS_BITS47TO32, layer_address >> 32);
assert(tiling->gob_height_is_8);
TH_NVB097_SET_E(th, BL, GOBS_PER_BLOCK_WIDTH, ONE_GOB);
TH_NVB097_SET_U(th, BL, GOBS_PER_BLOCK_HEIGHT, tiling->y_log2);
TH_NVB097_SET_U(th, BL, GOBS_PER_BLOCK_DEPTH, tiling->z_log2);
TH_NVB097_SET_U(th, BL, TILE_WIDTH_IN_GOBS, tiling->x_log2);
TH_NVB097_SET_U(th, BL, TEXTURE_TYPE, pipe_to_nv_texture_type(view->type));
} else {
TH_NVB097_SET_E(th, PITCH, HEADER_VERSION, SELECT_PITCH);
assert((layer_address & BITFIELD_MASK(5)) == 0);
TH_NVB097_SET_U(th, PITCH, ADDRESS_BITS31TO5,
(uint32_t)layer_address >> 5);
TH_NVB097_SET_U(th, PITCH, ADDRESS_BITS47TO32,
layer_address >> 32);
uint32_t pitch = image->levels[0].row_stride_B;
assert((pitch & BITFIELD_MASK(5)) == 0);
TH_NVB097_SET_U(th, PITCH, PITCH_BITS20TO5, pitch >> 5);
assert(view->type == NIL_VIEW_TYPE_2D ||
view->type == NIL_VIEW_TYPE_2D_ARRAY);
assert(image->sample_layout == NIL_SAMPLE_LAYOUT_1X1);
assert(view->num_levels == 1);
TH_NVB097_SET_E(th, PITCH, TEXTURE_TYPE, TWO_D_NO_MIPMAP);
}
TH_NVB097_SET_B(th, BL, LOD_ANISO_QUALITY2, true);
TH_NVB097_SET_E(th, BL, LOD_ANISO_QUALITY, LOD_QUALITY_HIGH);
TH_NVB097_SET_E(th, BL, LOD_ISO_QUALITY, LOD_QUALITY_HIGH);
TH_NVB097_SET_E(th, BL, ANISO_COARSE_SPREAD_MODIFIER, SPREAD_MODIFIER_NONE);
const struct nil_extent4d extent = nil_normalize_extent(image, view);
TH_NVB097_SET_U(th, BL, WIDTH_MINUS_ONE, extent.width - 1);
if (dev->cls_eng3d >= PASCAL_A) {
const uint32_t height_1 = extent.height - 1;
const uint32_t depth_1 = extent.depth - 1;
TH_NVC097_SET_U(th, BL, HEIGHT_MINUS_ONE, height_1 & BITFIELD_MASK(16));
TH_NVC097_SET_U(th, BL, HEIGHT_MINUS_ONE_BIT16, height_1 >> 16);
TH_NVC097_SET_U(th, BL, DEPTH_MINUS_ONE, depth_1 & BITFIELD_MASK(14));
TH_NVC097_SET_U(th, BL, DEPTH_MINUS_ONE_BIT14, depth_1 >> 14);
} else {
TH_NVB097_SET_U(th, BL, HEIGHT_MINUS_ONE, extent.height - 1);
TH_NVB097_SET_U(th, BL, DEPTH_MINUS_ONE, extent.depth - 1);
}
TH_NVB097_SET_U(th, BL, MAX_MIP_LEVEL, nil_max_mip_level(image, view));
TH_NVB097_SET_B(th, BL, S_R_G_B_CONVERSION,
util_format_is_srgb(view->format));
TH_NVB097_SET_E(th, BL, SECTOR_PROMOTION, PROMOTE_TO_2_V);
TH_NVB097_SET_E(th, BL, BORDER_SIZE, BORDER_SAMPLER_COLOR);
/* In the sampler, the two options for FLOAT_COORD_NORMALIZATION are:
*
* - FORCE_UNNORMALIZED_COORDS
* - USE_HEADER_SETTING
*
* So we set it to normalized in the header and let the sampler select
* that or force non-normalized.
*/
TH_NVB097_SET_B(th, BL, NORMALIZED_COORDS, true);
TH_NVB097_SET_E(th, BL, ANISO_FINE_SPREAD_FUNC, SPREAD_FUNC_TWO);
TH_NVB097_SET_E(th, BL, ANISO_COARSE_SPREAD_FUNC, SPREAD_FUNC_ONE);
TH_NVB097_SET_U(th, BL, RES_VIEW_MIN_MIP_LEVEL, view->base_level);
TH_NVB097_SET_U(th, BL, RES_VIEW_MAX_MIP_LEVEL,
view->num_levels + view->base_level - 1);
TH_NVB097_SET_U(th, BL, MULTI_SAMPLE_COUNT,
nil_to_nvb097_multi_sample_count(image->sample_layout));
TH_NVB097_SET_UF(th, BL, MIN_LOD_CLAMP,
view->min_lod_clamp - view->base_level);
memcpy(desc_out, th, sizeof(th));
}
static const enum pipe_swizzle IDENTITY_SWIZZLE[4] = {
PIPE_SWIZZLE_X,
PIPE_SWIZZLE_Y,
PIPE_SWIZZLE_Z,
PIPE_SWIZZLE_W,
};
static void
nv9097_nil_buffer_fill_tic(uint64_t base_address,
enum pipe_format format,
uint32_t num_elements,
void *desc_out)
{
uint32_t th[8] = { };
TH_NV9097_SET_B(th, 4, USE_TEXTURE_HEADER_VERSION2, true);
assert(!util_format_is_compressed(format));
th[0] = nv9097_th_bl_0(format, IDENTITY_SWIZZLE);
TH_NV9097_SET_U(th, 1, OFFSET_LOWER, base_address);
TH_NV9097_SET_U(th, 2, OFFSET_UPPER, base_address >> 32);
TH_NV9097_SET_E(th, 2, MEMORY_LAYOUT, PITCH);
TH_NV9097_SET_U(th, 4, WIDTH, num_elements);
TH_NV9097_SET_E(th, 2, TEXTURE_TYPE, ONE_D_BUFFER);
memcpy(desc_out, th, sizeof(th));
}
static void
nvb097_nil_buffer_fill_tic(uint64_t base_address,
enum pipe_format format,
uint32_t num_elements,
void *desc_out)
{
uint32_t th[8] = { };
assert(!util_format_is_compressed(format));
th[0] = nvb097_th_bl_0(format, IDENTITY_SWIZZLE);
TH_NVB097_SET_U(th, 1D, ADDRESS_BITS31TO0, base_address);
TH_NVB097_SET_U(th, 1D, ADDRESS_BITS47TO32, base_address >> 32);
TH_NVB097_SET_E(th, 1D, HEADER_VERSION, SELECT_ONE_D_BUFFER);
TH_NVB097_SET_U(th, 1D, WIDTH_MINUS_ONE_BITS15TO0,
(num_elements - 1) & 0xffff);
TH_NVB097_SET_U(th, 1D, WIDTH_MINUS_ONE_BITS31TO16,
(num_elements - 1) >> 16);
TH_NVB097_SET_E(th, 1D, TEXTURE_TYPE, ONE_D_BUFFER);
/* TODO: Do we need this? */
TH_NVB097_SET_E(th, 1D, SECTOR_PROMOTION, PROMOTE_TO_2_V);
memcpy(desc_out, th, sizeof(th));
}
void
nil_image_fill_tic(struct nv_device_info *dev,
const struct nil_image *image,
const struct nil_view *view,
uint64_t base_address,
void *desc_out)
{
if (dev->cls_eng3d >= MAXWELL_A) {
nvb097_nil_image_fill_tic(dev, image, view, base_address, desc_out);
} else if (dev->cls_eng3d >= FERMI_A) {
nv9097_nil_image_fill_tic(image, view, base_address, desc_out);
} else {
unreachable("Tesla and older not supported");
}
}
void
nil_buffer_fill_tic(struct nv_device_info *dev,
uint64_t base_address,
enum pipe_format format,
uint32_t num_elements,
void *desc_out)
{
if (dev->cls_eng3d >= MAXWELL_A) {
nvb097_nil_buffer_fill_tic(base_address, format, num_elements, desc_out);
} else if (dev->cls_eng3d >= FERMI_A) {
nv9097_nil_buffer_fill_tic(base_address, format, num_elements, desc_out);
} else {
unreachable("Tesla and older not supported");
}
}

633
src/nouveau/nil/tic.rs Normal file
View file

@ -0,0 +1,633 @@
// Copyright © 2024 Collabora, Ltd.
// SPDX-License-Identifier: MIT
#![allow(unused_macros)]
extern crate bitview;
extern crate nvidia_headers;
use bitview::*;
use nil_rs_bindings::*;
use nvidia_headers::cl9097::tex as cl9097;
use nvidia_headers::cl9097::FERMI_A;
use nvidia_headers::clb097::tex as clb097;
use nvidia_headers::clb097::MAXWELL_A;
use nvidia_headers::clc097::tex as clc097;
use nvidia_headers::clc097::PASCAL_A;
use paste::paste;
use std::ops::Range;
use crate::extent::Extent4D;
use crate::format::Format;
use crate::image::Image;
use crate::image::ImageDim;
use crate::image::SampleLayout;
use crate::image::View;
use crate::image::ViewType;
macro_rules! set_enum {
($th:expr, $cls:ident, $field:ident, $enum:ident) => {
paste! {
$th.set_field($cls::$field, $cls::[<$field _ $enum>])
}
};
}
trait SetUFixed {
fn set_ufixed(&mut self, range: Range<usize>, val: f32);
}
const FIXED_FRAC_BITS: u32 = 8;
impl<T: SetFieldU64> SetUFixed for T {
fn set_ufixed(&mut self, range: Range<usize>, val: f32) {
assert!(range.len() >= FIXED_FRAC_BITS as usize);
let scaled = val * ((1 << FIXED_FRAC_BITS) as f32);
let scaled_max = ((1 << range.len()) - 1) as f32;
let u_val = scaled.clamp(0.0, scaled_max).round() as u32;
self.set_field(range, u_val);
}
}
fn nv9097_th_v2_source(
fmt: &nil_tic_format,
swizzle: pipe_swizzle,
is_int: bool,
) -> u32 {
match swizzle {
PIPE_SWIZZLE_X => fmt.src_x(),
PIPE_SWIZZLE_Y => fmt.src_y(),
PIPE_SWIZZLE_Z => fmt.src_z(),
PIPE_SWIZZLE_W => fmt.src_w(),
PIPE_SWIZZLE_0 => cl9097::TEXHEADV2_X_SOURCE_IN_ZERO,
PIPE_SWIZZLE_1 => {
if is_int {
cl9097::TEXHEADV2_X_SOURCE_IN_ONE_INT
} else {
cl9097::TEXHEADV2_X_SOURCE_IN_ONE_FLOAT
}
}
other => panic!("Invalid component swizzle {}", other),
}
}
fn nvb097_th_bl_source(
fmt: &nil_tic_format,
swizzle: pipe_swizzle,
is_int: bool,
) -> u32 {
match swizzle {
PIPE_SWIZZLE_X => fmt.src_x(),
PIPE_SWIZZLE_Y => fmt.src_y(),
PIPE_SWIZZLE_Z => fmt.src_z(),
PIPE_SWIZZLE_W => fmt.src_w(),
PIPE_SWIZZLE_0 => clb097::TEXHEADV2_X_SOURCE_IN_ZERO,
PIPE_SWIZZLE_1 => {
if is_int {
clb097::TEXHEADV2_X_SOURCE_IN_ONE_INT
} else {
clb097::TEXHEADV2_X_SOURCE_IN_ONE_FLOAT
}
}
other => panic!("Invalid component swizzle {}", other),
}
}
type THBitView<'a> = BitMutView<'a, [u32; 8]>;
fn nv9097_set_th_v2_0<'a>(
th: &mut THBitView<'a>,
format: &Format,
swizzle: [nil_rs_bindings::pipe_swizzle; 4],
) {
let fmt = &format.info().tic;
let is_int = format.is_integer();
let source = [
nv9097_th_v2_source(fmt, swizzle[0], is_int),
nv9097_th_v2_source(fmt, swizzle[1], is_int),
nv9097_th_v2_source(fmt, swizzle[2], is_int),
nv9097_th_v2_source(fmt, swizzle[3], is_int),
];
th.set_field(cl9097::TEXHEADV2_COMPONENT_SIZES, fmt.comp_sizes());
th.set_field(cl9097::TEXHEADV2_R_DATA_TYPE, fmt.type_r());
th.set_field(cl9097::TEXHEADV2_G_DATA_TYPE, fmt.type_g());
th.set_field(cl9097::TEXHEADV2_B_DATA_TYPE, fmt.type_b());
th.set_field(cl9097::TEXHEADV2_A_DATA_TYPE, fmt.type_a());
th.set_field(cl9097::TEXHEADV2_X_SOURCE, source[0]);
th.set_field(cl9097::TEXHEADV2_Y_SOURCE, source[1]);
th.set_field(cl9097::TEXHEADV2_Z_SOURCE, source[2]);
th.set_field(cl9097::TEXHEADV2_W_SOURCE, source[3]);
}
fn nvb097_set_th_bl_0<'a>(
th: &mut THBitView<'a>,
format: &Format,
swizzle: [nil_rs_bindings::pipe_swizzle; 4],
) {
let fmt = &format.info().tic;
let is_int = format.is_integer();
let source = [
nvb097_th_bl_source(fmt, swizzle[0], is_int),
nvb097_th_bl_source(fmt, swizzle[1], is_int),
nvb097_th_bl_source(fmt, swizzle[2], is_int),
nvb097_th_bl_source(fmt, swizzle[3], is_int),
];
th.set_field(clb097::TEXHEAD_BL_COMPONENTS, fmt.comp_sizes());
th.set_field(clb097::TEXHEAD_BL_R_DATA_TYPE, fmt.type_r());
th.set_field(clb097::TEXHEAD_BL_G_DATA_TYPE, fmt.type_g());
th.set_field(clb097::TEXHEAD_BL_B_DATA_TYPE, fmt.type_b());
th.set_field(clb097::TEXHEAD_BL_A_DATA_TYPE, fmt.type_a());
th.set_field(clb097::TEXHEAD_BL_X_SOURCE, source[0]);
th.set_field(clb097::TEXHEAD_BL_Y_SOURCE, source[1]);
th.set_field(clb097::TEXHEAD_BL_Z_SOURCE, source[2]);
th.set_field(clb097::TEXHEAD_BL_W_SOURCE, source[3]);
}
fn pipe_to_nv_texture_type(ty: ViewType) -> u32 {
match ty {
ViewType::_1D => clb097::TEXHEAD_BL_TEXTURE_TYPE_ONE_D,
ViewType::_2D => clb097::TEXHEAD_BL_TEXTURE_TYPE_TWO_D,
ViewType::_3D | ViewType::_3DSliced => {
clb097::TEXHEAD_BL_TEXTURE_TYPE_THREE_D
}
ViewType::Cube => clb097::TEXHEAD_BL_TEXTURE_TYPE_CUBEMAP,
ViewType::_1DArray => clb097::TEXHEAD_BL_TEXTURE_TYPE_ONE_D_ARRAY,
ViewType::_2DArray => clb097::TEXHEAD_BL_TEXTURE_TYPE_TWO_D_ARRAY,
ViewType::CubeArray => clb097::TEXHEAD_BL_TEXTURE_TYPE_CUBEMAP_ARRAY,
}
}
fn nil_rs_to_nv9097_multi_sample_count(sample_layout: SampleLayout) -> u32 {
match sample_layout {
SampleLayout::_1x1 => cl9097::TEXHEADV2_MULTI_SAMPLE_COUNT_MODE_1X1,
SampleLayout::_2x1 => cl9097::TEXHEADV2_MULTI_SAMPLE_COUNT_MODE_2X1,
SampleLayout::_2x2 => cl9097::TEXHEADV2_MULTI_SAMPLE_COUNT_MODE_2X2,
SampleLayout::_4x2 => cl9097::TEXHEADV2_MULTI_SAMPLE_COUNT_MODE_4X2,
SampleLayout::_4x4 => cl9097::TEXHEADV2_MULTI_SAMPLE_COUNT_MODE_4X4,
SampleLayout::Invalid => panic!("Invalid sample layout"),
}
}
fn nil_rs_to_nvb097_multi_sample_count(sample_layout: SampleLayout) -> u32 {
match sample_layout {
SampleLayout::_1x1 => clb097::TEXHEAD_BL_MULTI_SAMPLE_COUNT_MODE_1X1,
SampleLayout::_2x1 => clb097::TEXHEAD_BL_MULTI_SAMPLE_COUNT_MODE_2X1,
SampleLayout::_2x2 => clb097::TEXHEAD_BL_MULTI_SAMPLE_COUNT_MODE_2X2,
SampleLayout::_4x2 => clb097::TEXHEAD_BL_MULTI_SAMPLE_COUNT_MODE_4X2,
SampleLayout::_4x4 => clb097::TEXHEAD_BL_MULTI_SAMPLE_COUNT_MODE_4X4,
SampleLayout::Invalid => panic!("Invalid sample layout"),
}
}
fn nil_rs_max_mip_level(image: &Image, view: &View) -> u32 {
if view.view_type != ViewType::_3D
&& view.array_len == 1
&& view.base_level == 0
&& view.num_levels == 1
{
// The Unnormalized coordinates bit in the sampler gets ignored if the
// referenced image has more than one miplevel. Fortunately, Vulkan has
// restrictions requiring the view to be a single-layer single-LOD view
// in order to use nonnormalizedCoordinates = VK_TRUE in the sampler.
// From the Vulkan 1.3.255 spec:
//
// "When unnormalizedCoordinates is VK_TRUE, images the sampler is
// used with in the shader have the following requirements:
//
// - The viewType must be either VK_IMAGE_VIEW_TYPE_1D or
// VK_IMAGE_VIEW_TYPE_2D.
// - The image view must have a single layer and a single mip
// level."
//
// Under these conditions, the view is simply LOD 0 of a single array
// slice so we don't need to care about aray stride between slices so
// it's safe to set the number of miplevels to 0 regardless of how many
// the image actually has.
0
} else {
image.num_levels - 1
}
}
fn normalize_extent(image: &Image, view: &View) -> Extent4D {
let mut extent = Extent4D {
width: image.extent_px.width,
height: image.extent_px.height,
depth: 0,
array_len: 0,
};
match view.view_type {
ViewType::_1D
| ViewType::_2D
| ViewType::_1DArray
| ViewType::_2DArray => {
assert!(image.extent_px.depth == 1);
extent.depth = view.array_len;
}
ViewType::_3D => {
assert!(image.dim == ImageDim::_3D);
extent.depth = image.extent_px.depth;
}
ViewType::Cube | ViewType::CubeArray => {
assert!(image.dim == ImageDim::_2D);
assert!(view.array_len % 6 == 0);
extent.depth = view.array_len / 6;
}
ViewType::_3DSliced => {
assert!(image.dim == ImageDim::_3D);
extent.depth = view.array_len;
}
}
extent
}
fn nv9097_fill_tic(
image: &Image,
view: &View,
base_address: u64,
desc_out: &mut [u32; 8],
) {
assert!(image.format.el_size_B() == view.format.el_size_B());
assert!(view.base_level + view.num_levels <= image.num_levels);
assert!(
view.base_array_layer + view.array_len <= image.extent_px.array_len
);
*desc_out = [0u32; 8];
let mut th = BitMutView::new(desc_out);
th.set_field(cl9097::TEXHEADV2_USE_TEXTURE_HEADER_VERSION2, true);
nv9097_set_th_v2_0(&mut th, &view.format, view.swizzle);
// There's no base layer field in the texture header
let layer_address = base_address
+ u64::from(view.base_array_layer)
+ u64::from(image.array_stride_B);
th.set_field(cl9097::TEXHEADV2_OFFSET_LOWER, layer_address as u32);
th.set_field(cl9097::TEXHEADV2_OFFSET_UPPER, (layer_address >> 32) as u32);
let tiling = &image.levels[0].tiling;
if tiling.is_tiled {
set_enum!(th, cl9097, TEXHEADV2_MEMORY_LAYOUT, BLOCKLINEAR);
assert!(tiling.gob_height_is_8);
assert!(tiling.x_log2 == 0);
set_enum!(th, cl9097, TEXHEADV2_GOBS_PER_BLOCK_WIDTH, ONE_GOB);
th.set_field(cl9097::TEXHEADV2_GOBS_PER_BLOCK_HEIGHT, tiling.y_log2);
th.set_field(cl9097::TEXHEADV2_GOBS_PER_BLOCK_DEPTH, tiling.z_log2);
let nv_tex_type = pipe_to_nv_texture_type(view.view_type);
th.set_field(cl9097::TEXHEADV2_TEXTURE_TYPE, nv_tex_type);
} else {
set_enum!(th, cl9097, TEXHEADV2_MEMORY_LAYOUT, PITCH);
let pitch = image.levels[0].row_stride_B;
th.set_field(cl9097::TEXHEADV2_PITCH, pitch);
assert!(
view.view_type == ViewType::_2D
|| view.view_type == ViewType::_2DArray
);
assert!(image.sample_layout == SampleLayout::_1x1);
assert!(view.num_levels == 1);
set_enum!(th, cl9097, TEXHEADV2_TEXTURE_TYPE, TWO_D_NO_MIPMAP);
}
set_enum!(th, cl9097, TEXHEADV2_LOD_ANISO_QUALITY, LOD_QUALITY_HIGH);
set_enum!(th, cl9097, TEXHEADV2_LOD_ISO_QUALITY, LOD_QUALITY_HIGH);
set_enum!(
th,
cl9097,
TEXHEADV2_ANISO_COARSE_SPREAD_MODIFIER,
SPREAD_MODIFIER_NONE
);
let extent = normalize_extent(image, view);
th.set_field(cl9097::TEXHEADV2_WIDTH, extent.width);
th.set_field(cl9097::TEXHEADV2_HEIGHT, extent.height);
th.set_field(cl9097::TEXHEADV2_DEPTH, extent.depth);
let max_mip_level = nil_rs_max_mip_level(image, view);
th.set_field(cl9097::TEXHEADV2_MAX_MIP_LEVEL, max_mip_level);
th.set_field(cl9097::TEXHEADV2_S_R_G_B_CONVERSION, view.format.is_srgb());
set_enum!(th, cl9097, TEXHEADV2_BORDER_SOURCE, BORDER_COLOR);
// In the sampler, the two options for FLOAT_COORD_NORMALIZATION are:
//
// - FORCE_UNNORMALIZED_COORDS
// - USE_HEADER_SETTING
//
// So we set it to normalized in the header and let the sampler select that
// or force non-normalized.
th.set_field(cl9097::TEXHEADV2_NORMALIZED_COORDS, true);
set_enum!(
th,
cl9097,
TEXHEADV2_ANISO_FINE_SPREAD_FUNC,
SPREAD_FUNC_TWO
);
set_enum!(
th,
cl9097,
TEXHEADV2_ANISO_COARSE_SPREAD_FUNC,
SPREAD_FUNC_ONE
);
th.set_field(cl9097::TEXHEADV2_RES_VIEW_MIN_MIP_LEVEL, view.base_level);
th.set_field(
cl9097::TEXHEADV2_RES_VIEW_MAX_MIP_LEVEL,
view.num_levels + view.base_level - 1,
);
let msc = nil_rs_to_nv9097_multi_sample_count(image.sample_layout);
th.set_field(cl9097::TEXHEADV2_MULTI_SAMPLE_COUNT, msc);
let min_lod_clamp = view.min_lod_clamp - (view.base_level as f32);
th.set_ufixed(cl9097::TEXHEADV2_MIN_LOD_CLAMP, min_lod_clamp);
}
fn nvb097_fill_tic(
dev: &nil_rs_bindings::nv_device_info,
image: &Image,
view: &View,
base_address: u64,
desc_out: &mut [u32; 8],
) {
assert!(image.format.el_size_B() == view.format.el_size_B());
assert!(view.base_level + view.num_levels <= image.num_levels);
*desc_out = [0u32; 8];
let mut th = BitMutView::new(desc_out);
nvb097_set_th_bl_0(&mut th, &view.format, view.swizzle);
let tiling = &image.levels[0].tiling;
// There's no base layer field in the texture header
let mut layer_address = base_address;
if view.view_type == ViewType::_3DSliced {
assert!(view.num_levels == 1);
assert!(
view.base_array_layer + view.array_len <= image.extent_px.depth
);
layer_address +=
image.level_z_offset_B(view.base_level, view.base_array_layer);
} else {
assert!(
view.base_array_layer + view.array_len <= image.extent_px.array_len
);
layer_address +=
u64::from(view.base_array_layer) * u64::from(image.array_stride_B);
}
if tiling.is_tiled {
set_enum!(th, clb097, TEXHEAD_BL_HEADER_VERSION, SELECT_BLOCKLINEAR);
let addr = BitView::new(&layer_address);
assert!(addr.get_bit_range_u64(0..9) == 0);
th.set_field(
clb097::TEXHEAD_BL_ADDRESS_BITS31TO9,
addr.get_bit_range_u64(9..32),
);
th.set_field(
clb097::TEXHEAD_BL_ADDRESS_BITS47TO32,
addr.get_bit_range_u64(32..48),
);
assert!(addr.get_bit_range_u64(48..64) == 0);
assert!(tiling.gob_height_is_8);
set_enum!(th, clb097, TEXHEAD_BL_GOBS_PER_BLOCK_WIDTH, ONE_GOB);
th.set_field(clb097::TEXHEAD_BL_GOBS_PER_BLOCK_HEIGHT, tiling.y_log2);
th.set_field(clb097::TEXHEAD_BL_GOBS_PER_BLOCK_DEPTH, tiling.z_log2);
th.set_field(clb097::TEXHEAD_BL_TILE_WIDTH_IN_GOBS, tiling.x_log2);
let nv_text_type = pipe_to_nv_texture_type(view.view_type);
th.set_field(clb097::TEXHEAD_BL_TEXTURE_TYPE, nv_text_type);
} else {
set_enum!(th, clb097, TEXHEAD_BL_HEADER_VERSION, SELECT_PITCH);
let addr = BitView::new(&layer_address);
assert!(addr.get_bit_range_u64(0..5) == 0);
th.set_field(
clb097::TEXHEAD_PITCH_ADDRESS_BITS31TO5,
addr.get_bit_range_u64(5..32),
);
th.set_field(
clb097::TEXHEAD_PITCH_ADDRESS_BITS47TO32,
addr.get_bit_range_u64(32..48),
);
assert!(addr.get_bit_range_u64(48..64) == 0);
let pitch = image.levels[0].row_stride_B;
let pitch = BitView::new(&pitch);
assert!(pitch.get_bit_range_u64(0..5) == 0);
assert!(pitch.get_bit_range_u64(21..32) == 0);
th.set_field(
clb097::TEXHEAD_PITCH_PITCH_BITS20TO5,
pitch.get_bit_range_u64(5..21),
);
assert!(
view.view_type == ViewType::_2D
|| view.view_type == ViewType::_2DArray
);
assert!(image.sample_layout == SampleLayout::_1x1);
assert!(view.num_levels == 1);
set_enum!(th, clb097, TEXHEAD_PITCH_TEXTURE_TYPE, TWO_D_NO_MIPMAP);
}
th.set_field(clb097::TEXHEAD_BL_LOD_ANISO_QUALITY2, true);
set_enum!(th, clb097, TEXHEAD_BL_LOD_ANISO_QUALITY, LOD_QUALITY_HIGH);
set_enum!(th, clb097, TEXHEAD_BL_LOD_ISO_QUALITY, LOD_QUALITY_HIGH);
set_enum!(
th,
clb097,
TEXHEAD_BL_ANISO_COARSE_SPREAD_MODIFIER,
SPREAD_MODIFIER_NONE
);
let extent = normalize_extent(image, view);
th.set_field(clb097::TEXHEAD_BL_WIDTH_MINUS_ONE, extent.width - 1);
if dev.cls_eng3d >= PASCAL_A {
let height_1 = extent.height - 1;
let depth_1 = extent.depth - 1;
th.set_field(clc097::TEXHEAD_BL_HEIGHT_MINUS_ONE, height_1 & 0xffff);
th.set_field(clc097::TEXHEAD_BL_HEIGHT_MINUS_ONE_BIT16, height_1 >> 16);
th.set_field(clc097::TEXHEAD_BL_DEPTH_MINUS_ONE, depth_1 & 0x3fff);
th.set_field(clc097::TEXHEAD_BL_DEPTH_MINUS_ONE_BIT14, depth_1 >> 14);
} else {
th.set_field(clb097::TEXHEAD_BL_HEIGHT_MINUS_ONE, extent.height - 1);
th.set_field(clb097::TEXHEAD_BL_DEPTH_MINUS_ONE, extent.depth - 1);
}
let max_mip_level = nil_rs_max_mip_level(image, view);
th.set_field(clb097::TEXHEAD_BL_MAX_MIP_LEVEL, max_mip_level);
th.set_field(clb097::TEXHEAD_BL_S_R_G_B_CONVERSION, view.format.is_srgb());
set_enum!(th, clb097, TEXHEAD_BL_SECTOR_PROMOTION, PROMOTE_TO_2_V);
set_enum!(th, clb097, TEXHEAD_BL_BORDER_SIZE, BORDER_SAMPLER_COLOR);
// In the sampler, the two options for FLOAT_COORD_NORMALIZATION are:
//
// - FORCE_UNNORMALIZED_COORDS
// - USE_HEADER_SETTING
//
// So we set it to normalized in the header and let the sampler select that
// or force non-normalized.
th.set_field(clb097::TEXHEAD_BL_NORMALIZED_COORDS, true);
set_enum!(
th,
clb097,
TEXHEAD_BL_ANISO_FINE_SPREAD_FUNC,
SPREAD_FUNC_TWO
);
set_enum!(
th,
clb097,
TEXHEAD_BL_ANISO_COARSE_SPREAD_FUNC,
SPREAD_FUNC_ONE
);
th.set_field(clb097::TEXHEAD_BL_RES_VIEW_MIN_MIP_LEVEL, view.base_level);
let max_mip_level = view.num_levels + view.base_level - 1;
th.set_field(clb097::TEXHEAD_BL_RES_VIEW_MAX_MIP_LEVEL, max_mip_level);
let msc = nil_rs_to_nvb097_multi_sample_count(image.sample_layout);
th.set_field(clb097::TEXHEAD_BL_MULTI_SAMPLE_COUNT, msc);
let min_lod_clamp = view.min_lod_clamp - (view.base_level as f32);
th.set_ufixed(clb097::TEXHEAD_BL_MIN_LOD_CLAMP, min_lod_clamp);
}
pub const IDENTITY_SWIZZLE: [nil_rs_bindings::pipe_swizzle; 4] = [
nil_rs_bindings::PIPE_SWIZZLE_X,
nil_rs_bindings::PIPE_SWIZZLE_Y,
nil_rs_bindings::PIPE_SWIZZLE_Z,
nil_rs_bindings::PIPE_SWIZZLE_W,
];
fn nv9097_nil_fill_buffer_tic(
base_address: u64,
format: Format,
num_elements: u32,
desc_out: &mut [u32; 8],
) {
*desc_out = [0u32; 8];
let mut th = BitMutView::new(desc_out);
th.set_field(cl9097::TEXHEADV2_USE_TEXTURE_HEADER_VERSION2, true);
assert!(format.supports_buffer());
nv9097_set_th_v2_0(&mut th, &format, IDENTITY_SWIZZLE);
th.set_field(cl9097::TEXHEADV2_OFFSET_LOWER, base_address as u32);
th.set_field(cl9097::TEXHEADV2_OFFSET_UPPER, (base_address >> 32) as u32);
set_enum!(th, cl9097, TEXHEADV2_MEMORY_LAYOUT, PITCH);
th.set_field(cl9097::TEXHEADV2_WIDTH, num_elements);
set_enum!(th, cl9097, TEXHEADV2_TEXTURE_TYPE, ONE_D_BUFFER);
}
fn nvb097_nil_fill_buffer_tic(
base_address: u64,
format: Format,
num_elements: u32,
desc_out: &mut [u32; 8],
) {
*desc_out = [0u32; 8];
let mut th = BitMutView::new(desc_out);
assert!(format.supports_buffer());
nvb097_set_th_bl_0(&mut th, &format, IDENTITY_SWIZZLE);
th.set_field(clb097::TEXHEAD_1D_ADDRESS_BITS31TO0, base_address as u32);
th.set_field(clb097::TEXHEAD_1D_ADDRESS_BITS47TO32, base_address >> 32);
set_enum!(th, clb097, TEXHEAD_1D_HEADER_VERSION, SELECT_ONE_D_BUFFER);
th.set_field(
clb097::TEXHEAD_1D_WIDTH_MINUS_ONE_BITS15TO0,
(num_elements - 1) & 0xffff,
);
th.set_field(
clb097::TEXHEAD_1D_WIDTH_MINUS_ONE_BITS31TO16,
(num_elements - 1) >> 16,
);
set_enum!(th, clb097, TEXHEAD_1D_TEXTURE_TYPE, ONE_D_BUFFER);
// TODO: Do we need this?
set_enum!(th, clb097, TEXHEAD_1D_SECTOR_PROMOTION, PROMOTE_TO_2_V);
}
impl Image {
#[no_mangle]
pub extern "C" fn nil_image_fill_tic(
&self,
dev: &nil_rs_bindings::nv_device_info,
view: &View,
base_address: u64,
desc_out: &mut [u32; 8],
) {
self.fill_tic(dev, view, base_address, desc_out);
}
pub fn fill_tic(
&self,
dev: &nil_rs_bindings::nv_device_info,
view: &View,
base_address: u64,
desc_out: &mut [u32; 8],
) {
if dev.cls_eng3d >= MAXWELL_A {
nvb097_fill_tic(dev, self, view, base_address, desc_out);
} else if dev.cls_eng3d >= FERMI_A {
nv9097_fill_tic(self, view, base_address, desc_out);
} else {
panic!("Tesla and older not supported");
}
}
}
#[no_mangle]
pub extern "C" fn nil_buffer_fill_tic(
dev: &nil_rs_bindings::nv_device_info,
base_address: u64,
format: Format,
num_elements: u32,
desc_out: &mut [u32; 8],
) {
fill_buffer_tic(dev, base_address, format, num_elements, desc_out);
}
pub fn fill_buffer_tic(
dev: &nil_rs_bindings::nv_device_info,
base_address: u64,
format: Format,
num_elements: u32,
desc_out: &mut [u32; 8],
) {
if dev.cls_eng3d >= MAXWELL_A {
nvb097_nil_fill_buffer_tic(base_address, format, num_elements, desc_out)
} else if dev.cls_eng3d >= FERMI_A {
nv9097_nil_fill_buffer_tic(base_address, format, num_elements, desc_out)
} else {
panic!("Tesla and older not supported");
}
}

View file

@ -57,8 +57,8 @@ nvk_CreateBufferView(VkDevice _device,
uint32_t desc[8]; uint32_t desc[8];
nil_buffer_fill_tic(&nvk_device_physical(device)->info, nil_buffer_fill_tic(&nvk_device_physical(device)->info,
nvk_buffer_address(buffer, view->vk.offset), nvk_buffer_address(buffer, view->vk.offset),
vk_format_to_pipe_format(view->vk.format), nil_format(vk_format_to_pipe_format(view->vk.format)),
view->vk.elements, desc); view->vk.elements, &desc);
result = nvk_descriptor_table_add(device, &device->images, result = nvk_descriptor_table_add(device, &device->images,
desc, sizeof(desc), &view->desc_index); desc, sizeof(desc), &view->desc_index);

View file

@ -74,8 +74,8 @@ image_3d_view_as_2d_array(struct nil_image *image,
struct nil_view *view, struct nil_view *view,
uint64_t *base_addr) uint64_t *base_addr)
{ {
assert(view->type == NIL_VIEW_TYPE_2D || assert(view->view_type == NIL_VIEW_TYPE_2D ||
view->type == NIL_VIEW_TYPE_2D_ARRAY); view->view_type == NIL_VIEW_TYPE_2D_ARRAY);
assert(view->num_levels == 1); assert(view->num_levels == 1);
uint64_t offset_B; uint64_t offset_B;
@ -102,6 +102,7 @@ nvk_image_view_init(struct nvk_device *dev,
bool driver_internal, bool driver_internal,
const VkImageViewCreateInfo *pCreateInfo) const VkImageViewCreateInfo *pCreateInfo)
{ {
struct nvk_physical_device *pdev = nvk_device_physical(dev);
VK_FROM_HANDLE(nvk_image, image, pCreateInfo->image); VK_FROM_HANDLE(nvk_image, image, pCreateInfo->image);
VkResult result; VkResult result;
@ -149,8 +150,8 @@ nvk_image_view_init(struct nvk_device *dev,
p_format = get_stencil_format(p_format); p_format = get_stencil_format(p_format);
struct nil_view nil_view = { struct nil_view nil_view = {
.type = vk_image_view_type_to_nil_view_type(view->vk.view_type), .view_type = vk_image_view_type_to_nil_view_type(view->vk.view_type),
.format = p_format, .format = nil_format(p_format),
.base_level = view->vk.base_mip_level, .base_level = view->vk.base_mip_level,
.num_levels = view->vk.level_count, .num_levels = view->vk.level_count,
.base_array_layer = view->vk.base_array_layer, .base_array_layer = view->vk.base_array_layer,
@ -165,11 +166,11 @@ nvk_image_view_init(struct nvk_device *dev,
}; };
if (util_format_is_compressed(nil_image.format.p_format) && if (util_format_is_compressed(nil_image.format.p_format) &&
!util_format_is_compressed(nil_view.format)) !util_format_is_compressed(nil_view.format.p_format))
image_uncompressed_view(&nil_image, &nil_view, &base_addr); image_uncompressed_view(&nil_image, &nil_view, &base_addr);
if (nil_image.dim == NIL_IMAGE_DIM_3D && if (nil_image.dim == NIL_IMAGE_DIM_3D &&
nil_view.type != NIL_VIEW_TYPE_3D) nil_view.view_type != NIL_VIEW_TYPE_3D)
image_3d_view_as_2d_array(&nil_image, &nil_view, &base_addr); image_3d_view_as_2d_array(&nil_image, &nil_view, &base_addr);
view->planes[view_plane].sample_layout = nil_image.sample_layout; view->planes[view_plane].sample_layout = nil_image.sample_layout;
@ -177,8 +178,8 @@ nvk_image_view_init(struct nvk_device *dev,
if (view->vk.usage & (VK_IMAGE_USAGE_SAMPLED_BIT | if (view->vk.usage & (VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) { VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) {
uint32_t tic[8]; uint32_t tic[8];
nil_image_fill_tic(&nvk_device_physical(dev)->info, nil_image_fill_tic(&nil_image, &pdev->info,
&nil_image, &nil_view, base_addr, tic); &nil_view, base_addr, &tic);
result = nvk_descriptor_table_add(dev, &dev->images, tic, sizeof(tic), result = nvk_descriptor_table_add(dev, &dev->images, tic, sizeof(tic),
&view->planes[view_plane].sampled_desc_index); &view->planes[view_plane].sampled_desc_index);
@ -192,7 +193,7 @@ nvk_image_view_init(struct nvk_device *dev,
/* For storage images, we can't have any cubes */ /* For storage images, we can't have any cubes */
if (view->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE || if (view->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE ||
view->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) view->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
nil_view.type = NIL_VIEW_TYPE_2D_ARRAY; nil_view.view_type = NIL_VIEW_TYPE_2D_ARRAY;
if (view->vk.view_type == VK_IMAGE_VIEW_TYPE_3D) { if (view->vk.view_type == VK_IMAGE_VIEW_TYPE_3D) {
/* Without VK_AMD_shader_image_load_store_lod, the client can only /* Without VK_AMD_shader_image_load_store_lod, the client can only
@ -205,7 +206,7 @@ nvk_image_view_init(struct nvk_device *dev,
if (view->vk.storage.z_slice_offset > 0 || if (view->vk.storage.z_slice_offset > 0 ||
view->vk.storage.z_slice_count < nil_image.extent_px.depth) { view->vk.storage.z_slice_count < nil_image.extent_px.depth) {
nil_view.type = NIL_VIEW_TYPE_3D_SLICED; nil_view.view_type = NIL_VIEW_TYPE_3D_SLICED;
nil_view.base_array_layer = view->vk.storage.z_slice_offset; nil_view.base_array_layer = view->vk.storage.z_slice_offset;
nil_view.array_len = view->vk.storage.z_slice_count; nil_view.array_len = view->vk.storage.z_slice_count;
} }
@ -215,8 +216,8 @@ nvk_image_view_init(struct nvk_device *dev,
nil_image = nil_msaa_image_as_sa(&nil_image); nil_image = nil_msaa_image_as_sa(&nil_image);
uint32_t tic[8]; uint32_t tic[8];
nil_image_fill_tic(&nvk_device_physical(dev)->info, nil_image_fill_tic(&nil_image, &pdev->info, &nil_view,
&nil_image, &nil_view, base_addr, tic); base_addr, &tic);
result = nvk_descriptor_table_add(dev, &dev->images, tic, sizeof(tic), result = nvk_descriptor_table_add(dev, &dev->images, tic, sizeof(tic),
&view->planes[view_plane].storage_desc_index); &view->planes[view_plane].storage_desc_index);