Skip to content

Commit

Permalink
Merge #69
Browse files Browse the repository at this point in the history
69: Swapchain resize r=kvark a=kvark

Based on #67 

Here are the steps (as outlined on Gitter) that this PR follows:
  1. create a dummy frame in the swapchain (`SwapChain::outdated`). We return it when we aren't able to acquire a real frame. No synchronization is done atm, but shouldn't be anything critical there.
  2. handle the errors on acquire and present, use the dummy frame where needed. Presentation errors are just ignored, while acquiring errors are forcing the dummy frame. The idea is that the user would know about a swapchain resize from some kind of event loop / WSI, and thus they'd know when they should actually re-create it.
  3. associate surface with a swapchain. We merge the IDs since there can't be multiple swapchains on the same surface in the near future. Merging simplifies a lot of things in the implementation, but this is to be revised for sure once we get a better look on the browser integration.
  4. when the swapchain is re-created, consume the old one associated with a surface.


Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
  • Loading branch information
bors[bot] and kvark committed Feb 22, 2019
2 parents 917626c + 59fe349 commit 022087b
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 122 deletions.
36 changes: 23 additions & 13 deletions gfx-examples/src/cube.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,22 @@ struct Cube {
index_buf: wgpu::Buffer,
index_count: usize,
bind_group: wgpu::BindGroup,
uniform_buf: wgpu::Buffer,
pipeline: wgpu::RenderPipeline,
}

impl Cube {
fn generate_matrix(aspect_ratio: f32) -> cgmath::Matrix4<f32> {
let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 10.0);
let mx_view = cgmath::Matrix4::look_at(
cgmath::Point3::new(1.5f32, -5.0, 3.0),
cgmath::Point3::new(0f32, 0.0, 0.0),
cgmath::Vector3::unit_z(),
);
mx_projection * mx_view
}
}

impl framework::Example for Cube {
fn init(device: &mut wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self {
use std::mem;
Expand Down Expand Up @@ -196,18 +209,9 @@ impl framework::Example for Cube {
size: 64,
usage: wgpu::BufferUsageFlags::UNIFORM | wgpu::BufferUsageFlags::TRANSFER_DST,
});
{
let aspect_ratio = sc_desc.width as f32 / sc_desc.height as f32;
let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 10.0);
let mx_view = cgmath::Matrix4::look_at(
cgmath::Point3::new(1.5f32, -5.0, 3.0),
cgmath::Point3::new(0f32, 0.0, 0.0),
cgmath::Vector3::unit_z(),
);
let mx_total = mx_projection * mx_view;
let mx_raw: &[f32; 16] = mx_total.as_ref();
uniform_buf.set_sub_data(0, framework::cast_slice(&mx_raw[..]));
}
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
let mx_ref: &[f32; 16] = mx_total.as_ref();
uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..]));

// Create bind group
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
Expand Down Expand Up @@ -294,11 +298,17 @@ impl framework::Example for Cube {
index_buf,
index_count: index_data.len(),
bind_group,
uniform_buf,
pipeline,
}
}

fn update(&mut self, _event: wgpu::winit::WindowEvent) {
fn update(&mut self, event: wgpu::winit::WindowEvent) {
if let wgpu::winit::WindowEvent::Resized(size) = event {
let mx_total = Self::generate_matrix(size.width as f32 / size.height as f32);
let mx_ref: &[f32; 16] = mx_total.as_ref();
self.uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..]));
}
}

fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
Expand Down
8 changes: 6 additions & 2 deletions gfx-examples/src/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ pub fn run<E: Example>(title: &str) {
.to_physical(window.get_hidpi_factor());

let surface = instance.create_surface(&window);
let sc_desc = wgpu::SwapChainDescriptor {
let mut sc_desc = wgpu::SwapChainDescriptor {
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT,
format: wgpu::TextureFormat::B8g8r8a8Unorm,
width: size.width as u32,
Expand All @@ -91,7 +91,11 @@ pub fn run<E: Example>(title: &str) {
..
} => {
let physical = size.to_physical(window.get_hidpi_factor());
info!("Resized to {:?}", physical);
info!("Resizing to {:?}", physical);
sc_desc.width = physical.width as u32;
sc_desc.height = physical.height as u32;
swap_chain = device.create_swap_chain(&surface, &sc_desc);
example.update(WindowEvent::Resized(size));
}
Event::WindowEvent { event, .. } => match event {
WindowEvent::KeyboardInput {
Expand Down
4 changes: 2 additions & 2 deletions wgpu-bindings/wgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,10 +435,10 @@ typedef struct {
WGPUByteArray code;
} WGPUShaderModuleDescriptor;

typedef WGPUId WGPUSwapChainId;

typedef WGPUId WGPUSurfaceId;

typedef WGPUSurfaceId WGPUSwapChainId;

typedef uint32_t WGPUTextureUsageFlags;

typedef struct {
Expand Down
137 changes: 96 additions & 41 deletions wgpu-native/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,8 @@ unsafe impl<B: hal::Backend> Send for DestroyedResources<B> {}
unsafe impl<B: hal::Backend> Sync for DestroyedResources<B> {}

impl<B: hal::Backend> DestroyedResources<B> {
fn add(&mut self, resource_id: ResourceId, life_guard: &LifeGuard) {
self.referenced
.push((resource_id, life_guard.ref_count.clone()));
fn add(&mut self, resource_id: ResourceId, ref_count: RefCount) {
self.referenced.push((resource_id, ref_count));
}

/// Returns the last submission index that is done.
Expand Down Expand Up @@ -139,7 +138,11 @@ impl<B: hal::Backend> DestroyedResources<B> {
}

impl DestroyedResources<back::Backend> {
fn triage_referenced(&mut self) {
fn triage_referenced(
&mut self,
buffer_tracker: &mut BufferTracker,
texture_tracker: &mut TextureTracker,
) {
for i in (0..self.referenced.len()).rev() {
// one in resource itself, and one here in this list
let num_refs = self.referenced[i].1.load();
Expand All @@ -148,11 +151,13 @@ impl DestroyedResources<back::Backend> {
let resource_id = self.referenced.swap_remove(i).0;
let (submit_index, resource) = match resource_id {
ResourceId::Buffer(id) => {
buffer_tracker.remove(id);
let buf = HUB.buffers.unregister(id);
let si = buf.life_guard.submission_index.load(Ordering::Acquire);
(si, Resource::Buffer(buf))
}
ResourceId::Texture(id) => {
texture_tracker.remove(id);
let tex = HUB.textures.unregister(id);
let si = tex.life_guard.submission_index.load(Ordering::Acquire);
(si, Resource::Texture(tex))
Expand Down Expand Up @@ -369,7 +374,10 @@ pub extern "C" fn wgpu_buffer_destroy(buffer_id: BufferId) {
.get(buffer.device_id.value)
.destroyed
.lock()
.add(ResourceId::Buffer(buffer_id), &buffer.life_guard);
.add(
ResourceId::Buffer(buffer_id),
buffer.life_guard.ref_count.clone(),
);
}


Expand Down Expand Up @@ -579,7 +587,10 @@ pub extern "C" fn wgpu_texture_destroy(texture_id: TextureId) {
.get(texture.device_id.value)
.destroyed
.lock()
.add(ResourceId::Texture(texture_id), &texture.life_guard);
.add(
ResourceId::Texture(texture_id),
texture.life_guard.ref_count.clone(),
);
}

#[no_mangle]
Expand All @@ -595,7 +606,10 @@ pub extern "C" fn wgpu_texture_view_destroy(texture_view_id: TextureViewId) {
.get(device_id)
.destroyed
.lock()
.add(ResourceId::TextureView(texture_view_id), &view.life_guard);
.add(
ResourceId::TextureView(texture_view_id),
view.life_guard.ref_count.clone(),
);
}


Expand Down Expand Up @@ -902,6 +916,8 @@ pub extern "C" fn wgpu_queue_submit(
.life_guard
.submission_index
.fetch_add(1, Ordering::Relaxed);
let mut buffer_tracker = device.buffer_tracker.lock();
let mut texture_tracker = device.texture_tracker.lock();

//TODO: if multiple command buffers are submitted, we can re-use the last
// native command buffer of the previous chain instead of always creating
Expand All @@ -910,8 +926,6 @@ pub extern "C" fn wgpu_queue_submit(
let mut command_buffer_guard = HUB.command_buffers.write();
let buffer_guard = HUB.buffers.read();
let texture_guard = HUB.textures.read();
let mut buffer_tracker = device.buffer_tracker.lock();
let mut texture_tracker = device.texture_tracker.lock();

// finish all the command buffers first
for &cmb_id in command_buffer_ids {
Expand Down Expand Up @@ -965,17 +979,20 @@ pub extern "C" fn wgpu_queue_submit(
let fence = device.raw.create_fence(false).unwrap();
{
let command_buffer_guard = HUB.command_buffers.read();
let swap_chain_guard = HUB.swap_chains.read();
let surface_guard = HUB.surfaces.read();

let wait_semaphores = swap_chain_links
.into_iter()
.map(|link| {
.flat_map(|link| {
//TODO: check the epoch
let sem = &swap_chain_guard
surface_guard
.get(link.swap_chain_id.0)
.frames[link.image_index as usize]
.sem_available;
(sem, hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT)
.swap_chain
.as_ref()
.map(|swap_chain| (
&swap_chain.frames[link.image_index as usize].sem_available,
hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT,
))
});

let submission =
Expand All @@ -997,7 +1014,7 @@ pub extern "C" fn wgpu_queue_submit(

let last_done = {
let mut destroyed = device.destroyed.lock();
destroyed.triage_referenced();
destroyed.triage_referenced(&mut *buffer_tracker, &mut *texture_tracker);
let last_done = destroyed.cleanup(&device.raw);

destroyed.active.push(ActiveSubmission {
Expand Down Expand Up @@ -1294,12 +1311,12 @@ pub extern "C" fn wgpu_device_create_compute_pipeline(
HUB.compute_pipelines.register(pipeline)
}


pub fn device_create_swap_chain(
device_id: DeviceId,
surface_id: SurfaceId,
desc: &swap_chain::SwapChainDescriptor,
) -> (swap_chain::SwapChain<back::Backend>, Vec<resource::Texture<back::Backend>>) {
outdated: swap_chain::OutdatedFrame,
) -> Vec<resource::Texture<back::Backend>> {
let device_guard = HUB.devices.read();
let device = device_guard.get(device_id);
let mut surface_guard = HUB.surfaces.write();
Expand Down Expand Up @@ -1331,42 +1348,60 @@ pub fn device_create_swap_chain(
"Requested size {}x{} is outside of the supported range: {:?}",
desc.width, desc.height, caps.extents);


let (old_raw, sem_available, command_pool) = match surface.swap_chain.take() {
Some(mut old) => {
assert_eq!(old.device_id.value, device_id);
let mut destroyed = device.destroyed.lock();
destroyed.add(ResourceId::Texture(old.outdated.texture_id.value), old.outdated.texture_id.ref_count);
destroyed.add(ResourceId::TextureView(old.outdated.view_id.value), old.outdated.view_id.ref_count);
unsafe {
old.command_pool.reset()
};
(Some(old.raw), old.sem_available, old.command_pool)
}
_ => unsafe {
let sem_available = device.raw
.create_semaphore()
.unwrap();
let command_pool = device.raw
.create_command_pool_typed(
&device.queue_group,
hal::pool::CommandPoolCreateFlags::RESET_INDIVIDUAL,
)
.unwrap();
(None, sem_available, command_pool)
}
};

let (raw, backbuffer) = unsafe {
device.raw
.create_swapchain(
&mut surface.raw,
config.with_image_usage(usage),
None,
old_raw,
)
.unwrap()
};
let command_pool = unsafe {
device.raw
.create_command_pool_typed(
&device.queue_group,
hal::pool::CommandPoolCreateFlags::RESET_INDIVIDUAL,
)
.unwrap()
};

let swap_chain = swap_chain::SwapChain {
surface.swap_chain = Some(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(),
sem_available,
outdated,
command_pool,
};
});

let images = match backbuffer {
hal::Backbuffer::Images(images) => images,
hal::Backbuffer::Framebuffer(_) => panic!("Deprecated API detected!"),
};

let textures = images
images
.into_iter()
.map(|raw| resource::Texture {
raw,
Expand All @@ -1384,18 +1419,20 @@ pub fn device_create_swap_chain(
swap_chain_link: None,
life_guard: LifeGuard::new(),
})
.collect();

(swap_chain, textures)
.collect()
}

#[cfg(feature = "local")]
fn swap_chain_populate_textures(
swap_chain_id: SwapChainId,
textures: Vec<resource::Texture<back::Backend>>,
) {
let mut swap_chain_guard = HUB.swap_chains.write();
let swap_chain = swap_chain_guard.get_mut(swap_chain_id);
let mut surface_guard = HUB.surfaces.write();
let swap_chain = surface_guard
.get_mut(swap_chain_id)
.swap_chain
.as_mut()
.unwrap();
let device_guard = HUB.devices.read();
let device = device_guard.get(swap_chain.device_id.value);

Expand Down Expand Up @@ -1457,10 +1494,28 @@ pub extern "C" fn wgpu_device_create_swap_chain(
surface_id: SurfaceId,
desc: &swap_chain::SwapChainDescriptor,
) -> SwapChainId {
let (swap_chain, textures) = device_create_swap_chain(device_id, surface_id, desc);
let id = HUB.swap_chains.register(swap_chain);
swap_chain_populate_textures(id, textures);
id
let outdated = {
let outdated_texture = device_create_texture(device_id, &desc.to_texture_desc());
let texture_id = Stored {
ref_count: outdated_texture.life_guard.ref_count.clone(),
value: HUB.textures.register(outdated_texture),
};
device_track_texture(device_id, texture_id.value, texture_id.ref_count.clone());

let outdated_view = texture_create_default_view(texture_id.value);
let view_id = Stored {
ref_count: outdated_view.life_guard.ref_count.clone(),
value: HUB.texture_views.register(outdated_view),
};
swap_chain::OutdatedFrame {
texture_id,
view_id,
}
};

let textures = device_create_swap_chain(device_id, surface_id, desc, outdated);
swap_chain_populate_textures(surface_id, textures);
surface_id
}


Expand Down
3 changes: 1 addition & 2 deletions wgpu-native/src/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
RenderPassHandle, ComputePassHandle,
PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle,
BufferHandle, SamplerHandle, TextureHandle, TextureViewHandle,
SurfaceHandle, SwapChainHandle,
SurfaceHandle,
};

use hal::backend::FastHashMap;
Expand Down Expand Up @@ -126,7 +126,6 @@ pub struct Hub {
pub(crate) texture_views: Arc<Registry<TextureViewHandle>>,
pub(crate) samplers: Arc<Registry<SamplerHandle>>,
pub(crate) surfaces: Arc<Registry<SurfaceHandle>>,
pub(crate) swap_chains: Arc<Registry<SwapChainHandle>>,
}

lazy_static! {
Expand Down
Loading

0 comments on commit 022087b

Please sign in to comment.