use wgpu::*; pub struct TextureWrapper { pub width: u32, pub height: u32, pub block_size: u32, pub texture: Texture, pub view: TextureView, } impl TextureWrapper { pub fn new( device: &Device, width: u32, height: u32, format: TextureFormat, usage: TextureUsages, ) -> Self { let texture = device.create_texture(&TextureDescriptor { label: None, size: Extent3d { width, height, depth_or_array_layers: 1, }, mip_level_count: 1, sample_count: 1, dimension: TextureDimension::D2, format, usage, view_formats: &[], }); let view = texture.create_view(&TextureViewDescriptor::default()); // NOTE: Depth, Stencil, YUVでない限りはNoneにはならないが、念の為`1`にunwrapする。 let block_size = format.block_copy_size(None).unwrap_or(1); Self { width, height, block_size, texture, view, } } /// テクスチャ全体を更新するメソッド /// /// * queue - queue /// * data - 更新データ /// /// `data`がテクスチャサイズと一致しない場合は、クラッシュしないように不足分が白色で埋められる。 pub fn write(&self, queue: &Queue, data: &[u8]) { self.write_partial(queue, data, Origin3d::ZERO, self.width, self.height); } /// テクスチャを部分的に更新するメソッド /// /// * queue - queue /// * data - 更新データ /// * origin - 更新領域の開始座標 /// * width - 更新領域の幅 /// * height - 更新領域の高さ /// /// `data`が更新領域サイズと一致しない場合は、クラッシュしないように不足分が白色で埋められる。 pub fn write_partial( &self, queue: &Queue, data: &[u8], origin: Origin3d, width: u32, height: u32, ) { let expected_len = (width * height * self.block_size) as usize; // `data`が想定サイズより短い場合はエラーになるので不足分を白色で埋める。 let buffer; let data = if data.len() >= expected_len { data } else { let mut v = Vec::with_capacity(expected_len); v.extend_from_slice(data); v.resize(expected_len, 0xff); buffer = v; buffer.as_slice() }; queue.write_texture( TexelCopyTextureInfo { texture: &self.texture, mip_level: 0, origin, aspect: TextureAspect::All, }, data, TexelCopyBufferLayout { offset: 0, bytes_per_row: Some(width * self.block_size), rows_per_image: Some(height), }, Extent3d { width, height, depth_or_array_layers: 1, }, ); } }