Skip to content

Commit 022087b

Browse files
bors[bot]kvark
andcommitted
Merge #69
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>
2 parents 917626c + 59fe349 commit 022087b

File tree

9 files changed

+248
-122
lines changed

9 files changed

+248
-122
lines changed

gfx-examples/src/cube.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,22 @@ struct Cube {
8888
index_buf: wgpu::Buffer,
8989
index_count: usize,
9090
bind_group: wgpu::BindGroup,
91+
uniform_buf: wgpu::Buffer,
9192
pipeline: wgpu::RenderPipeline,
9293
}
9394

95+
impl Cube {
96+
fn generate_matrix(aspect_ratio: f32) -> cgmath::Matrix4<f32> {
97+
let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 10.0);
98+
let mx_view = cgmath::Matrix4::look_at(
99+
cgmath::Point3::new(1.5f32, -5.0, 3.0),
100+
cgmath::Point3::new(0f32, 0.0, 0.0),
101+
cgmath::Vector3::unit_z(),
102+
);
103+
mx_projection * mx_view
104+
}
105+
}
106+
94107
impl framework::Example for Cube {
95108
fn init(device: &mut wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self {
96109
use std::mem;
@@ -196,18 +209,9 @@ impl framework::Example for Cube {
196209
size: 64,
197210
usage: wgpu::BufferUsageFlags::UNIFORM | wgpu::BufferUsageFlags::TRANSFER_DST,
198211
});
199-
{
200-
let aspect_ratio = sc_desc.width as f32 / sc_desc.height as f32;
201-
let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 10.0);
202-
let mx_view = cgmath::Matrix4::look_at(
203-
cgmath::Point3::new(1.5f32, -5.0, 3.0),
204-
cgmath::Point3::new(0f32, 0.0, 0.0),
205-
cgmath::Vector3::unit_z(),
206-
);
207-
let mx_total = mx_projection * mx_view;
208-
let mx_raw: &[f32; 16] = mx_total.as_ref();
209-
uniform_buf.set_sub_data(0, framework::cast_slice(&mx_raw[..]));
210-
}
212+
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
213+
let mx_ref: &[f32; 16] = mx_total.as_ref();
214+
uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..]));
211215

212216
// Create bind group
213217
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
@@ -294,11 +298,17 @@ impl framework::Example for Cube {
294298
index_buf,
295299
index_count: index_data.len(),
296300
bind_group,
301+
uniform_buf,
297302
pipeline,
298303
}
299304
}
300305

301-
fn update(&mut self, _event: wgpu::winit::WindowEvent) {
306+
fn update(&mut self, event: wgpu::winit::WindowEvent) {
307+
if let wgpu::winit::WindowEvent::Resized(size) = event {
308+
let mx_total = Self::generate_matrix(size.width as f32 / size.height as f32);
309+
let mx_ref: &[f32; 16] = mx_total.as_ref();
310+
self.uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..]));
311+
}
302312
}
303313

