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:
bors[bot] 2019-01-19 13:31:35 +00:00
commit 0f592b4443
20 changed files with 731 additions and 168 deletions

38
Cargo.lock generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,6 +2,7 @@ use crate::{BindGroupLayoutId, BufferId, SamplerId, TextureViewId};
use bitflags::bitflags;
bitflags! {
#[repr(transparent)]
pub struct ShaderStageFlags: u32 {

View File

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

View File

@ -5,6 +5,7 @@ use hal::command::RawCommandBuffer;
use std::iter;
pub struct ComputePass<B: hal::Backend> {
raw: B::CommandBuffer,
cmb_id: Stored<CommandBufferId>,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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! {

View File

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

View 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();
}
}

View File

@ -8,6 +8,7 @@ use std::ops::{BitOr, Range};
use bitflags::bitflags;
#[derive(Clone, Debug, PartialEq)]
#[allow(unused)]
pub enum Tracktion<T> {

View File

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

View File

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