Bug 1629605 - wgpu tracking fixes r=jgilbert

Differential Revision: https://phabricator.services.mozilla.com/D70707

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Dzmitry Malyshau 2020-04-13 22:46:31 +00:00
parent 7bcf9efc52
commit 64c80998c6
14 changed files with 353 additions and 90 deletions

View File

@ -1,5 +1,35 @@
# Change Log
## v0.5 (06-04-2020)
- Crates:
- `wgpu-types`: common types between native and web targets
- `wgpu-core`: internal API for the native and remote wrappers
- Features:
- based on gfx-hal-0.5
- moved from Rendy to the new `gfx-memory` and `gfx-descriptor` crates
- passes are now recorded on the client side. The user is also responsible to keep all resources referenced in the pass up until it ends recording.
- revised GPU lifetime tracking of all resources
- revised usage tracking logic
- all IDs are now non-zero
- Mailbox present mode
- Validation:
- active pipeline
- Fixes:
- lots of small API changes to closely match upstream WebGPU
- true read-only storage bindings
- unmapping dropped buffers
- better error messages on misused swapchain frames
## v0.4.3 (20-01-2020)
- improved swap chain error handling
## v0.4.2 (15-12-2019)
- fixed render pass transitions
## v0.4.1 (28-11-2019)
- fixed depth/stencil transitions
- fixed dynamic offset iteration
## v0.4 (03-11-2019)
- Platforms: removed OpenGL/WebGL support temporarily
- Features:

16
gfx/wgpu/Cargo.lock generated
View File

