use std::sync::Arc;
use crate::context::Context;
use crate::resource::Texture;
const LAYER_SIZE: u32 = 1024;
pub struct TexArray {
pub view: wgpu::TextureView,
pub sampler: wgpu::Sampler,
}
impl TexArray {
pub fn build(sources: &[Arc<Texture>]) -> TexArray {
let ctxt = Context::get();
let layers = (sources.len() as u32) + 1;
let texture = ctxt.create_texture(&wgpu::TextureDescriptor {
label: Some("rt_tex_array"),
size: wgpu::Extent3d {
width: LAYER_SIZE,
height: LAYER_SIZE,
depth_or_array_layers: layers,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
let bgl = ctxt.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("rt_blit_bgl"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
});
let layout = ctxt.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("rt_blit_layout"),
bind_group_layouts: &[Some(&bgl)],
immediate_size: 0,
});
let shader = ctxt.create_shader_module(
Some("rt_blit_shader"),
include_str!("../../builtin/raytrace/blit.wgsl"),
);
let pipeline = ctxt.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("rt_blit_pipeline"),
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::Rgba8Unorm,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleStrip,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview_mask: None,
cache: None,
});
let sampler = ctxt.create_sampler(&wgpu::SamplerDescriptor {
label: Some("rt_blit_sampler"),
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::Repeat,
address_mode_w: wgpu::AddressMode::Repeat,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
..Default::default()
});
let mut encoder = ctxt.create_command_encoder(Some("rt_tex_array_blit"));
for (i, src) in sources.iter().enumerate() {
let layer_view = texture.create_view(&wgpu::TextureViewDescriptor {
label: Some("rt_tex_array_layer"),
base_array_layer: i as u32,
array_layer_count: Some(1),
dimension: Some(wgpu::TextureViewDimension::D2),
..Default::default()
});
let bind_group = ctxt.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("rt_blit_bind_group"),
layout: &bgl,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&src.view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&sampler),
},
],
});
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("rt_blit_pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &layer_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
pass.set_pipeline(&pipeline);
pass.set_bind_group(0, &bind_group, &[]);
pass.draw(0..4, 0..1);
}
{
let layer_view = texture.create_view(&wgpu::TextureViewDescriptor {
label: Some("rt_tex_array_fallback"),
base_array_layer: sources.len() as u32,
array_layer_count: Some(1),
dimension: Some(wgpu::TextureViewDimension::D2),
..Default::default()
});
let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("rt_blit_fallback_pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &layer_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
}
ctxt.submit(std::iter::once(encoder.finish()));
let view = texture.create_view(&wgpu::TextureViewDescriptor {
label: Some("rt_tex_array_view"),
dimension: Some(wgpu::TextureViewDimension::D2Array),
..Default::default()
});
TexArray { view, sampler }
}
}