Improvements to caches and switch to ahash (#2019)

* Add `OnceCache`

* Switch to `ahash`
This commit is contained in:
marc0246 2022-10-04 10:04:52 +02:00 committed by GitHub
parent 2277448a0e
commit 1c2d195dab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 408 additions and 378 deletions

View File

@ -15,6 +15,7 @@ categories = ["rendering::graphics-api"]
proc-macro = true
[dependencies]
ahash = "0.8"
heck = "0.4"
proc-macro2 = "1.0"
quote = "1.0"

View File

@ -7,23 +7,21 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::entry_point;
use crate::read_file_to_string;
use crate::structs;
use crate::RegisteredType;
use crate::TypesMeta;
use crate::{entry_point, read_file_to_string, structs, RegisteredType, TypesMeta};
use ahash::HashMap;
use proc_macro2::TokenStream;
pub use shaderc::{CompilationArtifact, IncludeType, ResolvedInclude, ShaderKind};
use shaderc::{CompileOptions, Compiler, EnvVersion, SpirvVersion, TargetEnv};
use std::collections::HashMap;
use std::iter::Iterator;
use std::path::Path;
use std::{
cell::{RefCell, RefMut},
io::Error as IoError,
iter::Iterator,
path::Path,
};
use vulkano::shader::{
reflect,
spirv::{Spirv, SpirvError},
};
use vulkano::shader::reflect;
use vulkano::shader::spirv::{Spirv, SpirvError};
pub(super) fn path_to_str(path: &Path) -> &str {
path.to_str().expect(
@ -378,7 +376,7 @@ mod tests {
.unwrap();
let spirv = Spirv::new(comp.as_binary()).unwrap();
let res = std::panic::catch_unwind(|| {
structs::write_structs("", &spirv, &TypesMeta::default(), &mut HashMap::new())
structs::write_structs("", &spirv, &TypesMeta::default(), &mut HashMap::default())
});
assert!(res.is_err());
}
@ -407,7 +405,7 @@ mod tests {
)
.unwrap();
let spirv = Spirv::new(comp.as_binary()).unwrap();
structs::write_structs("", &spirv, &TypesMeta::default(), &mut HashMap::new());
structs::write_structs("", &spirv, &TypesMeta::default(), &mut HashMap::default());
}
#[test]
fn test_wrap_alignment() {
@ -439,7 +437,7 @@ mod tests {
)
.unwrap();
let spirv = Spirv::new(comp.as_binary()).unwrap();
structs::write_structs("", &spirv, &TypesMeta::default(), &mut HashMap::new());
structs::write_structs("", &spirv, &TypesMeta::default(), &mut HashMap::default());
}
#[test]

View File

@ -7,15 +7,16 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use ahash::HashMap;
use proc_macro2::TokenStream;
use std::collections::HashMap;
use vulkano::pipeline::layout::PushConstantRange;
use vulkano::shader::spirv::ExecutionModel;
use vulkano::shader::{
DescriptorIdentifier, DescriptorRequirements, ShaderExecution, ShaderInterfaceEntry,
ShaderInterfaceEntryType, SpecializationConstantRequirements,
use vulkano::{
pipeline::layout::PushConstantRange,
shader::{
spirv::ExecutionModel, DescriptorIdentifier, DescriptorRequirements, EntryPointInfo,
ShaderExecution, ShaderInterface, ShaderInterfaceEntry, ShaderInterfaceEntryType,
ShaderStages, SpecializationConstantRequirements,
},
};
use vulkano::shader::{EntryPointInfo, ShaderInterface, ShaderStages};
pub(super) fn write_entry_point(
name: &str,

View File

@ -225,17 +225,19 @@ extern crate quote;
extern crate syn;
use crate::codegen::ShaderKind;
use ahash::HashMap;
use shaderc::{EnvVersion, SpirvVersion};
use std::borrow::Cow;
use std::collections::HashMap;
use std::fs;
use std::fs::File;
use std::io::{Read, Result as IoResult};
use std::path::Path;
use std::slice::from_raw_parts;
use std::{env, iter::empty};
use syn::parse::{Parse, ParseStream, Result};
use std::{
borrow::Cow,
env, fs,
fs::File,
io::{Read, Result as IoResult},
iter::empty,
path::Path,
slice::from_raw_parts,
};
use syn::{
parse::{Parse, ParseStream, Result},
Ident, ItemUse, LitBool, LitStr, Meta, MetaList, NestedMeta, Path as SynPath, TypeImplTrait,
};
@ -373,7 +375,7 @@ impl Parse for MacroInput {
let mut include_directories = Vec::new();
let mut macro_defines = Vec::new();
let mut shared_constants = None;
let mut shaders = HashMap::new();
let mut shaders = HashMap::default();
let mut spirv_version = None;
let mut types_meta = None;
let mut vulkan_version = None;
@ -802,7 +804,7 @@ pub fn shader(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let mut shaders_code = Vec::with_capacity(input.shaders.len());
let mut types_code = Vec::with_capacity(input.shaders.len());
let mut types_registry = HashMap::new();
let mut types_registry = HashMap::default();
for (prefix, (shader_kind, shader_source)) in input.shaders {
let (code, types) = if let SourceKind::Bytes(path) = shader_source {

View File

@ -8,9 +8,10 @@
// according to those terms.
use crate::{RegisteredType, TypesMeta};
use ahash::HashMap;
use heck::ToUpperCamelCase;
use proc_macro2::{Span, TokenStream};
use std::{borrow::Cow, collections::HashMap, mem};
use std::{borrow::Cow, mem};
use syn::{Ident, LitStr};
use vulkano::shader::spirv::{Decoration, Id, Instruction, Spirv};

View File

@ -12,6 +12,7 @@ keywords = ["vulkan", "bindings", "graphics", "gpu", "rendering"]
categories = ["rendering::graphics-api"]
[dependencies]
ahash = "0.8"
vulkano = { version = "0.31.0", path = "../vulkano" }
vulkano-win = { version = "0.31.0", path = "../vulkano-win" }
winit = { version = "0.27" }

View File

@ -17,8 +17,8 @@ use vulkano::{
debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo},
Instance, InstanceCreateInfo, InstanceExtensions,
},
Version, VulkanLibrary,
};
use vulkano::{Version, VulkanLibrary};
/// A configuration struct to pass various creation options to create [`VulkanoContext`].
///

View File

@ -7,22 +7,20 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::collections::HashMap;
use crate::{context::VulkanoContext, window::WindowDescriptor};
use ahash::HashMap;
use std::sync::Arc;
use crate::context::VulkanoContext;
use crate::window::WindowDescriptor;
use vulkano::device::Device;
use vulkano::image::{ImageUsage, StorageImage, SwapchainImage};
use vulkano::swapchain::SwapchainPresentInfo;
use vulkano::{
device::Queue,
device::{Device, Queue},
format::Format,
image::{view::ImageView, ImageAccess, ImageViewAbstract},
swapchain,
swapchain::{AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError},
sync,
sync::{FlushError, GpuFuture},
image::{
view::ImageView, ImageAccess, ImageUsage, ImageViewAbstract, StorageImage, SwapchainImage,
},
swapchain::{
self, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
};
use vulkano_win::create_surface_from_winit;
use winit::window::Window;

View File

@ -11,13 +11,14 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::context::VulkanoContext;
use crate::renderer::VulkanoWindowRenderer;
use crate::{context::VulkanoContext, renderer::VulkanoWindowRenderer};
use ahash::HashMap;
use std::collections::hash_map::{Iter, IterMut};
use std::collections::HashMap;
use vulkano::swapchain::{PresentMode, SwapchainCreateInfo};
use winit::dpi::LogicalSize;
use winit::window::{CursorGrabMode, WindowId};
use winit::{
dpi::LogicalSize,
window::{CursorGrabMode, WindowId},
};
/// A struct organizing windows and their corresponding renderers. This makes it easy to handle multiple windows.
///

View File

@ -6,9 +6,10 @@ use raw_window_handle::{
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
};
use std::sync::Arc;
use vulkano::instance::Instance;
use vulkano::swapchain::Surface;
use vulkano::swapchain::SurfaceCreationError;
use vulkano::{
instance::Instance,
swapchain::{Surface, SurfaceCreationError},
};
/// Creates a vulkan surface from a generic window
/// which implements HasRawWindowHandle and thus can reveal the os-dependent handle.

View File

@ -14,6 +14,7 @@ readme = "../README.md"
build = "build.rs"
[dependencies]
ahash = "0.8"
# When updating Ash, also update vk.xml to the same Vulkan patch version that Ash uses.
# All versions of vk.xml can be found at https://github.com/KhronosGroup/Vulkan-Headers/commits/main/registry/vk.xml.
ash = "0.37"
@ -30,6 +31,7 @@ objc = "0.2.5"
core-graphics-types = "0.1"
[build-dependencies]
ahash = "0.8"
heck = "0.4"
indexmap = "1.8"
lazy_static = "1.4"

View File

@ -7,9 +7,8 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{write_file, VkRegistryData};
use super::{write_file, IndexMap, VkRegistryData};
use heck::ToSnakeCase;
use indexmap::IndexMap;
use proc_macro2::{Ident, Literal, TokenStream};
use quote::{format_ident, quote};
use std::fmt::Write as _;

View File

@ -7,16 +7,13 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{write_file, VkRegistryData};
use super::{write_file, IndexMap, VkRegistryData};
use ahash::HashMap;
use heck::ToSnakeCase;
use indexmap::IndexMap;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use regex::Regex;
use std::{
collections::{hash_map::Entry, HashMap},
fmt::Write as _,
};
use std::{collections::hash_map::Entry, fmt::Write as _};
use vk_parse::{Extension, Type, TypeMember, TypeMemberMarkup, TypeSpec};
// This is not included in vk.xml, so it's added here manually
@ -515,7 +512,7 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
}
fn features_members(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<FeaturesMember> {
let mut features = HashMap::new();
let mut features = HashMap::default();
std::iter::once(&types["VkPhysicalDeviceFeatures"])
.chain(sorted_structs(types).into_iter())
.filter(|(ty, _)| {
@ -728,7 +725,7 @@ fn features_ffi_members<'a>(
types: &'a HashMap<&str, (&Type, Vec<&str>)>,
extensions: &IndexMap<&'a str, &Extension>,
) -> Vec<FeaturesFfiMember> {
let mut feature_included_in: HashMap<&str, Vec<&str>> = HashMap::new();
let mut feature_included_in: HashMap<&str, Vec<&str>> = HashMap::default();
sorted_structs(types)
.into_iter()
.map(|(ty, provided_by)| {

View File

@ -7,9 +7,8 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{write_file, VkRegistryData};
use super::{write_file, IndexMap, VkRegistryData};
use heck::{ToSnakeCase, ToUpperCamelCase};
use indexmap::IndexMap;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use vk_parse::{Extension, ExtensionChild, InterfaceItem};

View File

@ -7,9 +7,8 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{extensions::RequiresOneOf, write_file, VkRegistryData};
use super::{extensions::RequiresOneOf, write_file, IndexMap, VkRegistryData};
use heck::ToSnakeCase;
use indexmap::IndexMap;
use lazy_static::lazy_static;
use proc_macro2::{Ident, Literal, TokenStream};
use quote::{format_ident, quote};

View File

@ -8,11 +8,10 @@
// according to those terms.
use self::spirv_grammar::SpirvGrammar;
use indexmap::IndexMap;
use ahash::HashMap;
use lazy_static::lazy_static;
use regex::Regex;
use std::{
collections::HashMap,
env,
fmt::Display,
fs::File,
@ -36,6 +35,8 @@ mod spirv_parse;
mod spirv_reqs;
mod version;
pub type IndexMap<K, V> = indexmap::IndexMap<K, V, ahash::RandomState>;
pub fn autogen() {
let registry = get_vk_registry("vk.xml");
let vk_data = VkRegistryData::new(&registry);

View File

@ -7,16 +7,13 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{write_file, VkRegistryData};
use super::{write_file, IndexMap, VkRegistryData};
use ahash::HashMap;
use heck::ToSnakeCase;
use indexmap::IndexMap;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use regex::Regex;
use std::{
collections::{hash_map::Entry, HashMap},
fmt::Write as _,
};
use std::{collections::hash_map::Entry, fmt::Write as _};
use vk_parse::{Extension, Type, TypeMember, TypeMemberMarkup, TypeSpec};
pub fn write(vk_data: &VkRegistryData) {
@ -142,7 +139,7 @@ fn properties_output(members: &[PropertiesMember]) -> TokenStream {
}
fn properties_members(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<PropertiesMember> {
let mut properties = HashMap::new();
let mut properties = HashMap::default();
[
&types["VkPhysicalDeviceProperties"],
@ -306,7 +303,7 @@ fn properties_ffi_members<'a>(
types: &'a HashMap<&str, (&Type, Vec<&str>)>,
extensions: &IndexMap<&'a str, &Extension>,
) -> Vec<PropertiesFfiMember> {
let mut property_included_in: HashMap<&str, Vec<&str>> = HashMap::new();
let mut property_included_in: HashMap<&str, Vec<&str>> = HashMap::default();
sorted_structs(types)
.into_iter()
.map(|(ty, provided_by)| {

View File

@ -8,11 +8,11 @@
// according to those terms.
use super::{write_file, SpirvGrammar};
use ahash::{HashMap, HashSet};
use heck::ToSnakeCase;
use lazy_static::lazy_static;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use std::collections::{HashMap, HashSet};
lazy_static! {
static ref SPEC_CONSTANT_OP: HashSet<&'static str> = {
@ -252,7 +252,7 @@ fn instruction_members(grammar: &SpirvGrammar) -> Vec<InstructionMember> {
let name = format_ident!("{}", instruction.opname.strip_prefix("Op").unwrap());
let mut has_result_id = false;
let mut has_result_type_id = false;
let mut operand_names = HashMap::new();
let mut operand_names = HashMap::default();
let mut operands = instruction
.operands

View File

@ -9,10 +9,10 @@
use super::{
spirv_grammar::{SpirvGrammar, SpirvKindEnumerant},
write_file, VkRegistryData,
write_file, IndexMap, VkRegistryData,
};
use heck::ToSnakeCase;
use indexmap::{map::Entry, IndexMap};
use indexmap::map::Entry;
use lazy_static::lazy_static;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
@ -148,7 +148,7 @@ fn spirv_capabilities_members(
capabilities: &[&SpirvExtOrCap],
grammar_enumerants: &[SpirvKindEnumerant],
) -> Vec<SpirvReqsMember> {
let mut members: IndexMap<String, SpirvReqsMember> = IndexMap::new();
let mut members: IndexMap<String, SpirvReqsMember> = IndexMap::default();
for ext_or_cap in capabilities {
let mut enables: Vec<_> = ext_or_cap.enables.iter().filter_map(make_enable).collect();

78
vulkano/src/cache.rs Normal file
View File

@ -0,0 +1,78 @@
use ahash::HashMap;
use parking_lot::RwLock;
use std::{collections::hash_map::Entry, hash::Hash};
/// A map specialized to caching properties that are specific to a Vulkan implementation.
///
/// Readers never block each other, except when an entry is vacant. In that case it gets written to
/// once and then never again, entries are immutable after insertion.
#[derive(Debug)]
pub(crate) struct OnceCache<K, V> {
inner: RwLock<HashMap<K, V>>,
}
impl<K, V> Default for OnceCache<K, V> {
fn default() -> Self {
OnceCache {
inner: RwLock::new(HashMap::default()),
}
}
}
impl<K, V> OnceCache<K, V> {
/// Creates a new `OnceCache`.
pub fn new() -> Self {
Self::default()
}
}
impl<K, V> OnceCache<K, V>
where
K: Eq + Hash,
V: Clone,
{
/// Returns the value for the specified `key`. The entry gets written to with the value
/// returned by `f` if it doesn't exist.
pub fn get_or_insert(&self, key: K, f: impl FnOnce(&K) -> V) -> V {
if let Some(value) = self.inner.read().get(&key) {
return value.clone();
}
match self.inner.write().entry(key) {
Entry::Occupied(entry) => {
// This can happen if someone else inserted an entry between when we released
// the read lock and acquired the write lock.
entry.get().clone()
}
Entry::Vacant(entry) => {
let value = f(entry.key());
entry.insert(value.clone());
value
}
}
}
/// Returns the value for the specified `key`. The entry gets written to with the value
/// returned by `f` if it doesn't exist. If `f` returns [`Err`], the error is propagated and
/// the entry isn't written to.
pub fn get_or_try_insert<E>(&self, key: K, f: impl FnOnce(&K) -> Result<V, E>) -> Result<V, E> {
if let Some(value) = self.inner.read().get(&key) {
return Ok(value.clone());
}
match self.inner.write().entry(key) {
Entry::Occupied(entry) => {
// This can happen if someone else inserted an entry between when we released
// the read lock and acquired the write lock.
Ok(entry.get().clone())
}
Entry::Vacant(entry) => {
let value = f(entry.key())?;
entry.insert(value.clone());
Ok(value)
}
}
}
}

View File

@ -29,8 +29,8 @@ use crate::{
sync::{AccessCheckError, AccessFlags, GpuFuture, PipelineMemoryAccess, PipelineStages},
DeviceSize, OomError, RequirementNotMet, RequiresOneOf,
};
use ahash::HashMap;
use std::{
collections::HashMap,
error::Error,
fmt::{Display, Error as FmtError, Formatter},
marker::PhantomData,

View File

@ -43,10 +43,11 @@ use crate::{
},
DeviceSize, OomError, VulkanObject,
};
use ahash::HashMap;
use smallvec::SmallVec;
use std::{
borrow::Cow,
collections::{hash_map::Entry, HashMap},
collections::hash_map::Entry,
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
ops::{Range, RangeInclusive},

View File

@ -84,9 +84,9 @@ use crate::{
},
DeviceSize,
};
use ahash::HashMap;
use std::{
borrow::Cow,
collections::HashMap,
fmt::{Debug, Error as FmtError, Formatter},
ops::Range,
sync::Arc,

View File

@ -18,8 +18,9 @@ use crate::{
shader::{DescriptorRequirements, ShaderStages},
OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use ahash::HashMap;
use std::{
collections::{BTreeMap, HashMap},
collections::BTreeMap,
error::Error,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
@ -900,7 +901,7 @@ mod tests {
},
shader::ShaderStages,
};
use std::collections::HashMap;
use ahash::HashMap;
#[test]
fn empty() {

View File

@ -89,9 +89,9 @@ use crate::{
sampler::Sampler,
OomError, VulkanObject,
};
use ahash::HashMap;
use smallvec::{smallvec, SmallVec};
use std::{
collections::HashMap,
error::Error,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},

View File

@ -20,7 +20,8 @@ use crate::{
device::{Device, DeviceOwned},
OomError,
};
use std::{collections::HashMap, sync::Arc};
use ahash::HashMap;
use std::sync::Arc;
/// Standard implementation of a descriptor pool.
///

View File

@ -15,9 +15,9 @@ use crate::{
device::{Device, DeviceOwned},
OomError, Version, VulkanError, VulkanObject,
};
use ahash::HashMap;
use smallvec::SmallVec;
use std::{
collections::HashMap,
error::Error,
fmt::{Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},

View File

@ -120,12 +120,13 @@ pub use crate::{
extensions::{ExtensionRestriction, ExtensionRestrictionError},
fns::DeviceFunctions,
};
use ahash::HashMap;
use ash::vk::Handle;
use parking_lot::Mutex;
use smallvec::SmallVec;
use std::{
cell::RefCell,
collections::{hash_map::Entry, HashMap},
collections::hash_map::Entry,
error::Error,
ffi::CString,
fmt::{Display, Error as FmtError, Formatter},

View File

@ -10,6 +10,7 @@
use super::QueueFamilyProperties;
use crate::{
buffer::{ExternalBufferInfo, ExternalBufferProperties},
cache::OnceCache,
device::{DeviceExtensions, Features, FeaturesFfi, Properties, PropertiesFfi},
format::{Format, FormatProperties},
image::{
@ -30,10 +31,7 @@ use crate::{
ExtensionProperties, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use bytemuck::cast_slice;
use parking_lot::RwLock;
use std::{
collections::{hash_map::Entry, HashMap},
convert::Infallible,
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
@ -78,14 +76,13 @@ pub struct PhysicalDevice {
queue_family_properties: Vec<QueueFamilyProperties>,
// Data queried by the user at runtime, cached for faster lookups.
external_buffer_properties: RwLock<HashMap<ExternalBufferInfo, ExternalBufferProperties>>,
external_fence_properties: RwLock<HashMap<ExternalFenceInfo, ExternalFenceProperties>>,
external_semaphore_properties:
RwLock<HashMap<ExternalSemaphoreInfo, ExternalSemaphoreProperties>>,
format_properties: RwLock<HashMap<Format, FormatProperties>>,
image_format_properties: RwLock<HashMap<ImageFormatInfo, Option<ImageFormatProperties>>>,
external_buffer_properties: OnceCache<ExternalBufferInfo, ExternalBufferProperties>,
external_fence_properties: OnceCache<ExternalFenceInfo, ExternalFenceProperties>,
external_semaphore_properties: OnceCache<ExternalSemaphoreInfo, ExternalSemaphoreProperties>,
format_properties: OnceCache<Format, FormatProperties>,
image_format_properties: OnceCache<ImageFormatInfo, Option<ImageFormatProperties>>,
sparse_image_format_properties:
RwLock<HashMap<SparseImageFormatInfo, Vec<SparseImageFormatProperties>>>,
OnceCache<SparseImageFormatInfo, Vec<SparseImageFormatProperties>>,
}
impl PhysicalDevice {
@ -143,12 +140,12 @@ impl PhysicalDevice {
memory_properties,
queue_family_properties,
external_buffer_properties: RwLock::new(HashMap::new()),
external_fence_properties: RwLock::new(HashMap::new()),
external_semaphore_properties: RwLock::new(HashMap::new()),
format_properties: RwLock::new(HashMap::new()),
image_format_properties: RwLock::new(HashMap::new()),
sparse_image_format_properties: RwLock::new(HashMap::new()),
external_buffer_properties: OnceCache::new(),
external_fence_properties: OnceCache::new(),
external_semaphore_properties: OnceCache::new(),
format_properties: OnceCache::new(),
image_format_properties: OnceCache::new(),
sparse_image_format_properties: OnceCache::new(),
}))
}
@ -544,7 +541,7 @@ impl PhysicalDevice {
&self,
info: ExternalBufferInfo,
) -> ExternalBufferProperties {
get_cached(&self.external_buffer_properties, info, |info| {
self.external_buffer_properties.get_or_insert(info, |info| {
/* Input */
let &ExternalBufferInfo {
@ -584,13 +581,12 @@ impl PhysicalDevice {
);
}
Ok::<_, Infallible>(ExternalBufferProperties {
ExternalBufferProperties {
external_memory_properties: external_buffer_properties
.external_memory_properties
.into(),
}
})
})
.unwrap()
}
/// Retrieves the external handle properties supported for fences with a given
@ -648,7 +644,7 @@ impl PhysicalDevice {
&self,
info: ExternalFenceInfo,
) -> ExternalFenceProperties {
get_cached(&self.external_fence_properties, info, |info| {
self.external_fence_properties.get_or_insert(info, |info| {
/* Input */
let &ExternalFenceInfo {
@ -684,7 +680,7 @@ impl PhysicalDevice {
);
}
Ok::<_, Infallible>(ExternalFenceProperties {
ExternalFenceProperties {
exportable: external_fence_properties
.external_fence_features
.intersects(ash::vk::ExternalFenceFeatureFlags::EXPORTABLE),
@ -695,9 +691,8 @@ impl PhysicalDevice {
.export_from_imported_handle_types
.into(),
compatible_handle_types: external_fence_properties.compatible_handle_types.into(),
}
})
})
.unwrap()
}
/// Retrieves the external handle properties supported for semaphores with a given
@ -755,7 +750,8 @@ impl PhysicalDevice {
&self,
info: ExternalSemaphoreInfo,
) -> ExternalSemaphoreProperties {
get_cached(&self.external_semaphore_properties, info, |info| {
self.external_semaphore_properties
.get_or_insert(info, |info| {
/* Input */
let &ExternalSemaphoreInfo {
@ -770,7 +766,8 @@ impl PhysicalDevice {
/* Output */
let mut external_semaphore_properties = ash::vk::ExternalSemaphoreProperties::default();
let mut external_semaphore_properties =
ash::vk::ExternalSemaphoreProperties::default();
/* Call */
@ -791,7 +788,7 @@ impl PhysicalDevice {
);
}
Ok::<_, Infallible>(ExternalSemaphoreProperties {
ExternalSemaphoreProperties {
exportable: external_semaphore_properties
.external_semaphore_features
.intersects(ash::vk::ExternalSemaphoreFeatureFlags::EXPORTABLE),
@ -804,9 +801,8 @@ impl PhysicalDevice {
compatible_handle_types: external_semaphore_properties
.compatible_handle_types
.into(),
}
})
})
.unwrap()
}
/// Retrieves the properties of a format when used by this physical device.
@ -832,7 +828,7 @@ impl PhysicalDevice {
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn format_properties_unchecked(&self, format: Format) -> FormatProperties {
get_cached(&self.format_properties, format, |&format| {
self.format_properties.get_or_insert(format, |&format| {
let mut format_properties2 = ash::vk::FormatProperties2::default();
let mut format_properties3 = if self.api_version() >= Version::V1_3
|| self.supported_extensions().khr_format_feature_flags2
@ -874,7 +870,7 @@ impl PhysicalDevice {
);
}
Ok::<_, Infallible>(match format_properties3 {
match format_properties3 {
Some(format_properties3) => FormatProperties {
linear_tiling_features: format_properties3.linear_tiling_features.into(),
optimal_tiling_features: format_properties3.optimal_tiling_features.into(),
@ -893,9 +889,8 @@ impl PhysicalDevice {
buffer_features: format_properties2.format_properties.buffer_features.into(),
_ne: crate::NonExhaustive(()),
},
}
})
})
.unwrap()
}
/// Returns the properties supported for images with a given image configuration.
@ -1043,10 +1038,8 @@ impl PhysicalDevice {
}
}
get_cached(
&self.image_format_properties,
image_format_info,
|image_format_info| {
self.image_format_properties
.get_or_try_insert(image_format_info, |image_format_info| {
/* Input */
let &ImageFormatInfo {
format,
@ -1198,8 +1191,7 @@ impl PhysicalDevice {
Err(VulkanError::FormatNotSupported) => None,
Err(err) => return Err(err),
})
},
)
})
}
/// Queries whether the physical device supports presenting to QNX Screen surfaces from queues
@ -1325,10 +1317,8 @@ impl PhysicalDevice {
&self,
format_info: SparseImageFormatInfo,
) -> Vec<SparseImageFormatProperties> {
get_cached(
&self.sparse_image_format_properties,
format_info,
|format_info| {
self.sparse_image_format_properties
.get_or_insert(format_info, |format_info| {
let &SparseImageFormatInfo {
format,
image_type,
@ -1396,7 +1386,6 @@ impl PhysicalDevice {
sparse_image_format_properties2.set_len(count as usize);
Ok::<_, Infallible>(
sparse_image_format_properties2
.into_iter()
.map(
@ -1422,8 +1411,7 @@ impl PhysicalDevice {
flags: sparse_image_format_properties2.properties.flags.into(),
},
)
.collect(),
)
.collect()
} else {
let mut count = 0;
@ -1454,7 +1442,6 @@ impl PhysicalDevice {
sparse_image_format_properties.set_len(count as usize);
Ok::<_, Infallible>(
sparse_image_format_properties
.into_iter()
.map(
@ -1468,12 +1455,9 @@ impl PhysicalDevice {
flags: sparse_image_format_properties.flags.into(),
},
)
.collect(),
)
.collect()
}
},
)
.unwrap()
})
}
/// Returns the capabilities that are supported by the physical device for the given surface.
@ -1555,8 +1539,7 @@ impl PhysicalDevice {
surface: &Surface<W>,
surface_info: SurfaceInfo,
) -> Result<SurfaceCapabilities, VulkanError> {
get_cached(
&surface.surface_capabilities,
surface.surface_capabilities.get_or_try_insert(
(self.handle, surface_info),
|(_, surface_info)| {
/* Input */
@ -1805,8 +1788,7 @@ impl PhysicalDevice {
surface: &Surface<W>,
surface_info: SurfaceInfo,
) -> Result<Vec<(Format, ColorSpace)>, VulkanError> {
get_cached(
&surface.surface_formats,
surface.surface_formats.get_or_try_insert(
(self.handle, surface_info),
|(_, surface_info)| {
let &SurfaceInfo {
@ -1992,7 +1974,9 @@ impl PhysicalDevice {
&self,
surface: &Surface<W>,
) -> Result<impl Iterator<Item = PresentMode>, VulkanError> {
get_cached(&surface.surface_present_modes, self.handle, |_| {
surface
.surface_present_modes
.get_or_try_insert(self.handle, |_| {
let fns = self.instance.fns();
let modes = loop {
@ -2082,10 +2066,9 @@ impl PhysicalDevice {
queue_family_index: u32,
surface: &Surface<W>,
) -> Result<bool, VulkanError> {
get_cached(
&surface.surface_support,
(self.handle, queue_family_index),
|_| {
surface
.surface_support
.get_or_try_insert((self.handle, queue_family_index), |_| {
let fns = self.instance.fns();
let mut output = MaybeUninit::uninit();
@ -2099,8 +2082,7 @@ impl PhysicalDevice {
.map_err(VulkanError::from)?;
Ok(output.assume_init() != 0)
},
)
})
}
/// Retrieves the properties of tools that are currently active on the physical device.
@ -2472,37 +2454,6 @@ impl Hash for PhysicalDevice {
}
}
unsafe fn get_cached<K, V, E>(
cache: &RwLock<HashMap<K, V>>,
key: K,
func: impl FnOnce(&K) -> Result<V, E>,
) -> Result<V, E>
where
K: Eq + Hash,
V: Clone,
{
{
let read_lock = cache.read();
if let Some(result) = read_lock.get(&key) {
return Ok(result.clone());
}
}
let mut write_lock = cache.write();
match write_lock.entry(key) {
Entry::Occupied(entry) => {
// This can happen if someone else inserted an entry between when we released
// the read lock and acquired the write lock.
Ok(entry.get().clone())
}
Entry::Vacant(entry) => {
let result = func(entry.key())?;
entry.insert(result.clone());
Ok(result)
}
}
}
vulkan_enum! {
/// Type of a physical device.
#[non_exhaustive]

View File

@ -104,6 +104,7 @@ pub mod format;
mod version;
#[macro_use]
pub mod render_pass;
mod cache;
mod fns;
pub mod image;
pub mod instance;

View File

@ -36,8 +36,8 @@ use crate::{
shader::{DescriptorRequirements, EntryPoint, SpecializationConstants},
DeviceSize, OomError, VulkanError, VulkanObject,
};
use ahash::HashMap;
use std::{
collections::HashMap,
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
mem,

View File

@ -51,9 +51,10 @@ use crate::{
},
DeviceSize, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use ahash::HashMap;
use smallvec::SmallVec;
use std::{
collections::{hash_map::Entry, HashMap},
collections::hash_map::Entry,
mem::{size_of_val, MaybeUninit},
ptr, slice,
sync::Arc,
@ -217,7 +218,7 @@ where
// We want to union each push constant range into a set of ranges that do not have intersecting stage flags.
// e.g. The range [0, 16) is either made available to Vertex | Fragment or we only make [0, 16) available to
// Vertex and a subrange available to Fragment, like [0, 8)
let mut range_map = HashMap::new();
let mut range_map = HashMap::default();
for stage in stages.iter() {
if let Some(range) = stage.push_constant_requirements() {
match range_map.entry((range.offset, range.size)) {
@ -2382,7 +2383,7 @@ where
let render_pass = render_pass.as_ref().unwrap();
let mut descriptor_requirements: HashMap<(u32, u32), DescriptorRequirements> =
HashMap::new();
HashMap::default();
let mut dynamic_state: HashMap<DynamicState, bool> = HashMap::default();
let mut stages = HashMap::default();
let mut stages_vk: SmallVec<[_; 5]> = SmallVec::new();

View File

@ -70,8 +70,8 @@ use crate::{
shader::{DescriptorRequirements, ShaderStage},
VulkanObject,
};
use ahash::HashMap;
use std::{
collections::HashMap,
fmt::{Debug, Error as FmtError, Formatter},
hash::{Hash, Hasher},
ptr,

View File

@ -106,7 +106,7 @@ pub use self::{
vertex::{Vertex, VertexMemberInfo, VertexMemberTy},
};
use crate::format::Format;
use std::collections::HashMap;
use ahash::HashMap;
mod buffers;
mod collection;

View File

@ -28,9 +28,9 @@ use crate::{
sync::PipelineStages,
DeviceSize, OomError, Version, VulkanError, VulkanObject,
};
use ahash::{HashMap, HashSet};
use std::{
borrow::Cow,
collections::{HashMap, HashSet},
error::Error,
ffi::{CStr, CString},
fmt::{Display, Error as FmtError, Formatter},

View File

@ -25,10 +25,8 @@ use crate::{
},
DeviceSize,
};
use std::{
borrow::Cow,
collections::{HashMap, HashSet},
};
use ahash::{HashMap, HashSet};
use std::borrow::Cow;
/// Returns an iterator of the capabilities used by `spirv`.
pub fn spirv_capabilities(spirv: &Spirv) -> impl Iterator<Item = &Capability> {

View File

@ -16,8 +16,8 @@
//! [SPIR-V specification](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html).
use crate::Version;
use ahash::{HashMap, HashMapExt};
use std::{
collections::HashMap,
error::Error,
fmt::{Display, Error as FmtError, Formatter},
ops::Range,

View File

@ -9,6 +9,7 @@
use super::{FullScreenExclusive, Win32Monitor};
use crate::{
cache::OnceCache,
format::Format,
image::ImageUsage,
instance::Instance,
@ -23,9 +24,7 @@ use crate::{
#[cfg(target_os = "ios")]
use objc::{class, msg_send, runtime::Object, sel, sel_impl};
use parking_lot::RwLock;
use std::{
collections::HashMap,
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
@ -52,11 +51,11 @@ pub struct Surface<W> {
// This is stored here rather than on `PhysicalDevice` to ensure that it's freed when the
// `Surface` is destroyed.
pub(crate) surface_capabilities:
RwLock<HashMap<(ash::vk::PhysicalDevice, SurfaceInfo), SurfaceCapabilities>>,
OnceCache<(ash::vk::PhysicalDevice, SurfaceInfo), SurfaceCapabilities>,
pub(crate) surface_formats:
RwLock<HashMap<(ash::vk::PhysicalDevice, SurfaceInfo), Vec<(Format, ColorSpace)>>>,
pub(crate) surface_present_modes: RwLock<HashMap<ash::vk::PhysicalDevice, Vec<PresentMode>>>,
pub(crate) surface_support: RwLock<HashMap<(ash::vk::PhysicalDevice, u32), bool>>,
OnceCache<(ash::vk::PhysicalDevice, SurfaceInfo), Vec<(Format, ColorSpace)>>,
pub(crate) surface_present_modes: OnceCache<ash::vk::PhysicalDevice, Vec<PresentMode>>,
pub(crate) surface_support: OnceCache<(ash::vk::PhysicalDevice, u32), bool>,
}
impl<W> Surface<W> {
@ -85,10 +84,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}
}
@ -151,10 +150,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -250,10 +249,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -331,10 +330,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -420,10 +419,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -506,10 +505,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -592,10 +591,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -679,10 +678,10 @@ impl<W> Surface<W> {
has_swapchain: AtomicBool::new(false),
metal_layer,
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -767,10 +766,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -845,10 +844,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -936,10 +935,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -1017,10 +1016,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -1110,10 +1109,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -1201,10 +1200,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -1292,10 +1291,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}
@ -1383,10 +1382,10 @@ impl<W> Surface<W> {
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_capabilities: RwLock::new(HashMap::new()),
surface_formats: RwLock::new(HashMap::new()),
surface_present_modes: RwLock::new(HashMap::new()),
surface_support: RwLock::new(HashMap::new()),
surface_capabilities: OnceCache::new(),
surface_formats: OnceCache::new(),
surface_present_modes: OnceCache::new(),
surface_support: OnceCache::new(),
}))
}