@ -653,7 +653,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wgpu-core"
version = "0.1.0"
version = "0.5.0"
dependencies = [
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"battery 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -674,12 +674,12 @@ dependencies = [
"serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"wgpu-types 0.1.0",
"wgpu-types 0.5.0",
]
[[package]]
name = "wgpu-native"
version = "0.4.0"
version = "0.5.0"
dependencies = [
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -687,8 +687,8 @@ dependencies = [
"objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"wgpu-core 0.1.0",
"wgpu-types 0.1.0",
"wgpu-core 0.5.0",
"wgpu-types 0.5.0",
]
[[package]]
@ -697,13 +697,13 @@ version = "0.1.0"
dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"wgpu-core 0.1.0",
"wgpu-types 0.1.0",
"wgpu-core 0.5.0",
"wgpu-types 0.5.0",
]
[[package]]
name = "wgpu-types"
version = "0.1.0"
version = "0.5.0"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"peek-poke 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -2,7 +2,7 @@
* 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/. */
/* Generated with cbindgen:0.14.0 */
/* Generated with cbindgen:0.14.1 */
/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
* To generate this file:
@ -37,7 +37,7 @@ typedef unsigned long long WGPUOption_TextureViewId;
#define WGPUMAX_MIP_LEVELS 16
#define WGPUMAX_VERTEX_BUFFERS 8
#define WGPUMAX_VERTEX_BUFFERS 16
typedef enum {
WGPUAddressMode_ClampToEdge = 0,

View File

@ -1,6 +1,6 @@
[package]
name = "wgpu-core"
version = "0.1.0"
version = "0.5.0"
authors = [
"Dzmitry Malyshau <kvark@mozilla.com>",
"Joshua Groves <josh@joshgroves.com>",
@ -45,7 +45,7 @@ optional = true
[dependencies.wgt]
path = "../wgpu-types"
package = "wgpu-types"
version = "0.1"
version = "0.5"
features = ["peek-poke"]
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]

View File

@ -23,15 +23,14 @@ use crate::{
use arrayvec::ArrayVec;
use hal::command::CommandBuffer as _;
use peek_poke::{Peek, PeekPoke, Poke};
use smallvec::SmallVec;
use wgt::{
BufferAddress, BufferUsage, Color, DynamicOffset, IndexFormat, InputStepMode, LoadOp,
RenderPassColorAttachmentDescriptorBase, RenderPassDepthStencilAttachmentDescriptorBase,
TextureUsage, BIND_BUFFER_ALIGNMENT,
};
use std::{
borrow::Borrow, collections::hash_map::Entry, iter, marker::PhantomData, mem, ops::Range, slice,
};
use std::{borrow::Borrow, collections::hash_map::Entry, iter, mem, ops::Range, slice};
pub type RenderPassColorAttachmentDescriptor =
RenderPassColorAttachmentDescriptorBase<id::TextureViewId>;
@ -227,7 +226,7 @@ impl VertexBufferState {
#[derive(Debug)]
pub struct VertexState {
inputs: [VertexBufferState; MAX_VERTEX_BUFFERS],
inputs: SmallVec<[VertexBufferState; MAX_VERTEX_BUFFERS]>,
vertex_limit: u32,
instance_limit: u32,
}
@ -438,7 +437,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let mut resolves = ArrayVec::new();
for at in &color_attachments {
let view = &view_guard[at.attachment];
let view = trackers
.views
.use_extend(&*view_guard, at.attachment, (), ())
.unwrap();
if let Some(ex) = extent {
assert_eq!(ex, view.extent);
} else {
@ -448,10 +450,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
view.samples, sample_count,
"All attachments must have the same sample_count"
);
let first_use = trackers
.views
.init(at.attachment, view.life_guard.add_ref(), PhantomData)
.is_ok();
let layouts = match view.inner {
TextureViewInner::Native { ref source_id, .. } => {
@ -477,10 +475,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
let end = hal::image::Layout::Present;
let start = if first_use {
hal::image::Layout::Undefined
} else {
end
let start = match base_trackers.views.query(at.attachment, ()) {
Some(_) => end,
None => hal::image::Layout::Undefined,
};
start..end
}
@ -496,16 +493,15 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
for resolve_target in color_attachments.iter().flat_map(|at| at.resolve_target) {
let view = &view_guard[resolve_target];
let view = trackers
.views
.use_extend(&*view_guard, resolve_target, (), ())
.unwrap();
assert_eq!(extent, Some(view.extent));
assert_eq!(
view.samples, 1,
"All resolve_targets must have a sample_count of 1"
);
let first_use = trackers
.views
.init(resolve_target, view.life_guard.add_ref(), PhantomData)
.is_ok();
let layouts = match view.inner {
TextureViewInner::Native { ref source_id, .. } => {
@ -531,10 +527,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
let end = hal::image::Layout::Present;
let start = if first_use {
hal::image::Layout::Undefined
} else {
end
let start = match base_trackers.views.query(resolve_target, ()) {
Some(_) => end,
None => hal::image::Layout::Undefined,
};
start..end
}
@ -798,7 +793,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
limit: 0,
},
vertex: VertexState {
inputs: [VertexBufferState::EMPTY; MAX_VERTEX_BUFFERS],
inputs: SmallVec::new(),
vertex_limit: 0,
instance_limit: 0,
},
@ -968,7 +963,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
vbs.stride = stride;
vbs.rate = rate;
}
for vbs in state.vertex.inputs[pipeline.vertex_strides.len()..].iter_mut() {
let vertex_strides_len = pipeline.vertex_strides.len();
for vbs in state.vertex.inputs.iter_mut().skip(vertex_strides_len) {
vbs.stride = 0;
vbs.rate = InputStepMode::Vertex;
}
@ -1017,6 +1013,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.use_extend(&*buffer_guard, buffer_id, (), BufferUsage::VERTEX)
.unwrap();
assert!(buffer.usage.contains(BufferUsage::VERTEX));
let empty_slots = (1 + slot as usize).saturating_sub(state.vertex.inputs.len());
state
.vertex
.inputs
.extend(iter::repeat(VertexBufferState::EMPTY).take(empty_slots));
state.vertex.inputs[slot as usize].total_size = if size != 0 {
size
} else {
@ -1158,6 +1159,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
log::trace!("Merging {:?} with the render pass", encoder_id);
unsafe {
raw.end_render_pass();
}
super::CommandBuffer::insert_barriers(
cmb.raw.last_mut().unwrap(),
&mut cmb.trackers,
@ -1167,7 +1172,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
);
unsafe {
cmb.raw.last_mut().unwrap().finish();
raw.end_render_pass();
}
cmb.raw.push(raw);
}

View File

@ -34,7 +34,7 @@ mod life;
pub const MAX_COLOR_TARGETS: usize = 4;
pub const MAX_MIP_LEVELS: usize = 16;
pub const MAX_VERTEX_BUFFERS: usize = 8;
pub const MAX_VERTEX_BUFFERS: usize = 16;
pub fn all_buffer_stages() -> hal::pso::PipelineStage {
use hal::pso::PipelineStage as Ps;
@ -1044,7 +1044,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (bind_group_layout_guard, mut token) = hub.bind_group_layouts.read(&mut token);
let bind_group_layout = &bind_group_layout_guard[desc.layout];
let entries = unsafe { slice::from_raw_parts(desc.entries, desc.entries_length) };
assert_eq!(entries.len(), bind_group_layout.entries.len());
assert_eq!(entries.len(), bind_group_layout.entries.len(), "Bind group has {} entries and bind group layout has {} entries, they should be the same.", entries.len(), bind_group_layout.entries.len());
let desc_set = unsafe {
let mut desc_sets = ArrayVec::<[_; 1]>::new();
@ -1503,6 +1503,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// execute resource transitions
let mut transit = device.com_allocator.extend(comb);
unsafe {
// the last buffer was open, closing now
comb.raw.last_mut().unwrap().finish();
transit.begin_primary(hal::command::CommandBufferFlags::ONE_TIME_SUBMIT);
}
log::trace!("Stitching command buffer {:?} before submission", cmb_id);
@ -1517,9 +1519,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
transit.finish();
}
comb.raw.insert(0, transit);
unsafe {
comb.raw.last_mut().unwrap().finish();
}
}
log::debug!("Device after submission {}: {:#?}", submit_index, trackers);

View File

@ -23,7 +23,13 @@ pub struct Id<T>(NonZeroU64, PhantomData<T>);
// required for PeekPoke
impl<T> Default for Id<T> {
fn default() -> Self {
Id(unsafe { NonZeroU64::new_unchecked(!0) }, PhantomData)
Id(
// Create an ID that doesn't make sense:
// the high `BACKEND_BITS` are to be set to 0, which matches `Backend::Empty`,
// the other bits are all 1s
unsafe { NonZeroU64::new_unchecked(!0 >> BACKEND_BITS) },
PhantomData,
)
}
}

View File

@ -55,22 +55,28 @@ impl ResourceState for BufferState {
output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
let old = self.last;
if usage != old || !BufferUsage::ORDERED.contains(usage) {
if old != usage || !BufferUsage::ORDERED.contains(usage) {
let pending = PendingTransition {
id,
selector: (),
usage: old..usage,
};
self.last = match output {
None => pending.collapse()?,
*self = match output {
None => {
assert_eq!(
self.first, None,
"extending a state that is already a transition"
);
Unit::new(pending.collapse()?)
}
Some(transitions) => {
transitions.push(pending);
if self.first.is_none() {
self.first = Some(old);
Unit {
first: self.first.or(Some(old)),
last: usage,
}
usage
}
}
};
}
Ok(())
}
@ -83,28 +89,33 @@ impl ResourceState for BufferState {
) -> Result<(), PendingTransition<Self>> {
let old = self.last;
let new = other.port();
self.last = if old == new && BufferUsage::ORDERED.contains(new) {
if self.first.is_none() {
if old == new && BufferUsage::ORDERED.contains(new) {
if output.is_some() && self.first.is_none() {
self.first = Some(old);
}
other.last
} else {
let pending = PendingTransition {
id,
selector: (),
usage: old..new,
};
match output {
None => pending.collapse()?,
*self = match output {
None => {
assert_eq!(
self.first, None,
"extending a state that is already a transition"
);
Unit::new(pending.collapse()?)
}
Some(transitions) => {
transitions.push(pending);
if self.first.is_none() {
self.first = Some(old);
Unit {
first: self.first.or(Some(old)),
last: other.last,
}
other.last
}
}
};
};
}
Ok(())
}
@ -114,19 +125,71 @@ impl ResourceState for BufferState {
#[cfg(test)]
mod test {
use super::*;
use crate::id::TypedId;
use crate::id::Id;
#[test]
fn change() {
fn change_extend() {
let mut bs = Unit {
first: Some(BufferUsage::INDEX),
first: None,
last: BufferUsage::INDEX,
};
let id = Id::default();
assert_eq!(
bs.change(id, (), BufferUsage::STORAGE, None),
Err(PendingTransition {
id,
selector: (),
usage: BufferUsage::INDEX..BufferUsage::STORAGE,
}),
);
bs.change(id, (), BufferUsage::VERTEX, None).unwrap();
bs.change(id, (), BufferUsage::INDEX, None).unwrap();
assert_eq!(bs, Unit::new(BufferUsage::VERTEX | BufferUsage::INDEX));
}
#[test]
fn change_replace() {
let mut bs = Unit {
first: None,
last: BufferUsage::STORAGE,
};
let id = TypedId::zip(1, 0, wgt::Backend::Empty);
assert!(bs.change(id, (), BufferUsage::VERTEX, None).is_err());
bs.change(id, (), BufferUsage::VERTEX, Some(&mut Vec::new()))
let id = Id::default();
let mut list = Vec::new();
bs.change(id, (), BufferUsage::VERTEX, Some(&mut list))
.unwrap();
bs.change(id, (), BufferUsage::INDEX, None).unwrap();
assert_eq!(bs.last, BufferUsage::VERTEX | BufferUsage::INDEX);
assert_eq!(
&list,
&[PendingTransition {
id,
selector: (),
usage: BufferUsage::STORAGE..BufferUsage::VERTEX,
}],
);
assert_eq!(
bs,
Unit {
first: Some(BufferUsage::STORAGE),
last: BufferUsage::VERTEX,
}
);
list.clear();
bs.change(id, (), BufferUsage::STORAGE, Some(&mut list))
.unwrap();
assert_eq!(
&list,
&[PendingTransition {
id,
selector: (),
usage: BufferUsage::VERTEX..BufferUsage::STORAGE,
}],
);
assert_eq!(
bs,
Unit {
first: Some(BufferUsage::STORAGE),
last: BufferUsage::STORAGE,
}
);
}
}

View File

@ -111,7 +111,7 @@ struct Resource<S> {
/// A structure containing all the information about a particular resource
/// transition. User code should be able to generate a pipeline barrier
/// based on the contents.
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct PendingTransition<S: ResourceState> {
pub id: S::Id,
pub selector: S::Selector,

View File

@ -9,7 +9,7 @@ use std::{cmp::Ordering, fmt::Debug, iter, ops::Range, slice::Iter};
/// Structure that keeps track of a I -> T mapping,
/// optimized for a case where keys of the same values
/// are often grouped together linearly.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct RangedStates<I, T> {
/// List of ranges, each associated with a singe value.
/// Ranges of keys have to be non-intersecting and ordered.

View File

@ -13,7 +13,7 @@ use std::{iter, ops::Range};
//TODO: store `hal::image::State` here to avoid extra conversions
type PlaneStates = RangedStates<hal::image::Layer, Unit<TextureUsage>>;
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct TextureState {
mips: ArrayVec<[PlaneStates; MAX_MIP_LEVELS]>,
/// True if we have the information about all the subresources here
@ -116,14 +116,20 @@ impl ResourceState for TextureState {
usage: unit.last..usage,
};
unit.last = match output {
None => pending.collapse()?,
*unit = match output {
None => {
assert_eq!(
unit.first, None,
"extending a state that is already a transition"
);
Unit::new(pending.collapse()?)
}
Some(ref mut out) => {
out.push(pending);
if unit.first.is_none() {
unit.first = Some(unit.last);
Unit {
first: unit.first.or(Some(unit.last)),
last: usage,
}
usage
}
};
}
@ -172,7 +178,10 @@ impl ResourceState for TextureState {
let to_usage = end.port();
if start.last == to_usage && TextureUsage::ORDERED.contains(to_usage) {
Unit {
first: start.first,
first: match output {
None => start.first,
Some(_) => start.first.or(Some(start.last)),
},
last: end.last,
}
} else {
@ -191,14 +200,18 @@ impl ResourceState for TextureState {
};
match output {
None => Unit {
first: start.first,
last: pending.collapse()?,
},
None => {
assert_eq!(
start.first, None,
"extending a state that is already a transition"
);
Unit::new(pending.collapse()?)
}
Some(ref mut out) => {
out.push(pending);
Unit {
first: Some(start.last),
// this has to leave a valid `first` state
first: start.first.or(Some(start.last)),
last: end.last,
}
}
@ -222,9 +235,9 @@ impl ResourceState for TextureState {
#[cfg(test)]
mod test {
//TODO: change() and merge() tests
//use crate::TypedId;
//TODO: change() tests
use super::*;
use crate::id::Id;
use hal::{format::Aspects, image::SubresourceRange};
#[test]
@ -274,4 +287,151 @@ mod test {
None,
);
}
#[test]
fn merge() {
let id = Id::default();
let mut ts1 = TextureState::default();
ts1.mips.push(PlaneStates::from_slice(&[(
1..3,
Unit::new(TextureUsage::SAMPLED),
)]));
let mut ts2 = TextureState::default();
assert_eq!(
ts1.merge(id, &ts2, None),
Ok(()),
"failed to merge with an empty"
);
ts2.mips.push(PlaneStates::from_slice(&[(
1..2,
Unit::new(TextureUsage::COPY_SRC),
)]));
assert_eq!(
ts1.merge(Id::default(), &ts2, None),
Ok(()),
"failed to extend a compatible state"
);
assert_eq!(
ts1.mips[0].query(&(1..2), |&v| v),
Some(Ok(Unit {
first: None,
last: TextureUsage::SAMPLED | TextureUsage::COPY_SRC,
})),
"wrong extension result"
);
ts2.mips[0] = PlaneStates::from_slice(&[(1..2, Unit::new(TextureUsage::COPY_DST))]);
assert_eq!(
ts1.clone().merge(Id::default(), &ts2, None),
Err(PendingTransition {
id,
selector: SubresourceRange {
aspects: Aspects::empty(),
levels: 0..1,
layers: 1..2,
},
usage: TextureUsage::SAMPLED | TextureUsage::COPY_SRC..TextureUsage::COPY_DST,
}),
"wrong error on extending with incompatible state"
);
let mut list = Vec::new();
ts2.mips[0] = PlaneStates::from_slice(&[
(1..2, Unit::new(TextureUsage::COPY_DST)),
(
2..3,
Unit {
first: Some(TextureUsage::COPY_SRC),
last: TextureUsage::OUTPUT_ATTACHMENT,
},
),
]);
ts1.merge(Id::default(), &ts2, Some(&mut list)).unwrap();
assert_eq!(
&list,
&[
PendingTransition {
id,
selector: SubresourceRange {
aspects: Aspects::empty(),
levels: 0..1,
layers: 1..2,
},
usage: TextureUsage::SAMPLED | TextureUsage::COPY_SRC..TextureUsage::COPY_DST,
},
PendingTransition {
id,
selector: SubresourceRange {
aspects: Aspects::empty(),
levels: 0..1,
layers: 2..3,
},
// the transition links the end of the base rage (..SAMPLED)
// with the start of the next range (COPY_SRC..)
usage: TextureUsage::SAMPLED..TextureUsage::COPY_SRC,
},
],
"replacing produced wrong transitions"
);
assert_eq!(
ts1.mips[0].query(&(1..2), |&v| v),
Some(Ok(Unit {
first: Some(TextureUsage::SAMPLED | TextureUsage::COPY_SRC),
last: TextureUsage::COPY_DST,
})),
"wrong final layer 1 state"
);
assert_eq!(
ts1.mips[0].query(&(2..3), |&v| v),
Some(Ok(Unit {
first: Some(TextureUsage::SAMPLED),
last: TextureUsage::OUTPUT_ATTACHMENT,
})),
"wrong final layer 2 state"
);
list.clear();
ts2.mips[0] = PlaneStates::from_slice(&[(
2..3,
Unit {
first: Some(TextureUsage::OUTPUT_ATTACHMENT),
last: TextureUsage::COPY_SRC,
},
)]);
ts1.merge(Id::default(), &ts2, Some(&mut list)).unwrap();
assert_eq!(&list, &[], "unexpected replacing transition");
list.clear();
ts2.mips[0] = PlaneStates::from_slice(&[(
2..3,
Unit {
first: Some(TextureUsage::COPY_DST),
last: TextureUsage::COPY_DST,
},
)]);
ts1.merge(Id::default(), &ts2, Some(&mut list)).unwrap();
assert_eq!(
&list,
&[PendingTransition {
id,
selector: SubresourceRange {
aspects: Aspects::empty(),
levels: 0..1,
layers: 2..3,
},
usage: TextureUsage::COPY_SRC..TextureUsage::COPY_DST,
},],
"invalid replacing transition"
);
assert_eq!(
ts1.mips[0].query(&(2..3), |&v| v),
Some(Ok(Unit {
// the initial state here is never expected to change
first: Some(TextureUsage::SAMPLED),
last: TextureUsage::COPY_DST,
})),
"wrong final layer 2 state"
);
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "wgpu-native"
version = "0.4.0"
version = "0.5.0"
authors = [
"Dzmitry Malyshau <kvark@mozilla.com>",
"Joshua Groves <josh@joshgroves.com>",
@ -23,12 +23,12 @@ vulkan-portability = ["core/gfx-backend-vulkan"]
[dependencies.core]
path = "../wgpu-core"
package = "wgpu-core"
version = "0.1"
version = "0.5"
[dependencies.wgt]
path = "../wgpu-types"
package = "wgpu-types"
version = "0.1"
version = "0.5"
[dependencies]
arrayvec = "0.5"

View File

@ -7,6 +7,7 @@ authors = [
]
edition = "2018"
license = "MPL-2.0"
publish = false
[lib]
# Enabling these targets makes our CI bots try to build them and fail atm
@ -18,13 +19,13 @@ default = []
[dependencies.core]
path = "../wgpu-core"
package = "wgpu-core"
version = "0.1"
version = "0.5"
features = ["serde"]
[dependencies.wgt]
path = "../wgpu-types"
package = "wgpu-types"
version = "0.1"
version = "0.5"
features = ["serde"]
[dependencies]

View File

@ -1,6 +1,6 @@
[package]
name = "wgpu-types"
version = "0.1.0"
version = "0.5.0"
authors = [
"Dzmitry Malyshau <kvark@mozilla.com>",
"Joshua Groves <josh@joshgroves.com>",