23: State transitions for a render pass r=grovesNL a=kvark

This PR introduces a simple resource tracker, which is used to build the pipeline barriers gluing the main command buffer with the one composed for the render pass contents. Render passes are still not started properly, blocked on the W3C discussion about the parameters.

Co-authored-by: Dzmitry Malyshau <dmalyshau@mozilla.com>
This commit is contained in:
bors[bot] 2018-10-23 14:54:10 +00:00
commit 23e32b41a0
16 changed files with 469 additions and 137 deletions

6
Cargo.lock generated
View File

@ -82,7 +82,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "cbindgen" name = "cbindgen"
version = "0.6.4" version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1033,7 +1033,7 @@ dependencies = [
name = "wgpu-bindings" name = "wgpu-bindings"
version = "0.1.0" version = "0.1.0"
dependencies = [ 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]] [[package]]
@ -1139,7 +1139,7 @@ dependencies = [
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "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 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 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 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 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" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"

63
Makefile Normal file
View File

@ -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)

View File

@ -40,7 +40,7 @@ int main()
.bindings_length = 0, .bindings_length = 0,
}; };
WGPUBindGroupLayoutId _bind_group_layout = wgpu_device_create_bind_group_layout(device, &bind_group_layout_desc); WGPUBindGroupLayoutId _bind_group_layout = wgpu_device_create_bind_group_layout(device, &bind_group_layout_desc);
WGPUPipelineLayoutDescriptor pipeline_layout_desc = { WGPUPipelineLayoutDescriptor pipeline_layout_desc = {
.bind_group_layouts = NULL, .bind_group_layouts = NULL,
.bind_group_layouts_length = 0, .bind_group_layouts_length = 0,
@ -116,7 +116,7 @@ int main()
.formats_length = FORMATS_LENGTH, .formats_length = FORMATS_LENGTH,
}; };
WGPUAttachmentStateId attachment_state = wgpu_device_create_attachment_state(device, &attachment_state_desc); WGPUAttachmentStateId attachment_state = wgpu_device_create_attachment_state(device, &attachment_state_desc);
WGPURenderPipelineDescriptor render_pipeline_desc = { WGPURenderPipelineDescriptor render_pipeline_desc = {
.layout = layout, .layout = layout,
.stages = stages, .stages = stages,

View File

@ -10,4 +10,4 @@ authors = [
default = [] default = []
[dependencies] [dependencies]
cbindgen = "0.6.3" cbindgen = "0.6.6"

View File

@ -11,8 +11,8 @@ const HEADER: &str = "
"; ";
fn main() { fn main() {
let mut crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
crate_dir.push("../wgpu-native"); let source_dir = crate_dir.parent().unwrap().join("wgpu-native");
let config = cbindgen::Config { let config = cbindgen::Config {
header: Some(String::from(HEADER.trim())), header: Some(String::from(HEADER.trim())),
@ -33,9 +33,10 @@ fn main() {
}; };
cbindgen::Builder::new() cbindgen::Builder::new()
.with_crate(crate_dir) .with_crate(source_dir)
.with_config(config) .with_config(config)
.with_parse_expand(&["wgpu-native"])
.generate() .generate()
.unwrap() .unwrap()
.write_to_file("wgpu.h"); .write_to_file(crate_dir.join("wgpu.h"));
} }

View File

@ -28,20 +28,6 @@
#define WGPUShaderStageFlags_VERTEX 1 #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 { typedef enum {
WGPUBindingType_UniformBuffer = 0, WGPUBindingType_UniformBuffer = 0,
WGPUBindingType_Sampler = 1, WGPUBindingType_Sampler = 1,
@ -276,12 +262,40 @@ typedef struct {
#define WGPUBLUE (Color){ .r = 0, .g = 0, .b = 1, .a = 1 } #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 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 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 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 } #define WGPUWHITE (Color){ .r = 1, .g = 1, .b = 1, .a = 1 }
WGPUDeviceId wgpu_adapter_create_device(WGPUAdapterId adapter_id, WGPUDeviceId wgpu_adapter_create_device(WGPUAdapterId adapter_id,

View File

@ -1,5 +1,6 @@
use super::CommandBuffer; use super::CommandBuffer;
use {DeviceId, Stored}; use {DeviceId, Stored};
use track::{Tracker};
use hal::command::RawCommandBuffer; use hal::command::RawCommandBuffer;
use hal::pool::RawCommandPool; use hal::pool::RawCommandPool;
@ -12,14 +13,37 @@ use std::thread;
struct CommandPool<B: hal::Backend> { struct CommandPool<B: hal::Backend> {
raw: B::CommandPool, raw: B::CommandPool,
available: Vec<CommandBuffer<B>>, available: Vec<B::CommandBuffer>,
}
impl<B: hal::Backend> CommandPool<B> {
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<B: hal::Backend> { struct Inner<B: hal::Backend> {
pools: HashMap<thread::ThreadId, CommandPool<B>>, pools: HashMap<thread::ThreadId, CommandPool<B>>,
fences: Vec<B::Fence>,
pending: Vec<CommandBuffer<B>>, pending: Vec<CommandBuffer<B>>,
} }
impl<B: hal::Backend> Inner<B> {
fn recycle(&mut self, cmd_buf: CommandBuffer<B>) {
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<B: hal::Backend> { pub struct CommandAllocator<B: hal::Backend> {
queue_family: hal::queue::QueueFamilyId, queue_family: hal::queue::QueueFamilyId,
inner: Mutex<Inner<B>>, inner: Mutex<Inner<B>>,
@ -31,6 +55,7 @@ impl<B: hal::Backend> CommandAllocator<B> {
queue_family, queue_family,
inner: Mutex::new(Inner { inner: Mutex::new(Inner {
pools: HashMap::new(), pools: HashMap::new(),
fences: Vec::new(),
pending: Vec::new(), pending: Vec::new(),
}), }),
} }
@ -41,6 +66,17 @@ impl<B: hal::Backend> CommandAllocator<B> {
) -> CommandBuffer<B> { ) -> CommandBuffer<B> {
let thread_id = thread::current().id(); let thread_id = thread::current().id();
let mut inner = self.inner.lock().unwrap(); 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 { let pool = inner.pools.entry(thread_id).or_insert_with(|| CommandPool {
raw: device.create_command_pool( raw: device.create_command_pool(
self.queue_family, self.queue_family,
@ -48,21 +84,27 @@ impl<B: hal::Backend> CommandAllocator<B> {
), ),
available: Vec::new(), available: Vec::new(),
}); });
let init = pool.allocate();
if let Some(cmd_buf) = pool.available.pop() { CommandBuffer {
assert_eq!(device_id, cmd_buf.device_id.0); raw: vec![init],
device.reset_fence(&cmd_buf.fence); fence,
return cmd_buf; 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>) -> 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() pool.available.pop().unwrap()
} }
@ -70,16 +112,8 @@ impl<B: hal::Backend> CommandAllocator<B> {
self.inner.lock().unwrap().pending.push(cmd_buf); self.inner.lock().unwrap().pending.push(cmd_buf);
} }
pub fn recycle(&self, mut cmd_buf: CommandBuffer<B>) { pub fn recycle(&self, cmd_buf: CommandBuffer<B>) {
cmd_buf.raw.as_mut().unwrap().reset(false); self.inner.lock().unwrap().recycle(cmd_buf);
self.inner
.lock()
.unwrap()
.pools
.get_mut(&cmd_buf.recorded_thread_id)
.unwrap()
.available
.push(cmd_buf);
} }
pub fn maintain(&self, device: &B::Device) { pub fn maintain(&self, device: &B::Device) {
@ -87,12 +121,7 @@ impl<B: hal::Backend> CommandAllocator<B> {
for i in (0..inner.pending.len()).rev() { for i in (0..inner.pending.len()).rev() {
if device.get_fence_status(&inner.pending[i].fence) { if device.get_fence_status(&inner.pending[i].fence) {
let cmd_buf = inner.pending.swap_remove(i); let cmd_buf = inner.pending.swap_remove(i);
inner inner.recycle(cmd_buf);
.pools
.get_mut(&cmd_buf.recorded_thread_id)
.unwrap()
.available
.push(cmd_buf);
} }
} }
} }

View File

@ -35,7 +35,8 @@ pub extern "C" fn wgpu_compute_pass_end_pass(
HUB.command_buffers HUB.command_buffers
.lock() .lock()
.get_mut(pass.cmb_id.0) .get_mut(pass.cmb_id.0)
.raw = Some(pass.raw); .raw
.push(pass.raw);
pass.cmb_id.0 pass.cmb_id.0
} }

View File

@ -13,9 +13,11 @@ use {
BufferId, CommandBufferId, ComputePassId, DeviceId, RenderPassId, TextureId, TextureViewId, BufferId, CommandBufferId, ComputePassId, DeviceId, RenderPassId, TextureId, TextureViewId,
}; };
use registry::{HUB, Items, Registry}; use registry::{HUB, Items, Registry};
use track::{BufferTracker, TextureTracker};
use std::thread::ThreadId; use std::thread::ThreadId;
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum LoadOp { pub enum LoadOp {
@ -72,10 +74,12 @@ pub struct TextureCopyView {
} }
pub struct CommandBuffer<B: hal::Backend> { pub struct CommandBuffer<B: hal::Backend> {
pub(crate) raw: Option<B::CommandBuffer>, pub(crate) raw: Vec<B::CommandBuffer>,
fence: B::Fence, fence: B::Fence,
recorded_thread_id: ThreadId, recorded_thread_id: ThreadId,
device_id: Stored<DeviceId>, device_id: Stored<DeviceId>,
buffer_tracker: BufferTracker,
texture_tracker: TextureTracker,
} }
#[repr(C)] #[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 mut cmb_guard = HUB.command_buffers.lock();
let cmb = cmb_guard.get_mut(command_buffer_id); let cmb = cmb_guard.get_mut(command_buffer_id);
let raw = cmb.raw.take().unwrap();
let device_guard = HUB.devices.lock(); 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 render_pass = device.create_render_pass();
//let framebuffer = device.create_framebuffer(); //let framebuffer = device.create_framebuffer();
@ -108,7 +112,10 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
HUB.render_passes HUB.render_passes
.lock() .lock()
.register(RenderPass::new(raw, command_buffer_id)) .register(RenderPass::new(
current_comb,
command_buffer_id,
))
} }
#[no_mangle] #[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 mut cmb_guard = HUB.command_buffers.lock();
let cmb = cmb_guard.get_mut(command_buffer_id); let cmb = cmb_guard.get_mut(command_buffer_id);
let raw = cmb.raw.take().unwrap(); let raw = cmb.raw.pop().unwrap();
HUB.compute_passes HUB.compute_passes
.lock() .lock()

View File

@ -1,4 +1,6 @@
use conv;
use registry::{HUB, Items, Registry}; use registry::{HUB, Items, Registry};
use track::{BufferTracker, TextureTracker};
use { use {
Stored, Stored,
CommandBufferId, RenderPassId, CommandBufferId, RenderPassId,
@ -11,13 +13,20 @@ use hal::command::RawCommandBuffer;
pub struct RenderPass<B: hal::Backend> { pub struct RenderPass<B: hal::Backend> {
raw: B::CommandBuffer, raw: B::CommandBuffer,
cmb_id: Stored<CommandBufferId>, cmb_id: Stored<CommandBufferId>,
buffer_tracker: BufferTracker,
texture_tracker: TextureTracker,
} }
impl<B: hal::Backend> RenderPass<B> { impl<B: hal::Backend> RenderPass<B> {
pub fn new(raw: B::CommandBuffer, cmb_id: CommandBufferId) -> Self { pub fn new(
raw: B::CommandBuffer,
cmb_id: CommandBufferId,
) -> Self {
RenderPass { RenderPass {
raw, raw,
cmb_id: Stored(cmb_id), 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); .take(pass_id);
pass.raw.end_render_pass(); pass.raw.end_render_pass();
HUB.command_buffers let buffer_guard = HUB.buffers.lock();
.lock() let texture_guard = HUB.textures.lock();
.get_mut(pass.cmb_id.0) let mut cmb_guard = HUB.command_buffers.lock();
.raw = Some(pass.raw); 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 pass.cmb_id.0
} }

View File

@ -2,7 +2,8 @@ use hal;
use {Extent3d, binding_model, pipeline, resource}; use {Extent3d, binding_model, pipeline, resource};
pub(crate) fn map_buffer_usage(
pub fn map_buffer_usage(
usage: resource::BufferUsageFlags, usage: resource::BufferUsageFlags,
) -> (hal::buffer::Usage, hal::memory::Properties) { ) -> (hal::buffer::Usage, hal::memory::Properties) {
use hal::buffer::Usage as U; use hal::buffer::Usage as U;
@ -40,7 +41,38 @@ pub(crate) fn map_buffer_usage(
(hal_usage, hal_memory) (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, binding_ty: binding_model::BindingType,
) -> hal::pso::DescriptorType { ) -> hal::pso::DescriptorType {
use binding_model::BindingType::*; 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, shader_stage_flags: binding_model::ShaderStageFlags,
) -> hal::pso::ShaderStageFlags { ) -> hal::pso::ShaderStageFlags {
use binding_model::{ use binding_model::{
@ -73,7 +105,7 @@ pub(crate) fn map_shader_stage_flags(
value value
} }
pub(crate) fn map_primitive_topology( pub fn map_primitive_topology(
primitive_topology: pipeline::PrimitiveTopology, primitive_topology: pipeline::PrimitiveTopology,
) -> hal::Primitive { ) -> hal::Primitive {
use hal::Primitive as H; 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, desc: &pipeline::BlendStateDescriptor,
) -> hal::pso::ColorBlendDesc { ) -> hal::pso::ColorBlendDesc {
let color_mask = desc.write_mask; 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, desc: &pipeline::DepthStencilStateDescriptor,
) -> hal::pso::DepthStencilDesc { ) -> hal::pso::DepthStencilDesc {
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 hal::format::Format as H;
use resource::TextureFormat::*; use resource::TextureFormat::*;
match texture_format { match texture_format {
@ -244,7 +276,9 @@ fn checked_u32_as_u16(value: u32) -> u16 {
value as 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 hal::image::Kind as H;
use resource::TextureDimension::*; use resource::TextureDimension::*;
let Extent3d { width, height, depth } = size; 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 { pub fn map_buffer_state(
use hal::image::Usage as H; usage: resource::BufferUsageFlags,
use resource::{ ) -> hal::buffer::State {
TextureUsageFlags_TRANSFER_SRC, TextureUsageFlags_TRANSFER_DST, TextureUsageFlags_SAMPLED, use hal::buffer::Access as A;
TextureUsageFlags_STORAGE, TextureUsageFlags_OUTPUT_ATTACHMENT, use resource::BufferUsageFlags as W;
};
let mut value = H::empty(); let mut access = A::empty();
if 0 != flags & TextureUsageFlags_TRANSFER_SRC { if usage.contains(W::TRANSFER_SRC) {
value |= H::TRANSFER_SRC; access |= A::TRANSFER_READ;
} }
if 0 != flags & TextureUsageFlags_TRANSFER_DST { if usage.contains(W::TRANSFER_DST) {
value |= H::TRANSFER_DST; access |= A::TRANSFER_WRITE;
} }
if 0 != flags & TextureUsageFlags_SAMPLED { if usage.contains(W::INDEX) {
value |= H::SAMPLED; access |= A::INDEX_BUFFER_READ;
} }
if 0 != flags & TextureUsageFlags_STORAGE { if usage.contains(W::VERTEX) {
value |= H::STORAGE; access |= A::VERTEX_BUFFER_READ;
} }
if 0 != flags & TextureUsageFlags_OUTPUT_ATTACHMENT { if usage.contains(W::UNIFORM) {
if format.surface_desc().aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) { access |= A::CONSTANT_BUFFER_READ | A::SHADER_READ;
value |= H::DEPTH_STENCIL_ATTACHMENT;
} else {
value |= H::COLOR_ATTACHMENT;
}
} }
// Note: TextureUsageFlags::Present does not need to be handled explicitly if usage.contains(W::STORAGE) {
// TODO: HAL Transient Attachment, HAL Input Attachment access |= A::SHADER_WRITE;
value }
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)
} }

View File

@ -1,5 +1,6 @@
use {back, binding_model, command, conv, pipeline, resource}; use {back, binding_model, command, conv, pipeline, resource};
use registry::{HUB, Items, Registry}; use registry::{HUB, Items, Registry};
use track::{BufferTracker, TextureTracker, TrackPermit};
use { use {
AttachmentStateId, BindGroupLayoutId, BlendStateId, CommandBufferId, DepthStencilStateId, AttachmentStateId, BindGroupLayoutId, BlendStateId, CommandBufferId, DepthStencilStateId,
DeviceId, PipelineLayoutId, QueueId, RenderPipelineId, ShaderModuleId, TextureId, DeviceId, PipelineLayoutId, QueueId, RenderPipelineId, ShaderModuleId, TextureId,
@ -8,16 +9,19 @@ use {
use hal::command::RawCommandBuffer; use hal::command::RawCommandBuffer;
use hal::queue::RawCommandQueue; use hal::queue::RawCommandQueue;
use hal::{self, Device as _Device}; use hal::{self, Device as _Device};
use rendy_memory::{allocator, Config, Heaps};
use std::{ffi, slice}; use std::{ffi, slice};
use rendy_memory::{allocator, Config, Heaps}; use std::sync::Mutex;
pub struct Device<B: hal::Backend> { pub struct Device<B: hal::Backend> {
pub(crate) raw: B::Device, pub(crate) raw: B::Device,
queue_group: hal::QueueGroup<B, hal::General>, queue_group: hal::QueueGroup<B, hal::General>,
mem_allocator: Heaps<B::Memory>, mem_allocator: Heaps<B::Memory>,
com_allocator: command::CommandAllocator<B>, pub(crate) com_allocator: command::CommandAllocator<B>,
buffer_tracker: Mutex<BufferTracker>,
texture_tracker: Mutex<TextureTracker>,
mem_props: hal::MemoryProperties, mem_props: hal::MemoryProperties,
} }
@ -53,6 +57,8 @@ impl<B: hal::Backend> Device<B> {
mem_allocator, mem_allocator,
com_allocator: command::CommandAllocator::new(queue_group.family()), com_allocator: command::CommandAllocator::new(queue_group.family()),
queue_group, queue_group,
buffer_tracker: Mutex::new(BufferTracker::new()),
texture_tracker: Mutex::new(TextureTracker::new()),
mem_props, mem_props,
} }
} }
@ -69,7 +75,8 @@ pub extern "C" fn wgpu_device_create_texture(
) -> TextureId { ) -> TextureId {
let kind = conv::map_texture_dimension_size(desc.dimension, desc.size); let kind = conv::map_texture_dimension_size(desc.dimension, desc.size);
let format = conv::map_texture_format(desc.format); 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_guard = HUB.devices.lock();
let device = &device_guard.get(device_id); let device = &device_guard.get(device_id);
let image_unbound = device let image_unbound = device
@ -101,11 +108,20 @@ pub extern "C" fn wgpu_device_create_texture(
.raw .raw
.bind_image_memory(&image_memory, 0, image_unbound) .bind_image_memory(&image_memory, 0, image_unbound)
.unwrap(); .unwrap();
HUB.textures
let id = HUB.textures
.lock() .lock()
.register(resource::Texture { .register(resource::Texture {
raw: bound_image, 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] #[no_mangle]
@ -215,11 +231,11 @@ pub extern "C" fn wgpu_device_create_command_buffer(
device_id: DeviceId, device_id: DeviceId,
_desc: &command::CommandBufferDescriptor, _desc: &command::CommandBufferDescriptor,
) -> CommandBufferId { ) -> CommandBufferId {
let mut device_guard = HUB.devices.lock(); let device_guard = HUB.devices.lock();
let device = device_guard.get_mut(device_id); let device = device_guard.get(device_id);
let mut cmd_buf = device.com_allocator.allocate(device_id, &device.raw); 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::CommandBufferFlags::ONE_TIME_SUBMIT,
hal::command::CommandBufferInheritanceInfo::default(), hal::command::CommandBufferInheritanceInfo::default(),
); );
@ -249,7 +265,7 @@ pub extern "C" fn wgpu_queue_submit(
command_buffer_guard command_buffer_guard
.get_mut(cmb_id) .get_mut(cmb_id)
.raw .raw
.as_mut() .last_mut()
.unwrap() .unwrap()
.finish(); .finish();
} }
@ -259,12 +275,8 @@ pub extern "C" fn wgpu_queue_submit(
let submission = hal::queue::RawSubmission { let submission = hal::queue::RawSubmission {
cmd_buffers: command_buffer_ids cmd_buffers: command_buffer_ids
.iter() .iter()
.map(|&cmb_id| { .flat_map(|&cmb_id| {
command_buffer_guard &command_buffer_guard.get(cmb_id).raw
.get(cmb_id)
.raw
.as_ref()
.unwrap()
}), }),
wait_semaphores: &[], wait_semaphores: &[],
signal_semaphores: &[], signal_semaphores: &[],

View File

@ -29,6 +29,7 @@ mod instance;
mod pipeline; mod pipeline;
mod registry; mod registry;
mod resource; mod resource;
mod track;
pub use self::binding_model::*; pub use self::binding_model::*;
pub use self::command::*; pub use self::command::*;
@ -40,7 +41,7 @@ pub use self::resource::*;
use back::Backend as B; use back::Backend as B;
use registry::Id; use registry::Id;
#[derive(Debug, PartialEq)] #[derive(Debug, Hash, PartialEq, Eq)]
struct Stored<T>(T); struct Stored<T>(T);
#[cfg(not(feature = "remote"))] #[cfg(not(feature = "remote"))]
unsafe impl<T> Sync for Stored<T> {} unsafe impl<T> Sync for Stored<T> {}
@ -95,6 +96,7 @@ pub type DeviceId = Id;
type DeviceHandle = Device<B>; type DeviceHandle = Device<B>;
pub type QueueId = Id; pub type QueueId = Id;
pub type BufferId = Id; pub type BufferId = Id;
type BufferHandle = Buffer<B>;
// Resource // Resource
pub type TextureViewId = Id; pub type TextureViewId = Id;

View File

@ -13,7 +13,7 @@ use {
BlendStateHandle, CommandBufferHandle, DepthStencilStateHandle, DeviceHandle, InstanceHandle, BlendStateHandle, CommandBufferHandle, DepthStencilStateHandle, DeviceHandle, InstanceHandle,
RenderPassHandle, ComputePassHandle, RenderPassHandle, ComputePassHandle,
PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle, PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle,
TextureHandle, BufferHandle, TextureHandle,
}; };
@ -48,6 +48,7 @@ pub struct Hub {
pub(crate) compute_pipelines: ConcreteRegistry<ComputePipelineHandle>, pub(crate) compute_pipelines: ConcreteRegistry<ComputePipelineHandle>,
pub(crate) render_passes: ConcreteRegistry<RenderPassHandle>, pub(crate) render_passes: ConcreteRegistry<RenderPassHandle>,
pub(crate) compute_passes: ConcreteRegistry<ComputePassHandle>, pub(crate) compute_passes: ConcreteRegistry<ComputePassHandle>,
pub(crate) buffers: ConcreteRegistry<BufferHandle>,
pub(crate) textures: ConcreteRegistry<TextureHandle>, pub(crate) textures: ConcreteRegistry<TextureHandle>,
} }

View File

@ -1,11 +1,11 @@
use {Extent3d};
use hal; use hal;
use Extent3d;
bitflags! { bitflags! {
#[repr(transparent)] #[repr(transparent)]
pub struct BufferUsageFlags: u32 { pub struct BufferUsageFlags: u32 {
const NONE = 0;
const MAP_READ = 1; const MAP_READ = 1;
const MAP_WRITE = 2; const MAP_WRITE = 2;
const TRANSFER_SRC = 4; const TRANSFER_SRC = 4;
@ -14,6 +14,8 @@ bitflags! {
const VERTEX = 32; const VERTEX = 32;
const UNIFORM = 64; const UNIFORM = 64;
const STORAGE = 128; const STORAGE = 128;
const NONE = 0;
const WRITE_ALL = 2 + 8 + 128;
} }
} }
@ -23,9 +25,10 @@ pub struct BufferDescriptor {
pub usage: BufferUsageFlags, pub usage: BufferUsageFlags,
} }
pub struct Buffer<B: hal::Backend> { pub(crate) struct Buffer<B: hal::Backend> {
pub(crate) raw: B::UnboundBuffer, //pub raw: B::UnboundBuffer,
pub(crate) memory_properties: hal::memory::Properties, pub raw: B::Buffer,
pub memory_properties: hal::memory::Properties,
// TODO: mapping, unmap() // TODO: mapping, unmap()
} }
@ -50,22 +53,19 @@ pub enum TextureFormat {
D32FloatS8Uint = 3, D32FloatS8Uint = 3,
} }
// TODO: bitflags bitflags! {
pub type TextureUsageFlags = u32; #[repr(transparent)]
#[allow(non_upper_case_globals)] pub struct TextureUsageFlags: u32 {
pub const TextureUsageFlags_NONE: u32 = 0; const TRANSFER_SRC = 1;
#[allow(non_upper_case_globals)] const TRANSFER_DST = 2;
pub const TextureUsageFlags_TRANSFER_SRC: u32 = 1; const SAMPLED = 4;
#[allow(non_upper_case_globals)] const STORAGE = 8;
pub const TextureUsageFlags_TRANSFER_DST: u32 = 2; const OUTPUT_ATTACHMENT = 16;
#[allow(non_upper_case_globals)] const PRESENT = 32;
pub const TextureUsageFlags_SAMPLED: u32 = 4; const NONE = 0;
#[allow(non_upper_case_globals)] const WRITE_ALL = 2 + 8 + 16;
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;
#[repr(C)] #[repr(C)]
pub struct TextureDescriptor { pub struct TextureDescriptor {
@ -76,8 +76,9 @@ pub struct TextureDescriptor {
pub usage: TextureUsageFlags, pub usage: TextureUsageFlags,
} }
pub struct Texture<B: hal::Backend> { pub(crate) struct Texture<B: hal::Backend> {
pub(crate) raw: B::Image, pub raw: B::Image,
pub aspects: hal::format::Aspects,
} }
#[repr(C)] #[repr(C)]

88
wgpu-native/src/track.rs Normal file
View File

@ -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<T> {
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<I, U> {
map: HashMap<Stored<I>, U>,
}
pub type BufferTracker = Tracker<BufferId, BufferUsageFlags>;
pub type TextureTracker = Tracker<TextureId, TextureUsageFlags>;
impl<
I: Clone + Hash + Eq,
U: Copy + GenericUsage + BitOr<Output = U> + PartialEq,
> Tracker<I, U> {
pub fn new() -> Self {
Tracker {
map: HashMap::new(),
}
}
pub fn track(&mut self, id: I, usage: U, permit: TrackPermit) -> Result<Tracktion<U>, 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<Item = (I, Range<U>)> {
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!"),
})
}
}