|
|
|
async fn run() {
|
|
|
|
let adapter = wgpu::Adapter::request(
|
|
|
|
&wgpu::RequestAdapterOptions {
|
|
|
|
power_preference: wgpu::PowerPreference::Default,
|
|
|
|
compatible_surface: None,
|
|
|
|
},
|
|
|
|
wgpu::BackendBit::PRIMARY,
|
|
|
|
).await.unwrap();
|
|
|
|
let (device, queue) = adapter.request_device(&Default::default()).await;
|
|
|
|
|
|
|
|
let texture_size = 256u32;
|
|
|
|
let texture_desc = wgpu::TextureDescriptor {
|
|
|
|
size: wgpu::Extent3d {
|
|
|
|
width: texture_size,
|
|
|
|
height: texture_size,
|
|
|
|
depth: 1,
|
|
|
|
},
|
|
|
|
array_layer_count: 1,
|
|
|
|
mip_level_count: 1,
|
|
|
|
sample_count: 1,
|
|
|
|
dimension: wgpu::TextureDimension::D2,
|
|
|
|
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
|
|
|
usage: wgpu::TextureUsage::COPY_SRC
|
|
|
|
| wgpu::TextureUsage::OUTPUT_ATTACHMENT
|
|
|
|
,
|
|
|
|
label: None,
|
|
|
|
};
|
|
|
|
let texture = device.create_texture(&texture_desc);
|
|
|
|
let texture_view = texture.create_default_view();
|
|
|
|
|
|
|
|
// we need to store this for later
|
|
|
|
let u32_size = std::mem::size_of::<u32>() as u32;
|
|
|
|
|
|
|
|
let output_buffer_size = (u32_size * texture_size * texture_size) as wgpu::BufferAddress;
|
|
|
|
let output_buffer_desc = wgpu::BufferDescriptor {
|
|
|
|
size: output_buffer_size,
|
|
|
|
usage: wgpu::BufferUsage::COPY_DST
|
|
|
|
// this tells wpgu that we want to read this buffer from the cpu
|
|
|
|
| wgpu::BufferUsage::MAP_READ,
|
|
|
|
label: None,
|
|
|
|
};
|
|
|
|
let output_buffer = device.create_buffer(&output_buffer_desc);
|
|
|
|
|
|
|
|
let vs_src = include_str!("shader.vert");
|
|
|
|
let fs_src = include_str!("shader.frag");
|
|
|
|
let vs_spirv = glsl_to_spirv::compile(vs_src, glsl_to_spirv::ShaderType::Vertex).unwrap();
|
|
|
|
let fs_spirv = glsl_to_spirv::compile(fs_src, glsl_to_spirv::ShaderType::Fragment).unwrap();
|
|
|
|
let vs_data = wgpu::read_spirv(vs_spirv).unwrap();
|
|
|
|
let fs_data = wgpu::read_spirv(fs_spirv).unwrap();
|
|
|
|
let vs_module = device.create_shader_module(&vs_data);
|
|
|
|
let fs_module = device.create_shader_module(&fs_data);
|
|
|
|
|
|
|
|
let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
|
|
bind_group_layouts: &[],
|
|
|
|
});
|
|
|
|
|
|
|
|
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
|
|
layout: &render_pipeline_layout,
|
|
|
|
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
|
|
|
module: &vs_module,
|
|
|
|
entry_point: "main",
|
|
|
|
},
|
|
|
|
fragment_stage: Some(wgpu::ProgrammableStageDescriptor {
|
|
|
|
module: &fs_module,
|
|
|
|
entry_point: "main",
|
|
|
|
}),
|
|
|
|
rasterization_state: Some(wgpu::RasterizationStateDescriptor {
|
|
|
|
front_face: wgpu::FrontFace::Ccw,
|
|
|
|
cull_mode: wgpu::CullMode::Back,
|
|
|
|
depth_bias: 0,
|
|
|
|
depth_bias_slope_scale: 0.0,
|
|
|
|
depth_bias_clamp: 0.0,
|
|
|
|
}),
|
|
|
|
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
|
|
|
|
color_states: &[
|
|
|
|
wgpu::ColorStateDescriptor {
|
|
|
|
format: texture_desc.format,
|
|
|
|
color_blend: wgpu::BlendDescriptor::REPLACE,
|
|
|
|
alpha_blend: wgpu::BlendDescriptor::REPLACE,
|
|
|
|
write_mask: wgpu::ColorWrite::ALL,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
depth_stencil_state: None,
|
|
|
|
vertex_state: wgpu::VertexStateDescriptor {
|
|
|
|
index_format: wgpu::IndexFormat::Uint16,
|
|
|
|
vertex_buffers: &[],
|
|
|
|
},
|
|
|
|
sample_count: 1,
|
|
|
|
sample_mask: !0,
|
|
|
|
alpha_to_coverage_enabled: false,
|
|
|
|
});
|
|
|
|
|
|
|
|
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
|
|
|
label: None,
|
|
|
|
});
|
|
|
|
|
|
|
|
{
|
|
|
|
let render_pass_desc = wgpu::RenderPassDescriptor {
|
|
|
|
color_attachments: &[
|
|
|
|
wgpu::RenderPassColorAttachmentDescriptor {
|
|
|
|
attachment: &texture_view,
|
|
|
|
resolve_target: None,
|
|
|
|
load_op: wgpu::LoadOp::Clear,
|
|
|
|
store_op: wgpu::StoreOp::Store,
|
|
|
|
clear_color: wgpu::Color {
|
|
|
|
r: 0.1,
|
|
|
|
g: 0.2,
|
|
|
|
b: 0.3,
|
|
|
|
a: 1.0,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
],
|
|
|
|
depth_stencil_attachment: None,
|
|
|
|
};
|
|
|
|
let mut render_pass = encoder.begin_render_pass(&render_pass_desc);
|
|
|
|
|
|
|
|
render_pass.set_pipeline(&render_pipeline);
|
|
|
|
render_pass.draw(0..3, 0..1);
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
bytes_per_row: u32_size * texture_size,
|
|
|
|
rows_per_image: texture_size,
|
|
|
|
},
|
|
|
|
texture_desc.size,
|
|
|
|
);
|
|
|
|
|
|
|
|
queue.submit(&[encoder.finish()]);
|
|
|
|
|
|
|
|
// NOTE: We have to create the mapping THEN device.poll(). If we don't
|
|
|
|
// the application will freeze.
|
|
|
|
let mapping = output_buffer.map_read(0, output_buffer_size);
|
|
|
|
device.poll(wgpu::Maintain::Wait);
|
|
|
|
|
|
|
|
let result = mapping.await.unwrap();
|
|
|
|
let data = result.as_slice();
|
|
|
|
|
|
|
|
use image::{ImageBuffer, Rgba};
|
|
|
|
let buffer = ImageBuffer::<Rgba<u8>, _>::from_raw(
|
|
|
|
texture_size,
|
|
|
|
texture_size,
|
|
|
|
data,
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
buffer.save("image.png").unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
use futures::executor::block_on;
|
|
|
|
block_on(run());
|
|
|
|
}
|