1056: Replace gfx-descriptor by gpu-descriptor r=cwfitzgerald a=kvark

**Connections**
Unblocks #1027
cc @zakarumych 

**Description**
Removes the last link we had between us and gfx-rs.

**Testing**
Tested on wgpu-rs

Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
bors[bot]
2020-12-01 02:49:15 +00:00
committed by GitHub
7 changed files with 264 additions and 56 deletions

41
Cargo.lock generated
View File

@@ -15,6 +15,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]]
name = "ahash"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6789e291be47ace86a60303502173d84af8327e3627ecf334356ee0f87a164c"
[[package]]
name = "aho-corasick"
version = "0.7.15"
@@ -690,18 +696,6 @@ dependencies = [
"x11",
]
[[package]]
name = "gfx-descriptor"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd8c7afcd000f279d541a490e27117e61037537279b9342279abf4938fe60c6b"
dependencies = [
"arrayvec",
"fxhash",
"gfx-hal",
"log",
]
[[package]]
name = "gfx-hal"
version = "0.6.0"
@@ -778,11 +772,32 @@ dependencies = [
"bitflags",
]
[[package]]
name = "gpu-descriptor"
version = "0.1.0"
source = "git+https://github.com/zakarumych/gpu-descriptor?rev=831460c4b5120d9a74744d542f39a95b9816b5ab#831460c4b5120d9a74744d542f39a95b9816b5ab"
dependencies = [
"bitflags",
"gpu-descriptor-types",
"hashbrown",
]
[[package]]
name = "gpu-descriptor-types"
version = "0.1.0"
source = "git+https://github.com/zakarumych/gpu-descriptor?rev=831460c4b5120d9a74744d542f39a95b9816b5ab#831460c4b5120d9a74744d542f39a95b9816b5ab"
dependencies = [
"bitflags",
]
[[package]]
name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
dependencies = [
"ahash",
]
[[package]]
name = "hermit-abi"
@@ -2198,9 +2213,9 @@ dependencies = [
"gfx-backend-gl",
"gfx-backend-metal",
"gfx-backend-vulkan",
"gfx-descriptor",
"gfx-hal",
"gpu-alloc",
"gpu-descriptor",
"loom",
"naga",
"parking_lot 0.11.0",

View File

@@ -7,7 +7,7 @@ This is an active GitHub mirror of the WebGPU implementation in Rust, which now
[![Matrix](https://img.shields.io/badge/Dev_Matrix-%23wgpu%3Amatrix.org-blueviolet.svg)](https://matrix.to/#/#wgpu:matrix.org) [![Matrix](https://img.shields.io/badge/User_Matrix-%23wgpu--users%3Amatrix.org-blueviolet.svg)](https://matrix.to/#/#wgpu-users:matrix.org)
[![Build Status](https://github.com/gfx-rs/wgpu/workflows/CI/badge.svg)](https://github.com/gfx-rs/wgpu/actions)
This is the core logic of an experimental [WebGPU](https://www.w3.org/community/gpu/) implementation. It's written in Rust and is based on [gfx-hal](https://github.com/gfx-rs/gfx) with help of [gfx-extras](https://github.com/gfx-rs/gfx-extras). See the upstream [WebGPU specification](https://gpuweb.github.io/gpuweb/) (work in progress).
This is the core logic of an experimental [WebGPU](https://www.w3.org/community/gpu/) implementation. It's written in Rust and is based on [gfx-hal](https://github.com/gfx-rs/gfx) with help of [gpu-alloc](https://github.com/zakarumych/gpu-alloc) and [gpu-descriptor](https://github.com/zakarumych/gpu-descriptor). See the upstream [WebGPU specification](https://gpuweb.github.io/gpuweb/) (work in progress).
The implementation consists of the following parts:

View File

@@ -34,8 +34,8 @@ serde = { version = "1.0", features = ["serde_derive"], optional = true }
smallvec = "1"
tracing = { version = "0.1", default-features = false, features = ["std"] }
thiserror = "1"
gfx-descriptor = "0.2"
gpu-alloc = { git = "https://github.com/zakarumych/gpu-alloc", rev = "d07be73f9439a37c89f5b72f2500cbf0eb4ff613" }
gpu-descriptor = { git = "https://github.com/zakarumych/gpu-descriptor", rev = "831460c4b5120d9a74744d542f39a95b9816b5ab"}
[dependencies.naga]
version = "0.2"

View File

@@ -3,7 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
device::{DeviceError, SHADER_STAGE_COUNT},
device::{
descriptor::{DescriptorSet, DescriptorTotalCount},
DeviceError, SHADER_STAGE_COUNT,
},
hub::Resource,
id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid},
track::{TrackerSet, DUMMY_SELECTOR},
@@ -12,7 +15,6 @@ use crate::{
};
use arrayvec::ArrayVec;
use gfx_descriptor::{DescriptorCounts, DescriptorSet};
#[cfg(feature = "replay")]
use serde::Deserialize;
@@ -322,7 +324,7 @@ pub struct BindGroupLayout<B: hal::Backend> {
pub(crate) device_id: Stored<DeviceId>,
pub(crate) multi_ref_count: MultiRefCount,
pub(crate) entries: BindEntryMap,
pub(crate) desc_counts: DescriptorCounts,
pub(crate) desc_count: DescriptorTotalCount,
pub(crate) dynamic_count: usize,
pub(crate) count_validator: BindingTypeMaxCountValidator,
#[cfg(debug_assertions)]

View File

@@ -0,0 +1,168 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::DeviceError;
use arrayvec::ArrayVec;
pub use gpu_descriptor::DescriptorTotalCount;
pub type DescriptorSet<B> = gpu_descriptor::DescriptorSet<<B as hal::Backend>::DescriptorSet>;
#[derive(Debug)]
pub struct DescriptorAllocator<B: hal::Backend>(
gpu_descriptor::DescriptorAllocator<B::DescriptorPool, B::DescriptorSet>,
);
struct DescriptorDevice<'a, B: hal::Backend>(&'a B::Device);
impl<B: hal::Backend> DescriptorAllocator<B> {
pub fn new() -> Self {
DescriptorAllocator(unsafe { gpu_descriptor::DescriptorAllocator::new(0) })
}
pub fn allocate(
&mut self,
device: &B::Device,
layout: &B::DescriptorSetLayout,
layout_descriptor_count: &DescriptorTotalCount,
count: u32,
) -> Result<Vec<DescriptorSet<B>>, DeviceError> {
self.0
.allocate(
&DescriptorDevice::<B>(device),
layout,
gpu_descriptor::DescriptorSetLayoutCreateFlags::empty(),
layout_descriptor_count,
count,
)
.map_err(|err| {
tracing::warn!("Descriptor set allocation failed: {}", err);
DeviceError::OutOfMemory
})
}
pub fn free(&mut self, device: &B::Device, sets: impl IntoIterator<Item = DescriptorSet<B>>) {
unsafe { self.0.free(&DescriptorDevice::<B>(device), sets) }
}
pub fn cleanup(&mut self, device: &B::Device) {
self.0.cleanup(&DescriptorDevice::<B>(device))
}
}
impl<B: hal::Backend>
gpu_descriptor::DescriptorDevice<B::DescriptorSetLayout, B::DescriptorPool, B::DescriptorSet>
for DescriptorDevice<'_, B>
{
unsafe fn create_descriptor_pool(
&self,
descriptor_count: &DescriptorTotalCount,
max_sets: u32,
flags: gpu_descriptor::DescriptorPoolCreateFlags,
) -> Result<B::DescriptorPool, gpu_descriptor::CreatePoolError> {
let mut ranges = ArrayVec::<[_; 7]>::new();
ranges.push(hal::pso::DescriptorRangeDesc {
ty: hal::pso::DescriptorType::Sampler,
count: descriptor_count.sampler as _,
});
ranges.push(hal::pso::DescriptorRangeDesc {
ty: hal::pso::DescriptorType::Image {
ty: hal::pso::ImageDescriptorType::Sampled {
with_sampler: false,
},
},
count: descriptor_count.sampled_image as _,
});
ranges.push(hal::pso::DescriptorRangeDesc {
ty: hal::pso::DescriptorType::Image {
ty: hal::pso::ImageDescriptorType::Storage { read_only: false },
},
count: descriptor_count.storage_image as _,
});
ranges.push(hal::pso::DescriptorRangeDesc {
ty: hal::pso::DescriptorType::Buffer {
ty: hal::pso::BufferDescriptorType::Uniform,
format: hal::pso::BufferDescriptorFormat::Structured {
dynamic_offset: false,
},
},
count: descriptor_count.uniform_buffer as _,
});
ranges.push(hal::pso::DescriptorRangeDesc {
ty: hal::pso::DescriptorType::Buffer {
ty: hal::pso::BufferDescriptorType::Storage { read_only: false },
format: hal::pso::BufferDescriptorFormat::Structured {
dynamic_offset: false,
},
},
count: descriptor_count.storage_buffer as _,
});
ranges.push(hal::pso::DescriptorRangeDesc {
ty: hal::pso::DescriptorType::Buffer {
ty: hal::pso::BufferDescriptorType::Uniform,
format: hal::pso::BufferDescriptorFormat::Structured {
dynamic_offset: true,
},
},
count: descriptor_count.uniform_buffer_dynamic as _,
});
ranges.push(hal::pso::DescriptorRangeDesc {
ty: hal::pso::DescriptorType::Buffer {
ty: hal::pso::BufferDescriptorType::Storage { read_only: false },
format: hal::pso::BufferDescriptorFormat::Structured {
dynamic_offset: true,
},
},
count: descriptor_count.storage_buffer_dynamic as _,
});
ranges.retain(|rd| rd.count != 0);
match hal::device::Device::create_descriptor_pool(
self.0,
max_sets as usize,
ranges,
hal::pso::DescriptorPoolCreateFlags::from_bits_truncate(flags.bits() as u32),
) {
Ok(pool) => Ok(pool),
Err(hal::device::OutOfMemory::Host) => {
Err(gpu_descriptor::CreatePoolError::OutOfHostMemory)
}
Err(hal::device::OutOfMemory::Device) => {
Err(gpu_descriptor::CreatePoolError::OutOfDeviceMemory)
}
}
}
unsafe fn destroy_descriptor_pool(&self, pool: B::DescriptorPool) {
hal::device::Device::destroy_descriptor_pool(self.0, pool);
}
unsafe fn alloc_descriptor_sets<'a>(
&self,
pool: &mut B::DescriptorPool,
layouts: impl Iterator<Item = &'a B::DescriptorSetLayout>,
sets: &mut impl Extend<B::DescriptorSet>,
) -> Result<(), gpu_descriptor::DeviceAllocationError> {
use gpu_descriptor::DeviceAllocationError as Dae;
match hal::pso::DescriptorPool::allocate(pool, layouts, sets) {
Ok(()) => Ok(()),
Err(hal::pso::AllocationError::OutOfMemory(oom)) => Err(match oom {
hal::device::OutOfMemory::Host => Dae::OutOfHostMemory,
hal::device::OutOfMemory::Device => Dae::OutOfDeviceMemory,
}),
Err(hal::pso::AllocationError::OutOfPoolMemory) => Err(Dae::OutOfPoolMemory),
Err(hal::pso::AllocationError::FragmentedPool) => Err(Dae::FragmentedPool),
Err(hal::pso::AllocationError::IncompatibleLayout) => {
panic!("Incompatible descriptor set layout")
}
}
}
unsafe fn dealloc_descriptor_sets<'a>(
&self,
pool: &mut B::DescriptorPool,
sets: impl Iterator<Item = B::DescriptorSet>,
) {
hal::pso::DescriptorPool::free(pool, sets)
}
}

View File

@@ -5,7 +5,12 @@
#[cfg(feature = "trace")]
use crate::device::trace;
use crate::{
device::{alloc, queue::TempResource, DeviceError},
device::{
alloc,
descriptor::{DescriptorAllocator, DescriptorSet},
queue::TempResource,
DeviceError,
},
hub::{GfxBackend, GlobalIdentityHandlerFactory, Hub, Token},
id, resource,
track::TrackerSet,
@@ -13,7 +18,6 @@ use crate::{
};
use copyless::VecHelper as _;
use gfx_descriptor::{DescriptorAllocator, DescriptorSet};
use hal::device::Device as _;
use parking_lot::Mutex;
use thiserror::Error;
@@ -159,7 +163,7 @@ impl<B: hal::Backend> NonReferencedResources<B> {
if !self.desc_sets.is_empty() {
descriptor_allocator_mutex
.lock()
.free(self.desc_sets.drain(..));
.free(device, self.desc_sets.drain(..));
}
for raw in self.compute_pipes.drain(..) {

View File

@@ -17,7 +17,6 @@ use crate::{
use arrayvec::ArrayVec;
use copyless::VecHelper as _;
use gfx_descriptor::DescriptorAllocator;
use hal::{
command::CommandBuffer as _,
device::Device as _,
@@ -41,6 +40,7 @@ use std::{
};
pub mod alloc;
pub mod descriptor;
mod life;
mod queue;
#[cfg(any(feature = "trace", feature = "replay"))]
@@ -218,7 +218,7 @@ pub struct Device<B: hal::Backend> {
pub(crate) queue_group: hal::queue::QueueGroup<B>,
pub(crate) cmd_allocator: command::CommandAllocator<B>,
mem_allocator: Mutex<alloc::MemoryAllocator<B>>,
desc_allocator: Mutex<DescriptorAllocator<B>>,
desc_allocator: Mutex<descriptor::DescriptorAllocator<B>>,
//Note: The submission index here corresponds to the last submission that is done.
pub(crate) life_guard: LifeGuard,
pub(crate) active_submission_index: SubmissionIndex,
@@ -260,7 +260,7 @@ impl<B: GfxBackend> Device<B> {
.or(Err(CreateDeviceError::OutOfMemory))?;
let mem_allocator = alloc::MemoryAllocator::new(mem_props, hal_limits);
let descriptors = unsafe { DescriptorAllocator::new() };
let descriptors = descriptor::DescriptorAllocator::new();
#[cfg(not(feature = "trace"))]
match trace_path {
Some(_) => tracing::error!("Feature 'trace' is not enabled"),
@@ -985,23 +985,51 @@ impl<B: GfxBackend> Device<B> {
label: Option<&str>,
entry_map: binding_model::BindEntryMap,
) -> Result<binding_model::BindGroupLayout<B>, binding_model::CreateBindGroupLayoutError> {
// Validate the count parameter
let mut desc_count = descriptor::DescriptorTotalCount::default();
for binding in entry_map.values() {
if binding.count.is_some() {
match binding.ty {
wgt::BindingType::Texture { .. } => {
if !self
.features
.contains(wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY)
{
return Err(binding_model::CreateBindGroupLayoutError::MissingFeature(
wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY,
));
}
use wgt::BindingType as Bt;
let (counter, array_feature) = match binding.ty {
Bt::Buffer {
ty: wgt::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: _,
} => (&mut desc_count.uniform_buffer, None),
Bt::Buffer {
ty: wgt::BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: _,
} => (&mut desc_count.uniform_buffer_dynamic, None),
Bt::Buffer {
ty: wgt::BufferBindingType::Storage { .. },
has_dynamic_offset: false,
min_binding_size: _,
} => (&mut desc_count.storage_buffer, None),
Bt::Buffer {
ty: wgt::BufferBindingType::Storage { .. },
has_dynamic_offset: true,
min_binding_size: _,
} => (&mut desc_count.storage_buffer_dynamic, None),
Bt::Sampler { .. } => (&mut desc_count.sampler, None),
Bt::Texture { .. } => (
&mut desc_count.sampled_image,
Some(wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY),
),
Bt::StorageTexture { .. } => (&mut desc_count.storage_image, None),
};
*counter += match binding.count {
// Validate the count parameter
Some(count) => {
let feature = array_feature
.ok_or(binding_model::CreateBindGroupLayoutError::ArrayUnsupported)?;
if !self.features.contains(feature) {
return Err(binding_model::CreateBindGroupLayoutError::MissingFeature(
feature,
));
}
_ => return Err(binding_model::CreateBindGroupLayoutError::ArrayUnsupported),
count.get()
}
}
None => 1,
};
}
let raw_bindings = entry_map
@@ -1015,8 +1043,6 @@ impl<B: GfxBackend> Device<B> {
stage_flags: conv::map_shader_stage_flags(entry.visibility),
immutable_samplers: false, // TODO
});
let desc_counts = raw_bindings.clone().collect();
let raw = unsafe {
let mut raw_layout = self
.raw
@@ -1046,7 +1072,7 @@ impl<B: GfxBackend> Device<B> {
ref_count: self.life_guard.add_ref(),
},
multi_ref_count: MultiRefCount::new(),
desc_counts,
desc_count,
dynamic_count: entry_map
.values()
.filter(|b| b.ty.has_dynamic_offset())
@@ -1343,17 +1369,10 @@ impl<B: GfxBackend> Device<B> {
}
}
let mut desc_sets = ArrayVec::<[_; 1]>::new();
self.desc_allocator
.lock()
.allocate(
&self.raw,
&layout.raw,
&layout.desc_counts,
1,
&mut desc_sets,
)
.expect("failed to allocate descriptor set");
let mut desc_sets =
self.desc_allocator
.lock()
.allocate(&self.raw, &layout.raw, &layout.desc_count, 1)?;
let mut desc_set = desc_sets.pop().unwrap();
// Set the descriptor set's label for easier debugging.
@@ -2156,9 +2175,9 @@ impl<B: GfxBackend> Device<B> {
impl<B: hal::Backend> Device<B> {
pub(crate) fn destroy_bind_group(&self, bind_group: binding_model::BindGroup<B>) {
unsafe {
self.desc_allocator.lock().free(iter::once(bind_group.raw));
}
self.desc_allocator
.lock()
.free(&self.raw, iter::once(bind_group.raw));
}
pub(crate) fn destroy_buffer(&self, buffer: resource::Buffer<B>) {
@@ -2195,7 +2214,7 @@ impl<B: hal::Backend> Device<B> {
.dispose(&self.raw, &self.cmd_allocator, &mut mem_alloc);
self.cmd_allocator.destroy(&self.raw);
unsafe {
desc_alloc.clear(&self.raw);
desc_alloc.cleanup(&self.raw);
mem_alloc.clear(&self.raw);
for (_, rp) in self.render_passes.lock().drain() {
self.raw.destroy_render_pass(rp);