diff --git a/Cargo.lock b/Cargo.lock index 61de9c0b3..bfb3cbad4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,7 +82,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cbindgen" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1033,7 +1033,7 @@ dependencies = [ name = "wgpu-bindings" version = "0.1.0" dependencies = [ - "cbindgen 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cbindgen 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1139,7 +1139,7 @@ dependencies = [ "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" -"checksum cbindgen 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "33dfad88cda0bab90ef91c4ae338f132ba6934ea59b6e352eb96f558b5a879d7" +"checksum cbindgen 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "660a462ad3acdc79f83dcc84161d9e87f01cb29754b7ab5196785e1f0c11f714" "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..d5d3ab0db --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +RUST_BACKTRACE:=1 +EXCLUDES:= +FEATURE_RUST:= +FEATURE_NATIVE:= + +ifeq (,$(TARGET)) + CHECK_TARGET_FLAG= +else + CHECK_TARGET_FLAG=--target $(TARGET) +endif + +ifeq ($(OS),Windows_NT) + ifeq ($(TARGET),x86_64-pc-windows-gnu) + FEATURE_RUST=vulkan + FEATURE_NATIVE=gfx-backend-vulkan + else + FEATURE_RUST=dx12 + FEATURE_NATIVE=gfx-backend-dx12 + endif +else + UNAME_S:=$(shell uname -s) + ifeq ($(UNAME_S),Linux) + FEATURE_RUST=vulkan + FEATURE_NATIVE=gfx-backend-vulkan + endif + ifeq ($(UNAME_S),Darwin) + FEATURE_RUST=metal + FEATURE_NATIVE=gfx-backend-metal + endif +endif + + +.PHONY: all check test doc clear lib-native lib-rust examples-native examples-rust + +all: examples-native examples-rust + +check: + cargo check --all + +test: + cargo test --all --features "$(FEATURE_NATIVE) $(FEATURE_RUST)" + +doc: + cargo doc --all + +clear: + cargo clear + rm wgpu-bindings/wgpu.h + +lib-native: Cargo.lock wgpu-native/Cargo.toml $(wildcard wgpu-native/**/*.rs) + cargo build --manifest-path wgpu-native/Cargo.toml --features $(FEATURE_NATIVE) + +lib-rust: Cargo.lock wgpu-rs/Cargo.toml $(wildcard wgpu-rs/**/*.rs) + cargo build --manifest-path wgpu-rs/Cargo.toml --features $(FEATURE_RUST) + +wgpu-bindings/wgpu.h: Cargo.lock wgpu-bindings/src/*.rs lib-native + cargo +nightly run --manifest-path wgpu-bindings/Cargo.toml + +examples-native: lib-native wgpu-bindings/wgpu.h $(wildcard wgpu-native/**/*.c) + $(MAKE) -C examples + +examples-rust: lib-rust examples/Cargo.toml $(wildcard wgpu-native/**/*.rs) + cargo build --manifest-path examples/Cargo.toml --bin hello_triangle --features $(FEATURE_RUST) diff --git a/examples/hello_triangle_c/main.c b/examples/hello_triangle_c/main.c index 6b9f534c7..1765fdcf6 100644 --- a/examples/hello_triangle_c/main.c +++ b/examples/hello_triangle_c/main.c @@ -40,7 +40,7 @@ int main() .bindings_length = 0, }; WGPUBindGroupLayoutId _bind_group_layout = wgpu_device_create_bind_group_layout(device, &bind_group_layout_desc); - + WGPUPipelineLayoutDescriptor pipeline_layout_desc = { .bind_group_layouts = NULL, .bind_group_layouts_length = 0, @@ -116,7 +116,7 @@ int main() .formats_length = FORMATS_LENGTH, }; WGPUAttachmentStateId attachment_state = wgpu_device_create_attachment_state(device, &attachment_state_desc); - + WGPURenderPipelineDescriptor render_pipeline_desc = { .layout = layout, .stages = stages, diff --git a/wgpu-bindings/Cargo.toml b/wgpu-bindings/Cargo.toml index 7ab66cfdb..a2eb27916 100644 --- a/wgpu-bindings/Cargo.toml +++ b/wgpu-bindings/Cargo.toml @@ -10,4 +10,4 @@ authors = [ default = [] [dependencies] -cbindgen = "0.6.3" +cbindgen = "0.6.6" diff --git a/wgpu-bindings/src/main.rs b/wgpu-bindings/src/main.rs index 42a5d402f..02f719a07 100644 --- a/wgpu-bindings/src/main.rs +++ b/wgpu-bindings/src/main.rs @@ -11,8 +11,8 @@ const HEADER: &str = " "; fn main() { - let mut crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - crate_dir.push("../wgpu-native"); + let crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let source_dir = crate_dir.parent().unwrap().join("wgpu-native"); let config = cbindgen::Config { header: Some(String::from(HEADER.trim())), @@ -33,9 +33,10 @@ fn main() { }; cbindgen::Builder::new() - .with_crate(crate_dir) + .with_crate(source_dir) .with_config(config) + .with_parse_expand(&["wgpu-native"]) .generate() .unwrap() - .write_to_file("wgpu.h"); + .write_to_file(crate_dir.join("wgpu.h")); } diff --git a/wgpu-bindings/wgpu.h b/wgpu-bindings/wgpu.h index 11fc5b373..bfa5e1530 100644 --- a/wgpu-bindings/wgpu.h +++ b/wgpu-bindings/wgpu.h @@ -28,20 +28,6 @@ #define WGPUShaderStageFlags_VERTEX 1 -#define WGPUTextureUsageFlags_NONE 0 - -#define WGPUTextureUsageFlags_OUTPUT_ATTACHMENT 16 - -#define WGPUTextureUsageFlags_PRESENT 32 - -#define WGPUTextureUsageFlags_SAMPLED 4 - -#define WGPUTextureUsageFlags_STORAGE 8 - -#define WGPUTextureUsageFlags_TRANSFER_DST 2 - -#define WGPUTextureUsageFlags_TRANSFER_SRC 1 - typedef enum { WGPUBindingType_UniformBuffer = 0, WGPUBindingType_Sampler = 1, @@ -276,12 +262,40 @@ typedef struct { #define WGPUBLUE (Color){ .r = 0, .g = 0, .b = 1, .a = 1 } +#define WGPUEXTEND (TrackPermit){ .bits = 1 } + #define WGPUGREEN (Color){ .r = 0, .g = 1, .b = 0, .a = 1 } +#define WGPUINDEX (BufferUsageFlags){ .bits = 16 } + +#define WGPUMAP_READ (BufferUsageFlags){ .bits = 1 } + +#define WGPUMAP_WRITE (BufferUsageFlags){ .bits = 2 } + +#define WGPUNONE (BufferUsageFlags){ .bits = 0 } + +#define WGPUOUTPUT_ATTACHMENT (TextureUsageFlags){ .bits = 16 } + +#define WGPUPRESENT (TextureUsageFlags){ .bits = 32 } + #define WGPURED (Color){ .r = 1, .g = 0, .b = 0, .a = 1 } +#define WGPUREPLACE (TrackPermit){ .bits = 2 } + +#define WGPUSAMPLED (TextureUsageFlags){ .bits = 4 } + +#define WGPUSTORAGE (BufferUsageFlags){ .bits = 128 } + +#define WGPUTRANSFER_DST (BufferUsageFlags){ .bits = 8 } + +#define WGPUTRANSFER_SRC (BufferUsageFlags){ .bits = 4 } + #define WGPUTRANSPARENT (Color){ .r = 0, .g = 0, .b = 0, .a = 0 } +#define WGPUUNIFORM (BufferUsageFlags){ .bits = 64 } + +#define WGPUVERTEX (BufferUsageFlags){ .bits = 32 } + #define WGPUWHITE (Color){ .r = 1, .g = 1, .b = 1, .a = 1 } WGPUDeviceId wgpu_adapter_create_device(WGPUAdapterId adapter_id, diff --git a/wgpu-native/src/command/allocator.rs b/wgpu-native/src/command/allocator.rs index 6c45be2c2..d37b4e5e4 100644 --- a/wgpu-native/src/command/allocator.rs +++ b/wgpu-native/src/command/allocator.rs @@ -1,5 +1,6 @@ use super::CommandBuffer; use {DeviceId, Stored}; +use track::{Tracker}; use hal::command::RawCommandBuffer; use hal::pool::RawCommandPool; @@ -12,14 +13,37 @@ use std::thread; struct CommandPool { raw: B::CommandPool, - available: Vec>, + available: Vec, +} + +impl CommandPool { + fn allocate(&mut self) -> B::CommandBuffer { + if self.available.is_empty() { + let extra = self.raw.allocate(20, hal::command::RawLevel::Primary); + self.available.extend(extra); + } + + self.available.pop().unwrap() + } } struct Inner { pools: HashMap>, + fences: Vec, pending: Vec>, } +impl Inner { + fn recycle(&mut self, cmd_buf: CommandBuffer) { + let pool = self.pools.get_mut(&cmd_buf.recorded_thread_id).unwrap(); + for mut raw in cmd_buf.raw { + raw.reset(false); + pool.available.push(raw); + } + self.fences.push(cmd_buf.fence); + } +} + pub struct CommandAllocator { queue_family: hal::queue::QueueFamilyId, inner: Mutex>, @@ -31,6 +55,7 @@ impl CommandAllocator { queue_family, inner: Mutex::new(Inner { pools: HashMap::new(), + fences: Vec::new(), pending: Vec::new(), }), } @@ -41,6 +66,17 @@ impl CommandAllocator { ) -> CommandBuffer { let thread_id = thread::current().id(); let mut inner = self.inner.lock().unwrap(); + + let fence = match inner.fences.pop() { + Some(fence) => { + device.reset_fence(&fence); + fence + } + None => { + device.create_fence(false) + } + }; + let pool = inner.pools.entry(thread_id).or_insert_with(|| CommandPool { raw: device.create_command_pool( self.queue_family, @@ -48,21 +84,27 @@ impl CommandAllocator { ), available: Vec::new(), }); + let init = pool.allocate(); - if let Some(cmd_buf) = pool.available.pop() { - assert_eq!(device_id, cmd_buf.device_id.0); - device.reset_fence(&cmd_buf.fence); - return cmd_buf; + CommandBuffer { + raw: vec![init], + fence, + recorded_thread_id: thread_id, + device_id: Stored(device_id), + buffer_tracker: Tracker::new(), + texture_tracker: Tracker::new(), + } + } + + pub fn extend(&self, cmd_buf: &CommandBuffer) -> B::CommandBuffer { + let mut inner = self.inner.lock().unwrap(); + let pool = inner.pools.get_mut(&cmd_buf.recorded_thread_id).unwrap(); + + if pool.available.is_empty() { + let extra = pool.raw.allocate(20, hal::command::RawLevel::Primary); + pool.available.extend(extra); } - for cmbuf in pool.raw.allocate(20, hal::command::RawLevel::Primary) { - pool.available.push(CommandBuffer { - raw: Some(cmbuf), - fence: device.create_fence(false), - recorded_thread_id: thread_id, - device_id: Stored(device_id), - }); - } pool.available.pop().unwrap() } @@ -70,16 +112,8 @@ impl CommandAllocator { self.inner.lock().unwrap().pending.push(cmd_buf); } - pub fn recycle(&self, mut cmd_buf: CommandBuffer) { - cmd_buf.raw.as_mut().unwrap().reset(false); - self.inner - .lock() - .unwrap() - .pools - .get_mut(&cmd_buf.recorded_thread_id) - .unwrap() - .available - .push(cmd_buf); + pub fn recycle(&self, cmd_buf: CommandBuffer) { + self.inner.lock().unwrap().recycle(cmd_buf); } pub fn maintain(&self, device: &B::Device) { @@ -87,12 +121,7 @@ impl CommandAllocator { for i in (0..inner.pending.len()).rev() { if device.get_fence_status(&inner.pending[i].fence) { let cmd_buf = inner.pending.swap_remove(i); - inner - .pools - .get_mut(&cmd_buf.recorded_thread_id) - .unwrap() - .available - .push(cmd_buf); + inner.recycle(cmd_buf); } } } diff --git a/wgpu-native/src/command/compute.rs b/wgpu-native/src/command/compute.rs index 3f96a1774..05bcc7703 100644 --- a/wgpu-native/src/command/compute.rs +++ b/wgpu-native/src/command/compute.rs @@ -35,7 +35,8 @@ pub extern "C" fn wgpu_compute_pass_end_pass( HUB.command_buffers .lock() .get_mut(pass.cmb_id.0) - .raw = Some(pass.raw); + .raw + .push(pass.raw); pass.cmb_id.0 } diff --git a/wgpu-native/src/command/mod.rs b/wgpu-native/src/command/mod.rs index 25c44a745..14bdbcf89 100644 --- a/wgpu-native/src/command/mod.rs +++ b/wgpu-native/src/command/mod.rs @@ -13,9 +13,11 @@ use { BufferId, CommandBufferId, ComputePassId, DeviceId, RenderPassId, TextureId, TextureViewId, }; use registry::{HUB, Items, Registry}; +use track::{BufferTracker, TextureTracker}; use std::thread::ThreadId; + #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub enum LoadOp { @@ -72,10 +74,12 @@ pub struct TextureCopyView { } pub struct CommandBuffer { - pub(crate) raw: Option, + pub(crate) raw: Vec, fence: B::Fence, recorded_thread_id: ThreadId, device_id: Stored, + buffer_tracker: BufferTracker, + texture_tracker: TextureTracker, } #[repr(C)] @@ -89,10 +93,10 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass( let mut cmb_guard = HUB.command_buffers.lock(); let cmb = cmb_guard.get_mut(command_buffer_id); - let raw = cmb.raw.take().unwrap(); - let device_guard = HUB.devices.lock(); - let _device = &device_guard.get(cmb.device_id.0).raw; + let device = device_guard.get(cmb.device_id.0); + + let current_comb = device.com_allocator.extend(cmb); //let render_pass = device.create_render_pass(); //let framebuffer = device.create_framebuffer(); @@ -108,7 +112,10 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass( HUB.render_passes .lock() - .register(RenderPass::new(raw, command_buffer_id)) + .register(RenderPass::new( + current_comb, + command_buffer_id, + )) } #[no_mangle] @@ -118,7 +125,7 @@ pub extern "C" fn wgpu_command_buffer_begin_compute_pass( let mut cmb_guard = HUB.command_buffers.lock(); let cmb = cmb_guard.get_mut(command_buffer_id); - let raw = cmb.raw.take().unwrap(); + let raw = cmb.raw.pop().unwrap(); HUB.compute_passes .lock() diff --git a/wgpu-native/src/command/render.rs b/wgpu-native/src/command/render.rs index 79dcd91da..88aa3310b 100644 --- a/wgpu-native/src/command/render.rs +++ b/wgpu-native/src/command/render.rs @@ -1,4 +1,6 @@ +use conv; use registry::{HUB, Items, Registry}; +use track::{BufferTracker, TextureTracker}; use { Stored, CommandBufferId, RenderPassId, @@ -11,13 +13,20 @@ use hal::command::RawCommandBuffer; pub struct RenderPass { raw: B::CommandBuffer, cmb_id: Stored, + buffer_tracker: BufferTracker, + texture_tracker: TextureTracker, } impl RenderPass { - pub fn new(raw: B::CommandBuffer, cmb_id: CommandBufferId) -> Self { + pub fn new( + raw: B::CommandBuffer, + cmb_id: CommandBufferId, + ) -> Self { RenderPass { raw, cmb_id: Stored(cmb_id), + buffer_tracker: BufferTracker::new(), + texture_tracker: TextureTracker::new(), } } } @@ -31,9 +40,43 @@ pub extern "C" fn wgpu_render_pass_end_pass( .take(pass_id); pass.raw.end_render_pass(); - HUB.command_buffers - .lock() - .get_mut(pass.cmb_id.0) - .raw = Some(pass.raw); + let buffer_guard = HUB.buffers.lock(); + let texture_guard = HUB.textures.lock(); + let mut cmb_guard = HUB.command_buffers.lock(); + let cmb = cmb_guard.get_mut(pass.cmb_id.0); + + let buffer_barriers = cmb.buffer_tracker + .consume(pass.buffer_tracker) + .map(|(id, transit)| { + let b = buffer_guard.get(id); + hal::memory::Barrier::Buffer { + states: conv::map_buffer_state(transit.start) .. + conv::map_buffer_state(transit.end), + target: &b.raw, + } + }); + let texture_barriers = cmb.texture_tracker + .consume(pass.texture_tracker) + .map(|(id, transit)| { + let t = texture_guard.get(id); + hal::memory::Barrier::Image { + states: conv::map_texture_state(transit.start, t.aspects) .. + conv::map_texture_state(transit.end, t.aspects), + target: &t.raw, + range: hal::image::SubresourceRange { //TODO! + aspects: t.aspects, + levels: 0 .. 1, + layers: 0 .. 1, + }, + } + }); + + pass.raw.pipeline_barrier( + hal::pso::PipelineStage::TOP_OF_PIPE .. hal::pso::PipelineStage::BOTTOM_OF_PIPE, + hal::memory::Dependencies::empty(), + buffer_barriers.chain(texture_barriers), + ); + + cmb.raw.push(pass.raw); pass.cmb_id.0 } diff --git a/wgpu-native/src/conv.rs b/wgpu-native/src/conv.rs index 4708c7464..c266e1e8f 100644 --- a/wgpu-native/src/conv.rs +++ b/wgpu-native/src/conv.rs @@ -2,7 +2,8 @@ use hal; use {Extent3d, binding_model, pipeline, resource}; -pub(crate) fn map_buffer_usage( + +pub fn map_buffer_usage( usage: resource::BufferUsageFlags, ) -> (hal::buffer::Usage, hal::memory::Properties) { use hal::buffer::Usage as U; @@ -40,7 +41,38 @@ pub(crate) fn map_buffer_usage( (hal_usage, hal_memory) } -pub(crate) fn map_binding_type( +pub fn map_texture_usage( + usage: resource::TextureUsageFlags, aspects: hal::format::Aspects +) -> hal::image::Usage { + use hal::image::Usage as U; + use resource::TextureUsageFlags as W; + + let mut value = U::empty(); + if usage.contains(W::TRANSFER_SRC) { + value |= U::TRANSFER_SRC; + } + if usage.contains(W::TRANSFER_DST) { + value |= U::TRANSFER_DST; + } + if usage.contains(W::SAMPLED) { + value |= U::SAMPLED; + } + if usage.contains(W::STORAGE) { + value |= U::STORAGE; + } + if usage.contains(W::OUTPUT_ATTACHMENT) { + if aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) { + value |= U::DEPTH_STENCIL_ATTACHMENT; + } else { + value |= U::COLOR_ATTACHMENT; + } + } + // Note: TextureUsageFlags::Present does not need to be handled explicitly + // TODO: HAL Transient Attachment, HAL Input Attachment + value +} + +pub fn map_binding_type( binding_ty: binding_model::BindingType, ) -> hal::pso::DescriptorType { use binding_model::BindingType::*; @@ -53,7 +85,7 @@ pub(crate) fn map_binding_type( } } -pub(crate) fn map_shader_stage_flags( +pub fn map_shader_stage_flags( shader_stage_flags: binding_model::ShaderStageFlags, ) -> hal::pso::ShaderStageFlags { use binding_model::{ @@ -73,7 +105,7 @@ pub(crate) fn map_shader_stage_flags( value } -pub(crate) fn map_primitive_topology( +pub fn map_primitive_topology( primitive_topology: pipeline::PrimitiveTopology, ) -> hal::Primitive { use hal::Primitive as H; @@ -87,7 +119,7 @@ pub(crate) fn map_primitive_topology( } } -pub(crate) fn map_blend_state_descriptor( +pub fn map_blend_state_descriptor( desc: &pipeline::BlendStateDescriptor, ) -> hal::pso::ColorBlendDesc { let color_mask = desc.write_mask; @@ -164,7 +196,7 @@ fn map_blend_factor(blend_factor: pipeline::BlendFactor) -> hal::pso::Factor { } } -pub(crate) fn map_depth_stencil_state( +pub fn map_depth_stencil_state( desc: &pipeline::DepthStencilStateDescriptor, ) -> hal::pso::DepthStencilDesc { hal::pso::DepthStencilDesc { @@ -228,7 +260,7 @@ fn map_stencil_operation(stencil_operation: pipeline::StencilOperation) -> hal:: } } -pub(crate) fn map_texture_format(texture_format: resource::TextureFormat) -> hal::format::Format { +pub fn map_texture_format(texture_format: resource::TextureFormat) -> hal::format::Format { use hal::format::Format as H; use resource::TextureFormat::*; match texture_format { @@ -244,7 +276,9 @@ fn checked_u32_as_u16(value: u32) -> u16 { value as u16 } -pub(crate) fn map_texture_dimension_size(dimension: resource::TextureDimension, size: Extent3d) -> hal::image::Kind { +pub fn map_texture_dimension_size( + dimension: resource::TextureDimension, size: Extent3d +) -> hal::image::Kind { use hal::image::Kind as H; use resource::TextureDimension::*; let Extent3d { width, height, depth } = size; @@ -258,33 +292,69 @@ pub(crate) fn map_texture_dimension_size(dimension: resource::TextureDimension, } } -pub(crate) fn map_texture_usage_flags(flags: u32, format: hal::format::Format) -> hal::image::Usage { - use hal::image::Usage as H; - use resource::{ - TextureUsageFlags_TRANSFER_SRC, TextureUsageFlags_TRANSFER_DST, TextureUsageFlags_SAMPLED, - TextureUsageFlags_STORAGE, TextureUsageFlags_OUTPUT_ATTACHMENT, - }; - let mut value = H::empty(); - if 0 != flags & TextureUsageFlags_TRANSFER_SRC { - value |= H::TRANSFER_SRC; +pub fn map_buffer_state( + usage: resource::BufferUsageFlags, +) -> hal::buffer::State { + use hal::buffer::Access as A; + use resource::BufferUsageFlags as W; + + let mut access = A::empty(); + if usage.contains(W::TRANSFER_SRC) { + access |= A::TRANSFER_READ; } - if 0 != flags & TextureUsageFlags_TRANSFER_DST { - value |= H::TRANSFER_DST; + if usage.contains(W::TRANSFER_DST) { + access |= A::TRANSFER_WRITE; } - if 0 != flags & TextureUsageFlags_SAMPLED { - value |= H::SAMPLED; + if usage.contains(W::INDEX) { + access |= A::INDEX_BUFFER_READ; } - if 0 != flags & TextureUsageFlags_STORAGE { - value |= H::STORAGE; + if usage.contains(W::VERTEX) { + access |= A::VERTEX_BUFFER_READ; } - if 0 != flags & TextureUsageFlags_OUTPUT_ATTACHMENT { - if format.surface_desc().aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) { - value |= H::DEPTH_STENCIL_ATTACHMENT; - } else { - value |= H::COLOR_ATTACHMENT; - } + if usage.contains(W::UNIFORM) { + access |= A::CONSTANT_BUFFER_READ | A::SHADER_READ; } - // Note: TextureUsageFlags::Present does not need to be handled explicitly - // TODO: HAL Transient Attachment, HAL Input Attachment - value + if usage.contains(W::STORAGE) { + access |= A::SHADER_WRITE; + } + + access +} + +pub fn map_texture_state( + usage: resource::TextureUsageFlags, + aspects: hal::format::Aspects, +) -> hal::image::State { + use hal::image::{Access as A, Layout as L}; + use resource::TextureUsageFlags as W; + + let is_color = aspects.contains(hal::format::Aspects::COLOR); + let layout = match usage { + W::TRANSFER_SRC => L::TransferSrcOptimal, + W::TRANSFER_DST => L::TransferDstOptimal, + W::SAMPLED => L::ShaderReadOnlyOptimal, + W::OUTPUT_ATTACHMENT if is_color => L::ColorAttachmentOptimal, + W::OUTPUT_ATTACHMENT => L::DepthStencilAttachmentOptimal, //TODO: read-only depth/stencil + _ => L::General, + }; + + let mut access = A::empty(); + if usage.contains(W::TRANSFER_SRC) { + access |= A::TRANSFER_READ; + } + if usage.contains(W::TRANSFER_DST) { + access |= A::TRANSFER_WRITE; + } + if usage.contains(W::SAMPLED) { + access |= A::SHADER_READ; + } + if usage.contains(W::STORAGE) { + access |= A::SHADER_WRITE; + } + if usage.contains(W::OUTPUT_ATTACHMENT) { + //TODO: read-only attachments + access |= if is_color { A::COLOR_ATTACHMENT_WRITE } else { A::DEPTH_STENCIL_ATTACHMENT_WRITE }; + } + + (access, layout) } diff --git a/wgpu-native/src/device.rs b/wgpu-native/src/device.rs index d2185a235..3c7c4e6ad 100644 --- a/wgpu-native/src/device.rs +++ b/wgpu-native/src/device.rs @@ -1,5 +1,6 @@ use {back, binding_model, command, conv, pipeline, resource}; use registry::{HUB, Items, Registry}; +use track::{BufferTracker, TextureTracker, TrackPermit}; use { AttachmentStateId, BindGroupLayoutId, BlendStateId, CommandBufferId, DepthStencilStateId, DeviceId, PipelineLayoutId, QueueId, RenderPipelineId, ShaderModuleId, TextureId, @@ -8,16 +9,19 @@ use { use hal::command::RawCommandBuffer; use hal::queue::RawCommandQueue; use hal::{self, Device as _Device}; +use rendy_memory::{allocator, Config, Heaps}; use std::{ffi, slice}; -use rendy_memory::{allocator, Config, Heaps}; +use std::sync::Mutex; pub struct Device { pub(crate) raw: B::Device, queue_group: hal::QueueGroup, mem_allocator: Heaps, - com_allocator: command::CommandAllocator, + pub(crate) com_allocator: command::CommandAllocator, + buffer_tracker: Mutex, + texture_tracker: Mutex, mem_props: hal::MemoryProperties, } @@ -53,6 +57,8 @@ impl Device { mem_allocator, com_allocator: command::CommandAllocator::new(queue_group.family()), queue_group, + buffer_tracker: Mutex::new(BufferTracker::new()), + texture_tracker: Mutex::new(TextureTracker::new()), mem_props, } } @@ -69,7 +75,8 @@ pub extern "C" fn wgpu_device_create_texture( ) -> TextureId { let kind = conv::map_texture_dimension_size(desc.dimension, desc.size); let format = conv::map_texture_format(desc.format); - let usage = conv::map_texture_usage_flags(desc.usage, format); + let aspects = format.surface_desc().aspects; + let usage = conv::map_texture_usage(desc.usage, aspects); let device_guard = HUB.devices.lock(); let device = &device_guard.get(device_id); let image_unbound = device @@ -101,11 +108,20 @@ pub extern "C" fn wgpu_device_create_texture( .raw .bind_image_memory(&image_memory, 0, image_unbound) .unwrap(); - HUB.textures + + let id = HUB.textures .lock() .register(resource::Texture { raw: bound_image, - }) + aspects, + }); + device.texture_tracker + .lock() + .unwrap() + .track(id, resource::TextureUsageFlags::empty(), TrackPermit::empty()) + .expect("Resource somehow is already registered"); + + id } #[no_mangle] @@ -215,11 +231,11 @@ pub extern "C" fn wgpu_device_create_command_buffer( device_id: DeviceId, _desc: &command::CommandBufferDescriptor, ) -> CommandBufferId { - let mut device_guard = HUB.devices.lock(); - let device = device_guard.get_mut(device_id); + let device_guard = HUB.devices.lock(); + let device = device_guard.get(device_id); let mut cmd_buf = device.com_allocator.allocate(device_id, &device.raw); - cmd_buf.raw.as_mut().unwrap().begin( + cmd_buf.raw.last_mut().unwrap().begin( hal::command::CommandBufferFlags::ONE_TIME_SUBMIT, hal::command::CommandBufferInheritanceInfo::default(), ); @@ -249,7 +265,7 @@ pub extern "C" fn wgpu_queue_submit( command_buffer_guard .get_mut(cmb_id) .raw - .as_mut() + .last_mut() .unwrap() .finish(); } @@ -259,12 +275,8 @@ pub extern "C" fn wgpu_queue_submit( let submission = hal::queue::RawSubmission { cmd_buffers: command_buffer_ids .iter() - .map(|&cmb_id| { - command_buffer_guard - .get(cmb_id) - .raw - .as_ref() - .unwrap() + .flat_map(|&cmb_id| { + &command_buffer_guard.get(cmb_id).raw }), wait_semaphores: &[], signal_semaphores: &[], diff --git a/wgpu-native/src/lib.rs b/wgpu-native/src/lib.rs index 9d3248aa5..f1705c5bb 100644 --- a/wgpu-native/src/lib.rs +++ b/wgpu-native/src/lib.rs @@ -29,6 +29,7 @@ mod instance; mod pipeline; mod registry; mod resource; +mod track; pub use self::binding_model::*; pub use self::command::*; @@ -40,7 +41,7 @@ pub use self::resource::*; use back::Backend as B; use registry::Id; -#[derive(Debug, PartialEq)] +#[derive(Debug, Hash, PartialEq, Eq)] struct Stored(T); #[cfg(not(feature = "remote"))] unsafe impl Sync for Stored {} @@ -95,6 +96,7 @@ pub type DeviceId = Id; type DeviceHandle = Device; pub type QueueId = Id; pub type BufferId = Id; +type BufferHandle = Buffer; // Resource pub type TextureViewId = Id; diff --git a/wgpu-native/src/registry/mod.rs b/wgpu-native/src/registry/mod.rs index ca9a32b5c..935732323 100644 --- a/wgpu-native/src/registry/mod.rs +++ b/wgpu-native/src/registry/mod.rs @@ -13,7 +13,7 @@ use { BlendStateHandle, CommandBufferHandle, DepthStencilStateHandle, DeviceHandle, InstanceHandle, RenderPassHandle, ComputePassHandle, PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle, - TextureHandle, + BufferHandle, TextureHandle, }; @@ -48,6 +48,7 @@ pub struct Hub { pub(crate) compute_pipelines: ConcreteRegistry, pub(crate) render_passes: ConcreteRegistry, pub(crate) compute_passes: ConcreteRegistry, + pub(crate) buffers: ConcreteRegistry, pub(crate) textures: ConcreteRegistry, } diff --git a/wgpu-native/src/resource.rs b/wgpu-native/src/resource.rs index 884a1d3a3..14df48e7a 100644 --- a/wgpu-native/src/resource.rs +++ b/wgpu-native/src/resource.rs @@ -1,11 +1,11 @@ +use {Extent3d}; + use hal; -use Extent3d; bitflags! { #[repr(transparent)] pub struct BufferUsageFlags: u32 { - const NONE = 0; const MAP_READ = 1; const MAP_WRITE = 2; const TRANSFER_SRC = 4; @@ -14,6 +14,8 @@ bitflags! { const VERTEX = 32; const UNIFORM = 64; const STORAGE = 128; + const NONE = 0; + const WRITE_ALL = 2 + 8 + 128; } } @@ -23,9 +25,10 @@ pub struct BufferDescriptor { pub usage: BufferUsageFlags, } -pub struct Buffer { - pub(crate) raw: B::UnboundBuffer, - pub(crate) memory_properties: hal::memory::Properties, +pub(crate) struct Buffer { + //pub raw: B::UnboundBuffer, + pub raw: B::Buffer, + pub memory_properties: hal::memory::Properties, // TODO: mapping, unmap() } @@ -50,22 +53,19 @@ pub enum TextureFormat { D32FloatS8Uint = 3, } -// TODO: bitflags -pub type TextureUsageFlags = u32; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_NONE: u32 = 0; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_TRANSFER_SRC: u32 = 1; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_TRANSFER_DST: u32 = 2; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_SAMPLED: u32 = 4; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_STORAGE: u32 = 8; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_OUTPUT_ATTACHMENT: u32 = 16; -#[allow(non_upper_case_globals)] -pub const TextureUsageFlags_PRESENT: u32 = 32; +bitflags! { + #[repr(transparent)] + pub struct TextureUsageFlags: u32 { + const TRANSFER_SRC = 1; + const TRANSFER_DST = 2; + const SAMPLED = 4; + const STORAGE = 8; + const OUTPUT_ATTACHMENT = 16; + const PRESENT = 32; + const NONE = 0; + const WRITE_ALL = 2 + 8 + 16; + } +} #[repr(C)] pub struct TextureDescriptor { @@ -76,8 +76,9 @@ pub struct TextureDescriptor { pub usage: TextureUsageFlags, } -pub struct Texture { - pub(crate) raw: B::Image, +pub(crate) struct Texture { + pub raw: B::Image, + pub aspects: hal::format::Aspects, } #[repr(C)] diff --git a/wgpu-native/src/track.rs b/wgpu-native/src/track.rs new file mode 100644 index 000000000..752e06116 --- /dev/null +++ b/wgpu-native/src/track.rs @@ -0,0 +1,88 @@ +use {Stored, BufferId, TextureId}; +use resource::{BufferUsageFlags, TextureUsageFlags}; + +use std::collections::hash_map::{Entry, HashMap}; +use std::hash::Hash; +use std::ops::{BitOr, Range}; + + +#[derive(Clone, Debug, PartialEq)] +pub enum Tracktion { + Init, + Keep, + Extend { old: T }, + Replace { old: T }, +} + +bitflags! { + pub struct TrackPermit: u32 { + const EXTEND = 1; + const REPLACE = 2; + } +} + + +pub trait GenericUsage { + fn is_exclusive(&self) -> bool; +} +impl GenericUsage for BufferUsageFlags { + fn is_exclusive(&self) -> bool { + BufferUsageFlags::WRITE_ALL.intersects(*self) + } +} +impl GenericUsage for TextureUsageFlags { + fn is_exclusive(&self) -> bool { + TextureUsageFlags::WRITE_ALL.intersects(*self) + } +} + + +pub struct Tracker { + map: HashMap, U>, +} +pub type BufferTracker = Tracker; +pub type TextureTracker = Tracker; + +impl< + I: Clone + Hash + Eq, + U: Copy + GenericUsage + BitOr + PartialEq, +> Tracker { + pub fn new() -> Self { + Tracker { + map: HashMap::new(), + } + } + + pub fn track(&mut self, id: I, usage: U, permit: TrackPermit) -> Result, U> { + match self.map.entry(Stored(id)) { + Entry::Vacant(e) => { + e.insert(usage); + Ok(Tracktion::Init) + } + Entry::Occupied(mut e) => { + let old = *e.get(); + if usage == old { + Ok(Tracktion::Keep) + } else if permit.contains(TrackPermit::EXTEND) && !(old | usage).is_exclusive() { + Ok(Tracktion::Extend { old: e.insert(old | usage) }) + } else if permit.contains(TrackPermit::REPLACE) { + Ok(Tracktion::Replace { old: e.insert(usage) }) + } else { + Err(old) + } + } + } + } + + pub(crate) fn consume<'a>(&'a mut self, other: Self) -> impl 'a + Iterator)> { + other.map + .into_iter() + .flat_map(move |(id, new)| match self.track(id.0.clone(), new, TrackPermit::REPLACE) { + Ok(Tracktion::Init) | + Ok(Tracktion::Keep) => None, + Ok(Tracktion::Replace { old }) => Some((id.0, old .. new)), + Ok(Tracktion::Extend { .. }) | + Err(_) => panic!("Unable to consume a resource transition!"), + }) + } +}