From fbc57a39c870315bfe1fc0af2498fc38938294f2 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 12 Feb 2025 16:02:29 +0800 Subject: [PATCH 01/32] add `default-feature = false` to some deps, `std` feature and `hashbrown` --- Cargo.toml | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fa05010d..058d6893 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,26 +12,24 @@ keywords = ["vulkan", "memory", "allocator"] documentation = "https://docs.rs/gpu-allocator/" rust-version = "1.71" -include = [ - "/README.md", - "/LICENSE-*", - "/src", - "/examples", -] +include = ["/README.md", "/LICENSE-*", "/src", "/examples"] [package.metadata.docs.rs] all-features = true [dependencies] -log = "0.4" -thiserror = "1.0" -presser = { version = "0.3" } +log = { version = "0.4", default-feature = false } +thiserror = { version = "2.0", default-feature = false } +presser = { version = "0.3", default-feature = false } # Only needed for Vulkan. Disable all default features as good practice, # such as the ability to link/load a Vulkan library. -ash = { version = "0.38", optional = true, default-features = false, features = ["debug"] } +ash = { version = "0.38", optional = true, default-features = false, features = [ + "debug", +] } # Only needed for visualizer. egui = { version = ">=0.24, <=0.27", optional = true, default-features = false } egui_extras = { version = ">=0.24, <=0.27", optional = true, default-features = false } +hashbrown = { version = "0.15.2", optional = true } [target.'cfg(target_vendor = "apple")'.dependencies] objc2 = { version = "0.6", default-features = false, optional = true } @@ -49,23 +47,38 @@ objc2-metal = { version = "0.3", default-features = false, features = [ [target.'cfg(windows)'.dependencies] # Only needed for public-winapi interop helpers -winapi = { version = "0.3.9", features = ["d3d12", "winerror", "impl-default", "impl-debug"], optional = true } +winapi = { version = "0.3.9", features = [ + "d3d12", + "winerror", + "impl-default", + "impl-debug", +], optional = true } [target.'cfg(windows)'.dependencies.windows] version = ">=0.53,<=0.59" -features = [ - "Win32_Graphics_Direct3D12", - "Win32_Graphics_Dxgi_Common", -] +features = ["Win32_Graphics_Direct3D12", "Win32_Graphics_Dxgi_Common"] optional = true [dev-dependencies] # Enable the "loaded" feature to be able to access the Vulkan entrypoint. -ash = { version = "0.38", default-features = false, features = ["debug", "loaded"] } +ash = { version = "0.38", default-features = false, features = [ + "debug", + "loaded", +] } env_logger = "0.10" [target.'cfg(windows)'.dev-dependencies] -winapi = { version = "0.3.9", features = ["d3d12", "d3d12sdklayers", "dxgi1_6", "winerror", "impl-default", "impl-debug", "winuser", "windowsx", "libloaderapi"] } +winapi = { version = "0.3.9", features = [ + "d3d12", + "d3d12sdklayers", + "dxgi1_6", + "winerror", + "impl-default", + "impl-debug", + "winuser", + "windowsx", + "libloaderapi", +] } [target.'cfg(windows)'.dev-dependencies.windows] # API-breaks since Windows 0.58 only affect our examples @@ -98,11 +111,13 @@ name = "metal-buffer" required-features = ["metal"] [features] +std = ["presser/std"] visualizer = ["dep:egui", "dep:egui_extras"] vulkan = ["dep:ash"] d3d12 = ["dep:windows"] metal = ["dep:objc2", "dep:objc2-metal", "dep:objc2-foundation"] # Expose helper functionality for winapi types to interface with gpu-allocator, which is primarily windows-rs driven public-winapi = ["dep:winapi"] +hashbrown = ["dep:hashbrown"] -default = ["d3d12", "vulkan", "metal"] +default = ["std", "d3d12", "vulkan", "metal"] From 8f853b06f4113e88bbe81d1c7e0c2d13f5e3c970 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 12 Feb 2025 16:03:09 +0800 Subject: [PATCH 02/32] add `no_std` feature compile error --- src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index b148ace0..759aefb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -212,6 +212,16 @@ //! # fn main() {} //! ``` #![deny(clippy::unimplemented, clippy::unwrap_used, clippy::ok_expect)] +#![cfg_attr(not(feature = "std"), no_std)] + +#[macro_use] +extern crate alloc; + +#[cfg(all(not(feature = "std"), not(feature = "hashbrown")))] +compile_error!("\"hashbrown\" feature should be enabled in \"no_std\" environment."); + +#[cfg(all(not(feature = "std"), feature = "visualizer"))] +compile_error!("Cannot enable \"visualizer\" feature in \"no_std\" environment."); mod result; pub use result::*; From e3ca7fb0e33a7932b6bd1ad5e36174188fc4f4a3 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 12 Feb 2025 16:19:21 +0800 Subject: [PATCH 03/32] remove `std::backtrace::Backtrace` in `no_std` --- .../dedicated_block_allocator/mod.rs | 32 +++++++++++++-- src/allocator/free_list_allocator/mod.rs | 41 +++++++++++++++++-- src/allocator/mod.rs | 6 ++- src/d3d12/mod.rs | 26 +++++++++--- src/lib.rs | 4 ++ src/metal/mod.rs | 17 +++++++- src/vulkan/mod.rs | 18 +++++++- 7 files changed, 124 insertions(+), 20 deletions(-) diff --git a/src/allocator/dedicated_block_allocator/mod.rs b/src/allocator/dedicated_block_allocator/mod.rs index 746b4dcd..77b7bec4 100644 --- a/src/allocator/dedicated_block_allocator/mod.rs +++ b/src/allocator/dedicated_block_allocator/mod.rs @@ -1,4 +1,6 @@ #![deny(unsafe_code, clippy::unwrap_used)] +#[cfg(feature = "std")] +use std::{backtrace::Backtrace, sync::Arc}; #[cfg(feature = "visualizer")] pub(crate) mod visualizer; @@ -16,6 +18,7 @@ pub(crate) struct DedicatedBlockAllocator { allocated: u64, /// Only used if [`crate::AllocatorDebugSettings::store_stack_traces`] is [`true`] name: Option, + #[cfg(feature = "std")] backtrace: Arc, } @@ -25,6 +28,7 @@ impl DedicatedBlockAllocator { size, allocated: 0, name: None, + #[cfg(feature = "std")] backtrace: Arc::new(Backtrace::disabled()), } } @@ -39,8 +43,8 @@ impl SubAllocator for DedicatedBlockAllocator { _allocation_type: AllocationType, _granularity: u64, name: &str, - backtrace: Arc, - ) -> Result<(u64, std::num::NonZeroU64)> { + #[cfg(feature = "std")] backtrace: Arc, + ) -> Result<(u64, core::num::NonZeroU64)> { if self.allocated != 0 { return Err(AllocationError::OutOfMemory); } @@ -53,7 +57,10 @@ impl SubAllocator for DedicatedBlockAllocator { self.allocated = size; self.name = Some(name.to_string()); - self.backtrace = backtrace; + #[cfg(feature = "std")] + { + self.backtrace = backtrace; + } #[allow(clippy::unwrap_used)] let dummy_id = std::num::NonZeroU64::new(1).unwrap(); @@ -91,6 +98,7 @@ impl SubAllocator for DedicatedBlockAllocator { let empty = "".to_string(); let name = self.name.as_ref().unwrap_or(&empty); + #[cfg(feature = "std")] log!( log_level, r#"leak detected: {{ @@ -107,7 +115,23 @@ impl SubAllocator for DedicatedBlockAllocator { self.size, name, self.backtrace - ) + ); + #[cfg(not(feature = "std"))] + log!( + log_level, + r#"leak detected: {{ + memory type: {} + memory block: {} + dedicated allocation: {{ + size: 0x{:x}, + name: {}, + }} +}}"#, + memory_type_index, + memory_block_index, + self.size, + name, + ); } fn report_allocations(&self) -> Vec { diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index d7cde2e8..df1e756c 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -3,6 +3,7 @@ #[cfg(feature = "visualizer")] pub(crate) mod visualizer; +#[cfg(feature = "std")] use std::{ backtrace::Backtrace, collections::{HashMap, HashSet}, @@ -32,6 +33,7 @@ pub(crate) struct MemoryChunk { pub(crate) allocation_type: AllocationType, pub(crate) name: Option, /// Only used if [`crate::AllocatorDebugSettings::store_stack_traces`] is [`true`] + #[cfg(feature = "std")] pub(crate) backtrace: Arc, next: Option, prev: Option, @@ -79,6 +81,7 @@ impl FreeListAllocator { offset: 0, allocation_type: AllocationType::Free, name: None, + #[cfg(feature = "std")] backtrace: Arc::new(Backtrace::disabled()), prev: None, next: None, @@ -162,8 +165,8 @@ impl SubAllocator for FreeListAllocator { allocation_type: AllocationType, granularity: u64, name: &str, - backtrace: Arc, - ) -> Result<(u64, std::num::NonZeroU64)> { + #[cfg(feature = "std")] backtrace: Arc, + ) -> Result<(u64, core::num::NonZeroU64)> { let free_size = self.size - self.allocated; if size > free_size { return Err(AllocationError::OutOfMemory); @@ -249,6 +252,7 @@ impl SubAllocator for FreeListAllocator { offset: free_chunk.offset, allocation_type, name: Some(name.to_string()), + #[cfg(feature = "std")] backtrace, prev: free_chunk.prev, next: Some(first_fit_id), @@ -278,7 +282,10 @@ impl SubAllocator for FreeListAllocator { chunk.allocation_type = allocation_type; chunk.name = Some(name.to_string()); - chunk.backtrace = backtrace; + #[cfg(feature = "std")] + { + chunk.backtrace = backtrace; + } self.remove_id_from_free_list(first_fit_id); @@ -302,7 +309,10 @@ impl SubAllocator for FreeListAllocator { })?; chunk.allocation_type = AllocationType::Free; chunk.name = None; - chunk.backtrace = Arc::new(Backtrace::disabled()); + #[cfg(feature = "std")] + { + chunk.backtrace = Arc::new(Backtrace::disabled()); + } self.allocated -= chunk.size; @@ -363,6 +373,7 @@ impl SubAllocator for FreeListAllocator { let empty = "".to_string(); let name = chunk.name.as_ref().unwrap_or(&empty); + #[cfg(feature = "std")] log!( log_level, r#"leak detected: {{ @@ -386,6 +397,28 @@ impl SubAllocator for FreeListAllocator { name, chunk.backtrace ); + #[cfg(not(feature = "std"))] + log!( + log_level, + r#"leak detected: {{ + memory type: {} + memory block: {} + chunk: {{ + chunk_id: {}, + size: 0x{:x}, + offset: 0x{:x}, + allocation_type: {:?}, + name: {}, + }} +}}"#, + memory_type_index, + memory_block_index, + chunk_id, + chunk.size, + chunk.offset, + chunk.allocation_type, + name, + ); } } diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs index 5d40bbf6..f2aa2e53 100644 --- a/src/allocator/mod.rs +++ b/src/allocator/mod.rs @@ -1,6 +1,8 @@ use std::{backtrace::Backtrace, fmt, ops::Range, sync::Arc}; use log::*; +#[cfg(feature = "std")] +use std::{backtrace::Backtrace, sync::Arc}; use crate::result::*; @@ -113,8 +115,8 @@ pub(crate) trait SubAllocator: SubAllocatorBase + fmt::Debug + Sync + Send { allocation_type: AllocationType, granularity: u64, name: &str, - backtrace: Arc, - ) -> Result<(u64, std::num::NonZeroU64)>; + #[cfg(feature = "std")] backtrace: Arc, + ) -> Result<(u64, core::num::NonZeroU64)>; fn free(&mut self, chunk_id: Option) -> Result<()>; diff --git a/src/d3d12/mod.rs b/src/d3d12/mod.rs index 0bb23220..3d8a6900 100644 --- a/src/d3d12/mod.rs +++ b/src/d3d12/mod.rs @@ -1,12 +1,14 @@ -use std::{ - backtrace::Backtrace, +#[cfg(feature = "std")] +use std::{backtrace::Backtrace, sync::Arc}; + +use alloc::{boxed::Box, string::String, vec::Vec}; +use core::{ fmt, // TODO: Remove when bumping MSRV to 1.80 mem::size_of_val, - sync::Arc, }; - use log::{debug, warn, Level}; + use windows::Win32::{ Foundation::E_OUTOFMEMORY, Graphics::{ @@ -442,7 +444,7 @@ impl MemoryType { &mut self, device: &ID3D12DeviceVersion, desc: &AllocationCreateDesc<'_>, - backtrace: Arc, + #[cfg(feature = "std")] backtrace: Arc, allocation_sizes: &AllocationSizes, ) -> Result { let allocation_type = AllocationType::Linear; @@ -485,6 +487,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace, )?; @@ -508,6 +511,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace.clone(), ); @@ -558,6 +562,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace, ); let (offset, chunk_id) = match allocation { @@ -735,6 +740,7 @@ impl Allocator { let size = desc.size; let alignment = desc.alignment; + #[cfg(feature = "std")] let backtrace = Arc::new(if self.debug_settings.store_stack_traces { Backtrace::force_capture() } else { @@ -746,6 +752,7 @@ impl Allocator { "Allocating `{}` of {} bytes with an alignment of {}.", &desc.name, size, alignment ); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); debug!("Allocation stack trace: {}", backtrace); @@ -771,13 +778,20 @@ impl Allocator { }) .ok_or(AllocationError::NoCompatibleMemoryTypeFound)?; - memory_type.allocate(&self.device, desc, backtrace, &self.allocation_sizes) + memory_type.allocate( + &self.device, + desc, + #[cfg(feature = "std")] + backtrace, + &self.allocation_sizes, + ) } pub fn free(&mut self, allocation: Allocation) -> Result<()> { if self.debug_settings.log_frees { let name = allocation.name.as_deref().unwrap_or(""); debug!("Freeing `{}`.", name); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); debug!("Free stack trace: {}", backtrace); diff --git a/src/lib.rs b/src/lib.rs index 759aefb6..50d95a89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -264,12 +264,14 @@ pub struct AllocatorDebugSettings { /// Stores a copy of the full backtrace for every allocation made, this makes it easier to debug leaks /// or other memory allocations, but storing stack traces has a RAM overhead so should be disabled /// in shipping applications. + #[cfg(feature = "std")] pub store_stack_traces: bool, /// Log out every allocation as it's being made with log level Debug, rather spammy so off by default pub log_allocations: bool, /// Log out every free that is being called with log level Debug, rather spammy so off by default pub log_frees: bool, /// Log out stack traces when either `log_allocations` or `log_frees` is enabled. + #[cfg(feature = "std")] pub log_stack_traces: bool, } @@ -278,9 +280,11 @@ impl Default for AllocatorDebugSettings { Self { log_memory_information: false, log_leaks_on_shutdown: true, + #[cfg(feature = "std")] store_stack_traces: false, log_allocations: false, log_frees: false, + #[cfg(feature = "std")] log_stack_traces: false, } } diff --git a/src/metal/mod.rs b/src/metal/mod.rs index 7819d49d..403f9f27 100644 --- a/src/metal/mod.rs +++ b/src/metal/mod.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "std")] use std::{backtrace::Backtrace, sync::Arc}; #[cfg(feature = "visualizer")] @@ -225,7 +226,7 @@ impl MemoryType { &mut self, device: &ProtocolObject, desc: &AllocationCreateDesc<'_>, - backtrace: Arc, + #[cfg(feature = "std")] backtrace: Arc, allocation_sizes: &AllocationSizes, ) -> Result { let allocation_type = allocator::AllocationType::Linear; @@ -268,6 +269,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace, )?; @@ -291,6 +293,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace.clone(), ); @@ -341,6 +344,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace, ); let (offset, chunk_id) = match allocation { @@ -452,6 +456,7 @@ impl Allocator { let size = desc.size; let alignment = desc.alignment; + #[cfg(feature = "std")] let backtrace = Arc::new(if self.debug_settings.store_stack_traces { Backtrace::force_capture() } else { @@ -463,6 +468,7 @@ impl Allocator { "Allocating `{}` of {} bytes with an alignment of {}.", &desc.name, size, alignment ); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); debug!("Allocation stack trace: {}", backtrace); @@ -484,13 +490,20 @@ impl Allocator { }) .ok_or(AllocationError::NoCompatibleMemoryTypeFound)?; - memory_type.allocate(&self.device, desc, backtrace, &self.allocation_sizes) + memory_type.allocate( + &self.device, + desc, + #[cfg(feature = "std")] + backtrace, + &self.allocation_sizes, + ) } pub fn free(&mut self, allocation: &Allocation) -> Result<()> { if self.debug_settings.log_frees { let name = allocation.name.as_deref().unwrap_or(""); debug!("Freeing `{}`.", name); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); debug!("Free stack trace: {}", backtrace); diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index 15382640..18ca04b8 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -1,9 +1,15 @@ #[cfg(feature = "visualizer")] mod visualizer; -use std::{backtrace::Backtrace, fmt, marker::PhantomData, sync::Arc}; + +#[cfg(feature = "std")] +use std::{backtrace::Backtrace, sync::Arc}; + +use alloc::{borrow::ToOwned, boxed::Box, string::ToString, vec::Vec}; +use core::{fmt, marker::PhantomData}; use ash::vk; use log::{debug, Level}; + #[cfg(feature = "visualizer")] pub use visualizer::AllocatorVisualizer; @@ -456,7 +462,7 @@ impl MemoryType { device: &ash::Device, desc: &AllocationCreateDesc<'_>, granularity: u64, - backtrace: Arc, + #[cfg(feature = "std")] backtrace: Arc, allocation_sizes: &AllocationSizes, ) -> Result { let allocation_type = if desc.linear { @@ -518,6 +524,7 @@ impl MemoryType { allocation_type, granularity, desc.name, + #[cfg(feature = "std")] backtrace, )?; @@ -544,6 +551,7 @@ impl MemoryType { allocation_type, granularity, desc.name, + #[cfg(feature = "std")] backtrace.clone(), ); @@ -608,6 +616,7 @@ impl MemoryType { allocation_type, granularity, desc.name, + #[cfg(feature = "std")] backtrace, ); let (offset, chunk_id) = match allocation { @@ -769,6 +778,7 @@ impl Allocator { let size = desc.requirements.size; let alignment = desc.requirements.alignment; + #[cfg(feature = "std")] let backtrace = Arc::new(if self.debug_settings.store_stack_traces { Backtrace::force_capture() } else { @@ -780,6 +790,7 @@ impl Allocator { "Allocating `{}` of {} bytes with an alignment of {}.", &desc.name, size, alignment ); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); debug!("Allocation stack trace: {}", backtrace); @@ -834,6 +845,7 @@ impl Allocator { &self.device, desc, self.buffer_image_granularity, + #[cfg(feature = "std")] backtrace.clone(), &self.allocation_sizes, ) @@ -856,6 +868,7 @@ impl Allocator { &self.device, desc, self.buffer_image_granularity, + #[cfg(feature = "std")] backtrace, &self.allocation_sizes, ) @@ -871,6 +884,7 @@ impl Allocator { if self.debug_settings.log_frees { let name = allocation.name.as_deref().unwrap_or(""); debug!("Freeing `{}`.", name); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); debug!("Free stack trace: {}", backtrace); From eb9e04c5473c5fc24bc0d8613fd02738dc63ad9f Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 12 Feb 2025 16:20:03 +0800 Subject: [PATCH 04/32] replace `std::*` with `core::*` or `alloc::*` --- .../dedicated_block_allocator/mod.rs | 17 +++++---- src/allocator/free_list_allocator/mod.rs | 37 ++++++++++++------- src/allocator/mod.rs | 12 +++--- src/d3d12/mod.rs | 30 +++++++-------- src/metal/mod.rs | 4 +- src/result.rs | 3 +- src/vulkan/mod.rs | 18 ++++----- 7 files changed, 68 insertions(+), 53 deletions(-) diff --git a/src/allocator/dedicated_block_allocator/mod.rs b/src/allocator/dedicated_block_allocator/mod.rs index 77b7bec4..7bfccc56 100644 --- a/src/allocator/dedicated_block_allocator/mod.rs +++ b/src/allocator/dedicated_block_allocator/mod.rs @@ -4,8 +4,11 @@ use std::{backtrace::Backtrace, sync::Arc}; #[cfg(feature = "visualizer")] pub(crate) mod visualizer; - -use std::{backtrace::Backtrace, sync::Arc}; +use alloc::{ + borrow::ToOwned, + string::{String, ToString}, + vec::Vec, +}; use log::{log, Level}; @@ -63,12 +66,12 @@ impl SubAllocator for DedicatedBlockAllocator { } #[allow(clippy::unwrap_used)] - let dummy_id = std::num::NonZeroU64::new(1).unwrap(); + let dummy_id = core::num::NonZeroU64::new(1).unwrap(); Ok((0, dummy_id)) } - fn free(&mut self, chunk_id: Option) -> Result<()> { - if chunk_id != std::num::NonZeroU64::new(1) { + fn free(&mut self, chunk_id: Option) -> Result<()> { + if chunk_id != core::num::NonZeroU64::new(1) { Err(AllocationError::Internal("Chunk ID must be 1.".into())) } else { self.allocated = 0; @@ -78,10 +81,10 @@ impl SubAllocator for DedicatedBlockAllocator { fn rename_allocation( &mut self, - chunk_id: Option, + chunk_id: Option, name: &str, ) -> Result<()> { - if chunk_id != std::num::NonZeroU64::new(1) { + if chunk_id != core::num::NonZeroU64::new(1) { Err(AllocationError::Internal("Chunk ID must be 1.".into())) } else { self.name = Some(name.into()); diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index df1e756c..a0b6d377 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -10,6 +10,15 @@ use std::{ sync::Arc, }; +use alloc::{ + borrow::ToOwned, + string::{String, ToString}, + vec::Vec, +}; + +#[cfg(feature = "hashbrown")] +use hashbrown::{HashMap, HashSet}; + use log::{log, Level}; use super::{AllocationReport, AllocationType, SubAllocator, SubAllocatorBase}; @@ -27,7 +36,7 @@ fn align_up(val: u64, alignment: u64) -> u64 { #[derive(Debug)] pub(crate) struct MemoryChunk { - pub(crate) chunk_id: std::num::NonZeroU64, + pub(crate) chunk_id: core::num::NonZeroU64, pub(crate) size: u64, pub(crate) offset: u64, pub(crate) allocation_type: AllocationType, @@ -35,8 +44,8 @@ pub(crate) struct MemoryChunk { /// Only used if [`crate::AllocatorDebugSettings::store_stack_traces`] is [`true`] #[cfg(feature = "std")] pub(crate) backtrace: Arc, - next: Option, - prev: Option, + next: Option, + prev: Option, } #[derive(Debug)] @@ -44,8 +53,8 @@ pub(crate) struct FreeListAllocator { size: u64, allocated: u64, pub(crate) chunk_id_counter: u64, - pub(crate) chunks: HashMap, - free_chunks: HashSet, + pub(crate) chunks: HashMap, + free_chunks: HashSet, } /// Test if two suballocations will overlap the same page. @@ -70,7 +79,7 @@ fn has_granularity_conflict(type0: AllocationType, type1: AllocationType) -> boo impl FreeListAllocator { pub(crate) fn new(size: u64) -> Self { #[allow(clippy::unwrap_used)] - let initial_chunk_id = std::num::NonZeroU64::new(1).unwrap(); + let initial_chunk_id = core::num::NonZeroU64::new(1).unwrap(); let mut chunks = HashMap::default(); chunks.insert( @@ -103,7 +112,7 @@ impl FreeListAllocator { } /// Generates a new unique chunk ID - fn get_new_chunk_id(&mut self) -> Result { + fn get_new_chunk_id(&mut self) -> Result { if self.chunk_id_counter == u64::MAX { // End of chunk id counter reached, no more allocations are possible. return Err(AllocationError::OutOfMemory); @@ -111,19 +120,19 @@ impl FreeListAllocator { let id = self.chunk_id_counter; self.chunk_id_counter += 1; - std::num::NonZeroU64::new(id).ok_or_else(|| { + core::num::NonZeroU64::new(id).ok_or_else(|| { AllocationError::Internal("New chunk id was 0, which is not allowed.".into()) }) } /// Finds the specified `chunk_id` in the list of free chunks and removes if from the list - fn remove_id_from_free_list(&mut self, chunk_id: std::num::NonZeroU64) { + fn remove_id_from_free_list(&mut self, chunk_id: core::num::NonZeroU64) { self.free_chunks.remove(&chunk_id); } /// Merges two adjacent chunks. Right chunk will be merged into the left chunk fn merge_free_chunks( &mut self, - chunk_left: std::num::NonZeroU64, - chunk_right: std::num::NonZeroU64, + chunk_left: core::num::NonZeroU64, + chunk_right: core::num::NonZeroU64, ) -> Result<()> { // Gather data from right chunk and remove it let (right_size, right_next) = { @@ -172,7 +181,7 @@ impl SubAllocator for FreeListAllocator { return Err(AllocationError::OutOfMemory); } - let mut best_fit_id: Option = None; + let mut best_fit_id: Option = None; let mut best_offset = 0u64; let mut best_aligned_size = 0u64; let mut best_chunk_size = 0u64; @@ -297,7 +306,7 @@ impl SubAllocator for FreeListAllocator { Ok((best_offset, chunk_id)) } - fn free(&mut self, chunk_id: Option) -> Result<()> { + fn free(&mut self, chunk_id: Option) -> Result<()> { let chunk_id = chunk_id .ok_or_else(|| AllocationError::Internal("Chunk ID must be a valid value.".into()))?; @@ -337,7 +346,7 @@ impl SubAllocator for FreeListAllocator { fn rename_allocation( &mut self, - chunk_id: Option, + chunk_id: Option, name: &str, ) -> Result<()> { let chunk_id = chunk_id diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs index f2aa2e53..0e21a6d7 100644 --- a/src/allocator/mod.rs +++ b/src/allocator/mod.rs @@ -1,5 +1,5 @@ -use std::{backtrace::Backtrace, fmt, ops::Range, sync::Arc}; - +use alloc::{fmt, string::String, vec::Vec}; +use core::ops::Range; use log::*; #[cfg(feature = "std")] use std::{backtrace::Backtrace, sync::Arc}; @@ -81,7 +81,7 @@ impl fmt::Debug for AllocationReport { impl fmt::Debug for AllocatorReport { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut allocations = self.allocations.clone(); - allocations.sort_by_key(|alloc| std::cmp::Reverse(alloc.size)); + allocations.sort_by_key(|alloc| core::cmp::Reverse(alloc.size)); let max_num_allocations_to_print = f.precision().unwrap_or(usize::MAX); allocations.truncate(max_num_allocations_to_print); @@ -89,7 +89,7 @@ impl fmt::Debug for AllocatorReport { f.debug_struct("AllocatorReport") .field( "summary", - &std::format_args!( + &core::format_args!( "{} / {}", fmt_bytes(self.total_allocated_bytes), fmt_bytes(self.total_reserved_bytes) @@ -118,11 +118,11 @@ pub(crate) trait SubAllocator: SubAllocatorBase + fmt::Debug + Sync + Send { #[cfg(feature = "std")] backtrace: Arc, ) -> Result<(u64, core::num::NonZeroU64)>; - fn free(&mut self, chunk_id: Option) -> Result<()>; + fn free(&mut self, chunk_id: Option) -> Result<()>; fn rename_allocation( &mut self, - chunk_id: Option, + chunk_id: Option, name: &str, ) -> Result<()>; diff --git a/src/d3d12/mod.rs b/src/d3d12/mod.rs index 3d8a6900..bfde4eff 100644 --- a/src/d3d12/mod.rs +++ b/src/d3d12/mod.rs @@ -38,49 +38,49 @@ mod public_winapi { impl ToWinapi for ID3D12Resource { fn as_winapi(&self) -> *const winapi_d3d12::ID3D12Resource { - unsafe { std::mem::transmute_copy(self) } + unsafe { core::mem::transmute_copy(self) } } fn as_winapi_mut(&mut self) -> *mut winapi_d3d12::ID3D12Resource { - unsafe { std::mem::transmute_copy(self) } + unsafe { core::mem::transmute_copy(self) } } } impl ToWinapi for ID3D12Device { fn as_winapi(&self) -> *const winapi_d3d12::ID3D12Device { - unsafe { std::mem::transmute_copy(self) } + unsafe { core::mem::transmute_copy(self) } } fn as_winapi_mut(&mut self) -> *mut winapi_d3d12::ID3D12Device { - unsafe { std::mem::transmute_copy(self) } + unsafe { core::mem::transmute_copy(self) } } } impl ToWindows for *const winapi_d3d12::ID3D12Device { fn as_windows(&self) -> &ID3D12Device { - unsafe { std::mem::transmute(self) } + unsafe { core::mem::transmute(self) } } } impl ToWindows for *mut winapi_d3d12::ID3D12Device { fn as_windows(&self) -> &ID3D12Device { - unsafe { std::mem::transmute(self) } + unsafe { core::mem::transmute(self) } } } impl ToWindows for &mut winapi_d3d12::ID3D12Device { fn as_windows(&self) -> &ID3D12Device { - unsafe { std::mem::transmute(self) } + unsafe { core::mem::transmute(self) } } } impl ToWinapi for ID3D12Heap { fn as_winapi(&self) -> *const winapi_d3d12::ID3D12Heap { - unsafe { std::mem::transmute_copy(self) } + unsafe { core::mem::transmute_copy(self) } } fn as_winapi_mut(&mut self) -> *mut winapi_d3d12::ID3D12Heap { - unsafe { std::mem::transmute_copy(self) } + unsafe { core::mem::transmute_copy(self) } } } } @@ -208,10 +208,10 @@ impl<'a> AllocationCreateDesc<'a> { let device = device.as_windows(); // Raw structs are binary-compatible let desc = unsafe { - std::mem::transmute::<&winapi_d3d12::D3D12_RESOURCE_DESC, &D3D12_RESOURCE_DESC>(desc) + core::mem::transmute::<&winapi_d3d12::D3D12_RESOURCE_DESC, &D3D12_RESOURCE_DESC>(desc) }; let allocation_info = - unsafe { device.GetResourceAllocationInfo(0, std::slice::from_ref(desc)) }; + unsafe { device.GetResourceAllocationInfo(0, core::slice::from_ref(desc)) }; let resource_category: ResourceCategory = desc.into(); AllocationCreateDesc { @@ -234,7 +234,7 @@ impl<'a> AllocationCreateDesc<'a> { location: MemoryLocation, ) -> Self { let allocation_info = - unsafe { device.GetResourceAllocationInfo(0, std::slice::from_ref(desc)) }; + unsafe { device.GetResourceAllocationInfo(0, core::slice::from_ref(desc)) }; let resource_category: ResourceCategory = desc.into(); AllocationCreateDesc { @@ -259,7 +259,7 @@ pub enum ID3D12DeviceVersion { Device12(ID3D12Device12), } -impl std::ops::Deref for ID3D12DeviceVersion { +impl core::ops::Deref for ID3D12DeviceVersion { type Target = ID3D12Device; fn deref(&self) -> &Self::Target { @@ -324,7 +324,7 @@ pub struct CommittedAllocationStatistics { #[derive(Debug)] pub struct Allocation { - chunk_id: Option, + chunk_id: Option, offset: u64, size: u64, memory_block_index: usize, @@ -335,7 +335,7 @@ pub struct Allocation { } impl Allocation { - pub fn chunk_id(&self) -> Option { + pub fn chunk_id(&self) -> Option { self.chunk_id } diff --git a/src/metal/mod.rs b/src/metal/mod.rs index 403f9f27..80ea4028 100644 --- a/src/metal/mod.rs +++ b/src/metal/mod.rs @@ -1,6 +1,8 @@ #[cfg(feature = "std")] use std::{backtrace::Backtrace, sync::Arc}; +use alloc::{boxed::Box, string::ToString, vec::Vec}; + #[cfg(feature = "visualizer")] mod visualizer; #[cfg(feature = "visualizer")] @@ -30,7 +32,7 @@ fn memory_location_to_metal(location: MemoryLocation) -> MTLResourceOptions { #[derive(Debug)] pub struct Allocation { - chunk_id: Option, + chunk_id: Option, offset: u64, size: u64, memory_block_index: usize, diff --git a/src/result.rs b/src/result.rs index 8ccb98a7..d2c5a520 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,3 +1,4 @@ +use alloc::string::String; use thiserror::Error; #[derive(Error, Debug)] @@ -22,4 +23,4 @@ pub enum AllocationError { CastableFormatsRequiresAtLeastDevice12, } -pub type Result = ::std::result::Result; +pub type Result = ::core::result::Result; diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index 18ca04b8..6e6c6a3d 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -49,7 +49,7 @@ pub struct AllocationCreateDesc<'a> { /// mark the entire [`Allocation`] as such, instead relying on the compiler to /// auto-implement this or fail if fields are added that violate this constraint #[derive(Clone, Copy, Debug)] -pub(crate) struct SendSyncPtr(std::ptr::NonNull); +pub(crate) struct SendSyncPtr(core::ptr::NonNull); // Sending is fine because mapped_ptr does not change based on the thread we are in unsafe impl Send for SendSyncPtr {} // Sync is also okay because Sending &Allocation is safe: a mutable reference @@ -153,7 +153,7 @@ pub struct AllocatorCreateDesc { /// [\[1\]]: presser#motivation #[derive(Debug)] pub struct Allocation { - chunk_id: Option, + chunk_id: Option, offset: u64, size: u64, memory_block_index: usize, @@ -202,7 +202,7 @@ impl Allocation { }) } - pub fn chunk_id(&self) -> Option { + pub fn chunk_id(&self) -> Option { self.chunk_id } @@ -245,7 +245,7 @@ impl Allocation { /// Returns a valid mapped pointer if the memory is host visible, otherwise it will return None. /// The pointer already points to the exact memory region of the suballocation, so no offset needs to be applied. - pub fn mapped_ptr(&self) -> Option> { + pub fn mapped_ptr(&self) -> Option> { self.mapped_ptr.map(|SendSyncPtr(p)| p) } @@ -253,7 +253,7 @@ impl Allocation { /// The slice already references the exact memory region of the allocation, so no offset needs to be applied. pub fn mapped_slice(&self) -> Option<&[u8]> { self.mapped_ptr().map(|ptr| unsafe { - std::slice::from_raw_parts(ptr.cast().as_ptr(), self.size as usize) + core::slice::from_raw_parts(ptr.cast().as_ptr(), self.size as usize) }) } @@ -261,7 +261,7 @@ impl Allocation { /// The slice already references the exact memory region of the allocation, so no offset needs to be applied. pub fn mapped_slice_mut(&mut self) -> Option<&mut [u8]> { self.mapped_ptr().map(|ptr| unsafe { - std::slice::from_raw_parts_mut(ptr.cast().as_ptr(), self.size as usize) + core::slice::from_raw_parts_mut(ptr.cast().as_ptr(), self.size as usize) }) } @@ -410,7 +410,7 @@ impl MemoryBlock { AllocationError::FailedToMap(e.to_string()) }) .and_then(|p| { - std::ptr::NonNull::new(p).map(SendSyncPtr).ok_or_else(|| { + core::ptr::NonNull::new(p).map(SendSyncPtr).ok_or_else(|| { AllocationError::FailedToMap("Returned mapped pointer is null".to_owned()) }) }) @@ -560,7 +560,7 @@ impl MemoryType { let mapped_ptr = if let Some(SendSyncPtr(mapped_ptr)) = mem_block.mapped_ptr { let offset_ptr = unsafe { mapped_ptr.as_ptr().add(offset as usize) }; - std::ptr::NonNull::new(offset_ptr).map(SendSyncPtr) + core::ptr::NonNull::new(offset_ptr).map(SendSyncPtr) } else { None }; @@ -634,7 +634,7 @@ impl MemoryType { let mapped_ptr = if let Some(SendSyncPtr(mapped_ptr)) = mem_block.mapped_ptr { let offset_ptr = unsafe { mapped_ptr.as_ptr().add(offset as usize) }; - std::ptr::NonNull::new(offset_ptr).map(SendSyncPtr) + core::ptr::NonNull::new(offset_ptr).map(SendSyncPtr) } else { None }; From 48be63c8ca0a4feeb0c9885d3c604830a07e41cd Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 13 Feb 2025 09:35:20 +0800 Subject: [PATCH 05/32] add clippy lints for `no_std` maintenance --- src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 50d95a89..07c1385f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -212,6 +212,11 @@ //! # fn main() {} //! ``` #![deny(clippy::unimplemented, clippy::unwrap_used, clippy::ok_expect)] +#![warn( + clippy::alloc_instead_of_core, + clippy::std_instead_of_alloc, + clippy::std_instead_of_core +)] #![cfg_attr(not(feature = "std"), no_std)] #[macro_use] From 4d7b66805c4ab071303ca2e829701c425aa44a3c Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 13 Feb 2025 09:43:01 +0800 Subject: [PATCH 06/32] revert formatting of `Cargo.toml` --- Cargo.toml | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 058d6893..a50ed13f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,12 @@ keywords = ["vulkan", "memory", "allocator"] documentation = "https://docs.rs/gpu-allocator/" rust-version = "1.71" -include = ["/README.md", "/LICENSE-*", "/src", "/examples"] +include = [ + "/README.md", + "/LICENSE-*", + "/src", + "/examples" +] [package.metadata.docs.rs] all-features = true @@ -23,9 +28,7 @@ thiserror = { version = "2.0", default-feature = false } presser = { version = "0.3", default-feature = false } # Only needed for Vulkan. Disable all default features as good practice, # such as the ability to link/load a Vulkan library. -ash = { version = "0.38", optional = true, default-features = false, features = [ - "debug", -] } +ash = { version = "0.38", optional = true, default-features = false, features = ["debug"] } # Only needed for visualizer. egui = { version = ">=0.24, <=0.27", optional = true, default-features = false } egui_extras = { version = ">=0.24, <=0.27", optional = true, default-features = false } @@ -47,38 +50,23 @@ objc2-metal = { version = "0.3", default-features = false, features = [ [target.'cfg(windows)'.dependencies] # Only needed for public-winapi interop helpers -winapi = { version = "0.3.9", features = [ - "d3d12", - "winerror", - "impl-default", - "impl-debug", -], optional = true } +winapi = { version = "0.3.9", features = ["d3d12", "winerror", "impl-default", "impl-debug"], optional = true } [target.'cfg(windows)'.dependencies.windows] version = ">=0.53,<=0.59" -features = ["Win32_Graphics_Direct3D12", "Win32_Graphics_Dxgi_Common"] +features = [ + "Win32_Graphics_Direct3D12", + "Win32_Graphics_Dxgi_Common", +] optional = true [dev-dependencies] # Enable the "loaded" feature to be able to access the Vulkan entrypoint. -ash = { version = "0.38", default-features = false, features = [ - "debug", - "loaded", -] } +ash = { version = "0.38", default-features = false, features = ["debug", "loaded"] } env_logger = "0.10" [target.'cfg(windows)'.dev-dependencies] -winapi = { version = "0.3.9", features = [ - "d3d12", - "d3d12sdklayers", - "dxgi1_6", - "winerror", - "impl-default", - "impl-debug", - "winuser", - "windowsx", - "libloaderapi", -] } +winapi = { version = "0.3.9", features = ["d3d12", "d3d12sdklayers", "dxgi1_6", "winerror", "impl-default", "impl-debug", "winuser", "windowsx", "libloaderapi"] } [target.'cfg(windows)'.dev-dependencies.windows] # API-breaks since Windows 0.58 only affect our examples From 3cee15fa3962acb573bf60919ef37c6fb4c54e2a Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 13 Feb 2025 09:43:13 +0800 Subject: [PATCH 07/32] fix typos in deps --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a50ed13f..cec555e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,9 @@ include = [ all-features = true [dependencies] -log = { version = "0.4", default-feature = false } -thiserror = { version = "2.0", default-feature = false } -presser = { version = "0.3", default-feature = false } +log = { version = "0.4", default-features = false } +thiserror = { version = "2.0", default-features = false } +presser = { version = "0.3", default-features = false } # Only needed for Vulkan. Disable all default features as good practice, # such as the ability to link/load a Vulkan library. ash = { version = "0.38", optional = true, default-features = false, features = ["debug"] } From 51e8723dca8401f1e3dfd6eecdb377a05b705b6c Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 13 Feb 2025 09:46:52 +0800 Subject: [PATCH 08/32] add non_exhaustive for `AllocatorDebugSettings` for backward compatible --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 07c1385f..f99da251 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -260,6 +260,7 @@ pub enum MemoryLocation { GpuToCpu, } +#[non_exhaustive] #[derive(Copy, Clone, Debug)] pub struct AllocatorDebugSettings { /// Logs out debugging information about the various heaps the current device has on startup From a4d3463a66cd93d642b10e5ab2c013951e864a02 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 13 Feb 2025 09:54:11 +0800 Subject: [PATCH 09/32] reorder imports and mods --- src/allocator/free_list_allocator/mod.rs | 14 +++++--------- src/allocator/mod.rs | 3 ++- src/d3d12/mod.rs | 7 +++---- src/metal/mod.rs | 13 ++++++------- src/result.rs | 1 + src/vulkan/mod.rs | 10 ++++------ 6 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index a0b6d377..262e9ffa 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -3,22 +3,18 @@ #[cfg(feature = "visualizer")] pub(crate) mod visualizer; -#[cfg(feature = "std")] -use std::{ - backtrace::Backtrace, - collections::{HashMap, HashSet}, - sync::Arc, -}; - use alloc::{ borrow::ToOwned, string::{String, ToString}, vec::Vec, }; +#[cfg(all(feature = "std", not(feature = "hashbrown")))] +use std::collections::{HashMap, HashSet}; +#[cfg(feature = "std")] +use std::{backtrace::Backtrace, sync::Arc}; -#[cfg(feature = "hashbrown")] +#[cfg(all(not(feature = "std"), feature = "hashbrown"))] use hashbrown::{HashMap, HashSet}; - use log::{log, Level}; use super::{AllocationReport, AllocationType, SubAllocator, SubAllocatorBase}; diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs index 0e21a6d7..9a3cf463 100644 --- a/src/allocator/mod.rs +++ b/src/allocator/mod.rs @@ -1,9 +1,10 @@ use alloc::{fmt, string::String, vec::Vec}; use core::ops::Range; -use log::*; #[cfg(feature = "std")] use std::{backtrace::Backtrace, sync::Arc}; +use log::*; + use crate::result::*; pub(crate) mod dedicated_block_allocator; diff --git a/src/d3d12/mod.rs b/src/d3d12/mod.rs index bfde4eff..6dadca45 100644 --- a/src/d3d12/mod.rs +++ b/src/d3d12/mod.rs @@ -1,14 +1,13 @@ -#[cfg(feature = "std")] -use std::{backtrace::Backtrace, sync::Arc}; - use alloc::{boxed::Box, string::String, vec::Vec}; use core::{ fmt, // TODO: Remove when bumping MSRV to 1.80 mem::size_of_val, }; -use log::{debug, warn, Level}; +#[cfg(feature = "std")] +use std::{backtrace::Backtrace, sync::Arc}; +use log::{debug, warn, Level}; use windows::Win32::{ Foundation::E_OUTOFMEMORY, Graphics::{ diff --git a/src/metal/mod.rs b/src/metal/mod.rs index 80ea4028..6adebdfa 100644 --- a/src/metal/mod.rs +++ b/src/metal/mod.rs @@ -1,13 +1,7 @@ +use alloc::{boxed::Box, string::ToString, vec::Vec}; #[cfg(feature = "std")] use std::{backtrace::Backtrace, sync::Arc}; -use alloc::{boxed::Box, string::ToString, vec::Vec}; - -#[cfg(feature = "visualizer")] -mod visualizer; -#[cfg(feature = "visualizer")] -pub use visualizer::AllocatorVisualizer; - use log::debug; use objc2::{rc::Retained, runtime::ProtocolObject}; use objc2_foundation::NSString; @@ -16,6 +10,11 @@ use objc2_metal::{ MTLStorageMode, MTLTextureDescriptor, }; +#[cfg(feature = "visualizer")] +mod visualizer; +#[cfg(feature = "visualizer")] +pub use visualizer::AllocatorVisualizer; + use crate::{ allocator::{self, AllocatorReport, MemoryBlockReport}, AllocationError, AllocationSizes, AllocatorDebugSettings, MemoryLocation, Result, diff --git a/src/result.rs b/src/result.rs index d2c5a520..50bfff33 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,4 +1,5 @@ use alloc::string::String; + use thiserror::Error; #[derive(Error, Debug)] diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index 6e6c6a3d..fbe967e0 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -1,15 +1,13 @@ -#[cfg(feature = "visualizer")] -mod visualizer; - -#[cfg(feature = "std")] -use std::{backtrace::Backtrace, sync::Arc}; - use alloc::{borrow::ToOwned, boxed::Box, string::ToString, vec::Vec}; use core::{fmt, marker::PhantomData}; +#[cfg(feature = "std")] +use std::{backtrace::Backtrace, sync::Arc}; use ash::vk; use log::{debug, Level}; +#[cfg(feature = "visualizer")] +mod visualizer; #[cfg(feature = "visualizer")] pub use visualizer::AllocatorVisualizer; From d1caf98f7185aa83b3449479851c899451ac3bf7 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 13 Feb 2025 10:17:14 +0800 Subject: [PATCH 10/32] format backtrace ahead by feature instead of duplicated log statements --- .../dedicated_block_allocator/mod.rs | 31 ++++++--------- src/allocator/free_list_allocator/mod.rs | 39 ++++++------------- 2 files changed, 22 insertions(+), 48 deletions(-) diff --git a/src/allocator/dedicated_block_allocator/mod.rs b/src/allocator/dedicated_block_allocator/mod.rs index 7bfccc56..986a1d0c 100644 --- a/src/allocator/dedicated_block_allocator/mod.rs +++ b/src/allocator/dedicated_block_allocator/mod.rs @@ -101,25 +101,17 @@ impl SubAllocator for DedicatedBlockAllocator { let empty = "".to_string(); let name = self.name.as_ref().unwrap_or(&empty); - #[cfg(feature = "std")] - log!( - log_level, - r#"leak detected: {{ - memory type: {} - memory block: {} - dedicated allocation: {{ - size: 0x{:x}, - name: {}, + let backtrace_info = if cfg!(feature = "std") { + format!( + r#" backtrace: {} - }} -}}"#, - memory_type_index, - memory_block_index, - self.size, - name, - self.backtrace - ); - #[cfg(not(feature = "std"))] + "#, + self.backtrace + ) + } else { + "".to_owned() + }; + log!( log_level, r#"leak detected: {{ @@ -127,8 +119,7 @@ impl SubAllocator for DedicatedBlockAllocator { memory block: {} dedicated allocation: {{ size: 0x{:x}, - name: {}, - }} + name: {},{backtrace_info}}} }}"#, memory_type_index, memory_block_index, diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index 262e9ffa..01c33b6e 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -377,32 +377,16 @@ impl SubAllocator for FreeListAllocator { } let empty = "".to_string(); let name = chunk.name.as_ref().unwrap_or(&empty); - - #[cfg(feature = "std")] - log!( - log_level, - r#"leak detected: {{ - memory type: {} - memory block: {} - chunk: {{ - chunk_id: {}, - size: 0x{:x}, - offset: 0x{:x}, - allocation_type: {:?}, - name: {}, - backtrace: {} - }} -}}"#, - memory_type_index, - memory_block_index, - chunk_id, - chunk.size, - chunk.offset, - chunk.allocation_type, - name, - chunk.backtrace - ); - #[cfg(not(feature = "std"))] + let backtrace_info = if cfg!(feature = "std") { + format!( + r#" + backtrace: {} + "#, + chunk.backtrace + ) + } else { + "".to_owned() + }; log!( log_level, r#"leak detected: {{ @@ -413,8 +397,7 @@ impl SubAllocator for FreeListAllocator { size: 0x{:x}, offset: 0x{:x}, allocation_type: {:?}, - name: {}, - }} + name: {},{backtrace_info}}} }}"#, memory_type_index, memory_block_index, From 4c45a0196a978d4d109b519272cfae6f25f980cf Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 13 Feb 2025 10:27:19 +0800 Subject: [PATCH 11/32] reorder mod in allocator module --- src/allocator/dedicated_block_allocator/mod.rs | 5 +++-- src/allocator/free_list_allocator/mod.rs | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/allocator/dedicated_block_allocator/mod.rs b/src/allocator/dedicated_block_allocator/mod.rs index 986a1d0c..44a810ab 100644 --- a/src/allocator/dedicated_block_allocator/mod.rs +++ b/src/allocator/dedicated_block_allocator/mod.rs @@ -2,8 +2,6 @@ #[cfg(feature = "std")] use std::{backtrace::Backtrace, sync::Arc}; -#[cfg(feature = "visualizer")] -pub(crate) mod visualizer; use alloc::{ borrow::ToOwned, string::{String, ToString}, @@ -12,6 +10,9 @@ use alloc::{ use log::{log, Level}; +#[cfg(feature = "visualizer")] +pub(crate) mod visualizer; + use super::{AllocationReport, AllocationType, SubAllocator, SubAllocatorBase}; use crate::{AllocationError, Result}; diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index 01c33b6e..44adcd5f 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -1,8 +1,5 @@ #![deny(unsafe_code, clippy::unwrap_used)] -#[cfg(feature = "visualizer")] -pub(crate) mod visualizer; - use alloc::{ borrow::ToOwned, string::{String, ToString}, @@ -17,6 +14,9 @@ use std::{backtrace::Backtrace, sync::Arc}; use hashbrown::{HashMap, HashSet}; use log::{log, Level}; +#[cfg(feature = "visualizer")] +pub(crate) mod visualizer; + use super::{AllocationReport, AllocationType, SubAllocator, SubAllocatorBase}; use crate::{AllocationError, Result}; From f2a6bfb2935aee04e80cd737eeb0f5366963e2eb Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 13 Feb 2025 10:50:51 +0800 Subject: [PATCH 12/32] make `std` feature conflict with `hashbrown` in compile error and gate `free_list_allocator` by feature --- .../dedicated_block_allocator/mod.rs | 19 ++++++++------ src/allocator/free_list_allocator/mod.rs | 25 ++++++++++++------- src/allocator/mod.rs | 2 ++ src/lib.rs | 4 +-- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/allocator/dedicated_block_allocator/mod.rs b/src/allocator/dedicated_block_allocator/mod.rs index 44a810ab..0ae374a3 100644 --- a/src/allocator/dedicated_block_allocator/mod.rs +++ b/src/allocator/dedicated_block_allocator/mod.rs @@ -101,17 +101,20 @@ impl SubAllocator for DedicatedBlockAllocator { ) { let empty = "".to_string(); let name = self.name.as_ref().unwrap_or(&empty); - - let backtrace_info = if cfg!(feature = "std") { - format!( + let backtrace_info; + #[cfg(feature = "std")] + { + backtrace_info = format!( r#" - backtrace: {} - "#, + backtrace: {} + "#, self.backtrace ) - } else { - "".to_owned() - }; + } + #[cfg(not(feature = "std"))] + { + backtrace_info = "".to_owned() + } log!( log_level, diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index 44adcd5f..39384ea4 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -5,12 +5,15 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; -#[cfg(all(feature = "std", not(feature = "hashbrown")))] -use std::collections::{HashMap, HashSet}; + #[cfg(feature = "std")] -use std::{backtrace::Backtrace, sync::Arc}; +use std::{ + backtrace::Backtrace, + collections::{HashMap, HashSet}, + sync::Arc, +}; -#[cfg(all(not(feature = "std"), feature = "hashbrown"))] +#[cfg(feature = "hashbrown")] use hashbrown::{HashMap, HashSet}; use log::{log, Level}; @@ -377,16 +380,20 @@ impl SubAllocator for FreeListAllocator { } let empty = "".to_string(); let name = chunk.name.as_ref().unwrap_or(&empty); - let backtrace_info = if cfg!(feature = "std") { - format!( + let backtrace_info; + #[cfg(feature = "std")] + { + backtrace_info = format!( r#" backtrace: {} "#, chunk.backtrace ) - } else { - "".to_owned() - }; + } + #[cfg(not(feature = "std"))] + { + backtrace_info = "".to_owned() + } log!( log_level, r#"leak detected: {{ diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs index 9a3cf463..3bc3b337 100644 --- a/src/allocator/mod.rs +++ b/src/allocator/mod.rs @@ -10,7 +10,9 @@ use crate::result::*; pub(crate) mod dedicated_block_allocator; pub(crate) use dedicated_block_allocator::DedicatedBlockAllocator; +#[cfg(any(feature = "std", feature = "hashbrown"))] pub(crate) mod free_list_allocator; +#[cfg(any(feature = "std", feature = "hashbrown"))] pub(crate) use free_list_allocator::FreeListAllocator; #[derive(PartialEq, Copy, Clone, Debug)] diff --git a/src/lib.rs b/src/lib.rs index f99da251..771147ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -222,8 +222,8 @@ #[macro_use] extern crate alloc; -#[cfg(all(not(feature = "std"), not(feature = "hashbrown")))] -compile_error!("\"hashbrown\" feature should be enabled in \"no_std\" environment."); +#[cfg(all(feature = "std", feature = "hashbrown"))] +compile_error!("\"hashbrown\" feature should not be enabled in \"std\" environment."); #[cfg(all(not(feature = "std"), feature = "visualizer"))] compile_error!("Cannot enable \"visualizer\" feature in \"no_std\" environment."); From d59fe2692e0f4f656347656470eb87a41a966582 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 27 Feb 2025 09:09:24 +0800 Subject: [PATCH 13/32] restore trailing comma --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cec555e7..b5fcc6dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ include = [ "/README.md", "/LICENSE-*", "/src", - "/examples" + "/examples", ] [package.metadata.docs.rs] From 3e00364b8ab621ee796470cae9bb46b186371cca Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 27 Feb 2025 09:14:16 +0800 Subject: [PATCH 14/32] remove empty line and reorder import --- src/allocator/dedicated_block_allocator/mod.rs | 5 ++--- src/allocator/free_list_allocator/mod.rs | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/allocator/dedicated_block_allocator/mod.rs b/src/allocator/dedicated_block_allocator/mod.rs index 0ae374a3..d7d8d5c5 100644 --- a/src/allocator/dedicated_block_allocator/mod.rs +++ b/src/allocator/dedicated_block_allocator/mod.rs @@ -1,12 +1,11 @@ #![deny(unsafe_code, clippy::unwrap_used)] -#[cfg(feature = "std")] -use std::{backtrace::Backtrace, sync::Arc}; - use alloc::{ borrow::ToOwned, string::{String, ToString}, vec::Vec, }; +#[cfg(feature = "std")] +use std::{backtrace::Backtrace, sync::Arc}; use log::{log, Level}; diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index 39384ea4..585275c8 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -5,7 +5,6 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; - #[cfg(feature = "std")] use std::{ backtrace::Backtrace, From 457411a2b49b857bd57e9fc5fcd251c11905b97d Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 27 Feb 2025 09:30:58 +0800 Subject: [PATCH 15/32] simplify memory leak logging --- src/allocator/dedicated_block_allocator/mod.rs | 10 +++++----- src/allocator/free_list_allocator/mod.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/allocator/dedicated_block_allocator/mod.rs b/src/allocator/dedicated_block_allocator/mod.rs index d7d8d5c5..955b7b06 100644 --- a/src/allocator/dedicated_block_allocator/mod.rs +++ b/src/allocator/dedicated_block_allocator/mod.rs @@ -104,15 +104,14 @@ impl SubAllocator for DedicatedBlockAllocator { #[cfg(feature = "std")] { backtrace_info = format!( - r#" - backtrace: {} - "#, + ", + backtrace: {}", self.backtrace ) } #[cfg(not(feature = "std"))] { - backtrace_info = "".to_owned() + backtrace_info = "" } log!( @@ -122,7 +121,8 @@ impl SubAllocator for DedicatedBlockAllocator { memory block: {} dedicated allocation: {{ size: 0x{:x}, - name: {},{backtrace_info}}} + name: {}{backtrace_info} + }} }}"#, memory_type_index, memory_block_index, diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index 585275c8..f03439a8 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -383,15 +383,14 @@ impl SubAllocator for FreeListAllocator { #[cfg(feature = "std")] { backtrace_info = format!( - r#" - backtrace: {} - "#, + ", + backtrace: {}", chunk.backtrace ) } #[cfg(not(feature = "std"))] { - backtrace_info = "".to_owned() + backtrace_info = "" } log!( log_level, @@ -403,7 +402,8 @@ impl SubAllocator for FreeListAllocator { size: 0x{:x}, offset: 0x{:x}, allocation_type: {:?}, - name: {},{backtrace_info}}} + name: {}{backtrace_info} + }} }}"#, memory_type_index, memory_block_index, From 578ada0c886489c7053b43c1dd6c03b34bda7d83 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 27 Feb 2025 09:37:05 +0800 Subject: [PATCH 16/32] prefer using `hashbrown`'s collections when `std` and `hashbrown` are both enabled --- src/allocator/free_list_allocator/mod.rs | 8 +++----- src/lib.rs | 3 --- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index f03439a8..8b40734b 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -5,12 +5,10 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; +#[cfg(all(feature = "std", not(feature = "hashbrown")))] +use std::collections::{HashMap, HashSet}; #[cfg(feature = "std")] -use std::{ - backtrace::Backtrace, - collections::{HashMap, HashSet}, - sync::Arc, -}; +use std::{backtrace::Backtrace, sync::Arc}; #[cfg(feature = "hashbrown")] use hashbrown::{HashMap, HashSet}; diff --git a/src/lib.rs b/src/lib.rs index 771147ee..ff3baf68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -222,9 +222,6 @@ #[macro_use] extern crate alloc; -#[cfg(all(feature = "std", feature = "hashbrown"))] -compile_error!("\"hashbrown\" feature should not be enabled in \"std\" environment."); - #[cfg(all(not(feature = "std"), feature = "visualizer"))] compile_error!("Cannot enable \"visualizer\" feature in \"no_std\" environment."); From 39abe5916905bdf9606b0a8cda0a49503065e4cb Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 27 Feb 2025 09:41:57 +0800 Subject: [PATCH 17/32] update `CI` for `std` environment --- .github/workflows/ci.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6058960..8e3fe9bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,11 +9,11 @@ jobs: matrix: include: - os: ubuntu-latest - features: vulkan + features: std,vulkan - os: windows-latest - features: vulkan,d3d12 + features: std,vulkan,d3d12 - os: macos-latest - features: vulkan,metal + features: std,vulkan,metal runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -30,11 +30,11 @@ jobs: matrix: include: - os: ubuntu-latest - features: vulkan,visualizer + features: std,vulkan,visualizer - os: windows-latest - features: vulkan,visualizer,d3d12,public-winapi + features: std,vulkan,visualizer,d3d12,public-winapi - os: macos-latest - features: vulkan,visualizer,metal + features: std,vulkan,visualizer,metal runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -57,11 +57,11 @@ jobs: matrix: include: - os: ubuntu-latest - features: vulkan,visualizer + features: std,vulkan,visualizer - os: windows-latest - features: vulkan,visualizer,d3d12,public-winapi + features: std,vulkan,visualizer,d3d12,public-winapi - os: macos-latest - features: vulkan,visualizer,metal + features: std,vulkan,visualizer,metal runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 From 742a2ce6e19a5caa49000ef9c75773189867c5c5 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Tue, 1 Apr 2025 17:23:55 +0800 Subject: [PATCH 18/32] document the `hashbrown` feature in `Cargo.toml` --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index b5fcc6dd..df2c4ab9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,6 +106,7 @@ d3d12 = ["dep:windows"] metal = ["dep:objc2", "dep:objc2-metal", "dep:objc2-foundation"] # Expose helper functionality for winapi types to interface with gpu-allocator, which is primarily windows-rs driven public-winapi = ["dep:winapi"] +# Enables the FreeListAllocator when `std` is not enabled by using the `hashbrown` crate hashbrown = ["dep:hashbrown"] default = ["std", "d3d12", "vulkan", "metal"] From 694b6ff54c5b6d8e09cd5c2558aa7821d80e6823 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Tue, 1 Apr 2025 17:24:56 +0800 Subject: [PATCH 19/32] update `CI` with `no_std` --- .github/workflows/ci.yml | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e3fe9bc..162056d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,11 +9,23 @@ jobs: matrix: include: - os: ubuntu-latest - features: std,vulkan + features: vulkan,hashbrown + - os: ubuntu-latest + features: vulkan,std + - os: ubuntu-latest + features: vulkan,std,hashbrown + - os: windows-latest + features: d3d12,hashbrown + - os: windows-latest + features: d3d12,std - os: windows-latest - features: std,vulkan,d3d12 + features: d3d12,std,hashbrown - os: macos-latest - features: std,vulkan,metal + features: metal,hashbrown + - os: macos-latest + features: metal,std + - os: macos-latest + features: metal,std,hashbrown runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -30,11 +42,23 @@ jobs: matrix: include: - os: ubuntu-latest - features: std,vulkan,visualizer + features: vulkan,visualizer,hashbrown + - os: ubuntu-latest + features: vulkan,visualizer,std + - os: ubuntu-latest + features: vulkan,visualizer,std,hashbrown - os: windows-latest - features: std,vulkan,visualizer,d3d12,public-winapi + features: d3d12,visualizer,public-winapi,hashbrown + - os: windows-latest + features: d3d12,visualizer,public-winapi,std + - os: windows-latest + features: d3d12,visualizer,public-winapi,std,hashbrown - os: macos-latest - features: std,vulkan,visualizer,metal + features: metal,visualizer,hashbrown + - os: macos-latest + features: metal,visualizer,std + - os: macos-latest + features: metal,visualizer,std,hashbrown runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 From 3e453edf7478fd39418f5298997cda17d74d6d03 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Tue, 1 Apr 2025 17:59:54 +0800 Subject: [PATCH 20/32] emit compile error when none of `std` and `hashbrown` is enabled --- src/allocator/mod.rs | 2 -- src/lib.rs | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs index 3bc3b337..9a3cf463 100644 --- a/src/allocator/mod.rs +++ b/src/allocator/mod.rs @@ -10,9 +10,7 @@ use crate::result::*; pub(crate) mod dedicated_block_allocator; pub(crate) use dedicated_block_allocator::DedicatedBlockAllocator; -#[cfg(any(feature = "std", feature = "hashbrown"))] pub(crate) mod free_list_allocator; -#[cfg(any(feature = "std", feature = "hashbrown"))] pub(crate) use free_list_allocator::FreeListAllocator; #[derive(PartialEq, Copy, Clone, Debug)] diff --git a/src/lib.rs b/src/lib.rs index ff3baf68..380f6d10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -225,6 +225,9 @@ extern crate alloc; #[cfg(all(not(feature = "std"), feature = "visualizer"))] compile_error!("Cannot enable \"visualizer\" feature in \"no_std\" environment."); +#[cfg(not(any(feature = "std", feature = "hashbrown")))] +compile_error!("Either `std` or `hashbrown` feature must be enabled"); + mod result; pub use result::*; From 541e814784c49fa6c429341d09d3cdd84a0b7e5e Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 1 Apr 2025 12:54:04 +0200 Subject: [PATCH 21/32] CI: Simplify and complete `matrix` setup --- .github/workflows/ci.yml | 76 +++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 162056d6..e3d3d449 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,26 +7,18 @@ jobs: name: Check MSRV (1.71.0) strategy: matrix: - include: + target: - os: ubuntu-latest - features: vulkan,hashbrown - - os: ubuntu-latest - features: vulkan,std - - os: ubuntu-latest - features: vulkan,std,hashbrown - - os: windows-latest - features: d3d12,hashbrown + backend: vulkan - os: windows-latest - features: d3d12,std - - os: windows-latest - features: d3d12,std,hashbrown - - os: macos-latest - features: metal,hashbrown - - os: macos-latest - features: metal,std + backend: vulkan,d3d12 - os: macos-latest - features: metal,std,hashbrown - runs-on: ${{ matrix.os }} + backend: vulkan,metal + features: + - hashbrown + - std + - hashbrown,std + runs-on: ${{ matrix.target.os }} steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly @@ -34,38 +26,30 @@ jobs: run: cargo +nightly generate-lockfile -Zminimal-versions - uses: dtolnay/rust-toolchain@1.71.0 # Note that examples are extempt from the MSRV check, so that they can use newer Rust features - - run: cargo check --workspace --features ${{ matrix.features }} --no-default-features + - run: cargo check --workspace --features ${{ matrix.target.backend }},${{ matrix.features }} --no-default-features test: name: Test Suite strategy: matrix: - include: + target: - os: ubuntu-latest - features: vulkan,visualizer,hashbrown - - os: ubuntu-latest - features: vulkan,visualizer,std - - os: ubuntu-latest - features: vulkan,visualizer,std,hashbrown - - os: windows-latest - features: d3d12,visualizer,public-winapi,hashbrown + backend: vulkan - os: windows-latest - features: d3d12,visualizer,public-winapi,std - - os: windows-latest - features: d3d12,visualizer,public-winapi,std,hashbrown - - os: macos-latest - features: metal,visualizer,hashbrown - - os: macos-latest - features: metal,visualizer,std + backend: vulkan,d3d12 - os: macos-latest - features: metal,visualizer,std,hashbrown - runs-on: ${{ matrix.os }} + backend: vulkan,metal + features: + - hashbrown + - std + - hashbrown,std + runs-on: ${{ matrix.target.os }} steps: - uses: actions/checkout@v4 - name: Cargo test all targets - run: cargo test --workspace --all-targets --features ${{ matrix.features }} --no-default-features + run: cargo test --workspace --all-targets --features visualizer,${{ matrix.target.backend }},${{ matrix.features }} --no-default-features - name: Cargo test docs - run: cargo test --workspace --doc --features ${{ matrix.features }} --no-default-features + run: cargo test --workspace --doc --features visualizer,${{ matrix.target.backend }},${{ matrix.features }} --no-default-features fmt: name: Rustfmt @@ -79,18 +63,22 @@ jobs: name: Clippy strategy: matrix: - include: + target: - os: ubuntu-latest - features: std,vulkan,visualizer + backend: vulkan - os: windows-latest - features: std,vulkan,visualizer,d3d12,public-winapi + backend: vulkan,d3d12 - os: macos-latest - features: std,vulkan,visualizer,metal - runs-on: ${{ matrix.os }} + backend: vulkan,metal + features: + - hashbrown + - std + - hashbrown,std + runs-on: ${{ matrix.target.os }} steps: - uses: actions/checkout@v4 - name: Cargo clippy - run: cargo clippy --workspace --all-targets --features ${{ matrix.features }} --no-default-features -- -D warnings + run: cargo clippy --workspace --all-targets --features visualizer,${{ matrix.target.backend }},${{ matrix.features }} --no-default-features -- -D warnings doc: name: Build documentation @@ -98,7 +86,7 @@ jobs: matrix: # Rely on Windows and Mac to also compile the Vulkan portion (via --all-features) os: [windows-latest, macos-latest] - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.target.os }} env: RUSTDOCFLAGS: -Dwarnings steps: From 412359315340caf55a24628fa551103557013f56 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 2 Apr 2025 09:03:37 +0800 Subject: [PATCH 22/32] update missed `std` usages --- src/metal/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metal/mod.rs b/src/metal/mod.rs index 6adebdfa..b9b42fed 100644 --- a/src/metal/mod.rs +++ b/src/metal/mod.rs @@ -154,8 +154,8 @@ pub struct Allocator { allocation_sizes: AllocationSizes, } -impl std::fmt::Debug for Allocator { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl core::fmt::Debug for Allocator { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.generate_report().fmt(f) } } From 3d962a4f1b5a7521bebb58e661322167bb40d29e Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 2 Apr 2025 09:06:09 +0800 Subject: [PATCH 23/32] keep style of compile error the same --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 380f6d10..4f03b32b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -223,7 +223,7 @@ extern crate alloc; #[cfg(all(not(feature = "std"), feature = "visualizer"))] -compile_error!("Cannot enable \"visualizer\" feature in \"no_std\" environment."); +compile_error!("Cannot enable `visualizer` feature in `no_std` environment."); #[cfg(not(any(feature = "std", feature = "hashbrown")))] compile_error!("Either `std` or `hashbrown` feature must be enabled"); From 66dbf08256adc7dbd40f59b212472bfde412b005 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 2 Apr 2025 17:21:23 +0800 Subject: [PATCH 24/32] add todo related with storing of `format_args!` outside `format!` --- src/allocator/dedicated_block_allocator/mod.rs | 1 + src/allocator/free_list_allocator/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/allocator/dedicated_block_allocator/mod.rs b/src/allocator/dedicated_block_allocator/mod.rs index 955b7b06..d591f29f 100644 --- a/src/allocator/dedicated_block_allocator/mod.rs +++ b/src/allocator/dedicated_block_allocator/mod.rs @@ -103,6 +103,7 @@ impl SubAllocator for DedicatedBlockAllocator { let backtrace_info; #[cfg(feature = "std")] { + // TODO: Allocation could be avoided here if https://github.com/rust-lang/rust/pull/139135 is merged and stabilized. backtrace_info = format!( ", backtrace: {}", diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index 8b40734b..8529537f 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -380,6 +380,7 @@ impl SubAllocator for FreeListAllocator { let backtrace_info; #[cfg(feature = "std")] { + // TODO: Allocation could be avoided here if https://github.com/rust-lang/rust/pull/139135 is merged and stabilized. backtrace_info = format!( ", backtrace: {}", From 10d0742c45c0fdfd2e85a547807ee204abde214b Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 2 Apr 2025 17:35:05 +0800 Subject: [PATCH 25/32] update missed `std` usages --- src/visualizer/allocation_reports.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/visualizer/allocation_reports.rs b/src/visualizer/allocation_reports.rs index c95b51ae..fb03e38c 100644 --- a/src/visualizer/allocation_reports.rs +++ b/src/visualizer/allocation_reports.rs @@ -92,7 +92,7 @@ pub(crate) fn render_allocation_reports_ui( (AllocationReportVisualizeSorting::None, _) => {} (AllocationReportVisualizeSorting::Idx, true) => allocations.sort_by_key(|(idx, _)| *idx), (AllocationReportVisualizeSorting::Idx, false) => { - allocations.sort_by_key(|(idx, _)| std::cmp::Reverse(*idx)) + allocations.sort_by_key(|(idx, _)| core::cmp::Reverse(*idx)) } (AllocationReportVisualizeSorting::Name, true) => { allocations.sort_by(|(_, alloc1), (_, alloc2)| alloc1.name.cmp(&alloc2.name)) @@ -104,7 +104,7 @@ pub(crate) fn render_allocation_reports_ui( allocations.sort_by_key(|(_, alloc)| alloc.size) } (AllocationReportVisualizeSorting::Size, false) => { - allocations.sort_by_key(|(_, alloc)| std::cmp::Reverse(alloc.size)) + allocations.sort_by_key(|(_, alloc)| core::cmp::Reverse(alloc.size)) } } From 0ab0c8892d2bc65e990a06b7a018f8b6403a40a6 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 2 Apr 2025 17:40:17 +0800 Subject: [PATCH 26/32] fix lint --- src/allocator/dedicated_block_allocator/mod.rs | 4 +++- src/allocator/free_list_allocator/mod.rs | 7 ++++--- src/allocator/mod.rs | 4 +++- src/visualizer/memory_chunks.rs | 1 - src/vulkan/mod.rs | 4 +++- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/allocator/dedicated_block_allocator/mod.rs b/src/allocator/dedicated_block_allocator/mod.rs index d591f29f..02bb13df 100644 --- a/src/allocator/dedicated_block_allocator/mod.rs +++ b/src/allocator/dedicated_block_allocator/mod.rs @@ -1,11 +1,13 @@ #![deny(unsafe_code, clippy::unwrap_used)] +#[cfg(feature = "std")] +use alloc::sync::Arc; use alloc::{ borrow::ToOwned, string::{String, ToString}, vec::Vec, }; #[cfg(feature = "std")] -use std::{backtrace::Backtrace, sync::Arc}; +use std::backtrace::Backtrace; use log::{log, Level}; diff --git a/src/allocator/free_list_allocator/mod.rs b/src/allocator/free_list_allocator/mod.rs index 8529537f..db969d68 100644 --- a/src/allocator/free_list_allocator/mod.rs +++ b/src/allocator/free_list_allocator/mod.rs @@ -1,14 +1,15 @@ #![deny(unsafe_code, clippy::unwrap_used)] - +#[cfg(feature = "std")] +use alloc::sync::Arc; use alloc::{ borrow::ToOwned, string::{String, ToString}, vec::Vec, }; +#[cfg(feature = "std")] +use std::backtrace::Backtrace; #[cfg(all(feature = "std", not(feature = "hashbrown")))] use std::collections::{HashMap, HashSet}; -#[cfg(feature = "std")] -use std::{backtrace::Backtrace, sync::Arc}; #[cfg(feature = "hashbrown")] use hashbrown::{HashMap, HashSet}; diff --git a/src/allocator/mod.rs b/src/allocator/mod.rs index 9a3cf463..a4039116 100644 --- a/src/allocator/mod.rs +++ b/src/allocator/mod.rs @@ -1,7 +1,9 @@ +#[cfg(feature = "std")] +use alloc::sync::Arc; use alloc::{fmt, string::String, vec::Vec}; use core::ops::Range; #[cfg(feature = "std")] -use std::{backtrace::Backtrace, sync::Arc}; +use std::backtrace::Backtrace; use log::*; diff --git a/src/visualizer/memory_chunks.rs b/src/visualizer/memory_chunks.rs index ffe2afed..66156000 100644 --- a/src/visualizer/memory_chunks.rs +++ b/src/visualizer/memory_chunks.rs @@ -80,7 +80,6 @@ pub(crate) fn render_memory_chunks_ui<'a>( if cursor_idx < data.len() { bytes_required = data[cursor_idx].size; } - continue; } let bytes_used = bytes_required.min(bytes_left); diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index fbe967e0..f1104d02 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -1,7 +1,9 @@ +#[cfg(feature = "std")] +use alloc::sync::Arc; use alloc::{borrow::ToOwned, boxed::Box, string::ToString, vec::Vec}; use core::{fmt, marker::PhantomData}; #[cfg(feature = "std")] -use std::{backtrace::Backtrace, sync::Arc}; +use std::backtrace::Backtrace; use ash::vk; use log::{debug, Level}; From e896fab066015af4531e11814d06ae533b5a889c Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 2 Apr 2025 17:44:42 +0800 Subject: [PATCH 27/32] update `CI` --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3d3d449..260499c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,6 @@ jobs: - os: macos-latest backend: vulkan,metal features: - - hashbrown - std - hashbrown,std runs-on: ${{ matrix.target.os }} @@ -71,7 +70,6 @@ jobs: - os: macos-latest backend: vulkan,metal features: - - hashbrown - std - hashbrown,std runs-on: ${{ matrix.target.os }} From 8bdedba86d3f903158454afc6d2ac4f05075bdac Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Wed, 2 Apr 2025 17:46:51 +0800 Subject: [PATCH 28/32] fix lint --- src/d3d12/mod.rs | 4 +++- src/metal/mod.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/d3d12/mod.rs b/src/d3d12/mod.rs index 6dadca45..c08dcb46 100644 --- a/src/d3d12/mod.rs +++ b/src/d3d12/mod.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "std")] +use alloc::sync::Arc; use alloc::{boxed::Box, string::String, vec::Vec}; use core::{ fmt, @@ -5,7 +7,7 @@ use core::{ mem::size_of_val, }; #[cfg(feature = "std")] -use std::{backtrace::Backtrace, sync::Arc}; +use std::backtrace::Backtrace; use log::{debug, warn, Level}; use windows::Win32::{ diff --git a/src/metal/mod.rs b/src/metal/mod.rs index b9b42fed..b489e7df 100644 --- a/src/metal/mod.rs +++ b/src/metal/mod.rs @@ -1,6 +1,8 @@ +#[cfg(feature = "std")] +use alloc::sync::Arc; use alloc::{boxed::Box, string::ToString, vec::Vec}; #[cfg(feature = "std")] -use std::{backtrace::Backtrace, sync::Arc}; +use std::backtrace::Backtrace; use log::debug; use objc2::{rc::Retained, runtime::ProtocolObject}; From c4da9ba8ba5d05ad5260338058d662a4fba3ca7b Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 3 Apr 2025 08:42:56 +0800 Subject: [PATCH 29/32] add `no_std` content in `README` --- README.md | 33 ++++++++++++++++++++++++++++++++- README.tpl | 32 +++++++++++++++++++++++++++++++- src/lib.rs | 1 + 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 79e2403b..03cac8a7 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ let mut allocator = Allocator::new(&AllocatorCreateDesc { ``` ## Simple Metal allocation example + ```rust use gpu_allocator::metal::*; use gpu_allocator::MemoryLocation; @@ -167,9 +168,39 @@ drop(resource); allocator.free(&allocation).unwrap(); ``` +## `no_std` Support + +`no_std` support can be enabled by compiling with `--no-default-features` to +disable `std` support and `--features hashbrown` for `Hash` collections that are only +defined in `std` for internal usages in crate. For example: + +```toml +[dependencies] +gpu-allocator = { version = "0.27", default-features = false, features = ["hashbrown", "other features"] } +``` + +To support both `std` and `no_std` builds in project, you can use the following +in your `Cargo.toml`: + +```toml +[features] +default = ["std", "other features"] + +std = ["gpu-allocator/std"] +hashbrown = ["gpu-allocator/hashbrown"] +other_features = [] + +[dependencies] +gpu-allocator = { version = "0.27", default-features = false } +``` + ## Minimum Supported Rust Version -The MSRV for this crate and the `vulkan`, `d3d12` and `metal` features is Rust 1.71. Any other features such as the `visualizer` (with all the `egui` dependencies) may have a higher requirement and are not tested in our CI. +The MSRV for this crate and the `vulkan`, `d3d12` and `metal` features is Rust **1.71**. + +The `no_std` support requires version above **1.81** beacuase `no_std` support of dependency `thiserror` requires `core::error::Error` which is stabalized in **1.81**. + +Any other features such as the `visualizer` (with all the `egui` dependencies) may have a higher requirement and are not tested in our CI. ## License diff --git a/README.tpl b/README.tpl index dd3fd225..2997c506 100644 --- a/README.tpl +++ b/README.tpl @@ -19,9 +19,39 @@ gpu-allocator = "0.27.0" {{readme}} +## `no_std` Support + +`no_std` support can be enabled by compiling with `--no-default-features` to +disable `std` support and `--features hashbrown` for `Hash` collections that are only +defined in `std` for internal usages in crate. For example: + +```toml +[dependencies] +gpu-allocator = { version = "0.27", default-features = false, features = ["hashbrown", "other features"] } +``` + +To support both `std` and `no_std` builds in project, you can use the following +in your `Cargo.toml`: + +```toml +[features] +default = ["std", "other features"] + +std = ["gpu-allocator/std"] +hashbrown = ["gpu-allocator/hashbrown"] +other_features = [] + +[dependencies] +gpu-allocator = { version = "0.27", default-features = false } +``` + ## Minimum Supported Rust Version -The MSRV for this crate and the `vulkan`, `d3d12` and `metal` features is Rust 1.71. Any other features such as the `visualizer` (with all the `egui` dependencies) may have a higher requirement and are not tested in our CI. +The MSRV for this crate and the `vulkan`, `d3d12` and `metal` features is Rust **1.71**. + +The `no_std` support requires version above **1.81** beacuase `no_std` support of dependency `thiserror` requires `core::error::Error` which is stabalized in **1.81**. + +Any other features such as the `visualizer` (with all the `egui` dependencies) may have a higher requirement and are not tested in our CI. ## License diff --git a/src/lib.rs b/src/lib.rs index 4f03b32b..5e5171b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -174,6 +174,7 @@ //! ``` //! //! # Simple Metal allocation example +//! //! ```no_run //! # #[cfg(feature = "metal")] //! # fn main() { From d73de578d55f57d32f0bedd6082c099179bbcc1c Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 3 Apr 2025 08:59:50 +0800 Subject: [PATCH 30/32] fix `CI` --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 260499c0..83df4d9b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,7 +84,7 @@ jobs: matrix: # Rely on Windows and Mac to also compile the Vulkan portion (via --all-features) os: [windows-latest, macos-latest] - runs-on: ${{ matrix.target.os }} + runs-on: ${{ matrix.os }} env: RUSTDOCFLAGS: -Dwarnings steps: From b0b38a988c0f1cd7da65fed002a31680354424e3 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 17 Apr 2025 08:49:37 +0800 Subject: [PATCH 31/32] update `release.toml` --- release.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release.toml b/release.toml index 619bc93a..78eec971 100644 --- a/release.toml +++ b/release.toml @@ -6,6 +6,6 @@ sign-tag = true publish = false pre-release-replacements = [ - { file = "README.md", search = "gpu-allocator = .*", replace = "{{crate_name}} = \"{{version}}\"" }, - { file = "README.tpl", search = "gpu-allocator = .*", replace = "{{crate_name}} = \"{{version}}\"" }, + { file = "README.md", search = "gpu-allocator = { version = \".*\"", replace = "{{crate_name}} = { version = \"{{version}}\"" }, + { file = "README.tpl", search = "gpu-allocator = { version = \".*\"", replace = "{{crate_name}} = { version = \"{{version}}\"" }, ] From f93b1da112ea2cc313efa2401b4857d365231c53 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD Date: Thu, 17 Apr 2025 09:04:22 +0800 Subject: [PATCH 32/32] update `README` --- README.md | 4 ++-- README.tpl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 03cac8a7..84758b1a 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ```toml [dependencies] -gpu-allocator = "0.27.0" +gpu-allocator = { version = "0.27.0" } ``` ![Visualizer](visualizer.png) @@ -198,7 +198,7 @@ gpu-allocator = { version = "0.27", default-features = false } The MSRV for this crate and the `vulkan`, `d3d12` and `metal` features is Rust **1.71**. -The `no_std` support requires version above **1.81** beacuase `no_std` support of dependency `thiserror` requires `core::error::Error` which is stabalized in **1.81**. +The `no_std` support requires Rust **1.81** or higher because `no_std` support of dependency `thiserror` requires `core::error::Error` which is stabilized in **1.81**. Any other features such as the `visualizer` (with all the `egui` dependencies) may have a higher requirement and are not tested in our CI. diff --git a/README.tpl b/README.tpl index 2997c506..7afd85ab 100644 --- a/README.tpl +++ b/README.tpl @@ -12,7 +12,7 @@ ```toml [dependencies] -gpu-allocator = "0.27.0" +gpu-allocator = { version = "0.27.0" } ``` ![Visualizer](visualizer.png) @@ -49,7 +49,7 @@ gpu-allocator = { version = "0.27", default-features = false } The MSRV for this crate and the `vulkan`, `d3d12` and `metal` features is Rust **1.71**. -The `no_std` support requires version above **1.81** beacuase `no_std` support of dependency `thiserror` requires `core::error::Error` which is stabalized in **1.81**. +The `no_std` support requires Rust **1.81** or higher because `no_std` support of dependency `thiserror` requires `core::error::Error` which is stabilized in **1.81**. Any other features such as the `visualizer` (with all the `egui` dependencies) may have a higher requirement and are not tested in our CI.