mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-21 22:33:49 +00:00
Merge #34
34: Basic windowing and presentation r=grovesNL a=kvark - [x] native swapchain creation - [x] native use of frames and presentation - [x] native semaphore waits - [x] rust wrapping - [x] working examples ~~I may or may not bite the bullet and update gfx-rs here. Probably not :)~~ ## Architecture There is a bit of complexity here to manage all the synchronization and lifetimes properly. Essentially, presentation is exposed in Vulkan/gfx-rs as a separate hidden queue, so we inevitably run into the territory of using semaphores for synchronization, where previously we could ignore them for workloads on a single queue. A swapchain has a fixed (at creation) number of frames, each represented by a texture plus view pair. When `get_next_texture` is called we acquire the next image index and return this pair. We wait for the associated fence to make sure the frame is no image used. We then associate a semaphore with this index for image availability. The texture has extra information to link back to an image of the swapchain (which is `None` for regular textures). Whenever it's used, the command buffer collects that link to be used on submission, where it's just resolved to a semaphore that we wait on actual submission. Presenting on a swapchain creates a temporary command buffer that we only use for transiting the swapchain image into presentable state. This small submission is useful for establishing a "ready" semaphore as well as a fence (waited in `get_next_image`). The "ready" semaphore is used immediately for native `present` call. Co-authored-by: Dzmitry Malyshau <dmalyshau@mozilla.com> Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
commit
0f592b4443
38
Cargo.lock
generated
38
Cargo.lock
generated
@ -104,8 +104,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cbindgen"
|
||||
version = "0.6.7"
|
||||
source = "git+https://github.com/grovesNL/cbindgen?branch=associated-constants#c87c6774c9f1b9540abac4fc505ed63f0e0a0798"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -288,6 +288,24 @@ name = "gcc"
|
||||
version = "0.3.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-dx11"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gfx-hal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"range-alloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spirv_cross 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-dx12"
|
||||
version = "0.1.0"
|
||||
@ -1061,7 +1079,7 @@ dependencies = [
|
||||
name = "wgpu-bindings"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cbindgen 0.6.7 (git+https://github.com/grovesNL/cbindgen?branch=associated-constants)",
|
||||
"cbindgen 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1069,6 +1087,7 @@ name = "wgpu-native"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gfx-backend-dx11 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gfx-backend-dx12 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gfx-backend-empty 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gfx-backend-metal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1077,6 +1096,7 @@ dependencies = [
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1128,6 +1148,14 @@ dependencies = [
|
||||
"x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wio"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11"
|
||||
version = "2.18.1"
|
||||
@ -1180,7 +1208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"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.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||
"checksum cbindgen 0.6.7 (git+https://github.com/grovesNL/cbindgen?branch=associated-constants)" = "<none>"
|
||||
"checksum cbindgen 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "89ae8c2f780373f1842acb548fa53c7fd3acd6ca27d47966c69351719b239eae"
|
||||
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
@ -1201,6 +1229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
|
||||
"checksum gfx-backend-dx11 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7751e630a3472d96b1a0ce9cd6742f2e17c0f71a6e833f822b914a11f89bd7db"
|
||||
"checksum gfx-backend-dx12 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c373f40998da0fd605a7a90ce8d775a8cbcb06558edc2ea9740df1db2077686"
|
||||
"checksum gfx-backend-empty 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bb068297aed95a014abaa01738986c2ed5d08c5f9f152c992300c415e9b917c"
|
||||
"checksum gfx-backend-metal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68fa011e32280f7566bddbb736734291b685c812087c99bc848d6ac7ae3e0b7f"
|
||||
@ -1293,6 +1322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum winit 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c57c15bd4c0ef18dff33e263e452abe32d00e2e05771cacaa410a14cc1c0776"
|
||||
"checksum wio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8a31e8a268d6941ffb7f8d7989fc93e4692bd3e75a27d400a72b4be1dadb213"
|
||||
"checksum x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39697e3123f715483d311b5826e254b6f3cfebdd83cf7ef3358f579c3d68e235"
|
||||
"checksum x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)" = "940586acb859ea05c53971ac231685799a7ec1dee66ac0bccc0e6ad96e06b4e3"
|
||||
"checksum xcb 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5e917a3f24142e9ff8be2414e36c649d47d6cc2ba81f16201cdef96e533e02de"
|
||||
|
@ -14,7 +14,9 @@ path = "hello_triangle_rust/main.rs"
|
||||
[features]
|
||||
default = []
|
||||
remote = ["wgpu-native/remote"]
|
||||
winit = ["wgpu/winit"]
|
||||
metal = ["wgpu-native/gfx-backend-metal"]
|
||||
dx11 = ["wgpu-native/gfx-backend-dx11"]
|
||||
dx12 = ["wgpu-native/gfx-backend-dx12"]
|
||||
vulkan = ["wgpu-native/gfx-backend-vulkan"]
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
extern crate wgpu;
|
||||
extern crate wgpu_native;
|
||||
|
||||
fn main() {
|
||||
let instance = wgpu::Instance::new();
|
||||
let adapter = instance.get_adapter(&wgpu::AdapterDescriptor {
|
||||
@ -10,19 +12,6 @@ fn main() {
|
||||
},
|
||||
});
|
||||
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
size: wgpu::Extent3d {
|
||||
width: 256,
|
||||
height: 256,
|
||||
depth: 1,
|
||||
},
|
||||
array_size: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::R8g8b8a8Unorm,
|
||||
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT,
|
||||
});
|
||||
let color_view = texture.create_default_texture_view();
|
||||
|
||||
let vs_bytes = include_bytes!("./../data/hello_triangle.vert.spv");
|
||||
let vs_module = device.create_shader_module(vs_bytes);
|
||||
let fs_bytes = include_bytes!("./../data/hello_triangle.frag.spv");
|
||||
@ -64,21 +53,100 @@ fn main() {
|
||||
depth_stencil_state: &depth_stencil_state,
|
||||
});
|
||||
|
||||
let mut cmd_buf = device.create_command_buffer(&wgpu::CommandBufferDescriptor {});
|
||||
|
||||
#[cfg(feature = "winit")]
|
||||
{
|
||||
let rpass = cmd_buf.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &color_view,
|
||||
load_op: wgpu::LoadOp::Clear,
|
||||
store_op: wgpu::StoreOp::Store,
|
||||
clear_color: wgpu::Color::GREEN,
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
use wgpu_native::winit::{ControlFlow, Event, ElementState, EventsLoop, KeyboardInput, Window, WindowEvent, VirtualKeyCode};
|
||||
|
||||
let mut events_loop = EventsLoop::new();
|
||||
let window = Window::new(&events_loop).unwrap();
|
||||
let size = window
|
||||
.get_inner_size()
|
||||
.unwrap()
|
||||
.to_physical(window.get_hidpi_factor());
|
||||
|
||||
let surface = instance.create_surface(&window);
|
||||
let swap_chain = device.create_swap_chain(&surface, &wgpu::SwapChainDescriptor {
|
||||
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT | wgpu::TextureUsageFlags::PRESENT,
|
||||
format: wgpu::TextureFormat::B8g8r8a8Unorm,
|
||||
width: size.width as u32,
|
||||
height: size.height as u32,
|
||||
});
|
||||
|
||||
events_loop.run_forever(|event| {
|
||||
match event {
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::KeyboardInput {
|
||||
input: KeyboardInput { virtual_keycode: Some(code), state: ElementState::Pressed, .. },
|
||||
..
|
||||
} => match code {
|
||||
VirtualKeyCode::Escape => {
|
||||
return ControlFlow::Break
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
WindowEvent::CloseRequested => {
|
||||
return ControlFlow::Break
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let (_, view) = swap_chain.get_next_texture();
|
||||
let mut cmd_buf = device.create_command_buffer(&wgpu::CommandBufferDescriptor {});
|
||||
{
|
||||
let rpass = cmd_buf.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &view,
|
||||
load_op: wgpu::LoadOp::Clear,
|
||||
store_op: wgpu::StoreOp::Store,
|
||||
clear_color: wgpu::Color::GREEN,
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
rpass.end_pass();
|
||||
}
|
||||
|
||||
device
|
||||
.get_queue()
|
||||
.submit(&[cmd_buf]);
|
||||
|
||||
swap_chain.present();
|
||||
ControlFlow::Continue
|
||||
});
|
||||
rpass.end_pass();
|
||||
}
|
||||
|
||||
let queue = device.get_queue();
|
||||
queue.submit(&[cmd_buf]);
|
||||
#[cfg(not(feature = "winit"))]
|
||||
{
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
size: wgpu::Extent3d {
|
||||
width: 256,
|
||||
height: 256,
|
||||
depth: 1,
|
||||
},
|
||||
array_size: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::R8g8b8a8Unorm,
|
||||
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT,
|
||||
});
|
||||
let color_view = texture.create_default_texture_view();
|
||||
|
||||
let mut cmd_buf = device.create_command_buffer(&wgpu::CommandBufferDescriptor {});
|
||||
{
|
||||
let rpass = cmd_buf.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &color_view,
|
||||
load_op: wgpu::LoadOp::Clear,
|
||||
store_op: wgpu::StoreOp::Store,
|
||||
clear_color: wgpu::Color::GREEN,
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
rpass.end_pass();
|
||||
}
|
||||
|
||||
device
|
||||
.get_queue()
|
||||
.submit(&[cmd_buf]);
|
||||
}
|
||||
}
|
||||
|
@ -11,5 +11,4 @@ edition = "2018"
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
#cbindgen = "0.6.7"
|
||||
cbindgen = { git = "https://github.com/grovesNL/cbindgen", branch = "associated-constants"}
|
||||
cbindgen = "0.6.8"
|
||||
|
@ -22,6 +22,8 @@ parking_lot = { version = "0.7" }
|
||||
gfx-hal = "0.1.0"
|
||||
gfx-backend-empty = "0.1.0"
|
||||
gfx-backend-vulkan = { version = "0.1.0", optional = true }
|
||||
gfx-backend-dx11 = { version = "0.1.0", optional = true }
|
||||
gfx-backend-dx12 = { version = "0.1.0", optional = true }
|
||||
gfx-backend-metal = { version = "0.1.0", optional = true }
|
||||
#rendy-memory = { git = "https://github.com/rustgd/rendy", rev = "ce7dd7f", features = ["gfx-hal"] }
|
||||
winit = { version = "0.18", optional = true }
|
||||
|
@ -2,6 +2,7 @@ use crate::{BindGroupLayoutId, BufferId, SamplerId, TextureViewId};
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
|
||||
bitflags! {
|
||||
#[repr(transparent)]
|
||||
pub struct ShaderStageFlags: u32 {
|
||||
|
@ -1,14 +1,14 @@
|
||||
use super::CommandBuffer;
|
||||
use crate::track::Tracker;
|
||||
use crate::{DeviceId, LifeGuard, Stored};
|
||||
use crate::{DeviceId, LifeGuard, Stored, SubmissionIndex};
|
||||
|
||||
use hal::command::RawCommandBuffer;
|
||||
use hal::pool::RawCommandPool;
|
||||
use hal::Device;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use std::collections::HashMap;
|
||||
//TODO: use `parking_lot::Mutex`?
|
||||
use std::sync::Mutex;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
|
||||
struct CommandPool<B: hal::Backend> {
|
||||
@ -29,7 +29,6 @@ impl<B: hal::Backend> CommandPool<B> {
|
||||
|
||||
struct Inner<B: hal::Backend> {
|
||||
pools: HashMap<thread::ThreadId, CommandPool<B>>,
|
||||
fences: Vec<B::Fence>,
|
||||
pending: Vec<CommandBuffer<B>>,
|
||||
}
|
||||
|
||||
@ -42,7 +41,6 @@ impl<B: hal::Backend> Inner<B> {
|
||||
}
|
||||
pool.available.push(raw);
|
||||
}
|
||||
self.fences.push(cmd_buf.fence);
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +55,6 @@ impl<B: hal::Backend> CommandAllocator<B> {
|
||||
queue_family,
|
||||
inner: Mutex::new(Inner {
|
||||
pools: HashMap::new(),
|
||||
fences: Vec::new(),
|
||||
pending: Vec::new(),
|
||||
}),
|
||||
}
|
||||
@ -69,15 +66,7 @@ impl<B: hal::Backend> CommandAllocator<B> {
|
||||
device: &B::Device,
|
||||
) -> CommandBuffer<B> {
|
||||
let thread_id = thread::current().id();
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
|
||||
let fence = match inner.fences.pop() {
|
||||
Some(fence) => {
|
||||
unsafe { device.reset_fence(&fence).unwrap() };
|
||||
fence
|
||||
}
|
||||
None => device.create_fence(false).unwrap(),
|
||||
};
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
let pool = inner.pools.entry(thread_id).or_insert_with(|| CommandPool {
|
||||
raw: unsafe {
|
||||
@ -93,17 +82,17 @@ impl<B: hal::Backend> CommandAllocator<B> {
|
||||
|
||||
CommandBuffer {
|
||||
raw: vec![init],
|
||||
fence,
|
||||
recorded_thread_id: thread_id,
|
||||
device_id,
|
||||
life_guard: LifeGuard::new(),
|
||||
buffer_tracker: Tracker::new(),
|
||||
texture_tracker: Tracker::new(),
|
||||
swap_chain_links: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extend(&self, cmd_buf: &CommandBuffer<B>) -> B::CommandBuffer {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
let mut inner = self.inner.lock();
|
||||
let pool = inner.pools.get_mut(&cmd_buf.recorded_thread_id).unwrap();
|
||||
|
||||
if pool.available.is_empty() {
|
||||
@ -115,17 +104,18 @@ impl<B: hal::Backend> CommandAllocator<B> {
|
||||
}
|
||||
|
||||
pub fn submit(&self, cmd_buf: CommandBuffer<B>) {
|
||||
self.inner.lock().unwrap().pending.push(cmd_buf);
|
||||
self.inner.lock().pending.push(cmd_buf);
|
||||
}
|
||||
|
||||
pub fn recycle(&self, cmd_buf: CommandBuffer<B>) {
|
||||
self.inner.lock().unwrap().recycle(cmd_buf);
|
||||
self.inner.lock().recycle(cmd_buf);
|
||||
}
|
||||
|
||||
pub fn maintain(&self, device: &B::Device) {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
pub fn maintain(&self, device: &B::Device, last_done: SubmissionIndex) {
|
||||
let mut inner = self.inner.lock();
|
||||
for i in (0..inner.pending.len()).rev() {
|
||||
if unsafe { device.get_fence_status(&inner.pending[i].fence).unwrap() } {
|
||||
let index = inner.pending[i].life_guard.submission_index.load(Ordering::Acquire);
|
||||
if index <= last_done {
|
||||
let cmd_buf = inner.pending.swap_remove(i);
|
||||
inner.recycle(cmd_buf);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use hal::command::RawCommandBuffer;
|
||||
|
||||
use std::iter;
|
||||
|
||||
|
||||
pub struct ComputePass<B: hal::Backend> {
|
||||
raw: B::CommandBuffer,
|
||||
cmb_id: Stored<CommandBufferId>,
|
||||
|
@ -6,23 +6,27 @@ pub(crate) use self::allocator::CommandAllocator;
|
||||
pub use self::compute::*;
|
||||
pub use self::render::*;
|
||||
|
||||
use hal::command::RawCommandBuffer;
|
||||
use hal::Device;
|
||||
|
||||
use crate::device::{FramebufferKey, RenderPassKey};
|
||||
use crate::registry::{Items, HUB};
|
||||
use crate::swap_chain::{SwapChainLink, SwapImageEpoch};
|
||||
use crate::track::{BufferTracker, TextureTracker};
|
||||
use crate::{conv, resource};
|
||||
use crate::{
|
||||
BufferId, BufferUsageFlags, Color, CommandBufferId, ComputePassId, DeviceId, LifeGuard,
|
||||
Origin3d, RenderPassId, Stored, TextureId, TextureUsageFlags, TextureViewId, WeaklyStored, B,
|
||||
BufferId, CommandBufferId, ComputePassId, DeviceId,
|
||||
RenderPassId, TextureId, TextureViewId,
|
||||
BufferUsageFlags, TextureUsageFlags, Color, Origin3d,
|
||||
LifeGuard, Stored, WeaklyStored,
|
||||
B,
|
||||
};
|
||||
|
||||
use hal::command::RawCommandBuffer;
|
||||
use hal::Device;
|
||||
use log::trace;
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::ops::Range;
|
||||
use std::thread::ThreadId;
|
||||
|
||||
use log::trace;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
@ -81,12 +85,12 @@ pub struct TextureCopyView {
|
||||
|
||||
pub struct CommandBuffer<B: hal::Backend> {
|
||||
pub(crate) raw: Vec<B::CommandBuffer>,
|
||||
fence: B::Fence,
|
||||
recorded_thread_id: ThreadId,
|
||||
device_id: Stored<DeviceId>,
|
||||
life_guard: LifeGuard,
|
||||
pub(crate) life_guard: LifeGuard,
|
||||
pub(crate) buffer_tracker: BufferTracker,
|
||||
pub(crate) texture_tracker: TextureTracker,
|
||||
pub(crate) swap_chain_links: Vec<SwapChainLink<SwapImageEpoch>>,
|
||||
}
|
||||
|
||||
impl CommandBuffer<B> {
|
||||
@ -162,6 +166,7 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
|
||||
|
||||
let rp_key = {
|
||||
let tracker = &mut cmb.texture_tracker;
|
||||
let swap_chain_links = &mut cmb.swap_chain_links;
|
||||
|
||||
let depth_stencil_key = match desc.depth_stencil_attachment {
|
||||
Some(ref at) => {
|
||||
@ -189,6 +194,23 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
|
||||
|
||||
let color_keys = desc.color_attachments.iter().map(|at| {
|
||||
let view = view_guard.get(at.attachment);
|
||||
|
||||
if view.is_owned_by_swap_chain {
|
||||
let link = match HUB.textures
|
||||
.read()
|
||||
.get(view.texture_id.value)
|
||||
.swap_chain_link
|
||||
{
|
||||
Some(ref link) => SwapChainLink {
|
||||
swap_chain_id: link.swap_chain_id.clone(),
|
||||
epoch: *link.epoch.lock(),
|
||||
image_index: link.image_index,
|
||||
},
|
||||
None => unreachable!()
|
||||
};
|
||||
swap_chain_links.push(link);
|
||||
}
|
||||
|
||||
if let Some(ex) = extent {
|
||||
assert_eq!(ex, view.extent);
|
||||
} else {
|
||||
|
@ -4,6 +4,7 @@ use crate::{CommandBuffer, CommandBufferId, RenderPassId, Stored};
|
||||
|
||||
use hal::command::RawCommandBuffer;
|
||||
|
||||
|
||||
pub struct RenderPass<B: hal::Backend> {
|
||||
raw: B::CommandBuffer,
|
||||
cmb_id: Stored<CommandBufferId>,
|
||||
|
@ -1,23 +1,26 @@
|
||||
use crate::registry::{Items, HUB};
|
||||
use crate::{back, binding_model, command, conv, pipeline, resource, swap_chain};
|
||||
use crate::registry::{HUB, Items};
|
||||
use crate::track::{BufferTracker, TextureTracker};
|
||||
use crate::{back, binding_model, command, conv, pipeline, resource};
|
||||
use crate::{
|
||||
BindGroupLayoutId, BlendStateId, BufferId, CommandBuffer, CommandBufferId, DepthStencilStateId,
|
||||
DeviceId, LifeGuard, PipelineLayoutId, QueueId, RefCount, RenderPipelineId, ShaderModuleId,
|
||||
Stored, SubmissionIndex, TextureId, TextureUsageFlags, TextureViewId, WeaklyStored,
|
||||
CommandBuffer, LifeGuard, RefCount, Stored, SubmissionIndex, WeaklyStored,
|
||||
TextureUsageFlags,
|
||||
BindGroupLayoutId, BlendStateId, BufferId, CommandBufferId, DepthStencilStateId,
|
||||
AdapterId, DeviceId, PipelineLayoutId, QueueId, RenderPipelineId, ShaderModuleId,
|
||||
TextureId, TextureViewId,
|
||||
SurfaceId, SwapChainId,
|
||||
};
|
||||
|
||||
use hal::command::RawCommandBuffer;
|
||||
use hal::queue::RawCommandQueue;
|
||||
use hal::{self, Device as _Device};
|
||||
use hal::{self, Device as _Device, Surface as _Surface};
|
||||
//use rendy_memory::{allocator, Config, Heaps};
|
||||
use parking_lot::{Mutex};
|
||||
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
use std::{ffi, slice};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
|
||||
#[derive(Hash, PartialEq)]
|
||||
pub(crate) struct RenderPassKey {
|
||||
pub attachments: Vec<hal::pass::Attachment>,
|
||||
@ -40,8 +43,8 @@ enum Resource<B: hal::Backend> {
|
||||
Texture(resource::Texture<B>),
|
||||
}
|
||||
|
||||
struct ActiveFrame<B: hal::Backend> {
|
||||
submission_index: SubmissionIndex,
|
||||
struct ActiveSubmission<B: hal::Backend> {
|
||||
index: SubmissionIndex,
|
||||
fence: B::Fence,
|
||||
resources: Vec<Resource<B>>,
|
||||
}
|
||||
@ -51,8 +54,8 @@ struct DestroyedResources<B: hal::Backend> {
|
||||
/// other objects or command buffers.
|
||||
referenced: Vec<(ResourceId, RefCount)>,
|
||||
/// Resources that are not referenced any more but still used by GPU.
|
||||
/// Grouped by frames associated with a fence and a submission index.
|
||||
active: Vec<ActiveFrame<B>>,
|
||||
/// Grouped by submissions associated with a fence and a submission index.
|
||||
active: Vec<ActiveSubmission<B>>,
|
||||
/// Resources that are neither referenced or used, just pending
|
||||
/// actual deletion.
|
||||
free: Vec<Resource<B>>,
|
||||
@ -93,21 +96,29 @@ impl<B: hal::Backend> DestroyedResources<B> {
|
||||
match self
|
||||
.active
|
||||
.iter_mut()
|
||||
.find(|af| af.submission_index == submit_index)
|
||||
.find(|a| a.index == submit_index)
|
||||
{
|
||||
Some(af) => af.resources.push(resource),
|
||||
Some(a) => a.resources.push(resource),
|
||||
None => self.free.push(resource),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cleanup(&mut self, raw: &B::Device) {
|
||||
/// Returns the last submission index that is done.
|
||||
fn cleanup(&mut self, raw: &B::Device) -> SubmissionIndex {
|
||||
let mut last_done = 0;
|
||||
|
||||
for i in (0..self.active.len()).rev() {
|
||||
if unsafe { raw.get_fence_status(&self.active[i].fence) }.unwrap() {
|
||||
let af = self.active.swap_remove(i);
|
||||
self.free.extend(af.resources);
|
||||
unsafe { raw.destroy_fence(af.fence) };
|
||||
if unsafe {
|
||||
raw.get_fence_status(&self.active[i].fence).unwrap()
|
||||
} {
|
||||
let a = self.active.swap_remove(i);
|
||||
last_done = last_done.max(a.index);
|
||||
self.free.extend(a.resources);
|
||||
unsafe {
|
||||
raw.destroy_fence(a.fence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,17 +132,21 @@ impl<B: hal::Backend> DestroyedResources<B> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_done
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct Device<B: hal::Backend> {
|
||||
pub(crate) raw: B::Device,
|
||||
queue_group: hal::QueueGroup<B, hal::General>,
|
||||
adapter_id: WeaklyStored<AdapterId>,
|
||||
pub(crate) queue_group: hal::QueueGroup<B, hal::General>,
|
||||
//mem_allocator: Heaps<B::Memory>,
|
||||
pub(crate) com_allocator: command::CommandAllocator<B>,
|
||||
life_guard: LifeGuard,
|
||||
buffer_tracker: Mutex<BufferTracker>,
|
||||
texture_tracker: Mutex<TextureTracker>,
|
||||
pub(crate) texture_tracker: Mutex<TextureTracker>,
|
||||
mem_props: hal::MemoryProperties,
|
||||
pub(crate) render_passes: Mutex<HashMap<RenderPassKey, B::RenderPass>>,
|
||||
pub(crate) framebuffers: Mutex<HashMap<FramebufferKey, B::Framebuffer>>,
|
||||
@ -142,6 +157,7 @@ pub struct Device<B: hal::Backend> {
|
||||
impl<B: hal::Backend> Device<B> {
|
||||
pub(crate) fn new(
|
||||
raw: B::Device,
|
||||
adapter_id: WeaklyStored<AdapterId>,
|
||||
queue_group: hal::QueueGroup<B, hal::General>,
|
||||
mem_props: hal::MemoryProperties,
|
||||
) -> Self {
|
||||
@ -168,6 +184,7 @@ impl<B: hal::Backend> Device<B> {
|
||||
|
||||
Device {
|
||||
raw,
|
||||
adapter_id,
|
||||
//mem_allocator,
|
||||
com_allocator: command::CommandAllocator::new(queue_group.family()),
|
||||
queue_group,
|
||||
@ -246,24 +263,26 @@ pub extern "C" fn wgpu_device_create_texture(
|
||||
|
||||
let life_guard = LifeGuard::new();
|
||||
let ref_count = life_guard.ref_count.clone();
|
||||
let id = HUB.textures.write().register(resource::Texture {
|
||||
raw: bound_image,
|
||||
device_id: Stored {
|
||||
value: device_id,
|
||||
ref_count: device.life_guard.ref_count.clone(),
|
||||
},
|
||||
kind,
|
||||
format: desc.format,
|
||||
full_range,
|
||||
life_guard,
|
||||
});
|
||||
let query = device.texture_tracker.lock().query(
|
||||
&Stored {
|
||||
value: id,
|
||||
ref_count,
|
||||
},
|
||||
TextureUsageFlags::WRITE_ALL,
|
||||
);
|
||||
let id = HUB.textures
|
||||
.write()
|
||||
.register(resource::Texture {
|
||||
raw: bound_image,
|
||||
device_id: Stored {
|
||||
value: device_id,
|
||||
ref_count: device.life_guard.ref_count.clone(),
|
||||
},
|
||||
kind,
|
||||
format: desc.format,
|
||||
full_range,
|
||||
swap_chain_link: None,
|
||||
life_guard,
|
||||
});
|
||||
let query = device.texture_tracker
|
||||
.lock()
|
||||
.query(
|
||||
&Stored { value: id, ref_count },
|
||||
TextureUsageFlags::WRITE_ALL,
|
||||
);
|
||||
assert!(query.initialized);
|
||||
|
||||
id
|
||||
@ -289,26 +308,27 @@ pub extern "C" fn wgpu_texture_create_texture_view(
|
||||
hal::format::Swizzle::NO,
|
||||
hal::image::SubresourceRange {
|
||||
aspects: conv::map_texture_aspect_flags(desc.aspect),
|
||||
levels: desc.base_mip_level as u8
|
||||
..(desc.base_mip_level + desc.level_count) as u8,
|
||||
layers: desc.base_array_layer as u16
|
||||
..(desc.base_array_layer + desc.array_count) as u16,
|
||||
levels: desc.base_mip_level as u8 .. (desc.base_mip_level + desc.level_count) as u8,
|
||||
layers: desc.base_array_layer as u16 .. (desc.base_array_layer + desc.array_count) as u16,
|
||||
},
|
||||
)
|
||||
}
|
||||
.unwrap();
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
HUB.texture_views.write().register(resource::TextureView {
|
||||
raw,
|
||||
texture_id: Stored {
|
||||
value: texture_id,
|
||||
ref_count: texture.life_guard.ref_count.clone(),
|
||||
},
|
||||
format: texture.format,
|
||||
extent: texture.kind.extent(),
|
||||
samples: texture.kind.num_samples(),
|
||||
life_guard: LifeGuard::new(),
|
||||
})
|
||||
HUB.texture_views
|
||||
.write()
|
||||
.register(resource::TextureView {
|
||||
raw,
|
||||
texture_id: Stored {
|
||||
value: texture_id,
|
||||
ref_count: texture.life_guard.ref_count.clone(),
|
||||
},
|
||||
format: texture.format,
|
||||
extent: texture.kind.extent(),
|
||||
samples: texture.kind.num_samples(),
|
||||
is_owned_by_swap_chain: false,
|
||||
life_guard: LifeGuard::new(),
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -322,7 +342,7 @@ pub extern "C" fn wgpu_texture_create_default_texture_view(texture_id: TextureId
|
||||
hal::image::Kind::D3(..) => hal::image::ViewKind::D3,
|
||||
};
|
||||
|
||||
let raw = unsafe {
|
||||
let raw = unsafe{
|
||||
HUB.devices
|
||||
.read()
|
||||
.get(texture.device_id.value)
|
||||
@ -334,20 +354,23 @@ pub extern "C" fn wgpu_texture_create_default_texture_view(texture_id: TextureId
|
||||
hal::format::Swizzle::NO,
|
||||
texture.full_range.clone(),
|
||||
)
|
||||
}
|
||||
.unwrap();
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
HUB.texture_views.write().register(resource::TextureView {
|
||||
raw,
|
||||
texture_id: Stored {
|
||||
value: texture_id,
|
||||
ref_count: texture.life_guard.ref_count.clone(),
|
||||
},
|
||||
format: texture.format,
|
||||
extent: texture.kind.extent(),
|
||||
samples: texture.kind.num_samples(),
|
||||
life_guard: LifeGuard::new(),
|
||||
})
|
||||
HUB.texture_views
|
||||
.write()
|
||||
.register(resource::TextureView {
|
||||
raw,
|
||||
texture_id: Stored {
|
||||
value: texture_id,
|
||||
ref_count: texture.life_guard.ref_count.clone(),
|
||||
},
|
||||
format: texture.format,
|
||||
extent: texture.kind.extent(),
|
||||
samples: texture.kind.num_samples(),
|
||||
is_owned_by_swap_chain: false,
|
||||
life_guard: LifeGuard::new(),
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -521,6 +544,8 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
.submission_index
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
let mut swap_chain_links = Vec::new();
|
||||
|
||||
//TODO: if multiple command buffers are submitted, we can re-use the last
|
||||
// native command buffer of the previous chain instead of always creating
|
||||
// a temporary one, since the chains are not finished.
|
||||
@ -528,7 +553,10 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
// finish all the command buffers first
|
||||
for &cmb_id in command_buffer_ids {
|
||||
let comb = command_buffer_guard.get_mut(cmb_id);
|
||||
swap_chain_links.extend(comb.swap_chain_links.drain(..));
|
||||
// update submission IDs
|
||||
comb.life_guard.submission_index
|
||||
.store(old_submit_index, Ordering::Release);
|
||||
for id in comb.buffer_tracker.used() {
|
||||
buffer_guard
|
||||
.get(id)
|
||||
@ -572,14 +600,25 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
// now prepare the GPU submission
|
||||
let fence = device.raw.create_fence(false).unwrap();
|
||||
{
|
||||
let swap_chain_guard = HUB.swap_chains.read();
|
||||
let wait_semaphores = swap_chain_links
|
||||
.into_iter()
|
||||
.map(|link| {
|
||||
//TODO: check the epoch
|
||||
let sem = &swap_chain_guard
|
||||
.get(link.swap_chain_id.0)
|
||||
.frames[link.image_index as usize]
|
||||
.sem_available;
|
||||
(sem, hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT)
|
||||
});
|
||||
let submission =
|
||||
hal::queue::Submission::<_, _, &[<back::Backend as hal::Backend>::Semaphore]> {
|
||||
//TODO: may `OneShot` be enough?
|
||||
command_buffers: command_buffer_ids
|
||||
.iter()
|
||||
.flat_map(|&cmb_id| &command_buffer_guard.get(cmb_id).raw),
|
||||
wait_semaphores: Vec::new(),
|
||||
signal_semaphores: &[],
|
||||
wait_semaphores,
|
||||
signal_semaphores: &[], //TODO: signal `sem_present`?
|
||||
};
|
||||
unsafe {
|
||||
device.queue_group.queues[0]
|
||||
@ -588,17 +627,21 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let last_done = {
|
||||
let mut destroyed = device.destroyed.lock();
|
||||
destroyed.triage_referenced(&mut *buffer_guard, &mut *texture_guard);
|
||||
destroyed.cleanup(&device.raw);
|
||||
let last_done = destroyed.cleanup(&device.raw);
|
||||
|
||||
destroyed.active.push(ActiveFrame {
|
||||
submission_index: old_submit_index + 1,
|
||||
destroyed.active.push(ActiveSubmission {
|
||||
index: old_submit_index + 1,
|
||||
fence,
|
||||
resources: Vec::new(),
|
||||
});
|
||||
}
|
||||
|
||||
last_done
|
||||
};
|
||||
|
||||
device.com_allocator.maintain(&device.raw, last_done);
|
||||
|
||||
// finally, return the command buffers to the allocator
|
||||
for &cmb_id in command_buffer_ids {
|
||||
@ -823,3 +866,150 @@ pub extern "C" fn wgpu_device_create_render_pipeline(
|
||||
.write()
|
||||
.register(pipeline::RenderPipeline { raw: pipeline })
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_device_create_swap_chain(
|
||||
device_id: DeviceId,
|
||||
surface_id: SurfaceId,
|
||||
desc: &swap_chain::SwapChainDescriptor,
|
||||
) -> SwapChainId {
|
||||
let device_guard = HUB.devices.read();
|
||||
let device = device_guard.get(device_id);
|
||||
let mut surface_guard = HUB.surfaces.write();
|
||||
let surface = surface_guard.get_mut(surface_id);
|
||||
|
||||
let (caps, formats, _present_modes, _composite_alphas) = {
|
||||
let adapter_guard = HUB.adapters.read();
|
||||
let adapter = adapter_guard.get(device.adapter_id.0);
|
||||
assert!(surface.raw.supports_queue_family(&adapter.queue_families[0]));
|
||||
surface.raw.compatibility(&adapter.physical_device)
|
||||
};
|
||||
let num_frames = caps.image_count.start; //TODO: configure?
|
||||
let frame_format = conv::map_texture_format(desc.format);
|
||||
let config = hal::SwapchainConfig::new(
|
||||
desc.width,
|
||||
desc.height,
|
||||
frame_format,
|
||||
num_frames, //TODO: configure?
|
||||
);
|
||||
|
||||
let usage = conv::map_texture_usage(desc.usage, hal::format::Aspects::COLOR);
|
||||
if let Some(formats) = formats {
|
||||
assert!(formats.contains(&config.format),
|
||||
"Requested format {:?} is not in supported list: {:?}",
|
||||
config.format, formats);
|
||||
}
|
||||
//TODO: properly exclusive range
|
||||
assert!(desc.width >= caps.extents.start.width && desc.width <= caps.extents.end.width &&
|
||||
desc.height >= caps.extents.start.height && desc.height <= caps.extents.end.height,
|
||||
"Requested size {}x{} is outside of the supported range: {:?}",
|
||||
desc.width, desc.height, caps.extents);
|
||||
|
||||
let (raw, backbuffer) = unsafe {
|
||||
device.raw
|
||||
.create_swapchain(
|
||||
&mut surface.raw,
|
||||
config.with_image_usage(usage),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
let command_pool = unsafe {
|
||||
device.raw
|
||||
.create_command_pool_typed(
|
||||
&device.queue_group,
|
||||
hal::pool::CommandPoolCreateFlags::RESET_INDIVIDUAL,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let mut swap_chain_guard = HUB.swap_chains.write();
|
||||
|
||||
let swap_chain_id = swap_chain_guard
|
||||
.register(swap_chain::SwapChain {
|
||||
raw,
|
||||
device_id: Stored {
|
||||
value: device_id,
|
||||
ref_count: device.life_guard.ref_count.clone(),
|
||||
},
|
||||
frames: Vec::with_capacity(num_frames as usize),
|
||||
acquired: Vec::with_capacity(1), //TODO: get it from gfx-hal?
|
||||
sem_available: device.raw.create_semaphore().unwrap(),
|
||||
command_pool,
|
||||
});
|
||||
let swap_chain = swap_chain_guard.get_mut(swap_chain_id);
|
||||
|
||||
let images = match backbuffer {
|
||||
hal::Backbuffer::Images(images) => images,
|
||||
hal::Backbuffer::Framebuffer(_) => panic!("Deprecated API detected!"),
|
||||
};
|
||||
|
||||
let mut texture_guard = HUB.textures.write();
|
||||
let mut texture_view_guard = HUB.texture_views.write();
|
||||
|
||||
for (i, image) in images.into_iter().enumerate() {
|
||||
let kind = hal::image::Kind::D2(desc.width, desc.height, 1, 1);
|
||||
let full_range = hal::image::SubresourceRange {
|
||||
aspects: hal::format::Aspects::COLOR,
|
||||
levels: 0 .. 1,
|
||||
layers: 0 .. 1,
|
||||
};
|
||||
let view_raw = unsafe {
|
||||
device.raw
|
||||
.create_image_view(
|
||||
&image,
|
||||
hal::image::ViewKind::D2,
|
||||
frame_format,
|
||||
hal::format::Swizzle::NO,
|
||||
full_range.clone(),
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
let texture = resource::Texture {
|
||||
raw: image,
|
||||
device_id: Stored {
|
||||
value: device_id,
|
||||
ref_count: device.life_guard.ref_count.clone(),
|
||||
},
|
||||
kind,
|
||||
format: desc.format,
|
||||
full_range,
|
||||
swap_chain_link: Some(swap_chain::SwapChainLink {
|
||||
swap_chain_id: WeaklyStored(swap_chain_id), //TODO: strongly
|
||||
epoch: Mutex::new(0),
|
||||
image_index: i as hal::SwapImageIndex,
|
||||
}),
|
||||
life_guard: LifeGuard::new(),
|
||||
};
|
||||
let texture_id = Stored {
|
||||
ref_count: texture.life_guard.ref_count.clone(),
|
||||
value: texture_guard.register(texture),
|
||||
};
|
||||
device.texture_tracker
|
||||
.lock()
|
||||
.query(&texture_id, TextureUsageFlags::WRITE_ALL);
|
||||
|
||||
let view = resource::TextureView {
|
||||
raw: view_raw,
|
||||
texture_id: texture_id.clone(),
|
||||
format: desc.format,
|
||||
extent: kind.extent(),
|
||||
samples: kind.num_samples(),
|
||||
is_owned_by_swap_chain: true,
|
||||
life_guard: LifeGuard::new(),
|
||||
};
|
||||
swap_chain.frames.push(swap_chain::Frame {
|
||||
texture_id,
|
||||
view_id: Stored {
|
||||
ref_count: view.life_guard.ref_count.clone(),
|
||||
value: texture_view_guard.register(view),
|
||||
},
|
||||
fence: device.raw.create_fence(true).unwrap(),
|
||||
sem_available: device.raw.create_semaphore().unwrap(),
|
||||
sem_present: device.raw.create_semaphore().unwrap(),
|
||||
comb: swap_chain.command_pool.acquire_command_buffer(),
|
||||
});
|
||||
}
|
||||
|
||||
swap_chain_id
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
use hal::{Instance as _Instance, PhysicalDevice as _PhysicalDevice};
|
||||
use crate::registry::{HUB, Items};
|
||||
use crate::{WeaklyStored, Device,
|
||||
AdapterId, DeviceId, InstanceId,
|
||||
};
|
||||
#[cfg(feature = "winit")]
|
||||
use crate::{Surface, SurfaceId};
|
||||
|
||||
use hal::{self, Instance as _Instance, PhysicalDevice as _PhysicalDevice};
|
||||
|
||||
use crate::registry::{Items, HUB};
|
||||
use crate::{AdapterId, Device, DeviceId, InstanceId};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
@ -30,21 +35,36 @@ pub struct DeviceDescriptor {
|
||||
pub extern "C" fn wgpu_create_instance() -> InstanceId {
|
||||
#[cfg(any(
|
||||
feature = "gfx-backend-vulkan",
|
||||
feature = "gfx-backend-dx11",
|
||||
feature = "gfx-backend-dx12",
|
||||
feature = "gfx-backend-metal"
|
||||
))]
|
||||
{
|
||||
let inst = ::back::Instance::create("wgpu", 1);
|
||||
HUB.instances.write().register(inst)
|
||||
}
|
||||
#[cfg(not(any(
|
||||
feature = "gfx-backend-vulkan",
|
||||
feature = "gfx-backend-dx12",
|
||||
feature = "gfx-backend-metal"
|
||||
)))]
|
||||
{
|
||||
unimplemented!()
|
||||
if true {
|
||||
return HUB.instances.write().register(inst);
|
||||
}
|
||||
}
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(feature = "winit")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_instance_create_surface_from_winit(
|
||||
instance_id: InstanceId,
|
||||
window: &winit::Window,
|
||||
) -> SurfaceId {
|
||||
let raw = HUB.instances
|
||||
.read()
|
||||
.get(instance_id)
|
||||
.create_surface(window);
|
||||
let surface = Surface {
|
||||
raw,
|
||||
};
|
||||
|
||||
HUB.surfaces
|
||||
.write()
|
||||
.register(surface)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -77,9 +97,11 @@ pub extern "C" fn wgpu_adapter_create_device(
|
||||
) -> DeviceId {
|
||||
let mut adapter_guard = HUB.adapters.write();
|
||||
let adapter = adapter_guard.get_mut(adapter_id);
|
||||
let (device, queue_group) = adapter.open_with::<_, hal::General>(1, |_qf| true).unwrap();
|
||||
let (raw, queue_group) = adapter.open_with::<_, hal::General>(1, |_qf| true).unwrap();
|
||||
let mem_props = adapter.physical_device.memory_properties();
|
||||
let device = Device::new(raw, WeaklyStored(adapter_id), queue_group, mem_props);
|
||||
|
||||
HUB.devices
|
||||
.write()
|
||||
.register(Device::new(device, queue_group, mem_props))
|
||||
.register(device)
|
||||
}
|
||||
|
@ -1,9 +1,15 @@
|
||||
#[cfg(feature = "winit")]
|
||||
pub extern crate winit;
|
||||
|
||||
#[cfg(feature = "gfx-backend-dx11")]
|
||||
extern crate gfx_backend_dx11 as back;
|
||||
#[cfg(feature = "gfx-backend-dx12")]
|
||||
extern crate gfx_backend_dx12 as back;
|
||||
#[cfg(not(any(
|
||||
feature = "gfx-backend-vulkan",
|
||||
feature = "gfx-backend-dx11",
|
||||
feature = "gfx-backend-dx12",
|
||||
feature = "gfx-backend-metal"
|
||||
feature = "gfx-backend-metal",
|
||||
)))]
|
||||
extern crate gfx_backend_empty as back;
|
||||
#[cfg(feature = "gfx-backend-metal")]
|
||||
@ -22,6 +28,7 @@ mod instance;
|
||||
mod pipeline;
|
||||
mod registry;
|
||||
mod resource;
|
||||
mod swap_chain;
|
||||
mod track;
|
||||
|
||||
pub use self::binding_model::*;
|
||||
@ -30,6 +37,7 @@ pub use self::device::*;
|
||||
pub use self::instance::*;
|
||||
pub use self::pipeline::*;
|
||||
pub use self::resource::*;
|
||||
pub use self::swap_chain::*;
|
||||
|
||||
use back::Backend as B;
|
||||
pub use crate::registry::Id;
|
||||
@ -85,7 +93,7 @@ impl LifeGuard {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct Stored<T> {
|
||||
value: T,
|
||||
ref_count: RefCount,
|
||||
@ -94,7 +102,7 @@ struct Stored<T> {
|
||||
unsafe impl<T> Send for Stored<T> {}
|
||||
unsafe impl<T> Sync for Stored<T> {}
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
struct WeaklyStored<T>(T);
|
||||
|
||||
unsafe impl<T> Send for WeaklyStored<T> {}
|
||||
@ -214,3 +222,9 @@ pub type RenderPassId = Id;
|
||||
type RenderPassHandle = RenderPass<B>;
|
||||
pub type ComputePassId = Id;
|
||||
type ComputePassHandle = ComputePass<B>;
|
||||
|
||||
|
||||
pub type SurfaceId = Id;
|
||||
type SurfaceHandle = Surface<B>;
|
||||
pub type SwapChainId = Id;
|
||||
type SwapChainHandle = SwapChain<B>;
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::resource;
|
||||
|
||||
use crate::{BlendStateId, ByteArray, DepthStencilStateId, PipelineLayoutId, ShaderModuleId};
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum BlendFactor {
|
||||
|
@ -1,15 +1,17 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::RwLock;
|
||||
use crate::{
|
||||
AdapterHandle, BindGroupLayoutHandle, BindGroupHandle,
|
||||
BlendStateHandle, CommandBufferHandle, DepthStencilStateHandle, DeviceHandle, InstanceHandle,
|
||||
RenderPassHandle, ComputePassHandle,
|
||||
PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle,
|
||||
BufferHandle, TextureHandle, TextureViewHandle,
|
||||
SurfaceHandle, SwapChainHandle,
|
||||
};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
AdapterHandle, BindGroupHandle, BindGroupLayoutHandle, BlendStateHandle, BufferHandle,
|
||||
CommandBufferHandle, ComputePassHandle, ComputePipelineHandle, DepthStencilStateHandle,
|
||||
DeviceHandle, InstanceHandle, PipelineLayoutHandle, RenderPassHandle, RenderPipelineHandle,
|
||||
ShaderModuleHandle, TextureHandle, TextureViewHandle,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "remote"))]
|
||||
mod local;
|
||||
@ -49,6 +51,8 @@ pub struct Hub {
|
||||
pub(crate) buffers: ConcreteRegistry<BufferHandle>,
|
||||
pub(crate) textures: ConcreteRegistry<TextureHandle>,
|
||||
pub(crate) texture_views: ConcreteRegistry<TextureViewHandle>,
|
||||
pub(crate) surfaces: ConcreteRegistry<SurfaceHandle>,
|
||||
pub(crate) swap_chains: ConcreteRegistry<SwapChainHandle>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
|
@ -1,6 +1,13 @@
|
||||
use crate::{DeviceId, Extent3d, LifeGuard, Stored, TextureId};
|
||||
use crate::{
|
||||
Extent3d, LifeGuard, Stored,
|
||||
DeviceId, TextureId,
|
||||
};
|
||||
use crate::swap_chain::{SwapChainLink, SwapImageEpoch};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use hal;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
|
||||
bitflags! {
|
||||
#[repr(transparent)]
|
||||
@ -78,6 +85,7 @@ pub(crate) struct Texture<B: hal::Backend> {
|
||||
pub kind: hal::image::Kind,
|
||||
pub format: TextureFormat,
|
||||
pub full_range: hal::image::SubresourceRange,
|
||||
pub swap_chain_link: Option<SwapChainLink<Mutex<SwapImageEpoch>>>,
|
||||
pub life_guard: LifeGuard,
|
||||
}
|
||||
|
||||
@ -118,6 +126,7 @@ pub(crate) struct TextureView<B: hal::Backend> {
|
||||
pub format: TextureFormat,
|
||||
pub extent: hal::image::Extent,
|
||||
pub samples: hal::image::NumSamples,
|
||||
pub is_owned_by_swap_chain: bool,
|
||||
pub life_guard: LifeGuard,
|
||||
}
|
||||
|
||||
|
170
wgpu-native/src/swap_chain.rs
Normal file
170
wgpu-native/src/swap_chain.rs
Normal file
@ -0,0 +1,170 @@
|
||||
use crate::{Stored, WeaklyStored,
|
||||
DeviceId, SwapChainId, TextureId, TextureViewId,
|
||||
};
|
||||
use crate::{conv, resource};
|
||||
use crate::registry::{HUB, Items};
|
||||
use crate::track::{Tracktion, TrackPermit};
|
||||
|
||||
use hal;
|
||||
use hal::{Device as _Device, Swapchain as _Swapchain};
|
||||
use log::trace;
|
||||
|
||||
use std::{iter, mem};
|
||||
|
||||
|
||||
pub type SwapImageEpoch = u16;
|
||||
|
||||
pub(crate) struct SwapChainLink<E> {
|
||||
pub swap_chain_id: WeaklyStored<SwapChainId>, //TODO: strongly
|
||||
pub epoch: E,
|
||||
pub image_index: hal::SwapImageIndex,
|
||||
}
|
||||
|
||||
pub(crate) struct Surface<B: hal::Backend> {
|
||||
pub raw: B::Surface,
|
||||
}
|
||||
|
||||
pub(crate) struct Frame<B: hal::Backend> {
|
||||
pub texture_id: Stored<TextureId>,
|
||||
pub view_id: Stored<TextureViewId>,
|
||||
pub fence: B::Fence,
|
||||
pub sem_available: B::Semaphore,
|
||||
pub sem_present: B::Semaphore,
|
||||
pub comb: hal::command::CommandBuffer<B, hal::General, hal::command::MultiShot>,
|
||||
}
|
||||
|
||||
//TODO: does it need a ref-counted lifetime?
|
||||
|
||||
pub(crate) struct SwapChain<B: hal::Backend> {
|
||||
pub raw: B::Swapchain,
|
||||
pub device_id: Stored<DeviceId>,
|
||||
pub frames: Vec<Frame<B>>,
|
||||
pub acquired: Vec<hal::SwapImageIndex>,
|
||||
pub sem_available: B::Semaphore,
|
||||
pub command_pool: hal::CommandPool<B, hal::General>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SwapChainDescriptor {
|
||||
pub usage: resource::TextureUsageFlags,
|
||||
pub format: resource::TextureFormat,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SwapChainOutput {
|
||||
pub texture_id: TextureId,
|
||||
pub view_id: TextureViewId,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_swap_chain_get_next_texture(
|
||||
swap_chain_id: SwapChainId,
|
||||
) -> SwapChainOutput {
|
||||
let mut swap_chain_guard = HUB.swap_chains.write();
|
||||
let swap_chain = swap_chain_guard.get_mut(swap_chain_id);
|
||||
assert_ne!(swap_chain.acquired.len(), swap_chain.acquired.capacity(),
|
||||
"Unable to acquire any more swap chain images before presenting");
|
||||
|
||||
let device_guard = HUB.devices.read();
|
||||
let device = device_guard.get(swap_chain.device_id.value);
|
||||
|
||||
let image_index = unsafe {
|
||||
let sync = hal::FrameSync::Semaphore(&swap_chain.sem_available);
|
||||
swap_chain.raw.acquire_image(!0, sync).unwrap()
|
||||
};
|
||||
|
||||
swap_chain.acquired.push(image_index);
|
||||
let frame = &mut swap_chain.frames[image_index as usize];
|
||||
unsafe {
|
||||
device.raw.wait_for_fence(&frame.fence, !0).unwrap();
|
||||
}
|
||||
|
||||
mem::swap(&mut frame.sem_available, &mut swap_chain.sem_available);
|
||||
|
||||
let texture_guard = HUB.textures.read();
|
||||
let texture = texture_guard.get(frame.texture_id.value);
|
||||
match texture.swap_chain_link {
|
||||
Some(ref link) => *link.epoch.lock() += 1,
|
||||
None => unreachable!(),
|
||||
}
|
||||
|
||||
SwapChainOutput {
|
||||
texture_id: frame.texture_id.value,
|
||||
view_id: frame.view_id.value,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_swap_chain_present(
|
||||
swap_chain_id: SwapChainId,
|
||||
) {
|
||||
let mut swap_chain_guard = HUB.swap_chains.write();
|
||||
let swap_chain = swap_chain_guard.get_mut(swap_chain_id);
|
||||
let mut device_guard = HUB.devices.write();
|
||||
let device = device_guard.get_mut(swap_chain.device_id.value);
|
||||
|
||||
let image_index = swap_chain.acquired.remove(0);
|
||||
let frame = &mut swap_chain.frames[image_index as usize];
|
||||
|
||||
let texture_guard = HUB.textures.read();
|
||||
let texture = texture_guard.get(frame.texture_id.value);
|
||||
match texture.swap_chain_link {
|
||||
Some(ref link) => *link.epoch.lock() += 1,
|
||||
None => unreachable!(),
|
||||
}
|
||||
|
||||
trace!("transit {:?} to present", frame.texture_id.value);
|
||||
let tracktion = device.texture_tracker
|
||||
.lock()
|
||||
.transit(
|
||||
frame.texture_id.value,
|
||||
&texture.life_guard.ref_count,
|
||||
resource::TextureUsageFlags::PRESENT,
|
||||
TrackPermit::REPLACE,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let barrier = match tracktion {
|
||||
Tracktion::Keep => None,
|
||||
Tracktion::Replace { old } => Some(hal::memory::Barrier::Image {
|
||||
states: conv::map_texture_state(old, hal::format::Aspects::COLOR) ..
|
||||
(hal::image::Access::empty(), hal::image::Layout::Present),
|
||||
target: &texture.raw,
|
||||
families: None,
|
||||
range: texture.full_range.clone(),
|
||||
}),
|
||||
Tracktion::Init |
|
||||
Tracktion::Extend {..} => unreachable!(),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
frame.comb.begin(false);
|
||||
frame.comb.pipeline_barrier(
|
||||
hal::pso::PipelineStage::TOP_OF_PIPE .. hal::pso::PipelineStage::BOTTOM_OF_PIPE,
|
||||
hal::memory::Dependencies::empty(),
|
||||
barrier,
|
||||
);
|
||||
frame.comb.finish();
|
||||
|
||||
// now prepare the GPU submission
|
||||
let submission = hal::Submission {
|
||||
command_buffers: iter::once(&frame.comb),
|
||||
wait_semaphores: None,
|
||||
signal_semaphores: Some(&frame.sem_present),
|
||||
};
|
||||
|
||||
device.raw.reset_fence(&frame.fence).unwrap();
|
||||
device.queue_group.queues[0]
|
||||
.submit(submission, Some(&frame.fence));
|
||||
|
||||
swap_chain.raw
|
||||
.present(
|
||||
&mut device.queue_group.queues[0],
|
||||
image_index,
|
||||
iter::once(&frame.sem_present),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ use std::ops::{BitOr, Range};
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[allow(unused)]
|
||||
pub enum Tracktion<T> {
|
||||
|
@ -11,7 +11,9 @@ edition = "2018"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
winit = ["wgpu-native/winit"]
|
||||
metal = ["wgpu-native/gfx-backend-metal"]
|
||||
dx11 = ["wgpu-native/gfx-backend-dx11"]
|
||||
dx12 = ["wgpu-native/gfx-backend-dx12"]
|
||||
vulkan = ["wgpu-native/gfx-backend-vulkan"]
|
||||
|
||||
|
@ -13,6 +13,7 @@ pub use wgn::{
|
||||
RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor,
|
||||
RenderPassDescriptor, ShaderModuleDescriptor, ShaderStage, ShaderStageFlags, StoreOp,
|
||||
TextureDescriptor, TextureDimension, TextureFormat, TextureUsageFlags, TextureViewDescriptor,
|
||||
SwapChainDescriptor,
|
||||
};
|
||||
|
||||
pub struct Instance {
|
||||
@ -35,6 +36,14 @@ pub struct TextureView {
|
||||
id: wgn::TextureViewId,
|
||||
}
|
||||
|
||||
pub struct Surface {
|
||||
id: wgn::SurfaceId,
|
||||
}
|
||||
|
||||
pub struct SwapChain {
|
||||
id: wgn::SwapChainId,
|
||||
}
|
||||
|
||||
pub struct BindGroupLayout {
|
||||
id: wgn::BindGroupLayoutId,
|
||||
}
|
||||
@ -125,6 +134,13 @@ impl Instance {
|
||||
id: wgn::wgpu_instance_get_adapter(self.id, desc),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "winit")]
|
||||
pub fn create_surface(&self, window: &wgn::winit::Window) -> Surface {
|
||||
Surface {
|
||||
id: wgn::wgpu_instance_create_surface_from_winit(self.id, window)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Adapter {
|
||||
@ -148,6 +164,7 @@ impl Device {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: borrow instead of new object?
|
||||
pub fn get_queue(&self) -> Queue {
|
||||
Queue {
|
||||
id: wgn::wgpu_device_get_queue(self.id),
|
||||
@ -255,6 +272,12 @@ impl Device {
|
||||
id: wgn::wgpu_device_create_texture(self.id, &desc),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_swap_chain(&self, surface: &Surface, desc: &SwapChainDescriptor) -> SwapChain {
|
||||
SwapChain {
|
||||
id: wgn::wgpu_device_create_swap_chain(self.id, surface.id, desc),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Texture {
|
||||
@ -351,3 +374,15 @@ impl Queue {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl SwapChain {
|
||||
//TODO: borrow instead of new object?
|
||||
pub fn get_next_texture(&self) -> (Texture, TextureView) {
|
||||
let output = wgn::wgpu_swap_chain_get_next_texture(self.id);
|
||||
(Texture { id: output.texture_id} , TextureView { id: output.view_id })
|
||||
}
|
||||
|
||||
pub fn present(&self) {
|
||||
wgn::wgpu_swap_chain_present(self.id);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user