1 // Copyright © 2024 Collabora, Ltd.
2 // SPDX-License-Identifier: MIT
3
4 use nil_rs_bindings::*;
5 use nvidia_headers::classes::{cla297, clb097, clb197};
6
7 use crate::extent::{units, Extent4D};
8
9 #[repr(C)]
10 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
11 pub struct Format {
12 p_format: pipe_format,
13 }
14
15 impl TryFrom<pipe_format> for Format {
16 type Error = &'static str;
17
try_from(p_format: pipe_format) -> Result<Self, Self::Error>18 fn try_from(p_format: pipe_format) -> Result<Self, Self::Error> {
19 unsafe {
20 if p_format >= PIPE_FORMAT_COUNT {
21 Err("pipe_format is out-of-bounds")
22 } else if nil_format_table[p_format as usize].support() == 0 {
23 Err("Unsupported pipe_format")
24 } else {
25 Ok(Format { p_format })
26 }
27 }
28 }
29 }
30
31 impl From<Format> for pipe_format {
from(format: Format) -> pipe_format32 fn from(format: Format) -> pipe_format {
33 format.p_format
34 }
35 }
36
37 impl Format {
description(&self) -> &'static util_format_description38 fn description(&self) -> &'static util_format_description {
39 unsafe { &*util_format_description((*self).into()) }
40 }
41
el_size_B(&self) -> u3242 pub(crate) fn el_size_B(&self) -> u32 {
43 let bits = self.description().block.bits;
44 debug_assert!(bits % 8 == 0);
45 bits / 8
46 }
47
el_extent_sa(&self) -> Extent4D<units::Samples>48 pub(crate) fn el_extent_sa(&self) -> Extent4D<units::Samples> {
49 let desc = self.description();
50 Extent4D::new(desc.block.width, desc.block.height, desc.block.depth, 1)
51 }
52
info(&self) -> &nil_format_info53 pub(crate) fn info(&self) -> &nil_format_info {
54 unsafe { &nil_format_table[self.p_format as usize] }
55 }
56
is_integer(&self) -> bool57 pub(crate) fn is_integer(&self) -> bool {
58 unsafe { util_format_is_pure_integer((*self).into()) }
59 }
60
has_depth(&self) -> bool61 pub(crate) fn has_depth(&self) -> bool {
62 self.description().colorspace == UTIL_FORMAT_COLORSPACE_ZS
63 && u32::from(self.description().swizzle[0]) != PIPE_SWIZZLE_NONE
64 }
65
has_stencil(&self) -> bool66 pub(crate) fn has_stencil(&self) -> bool {
67 self.description().colorspace == UTIL_FORMAT_COLORSPACE_ZS
68 && u32::from(self.description().swizzle[1]) != PIPE_SWIZZLE_NONE
69 }
70
is_depth_or_stencil(&self) -> bool71 pub(crate) fn is_depth_or_stencil(&self) -> bool {
72 self.has_depth() || self.has_stencil()
73 }
74
is_srgb(&self) -> bool75 pub(crate) fn is_srgb(&self) -> bool {
76 self.description().colorspace == UTIL_FORMAT_COLORSPACE_SRGB
77 }
78
supports_texturing(&self, dev: &nv_device_info) -> bool79 pub fn supports_texturing(&self, dev: &nv_device_info) -> bool {
80 if self.info().support() & NIL_FORMAT_SUPPORTS_TEXTURE_BIT == 0 {
81 return false;
82 }
83
84 let desc = self.description();
85 if desc.layout == UTIL_FORMAT_LAYOUT_ETC
86 || desc.layout == UTIL_FORMAT_LAYOUT_ASTC
87 {
88 return dev.type_ == NV_DEVICE_TYPE_SOC
89 && dev.cls_eng3d >= cla297::KEPLER_C;
90 }
91
92 true
93 }
94
supports_filtering(&self, dev: &nv_device_info) -> bool95 pub fn supports_filtering(&self, dev: &nv_device_info) -> bool {
96 self.supports_texturing(dev) && !self.is_integer()
97 }
98
supports_buffer(&self) -> bool99 pub fn supports_buffer(&self) -> bool {
100 self.info().support() & NIL_FORMAT_SUPPORTS_BUFFER_BIT != 0
101 }
102
supports_storage(&self, dev: &nv_device_info) -> bool103 pub fn supports_storage(&self, dev: &nv_device_info) -> bool {
104 if (self.p_format == PIPE_FORMAT_R64_UINT
105 || self.p_format == PIPE_FORMAT_R64_SINT)
106 && dev.cls_eng3d < clb097::MAXWELL_A
107 {
108 return false;
109 }
110 self.info().support() & NIL_FORMAT_SUPPORTS_STORAGE_BIT != 0
111 }
112
supports_color_targets(&self, _dev: &nv_device_info) -> bool113 pub fn supports_color_targets(&self, _dev: &nv_device_info) -> bool {
114 self.info().support() & NIL_FORMAT_SUPPORTS_RENDER_BIT != 0
115 }
116
supports_blending(&self, _dev: &nv_device_info) -> bool117 pub fn supports_blending(&self, _dev: &nv_device_info) -> bool {
118 self.info().support() & NIL_FORMAT_SUPPORTS_ALPHA_BLEND_BIT != 0
119 }
120
supports_depth_stencil(&self, dev: &nv_device_info) -> bool121 pub fn supports_depth_stencil(&self, dev: &nv_device_info) -> bool {
122 if self.p_format == PIPE_FORMAT_S8_UINT {
123 return dev.cls_eng3d >= clb197::MAXWELL_B;
124 }
125 self.info().support() & NIL_FORMAT_SUPPORTS_DEPTH_STENCIL_BIT != 0
126 }
127 }
128
129 #[no_mangle]
nil_format_supports_texturing( dev: &nv_device_info, p_format: pipe_format, ) -> bool130 pub extern "C" fn nil_format_supports_texturing(
131 dev: &nv_device_info,
132 p_format: pipe_format,
133 ) -> bool {
134 Format::try_from(p_format).is_ok_and(|f| f.supports_texturing(dev))
135 }
136
137 #[no_mangle]
nil_format_supports_filtering( dev: &nv_device_info, p_format: pipe_format, ) -> bool138 pub extern "C" fn nil_format_supports_filtering(
139 dev: &nv_device_info,
140 p_format: pipe_format,
141 ) -> bool {
142 Format::try_from(p_format).is_ok_and(|f| f.supports_filtering(dev))
143 }
144
145 #[no_mangle]
nil_format_supports_buffer( _dev: &nv_device_info, p_format: pipe_format, ) -> bool146 pub extern "C" fn nil_format_supports_buffer(
147 _dev: &nv_device_info,
148 p_format: pipe_format,
149 ) -> bool {
150 Format::try_from(p_format).is_ok_and(|f| f.supports_buffer())
151 }
152
153 #[no_mangle]
nil_format_supports_storage( dev: &nv_device_info, p_format: pipe_format, ) -> bool154 pub extern "C" fn nil_format_supports_storage(
155 dev: &nv_device_info,
156 p_format: pipe_format,
157 ) -> bool {
158 Format::try_from(p_format).is_ok_and(|f| f.supports_storage(dev))
159 }
160
161 #[no_mangle]
nil_format_supports_color_targets( dev: &nv_device_info, p_format: pipe_format, ) -> bool162 pub extern "C" fn nil_format_supports_color_targets(
163 dev: &nv_device_info,
164 p_format: pipe_format,
165 ) -> bool {
166 Format::try_from(p_format).is_ok_and(|f| f.supports_color_targets(dev))
167 }
168
169 #[no_mangle]
nil_format_supports_blending( dev: &nv_device_info, p_format: pipe_format, ) -> bool170 pub extern "C" fn nil_format_supports_blending(
171 dev: &nv_device_info,
172 p_format: pipe_format,
173 ) -> bool {
174 Format::try_from(p_format).is_ok_and(|f| f.supports_blending(dev))
175 }
176
177 #[no_mangle]
nil_format_supports_depth_stencil( dev: &nv_device_info, p_format: pipe_format, ) -> bool178 pub extern "C" fn nil_format_supports_depth_stencil(
179 dev: &nv_device_info,
180 p_format: pipe_format,
181 ) -> bool {
182 Format::try_from(p_format).is_ok_and(|f| f.supports_depth_stencil(dev))
183 }
184
185 #[no_mangle]
nil_format_to_color_target(p_format: pipe_format) -> u32186 pub extern "C" fn nil_format_to_color_target(p_format: pipe_format) -> u32 {
187 Format::try_from(p_format).unwrap().info().czt()
188 }
189
190 #[no_mangle]
nil_format_to_depth_stencil(p_format: pipe_format) -> u32191 pub extern "C" fn nil_format_to_depth_stencil(p_format: pipe_format) -> u32 {
192 Format::try_from(p_format).unwrap().info().czt()
193 }
194
195 #[no_mangle]
nil_format(p_format: pipe_format) -> Format196 pub extern "C" fn nil_format(p_format: pipe_format) -> Format {
197 p_format.try_into().unwrap()
198 }
199