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 proc-macro = true
[dependencies] [dependencies]
ahash = "0.8"
heck = "0.4" heck = "0.4"
proc-macro2 = "1.0" proc-macro2 = "1.0"
quote = "1.0" quote = "1.0"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,8 +17,8 @@ use vulkano::{
debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo}, debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo},
Instance, InstanceCreateInfo, InstanceExtensions, Instance, InstanceCreateInfo, InstanceExtensions,
}, },
Version, VulkanLibrary,
}; };
use vulkano::{Version, VulkanLibrary};
/// A configuration struct to pass various creation options to create [`VulkanoContext`]. /// 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 // notice may not be copied, modified, or distributed except
// according to those terms. // according to those terms.
use std::collections::HashMap; use crate::{context::VulkanoContext, window::WindowDescriptor};
use ahash::HashMap;
use std::sync::Arc; 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::{ use vulkano::{
device::Queue, device::{Device, Queue},
format::Format, format::Format,
image::{view::ImageView, ImageAccess, ImageViewAbstract}, image::{
swapchain, view::ImageView, ImageAccess, ImageUsage, ImageViewAbstract, StorageImage, SwapchainImage,
swapchain::{AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError}, },
sync, swapchain::{
sync::{FlushError, GpuFuture}, self, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
}; };
use vulkano_win::create_surface_from_winit; use vulkano_win::create_surface_from_winit;
use winit::window::Window; use winit::window::Window;

View File

@ -11,13 +11,14 @@
// notice may not be copied, modified, or distributed except // notice may not be copied, modified, or distributed except
// according to those terms. // according to those terms.
use crate::context::VulkanoContext; use crate::{context::VulkanoContext, renderer::VulkanoWindowRenderer};
use crate::renderer::VulkanoWindowRenderer; use ahash::HashMap;
use std::collections::hash_map::{Iter, IterMut}; use std::collections::hash_map::{Iter, IterMut};
use std::collections::HashMap;
use vulkano::swapchain::{PresentMode, SwapchainCreateInfo}; use vulkano::swapchain::{PresentMode, SwapchainCreateInfo};
use winit::dpi::LogicalSize; use winit::{
use winit::window::{CursorGrabMode, WindowId}; dpi::LogicalSize,
window::{CursorGrabMode, WindowId},
};
/// A struct organizing windows and their corresponding renderers. This makes it easy to handle multiple windows. /// 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, HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
}; };
use std::sync::Arc; use std::sync::Arc;
use vulkano::instance::Instance; use vulkano::{
use vulkano::swapchain::Surface; instance::Instance,
use vulkano::swapchain::SurfaceCreationError; swapchain::{Surface, SurfaceCreationError},
};
/// Creates a vulkan surface from a generic window /// Creates a vulkan surface from a generic window
/// which implements HasRawWindowHandle and thus can reveal the os-dependent handle. /// which implements HasRawWindowHandle and thus can reveal the os-dependent handle.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,11 +8,11 @@
// according to those terms. // according to those terms.
use super::{write_file, SpirvGrammar}; use super::{write_file, SpirvGrammar};
use ahash::{HashMap, HashSet};
use heck::ToSnakeCase; use heck::ToSnakeCase;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use std::collections::{HashMap, HashSet};
lazy_static! { lazy_static! {
static ref SPEC_CONSTANT_OP: HashSet<&'static str> = { 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 name = format_ident!("{}", instruction.opname.strip_prefix("Op").unwrap());
let mut has_result_id = false; let mut has_result_id = false;
let mut has_result_type_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 let mut operands = instruction
.operands .operands

View File

@ -9,10 +9,10 @@
use super::{ use super::{
spirv_grammar::{SpirvGrammar, SpirvKindEnumerant}, spirv_grammar::{SpirvGrammar, SpirvKindEnumerant},
write_file, VkRegistryData, write_file, IndexMap, VkRegistryData,
}; };
use heck::ToSnakeCase; use heck::ToSnakeCase;
use indexmap::{map::Entry, IndexMap}; use indexmap::map::Entry;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
@ -148,7 +148,7 @@ fn spirv_capabilities_members(
capabilities: &[&SpirvExtOrCap], capabilities: &[&SpirvExtOrCap],
grammar_enumerants: &[SpirvKindEnumerant], grammar_enumerants: &[SpirvKindEnumerant],
) -> Vec<SpirvReqsMember> { ) -> Vec<SpirvReqsMember> {
let mut members: IndexMap<String, SpirvReqsMember> = IndexMap::new(); let mut members: IndexMap<String, SpirvReqsMember> = IndexMap::default();
for ext_or_cap in capabilities { for ext_or_cap in capabilities {
let mut enables: Vec<_> = ext_or_cap.enables.iter().filter_map(make_enable).collect(); 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}, sync::{AccessCheckError, AccessFlags, GpuFuture, PipelineMemoryAccess, PipelineStages},
DeviceSize, OomError, RequirementNotMet, RequiresOneOf, DeviceSize, OomError, RequirementNotMet, RequiresOneOf,
}; };
use ahash::HashMap;
use std::{ use std::{
collections::HashMap,
error::Error, error::Error,
fmt::{Display, Error as FmtError, Formatter}, fmt::{Display, Error as FmtError, Formatter},
marker::PhantomData, marker::PhantomData,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,6 +10,7 @@
use super::QueueFamilyProperties; use super::QueueFamilyProperties;
use crate::{ use crate::{
buffer::{ExternalBufferInfo, ExternalBufferProperties}, buffer::{ExternalBufferInfo, ExternalBufferProperties},
cache::OnceCache,
device::{DeviceExtensions, Features, FeaturesFfi, Properties, PropertiesFfi}, device::{DeviceExtensions, Features, FeaturesFfi, Properties, PropertiesFfi},
format::{Format, FormatProperties}, format::{Format, FormatProperties},
image::{ image::{
@ -30,10 +31,7 @@ use crate::{
ExtensionProperties, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject, ExtensionProperties, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
}; };
use bytemuck::cast_slice; use bytemuck::cast_slice;
use parking_lot::RwLock;
use std::{ use std::{
collections::{hash_map::Entry, HashMap},
convert::Infallible,
error::Error, error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter}, fmt::{Debug, Display, Error as FmtError, Formatter},
hash::{Hash, Hasher}, hash::{Hash, Hasher},
@ -78,14 +76,13 @@ pub struct PhysicalDevice {
queue_family_properties: Vec<QueueFamilyProperties>, queue_family_properties: Vec<QueueFamilyProperties>,
// Data queried by the user at runtime, cached for faster lookups. // Data queried by the user at runtime, cached for faster lookups.
external_buffer_properties: RwLock<HashMap<ExternalBufferInfo, ExternalBufferProperties>>, external_buffer_properties: OnceCache<ExternalBufferInfo, ExternalBufferProperties>,
external_fence_properties: RwLock<HashMap<ExternalFenceInfo, ExternalFenceProperties>>, external_fence_properties: OnceCache<ExternalFenceInfo, ExternalFenceProperties>,
external_semaphore_properties: external_semaphore_properties: OnceCache<ExternalSemaphoreInfo, ExternalSemaphoreProperties>,
RwLock<HashMap<ExternalSemaphoreInfo, ExternalSemaphoreProperties>>, format_properties: OnceCache<Format, FormatProperties>,
format_properties: RwLock<HashMap<Format, FormatProperties>>, image_format_properties: OnceCache<ImageFormatInfo, Option<ImageFormatProperties>>,
image_format_properties: RwLock<HashMap<ImageFormatInfo, Option<ImageFormatProperties>>>,
sparse_image_format_properties: sparse_image_format_properties:
RwLock<HashMap<SparseImageFormatInfo, Vec<SparseImageFormatProperties>>>, OnceCache<SparseImageFormatInfo, Vec<SparseImageFormatProperties>>,
} }
impl PhysicalDevice { impl PhysicalDevice {
@ -143,12 +140,12 @@ impl PhysicalDevice {
memory_properties, memory_properties,
queue_family_properties, queue_family_properties,
external_buffer_properties: RwLock::new(HashMap::new()), external_buffer_properties: OnceCache::new(),
external_fence_properties: RwLock::new(HashMap::new()), external_fence_properties: OnceCache::new(),
external_semaphore_properties: RwLock::new(HashMap::new()), external_semaphore_properties: OnceCache::new(),
format_properties: RwLock::new(HashMap::new()), format_properties: OnceCache::new(),
image_format_properties: RwLock::new(HashMap::new()), image_format_properties: OnceCache::new(),
sparse_image_format_properties: RwLock::new(HashMap::new()), sparse_image_format_properties: OnceCache::new(),
})) }))
} }
@ -544,7 +541,7 @@ impl PhysicalDevice {
&self, &self,
info: ExternalBufferInfo, info: ExternalBufferInfo,
) -> ExternalBufferProperties { ) -> ExternalBufferProperties {
get_cached(&self.external_buffer_properties, info, |info| { self.external_buffer_properties.get_or_insert(info, |info| {
/* Input */ /* Input */
let &ExternalBufferInfo { let &ExternalBufferInfo {
@ -584,13 +581,12 @@ impl PhysicalDevice {
); );
} }
Ok::<_, Infallible>(ExternalBufferProperties { ExternalBufferProperties {
external_memory_properties: external_buffer_properties external_memory_properties: external_buffer_properties
.external_memory_properties .external_memory_properties
.into(), .into(),
}) }
}) })
.unwrap()
} }
/// Retrieves the external handle properties supported for fences with a given /// Retrieves the external handle properties supported for fences with a given
@ -648,7 +644,7 @@ impl PhysicalDevice {
&self, &self,
info: ExternalFenceInfo, info: ExternalFenceInfo,
) -> ExternalFenceProperties { ) -> ExternalFenceProperties {
get_cached(&self.external_fence_properties, info, |info| { self.external_fence_properties.get_or_insert(info, |info| {
/* Input */ /* Input */
let &ExternalFenceInfo { let &ExternalFenceInfo {
@ -684,7 +680,7 @@ impl PhysicalDevice {
); );
} }
Ok::<_, Infallible>(ExternalFenceProperties { ExternalFenceProperties {
exportable: external_fence_properties exportable: external_fence_properties
.external_fence_features .external_fence_features
.intersects(ash::vk::ExternalFenceFeatureFlags::EXPORTABLE), .intersects(ash::vk::ExternalFenceFeatureFlags::EXPORTABLE),
@ -695,9 +691,8 @@ impl PhysicalDevice {
.export_from_imported_handle_types .export_from_imported_handle_types
.into(), .into(),
compatible_handle_types: external_fence_properties.compatible_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 /// Retrieves the external handle properties supported for semaphores with a given
@ -755,58 +750,59 @@ impl PhysicalDevice {
&self, &self,
info: ExternalSemaphoreInfo, info: ExternalSemaphoreInfo,
) -> ExternalSemaphoreProperties { ) -> ExternalSemaphoreProperties {
get_cached(&self.external_semaphore_properties, info, |info| { self.external_semaphore_properties
/* Input */ .get_or_insert(info, |info| {
/* Input */
let &ExternalSemaphoreInfo { let &ExternalSemaphoreInfo {
handle_type, handle_type,
_ne: _, _ne: _,
} = info; } = info;
let external_semaphore_info = ash::vk::PhysicalDeviceExternalSemaphoreInfo { let external_semaphore_info = ash::vk::PhysicalDeviceExternalSemaphoreInfo {
handle_type: handle_type.into(), handle_type: handle_type.into(),
..Default::default() ..Default::default()
}; };
/* Output */ /* Output */
let mut external_semaphore_properties = ash::vk::ExternalSemaphoreProperties::default(); let mut external_semaphore_properties =
ash::vk::ExternalSemaphoreProperties::default();
/* Call */ /* Call */
let fns = self.instance.fns(); let fns = self.instance.fns();
if self.instance.api_version() >= Version::V1_1 { if self.instance.api_version() >= Version::V1_1 {
(fns.v1_1.get_physical_device_external_semaphore_properties)( (fns.v1_1.get_physical_device_external_semaphore_properties)(
self.handle, self.handle,
&external_semaphore_info, &external_semaphore_info,
&mut external_semaphore_properties, &mut external_semaphore_properties,
) )
} else { } else {
(fns.khr_external_semaphore_capabilities (fns.khr_external_semaphore_capabilities
.get_physical_device_external_semaphore_properties_khr)( .get_physical_device_external_semaphore_properties_khr)(
self.handle, self.handle,
&external_semaphore_info, &external_semaphore_info,
&mut external_semaphore_properties, &mut external_semaphore_properties,
); );
} }
Ok::<_, Infallible>(ExternalSemaphoreProperties { ExternalSemaphoreProperties {
exportable: external_semaphore_properties exportable: external_semaphore_properties
.external_semaphore_features .external_semaphore_features
.intersects(ash::vk::ExternalSemaphoreFeatureFlags::EXPORTABLE), .intersects(ash::vk::ExternalSemaphoreFeatureFlags::EXPORTABLE),
importable: external_semaphore_properties importable: external_semaphore_properties
.external_semaphore_features .external_semaphore_features
.intersects(ash::vk::ExternalSemaphoreFeatureFlags::IMPORTABLE), .intersects(ash::vk::ExternalSemaphoreFeatureFlags::IMPORTABLE),
export_from_imported_handle_types: external_semaphore_properties export_from_imported_handle_types: external_semaphore_properties
.export_from_imported_handle_types .export_from_imported_handle_types
.into(), .into(),
compatible_handle_types: external_semaphore_properties compatible_handle_types: external_semaphore_properties
.compatible_handle_types .compatible_handle_types
.into(), .into(),
}
}) })
})
.unwrap()
} }
/// Retrieves the properties of a format when used by this physical device. /// 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))] #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn format_properties_unchecked(&self, format: Format) -> FormatProperties { 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_properties2 = ash::vk::FormatProperties2::default();
let mut format_properties3 = if self.api_version() >= Version::V1_3 let mut format_properties3 = if self.api_version() >= Version::V1_3
|| self.supported_extensions().khr_format_feature_flags2 || 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 { Some(format_properties3) => FormatProperties {
linear_tiling_features: format_properties3.linear_tiling_features.into(), linear_tiling_features: format_properties3.linear_tiling_features.into(),
optimal_tiling_features: format_properties3.optimal_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(), buffer_features: format_properties2.format_properties.buffer_features.into(),
_ne: crate::NonExhaustive(()), _ne: crate::NonExhaustive(()),
}, },
}) }
}) })
.unwrap()
} }
/// Returns the properties supported for images with a given image configuration. /// Returns the properties supported for images with a given image configuration.
@ -1043,10 +1038,8 @@ impl PhysicalDevice {
} }
} }
get_cached( self.image_format_properties
&self.image_format_properties, .get_or_try_insert(image_format_info, |image_format_info| {
image_format_info,
|image_format_info| {
/* Input */ /* Input */
let &ImageFormatInfo { let &ImageFormatInfo {
format, format,
@ -1198,8 +1191,7 @@ impl PhysicalDevice {
Err(VulkanError::FormatNotSupported) => None, Err(VulkanError::FormatNotSupported) => None,
Err(err) => return Err(err), Err(err) => return Err(err),
}) })
}, })
)
} }
/// Queries whether the physical device supports presenting to QNX Screen surfaces from queues /// Queries whether the physical device supports presenting to QNX Screen surfaces from queues
@ -1325,10 +1317,8 @@ impl PhysicalDevice {
&self, &self,
format_info: SparseImageFormatInfo, format_info: SparseImageFormatInfo,
) -> Vec<SparseImageFormatProperties> { ) -> Vec<SparseImageFormatProperties> {
get_cached( self.sparse_image_format_properties
&self.sparse_image_format_properties, .get_or_insert(format_info, |format_info| {
format_info,
|format_info| {
let &SparseImageFormatInfo { let &SparseImageFormatInfo {
format, format,
image_type, image_type,
@ -1396,34 +1386,32 @@ impl PhysicalDevice {
sparse_image_format_properties2.set_len(count as usize); sparse_image_format_properties2.set_len(count as usize);
Ok::<_, Infallible>( sparse_image_format_properties2
sparse_image_format_properties2 .into_iter()
.into_iter() .map(
.map( |sparse_image_format_properties2| SparseImageFormatProperties {
|sparse_image_format_properties2| SparseImageFormatProperties { aspects: sparse_image_format_properties2
aspects: sparse_image_format_properties2 .properties
.aspect_mask
.into(),
image_granularity: [
sparse_image_format_properties2
.properties .properties
.aspect_mask .image_granularity
.into(), .width,
image_granularity: [ sparse_image_format_properties2
sparse_image_format_properties2 .properties
.properties .image_granularity
.image_granularity .height,
.width, sparse_image_format_properties2
sparse_image_format_properties2 .properties
.properties .image_granularity
.image_granularity .depth,
.height, ],
sparse_image_format_properties2 flags: sparse_image_format_properties2.properties.flags.into(),
.properties },
.image_granularity )
.depth, .collect()
],
flags: sparse_image_format_properties2.properties.flags.into(),
},
)
.collect(),
)
} else { } else {
let mut count = 0; let mut count = 0;
@ -1454,26 +1442,22 @@ impl PhysicalDevice {
sparse_image_format_properties.set_len(count as usize); sparse_image_format_properties.set_len(count as usize);
Ok::<_, Infallible>( sparse_image_format_properties
sparse_image_format_properties .into_iter()
.into_iter() .map(
.map( |sparse_image_format_properties| SparseImageFormatProperties {
|sparse_image_format_properties| SparseImageFormatProperties { aspects: sparse_image_format_properties.aspect_mask.into(),
aspects: sparse_image_format_properties.aspect_mask.into(), image_granularity: [
image_granularity: [ sparse_image_format_properties.image_granularity.width,
sparse_image_format_properties.image_granularity.width, sparse_image_format_properties.image_granularity.height,
sparse_image_format_properties.image_granularity.height, sparse_image_format_properties.image_granularity.depth,
sparse_image_format_properties.image_granularity.depth, ],
], flags: sparse_image_format_properties.flags.into(),
flags: sparse_image_format_properties.flags.into(), },
}, )
) .collect()
.collect(),
)
} }
}, })
)
.unwrap()
} }
/// Returns the capabilities that are supported by the physical device for the given surface. /// Returns the capabilities that are supported by the physical device for the given surface.
@ -1555,8 +1539,7 @@ impl PhysicalDevice {
surface: &Surface<W>, surface: &Surface<W>,
surface_info: SurfaceInfo, surface_info: SurfaceInfo,
) -> Result<SurfaceCapabilities, VulkanError> { ) -> Result<SurfaceCapabilities, VulkanError> {
get_cached( surface.surface_capabilities.get_or_try_insert(
&surface.surface_capabilities,
(self.handle, surface_info), (self.handle, surface_info),
|(_, surface_info)| { |(_, surface_info)| {
/* Input */ /* Input */
@ -1805,8 +1788,7 @@ impl PhysicalDevice {
surface: &Surface<W>, surface: &Surface<W>,
surface_info: SurfaceInfo, surface_info: SurfaceInfo,
) -> Result<Vec<(Format, ColorSpace)>, VulkanError> { ) -> Result<Vec<(Format, ColorSpace)>, VulkanError> {
get_cached( surface.surface_formats.get_or_try_insert(
&surface.surface_formats,
(self.handle, surface_info), (self.handle, surface_info),
|(_, surface_info)| { |(_, surface_info)| {
let &SurfaceInfo { let &SurfaceInfo {
@ -1992,47 +1974,49 @@ impl PhysicalDevice {
&self, &self,
surface: &Surface<W>, surface: &Surface<W>,
) -> Result<impl Iterator<Item = PresentMode>, VulkanError> { ) -> Result<impl Iterator<Item = PresentMode>, VulkanError> {
get_cached(&surface.surface_present_modes, self.handle, |_| { surface
let fns = self.instance.fns(); .surface_present_modes
.get_or_try_insert(self.handle, |_| {
let fns = self.instance.fns();
let modes = loop { let modes = loop {
let mut count = 0; let mut count = 0;
(fns.khr_surface (fns.khr_surface
.get_physical_device_surface_present_modes_khr)( .get_physical_device_surface_present_modes_khr)(
self.internal_object(), self.internal_object(),
surface.internal_object(), surface.internal_object(),
&mut count, &mut count,
ptr::null_mut(), ptr::null_mut(),
) )
.result() .result()
.map_err(VulkanError::from)?; .map_err(VulkanError::from)?;
let mut modes = Vec::with_capacity(count as usize); let mut modes = Vec::with_capacity(count as usize);
let result = (fns let result = (fns
.khr_surface .khr_surface
.get_physical_device_surface_present_modes_khr)( .get_physical_device_surface_present_modes_khr)(
self.internal_object(), self.internal_object(),
surface.internal_object(), surface.internal_object(),
&mut count, &mut count,
modes.as_mut_ptr(), modes.as_mut_ptr(),
); );
match result { match result {
ash::vk::Result::SUCCESS => { ash::vk::Result::SUCCESS => {
modes.set_len(count as usize); modes.set_len(count as usize);
break modes; break modes;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
} }
ash::vk::Result::INCOMPLETE => (), };
err => return Err(VulkanError::from(err)),
}
};
Ok(modes Ok(modes
.into_iter() .into_iter()
.filter_map(|mode_vk| mode_vk.try_into().ok()) .filter_map(|mode_vk| mode_vk.try_into().ok())
.collect()) .collect())
}) })
.map(IntoIterator::into_iter) .map(IntoIterator::into_iter)
} }
/// Returns whether queues of the given queue family can draw on the given surface. /// Returns whether queues of the given queue family can draw on the given surface.
@ -2082,10 +2066,9 @@ impl PhysicalDevice {
queue_family_index: u32, queue_family_index: u32,
surface: &Surface<W>, surface: &Surface<W>,
) -> Result<bool, VulkanError> { ) -> Result<bool, VulkanError> {
get_cached( surface
&surface.surface_support, .surface_support
(self.handle, queue_family_index), .get_or_try_insert((self.handle, queue_family_index), |_| {
|_| {
let fns = self.instance.fns(); let fns = self.instance.fns();
let mut output = MaybeUninit::uninit(); let mut output = MaybeUninit::uninit();
@ -2099,8 +2082,7 @@ impl PhysicalDevice {
.map_err(VulkanError::from)?; .map_err(VulkanError::from)?;
Ok(output.assume_init() != 0) Ok(output.assume_init() != 0)
}, })
)
} }
/// Retrieves the properties of tools that are currently active on the physical device. /// 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! { vulkan_enum! {
/// Type of a physical device. /// Type of a physical device.
#[non_exhaustive] #[non_exhaustive]

View File

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

View File

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

View File

@ -51,9 +51,10 @@ use crate::{
}, },
DeviceSize, RequiresOneOf, Version, VulkanError, VulkanObject, DeviceSize, RequiresOneOf, Version, VulkanError, VulkanObject,
}; };
use ahash::HashMap;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
collections::{hash_map::Entry, HashMap}, collections::hash_map::Entry,
mem::{size_of_val, MaybeUninit}, mem::{size_of_val, MaybeUninit},
ptr, slice, ptr, slice,
sync::Arc, 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. // 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 // 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) // 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() { for stage in stages.iter() {
if let Some(range) = stage.push_constant_requirements() { if let Some(range) = stage.push_constant_requirements() {
match range_map.entry((range.offset, range.size)) { match range_map.entry((range.offset, range.size)) {
@ -2382,7 +2383,7 @@ where
let render_pass = render_pass.as_ref().unwrap(); let render_pass = render_pass.as_ref().unwrap();
let mut descriptor_requirements: HashMap<(u32, u32), DescriptorRequirements> = let mut descriptor_requirements: HashMap<(u32, u32), DescriptorRequirements> =
HashMap::new(); HashMap::default();
let mut dynamic_state: HashMap<DynamicState, bool> = HashMap::default(); let mut dynamic_state: HashMap<DynamicState, bool> = HashMap::default();
let mut stages = HashMap::default(); let mut stages = HashMap::default();
let mut stages_vk: SmallVec<[_; 5]> = SmallVec::new(); let mut stages_vk: SmallVec<[_; 5]> = SmallVec::new();

View File

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

View File

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

View File

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

View File

@ -25,10 +25,8 @@ use crate::{
}, },
DeviceSize, DeviceSize,
}; };
use std::{ use ahash::{HashMap, HashSet};
borrow::Cow, use std::borrow::Cow;
collections::{HashMap, HashSet},
};
/// Returns an iterator of the capabilities used by `spirv`. /// Returns an iterator of the capabilities used by `spirv`.
pub fn spirv_capabilities(spirv: &Spirv) -> impl Iterator<Item = &Capability> { 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). //! [SPIR-V specification](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html).
use crate::Version; use crate::Version;
use ahash::{HashMap, HashMapExt};
use std::{ use std::{
collections::HashMap,
error::Error, error::Error,
fmt::{Display, Error as FmtError, Formatter}, fmt::{Display, Error as FmtError, Formatter},
ops::Range, ops::Range,

View File

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