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]]
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"

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,
};
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,

View File

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

View File

@ -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"));
}

View File

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

View File

@ -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<B: hal::Backend> {
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> {
pools: HashMap<thread::ThreadId, CommandPool<B>>,
fences: Vec<B::Fence>,
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> {
queue_family: hal::queue::QueueFamilyId,
inner: Mutex<Inner<B>>,
@ -31,6 +55,7 @@ impl<B: hal::Backend> CommandAllocator<B> {
queue_family,
inner: Mutex::new(Inner {
pools: HashMap::new(),
fences: Vec::new(),
pending: Vec::new(),
}),
}
@ -41,6 +66,17 @@ impl<B: hal::Backend> CommandAllocator<B> {
) -> CommandBuffer<B> {
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<B: hal::Backend> CommandAllocator<B> {
),
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>) -> 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<B: hal::Backend> CommandAllocator<B> {
self.inner.lock().unwrap().pending.push(cmd_buf);
}
pub fn recycle(&self, mut cmd_buf: CommandBuffer<B>) {
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<B>) {
self.inner.lock().unwrap().recycle(cmd_buf);
}
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() {
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);
}
}
}

View File

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

View File

@ -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<B: hal::Backend> {
pub(crate) raw: Option<B::CommandBuffer>,
pub(crate) raw: Vec<B::CommandBuffer>,
fence: B::Fence,
recorded_thread_id: ThreadId,
device_id: Stored<DeviceId>,
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()

View File

@ -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<B: hal::Backend> {
raw: B::CommandBuffer,
cmb_id: Stored<CommandBufferId>,
buffer_tracker: BufferTracker,
texture_tracker: TextureTracker,
}
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 {
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
}

View File

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

View File

@ -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<B: hal::Backend> {
pub(crate) raw: B::Device,
queue_group: hal::QueueGroup<B, hal::General>,
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,
}
@ -53,6 +57,8 @@ impl<B: hal::Backend> Device<B> {
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: &[],

View File

@ -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>(T);
#[cfg(not(feature = "remote"))]
unsafe impl<T> Sync for Stored<T> {}
@ -95,6 +96,7 @@ pub type DeviceId = Id;
type DeviceHandle = Device<B>;
pub type QueueId = Id;
pub type BufferId = Id;
type BufferHandle = Buffer<B>;
// Resource
pub type TextureViewId = Id;

View File

@ -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<ComputePipelineHandle>,
pub(crate) render_passes: ConcreteRegistry<RenderPassHandle>,
pub(crate) compute_passes: ConcreteRegistry<ComputePassHandle>,
pub(crate) buffers: ConcreteRegistry<BufferHandle>,
pub(crate) textures: ConcreteRegistry<TextureHandle>,
}

View File

@ -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<B: hal::Backend> {
pub(crate) raw: B::UnboundBuffer,
pub(crate) memory_properties: hal::memory::Properties,
pub(crate) struct Buffer<B: hal::Backend> {
//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<B: hal::Backend> {
pub(crate) raw: B::Image,
pub(crate) struct Texture<B: hal::Backend> {
pub raw: B::Image,
pub aspects: hal::format::Aspects,
}
#[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!"),
})
}
}