mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Merge #1599
1599: Fix Limits for lava/llvmpipe and re-enable and re-work CI r=kvark,groves,wumpf a=cwfitzgerald **Connections** No longer fixes #1551. **Description** This PR has a couple things going on at once. - Fixes limits for llvmpipe, lavapipe, and rpi4. - Added a downlevel limit to express that RPI4 does not allow storage buffers in vertex shaders on GL. - Added a `Limits::downlevel_default()` that takes minimum limits from GLES and adds some more documentation on how to choose limits. - Moved all examples to the new downlevel limits - Reworks CI to re-enable software testing and unify instructions. **Testing** It is Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
This commit is contained in:
288
.github/workflows/ci.yml
vendored
288
.github/workflows/ci.yml
vendored
@@ -8,166 +8,170 @@ on:
|
||||
branches-ignore: [staging.tmp]
|
||||
|
||||
jobs:
|
||||
ios_build:
|
||||
name: iOS Stable
|
||||
runs-on: macos-10.15
|
||||
env:
|
||||
TARGET: aarch64-apple-ios
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: rustup component add clippy
|
||||
- run: rustup target add ${{ env.TARGET }}
|
||||
- run: cargo clippy --target ${{ env.TARGET }}
|
||||
|
||||
android_build:
|
||||
name: Android Stable
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TARGET: aarch64-linux-android
|
||||
PKG_CONFIG_ALLOW_CROSS: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: echo "$ANDROID_HOME/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_PATH
|
||||
- run: rustup component add clippy
|
||||
- run: rustup target add ${{ env.TARGET }}
|
||||
- run: cargo clippy --target ${{ env.TARGET }}
|
||||
- name: Additional core features
|
||||
run: cargo check --manifest-path wgpu-core/Cargo.toml --features trace --target ${{ env.TARGET }}
|
||||
|
||||
wasm:
|
||||
name: Web Assembly
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RUSTFLAGS: --cfg=web_sys_unstable_apis
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: rustup target add wasm32-unknown-unknown
|
||||
- name: Check WebGPU
|
||||
run: cargo check --package wgpu --examples --target=wasm32-unknown-unknown
|
||||
# disable until hal/Gles backend is setup
|
||||
# - name: Check WebGL
|
||||
# run: cargo check --all-targets --target=wasm32-unknown-unknown --features webgl
|
||||
|
||||
build:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-10.15, ubuntu-20.04, windows-2019]
|
||||
channel: [stable, nightly]
|
||||
include:
|
||||
- name: MacOS Stable
|
||||
channel: stable
|
||||
os: macos-10.15
|
||||
prepare_command:
|
||||
clippy_params:
|
||||
additional_core_features:
|
||||
additional_player_features: winit
|
||||
wrapper_features: trace
|
||||
- name: MacOS Nightly
|
||||
os: macos-10.15
|
||||
channel: nightly
|
||||
prepare_command:
|
||||
clippy_params:
|
||||
additional_core_features:
|
||||
additional_player_features:
|
||||
wrapper_features:
|
||||
- name: Ubuntu Stable
|
||||
os: ubuntu-20.04
|
||||
channel: stable
|
||||
prepare_command:
|
||||
clippy_params: --examples --all
|
||||
additional_core_features: trace,serial-pass
|
||||
additional_player_features: winit
|
||||
wrapper_features: spirv,replay
|
||||
- name: Ubuntu Nightly
|
||||
os: ubuntu-20.04
|
||||
channel: nightly
|
||||
prepare_command: |
|
||||
echo "Installing Vulkan"
|
||||
sudo apt-get update -y -qq
|
||||
sudo add-apt-repository ppa:ubuntu-x-swat/updates -y
|
||||
sudo apt-get update
|
||||
sudo apt install -y libxcb-xfixes0-dev mesa-vulkan-drivers
|
||||
clippy_params:
|
||||
additional_core_features: serial-pass
|
||||
additional_player_features:
|
||||
wrapper_features:
|
||||
- name: Windows Stable
|
||||
# Windows
|
||||
- name: Windows x86_64
|
||||
os: windows-2019
|
||||
channel: stable
|
||||
prepare_command: rustup default stable-msvc
|
||||
clippy_params:
|
||||
additional_core_features:
|
||||
additional_player_features:
|
||||
wrapper_features:
|
||||
- name: Windows Nightly
|
||||
os: windows-2019
|
||||
target: x86_64-pc-windows-msvc
|
||||
kind: compile
|
||||
|
||||
# MacOS
|
||||
|
||||
# Mac has no software runners, so don't run tests
|
||||
- name: MacOS x86_64
|
||||
os: macos-10.15
|
||||
channel: stable
|
||||
target: x86_64-apple-darwin
|
||||
kind: compile
|
||||
|
||||
|
||||
# IOS
|
||||
- name: IOS aarch64
|
||||
os: macos-10.15
|
||||
channel: stable
|
||||
target: aarch64-apple-ios
|
||||
kind: compile
|
||||
|
||||
|
||||
# Linux
|
||||
- name: Linux x86_64
|
||||
os: ubuntu-20.04
|
||||
channel: stable
|
||||
target: x86_64-unknown-linux-gnu
|
||||
kind: test
|
||||
|
||||
- name: Linux Nightly x86_64
|
||||
os: ubuntu-20.04
|
||||
channel: nightly
|
||||
prepare_command: rustup default nightly-msvc
|
||||
clippy_params:
|
||||
additional_core_features:
|
||||
additional_player_features:
|
||||
wrapper_features:
|
||||
target: x86_64-unknown-linux-gnu
|
||||
kind: compile
|
||||
|
||||
|
||||
# Android
|
||||
- name: Android aarch64
|
||||
os: ubuntu-20.04
|
||||
channel: stable
|
||||
target: aarch64-linux-android
|
||||
kind: compile
|
||||
|
||||
|
||||
# WebGPU/WebGL
|
||||
- name: WebAssembly
|
||||
os: ubuntu-20.04
|
||||
channel: stable
|
||||
target: wasm32-unknown-unknown
|
||||
kind: webgl
|
||||
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
env:
|
||||
PKG_CONFIG_ALLOW_CROSS: 1 # allow android to work
|
||||
RUSTFLAGS: --cfg=web_sys_unstable_apis
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- if: matrix.channel == 'nightly'
|
||||
name: Install latest nightly
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: install rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
toolchain: ${{ matrix.channel }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- if: matrix.clippy_params != ''
|
||||
run: rustup component add clippy
|
||||
# prepare
|
||||
- if: matrix.prepare_command != ''
|
||||
run: ${{ matrix.prepare_command }}
|
||||
# regular build
|
||||
- if: matrix.additional_core_features != ''
|
||||
run: cargo check --manifest-path wgpu-core/Cargo.toml --features ${{ matrix.additional_core_features }}
|
||||
- if: matrix.additional_player_features != ''
|
||||
run: cargo check --manifest-path player/Cargo.toml --features ${{ matrix.additional_player_features }}
|
||||
- run: cargo check --manifest-path wgpu/Cargo.toml --examples --features ${{ matrix.wrapper_features }},
|
||||
# clippy
|
||||
- if: matrix.clippy_params != ''
|
||||
run: cargo clippy ${{ matrix.clippy_params }}
|
||||
- if: matrix.channel == 'nightly'
|
||||
run: cargo test -p wgpu-core -- --nocapture
|
||||
# - if: matrix.channel == 'nightly'
|
||||
# run: cargo run --bin wgpu-info -- cargo test -p wgpu -- --nocapture
|
||||
profile: minimal
|
||||
components: clippy
|
||||
|
||||
- name: add android apk to path
|
||||
if: matrix.os == 'ubuntu-20.04' && matrix.target == 'aarch64-linux-android'
|
||||
run: |
|
||||
echo "$ANDROID_HOME/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_PATH
|
||||
|
||||
docs:
|
||||
runs-on: [ubuntu-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install latest nightly
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
override: true
|
||||
continue-on-error: true
|
||||
- name: cargo doc
|
||||
run: cargo --version; cargo doc --no-deps
|
||||
continue-on-error: true
|
||||
- name: install llvmpipe and lavapipe
|
||||
if: matrix.os == 'ubuntu-20.04' && matrix.kind == 'test'
|
||||
run: |
|
||||
echo "Installing Vulkan"
|
||||
sudo apt-get update -y -qq
|
||||
sudo add-apt-repository ppa:ubuntu-x-swat/updates -y
|
||||
sudo apt-get update
|
||||
sudo apt install -y libxcb-xfixes0-dev mesa-vulkan-drivers
|
||||
|
||||
lint:
|
||||
name: Clippy
|
||||
- name: load cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ matrix.name }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ matrix.name }}-cargo-
|
||||
|
||||
# This is separate for now because webgl isn't hooked up so we can't compile wgpu-core for wasm
|
||||
- name: check web
|
||||
if: matrix.kind == 'webgl'
|
||||
run: |
|
||||
cargo clippy --target ${{ matrix.target }} -p wgpu -- -D warnings
|
||||
|
||||
- name: check native stable (fatal warnings)
|
||||
if: (matrix.kind == 'compile' || matrix.kind == 'test') && matrix.channel == 'stable'
|
||||
run: |
|
||||
# check with no features
|
||||
cargo clippy --target ${{ matrix.target }} -p wgpu -p wgpu-core -p wgpu-info -p player -- -D warnings
|
||||
|
||||
# check with all features
|
||||
# explicitly don't mention wgpu-hal so that --all-features don't apply to it
|
||||
cargo clippy --target ${{ matrix.target }} -p wgpu -p wgpu-core -p wgpu-info -p player --examples --tests --all-features -- -D warnings
|
||||
|
||||
- name: check native nightly (non-fatal warnings)
|
||||
if: (matrix.kind == 'compile' || matrix.kind == 'test') && matrix.channel != 'stable'
|
||||
run: |
|
||||
# check with no features
|
||||
cargo clippy --target ${{ matrix.target }} -p wgpu -p wgpu-core -p wgpu-info -p player
|
||||
|
||||
# check with all features
|
||||
# explicitly don't mention wgpu-hal so that --all-features don't apply to it
|
||||
cargo clippy --target ${{ matrix.target }} -p wgpu -p wgpu-core -p wgpu-info -p player --examples --tests --all-features
|
||||
|
||||
- name: build tests
|
||||
if: matrix.kind == 'test'
|
||||
run: |
|
||||
cargo build --target ${{ matrix.target }} --bin wgpu-info
|
||||
cargo build --target ${{ matrix.target }} --tests -p player
|
||||
cargo build --target ${{ matrix.target }} --examples --tests -p wgpu
|
||||
|
||||
# - name: tests
|
||||
# if: matrix.kind == 'test'
|
||||
# run: |
|
||||
# # run wgpu-info
|
||||
# cargo run --target ${{ matrix.target }} --bin wgpu-info
|
||||
|
||||
# # run player tests
|
||||
# cargo test --target ${{ matrix.target }} -p player -- --nocapture
|
||||
|
||||
# # run coretests
|
||||
# cargo run --target ${{ matrix.target }} --bin wgpu-info -- cargo test --target ${{ matrix.target }} -p wgpu -- --nocapture --test-threads=1 # GLES is currently non-multithreadable
|
||||
|
||||
fmt:
|
||||
name: Format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: install rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
- run: rustup component add clippy
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: -- -D warnings
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: -- --check
|
||||
components: rustfmt
|
||||
|
||||
- name: run rustfmt
|
||||
run: |
|
||||
cargo fmt -- --check
|
||||
|
||||
18
bors.toml
18
bors.toml
@@ -1,12 +1,10 @@
|
||||
status = [
|
||||
"iOS Stable",
|
||||
"MacOS Stable",
|
||||
"MacOS Nightly",
|
||||
"Android Stable",
|
||||
"Ubuntu Stable",
|
||||
"Ubuntu Nightly",
|
||||
"Windows Stable",
|
||||
"Windows Nightly",
|
||||
"Web Assembly",
|
||||
#"Clippy",
|
||||
"Windows x86_64",
|
||||
"MacOS x86_64",
|
||||
"IOS aarch64",
|
||||
"Linux x86_64",
|
||||
"Linux Nightly x86_64",
|
||||
"Android aarch64",
|
||||
"WebAssembly",
|
||||
"Format",
|
||||
]
|
||||
|
||||
@@ -980,6 +980,7 @@ impl<A: HalApi> Device<A> {
|
||||
use wgt::BindingType as Bt;
|
||||
|
||||
let mut required_features = wgt::Features::empty();
|
||||
let mut required_downlevel_flags = wgt::DownlevelFlags::empty();
|
||||
let (array_feature, is_writable_storage) = match entry.ty {
|
||||
Bt::Buffer {
|
||||
ty: wgt::BufferBindingType::Uniform,
|
||||
@@ -1029,6 +1030,9 @@ impl<A: HalApi> Device<A> {
|
||||
error,
|
||||
})?;
|
||||
}
|
||||
if entry.visibility.contains(wgt::ShaderStages::VERTEX) {
|
||||
required_downlevel_flags |= wgt::DownlevelFlags::VERTEX_ACCESSABLE_STORAGE_BUFFERS;
|
||||
}
|
||||
if is_writable_storage && entry.visibility.contains(wgt::ShaderStages::VERTEX) {
|
||||
required_features |= wgt::Features::VERTEX_WRITABLE_STORAGE;
|
||||
}
|
||||
@@ -1047,6 +1051,13 @@ impl<A: HalApi> Device<A> {
|
||||
binding: entry.binding,
|
||||
error,
|
||||
})?;
|
||||
|
||||
self.require_downlevel_flags(required_downlevel_flags)
|
||||
.map_err(binding_model::BindGroupLayoutEntryError::MissingDownlevelFlags)
|
||||
.map_err(|error| binding_model::CreateBindGroupLayoutError::Entry {
|
||||
binding: entry.binding,
|
||||
error,
|
||||
})?;
|
||||
}
|
||||
|
||||
let mut hal_bindings = entry_map.values().cloned().collect::<Vec<_>>();
|
||||
|
||||
@@ -60,6 +60,15 @@ fn check_limits(requested: &wgt::Limits, allowed: &wgt::Limits) -> Vec<FailedLim
|
||||
failed
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downlevel_default_limits_less_than_default_limits() {
|
||||
let res = check_limits(&wgt::Limits::downlevel_defaults(), &wgt::Limits::default());
|
||||
assert!(
|
||||
res.is_empty(),
|
||||
"Downlevel limits are greater than default limits",
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Instance {
|
||||
#[allow(dead_code)]
|
||||
name: String,
|
||||
|
||||
@@ -114,6 +114,7 @@ impl super::Adapter {
|
||||
"igp",
|
||||
"mali",
|
||||
"intel",
|
||||
"v3d",
|
||||
];
|
||||
let strings_that_imply_cpu = ["mesa offscreen", "swiftshader", "llvmpipe"];
|
||||
|
||||
@@ -144,6 +145,8 @@ impl super::Adapter {
|
||||
0x5143
|
||||
} else if vendor.contains("intel") {
|
||||
0x8086
|
||||
} else if vendor.contains("broadcom") {
|
||||
0x14e4
|
||||
} else {
|
||||
0
|
||||
};
|
||||
@@ -184,6 +187,11 @@ impl super::Adapter {
|
||||
);
|
||||
features.set(wgt::Features::VERTEX_WRITABLE_STORAGE, ver >= (3, 1));
|
||||
|
||||
let vertex_shader_storage_blocks =
|
||||
gl.get_parameter_i32(glow::MAX_VERTEX_SHADER_STORAGE_BLOCKS);
|
||||
let fragment_shader_storage_blocks =
|
||||
gl.get_parameter_i32(glow::MAX_FRAGMENT_SHADER_STORAGE_BLOCKS);
|
||||
|
||||
let mut downlevel_flags = wgt::DownlevelFlags::empty()
|
||||
| wgt::DownlevelFlags::DEVICE_LOCAL_IMAGE_COPIES
|
||||
| wgt::DownlevelFlags::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES
|
||||
@@ -202,6 +210,10 @@ impl super::Adapter {
|
||||
wgt::DownlevelFlags::INDEPENDENT_BLENDING,
|
||||
ver >= (3, 2) || extensions.contains("GL_EXT_draw_buffers_indexed"),
|
||||
);
|
||||
downlevel_flags.set(
|
||||
wgt::DownlevelFlags::VERTEX_ACCESSABLE_STORAGE_BUFFERS,
|
||||
vertex_shader_storage_blocks > 0,
|
||||
);
|
||||
|
||||
let max_texture_size = gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) as u32;
|
||||
let max_texture_3d_size = gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) as u32;
|
||||
@@ -216,10 +228,12 @@ impl super::Adapter {
|
||||
let max_uniform_buffers_per_shader_stage =
|
||||
gl.get_parameter_i32(glow::MAX_VERTEX_UNIFORM_BLOCKS)
|
||||
.min(gl.get_parameter_i32(glow::MAX_FRAGMENT_UNIFORM_BLOCKS)) as u32;
|
||||
let max_storage_buffers_per_shader_stage = gl
|
||||
.get_parameter_i32(glow::MAX_VERTEX_SHADER_STORAGE_BLOCKS)
|
||||
.min(gl.get_parameter_i32(glow::MAX_FRAGMENT_SHADER_STORAGE_BLOCKS))
|
||||
as u32;
|
||||
let max_storage_buffers_per_shader_stage = if vertex_shader_storage_blocks > 0 {
|
||||
vertex_shader_storage_blocks.min(fragment_shader_storage_blocks)
|
||||
} else {
|
||||
fragment_shader_storage_blocks
|
||||
} as u32;
|
||||
|
||||
let max_storage_textures_per_shader_stage =
|
||||
gl.get_parameter_i32(glow::MAX_FRAGMENT_IMAGE_UNIFORMS) as u32;
|
||||
|
||||
@@ -239,10 +253,10 @@ impl super::Adapter {
|
||||
max_uniform_buffer_binding_size: gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE)
|
||||
as u32,
|
||||
max_storage_buffer_binding_size: if ver >= (3, 1) {
|
||||
gl.get_parameter_i32(glow::MAX_SHADER_STORAGE_BLOCK_SIZE) as u32
|
||||
gl.get_parameter_i32(glow::MAX_SHADER_STORAGE_BLOCK_SIZE)
|
||||
} else {
|
||||
0
|
||||
},
|
||||
} as u32,
|
||||
max_vertex_buffers: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_BINDINGS) as u32,
|
||||
max_vertex_attributes: (gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIBS) as u32)
|
||||
.min(super::MAX_VERTEX_ATTRIBUTES as u32),
|
||||
@@ -266,7 +280,7 @@ impl super::Adapter {
|
||||
ver >= (3, 1),
|
||||
);
|
||||
|
||||
let downlevel_limits = wgt::DownlevelLimits {};
|
||||
let downlevel_defaults = wgt::DownlevelLimits {};
|
||||
|
||||
Some(crate::ExposedAdapter {
|
||||
adapter: super::Adapter {
|
||||
@@ -282,7 +296,7 @@ impl super::Adapter {
|
||||
limits,
|
||||
downlevel: wgt::DownlevelCapabilities {
|
||||
flags: downlevel_flags,
|
||||
limits: downlevel_limits,
|
||||
limits: downlevel_defaults,
|
||||
shader_model: wgt::ShaderModel::Sm5,
|
||||
},
|
||||
alignments: crate::Alignments {
|
||||
|
||||
@@ -460,7 +460,9 @@ impl crate::Instance<super::Api> for Instance {
|
||||
) -> Result<Surface, crate::InstanceError> {
|
||||
use raw_window_handle::RawWindowHandle as Rwh;
|
||||
|
||||
#[cfg_attr(target_os = "android", allow(unused_mut))]
|
||||
let mut inner = self.inner.lock();
|
||||
#[cfg_attr(target_os = "android", allow(unused_mut))]
|
||||
let mut wl_window = None;
|
||||
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
||||
let (mut temp_xlib_handle, mut temp_xcb_handle);
|
||||
|
||||
@@ -12,6 +12,7 @@ use objc::{
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[link(name = "QuartzCore", kind = "framework")]
|
||||
extern "C" {
|
||||
#[allow(non_upper_case_globals)]
|
||||
|
||||
@@ -497,6 +497,20 @@ impl Features {
|
||||
|
||||
/// Represents the sets of limits an adapter/device supports.
|
||||
///
|
||||
/// We provide two different defaults.
|
||||
/// - [`Limits::downlevel_defaults()]. This is a set of limits that is guarenteed to
|
||||
/// work on all backends, including "downlevel" backends such
|
||||
/// as OpenGL and D3D11. For most applications we recommend using these
|
||||
/// limits, assuming they are high enough for your application.
|
||||
/// - [`Limits::default()`]. This is the set of limits that is guarenteed to
|
||||
/// work on all modern backends and is guarenteed to be supported by WebGPU.
|
||||
/// Applications needing more modern features can use this as a reasonable set of
|
||||
/// limits if they are targetting only desktop and modern mobile devices.
|
||||
///
|
||||
/// We recommend starting with the most restrictive limits you can and manually
|
||||
/// increasing the limits you need boosted. This will let you stay running on
|
||||
/// all hardware that supports the limits you need.
|
||||
///
|
||||
/// Limits "better" than the default must be supported by the adapter and requested when requesting
|
||||
/// a device. If limits "better" than the adapter supports are requested, requesting a device will panic.
|
||||
/// Once a device is requested, you may only use resources up to the limits requested _even_ if the
|
||||
@@ -593,6 +607,32 @@ impl Default for Limits {
|
||||
}
|
||||
}
|
||||
|
||||
impl Limits {
|
||||
/// These default limits are guarenteed to be compatible with GLES3, WebGL, and D3D11
|
||||
pub fn downlevel_defaults() -> Self {
|
||||
Self {
|
||||
max_texture_dimension_1d: 2096,
|
||||
max_texture_dimension_2d: 2096,
|
||||
max_texture_dimension_3d: 256,
|
||||
max_texture_array_layers: 256,
|
||||
max_bind_groups: 4,
|
||||
max_dynamic_uniform_buffers_per_pipeline_layout: 8,
|
||||
max_dynamic_storage_buffers_per_pipeline_layout: 4,
|
||||
max_sampled_textures_per_shader_stage: 16,
|
||||
max_samplers_per_shader_stage: 16,
|
||||
max_storage_buffers_per_shader_stage: 4,
|
||||
max_storage_textures_per_shader_stage: 4,
|
||||
max_uniform_buffers_per_shader_stage: 12,
|
||||
max_uniform_buffer_binding_size: 16384,
|
||||
max_storage_buffer_binding_size: 128 << 20,
|
||||
max_vertex_buffers: 8,
|
||||
max_vertex_attributes: 16,
|
||||
max_vertex_buffer_array_stride: 2048,
|
||||
max_push_constant_size: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the sets of additional limits on an adapter,
|
||||
/// which take place when running on downlevel backends.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
@@ -662,8 +702,15 @@ bitflags::bitflags! {
|
||||
const COMPARISON_SAMPLERS = 0x0000_0100;
|
||||
/// Supports different blending modes per color target.
|
||||
const INDEPENDENT_BLENDING = 0x0000_0200;
|
||||
/// Supports samplers with anisotropic filtering
|
||||
const ANISOTROPIC_FILTERING = 0x0001_0000;
|
||||
/// Supports attaching storage buffers to vertex shaders.
|
||||
const VERTEX_ACCESSABLE_STORAGE_BUFFERS = 0x0000_0400;
|
||||
|
||||
|
||||
/// Supports samplers with anisotropic filtering. Note this isn't actually required by WebGPU,
|
||||
/// the implementation is allowed to completely ignore aniso clamp. This flag is here for native backends
|
||||
/// so they can comunicate to the user of aniso is enabled.
|
||||
const ANISOTROPIC_FILTERING = 0x8000_0000;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -328,6 +328,6 @@ fn boids() {
|
||||
base_test_parameters: framework::test_common::TestParameters::default()
|
||||
.downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS),
|
||||
tolerance: 0,
|
||||
max_outliers: 600, // Currently bounded by rpi4
|
||||
max_outliers: 1000, // Currently bounded by rpi4
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ async fn create_red_image_with_dimensions(
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: None,
|
||||
features: wgpu::Features::empty(),
|
||||
limits: wgpu::Limits::default(),
|
||||
limits: wgpu::Limits::downlevel_defaults(),
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
||||
@@ -402,6 +402,6 @@ fn cube_lines() {
|
||||
optional_features: wgpu::Features::NON_FILL_POLYGON_MODE,
|
||||
base_test_parameters: framework::test_common::TestParameters::default(),
|
||||
tolerance: 2,
|
||||
max_outliers: 500, // Bounded by rpi4 & intel 620 on GL
|
||||
max_outliers: 600, // Bounded by rpi4 on GL
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ pub trait Example: 'static + Sized {
|
||||
wgpu::Features::empty()
|
||||
}
|
||||
fn required_limits() -> wgpu::Limits {
|
||||
wgpu::Limits::default()
|
||||
wgpu::Limits::downlevel_defaults() // These downlevel limits will allow the code to run on all possible hardware
|
||||
}
|
||||
fn init(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
|
||||
@@ -47,7 +47,7 @@ async fn execute_gpu(numbers: &[u32]) -> Option<Vec<u32>> {
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: None,
|
||||
features: wgpu::Features::empty(),
|
||||
limits: wgpu::Limits::default(),
|
||||
limits: wgpu::Limits::downlevel_defaults(),
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
||||
@@ -9,12 +9,7 @@ use common::{initialize_test, TestParameters};
|
||||
#[test]
|
||||
fn test_compute_1() {
|
||||
initialize_test(
|
||||
TestParameters::default().specific_failure(
|
||||
Some(wgpu::Backends::GL),
|
||||
None,
|
||||
Some("V3D"),
|
||||
false,
|
||||
),
|
||||
TestParameters::default().specific_failure(None, None, Some("V3D"), false),
|
||||
|ctx| {
|
||||
let input = &[1, 2, 3, 4];
|
||||
|
||||
@@ -31,12 +26,7 @@ fn test_compute_1() {
|
||||
#[test]
|
||||
fn test_compute_2() {
|
||||
initialize_test(
|
||||
TestParameters::default().specific_failure(
|
||||
Some(wgpu::Backends::GL),
|
||||
None,
|
||||
Some("V3D"),
|
||||
false,
|
||||
),
|
||||
TestParameters::default().specific_failure(None, None, Some("V3D"), false),
|
||||
|ctx| {
|
||||
let input = &[5, 23, 10, 9];
|
||||
|
||||
@@ -53,12 +43,7 @@ fn test_compute_2() {
|
||||
#[test]
|
||||
fn test_compute_overflow() {
|
||||
initialize_test(
|
||||
TestParameters::default().specific_failure(
|
||||
Some(wgpu::Backends::GL),
|
||||
None,
|
||||
Some("V3D"),
|
||||
false,
|
||||
),
|
||||
TestParameters::default().specific_failure(None, None, Some("V3D"), false),
|
||||
|ctx| {
|
||||
let input = &[77031, 837799, 8400511, 63728127];
|
||||
pollster::block_on(assert_execute_gpu(
|
||||
@@ -74,7 +59,9 @@ fn test_compute_overflow() {
|
||||
#[test]
|
||||
fn test_multithreaded_compute() {
|
||||
initialize_test(
|
||||
TestParameters::default().backend_failure(wgpu::Backends::GL),
|
||||
TestParameters::default()
|
||||
.backend_failure(wgpu::Backends::GL)
|
||||
.specific_failure(Some(wgpu::Backends::VULKAN), None, Some("V3D"), false),
|
||||
|ctx| {
|
||||
use std::{sync::mpsc, thread, time::Duration};
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: None,
|
||||
features: wgpu::Features::empty(),
|
||||
limits: wgpu::Limits::default(),
|
||||
limits: wgpu::Limits::downlevel_defaults(),
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
||||
@@ -85,7 +85,7 @@ async fn run(event_loop: EventLoop<()>, viewports: Vec<(Window, wgpu::Color)>) {
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: None,
|
||||
features: wgpu::Features::empty(),
|
||||
limits: wgpu::Limits::default(),
|
||||
limits: wgpu::Limits::downlevel_defaults(),
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
||||
@@ -484,7 +484,7 @@ fn mipmap() {
|
||||
optional_features: wgpu::Features::default(),
|
||||
base_test_parameters: framework::test_common::TestParameters::default()
|
||||
.backend_failure(wgpu::Backends::GL),
|
||||
tolerance: 25,
|
||||
max_outliers: 3000, // Mipmap sampling is highly variant between impls. This is currently bounded by AMD on mac
|
||||
tolerance: 50,
|
||||
max_outliers: 5000, // Mipmap sampling is highly variant between impls. This is currently bounded by lavapipe
|
||||
});
|
||||
}
|
||||
|
||||
@@ -830,7 +830,8 @@ fn shadow() {
|
||||
height: 768,
|
||||
optional_features: wgpu::Features::default(),
|
||||
base_test_parameters: framework::test_common::TestParameters::default()
|
||||
.downlevel_flags(wgpu::DownlevelFlags::COMPARISON_SAMPLERS),
|
||||
.downlevel_flags(wgpu::DownlevelFlags::COMPARISON_SAMPLERS)
|
||||
.specific_failure(Some(wgpu::Backends::VULKAN), None, Some("V3D"), false), // rpi4 on VK doesn't work: https://gitlab.freedesktop.org/mesa/mesa/-/issues/3916
|
||||
tolerance: 2,
|
||||
max_outliers: 500, // bounded by rpi4
|
||||
});
|
||||
|
||||
@@ -500,7 +500,7 @@ fn skybox_etc2() {
|
||||
optional_features: wgpu::Features::TEXTURE_COMPRESSION_ETC2,
|
||||
base_test_parameters: framework::test_common::TestParameters::default(),
|
||||
tolerance: 5,
|
||||
max_outliers: 50, // Bounded by rpi4
|
||||
max_outliers: 100, // Bounded by llvmpipe
|
||||
});
|
||||
}
|
||||
|
||||
@@ -512,7 +512,7 @@ fn skybox_astc() {
|
||||
height: 768,
|
||||
optional_features: wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR,
|
||||
base_test_parameters: framework::test_common::TestParameters::default(),
|
||||
tolerance: 5, // TODO
|
||||
max_outliers: 10, // TODO
|
||||
tolerance: 5,
|
||||
max_outliers: 300, // Bounded by rp4 on vk
|
||||
});
|
||||
}
|
||||
|
||||
@@ -49,14 +49,14 @@ fn create_indices() -> Vec<u16> {
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Color {
|
||||
RED,
|
||||
GREEN,
|
||||
Red,
|
||||
Green,
|
||||
}
|
||||
|
||||
fn create_texture_data(color: Color) -> [u8; 4] {
|
||||
match color {
|
||||
Color::RED => [255, 0, 0, 255],
|
||||
Color::GREEN => [0, 255, 0, 255],
|
||||
Color::Red => [255, 0, 0, 255],
|
||||
Color::Green => [0, 255, 0, 255],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,8 +122,8 @@ impl framework::Example for Example {
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
});
|
||||
|
||||
let red_texture_data = create_texture_data(Color::RED);
|
||||
let green_texture_data = create_texture_data(Color::GREEN);
|
||||
let red_texture_data = create_texture_data(Color::Red);
|
||||
let green_texture_data = create_texture_data(Color::Green);
|
||||
|
||||
let texture_descriptor = wgpu::TextureDescriptor {
|
||||
size: wgpu::Extent3d::default(),
|
||||
@@ -253,11 +253,11 @@ impl framework::Example for Example {
|
||||
});
|
||||
|
||||
Self {
|
||||
pipeline,
|
||||
bind_group,
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
index_format,
|
||||
bind_group,
|
||||
pipeline,
|
||||
uniform_workaround,
|
||||
}
|
||||
}
|
||||
@@ -340,8 +340,7 @@ fn texture_arrays_uniform() {
|
||||
image_path: "/examples/texture-arrays/screenshot.png",
|
||||
width: 1024,
|
||||
height: 768,
|
||||
optional_features: wgpu::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING
|
||||
| wgpu::Features::PUSH_CONSTANTS,
|
||||
optional_features: wgpu::Features::TEXTURE_BINDING_ARRAY | wgpu::Features::PUSH_CONSTANTS,
|
||||
base_test_parameters: framework::test_common::TestParameters::default().failure(),
|
||||
tolerance: 0,
|
||||
max_outliers: 0,
|
||||
@@ -355,7 +354,8 @@ fn texture_arrays_non_uniform() {
|
||||
image_path: "/examples/texture-arrays/screenshot.png",
|
||||
width: 1024,
|
||||
height: 768,
|
||||
optional_features: wgpu::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
optional_features: wgpu::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgpu::Features::RESOURCE_BINDING_ARRAY_NON_UNIFORM_INDEXING,
|
||||
base_test_parameters: framework::test_common::TestParameters::default().failure(),
|
||||
tolerance: 0,
|
||||
max_outliers: 0,
|
||||
@@ -369,7 +369,8 @@ fn texture_arrays_unsized_non_uniform() {
|
||||
image_path: "/examples/texture-arrays/screenshot.png",
|
||||
width: 1024,
|
||||
height: 768,
|
||||
optional_features: wgpu::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
|
||||
optional_features: wgpu::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgpu::Features::RESOURCE_BINDING_ARRAY_NON_UNIFORM_INDEXING
|
||||
| wgpu::Features::UNSIZED_BINDING_ARRAY,
|
||||
base_test_parameters: framework::test_common::TestParameters::default().failure(),
|
||||
tolerance: 0,
|
||||
|
||||
@@ -800,6 +800,6 @@ fn water() {
|
||||
base_test_parameters: framework::test_common::TestParameters::default()
|
||||
.downlevel_flags(wgpu::DownlevelFlags::READ_ONLY_DEPTH_STENCIL),
|
||||
tolerance: 5,
|
||||
max_outliers: 10,
|
||||
max_outliers: 300, // bounded by rpi4 on vk
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(clippy::type_complexity)]
|
||||
|
||||
use std::{
|
||||
fmt,
|
||||
future::Future,
|
||||
@@ -1262,8 +1264,8 @@ impl crate::Context for Context {
|
||||
|
||||
unsafe fn device_create_shader_module_spirv(
|
||||
&self,
|
||||
device: &Self::DeviceId,
|
||||
desc: &crate::ShaderModuleDescriptorSpirV,
|
||||
_device: &Self::DeviceId,
|
||||
_desc: &crate::ShaderModuleDescriptorSpirV,
|
||||
) -> Self::ShaderModuleId {
|
||||
unreachable!("SPIRV_SHADER_PASSTHROUGH is not enabled for this backend")
|
||||
}
|
||||
@@ -1289,7 +1291,7 @@ impl crate::Context for Context {
|
||||
if let Some(s) = size {
|
||||
mapped_buffer_binding.size(s.get() as f64);
|
||||
}
|
||||
JsValue::from(mapped_buffer_binding.clone())
|
||||
JsValue::from(mapped_buffer_binding)
|
||||
}
|
||||
crate::BindingResource::BufferArray(..) => {
|
||||
panic!("Web backend does not support arrays of buffers")
|
||||
@@ -1498,7 +1500,6 @@ impl crate::Context for Context {
|
||||
_device: &Self::DeviceId,
|
||||
_desc: &wgt::QuerySetDescriptor<crate::Label>,
|
||||
) -> Self::QuerySetId {
|
||||
()
|
||||
}
|
||||
|
||||
fn device_create_command_encoder(
|
||||
|
||||
@@ -71,13 +71,20 @@ fn lowest_downlevel_properties() -> DownlevelCapabilities {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FailureCase {
|
||||
backends: Option<wgpu::Backends>,
|
||||
vendor: Option<usize>,
|
||||
adapter: Option<String>,
|
||||
segfault: bool,
|
||||
}
|
||||
|
||||
// This information determines if a test should run.
|
||||
pub struct TestParameters {
|
||||
pub required_features: Features,
|
||||
pub required_limits: Limits,
|
||||
pub required_downlevel_properties: DownlevelCapabilities,
|
||||
// Backends where test should fail.
|
||||
pub failures: Vec<(Option<wgpu::Backends>, Option<usize>, Option<String>, bool)>,
|
||||
pub failures: Vec<FailureCase>,
|
||||
}
|
||||
|
||||
impl Default for TestParameters {
|
||||
@@ -126,13 +133,23 @@ impl TestParameters {
|
||||
|
||||
/// Mark the test as always failing, equivilant to specific_failure(None, None, None)
|
||||
pub fn failure(mut self) -> Self {
|
||||
self.failures.push((None, None, None, false));
|
||||
self.failures.push(FailureCase {
|
||||
backends: None,
|
||||
vendor: None,
|
||||
adapter: None,
|
||||
segfault: false,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Mark the test as always failing on a specific backend, equivilant to specific_failure(backend, None, None)
|
||||
pub fn backend_failure(mut self, backends: wgpu::Backends) -> Self {
|
||||
self.failures.push((Some(backends), None, None, false));
|
||||
self.failures.push(FailureCase {
|
||||
backends: Some(backends),
|
||||
vendor: None,
|
||||
adapter: None,
|
||||
segfault: false,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
@@ -150,12 +167,12 @@ impl TestParameters {
|
||||
device: Option<&'static str>,
|
||||
segfault: bool,
|
||||
) -> Self {
|
||||
self.failures.push((
|
||||
self.failures.push(FailureCase {
|
||||
backends,
|
||||
vendor,
|
||||
device.as_ref().map(AsRef::as_ref).map(str::to_lowercase),
|
||||
adapter: device.as_ref().map(AsRef::as_ref).map(str::to_lowercase),
|
||||
segfault,
|
||||
));
|
||||
});
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -222,45 +239,45 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te
|
||||
queue,
|
||||
};
|
||||
|
||||
let failure_reason = parameters.failures.iter().find_map(
|
||||
|(backend_failure, vendor_failure, adapter_failure, segfault)| {
|
||||
let always =
|
||||
backend_failure.is_none() && vendor_failure.is_none() && adapter_failure.is_none();
|
||||
let failure_reason = parameters.failures.iter().find_map(|failure| {
|
||||
let always =
|
||||
failure.backends.is_none() && failure.vendor.is_none() && failure.adapter.is_none();
|
||||
|
||||
let expect_failure_backend =
|
||||
backend_failure.map(|f| f.contains(wgpu::Backends::from(adapter_info.backend)));
|
||||
let expect_failure_vendor = vendor_failure.map(|v| v == adapter_info.vendor);
|
||||
let expect_failure_adapter = adapter_failure
|
||||
.as_deref()
|
||||
.map(|f| adapter_lowercase_name.contains(f));
|
||||
let expect_failure_backend = failure
|
||||
.backends
|
||||
.map(|f| f.contains(wgpu::Backends::from(adapter_info.backend)));
|
||||
let expect_failure_vendor = failure.vendor.map(|v| v == adapter_info.vendor);
|
||||
let expect_failure_adapter = failure
|
||||
.adapter
|
||||
.as_deref()
|
||||
.map(|f| adapter_lowercase_name.contains(f));
|
||||
|
||||
if expect_failure_backend.unwrap_or(true)
|
||||
&& expect_failure_vendor.unwrap_or(true)
|
||||
&& expect_failure_adapter.unwrap_or(true)
|
||||
{
|
||||
if always {
|
||||
Some((FailureReasons::ALWAYS, *segfault))
|
||||
} else {
|
||||
let mut reason = FailureReasons::empty();
|
||||
reason.set(
|
||||
FailureReasons::BACKEND,
|
||||
expect_failure_backend.unwrap_or(false),
|
||||
);
|
||||
reason.set(
|
||||
FailureReasons::VENDOR,
|
||||
expect_failure_vendor.unwrap_or(false),
|
||||
);
|
||||
reason.set(
|
||||
FailureReasons::ADAPTER,
|
||||
expect_failure_adapter.unwrap_or(false),
|
||||
);
|
||||
Some((reason, *segfault))
|
||||
}
|
||||
if expect_failure_backend.unwrap_or(true)
|
||||
&& expect_failure_vendor.unwrap_or(true)
|
||||
&& expect_failure_adapter.unwrap_or(true)
|
||||
{
|
||||
if always {
|
||||
Some((FailureReasons::ALWAYS, failure.segfault))
|
||||
} else {
|
||||
None
|
||||
let mut reason = FailureReasons::empty();
|
||||
reason.set(
|
||||
FailureReasons::BACKEND,
|
||||
expect_failure_backend.unwrap_or(false),
|
||||
);
|
||||
reason.set(
|
||||
FailureReasons::VENDOR,
|
||||
expect_failure_vendor.unwrap_or(false),
|
||||
);
|
||||
reason.set(
|
||||
FailureReasons::ADAPTER,
|
||||
expect_failure_adapter.unwrap_or(false),
|
||||
);
|
||||
Some((reason, failure.segfault))
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if let Some((reason, true)) = failure_reason {
|
||||
println!(
|
||||
|
||||
Reference in New Issue
Block a user