mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-06 02:58:05 +02:00
nil: Add some helpers for DRM format modifiers
Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24795>
(cherry picked from commit e1bd4127f3)
This commit is contained in:
parent
797b25e43d
commit
73f3805da3
7 changed files with 347 additions and 3 deletions
|
|
@ -1534,7 +1534,7 @@
|
|||
"description": "nil: Add some helpers for DRM format modifiers",
|
||||
"nominated": false,
|
||||
"nomination_type": 3,
|
||||
"resolution": 4,
|
||||
"resolution": 1,
|
||||
"main_sha": null,
|
||||
"because_sha": null,
|
||||
"notes": null
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
language = "C"
|
||||
|
||||
includes = ["nouveau/headers/nv_device_info.h", "util/format/u_format.h"]
|
||||
includes = ["nouveau/headers/nv_device_info.h", "util/format/u_format.h", "drm-uapi/drm_fourcc.h"]
|
||||
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
|
||||
include_guard = "NIL_H"
|
||||
usize_is_size_t = true
|
||||
|
|
@ -19,6 +19,7 @@ renaming_overrides_prefixing = true
|
|||
"GOB_DEPTH" = "NIL_GOB_DEPTH"
|
||||
"GOB_WIDTH_B" = "NIL_GOB_WIDTH_B"
|
||||
"MAX_LEVELS" = "NIL_MAX_LEVELS"
|
||||
"MAX_DRM_FORMAT_MODS" = "NIL_MAX_DRM_FORMAT_MODS"
|
||||
|
||||
# This is annoying. rename_types doesn't seem to work
|
||||
"Format" = "nil_format"
|
||||
|
|
|
|||
|
|
@ -58,6 +58,20 @@ impl Format {
|
|||
unsafe { util_format_is_pure_integer((*self).into()) }
|
||||
}
|
||||
|
||||
pub(crate) fn has_depth(&self) -> bool {
|
||||
self.description().colorspace == UTIL_FORMAT_COLORSPACE_ZS
|
||||
&& u32::from(self.description().swizzle[0]) != PIPE_SWIZZLE_NONE
|
||||
}
|
||||
|
||||
pub(crate) fn has_stencil(&self) -> bool {
|
||||
self.description().colorspace == UTIL_FORMAT_COLORSPACE_ZS
|
||||
&& u32::from(self.description().swizzle[1]) != PIPE_SWIZZLE_NONE
|
||||
}
|
||||
|
||||
pub(crate) fn is_depth_or_stencil(&self) -> bool {
|
||||
self.has_depth() || self.has_stencil()
|
||||
}
|
||||
|
||||
pub(crate) fn is_srgb(&self) -> bool {
|
||||
self.description().colorspace == UTIL_FORMAT_COLORSPACE_SRGB
|
||||
}
|
||||
|
|
|
|||
|
|
@ -486,7 +486,7 @@ impl Image {
|
|||
image_2d_out
|
||||
}
|
||||
|
||||
fn choose_pte_kind(
|
||||
pub fn choose_pte_kind(
|
||||
dev: &nil_rs_bindings::nv_device_info,
|
||||
format: Format,
|
||||
samples: u32,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ extern crate nvidia_headers;
|
|||
mod extent;
|
||||
mod format;
|
||||
mod image;
|
||||
mod modifiers;
|
||||
mod tic;
|
||||
mod tiling;
|
||||
|
||||
|
|
|
|||
|
|
@ -78,12 +78,16 @@ _nil_bindings_rs = rust.bindgen(
|
|||
'--allowlist-function', 'util_format_is_compressed',
|
||||
'--allowlist-function', 'util_format_is_pure_integer',
|
||||
'--allowlist-function', 'util_format_is_srgb',
|
||||
'--allowlist-function', 'drm_format_mod_block_linear_2D',
|
||||
'--allowlist-function', 'drm_mod_is_nvidia',
|
||||
'--allowlist-type', 'nil_format_support_flags',
|
||||
'--allowlist-type', 'nv_device_info',
|
||||
'--allowlist-type', 'nv_device_type',
|
||||
'--allowlist-type', 'pipe_format',
|
||||
'--allowlist-type', 'pipe_swizzle',
|
||||
'--allowlist-var', 'nil_format_table',
|
||||
'--allowlist-var', 'drm_format_mod_invalid',
|
||||
'--allowlist-var', 'drm_format_mod_linear',
|
||||
'--no-prepend-enum-name',
|
||||
],
|
||||
dependencies: _libnil_deps,
|
||||
|
|
|
|||
324
src/nouveau/nil/modifiers.rs
Normal file
324
src/nouveau/nil/modifiers.rs
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
// Copyright © 2024 Valve Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::format::Format;
|
||||
use crate::image::Image;
|
||||
use crate::tiling::Tiling;
|
||||
|
||||
use bitview::*;
|
||||
use nvidia_headers::classes::{cl9097, clc597};
|
||||
|
||||
pub const MAX_DRM_FORMAT_MODS: usize = 7;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub enum GOBKindVersion {
|
||||
Fermi = 0,
|
||||
G80 = 1,
|
||||
Turing = 2,
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for GOBKindVersion {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(gob_kind_version: u64) -> Result<Self, Self::Error> {
|
||||
match gob_kind_version {
|
||||
0 => Ok(GOBKindVersion::Fermi),
|
||||
1 => Ok(GOBKindVersion::G80),
|
||||
2 => Ok(GOBKindVersion::Turing),
|
||||
_ => Err("Invalid gob/kind version"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GOBKindVersion {
|
||||
pub fn for_dev(dev: &nil_rs_bindings::nv_device_info) -> GOBKindVersion {
|
||||
if dev.cls_eng3d >= clc597::TURING_A {
|
||||
GOBKindVersion::Turing
|
||||
} else if dev.cls_eng3d >= cl9097::FERMI_A {
|
||||
GOBKindVersion::Fermi
|
||||
} else {
|
||||
GOBKindVersion::G80
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub enum SectorLayout {
|
||||
TegraK1 = 0,
|
||||
Desktop = 1,
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for SectorLayout {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(sector_layout: u64) -> Result<Self, Self::Error> {
|
||||
match sector_layout {
|
||||
0 => Ok(SectorLayout::TegraK1),
|
||||
1 => Ok(SectorLayout::Desktop),
|
||||
_ => Err("Invalid gob/kind version"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SectorLayout {
|
||||
// For now, this always returns desktop, but will be different for Tegra
|
||||
pub fn for_dev(_dev: &nil_rs_bindings::nv_device_info) -> SectorLayout {
|
||||
SectorLayout::Desktop
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub enum CompressionType {
|
||||
None = 0,
|
||||
ROP3DOne = 1,
|
||||
ROP3DTwo = 2,
|
||||
CDEHorizontal = 3,
|
||||
CDEVertical = 4,
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for CompressionType {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(compression_type: u64) -> Result<Self, Self::Error> {
|
||||
match compression_type {
|
||||
0 => Ok(CompressionType::None),
|
||||
1 => Ok(CompressionType::ROP3DOne),
|
||||
2 => Ok(CompressionType::ROP3DTwo),
|
||||
3 => Ok(CompressionType::CDEHorizontal),
|
||||
4 => Ok(CompressionType::CDEVertical),
|
||||
_ => Err("Invalid gob/kind version"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const DRM_FORMAT_MOD_LINEAR: u64 = 0;
|
||||
pub const DRM_FORMAT_MOD_INVALID: u64 = 0x00ffffff_ffffffff;
|
||||
|
||||
const DRM_FORMAT_MOD_VENDOR_NVIDIA: u8 = 0x03;
|
||||
|
||||
pub struct BlockLinearModifier {
|
||||
drm_modifier: u64,
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for BlockLinearModifier {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(drm_modifier: u64) -> Result<Self, Self::Error> {
|
||||
let bv = BitView::new(&drm_modifier);
|
||||
let vendor: u8 = bv.get_bit_range_u64(56..64).try_into().unwrap();
|
||||
if vendor != DRM_FORMAT_MOD_VENDOR_NVIDIA {
|
||||
Err("modifier does not have DRM_FORMAT_MOD_VENDOR_NVIDIA")
|
||||
} else if !bv.get_bit(4) {
|
||||
Err("modifier is not block linear")
|
||||
} else if bv.get_bit_range_u64(5..12) != 0
|
||||
|| bv.get_bit_range_u64(26..56) != 0
|
||||
{
|
||||
Err("unknown reserved bits")
|
||||
} else {
|
||||
Ok(BlockLinearModifier { drm_modifier })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockLinearModifier {
|
||||
pub fn block_linear_2d(
|
||||
compression_type: CompressionType,
|
||||
sector_layout: SectorLayout,
|
||||
gob_kind_version: GOBKindVersion,
|
||||
pte_kind: u8,
|
||||
height_log2: u8,
|
||||
) -> BlockLinearModifier {
|
||||
let mut drm_modifier = 0_u64;
|
||||
let mut bv = BitMutView::new(&mut drm_modifier);
|
||||
bv.set_field(0..4, height_log2);
|
||||
bv.set_bit(4, true); // Must be 1, to indicate block-linear layout.
|
||||
bv.set_field(12..20, pte_kind);
|
||||
bv.set_field(20..22, gob_kind_version as u8);
|
||||
bv.set_field(22..23, sector_layout as u8);
|
||||
bv.set_field(23..26, compression_type as u8);
|
||||
bv.set_field(56..64, DRM_FORMAT_MOD_VENDOR_NVIDIA);
|
||||
BlockLinearModifier { drm_modifier }
|
||||
}
|
||||
|
||||
pub fn height_log2(&self) -> u8 {
|
||||
let bv = BitView::new(&self.drm_modifier);
|
||||
bv.get_bit_range_u64(0..4).try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn pte_kind(&self) -> u8 {
|
||||
let bv = BitView::new(&self.drm_modifier);
|
||||
bv.get_bit_range_u64(12..20).try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn gob_kind_version(&self) -> GOBKindVersion {
|
||||
let bv = BitView::new(&self.drm_modifier);
|
||||
bv.get_bit_range_u64(20..22).try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn sector_layout(&self) -> SectorLayout {
|
||||
let bv = BitView::new(&self.drm_modifier);
|
||||
bv.get_bit_range_u64(22..23).try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn compression_type(&self) -> CompressionType {
|
||||
let bv = BitView::new(&self.drm_modifier);
|
||||
bv.get_bit_range_u64(23..26).try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn tiling(&self) -> Tiling {
|
||||
Tiling {
|
||||
is_tiled: true,
|
||||
gob_height_is_8: self.gob_kind_version() != GOBKindVersion::G80,
|
||||
x_log2: 0,
|
||||
y_log2: self.height_log2(),
|
||||
z_log2: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn nil_drm_format_mods_for_format(
|
||||
dev: &nil_rs_bindings::nv_device_info,
|
||||
format: Format,
|
||||
mod_count: &mut usize,
|
||||
mods: &mut [u64; MAX_DRM_FORMAT_MODS],
|
||||
) {
|
||||
drm_format_mods_for_format(dev, format, mod_count, mods)
|
||||
}
|
||||
|
||||
pub fn drm_format_mods_for_format(
|
||||
dev: &nil_rs_bindings::nv_device_info,
|
||||
format: Format,
|
||||
mod_count: &mut usize,
|
||||
mods: &mut [u64; MAX_DRM_FORMAT_MODS],
|
||||
) {
|
||||
let max_mod_count = *mod_count;
|
||||
*mod_count = 0;
|
||||
|
||||
if format.is_depth_or_stencil() {
|
||||
return;
|
||||
}
|
||||
|
||||
if !format.supports_color_targets(dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
let compression_type = CompressionType::None;
|
||||
let sector_layout = SectorLayout::for_dev(dev);
|
||||
let gob_kind_version = GOBKindVersion::for_dev(dev);
|
||||
let pte_kind = Image::choose_pte_kind(dev, format, 1, false);
|
||||
|
||||
// We assume bigger tiling is better
|
||||
for i in 0..6 {
|
||||
let height_log2 = 5 - i;
|
||||
|
||||
let bl_mod = BlockLinearModifier::block_linear_2d(
|
||||
compression_type,
|
||||
sector_layout,
|
||||
gob_kind_version,
|
||||
pte_kind,
|
||||
height_log2,
|
||||
);
|
||||
|
||||
assert!(*mod_count < max_mod_count);
|
||||
mods[*mod_count] = bl_mod.drm_modifier;
|
||||
*mod_count += 1;
|
||||
}
|
||||
|
||||
assert!(*mod_count < max_mod_count);
|
||||
mods[*mod_count] = DRM_FORMAT_MOD_LINEAR;
|
||||
*mod_count += 1;
|
||||
}
|
||||
|
||||
pub fn drm_format_mod_is_supported(
|
||||
dev: &nil_rs_bindings::nv_device_info,
|
||||
format: Format,
|
||||
modifier: u64,
|
||||
) -> bool {
|
||||
if modifier == DRM_FORMAT_MOD_LINEAR {
|
||||
return true;
|
||||
}
|
||||
|
||||
let Ok(bl_mod) = BlockLinearModifier::try_from(modifier) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if bl_mod.height_log2() > 5 {
|
||||
return false;
|
||||
}
|
||||
|
||||
if bl_mod.gob_kind_version() != GOBKindVersion::for_dev(dev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if bl_mod.sector_layout() != SectorLayout::for_dev(dev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if bl_mod.compression_type() != CompressionType::None {
|
||||
return false;
|
||||
}
|
||||
|
||||
let pte_kind = Image::choose_pte_kind(dev, format, 1, false);
|
||||
if bl_mod.pte_kind() != pte_kind {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn score_drm_format_mod(modifier: u64) -> u32 {
|
||||
if modifier == DRM_FORMAT_MOD_LINEAR {
|
||||
return 1;
|
||||
}
|
||||
|
||||
let bl_mod = BlockLinearModifier::try_from(modifier).unwrap();
|
||||
|
||||
// Assume bigger Y-tiling is better
|
||||
let mut score = 10 + u32::from(bl_mod.height_log2());
|
||||
|
||||
if bl_mod.compression_type() != CompressionType::None {
|
||||
score += 10;
|
||||
}
|
||||
|
||||
score
|
||||
}
|
||||
|
||||
pub fn select_best_drm_format_mod(
|
||||
dev: &nil_rs_bindings::nv_device_info,
|
||||
format: Format,
|
||||
modifiers: &[u64],
|
||||
) -> u64 {
|
||||
let mut best = DRM_FORMAT_MOD_INVALID;
|
||||
let mut best_score = 0;
|
||||
|
||||
for &modifier in modifiers {
|
||||
if !drm_format_mod_is_supported(dev, format, modifier) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let score = score_drm_format_mod(modifier);
|
||||
if score > best_score {
|
||||
best = modifier;
|
||||
best_score = score;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn nil_select_best_drm_format_mod(
|
||||
dev: &nil_rs_bindings::nv_device_info,
|
||||
format: Format,
|
||||
modifier_count: usize,
|
||||
modifiers: *const u64,
|
||||
) -> u64 {
|
||||
let modifiers =
|
||||
unsafe { std::slice::from_raw_parts(modifiers, modifier_count) };
|
||||
select_best_drm_format_mod(dev, format, modifiers)
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue