mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Add an example showing how to capture a render
This commit is contained in:
@@ -32,3 +32,4 @@ cgmath = "0.17"
|
||||
env_logger = "0.6"
|
||||
glsl-to-spirv = "0.1"
|
||||
log = "0.4"
|
||||
png = "0.15"
|
||||
|
||||
106
examples/capture/main.rs
Normal file
106
examples/capture/main.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
/// This example shows how to capture an image by rendering it to a texture, copying the texture to
|
||||
/// a buffer, and retrieving it from the buffer. This could be used for "taking a screenshot," with
|
||||
/// the added benefit that this method doesn't require a window to be created.
|
||||
use std::fs::File;
|
||||
use std::mem::size_of;
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let instance = wgpu::Instance::new();
|
||||
|
||||
let adapter = instance.get_adapter(&wgpu::AdapterDescriptor {
|
||||
power_preference: wgpu::PowerPreference::LowPower,
|
||||
});
|
||||
|
||||
let mut device = adapter.request_device(&wgpu::DeviceDescriptor {
|
||||
extensions: wgpu::Extensions {
|
||||
anisotropic_filtering: false,
|
||||
},
|
||||
limits: wgpu::Limits::default(),
|
||||
});
|
||||
|
||||
// Rendered image is 256×256 with 32-bit RGBA color
|
||||
let size = 256u32;
|
||||
|
||||
// The output buffer lets us retrieve the data as an array
|
||||
let output_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: (size * size) as u64 * size_of::<u32>() as u64,
|
||||
usage: wgpu::BufferUsage::MAP_READ | wgpu::BufferUsage::TRANSFER_DST,
|
||||
});
|
||||
|
||||
let texture_extent = wgpu::Extent3d {
|
||||
width: size,
|
||||
height: size,
|
||||
depth: 1,
|
||||
};
|
||||
|
||||
// The render pipeline renders data into this texture
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
size: texture_extent,
|
||||
array_layer_count: 1,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsage::STORAGE
|
||||
| wgpu::TextureUsage::OUTPUT_ATTACHMENT
|
||||
| wgpu::TextureUsage::TRANSFER_SRC,
|
||||
});
|
||||
|
||||
// Set the background to be red
|
||||
let command_buffer = {
|
||||
let mut encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &texture.create_default_view(),
|
||||
resolve_target: None,
|
||||
load_op: wgpu::LoadOp::Clear,
|
||||
store_op: wgpu::StoreOp::Store,
|
||||
clear_color: wgpu::Color::RED,
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
// Copy the data from the texture to the buffer
|
||||
encoder.copy_texture_to_buffer(
|
||||
wgpu::TextureCopyView {
|
||||
texture: &texture,
|
||||
mip_level: 0,
|
||||
array_layer: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
},
|
||||
wgpu::BufferCopyView {
|
||||
buffer: &output_buffer,
|
||||
offset: 0,
|
||||
row_pitch: size_of::<u32>() as u32 * size,
|
||||
image_height: size,
|
||||
},
|
||||
texture_extent,
|
||||
);
|
||||
|
||||
encoder.finish()
|
||||
};
|
||||
|
||||
device.get_queue().submit(&[command_buffer]);
|
||||
|
||||
// Write the buffer as a PNG
|
||||
output_buffer.map_read_async(
|
||||
0,
|
||||
(size * size) as u64 * size_of::<u32>() as u64,
|
||||
move |result: wgpu::BufferMapAsyncResult<&[u8]>| {
|
||||
let mut png_encoder = png::Encoder::new(File::create("red.png").unwrap(), size, size);
|
||||
png_encoder.set_depth(png::BitDepth::Eight);
|
||||
png_encoder.set_color(png::ColorType::RGBA);
|
||||
png_encoder
|
||||
.write_header()
|
||||
.unwrap()
|
||||
.write_image_data(result.unwrap().data)
|
||||
.unwrap();
|
||||
},
|
||||
);
|
||||
|
||||
// The device will be polled when it is dropped but we can also poll it explicitly
|
||||
device.poll(true);
|
||||
}
|
||||
Reference in New Issue
Block a user