Skip to content

Commit 990cf94

Browse files
committed
Remove gpu-allocator dependency
Delete the shared gpu-allocator glue from wgpu-hal/src/lib.rs, inline a local AllocationSizes into the dx12 backend, drop gpu-allocator from the workspace and wgpu-hal manifests, and add the feature changelog entry.
1 parent a9ac317 commit 990cf94

7 files changed

Lines changed: 64 additions & 159 deletions

File tree

.deny.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ skip = [
1616
# Used by hashbrown 0.15.5
1717
{ name = "foldhash", version = "0.1.5" },
1818

19-
# naga depends on hashbrown 0.16 directly, while naga -> indexmap pulls hashbrown 0.17
20-
{ name = "hashbrown", version = "0.16.1" },
21-
2219
# wgpu-hal -> drm -> drm-sys uses an older version, while wgpu-hal -> drm -> rustix uses a newer one
2320
{ name = "linux-raw-sys", version = "0.9.4" },
2421
]

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@ Bottom level categories:
4242

4343
## Unreleased
4444

45+
### Major changes
46+
47+
#### In-tree memory allocator for Vulkan and D3D12
48+
49+
wgpu-hal's Vulkan and D3D12 backends now suballocate device memory with an in-tree allocator, built on two new crates: `wgpu-offset-allocator` and `wgpu-block-pool`, whose algorithms and policy are derived from AMD's VulkanMemoryAllocator and D3D12MemoryAllocator. The `gpu-allocator` dependency has been removed.
50+
51+
`MemoryBudgetThresholds::for_resource_creation` is now enforced inside the allocator, where it only gates the creation of new memory blocks and dedicated allocations. Previously it was a heuristic pre-check that could reject a resource even when it would have fit in already-allocated memory.
52+
53+
Also fixed along the way:
54+
55+
- On Vulkan, buffers used as acceleration-structure build inputs are now explicitly 16-byte aligned, as acceleration-structure build commands require. Previously this held only by accident of allocator layout and could be violated on some drivers (observed on AMD).
56+
- Device memory is no longer leaked on rare error paths during resource creation.
57+
58+
By @cwfitzgerald in [#9794](https://github.com/gfx-rs/wgpu/pull/9794).
59+
4560
### Added/New Features
4661

4762
#### General

Cargo.lock

Lines changed: 0 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,6 @@ mach-dxcompiler-rs = { version = "0.1.4", default-features = false } # remember
294294
windows-core = { version = "0.62", default-features = false }
295295
windows-result = { version = "0.4", default-features = false }
296296

297-
# DX12 and Vulkan dependencies
298-
gpu-allocator = { version = "0.28", default-features = false, features = [
299-
"hashbrown",
300-
] }
301-
302297
# Gles dependencies
303298
khronos-egl = "6"
304299
glow = "0.18"

wgpu-hal/Cargo.toml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@ vulkan = [
9494
"dep:arrayvec",
9595
"dep:ash",
9696
"dep:bytemuck",
97-
# The vulkan backend no longer uses gpu-allocator, but the shared
98-
# `gpu_allocator`-based glue in `lib.rs` is still gated on `any(dx12, vulkan)`
99-
# (the dx12 backend continues to use it). Keep the crate available - without its
100-
# `vulkan` feature - so `lib.rs` compiles in vulkan-only builds. Removing that glue
101-
# (and this dependency) is a follow-up once dx12 is ported too.
102-
"dep:gpu-allocator",
10397
"dep:libc",
10498
"dep:libloading",
10599
"dep:ordered-float",
@@ -147,7 +141,6 @@ dx12 = [
147141
"dep:arrayvec",
148142
"dep:bit-set",
149143
"dep:bytemuck",
150-
"dep:gpu-allocator",
151144
"dep:libloading",
152145
"dep:once_cell",
153146
"dep:ordered-float",
@@ -247,8 +240,6 @@ glow = { workspace = true, optional = true }
247240
########################
248241

249242
[target.'cfg(not(target_family = "wasm"))'.dependencies]
250-
# Backend: Vulkan and Dx12
251-
gpu-allocator = { workspace = true, optional = true }
252243
# Backend: Vulkan
253244
ash = { workspace = true, optional = true }
254245
smallvec = { workspace = true, optional = true, features = ["union"] }

wgpu-hal/src/dx12/suballocation.rs

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ use windows::Win32::Graphics::{Direct3D12, Dxgi};
7979
use crate::{
8080
auxil::dxgi::{name::ObjectExt as _, result::HResult as _},
8181
dx12::conv,
82-
AllocationSizes,
8382
};
8483

8584
/// The per-allocation user data stored inside the pool.
@@ -97,10 +96,55 @@ const DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT: u64 =
9796

9897
/// D3D12MA's default preferred block size (64 MiB).
9998
///
100-
/// We merge this with the [`AllocationSizes`] policy replicated from
101-
/// `wgpu_hal::lib`; see [`Pools::preferred_block_size`].
99+
/// We merge this with the [`AllocationSizes`] policy derived from the user's
100+
/// [`wgt::MemoryHints`]; see [`Pools::preferred_block_size`].
102101
const D3D12MA_DEFAULT_BLOCK_SIZE: u64 = 64 * 1024 * 1024;
103102

103+
/// Block-size policy used by this backend's suballocator to decide how large each
104+
/// memory block should be, derived from the user's [`wgt::MemoryHints`].
105+
///
106+
/// The vulkan backend replicates the same policy locally in
107+
/// `vulkan::suballocation`.
108+
struct AllocationSizes {
109+
min_device_memblock_size: u64,
110+
min_host_memblock_size: u64,
111+
}
112+
113+
impl AllocationSizes {
114+
fn from_memory_hints(memory_hints: &wgt::MemoryHints) -> Self {
115+
// TODO: the allocator's configuration should take hardware capability into
116+
// account.
117+
const MB: u64 = 1024 * 1024;
118+
119+
match memory_hints {
120+
wgt::MemoryHints::Performance => Self {
121+
min_device_memblock_size: 128 * MB,
122+
min_host_memblock_size: 64 * MB,
123+
},
124+
wgt::MemoryHints::MemoryUsage => Self {
125+
min_device_memblock_size: 8 * MB,
126+
min_host_memblock_size: 4 * MB,
127+
},
128+
wgt::MemoryHints::Manual {
129+
suballocated_device_memory_block_size,
130+
} => {
131+
// TODO: https://github.com/gfx-rs/wgpu/issues/8625
132+
// Would it be useful to expose the host size in memory hints
133+
// instead of always using half of the device size?
134+
let device_size = suballocated_device_memory_block_size;
135+
let host_min = device_size.start / 2;
136+
137+
// Clamp the sizes between 4MiB and 256MiB, since we use the sizes when
138+
// detecting high memory pressure and want them to stay within a sane range.
139+
Self {
140+
min_device_memblock_size: device_size.start.clamp(4 * MB, 256 * MB),
141+
min_host_memblock_size: host_min.clamp(4 * MB, 256 * MB),
142+
}
143+
}
144+
}
145+
}
146+
}
147+
104148
/// Refresh the DXGI budget query at most once per this many alloc/free
105149
/// operations, matching D3D12MA's `ShouldUpdateBudget` cadence.
106150
const BUDGET_REFRESH_INTERVAL: u32 = 30;
@@ -629,8 +673,8 @@ struct Pools {
629673

630674
impl Pools {
631675
/// Computes the preferred block size for a heap class, merging D3D12MA's
632-
/// 64 MiB default with the [`AllocationSizes`] policy replicated from
633-
/// `wgpu_hal::lib` (derived from [`wgt::MemoryHints`]).
676+
/// 64 MiB default with the [`AllocationSizes`] policy derived from
677+
/// [`wgt::MemoryHints`].
634678
///
635679
/// Merge rule: we take the *larger* of D3D12MA's default and wgpu's
636680
/// configured min block size for the segment (device vs host), so that:

wgpu-hal/src/lib.rs

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -387,107 +387,6 @@ pub enum DeviceError {
387387
Unexpected,
388388
}
389389

390-
#[cfg(any(dx12, vulkan))]
391-
impl From<gpu_allocator::AllocationError> for DeviceError {
392-
fn from(result: gpu_allocator::AllocationError) -> Self {
393-
match result {
394-
gpu_allocator::AllocationError::OutOfMemory => Self::OutOfMemory,
395-
gpu_allocator::AllocationError::FailedToMap(e) => {
396-
log::error!("gpu-allocator: Failed to map: {e}");
397-
Self::Lost
398-
}
399-
gpu_allocator::AllocationError::NoCompatibleMemoryTypeFound => {
400-
log::error!("gpu-allocator: No Compatible Memory Type Found");
401-
Self::Lost
402-
}
403-
gpu_allocator::AllocationError::InvalidAllocationCreateDesc => {
404-
log::error!("gpu-allocator: Invalid Allocation Creation Description");
405-
Self::Lost
406-
}
407-
gpu_allocator::AllocationError::InvalidAllocatorCreateDesc(e) => {
408-
log::error!("gpu-allocator: Invalid Allocator Creation Description: {e}");
409-
Self::Lost
410-
}
411-
412-
gpu_allocator::AllocationError::Internal(e) => {
413-
log::error!("gpu-allocator: Internal Error: {e}");
414-
Self::Lost
415-
}
416-
gpu_allocator::AllocationError::BarrierLayoutNeedsDevice10
417-
| gpu_allocator::AllocationError::CastableFormatsRequiresEnhancedBarriers
418-
| gpu_allocator::AllocationError::CastableFormatsRequiresAtLeastDevice12 => {
419-
unreachable!()
420-
}
421-
}
422-
}
423-
}
424-
425-
// A copy of gpu_allocator::AllocationSizes, allowing to read the configured value for
426-
// the dx12 backend, we should instead add getters to gpu_allocator::AllocationSizes
427-
// and remove this type.
428-
// https://github.com/Traverse-Research/gpu-allocator/issues/295
429-
#[cfg_attr(not(any(dx12, vulkan)), expect(dead_code))]
430-
pub(crate) struct AllocationSizes {
431-
pub(crate) min_device_memblock_size: u64,
432-
pub(crate) max_device_memblock_size: u64,
433-
pub(crate) min_host_memblock_size: u64,
434-
pub(crate) max_host_memblock_size: u64,
435-
}
436-
437-
impl AllocationSizes {
438-
#[allow(dead_code, reason = "may be unused on some platforms")]
439-
pub(crate) fn from_memory_hints(memory_hints: &wgt::MemoryHints) -> Self {
440-
// TODO: the allocator's configuration should take hardware capability into
441-
// account.
442-
const MB: u64 = 1024 * 1024;
443-
444-
match memory_hints {
445-
wgt::MemoryHints::Performance => Self {
446-
min_device_memblock_size: 128 * MB,
447-
max_device_memblock_size: 256 * MB,
448-
min_host_memblock_size: 64 * MB,
449-
max_host_memblock_size: 128 * MB,
450-
},
451-
wgt::MemoryHints::MemoryUsage => Self {
452-
min_device_memblock_size: 8 * MB,
453-
max_device_memblock_size: 64 * MB,
454-
min_host_memblock_size: 4 * MB,
455-
max_host_memblock_size: 32 * MB,
456-
},
457-
wgt::MemoryHints::Manual {
458-
suballocated_device_memory_block_size,
459-
} => {
460-
// TODO: https://github.com/gfx-rs/wgpu/issues/8625
461-
// Would it be useful to expose the host size in memory hints
462-
// instead of always using half of the device size?
463-
let device_size = suballocated_device_memory_block_size;
464-
let host_size = device_size.start / 2..device_size.end / 2;
465-
466-
// gpu_allocator clamps the sizes between 4MiB and 256MiB, but we clamp them ourselves since we use
467-
// the sizes when detecting high memory pressure and there is no way to query the values otherwise.
468-
Self {
469-
min_device_memblock_size: device_size.start.clamp(4 * MB, 256 * MB),
470-
max_device_memblock_size: device_size.end.clamp(4 * MB, 256 * MB),
471-
min_host_memblock_size: host_size.start.clamp(4 * MB, 256 * MB),
472-
max_host_memblock_size: host_size.end.clamp(4 * MB, 256 * MB),
473-
}
474-
}
475-
}
476-
}
477-
}
478-
479-
#[cfg(any(dx12, vulkan))]
480-
impl From<AllocationSizes> for gpu_allocator::AllocationSizes {
481-
fn from(value: AllocationSizes) -> gpu_allocator::AllocationSizes {
482-
gpu_allocator::AllocationSizes::new(
483-
value.min_device_memblock_size,
484-
value.min_host_memblock_size,
485-
)
486-
.with_max_device_memblock_size(value.max_device_memblock_size)
487-
.with_max_host_memblock_size(value.max_host_memblock_size)
488-
}
489-
}
490-
491390
#[allow(dead_code, reason = "may be unused on some platforms")]
492391
#[cold]
493392
fn hal_usage_error<T: fmt::Display>(txt: T) -> ! {

0 commit comments

Comments
 (0)