mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Merge #1502
1502: Refactor halmark example to properly recycle command pools r=kvark a=kvark **Connections** **Description** It didn't reset the command encoder until the end, which made it non-suitable for Vulkan benchmarking. **Testing** manually Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com> Co-authored-by: Dzmitry Malyshau <dmalyshau@mozilla.com>
This commit is contained in:
@@ -28,9 +28,24 @@ struct Locals {
|
||||
_pad: u32,
|
||||
}
|
||||
|
||||
struct UsedResources<A: hal::Api> {
|
||||
view: A::TextureView,
|
||||
cmd_buf: A::CommandBuffer,
|
||||
struct ExecutionContext<A: hal::Api> {
|
||||
encoder: A::CommandEncoder,
|
||||
fence: A::Fence,
|
||||
fence_value: hal::FenceValue,
|
||||
used_views: Vec<A::TextureView>,
|
||||
used_cmd_bufs: Vec<A::CommandBuffer>,
|
||||
bunnies_recorded: usize,
|
||||
}
|
||||
|
||||
impl<A: hal::Api> ExecutionContext<A> {
|
||||
unsafe fn wait_and_clear(&mut self, device: &A::Device) {
|
||||
device.wait(&self.fence, self.fence_value, !0).unwrap();
|
||||
for view in self.used_views.drain(..) {
|
||||
device.destroy_texture_view(view);
|
||||
}
|
||||
self.encoder.reset_all(self.used_cmd_bufs.drain(..));
|
||||
self.bunnies_recorded = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -53,11 +68,9 @@ struct Example<A: hal::Api> {
|
||||
global_buffer: A::Buffer,
|
||||
sampler: A::Sampler,
|
||||
texture: A::Texture,
|
||||
view: A::TextureView,
|
||||
fence: A::Fence,
|
||||
fence_value: hal::FenceValue,
|
||||
cmd_encoder: A::CommandEncoder,
|
||||
old_resources: Vec<(hal::FenceValue, UsedResources<A>)>,
|
||||
texture_view: A::TextureView,
|
||||
contexts: Vec<ExecutionContext<A>>,
|
||||
context_index: usize,
|
||||
extent: [u32; 2],
|
||||
start: Instant,
|
||||
}
|
||||
@@ -66,7 +79,11 @@ impl<A: hal::Api> Example<A> {
|
||||
fn init(window: &winit::window::Window) -> Result<Self, hal::InstanceError> {
|
||||
let instance_desc = hal::InstanceDescriptor {
|
||||
name: "example",
|
||||
flags: hal::InstanceFlag::all(),
|
||||
flags: if cfg!(debug_assertions) {
|
||||
hal::InstanceFlag::all()
|
||||
} else {
|
||||
hal::InstanceFlag::empty()
|
||||
},
|
||||
};
|
||||
let instance = unsafe { A::Instance::init(&instance_desc)? };
|
||||
let mut surface = unsafe { instance.create_surface(window).unwrap() };
|
||||
@@ -88,7 +105,7 @@ impl<A: hal::Api> Example<A> {
|
||||
|
||||
let window_size: (u32, u32) = window.inner_size().into();
|
||||
let surface_config = hal::SurfaceConfiguration {
|
||||
swap_chain_size: 2,
|
||||
swap_chain_size: 3,
|
||||
present_mode: wgt::PresentMode::Fifo,
|
||||
composite_alpha_mode: hal::CompositeAlphaMode::Opaque,
|
||||
format: wgt::TextureFormat::Bgra8UnormSrgb,
|
||||
@@ -357,7 +374,7 @@ impl<A: hal::Api> Example<A> {
|
||||
usage: hal::TextureUse::SAMPLED,
|
||||
range: wgt::ImageSubresourceRange::default(),
|
||||
};
|
||||
let view = unsafe { device.create_texture_view(&texture, &view_desc).unwrap() };
|
||||
let texture_view = unsafe { device.create_texture_view(&texture, &view_desc).unwrap() };
|
||||
|
||||
let global_group = {
|
||||
let global_buffer_binding = hal::BufferBinding {
|
||||
@@ -366,7 +383,7 @@ impl<A: hal::Api> Example<A> {
|
||||
size: None,
|
||||
};
|
||||
let texture_binding = hal::TextureBinding {
|
||||
view: &view,
|
||||
view: &texture_view,
|
||||
usage: hal::TextureUse::SAMPLED,
|
||||
};
|
||||
let global_group_desc = hal::BindGroupDescriptor {
|
||||
@@ -442,11 +459,16 @@ impl<A: hal::Api> Example<A> {
|
||||
global_buffer,
|
||||
sampler,
|
||||
texture,
|
||||
view,
|
||||
old_resources: Vec::new(),
|
||||
cmd_encoder,
|
||||
fence,
|
||||
fence_value: 1,
|
||||
texture_view,
|
||||
contexts: vec![ExecutionContext {
|
||||
encoder: cmd_encoder,
|
||||
fence,
|
||||
fence_value: 1,
|
||||
used_views: Vec::new(),
|
||||
used_cmd_bufs: Vec::new(),
|
||||
bunnies_recorded: 0,
|
||||
}],
|
||||
context_index: 0,
|
||||
extent: [window_size.0, window_size.1],
|
||||
start: Instant::now(),
|
||||
})
|
||||
@@ -454,22 +476,24 @@ impl<A: hal::Api> Example<A> {
|
||||
|
||||
fn exit(mut self) {
|
||||
unsafe {
|
||||
self.device.wait(&self.fence, self.fence_value, !0).unwrap();
|
||||
let mut cmd_buffers = Vec::new();
|
||||
for (_, old) in self.old_resources {
|
||||
self.device.destroy_texture_view(old.view);
|
||||
cmd_buffers.push(old.cmd_buf);
|
||||
{
|
||||
let ctx = &mut self.contexts[self.context_index];
|
||||
self.queue
|
||||
.submit(&[], Some((&mut ctx.fence, ctx.fence_value)))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
for mut ctx in self.contexts {
|
||||
ctx.wait_and_clear(&self.device);
|
||||
self.device.destroy_command_encoder(ctx.encoder);
|
||||
self.device.destroy_fence(ctx.fence);
|
||||
}
|
||||
self.cmd_encoder.reset_all(cmd_buffers.into_iter());
|
||||
self.surface.unconfigure(&self.device);
|
||||
|
||||
self.device.destroy_bind_group(self.local_group);
|
||||
self.device.destroy_bind_group(self.global_group);
|
||||
self.device.destroy_buffer(self.local_buffer);
|
||||
self.device.destroy_buffer(self.global_buffer);
|
||||
self.device.destroy_texture_view(self.view);
|
||||
self.device.destroy_command_encoder(self.cmd_encoder);
|
||||
self.device.destroy_fence(self.fence);
|
||||
self.device.destroy_texture_view(self.texture_view);
|
||||
self.device.destroy_texture(self.texture);
|
||||
self.device.destroy_sampler(self.sampler);
|
||||
self.device.destroy_shader_module(self.shader);
|
||||
@@ -480,6 +504,7 @@ impl<A: hal::Api> Example<A> {
|
||||
.destroy_bind_group_layout(self.global_group_layout);
|
||||
self.device.destroy_pipeline_layout(self.pipeline_layout);
|
||||
|
||||
self.surface.unconfigure(&self.device);
|
||||
self.device.exit();
|
||||
self.instance.destroy_surface(self.surface);
|
||||
}
|
||||
@@ -551,8 +576,10 @@ impl<A: hal::Api> Example<A> {
|
||||
}
|
||||
}
|
||||
|
||||
let ctx = &mut self.contexts[self.context_index];
|
||||
|
||||
unsafe {
|
||||
self.cmd_encoder.begin_encoding(Some("frame")).unwrap();
|
||||
ctx.encoder.begin_encoding(Some("frame")).unwrap();
|
||||
}
|
||||
|
||||
let surface_tex = unsafe { self.surface.acquire_texture(!0).unwrap().unwrap().texture };
|
||||
@@ -588,9 +615,9 @@ impl<A: hal::Api> Example<A> {
|
||||
depth_stencil_attachment: None,
|
||||
};
|
||||
unsafe {
|
||||
self.cmd_encoder.begin_render_pass(&pass_desc);
|
||||
self.cmd_encoder.set_render_pipeline(&self.pipeline);
|
||||
self.cmd_encoder
|
||||
ctx.encoder.begin_render_pass(&pass_desc);
|
||||
ctx.encoder.set_render_pipeline(&self.pipeline);
|
||||
ctx.encoder
|
||||
.set_bind_group(&self.pipeline_layout, 0, &self.global_group, &[]);
|
||||
}
|
||||
|
||||
@@ -598,45 +625,56 @@ impl<A: hal::Api> Example<A> {
|
||||
let offset =
|
||||
(i as wgt::DynamicOffset) * (wgt::BIND_BUFFER_ALIGNMENT as wgt::DynamicOffset);
|
||||
unsafe {
|
||||
self.cmd_encoder.set_bind_group(
|
||||
&self.pipeline_layout,
|
||||
1,
|
||||
&self.local_group,
|
||||
&[offset],
|
||||
);
|
||||
self.cmd_encoder.draw(0, 4, 0, 1);
|
||||
ctx.encoder
|
||||
.set_bind_group(&self.pipeline_layout, 1, &self.local_group, &[offset]);
|
||||
ctx.encoder.draw(0, 4, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
self.fence_value += 1;
|
||||
let last_done = unsafe { self.device.get_fence_value(&self.fence).unwrap() };
|
||||
for i in (0..self.old_resources.len()).rev() {
|
||||
if self.old_resources[i].0 <= last_done {
|
||||
let (_, old) = self.old_resources.swap_remove(i);
|
||||
unsafe {
|
||||
self.device.destroy_texture_view(old.view);
|
||||
//TODO: destroy the command buffer
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.bunnies_recorded += self.bunnies.len();
|
||||
let do_fence = ctx.bunnies_recorded > MAX_BUNNIES;
|
||||
|
||||
let cmd_buf = unsafe {
|
||||
self.cmd_encoder.end_render_pass();
|
||||
let cmd_buf = self.cmd_encoder.end_encoding().unwrap();
|
||||
self.queue
|
||||
.submit(&[&cmd_buf], Some((&mut self.fence, self.fence_value)))
|
||||
.unwrap();
|
||||
unsafe {
|
||||
ctx.encoder.end_render_pass();
|
||||
let cmd_buf = ctx.encoder.end_encoding().unwrap();
|
||||
let fence_param = if do_fence {
|
||||
Some((&mut ctx.fence, ctx.fence_value))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.queue.submit(&[&cmd_buf], fence_param).unwrap();
|
||||
self.queue.present(&mut self.surface, surface_tex).unwrap();
|
||||
cmd_buf
|
||||
ctx.used_cmd_bufs.push(cmd_buf);
|
||||
ctx.used_views.push(surface_tex_view);
|
||||
};
|
||||
|
||||
self.old_resources.push((
|
||||
self.fence_value,
|
||||
UsedResources {
|
||||
view: surface_tex_view,
|
||||
cmd_buf,
|
||||
},
|
||||
));
|
||||
if do_fence {
|
||||
log::info!("Context switch from {}", self.context_index);
|
||||
let old_fence_value = ctx.fence_value;
|
||||
drop(ctx);
|
||||
if self.contexts.len() == 1 {
|
||||
let hal_desc = hal::CommandEncoderDescriptor {
|
||||
label: None,
|
||||
queue: &self.queue,
|
||||
};
|
||||
self.contexts.push(unsafe {
|
||||
ExecutionContext {
|
||||
encoder: self.device.create_command_encoder(&hal_desc).unwrap(),
|
||||
fence: self.device.create_fence().unwrap(),
|
||||
fence_value: 0,
|
||||
used_views: Vec::new(),
|
||||
used_cmd_bufs: Vec::new(),
|
||||
bunnies_recorded: 0,
|
||||
}
|
||||
});
|
||||
}
|
||||
self.context_index = (self.context_index + 1) % self.contexts.len();
|
||||
let next = &mut self.contexts[self.context_index];
|
||||
unsafe {
|
||||
next.wait_and_clear(&self.device);
|
||||
}
|
||||
next.fence_value = old_fence_value + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user