304314
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {

gfx-examples/src/framework.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub fn run<E: Example>(title: &str) {
7070
.to_physical(window.get_hidpi_factor());
7171

7272
let surface = instance.create_surface(&window);
73-
let sc_desc = wgpu::SwapChainDescriptor {
73+
let mut sc_desc = wgpu::SwapChainDescriptor {
7474
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT,
7575
format: wgpu::TextureFormat::B8g8r8a8Unorm,
7676
width: size.width as u32,
@@ -91,7 +91,11 @@ pub fn run<E: Example>(title: &str) {
9191
..
9292
} => {
9393
let physical = size.to_physical(window.get_hidpi_factor());
94-
info!("Resized to {:?}", physical);
94+
info!("Resizing to {:?}", physical);
95+
sc_desc.width = physical.width as u32;
96+
sc_desc.height = physical.height as u32;
97+
swap_chain = device.create_swap_chain(&surface, &sc_desc);
98+
example.update(WindowEvent::Resized(size));
9599
}
96100
Event::WindowEvent { event, .. } => match event {
97101
WindowEvent::KeyboardInput {

wgpu-bindings/wgpu.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,10 +435,10 @@ typedef struct {
435435
WGPUByteArray code;
436436
} WGPUShaderModuleDescriptor;
437437

438-
typedef WGPUId WGPUSwapChainId;
439-
440438
typedef WGPUId WGPUSurfaceId;
441439

440+
typedef WGPUSurfaceId WGPUSwapChainId;
441+
442442
typedef uint32_t WGPUTextureUsageFlags;
443443

444444
typedef struct {

wgpu-native/src/device.rs

Lines changed: 96 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,8 @@ unsafe impl<B: hal::Backend> Send for DestroyedResources<B> {}
9898
unsafe impl<B: hal::Backend> Sync for DestroyedResources<B> {}
9999

100100
impl<B: hal::Backend> DestroyedResources<B> {
101-
fn add(&mut self, resource_id: ResourceId, life_guard: &LifeGuard) {
102-
self.referenced
103-
.push((resource_id, life_guard.ref_count.clone()));
101+
fn add(&mut self, resource_id: ResourceId, ref_count: RefCount) {
102+
self.referenced.push((resource_id, ref_count));
104103
}
105104

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

141140
impl DestroyedResources<back::Backend> {
142-
fn triage_referenced(&mut self) {
141+
fn triage_referenced(
142+
&mut self,
143+
buffer_tracker: &mut BufferTracker,
144+
texture_tracker: &mut TextureTracker,
145+
) {
143146
for i in (0..self.referenced.len()).rev() {
144147
// one in resource itself, and one here in this list
145148
let num_refs = self.referenced[i].1.load();
@@ -148,11 +151,13 @@ impl DestroyedResources<back::Backend> {
148151
let resource_id = self.referenced.swap_remove(i).0;
149152
let (submit_index, resource) = match resource_id {
150153
ResourceId::Buffer(id) => {
154+
buffer_tracker.remove(id);
151155
let buf = HUB.buffers.unregister(id);
152156
let si = buf.life_guard.submission_index.load(Ordering::Acquire);
153157
(si, Resource::Buffer(buf))
154158
}
155159
ResourceId::Texture(id) => {
160+
texture_tracker.remove(id);
156161
let tex = HUB.textures.unregister(id);
157162
let si = tex.life_guard.submission_index.load(Ordering::Acquire);
158163
(si, Resource::Texture(tex))
@@ -369,7 +374,10 @@ pub extern "C" fn wgpu_buffer_destroy(buffer_id: BufferId) {
369374
.get(buffer.device_id.value)
370375
.destroyed
371376
.lock()
372-
.add(ResourceId::Buffer(buffer_id), &buffer.life_guard);
377+
.add(
378+
ResourceId::Buffer(buffer_id),
379+
buffer.life_guard.ref_count.clone(),
380+
);
373381
}
374382

375383

@@ -579,7 +587,10 @@ pub extern "C" fn wgpu_texture_destroy(texture_id: TextureId) {
579587
.get(texture.device_id.value)
580588
.destroyed
581589
.lock()
582-
.add(ResourceId::Texture(texture_id), &texture.life_guard);
590+
.add(
591+
ResourceId::Texture(texture_id),
592+
texture.life_guard.ref_count.clone(),
593+
);
583594
}
584595

585596
#[no_mangle]
@@ -595,7 +606,10 @@ pub extern "C" fn wgpu_texture_view_destroy(texture_view_id: TextureViewId) {
595606
.get(device_id)
596607
.destroyed
597608
.lock()
598-
.add(ResourceId::TextureView(texture_view_id), &view.life_guard);
609+
.add(
610+
ResourceId::TextureView(texture_view_id),
611+
view.life_guard.ref_count.clone(),
612+
);
599613
}
600614

601615

@@ -902,6 +916,8 @@ pub extern "C" fn wgpu_queue_submit(
902916
.life_guard
903917
.submission_index
904918
.fetch_add(1, Ordering::Relaxed);
919+
let mut buffer_tracker = device.buffer_tracker.lock();
920+
let mut texture_tracker = device.texture_tracker.lock();
905921

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

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

970984
let wait_semaphores = swap_chain_links
971985
.into_iter()
972-
.map(|link| {
986+
.flat_map(|link| {
973987
//TODO: check the epoch
974-
let sem = &swap_chain_guard
988+
surface_guard
975989
.get(link.swap_chain_id.0)
976-
.frames[link.image_index as usize]
977-
.sem_available;
978-
(sem, hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT)
990+
.swap_chain
991+
.as_ref()
992+
.map(|swap_chain| (
993+
&swap_chain.frames[link.image_index as usize].sem_available,
994+
hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT,
995+
))
979996
});
980997

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

9981015
let last_done = {
9991016
let mut destroyed = device.destroyed.lock();
1000-
destroyed.triage_referenced();
1017+
destroyed.triage_referenced(&mut *buffer_tracker, &mut *texture_tracker);
10011018
let last_done = destroyed.cleanup(&device.raw);
10021019

10031020
destroyed.active.push(ActiveSubmission {
@@ -1294,12 +1311,12 @@ pub extern "C" fn wgpu_device_create_compute_pipeline(
12941311
HUB.compute_pipelines.register(pipeline)
12951312
}
12961313

1297-
12981314
pub fn device_create_swap_chain(
12991315
device_id: DeviceId,
13001316
surface_id: SurfaceId,
13011317
desc: &swap_chain::SwapChainDescriptor,
1302-
) -> (swap_chain::SwapChain<back::Backend>, Vec<resource::Texture<back::Backend>>) {
1318+
outdated: swap_chain::OutdatedFrame,
1319+
) -> Vec<resource::Texture<back::Backend>> {
13031320
let device_guard = HUB.devices.read();
13041321
let device = device_guard.get(device_id);
13051322
let mut surface_guard = HUB.surfaces.write();
@@ -1331,42 +1348,60 @@ pub fn device_create_swap_chain(
13311348
"Requested size {}x{} is outside of the supported range: {:?}",
13321349
desc.width, desc.height, caps.extents);
13331350

1351+
1352+
let (old_raw, sem_available, command_pool) = match surface.swap_chain.take() {
1353+
Some(mut old) => {
1354+
assert_eq!(old.device_id.value, device_id);
1355+
let mut destroyed = device.destroyed.lock();
1356+
destroyed.add(ResourceId::Texture(old.outdated.texture_id.value), old.outdated.texture_id.ref_count);
1357+
destroyed.add(ResourceId::TextureView(old.outdated.view_id.value), old.outdated.view_id.ref_count);
1358+
unsafe {
1359+
old.command_pool.reset()
1360+
};
1361+
(Some(old.raw), old.sem_available, old.command_pool)
1362+
}
1363+
_ => unsafe {
1364+
let sem_available = device.raw
1365+
.create_semaphore()
1366+
.unwrap();
1367+
let command_pool = device.raw
1368+
.create_command_pool_typed(
1369+
&device.queue_group,
1370+
hal::pool::CommandPoolCreateFlags::RESET_INDIVIDUAL,
1371+
)
1372+
.unwrap();
1373+
(None, sem_available, command_pool)
1374+
}
1375+
};
1376+
13341377
let (raw, backbuffer) = unsafe {
13351378
device.raw
13361379
.create_swapchain(
13371380
&mut surface.raw,
13381381
config.with_image_usage(usage),
1339-
None,
1382+
old_raw,
13401383
)
13411384
.unwrap()
13421385
};
1343-
let command_pool = unsafe {
1344-
device.raw
1345-
.create_command_pool_typed(
1346-
&device.queue_group,
1347-
hal::pool::CommandPoolCreateFlags::RESET_INDIVIDUAL,
1348-
)
1349-
.unwrap()
1350-
};
1351-
1352-
let swap_chain = swap_chain::SwapChain {
1386+
surface.swap_chain = Some(swap_chain::SwapChain {
13531387
raw,
13541388
device_id: Stored {
13551389
value: device_id,
13561390
ref_count: device.life_guard.ref_count.clone(),
13571391
},
13581392
frames: Vec::with_capacity(num_frames as usize),
13591393
acquired: Vec::with_capacity(1), //TODO: get it from gfx-hal?
1360-
sem_available: device.raw.create_semaphore().unwrap(),
1394+
sem_available,
1395+
outdated,
13611396
command_pool,
1362-
};
1397+
});
13631398

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

1369-
let textures = images
1404+
images
13701405
.into_iter()
13711406
.map(|raw| resource::Texture {
13721407
raw,
@@ -1384,18 +1419,20 @@ pub fn device_create_swap_chain(
13841419
swap_chain_link: None,
13851420
life_guard: LifeGuard::new(),
13861421
})
1387-
.collect();
1388-
1389-
(swap_chain, textures)
1422+
.collect()
13901423
}
13911424

13921425
#[cfg(feature = "local")]
13931426
fn swap_chain_populate_textures(
13941427
swap_chain_id: SwapChainId,
13951428
textures: Vec<resource::Texture<back::Backend>>,
13961429
) {
1397-
let mut swap_chain_guard = HUB.swap_chains.write();
1398-
let swap_chain = swap_chain_guard.get_mut(swap_chain_id);
1430+
let mut surface_guard = HUB.surfaces.write();
1431+
let swap_chain = surface_guard
1432+
.get_mut(swap_chain_id)
1433+
.swap_chain
1434+
.as_mut()
1435+
.unwrap();
13991436
let device_guard = HUB.devices.read();
14001437
let device = device_guard.get(swap_chain.device_id.value);
14011438

@@ -1457,10 +1494,28 @@ pub extern "C" fn wgpu_device_create_swap_chain(
14571494
surface_id: SurfaceId,
14581495
desc: &swap_chain::SwapChainDescriptor,
14591496
) -> SwapChainId {
1460-
let (swap_chain, textures) = device_create_swap_chain(device_id, surface_id, desc);
1461-
let id = HUB.swap_chains.register(swap_chain);
1462-
swap_chain_populate_textures(id, textures);
1463-
id
1497+
let outdated = {
1498+
let outdated_texture = device_create_texture(device_id, &desc.to_texture_desc());
1499+
let texture_id = Stored {
1500+
ref_count: outdated_texture.life_guard.ref_count.clone(),
1501+
value: HUB.textures.register(outdated_texture),
1502+
};
1503+
device_track_texture(device_id, texture_id.value, texture_id.ref_count.clone());
1504+
1505+
let outdated_view = texture_create_default_view(texture_id.value);
1506+
let view_id = Stored {
1507+
ref_count: outdated_view.life_guard.ref_count.clone(),
1508+
value: HUB.texture_views.register(outdated_view),
1509+
};
1510+
swap_chain::OutdatedFrame {
1511+
texture_id,
1512+
view_id,
1513+
}
1514+
};
1515+
1516+
let textures = device_create_swap_chain(device_id, surface_id, desc, outdated);
1517+
swap_chain_populate_textures(surface_id, textures);
1518+
surface_id
14641519
}
14651520

14661521

wgpu-native/src/hub.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
RenderPassHandle, ComputePassHandle,
55
PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle,
66
BufferHandle, SamplerHandle, TextureHandle, TextureViewHandle,
7-
SurfaceHandle, SwapChainHandle,
7+
SurfaceHandle,
88
};
99

1010
use hal::backend::FastHashMap;
@@ -126,7 +126,6 @@ pub struct Hub {
126126
pub(crate) texture_views: Arc<Registry<TextureViewHandle>>,
127127
pub(crate) samplers: Arc<Registry<SamplerHandle>>,
128128
pub(crate) surfaces: Arc<Registry<SurfaceHandle>>,
129-
pub(crate) swap_chains: Arc<Registry<SwapChainHandle>>,
130129
}
131130

132131
lazy_static! {

0 commit comments

Comments
 (0)