use alloc::string::String;
use crate::Backends;
#[cfg(doc)]
use crate::{Backend, DownlevelFlags};
#[derive(Clone, Debug)]
pub struct InstanceDescriptor {
pub backends: Backends,
pub flags: InstanceFlags,
pub backend_options: BackendOptions,
}
impl Default for InstanceDescriptor {
fn default() -> Self {
Self {
backends: Backends::all(),
flags: InstanceFlags::default(),
backend_options: BackendOptions::default(),
}
}
}
impl InstanceDescriptor {
#[must_use]
pub fn from_env_or_default() -> Self {
Self::default().with_env()
}
#[must_use]
pub fn with_env(self) -> Self {
let backends = self.backends.with_env();
let flags = self.flags.with_env();
let backend_options = self.backend_options.with_env();
Self {
backends,
flags,
backend_options,
}
}
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct InstanceFlags: u32 {
const DEBUG = 1 << 0;
const VALIDATION = 1 << 1;
const DISCARD_HAL_LABELS = 1 << 2;
const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3;
const GPU_BASED_VALIDATION = 1 << 4;
const VALIDATION_INDIRECT_CALL = 1 << 5;
const AUTOMATIC_TIMESTAMP_NORMALIZATION = 1 << 6;
}
}
impl Default for InstanceFlags {
fn default() -> Self {
Self::from_build_config()
}
}
impl InstanceFlags {
#[must_use]
pub fn debugging() -> Self {
InstanceFlags::DEBUG | InstanceFlags::VALIDATION | InstanceFlags::VALIDATION_INDIRECT_CALL
}
#[must_use]
pub fn advanced_debugging() -> Self {
Self::debugging() | InstanceFlags::GPU_BASED_VALIDATION
}
#[must_use]
pub fn from_build_config() -> Self {
if cfg!(debug_assertions) {
return InstanceFlags::debugging();
}
InstanceFlags::VALIDATION_INDIRECT_CALL
}
#[must_use]
pub fn from_env_or_default() -> Self {
Self::default().with_env()
}
#[must_use]
pub fn with_env(mut self) -> Self {
fn env(key: &str) -> Option<bool> {
crate::env::var(key).map(|s| match s.as_str() {
"0" => false,
_ => true,
})
}
if let Some(bit) = env("WGPU_VALIDATION") {
self.set(Self::VALIDATION, bit);
}
if let Some(bit) = env("WGPU_DEBUG") {
self.set(Self::DEBUG, bit);
}
if let Some(bit) = env("WGPU_DISCARD_HAL_LABELS") {
self.set(Self::DISCARD_HAL_LABELS, bit);
}
if let Some(bit) = env("WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER") {
self.set(Self::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER, bit);
}
if let Some(bit) = env("WGPU_GPU_BASED_VALIDATION") {
self.set(Self::GPU_BASED_VALIDATION, bit);
}
if let Some(bit) = env("WGPU_VALIDATION_INDIRECT_CALL") {
self.set(Self::VALIDATION_INDIRECT_CALL, bit);
}
self
}
}
#[derive(Clone, Debug, Default)]
pub struct BackendOptions {
pub gl: GlBackendOptions,
pub dx12: Dx12BackendOptions,
pub noop: NoopBackendOptions,
}
impl BackendOptions {
#[must_use]
pub fn from_env_or_default() -> Self {
Self {
gl: GlBackendOptions::from_env_or_default(),
dx12: Dx12BackendOptions::from_env_or_default(),
noop: NoopBackendOptions::from_env_or_default(),
}
}
#[must_use]
pub fn with_env(self) -> Self {
Self {
gl: self.gl.with_env(),
dx12: self.dx12.with_env(),
noop: self.noop.with_env(),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct GlBackendOptions {
pub gles_minor_version: Gles3MinorVersion,
pub fence_behavior: GlFenceBehavior,
}
impl GlBackendOptions {
#[must_use]
pub fn from_env_or_default() -> Self {
let gles_minor_version = Gles3MinorVersion::from_env().unwrap_or_default();
Self {
gles_minor_version,
fence_behavior: GlFenceBehavior::Normal,
}
}
#[must_use]
pub fn with_env(self) -> Self {
let gles_minor_version = self.gles_minor_version.with_env();
let short_circuit_fences = self.fence_behavior.with_env();
Self {
gles_minor_version,
fence_behavior: short_circuit_fences,
}
}
}
#[derive(Clone, Debug, Default)]
pub struct Dx12BackendOptions {
pub shader_compiler: Dx12Compiler,
}
impl Dx12BackendOptions {
#[must_use]
pub fn from_env_or_default() -> Self {
let compiler = Dx12Compiler::from_env().unwrap_or_default();
Self {
shader_compiler: compiler,
}
}
#[must_use]
pub fn with_env(self) -> Self {
let shader_compiler = self.shader_compiler.with_env();
Self { shader_compiler }
}
}
#[derive(Clone, Debug, Default)]
pub struct NoopBackendOptions {
pub enable: bool,
}
impl NoopBackendOptions {
#[must_use]
pub fn from_env_or_default() -> Self {
Self {
enable: Self::enable_from_env().unwrap_or(false),
}
}
#[must_use]
pub fn with_env(self) -> Self {
Self {
enable: Self::enable_from_env().unwrap_or(self.enable),
}
}
fn enable_from_env() -> Option<bool> {
let value = crate::env::var("WGPU_NOOP_BACKEND")?;
match value.as_str() {
"1" => Some(true),
"0" => Some(false),
_ => None,
}
}
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub enum DxcShaderModel {
V6_0,
V6_1,
V6_2,
V6_3,
V6_4,
V6_5,
V6_6,
V6_7,
}
#[derive(Clone, Debug, Default)]
pub enum Dx12Compiler {
#[default]
Fxc,
DynamicDxc {
dxc_path: String,
dxil_path: String,
max_shader_model: DxcShaderModel,
},
StaticDxc,
}
impl Dx12Compiler {
pub fn default_dynamic_dxc() -> Self {
Self::DynamicDxc {
dxc_path: String::from("dxcompiler.dll"),
dxil_path: String::from("dxil.dll"),
max_shader_model: DxcShaderModel::V6_5,
}
}
#[must_use]
pub fn from_env() -> Option<Self> {
let value = crate::env::var("WGPU_DX12_COMPILER")
.as_deref()?
.to_lowercase();
match value.as_str() {
"dxc" | "dynamicdxc" => Some(Self::default_dynamic_dxc()),
"staticdxc" => Some(Self::StaticDxc),
"fxc" => Some(Self::Fxc),
_ => None,
}
}
#[must_use]
pub fn with_env(self) -> Self {
if let Some(compiler) = Self::from_env() {
compiler
} else {
self
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
pub enum Gles3MinorVersion {
#[default]
Automatic,
Version0,
Version1,
Version2,
}
impl Gles3MinorVersion {
#[must_use]
pub fn from_env() -> Option<Self> {
let value = crate::env::var("WGPU_GLES_MINOR_VERSION")
.as_deref()?
.to_lowercase();
match value.as_str() {
"automatic" => Some(Self::Automatic),
"0" => Some(Self::Version0),
"1" => Some(Self::Version1),
"2" => Some(Self::Version2),
_ => None,
}
}
#[must_use]
pub fn with_env(self) -> Self {
if let Some(compiler) = Self::from_env() {
compiler
} else {
self
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum GlFenceBehavior {
#[default]
Normal,
AutoFinish,
}
impl GlFenceBehavior {
pub fn is_auto_finish(&self) -> bool {
matches!(self, Self::AutoFinish)
}
pub fn is_normal(&self) -> bool {
matches!(self, Self::Normal)
}
#[must_use]
pub fn from_env() -> Option<Self> {
let value = crate::env::var("WGPU_GL_FENCE_BEHAVIOR")
.as_deref()?
.to_lowercase();
match value.as_str() {
"normal" => Some(Self::Normal),
"autofinish" => Some(Self::AutoFinish),
_ => None,
}
}
#[must_use]
pub fn with_env(self) -> Self {
if let Some(fence) = Self::from_env() {
fence
} else {
self
}
}
}