1#[cfg(any(dx12, all(vulkan, windows)))]
5pub(super) mod dxgi;
6
7#[cfg(any(dx12, all(vulkan, windows)))]
8pub(super) mod dyn_lib;
9
10#[cfg(all(native, feature = "renderdoc"))]
11pub(super) mod renderdoc;
12
13pub mod db {
14 pub mod amd {
15 pub const VENDOR: u32 = 0x1002;
17 }
18 pub mod apple {
19 pub const VENDOR: u32 = 0x106B;
21 }
22 pub mod arm {
23 pub const VENDOR: u32 = 0x13B5;
25 }
26 pub mod broadcom {
27 pub const VENDOR: u32 = 0x14E4;
29 }
30 pub mod imgtec {
31 pub const VENDOR: u32 = 0x1010;
33 }
34 pub mod intel {
35 pub const VENDOR: u32 = 0x8086;
37 pub const DEVICE_KABY_LAKE_MASK: u32 = 0x5900;
38 pub const DEVICE_SKY_LAKE_MASK: u32 = 0x1900;
39 }
40 pub mod mesa {
41 pub const VENDOR: u32 = 0x10005;
47 }
48 pub mod nvidia {
49 pub const VENDOR: u32 = 0x10DE;
51 }
52 pub mod qualcomm {
53 pub const VENDOR: u32 = 0x5143;
55 }
56 pub mod verisilicon {
57 pub const VENDOR: u32 = 0x10002;
60 }
61}
62
63pub const MAX_I32_BINDING_SIZE: u32 = (1 << 31) - 1;
68
69pub use wgpu_naga_bridge::map_naga_stage;
70
71impl crate::CopyExtent {
72 pub fn map_extent_to_copy_size(extent: &wgt::Extent3d, dim: wgt::TextureDimension) -> Self {
73 Self {
74 width: extent.width,
75 height: extent.height,
76 depth: match dim {
77 wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => 1,
78 wgt::TextureDimension::D3 => extent.depth_or_array_layers,
79 },
80 }
81 }
82
83 pub fn min(&self, other: &Self) -> Self {
84 Self {
85 width: self.width.min(other.width),
86 height: self.height.min(other.height),
87 depth: self.depth.min(other.depth),
88 }
89 }
90
91 pub fn at_mip_level(&self, level: u32) -> Self {
95 Self {
96 width: (self.width >> level).max(1),
97 height: (self.height >> level).max(1),
98 depth: (self.depth >> level).max(1),
99 }
100 }
101}
102
103impl crate::TextureCopyBase {
104 pub fn max_copy_size(&self, full_size: &crate::CopyExtent) -> crate::CopyExtent {
105 let mip = full_size.at_mip_level(self.mip_level);
106 crate::CopyExtent {
107 width: mip.width - self.origin.x,
108 height: mip.height - self.origin.y,
109 depth: mip.depth - self.origin.z,
110 }
111 }
112}
113
114impl crate::BufferTextureCopy {
115 pub fn clamp_size_to_virtual(&mut self, full_size: &crate::CopyExtent) {
116 let max_size = self.texture_base.max_copy_size(full_size);
117 self.size = self.size.min(&max_size);
118 }
119}
120
121impl crate::TextureCopy {
122 pub fn clamp_size_to_virtual(
123 &mut self,
124 full_src_size: &crate::CopyExtent,
125 full_dst_size: &crate::CopyExtent,
126 ) {
127 let max_src_size = self.src_base.max_copy_size(full_src_size);
128 let max_dst_size = self.dst_base.max_copy_size(full_dst_size);
129 self.size = self.size.min(&max_src_size).min(&max_dst_size);
130 }
131}
132
133#[cfg_attr(not(any_backend), allow(dead_code))]
136pub(crate) fn adjust_raw_limits(mut limits: wgt::Limits) -> wgt::Limits {
137 limits.max_bind_groups = limits.max_bind_groups.min(crate::MAX_BIND_GROUPS as u32);
139 limits.max_vertex_buffers = limits
140 .max_vertex_buffers
141 .min(crate::MAX_VERTEX_BUFFERS as u32);
142 const { assert!(crate::MAX_BIND_GROUPS + crate::MAX_VERTEX_BUFFERS == 24) };
146 limits.max_bind_groups_plus_vertex_buffers = limits.max_bind_groups_plus_vertex_buffers.min(24);
147 limits.max_color_attachments = limits
148 .max_color_attachments
149 .min(crate::MAX_COLOR_ATTACHMENTS as u32);
150
151 const MAX_SHADER_STAGES_PER_PIPELINE: u32 = 2;
160 let max_per_stage_resources =
161 limits.max_bindings_per_bind_group / MAX_SHADER_STAGES_PER_PIPELINE;
162
163 cap_limits_to_be_under_the_sum_limit(
164 [
165 &mut limits.max_sampled_textures_per_shader_stage,
166 &mut limits.max_uniform_buffers_per_shader_stage,
167 &mut limits.max_storage_textures_per_shader_stage,
168 &mut limits.max_storage_buffers_per_shader_stage,
169 &mut limits.max_samplers_per_shader_stage,
170 &mut limits.max_acceleration_structures_per_shader_stage,
171 ],
172 max_per_stage_resources,
173 );
174 for (per_shader_stage, in_stage) in [
177 (
178 limits.max_storage_buffers_per_shader_stage,
179 [
180 &mut limits.max_storage_buffers_in_vertex_stage,
181 &mut limits.max_storage_buffers_in_fragment_stage,
182 ],
183 ),
184 (
185 limits.max_storage_textures_per_shader_stage,
186 [
187 &mut limits.max_storage_textures_in_vertex_stage,
188 &mut limits.max_storage_textures_in_fragment_stage,
189 ],
190 ),
191 ] {
192 for stage in in_stage {
193 assert_eq!(
194 *stage, 0,
195 "`max_storage_*_in_*_stage` limits must be 0 from HAL (for now)"
196 );
197 *stage = per_shader_stage;
198 }
199 }
200
201 limits.max_dynamic_uniform_buffers_per_pipeline_layout = limits
204 .max_dynamic_uniform_buffers_per_pipeline_layout
205 .min(limits.max_uniform_buffers_per_shader_stage);
206 limits.max_dynamic_storage_buffers_per_pipeline_layout = limits
207 .max_dynamic_storage_buffers_per_pipeline_layout
208 .min(limits.max_storage_buffers_per_shader_stage);
209
210 limits.min_uniform_buffer_offset_alignment = limits.min_uniform_buffer_offset_alignment.max(32);
211 limits.min_storage_buffer_offset_alignment = limits.min_storage_buffer_offset_alignment.max(32);
212
213 limits.max_uniform_buffer_binding_size = limits
214 .max_uniform_buffer_binding_size
215 .min(limits.max_buffer_size);
216 limits.max_storage_buffer_binding_size = limits
217 .max_storage_buffer_binding_size
218 .min(limits.max_buffer_size);
219
220 limits.max_storage_buffer_binding_size &= !(u64::from(wgt::STORAGE_BINDING_SIZE_ALIGNMENT) - 1);
221 limits.max_vertex_buffer_array_stride &= !(wgt::VERTEX_ALIGNMENT as u32 - 1);
222
223 let x = limits.max_compute_workgroup_size_x;
224 let y = limits.max_compute_workgroup_size_y;
225 let z = limits.max_compute_workgroup_size_z;
226 let m = limits.max_compute_invocations_per_workgroup;
227 limits.max_compute_workgroup_size_x = x.min(m);
228 limits.max_compute_workgroup_size_y = y.min(m);
229 limits.max_compute_workgroup_size_z = z.min(m);
230 limits.max_compute_invocations_per_workgroup = m.min(x.saturating_mul(y).saturating_mul(z));
231
232 limits.max_immediate_size = limits.max_immediate_size.min(256);
233
234 limits
235}
236
237pub fn cap_limits_to_be_under_the_sum_limit<const N: usize>(
240 mut limits: [&mut u32; N],
241 sum_limit: u32,
242) {
243 limits.sort();
244
245 let mut rem_limit = sum_limit;
246 let mut divisor = limits.len() as u32;
247 for limit_to_adjust in limits {
248 let limit = rem_limit / divisor;
249 *limit_to_adjust = (*limit_to_adjust).min(limit);
250 rem_limit -= *limit_to_adjust;
251 divisor -= 1;
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258
259 #[test]
260 fn test_cap_limits_to_be_under_the_sum_limit() {
261 test([3, 3, 3], 3, [1, 1, 1]);
262 test([3, 2, 1], 3, [1, 1, 1]);
263 test([1, 2, 3], 6, [1, 2, 3]);
264 test([1, 2, 3], 3, [1, 1, 1]);
265 test([1, 8, 100], 6, [1, 2, 3]);
266 test([2, 80, 80], 6, [2, 2, 2]);
267 test([2, 80, 80], 12, [2, 5, 5]);
268
269 #[track_caller]
270 fn test<const N: usize>(mut input: [u32; N], limit: u32, output: [u32; N]) {
271 cap_limits_to_be_under_the_sum_limit(input.each_mut(), limit);
272 assert_eq!(input, output);
273 }
274 }
275}