mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 06:00:20 +00:00
Wgpu 0.20 (#13186)
Currently blocked on https://github.com/gfx-rs/wgpu/issues/5774 # Objective Update to wgpu 0.20 ## Solution Update to wgpu 0.20 and naga_oil 0.14. ## Testing Tested a few different examples on linux (vulkan, webgl2, webgpu) and windows (dx12 + vulkan) and they worked. --- ## Changelog - Updated to wgpu 0.20. Note that we don't currently support wgpu's new pipeline overridable constants, as they don't work on web currently and need some more changes to naga_oil (and are somewhat redundant with naga_oil's shader defs). See wgpu's changelog for more https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md#v0200-2024-04-28 ## Migration Guide TODO --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: François Mockers <mockersf@gmail.com>
This commit is contained in:
parent
004ba585b2
commit
2825ac8a8e
7 changed files with 139 additions and 70 deletions
|
@ -17,7 +17,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev", features = [
|
||||||
bytemuck = { version = "1", features = ["derive"] }
|
bytemuck = { version = "1", features = ["derive"] }
|
||||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
wgpu-types = { version = "0.19", default-features = false, optional = true }
|
wgpu-types = { version = "0.20", default-features = false, optional = true }
|
||||||
encase = { version = "0.8", default-features = false }
|
encase = { version = "0.8", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -70,7 +70,7 @@ codespan-reporting = "0.11.0"
|
||||||
# It is enabled for now to avoid having to do a significant overhaul of the renderer just for wasm.
|
# It is enabled for now to avoid having to do a significant overhaul of the renderer just for wasm.
|
||||||
# When the 'atomics' feature is enabled `fragile-send-sync-non-atomic` does nothing
|
# When the 'atomics' feature is enabled `fragile-send-sync-non-atomic` does nothing
|
||||||
# and Bevy instead wraps `wgpu` types to verify they are not used off their origin thread.
|
# and Bevy instead wraps `wgpu` types to verify they are not used off their origin thread.
|
||||||
wgpu = { version = "0.19.3", default-features = false, features = [
|
wgpu = { version = "0.20", default-features = false, features = [
|
||||||
"wgsl",
|
"wgsl",
|
||||||
"dx12",
|
"dx12",
|
||||||
"metal",
|
"metal",
|
||||||
|
@ -78,7 +78,7 @@ wgpu = { version = "0.19.3", default-features = false, features = [
|
||||||
"naga-ir",
|
"naga-ir",
|
||||||
"fragile-send-sync-non-atomic-wasm",
|
"fragile-send-sync-non-atomic-wasm",
|
||||||
] }
|
] }
|
||||||
naga = { version = "0.19", features = ["wgsl-in"] }
|
naga = { version = "0.20", features = ["wgsl-in"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
bitflags = { version = "2.3", features = ["serde"] }
|
bitflags = { version = "2.3", features = ["serde"] }
|
||||||
bytemuck = { version = "1.5", features = ["derive", "must_cast"] }
|
bytemuck = { version = "1.5", features = ["derive", "must_cast"] }
|
||||||
|
@ -104,12 +104,12 @@ smallvec = { version = "1.11", features = ["const_new"] }
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
# Omit the `glsl` feature in non-WebAssembly by default.
|
# Omit the `glsl` feature in non-WebAssembly by default.
|
||||||
naga_oil = { version = "0.13", default-features = false, features = [
|
naga_oil = { version = "0.14", default-features = false, features = [
|
||||||
"test_shader",
|
"test_shader",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
naga_oil = "0.13"
|
naga_oil = "0.14"
|
||||||
js-sys = "0.3"
|
js-sys = "0.3"
|
||||||
web-sys = { version = "0.3.67", features = [
|
web-sys = { version = "0.3.67", features = [
|
||||||
'Blob',
|
'Blob',
|
||||||
|
|
|
@ -159,6 +159,7 @@ struct FrameData {
|
||||||
timestamps_query_set: Option<QuerySet>,
|
timestamps_query_set: Option<QuerySet>,
|
||||||
num_timestamps: u32,
|
num_timestamps: u32,
|
||||||
supports_timestamps_inside_passes: bool,
|
supports_timestamps_inside_passes: bool,
|
||||||
|
supports_timestamps_inside_encoders: bool,
|
||||||
pipeline_statistics_query_set: Option<QuerySet>,
|
pipeline_statistics_query_set: Option<QuerySet>,
|
||||||
num_pipeline_statistics: u32,
|
num_pipeline_statistics: u32,
|
||||||
buffer_size: u64,
|
buffer_size: u64,
|
||||||
|
@ -225,6 +226,8 @@ impl FrameData {
|
||||||
num_timestamps: 0,
|
num_timestamps: 0,
|
||||||
supports_timestamps_inside_passes: features
|
supports_timestamps_inside_passes: features
|
||||||
.contains(Features::TIMESTAMP_QUERY_INSIDE_PASSES),
|
.contains(Features::TIMESTAMP_QUERY_INSIDE_PASSES),
|
||||||
|
supports_timestamps_inside_encoders: features
|
||||||
|
.contains(Features::TIMESTAMP_QUERY_INSIDE_ENCODERS),
|
||||||
pipeline_statistics_query_set,
|
pipeline_statistics_query_set,
|
||||||
num_pipeline_statistics: 0,
|
num_pipeline_statistics: 0,
|
||||||
buffer_size,
|
buffer_size,
|
||||||
|
@ -252,6 +255,11 @@ impl FrameData {
|
||||||
encoder: &mut impl WriteTimestamp,
|
encoder: &mut impl WriteTimestamp,
|
||||||
is_inside_pass: bool,
|
is_inside_pass: bool,
|
||||||
) -> Option<u32> {
|
) -> Option<u32> {
|
||||||
|
// `encoder.write_timestamp` is unsupported on WebGPU.
|
||||||
|
if !self.supports_timestamps_inside_encoders {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
if is_inside_pass && !self.supports_timestamps_inside_passes {
|
if is_inside_pass && !self.supports_timestamps_inside_passes {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1237,6 +1237,7 @@ impl VertexFormatSize for VertexFormat {
|
||||||
VertexFormat::Unorm8x4 => 4,
|
VertexFormat::Unorm8x4 => 4,
|
||||||
VertexFormat::Snorm8x2 => 2,
|
VertexFormat::Snorm8x2 => 2,
|
||||||
VertexFormat::Snorm8x4 => 4,
|
VertexFormat::Snorm8x4 => 4,
|
||||||
|
VertexFormat::Unorm10_10_10_2 => 4,
|
||||||
VertexFormat::Uint16x2 => 2 * 2,
|
VertexFormat::Uint16x2 => 2 * 2,
|
||||||
VertexFormat::Uint16x4 => 2 * 4,
|
VertexFormat::Uint16x4 => 2 * 4,
|
||||||
VertexFormat::Sint16x2 => 2 * 2,
|
VertexFormat::Sint16x2 => 2 * 2,
|
||||||
|
|
|
@ -42,9 +42,9 @@ pub use wgpu::{
|
||||||
Extent3d, Face, Features as WgpuFeatures, FilterMode, FragmentState as RawFragmentState,
|
Extent3d, Face, Features as WgpuFeatures, FilterMode, FragmentState as RawFragmentState,
|
||||||
FrontFace, ImageCopyBuffer, ImageCopyBufferBase, ImageCopyTexture, ImageCopyTextureBase,
|
FrontFace, ImageCopyBuffer, ImageCopyBufferBase, ImageCopyTexture, ImageCopyTextureBase,
|
||||||
ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, Maintain,
|
ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, Maintain,
|
||||||
MapMode, MultisampleState, Operations, Origin3d, PipelineLayout, PipelineLayoutDescriptor,
|
MapMode, MultisampleState, Operations, Origin3d, PipelineCompilationOptions, PipelineLayout,
|
||||||
PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, RenderPassColorAttachment,
|
PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange,
|
||||||
RenderPassDepthStencilAttachment, RenderPassDescriptor,
|
RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor,
|
||||||
RenderPipelineDescriptor as RawRenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor,
|
RenderPipelineDescriptor as RawRenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor,
|
||||||
ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilFaceState,
|
ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilFaceState,
|
||||||
StencilOperation, StencilState, StorageTextureAccess, StoreOp, TextureAspect,
|
StencilOperation, StencilState, StorageTextureAccess, StoreOp, TextureAspect,
|
||||||
|
|
|
@ -25,7 +25,10 @@ use std::{
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
#[cfg(feature = "shader_format_spirv")]
|
#[cfg(feature = "shader_format_spirv")]
|
||||||
use wgpu::util::make_spirv;
|
use wgpu::util::make_spirv;
|
||||||
use wgpu::{DownlevelFlags, Features, VertexBufferLayout as RawVertexBufferLayout};
|
use wgpu::{
|
||||||
|
DownlevelFlags, Features, PipelineCompilationOptions,
|
||||||
|
VertexBufferLayout as RawVertexBufferLayout,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::render_resource::resource_macros::*;
|
use crate::render_resource::resource_macros::*;
|
||||||
|
|
||||||
|
@ -170,73 +173,17 @@ impl ShaderDefVal {
|
||||||
|
|
||||||
impl ShaderCache {
|
impl ShaderCache {
|
||||||
fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self {
|
fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self {
|
||||||
const CAPABILITIES: &[(Features, Capabilities)] = &[
|
let (capabilities, subgroup_stages) = get_capabilities(
|
||||||
(Features::PUSH_CONSTANTS, Capabilities::PUSH_CONSTANT),
|
render_device.features(),
|
||||||
(Features::SHADER_F64, Capabilities::FLOAT64),
|
render_adapter.get_downlevel_capabilities().flags,
|
||||||
(
|
);
|
||||||
Features::SHADER_PRIMITIVE_INDEX,
|
|
||||||
Capabilities::PRIMITIVE_INDEX,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
|
||||||
Capabilities::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
|
||||||
Capabilities::SAMPLER_NON_UNIFORM_INDEXING,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
|
||||||
Capabilities::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Features::TEXTURE_FORMAT_16BIT_NORM,
|
|
||||||
Capabilities::STORAGE_TEXTURE_16BIT_NORM_FORMATS,
|
|
||||||
),
|
|
||||||
(Features::MULTIVIEW, Capabilities::MULTIVIEW),
|
|
||||||
(
|
|
||||||
Features::SHADER_EARLY_DEPTH_TEST,
|
|
||||||
Capabilities::EARLY_DEPTH_TEST,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
let features = render_device.features();
|
|
||||||
let mut capabilities = Capabilities::empty();
|
|
||||||
for (feature, capability) in CAPABILITIES {
|
|
||||||
if features.contains(*feature) {
|
|
||||||
capabilities |= *capability;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const DOWNLEVEL_FLAGS_CAPABILITIES: &[(DownlevelFlags, Capabilities)] = &[
|
|
||||||
(
|
|
||||||
DownlevelFlags::CUBE_ARRAY_TEXTURES,
|
|
||||||
Capabilities::CUBE_ARRAY_TEXTURES,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
DownlevelFlags::MULTISAMPLED_SHADING,
|
|
||||||
Capabilities::MULTISAMPLED_SHADING,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
DownlevelFlags::CUBE_ARRAY_TEXTURES,
|
|
||||||
Capabilities::CUBE_ARRAY_TEXTURES,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
for (downlevel_flag, capability) in DOWNLEVEL_FLAGS_CAPABILITIES {
|
|
||||||
if render_adapter
|
|
||||||
.get_downlevel_capabilities()
|
|
||||||
.flags
|
|
||||||
.contains(*downlevel_flag)
|
|
||||||
{
|
|
||||||
capabilities |= *capability;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
let composer = naga_oil::compose::Composer::default();
|
let composer = naga_oil::compose::Composer::default();
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
let composer = naga_oil::compose::Composer::non_validating();
|
let composer = naga_oil::compose::Composer::non_validating();
|
||||||
|
|
||||||
let composer = composer.with_capabilities(capabilities);
|
let composer = composer.with_capabilities(capabilities, subgroup_stages);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
composer,
|
composer,
|
||||||
|
@ -791,6 +738,12 @@ impl PipelineCache {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: Expose this somehow
|
||||||
|
let compilation_options = PipelineCompilationOptions {
|
||||||
|
constants: &std::collections::HashMap::new(),
|
||||||
|
zero_initialize_workgroup_memory: false,
|
||||||
|
};
|
||||||
|
|
||||||
let descriptor = RawRenderPipelineDescriptor {
|
let descriptor = RawRenderPipelineDescriptor {
|
||||||
multiview: None,
|
multiview: None,
|
||||||
depth_stencil: descriptor.depth_stencil.clone(),
|
depth_stencil: descriptor.depth_stencil.clone(),
|
||||||
|
@ -802,6 +755,8 @@ impl PipelineCache {
|
||||||
buffers: &vertex_buffer_layouts,
|
buffers: &vertex_buffer_layouts,
|
||||||
entry_point: descriptor.vertex.entry_point.deref(),
|
entry_point: descriptor.vertex.entry_point.deref(),
|
||||||
module: &vertex_module,
|
module: &vertex_module,
|
||||||
|
// TODO: Should this be the same as the fragment compilation options?
|
||||||
|
compilation_options: compilation_options.clone(),
|
||||||
},
|
},
|
||||||
fragment: fragment_data
|
fragment: fragment_data
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -809,6 +764,8 @@ impl PipelineCache {
|
||||||
entry_point,
|
entry_point,
|
||||||
module,
|
module,
|
||||||
targets,
|
targets,
|
||||||
|
// TODO: Should this be the same as the vertex compilation options?
|
||||||
|
compilation_options,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -861,6 +818,11 @@ impl PipelineCache {
|
||||||
layout: layout.as_deref(),
|
layout: layout.as_deref(),
|
||||||
module: &compute_module,
|
module: &compute_module,
|
||||||
entry_point: &descriptor.entry_point,
|
entry_point: &descriptor.entry_point,
|
||||||
|
// TODO: Expose this somehow
|
||||||
|
compilation_options: PipelineCompilationOptions {
|
||||||
|
constants: &std::collections::HashMap::new(),
|
||||||
|
zero_initialize_workgroup_memory: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Pipeline::ComputePipeline(
|
Ok(Pipeline::ComputePipeline(
|
||||||
|
@ -1027,3 +989,89 @@ pub enum PipelineCacheError {
|
||||||
#[error("Could not create shader module: {0}")]
|
#[error("Could not create shader module: {0}")]
|
||||||
CreateShaderModule(String),
|
CreateShaderModule(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This needs to be kept up to date with the capabilities in the `create_validator` function in wgpu-core
|
||||||
|
// https://github.com/gfx-rs/wgpu/blob/trunk/wgpu-core/src/device/mod.rs#L449
|
||||||
|
// We use a modified version of the `create_validator` function because `naga_oil`'s composer stores the capabilities
|
||||||
|
// and subgroup shader stages instead of a `Validator`.
|
||||||
|
// We also can't use that function because `wgpu-core` isn't included in WebGPU builds.
|
||||||
|
/// Get the device capabilities and subgroup support for use in `naga_oil`.
|
||||||
|
fn get_capabilities(
|
||||||
|
features: Features,
|
||||||
|
downlevel: DownlevelFlags,
|
||||||
|
) -> (Capabilities, naga::valid::ShaderStages) {
|
||||||
|
let mut capabilities = Capabilities::empty();
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::PUSH_CONSTANT,
|
||||||
|
features.contains(Features::PUSH_CONSTANTS),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::FLOAT64,
|
||||||
|
features.contains(Features::SHADER_F64),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::PRIMITIVE_INDEX,
|
||||||
|
features.contains(Features::SHADER_PRIMITIVE_INDEX),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||||
|
features.contains(Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||||
|
features.contains(Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING),
|
||||||
|
);
|
||||||
|
// TODO: This needs a proper wgpu feature
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::SAMPLER_NON_UNIFORM_INDEXING,
|
||||||
|
features.contains(Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::STORAGE_TEXTURE_16BIT_NORM_FORMATS,
|
||||||
|
features.contains(Features::TEXTURE_FORMAT_16BIT_NORM),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::MULTIVIEW,
|
||||||
|
features.contains(Features::MULTIVIEW),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::EARLY_DEPTH_TEST,
|
||||||
|
features.contains(Features::SHADER_EARLY_DEPTH_TEST),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::SHADER_INT64,
|
||||||
|
features.contains(Features::SHADER_INT64),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::MULTISAMPLED_SHADING,
|
||||||
|
downlevel.contains(DownlevelFlags::MULTISAMPLED_SHADING),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::DUAL_SOURCE_BLENDING,
|
||||||
|
features.contains(Features::DUAL_SOURCE_BLENDING),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::CUBE_ARRAY_TEXTURES,
|
||||||
|
downlevel.contains(DownlevelFlags::CUBE_ARRAY_TEXTURES),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::SUBGROUP,
|
||||||
|
features.intersects(Features::SUBGROUP | Features::SUBGROUP_VERTEX),
|
||||||
|
);
|
||||||
|
capabilities.set(
|
||||||
|
Capabilities::SUBGROUP_BARRIER,
|
||||||
|
features.intersects(Features::SUBGROUP_BARRIER),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut subgroup_stages = naga::valid::ShaderStages::empty();
|
||||||
|
subgroup_stages.set(
|
||||||
|
naga::valid::ShaderStages::COMPUTE | naga::valid::ShaderStages::FRAGMENT,
|
||||||
|
features.contains(Features::SUBGROUP),
|
||||||
|
);
|
||||||
|
subgroup_stages.set(
|
||||||
|
naga::valid::ShaderStages::VERTEX,
|
||||||
|
features.contains(Features::SUBGROUP_VERTEX),
|
||||||
|
);
|
||||||
|
|
||||||
|
(capabilities, subgroup_stages)
|
||||||
|
}
|
||||||
|
|
|
@ -326,6 +326,18 @@ pub async fn initialize_renderer(
|
||||||
max_non_sampler_bindings: limits
|
max_non_sampler_bindings: limits
|
||||||
.max_non_sampler_bindings
|
.max_non_sampler_bindings
|
||||||
.min(constrained_limits.max_non_sampler_bindings),
|
.min(constrained_limits.max_non_sampler_bindings),
|
||||||
|
max_color_attachments: limits
|
||||||
|
.max_color_attachments
|
||||||
|
.min(constrained_limits.max_color_attachments),
|
||||||
|
max_color_attachment_bytes_per_sample: limits
|
||||||
|
.max_color_attachment_bytes_per_sample
|
||||||
|
.min(constrained_limits.max_color_attachment_bytes_per_sample),
|
||||||
|
min_subgroup_size: limits
|
||||||
|
.min_subgroup_size
|
||||||
|
.max(constrained_limits.min_subgroup_size),
|
||||||
|
max_subgroup_size: limits
|
||||||
|
.max_subgroup_size
|
||||||
|
.min(constrained_limits.max_subgroup_size),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue